Compare commits

..

181 Commits

Author SHA1 Message Date
iCrawl
bf92172d80 chore(util): release @discordjs/util@0.1.0 2022-10-03 14:08:03 +02:00
Suneet Tipirneni
b2ec865765 feat: add @discordjs/util (#8591)
* feat: add @discordjs/util

* fix: builders test

* refactor: make rest use lazy for ESM import

* chore: make requested changes

* Apply suggestions from code review

Co-authored-by: Parbez <imranbarbhuiya.fsd@gmail.com>
Co-authored-by: A. Román <kyradiscord@gmail.com>

* chore: make requested changes and add tests

* chore: regen lockfile

* test: add type tests

* chore: push missing files

* chore: make requested changes

* chore: update CI stuff

* chore: fix lockfile

* chore: make requested changes

Co-authored-by: Parbez <imranbarbhuiya.fsd@gmail.com>
Co-authored-by: A. Román <kyradiscord@gmail.com>
Co-authored-by: kodiakhq[bot] <49736102+kodiakhq[bot]@users.noreply.github.com>
2022-10-02 18:00:31 +00:00
SpaceEEC
3f8656115b fix(SequentialHandler): throw http error with proper name and more useful message (#8694)
Co-authored-by: kodiakhq[bot] <49736102+kodiakhq[bot]@users.noreply.github.com>
2022-10-01 14:50:18 +00:00
Almeida
883f6e9202 feat(ForumChannel): add defaultSortOrder (#8633) 2022-10-01 14:00:30 +00:00
Almeida
2ea2a85e63 types(ModalBuilder): fix constructor typings (#8690)
Co-authored-by: kodiakhq[bot] <49736102+kodiakhq[bot]@users.noreply.github.com>
2022-10-01 13:53:56 +00:00
DD
f063625836 fix(proxyRequests): forward query parameters (#8691)
Co-authored-by: kodiakhq[bot] <49736102+kodiakhq[bot]@users.noreply.github.com>
2022-10-01 13:46:52 +00:00
DD
6398e46043 chore(proxy-container): update README for proper request forwarding (#8692)
* chore(proxy-container): update README for proper request forwarding

* chore: remove unused import

Co-authored-by: kodiakhq[bot] <49736102+kodiakhq[bot]@users.noreply.github.com>
2022-10-01 13:40:24 +00:00
Almeida
d24dbf7d22 chore(deps): bump discord-api-types (#8685) 2022-10-01 13:30:19 +00:00
A. Román
3c231ae81a feat: add AbortSignal support (#8672)
* feat: add `AbortSignal` support

* fix: move the expect earlier

* fix: pass signal

Co-authored-by: kodiakhq[bot] <49736102+kodiakhq[bot]@users.noreply.github.com>
2022-09-25 18:44:03 +00:00
iCrawl
9f63eb977f chore(discord.js): release discord.js@14.5.0 2022-09-25 19:17:25 +02:00
iCrawl
c69f512450 chore(rest): release @discordjs/rest@1.2.0 2022-09-25 19:11:48 +02:00
iCrawl
4a07f9eaa1 chore: deps 2022-09-25 19:08:39 +02:00
Khafra
64cd53c4c2 feat(rest): use Agent with higher connect timeout (#8679)
* feat(rest): use Agent with higher connect timeout

* chore: lint

* chore: I'm an idiot

Co-authored-by: kodiakhq[bot] <49736102+kodiakhq[bot]@users.noreply.github.com>
2022-09-25 12:45:36 +00:00
MrMythicalYT
d79aa2d0d0 docs: fix duplicate typedefs (#8677)
Co-authored-by: kodiakhq[bot] <49736102+kodiakhq[bot]@users.noreply.github.com>
2022-09-25 11:46:10 +00:00
Rodry
822b7f234a types(Collection): make fn return type unknown (#8676)
Co-authored-by: kodiakhq[bot] <49736102+kodiakhq[bot]@users.noreply.github.com>
2022-09-25 11:40:58 +00:00
Jiralite
8ca407e089 docs(ForumChannel): Add @implements (#8678) 2022-09-25 13:27:56 +02:00
Jiralite
0126d9b810 fix(ThreadChannel): Add forum channel to parent (#8664)
fix(ThreadChannel): add forum channel to parent

Co-authored-by: kodiakhq[bot] <49736102+kodiakhq[bot]@users.noreply.github.com>
2022-09-24 14:51:11 +00:00
Jiralite
e9931229ae refactor(GuildBanManager): Add deprecation warning for deleteMessageDays (#8659)
refactor(GuildBanManager): add deprecation warning for `deleteMessageDays`

Co-authored-by: kodiakhq[bot] <49736102+kodiakhq[bot]@users.noreply.github.com>
2022-09-24 14:45:30 +00:00
Jiralite
1486bc9336 types(GuildChannelManager): Handle forum channel overload (#8660)
types(GuildChannelManager): handle forum channel overload

Co-authored-by: kodiakhq[bot] <49736102+kodiakhq[bot]@users.noreply.github.com>
2022-09-24 14:40:19 +00:00
Almeida
16fcdc3687 fix(GuildChannelManager): allow creating webhooks on forums (#8661)
Co-authored-by: kodiakhq[bot] <49736102+kodiakhq[bot]@users.noreply.github.com>
2022-09-24 14:34:19 +00:00
Jiralite
8622939229 fix(ForumChannel): Implement missing properties and methods (#8662)
* fix(ForumChannel): implement missing properties and methods

* refactor(ForumChannel): remove redundant default

* docs(ForumChannel): remove superfluous wording

Co-authored-by: kodiakhq[bot] <49736102+kodiakhq[bot]@users.noreply.github.com>
2022-09-24 14:28:42 +00:00
Jiralite
2487e3bf76 types(Caches): Allow GuildForumThreadManager and GuildTextThreadManager (#8665)
types: allow `GuildForumThreadManager` and `GuildTextThreadManager`

Co-authored-by: kodiakhq[bot] <49736102+kodiakhq[bot]@users.noreply.github.com>
2022-09-24 14:14:43 +00:00
Maksi
578bc951bd fix: RepliableInteraction respect cached generic (#8667)
* fix: RepliableInteraction respect cached generic

* fix: prettier format

* Update packages/discord.js/typings/index.d.ts

Co-authored-by: Jiralite <33201955+Jiralite@users.noreply.github.com>

Co-authored-by: Jiralite <33201955+Jiralite@users.noreply.github.com>
Co-authored-by: kodiakhq[bot] <49736102+kodiakhq[bot]@users.noreply.github.com>
2022-09-24 14:09:24 +00:00
Jiralite
1244854e13 fix(ThreadChannel): Allow editing flags (#8671)
fix(ThreadChannel): allow editing flags

Co-authored-by: kodiakhq[bot] <49736102+kodiakhq[bot]@users.noreply.github.com>
2022-09-24 14:02:30 +00:00
Almeida
b1e190c4f0 fix: allow adding forums to channelTypes (#8658)
Co-authored-by: kodiakhq[bot] <49736102+kodiakhq[bot]@users.noreply.github.com>
2022-09-24 13:37:41 +00:00
Jaworek
fc8ed816e6 fix(GuildChannelManager): typo in flags property name when editing (#8669)
* Update GuildChannelManager.js

* Update index.d.ts

* Update GuildChannelManager.js

* Update index.d.ts
2022-09-23 20:20:46 +00:00
Almeida
abb7226af3 feat(GuildChannelManager): allow editing flags (#8637)
Co-authored-by: kodiakhq[bot] <49736102+kodiakhq[bot]@users.noreply.github.com>
2022-09-21 22:00:06 +00:00
iCrawl
30ceaf7e47 chore: deps 2022-09-21 18:46:51 +02:00
iCrawl
9b40a79b3e fix: focus-ring styles 2022-09-21 15:46:44 +02:00
iCrawl
0b12d6fa10 chore(discord.js): release discord.js 14.4.0 2022-09-21 14:09:39 +02:00
Jiralite
b106956308 feat(Widget): Allow forum channels (#8645) 2022-09-21 02:57:32 +02:00
Jiralite
6f1f465a77 feat(WelcomeChannel): Add forum channel as a type (#8643) 2022-09-21 02:57:18 +02:00
Almeida
eb98372dcd chore: fix proxy-container Dockerfile (#8648) 2022-09-21 02:56:47 +02:00
Jiralite
5048a3d17a feat: Allow forum channels in webhook update event (#8646)
feat: allow forum channels in webhook update event
2022-09-20 11:51:34 +00:00
Jiralite
f0497343f1 docs: Correctly overwrite setRTCRegion method (#8642)
docs: correctly overwrite `setRTCRegion` method

Co-authored-by: kodiakhq[bot] <49736102+kodiakhq[bot]@users.noreply.github.com>
2022-09-19 21:07:58 +00:00
Jiralite
f6f15d8e87 fix: Correct applied tags type (#8641)
* fix: correct applied tags type

* types: this is never a private thread channel

Co-authored-by: kodiakhq[bot] <49736102+kodiakhq[bot]@users.noreply.github.com>
2022-09-19 21:02:36 +00:00
Jiralite
14bbc9150a types: Narrow channel type in thread managers (#8640)
types: narrow channel type in thread managers

Co-authored-by: kodiakhq[bot] <49736102+kodiakhq[bot]@users.noreply.github.com>
2022-09-19 20:00:59 +00:00
Jiralite
a7f816eeb7 fix(ThreadChannel): Make fetchStarterMessage() work in forum posts (#8638)
fix(ThreadChannel): make `fetchStarterMessage()` work in forum posts

Co-authored-by: kodiakhq[bot] <49736102+kodiakhq[bot]@users.noreply.github.com>
2022-09-19 19:55:33 +00:00
Jiralite
802b2394b0 docs(GuildTextThreadManager): Document correct @extend (#8639)
docs(GuildTextThreadManager): document correct `@extend`

Co-authored-by: kodiakhq[bot] <49736102+kodiakhq[bot]@users.noreply.github.com>
2022-09-19 19:50:18 +00:00
iCrawl
c446a84570 build: trigger rebuild 2022-09-19 15:40:57 +02:00
iCrawl
9cf0a4904b chore: patch all versions of tsdoc-config 2022-09-19 15:35:29 +02:00
iCrawl
25dc146247 build: revert to using patch 2022-09-19 15:13:22 +02:00
iCrawl
a2b08aaf3b build: different import for schema 2022-09-19 14:53:57 +02:00
iCrawl
eba9cc6038 chore: deps 2022-09-19 14:41:43 +02:00
Almeida
145eb2fc5d fix: update messageCount/totalMessageSent on message events (#8635)
Co-authored-by: kodiakhq[bot] <49736102+kodiakhq[bot]@users.noreply.github.com>
2022-09-19 00:38:23 +00:00
Almeida
8444576f45 docs(builders/components): document constructors (#8636) 2022-09-19 02:32:28 +02:00
iCrawl
6d43e26676 fix: border color in dark mode 2022-09-18 20:27:04 +02:00
iCrawl
2fc3d86f56 feat: searchbar 2022-09-18 20:16:50 +02:00
Suneet Tipirneni
8a8d519c9c feat: add support for guild forums (#7791)
* feat: add support for guild forums

* feat(webhook): add support for creating forum channel posts

* fix: duplicated docs

* feat: add support for message counts

* feat: add support for latest upstream changes

* fix: serialize forum channels

* types: fix channel unions

* types: fix tests

* types: fix tests (again)

* types: fix tests (again (again))

* chore: make requested changes

* chore: fix bugs and make requested changes

* types: use correct type for guild forum start messages

* chore: remove console.log

* chore: make requested changes

* chore: make requested changes

* chore: fix docs

* Update packages/discord.js/src/managers/GuildForumThreadManager.js

Co-authored-by: Jiralite <33201955+Jiralite@users.noreply.github.com>

* chore: update types

* chore: make requested changes

* chore: Apply suggestions

Co-authored-by: Jaworek <jaworekwiadomosci@gmail.com>
Co-authored-by: Jonathan Rubenstein <jrubcop@gmail.com>

* fix: import `ErrorCodes`

* fix: remove defunct code

* refactor: be consistent with channel class names

* feat(GuildChannel): add flags

* fix: rename file

* refactor: channel flags are everywhere!

* fix: import flags correctly

* chore(ThreadChannel): update message count string

* docs(Channels): correct `@param` type

* docs(Channels): ignore transformGuildDefaultReaction

* refactor: emoji object in tags

* chore: renaming consistency

* fix: document default reaction emojis in patching

* fix(GuildChannelManager): document `defaultThreadRateLimitPerUser`

* chore: semicolon

* docs(ErrorCodes): document `GuildForumMessageRequired`

* refactor: transform default reactions

* docs(APITypes): Add `ChannelFlags`

* fix: convert tags properly

* fix: pass an array of snowflakes

* refactor: handle flags better

* fix(ThreadChannel): receive tags

* fix(PartialGroupDMChannel): nullify `flags`

Apparently did not do this earlier.

* chore: misc sorting

* refactor: nullify emoji on tags if not present

* refactor(ForumChannel): modify returns

* types: protect the thread manager!

Co-authored-by: SpaceEEC <spaceeec@yahoo.com>

* chore: update `ChannelType` usage

* Update index.d.ts

* docs: Update default reaction emoji property names

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

* fix: only `name` is required when editing tags

- discord/discord-api-docs#5458

* types: add tests for `channel.flags`

* fix: allow unsetting the default reaction emoji

* refactor: remove v13 remnants

* docs: add missing closing tag

* feat: add `rateLimitPerUser`

* feat: add missing properties for create guild channel

- discord/discord-api-docs#5474

* refactor(GuildForumThreadManager): refactor message payload

* fix: handle magical `null` case

Co-authored-by: A. Román <kyradiscord@gmail.com>

Co-authored-by: Jiralite <33201955+Jiralite@users.noreply.github.com>
Co-authored-by: Jaworek <jaworekwiadomosci@gmail.com>
Co-authored-by: Jonathan Rubenstein <jrubcop@gmail.com>
Co-authored-by: SpaceEEC <spaceeec@yahoo.com>
Co-authored-by: Almeida <almeidx@pm.me>
Co-authored-by: A. Román <kyradiscord@gmail.com>
2022-09-18 14:23:44 +00:00
Almeida
669c3cd256 refactor: replace usage of deprecated ChannelTypes (#8625)
refactor: use new non-deprecated `ChannelType`s

Co-authored-by: kodiakhq[bot] <49736102+kodiakhq[bot]@users.noreply.github.com>
2022-09-17 13:56:19 +00:00
Suneet Tipirneni
678ceaa014 feat(website): use dropdowns for overloads (#8630)
Co-authored-by: Almeida <almeidx@pm.me>
Co-authored-by: iCrawl <buechler.noel@outlook.com>
2022-09-17 14:09:54 +02:00
iCrawl
0785353efe fix: footer hiding properly 2022-09-17 00:31:28 +02:00
iCrawl
8323926304 fix: overflow in cmdk menu 2022-09-17 00:30:15 +02:00
iCrawl
bccc2c8e89 refactor: light theme for cmdk 2022-09-16 23:42:01 +02:00
iCrawl
1d72663e92 fix: allow usage of ctrl key additionally to metakey 2022-09-16 23:27:44 +02:00
iCrawl
d0a2a6227d fix: prevent default for cmd+k 2022-09-16 23:17:05 +02:00
iCrawl
735e0bf52e feat: search 2022-09-16 23:04:05 +02:00
Almeida
1c5b78fd21 fix(SlashCommandBuilder): missing methods in subcommand builder (#8583) 2022-09-15 20:19:13 +02:00
Almeida
053da5bc91 types(interactions): pass Cached type to return type of methods (#8619) 2022-09-15 20:18:48 +02:00
RedGuy12
fc9653f5ae docs: fix regexps incorrectly being called global (#8624) 2022-09-15 20:15:01 +02:00
Almeida
22ac6b4660 docs: update misleading Client#guildMemberAvailable event description (#8626) 2022-09-15 20:13:55 +02:00
iCrawl
d14d47b62f chore: dep cleanup 2022-09-12 18:46:15 +02:00
Jiralite
a9f003ac9b types: Ensure events possess Client<true> (#8612)
types: ensure events possess `Client<true>`

Co-authored-by: kodiakhq[bot] <49736102+kodiakhq[bot]@users.noreply.github.com>
2022-09-11 18:36:24 +00:00
RedGuy12
1d4cdee321 types(GuildChannelManager): correct fetch return type (#8549)
* types(GuildChannelManager): correct `fetch` return type

* fix(ci): fix the types tests

* fix: fix the docs

* Update packages/discord.js/src/managers/GuildChannelManager.js

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

* types: allow channels in the collection to be null

Signed-off-by: RedGuy12 <61329810+RedGuy12@users.noreply.github.com>

* style: run prettier

Signed-off-by: RedGuy12 <61329810+RedGuy12@users.noreply.github.com>

* test: fix types again

Signed-off-by: RedGuy12 <61329810+RedGuy12@users.noreply.github.com>

* style: run prettier

Signed-off-by: RedGuy12 <61329810+RedGuy12@users.noreply.github.com>

Signed-off-by: RedGuy12 <61329810+RedGuy12@users.noreply.github.com>
Co-authored-by: Almeida <almeidx@pm.me>
Co-authored-by: kodiakhq[bot] <49736102+kodiakhq[bot]@users.noreply.github.com>
2022-09-11 18:29:28 +00:00
Jiralite
8e1afaebdb refactor: Split message send/edit types/documentation (#8590)
* refactor: split message send/edit types

* refactor: move `MessageEditOptions`

Co-authored-by: kodiakhq[bot] <49736102+kodiakhq[bot]@users.noreply.github.com>
2022-09-11 18:22:53 +00:00
advaith
32523325c6 docs(Options): update DefaultMakeCacheSettings (#8585)
Co-authored-by: kodiakhq[bot] <49736102+kodiakhq[bot]@users.noreply.github.com>
2022-09-11 18:16:34 +00:00
iCrawl
7a9e52e63a fix: tiny screen cmdk size 2022-09-09 21:55:35 +02:00
iCrawl
d11edc6397 fix: build script for website 2022-09-09 00:23:42 +02:00
iCrawl
96304d7cc8 feat: command menu 2022-09-09 00:08:59 +02:00
iCrawl
f9e9bfdedc chore: deps 2022-09-09 00:07:56 +02:00
iCrawl
ce1f5c8d47 feat: redirect to old docs for main documentation 2022-09-08 17:05:13 +02:00
advaith
03fb5b0a2f feat(GuildBanManager#create): add deleteMessageSeconds (#8326)
* feat(GuildBanManager#create): add `deleteMessageSeconds`

* Apply suggestions from code review

Co-authored-by: Jiralite <33201955+Jiralite@users.noreply.github.com>

* chore: remove typeof and return undefined if neither are set

Co-authored-by: Jiralite <33201955+Jiralite@users.noreply.github.com>
Co-authored-by: kodiakhq[bot] <49736102+kodiakhq[bot]@users.noreply.github.com>
2022-09-08 13:15:01 +00:00
RedGuy12
ce991dd1d8 test: rename incorrect test (#8596) 2022-09-08 15:08:28 +02:00
Parbez
dbca93098c chore: remove unused eslint disable comments (#8595) 2022-09-08 15:08:04 +02:00
A. Román
dd5a08944c docs: change name (#8604) 2022-09-08 01:46:41 +02:00
iCrawl
8e98ba94d2 fix: properly center badge text 2022-09-07 22:57:35 +02:00
iCrawl
74dc8c10d5 fix: hide menu on click 2022-09-07 19:19:58 +02:00
iCrawl
8d07ea9a62 fix: dark/light theme fixes 2022-09-07 18:39:02 +02:00
iCrawl
d8e774138d fix: accessibility improvements 2022-09-07 11:29:58 +02:00
Maksi
55c3ee20ae feat: add typeguard to BaseInteraction#isRepliable (#8565)
* feat: add typeguard to BaseInteraction#isRepliable

* fix: redefine RepliableInteraaction

...to exclude impossible interactions rather than specify possible ones

Co-authored-by: Jiralite <33201955+Jiralite@users.noreply.github.com>

* fix: remove InteractionResponseFields

* fix: replace InteractionResponseFields with RepliableInteraction in index test

Co-authored-by: Jiralite <33201955+Jiralite@users.noreply.github.com>
Co-authored-by: kodiakhq[bot] <49736102+kodiakhq[bot]@users.noreply.github.com>
2022-09-06 17:56:21 +00:00
Noel
c3341570d9 refactor: website components (#8600) 2022-09-06 19:48:33 +02:00
Almeida
f3ce4a75d0 docs: use remarks instead of Note in descriptions (#8597) 2022-09-05 18:14:19 +02:00
iCrawl
4ffdada4f7 chore: deps 2022-09-04 19:33:57 +02:00
Almeida
8b3d006118 feat(Integration): add scopes (#8483) 2022-09-04 08:11:27 +00:00
Almeida
d08a57cadd feat: add chatInputApplicationCommandMention formatter (#8546)
feat: add `chatInputApplicationCommandMention()` formatter

Co-authored-by: kodiakhq[bot] <49736102+kodiakhq[bot]@users.noreply.github.com>
2022-09-03 07:17:06 +00:00
iCrawl
0dc68445a1 refactor: open graph fixes 2022-09-03 05:02:16 +02:00
iCrawl
a7ad7e75ce feat: open graph 2022-09-03 04:48:33 +02:00
Suneet Tipirneni
f79ccb4971 chore(website): bump api-extractor-model (#8584) 2022-09-03 01:14:00 +02:00
iCrawl
6f2b223c8b refactor: extract create model function 2022-09-03 01:01:40 +02:00
iCrawl
a4777aa9b0 feat: add naive client-based search 2022-09-03 00:42:34 +02:00
iCrawl
f072d3d916 feat: redirect to latest version, otherwise click select version button 2022-09-02 22:42:12 +02:00
iCrawl
0238588067 build: fix website build 2022-09-02 22:07:19 +02:00
iCrawl
1d460e0434 chore: deps 2022-09-02 21:48:05 +02:00
RedGuy12
b9c62ac0f0 types(ThreadChannel): fetchStarterMessage must return a Message<true> (#8560)
Signed-off-by: RedGuy12 <61329810+RedGuy12@users.noreply.github.com>

Signed-off-by: RedGuy12 <61329810+RedGuy12@users.noreply.github.com>
Co-authored-by: kodiakhq[bot] <49736102+kodiakhq[bot]@users.noreply.github.com>
2022-09-02 18:44:39 +00:00
iCrawl
df46ab8061 build: tsup for better cjs / esm support 2022-09-02 18:08:16 +02:00
A. Román
b7eb96d456 types(interactions): fix {Slash,ContextMenu}CommandBuilder#toJSON (#8568) 2022-09-02 17:31:25 +02:00
D Trombett
f77612a55e types(webhook): avatar can be null (#8541) 2022-09-02 15:30:06 +00:00
Suneet Tipirneni
9b4116b659 chore(website): put seperators between properties (#8576) 2022-09-02 17:20:57 +02:00
Almeida
8a91d7c256 fix: docgen (#8582) 2022-09-01 22:04:58 +02:00
iCrawl
3b7ba4062e chore: fix leftover eslint exceptions 2022-09-01 21:26:09 +02:00
Suneet Tipirneni
edadb9fe5d refactor: use eslint-config-neon for packages. (#8579)
Co-authored-by: Noel <buechler.noel@outlook.com>
2022-09-01 20:50:16 +02:00
Parbez
4bdb0593ae chore: bump typescript-eslint to support ts 4.8 (#8573) 2022-08-30 22:23:00 +02:00
iCrawl
fd97da9b6c chore: missing config files 2022-08-29 21:48:12 +02:00
Suneet Tipirneni
d5dcddd350 feat: add util package for generating search indices (#8571) 2022-08-29 21:41:51 +02:00
Suneet Tipirneni
40324574eb docs: remove xml tag from collection#find (#8550) 2022-08-29 18:05:30 +02:00
A. Román
1398af66f0 chore(github): resolved typos in issue templates (#8564) 2022-08-29 18:04:37 +02:00
iCrawl
682e0e1802 fix: don't prefetch as links enter viewport 2022-08-26 12:00:25 +02:00
iCrawl
13baf75cae chore: return error 2022-08-24 06:09:39 +02:00
iCrawl
1d6b31b78d fix: revalidate on notFound 2022-08-24 05:42:43 +02:00
iCrawl
5f093dde24 chore: log errors as errors 2022-08-24 05:36:10 +02:00
iCrawl
b58e6a65ad fix: don't throw on not serializable kind 2022-08-24 05:23:03 +02:00
iCrawl
204f4dd7c4 chore: some logging 2022-08-23 22:37:19 +02:00
iCrawl
249ba0a9a6 refactor: contrast & colors 2022-08-23 21:31:38 +02:00
iCrawl
92933c2b61 refactor: memoize everything 2022-08-23 19:39:31 +02:00
iCrawl
abd3fc8ceb fix: properly 404 and revalidate 2022-08-23 18:53:38 +02:00
iCrawl
84059b6b25 fix: affix position when ToC is visible 2022-08-23 17:32:03 +02:00
iCrawl
6da405668f chore: just in case 2022-08-23 17:30:26 +02:00
iCrawl
58d2a1e6d7 chore: deps 2022-08-23 15:17:17 +02:00
iCrawl
7b5c688844 fix: mobile centering 2022-08-23 14:21:48 +02:00
iCrawl
28bc4f42c6 feat: light theme code blocks 2022-08-23 14:00:02 +02:00
iCrawl
5b4672bad3 refactor: css 2022-08-23 13:21:32 +02:00
iCrawl
a57b9ba5c4 refactor: mobile layout for badges 2022-08-23 12:54:40 +02:00
iCrawl
32da9b3868 fix: footer and sidebar mobile spacing 2022-08-23 12:06:18 +02:00
iCrawl
70806b401e style: type import 2022-08-23 12:01:48 +02:00
iCrawl
0674820723 style: spacing 2022-08-23 11:20:08 +02:00
iCrawl
2d5bce274c fix: footer on mobile 2022-08-23 11:13:39 +02:00
iCrawl
331dedcb9d refactor: front page 2022-08-23 10:57:34 +02:00
iCrawl
103e1bd843 feat: add footer links 2022-08-23 10:11:07 +02:00
iCrawl
ffafde0b6b refactor: make dark theme the default 2022-08-23 09:36:19 +02:00
iCrawl
28422eea58 fix: spacing of footer and affix 2022-08-23 09:15:33 +02:00
iCrawl
c826ad3ade feat: markdown syntax highlighting 2022-08-23 08:48:44 +02:00
iCrawl
17559becef refactor: change radius 2022-08-23 08:18:36 +02:00
iCrawl
b31a23b37c build: "no default export" 2022-08-23 08:01:09 +02:00
iCrawl
8e4f77a63b build: use module 2022-08-23 07:55:41 +02:00
iCrawl
b16ab8c69f fix: check if router is ready before using its path 2022-08-23 07:07:22 +02:00
iCrawl
cf8570c19c style: spacing on mobile 2022-08-23 07:05:48 +02:00
iCrawl
f0ab393411 fix: use correct icon on version select 2022-08-23 05:22:18 +02:00
iCrawl
11e02f1e5d refactor: include item kind into url 2022-08-23 05:13:53 +02:00
iCrawl
206523587a refactor: split out package constant 2022-08-23 04:20:41 +02:00
iCrawl
ac3bc6a2db style: spacing 2022-08-23 04:11:12 +02:00
iCrawl
af295acedc fix: wrong active item after anchor select 2022-08-23 03:59:53 +02:00
iCrawl
caa5c0332f feat: add anchor icon 2022-08-23 03:06:21 +02:00
iCrawl
434f696397 refactor: reset state and code cleanup 2022-08-23 02:38:53 +02:00
iCrawl
6062d361fb feat: more fallback cases 2022-08-23 02:13:10 +02:00
iCrawl
2ecb862e76 feat: use fallback with loading 2022-08-23 01:43:10 +02:00
iCrawl
360936140b fix: don't persist state between pages 2022-08-23 01:26:57 +02:00
iCrawl
0b56184ba7 fix: github link and light theme hover nav link 2022-08-23 01:21:28 +02:00
iCrawl
a55545850a refactor: better spacing 2022-08-23 01:02:46 +02:00
iCrawl
f16b11a91d feat: active navigation and back button 2022-08-23 00:44:09 +02:00
iCrawl
0fb2694871 refactor: switch to ssr for unbuilt pages 2022-08-23 00:13:04 +02:00
iCrawl
ee030003ec fix: markdown images and links 2022-08-22 23:58:49 +02:00
iCrawl
29c51be1f4 feat: custom 404 2022-08-22 23:58:33 +02:00
iCrawl
43a78be70b fix: return 404 if a fetch error or no data is returned 2022-08-22 23:29:23 +02:00
iCrawl
92c0c60519 feat: version picker 2022-08-22 23:08:23 +02:00
iCrawl
ba3e0ed348 fix: footer / sidebar / deprecation alert 2022-08-22 22:15:50 +02:00
iCrawl
f7ce9f8533 feat: footer 2022-08-22 21:52:17 +02:00
iCrawl
00990c93ae chore: missing vercel banner 2022-08-22 21:06:34 +02:00
iCrawl
c076b0d8cb fix: don't redirect to the first item 2022-08-22 21:02:15 +02:00
iCrawl
d297fb0b69 feat: readme if no member is selected 2022-08-22 20:51:43 +02:00
iCrawl
24c128d649 feat: experiment with spotlight 2022-08-22 19:44:56 +02:00
iCrawl
ec7c6e3d3e fix: selecting packages on the sidebar 2022-08-22 18:38:07 +02:00
iCrawl
6dfb9bbc48 feat: generate all tags 2022-08-22 18:30:46 +02:00
Suneet Tipirneni
4644e45e85 fix(website): use inter font for titles (#8542)
Co-authored-by: Noel <buechler.noel@outlook.com>
2022-08-22 18:29:26 +02:00
iCrawl
1e001601c8 refactor: change url scheme 2022-08-22 16:50:43 +02:00
iCrawl
1aec243b1d feat: packages route 2022-08-22 16:01:42 +02:00
iCrawl
191951ac28 feat: add ToC to interfaces 2022-08-22 15:38:47 +02:00
iCrawl
4fb4492b17 refactor: icons and head 2022-08-22 15:34:21 +02:00
iCrawl
abb968de81 feat: favicon 2022-08-22 14:57:51 +02:00
iCrawl
d9e53093f5 fix: properly check for properties and methods 2022-08-22 14:32:59 +02:00
iCrawl
e5678f4656 feat: list properties and method in table of content 2022-08-22 14:30:15 +02:00
iCrawl
9f18036078 fix: hydration error 2022-08-22 14:29:31 +02:00
iCrawl
474eae0afc style: change how optionals are displayed 2022-08-22 14:19:02 +02:00
iCrawl
caeb66e150 fix: overflowing content 2022-08-22 14:12:53 +02:00
iCrawl
7623fc552e ci: don't double check inputs 2022-08-22 12:11:45 +02:00
iCrawl
230c43e97d build: fix downlevel-dts 2022-08-22 11:29:57 +02:00
iCrawl
4e3fa586b5 chore(discord.js): release discord.js@14.3.0 2022-08-22 10:56:30 +02:00
Jiralite
6bb1474d20 types: Inference of guild in MessageManager (#8538)
* types: better inference of message manager

* types: alter helper methods

Co-authored-by: kodiakhq[bot] <49736102+kodiakhq[bot]@users.noreply.github.com>
2022-08-22 08:31:02 +00:00
iCrawl
27bbc8fe68 chore(builders): release @discordjs/builders@1.2.0 2022-08-22 10:10:19 +02:00
iCrawl
e2cde5daa0 chore(collection): release @discordjs/collection@1.1.0 2022-08-22 10:08:38 +02:00
iCrawl
0960457108 chore: update proxy and rest in proxy-container 2022-08-22 10:07:22 +02:00
iCrawl
cd6b365b17 chore: changelog 2022-08-22 10:06:49 +02:00
436 changed files with 13899 additions and 9403 deletions

View File

@@ -1,9 +1,12 @@
{
"root": true,
"extends": "marine/prettier/node",
"extends": ["neon/common", "neon/node", "neon/typescript", "neon/prettier"],
"parserOptions": {
"project": "./tsconfig.eslint.json"
},
"rules": {
"@typescript-eslint/consistent-type-definitions": ["error", "interface"]
},
"ignorePatterns": ["**/dist/*"],
"env": {
"jest": true

View File

@@ -52,7 +52,7 @@ body:
id: djs-version
attributes:
label: Package version
description: Which version of are you using? Run `npm list <package>` in your project directory and paste the output.
description: Which version of the package are you using? Run `npm list <package>` in your project directory and paste the output.
placeholder: We no longer support version 12 or earlier of discord.js
validations:
required: true

View File

@@ -5,7 +5,7 @@ body:
- type: markdown
attributes:
value: |
We can only implement features that Discord publishes, documents and merges into the Discord API documentation.
We can only implement features that Discord publishes, documents, and merges into the Discord API documentation.
We do not implement unreleased features.
Use Discord for questions: https://discord.gg/djs
- type: dropdown

4
.github/labeler.yml vendored
View File

@@ -37,3 +37,7 @@
'packages:ws':
- packages/ws/*
- packages/ws/**/*
'packages:util':
- packages/util/*
- packages/util/**/*

2
.github/labels.yml vendored
View File

@@ -66,6 +66,8 @@
color: 'fbca04'
- name: 'packages:ws'
color: 'fbca04'
- name: 'packages:util'
color: 'fbca04'
- name: 'performance'
color: '80c042'
- name: 'permissions'

View File

@@ -79,7 +79,7 @@ jobs:
max-parallel: 1
fail-fast: false
matrix:
package: ['builders', 'collection', 'discord.js', 'proxy', 'rest', 'voice', 'ws']
package: ['builders', 'collection', 'discord.js', 'proxy', 'rest', 'util', 'voice', 'ws']
runs-on: ubuntu-latest
env:
TURBO_TOKEN: ${{ secrets.TURBO_TOKEN }}
@@ -123,14 +123,14 @@ jobs:
path: 'out'
- name: Extract package and semver from tag
if: ${{ github.event.inputs.ref_type == 'tag' || env.BRANCH_OR_TAG == 'tag' }}
if: ${{ env.BRANCH_OR_TAG == 'tag' }}
id: extract-tag
uses: ./packages/actions/src/formatTag
with:
tag: ${{ env.BRANCH_NAME }}
- name: Move docs to correct directory
if: ${{ (github.event.inputs.ref_type == 'tag' || env.BRANCH_OR_TAG == 'tag') && matrix.package == steps.extract-tag.outputs.package }}
if: ${{ env.BRANCH_OR_TAG == 'tag' && matrix.package == steps.extract-tag.outputs.package }}
env:
PACKAGE: ${{ steps.extract-tag.outputs.package }}
SEMVER: ${{ steps.extract-tag.outputs.semver }}
@@ -142,7 +142,7 @@ jobs:
fi
- name: Move docs to correct directory
if: ${{ github.event.inputs.ref_type == 'branch' || env.BRANCH_OR_TAG == 'branch' }}
if: ${{ env.BRANCH_OR_TAG == 'branch' }}
env:
PACKAGE: ${{ matrix.package }}
run: |

View File

@@ -22,6 +22,6 @@ jobs:
run: yarn --immutable
- name: Deprecate versions
run: 'yarn npm-deprecate --name "*dev*" --package @discordjs/builders @discordjs/collection discord.js @discordjs/proxy @discordjs/rest @discordjs/voice'
run: 'yarn npm-deprecate --name "*dev*" --package @discordjs/builders @discordjs/collection discord.js @discordjs/proxy @discordjs/rest @discordjs/util @discordjs/voice'
env:
NODE_AUTH_TOKEN: ${{ secrets.NPM_PUBLISH_TOKEN }}

View File

@@ -20,6 +20,8 @@ jobs:
folder: 'proxy'
- package: '@discordjs/rest'
folder: 'rest'
- package: '@discordjs/util'
folder: 'util'
- package: '@discordjs/voice'
folder: 'voice'
- package: '@discordjs/ws'

View File

@@ -1,4 +1,4 @@
#!/bin/sh
. "$(dirname "$0")/_/husky.sh"
yarn build && yarn lint-staged
yarn build && yarn workspace @discordjs/website run build:local && yarn lint-staged

View File

@@ -1,95 +0,0 @@
import { relative, resolve } from 'node:path';
import glob from 'fast-glob';
import isCi from 'is-ci';
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 = isCi,
}: 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,
preferConst: true,
},
},
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,
},
},
}),
);
}
},
},
});
}

View File

@@ -18,7 +18,7 @@
"Amish Shah <amishshah.2k@gmail.com>",
"Vlad Frangu <kingdgrizzle@gmail.com>",
"SpaceEEC <spaceeec@yahoo.com>",
"Antonio Roman <kyradiscord@gmail.com>"
"Aura Román <kyradiscord@gmail.com>"
],
"keywords": [
"discord",
@@ -37,18 +37,17 @@
},
"homepage": "https://discord.js.org",
"devDependencies": {
"@commitlint/cli": "^17.0.3",
"@commitlint/config-angular": "^17.0.3",
"@commitlint/cli": "^17.1.2",
"@commitlint/config-angular": "^17.1.0",
"@favware/cliff-jumper": "^1.8.7",
"@favware/npm-deprecate": "^1.0.5",
"@types/is-ci": "^3.0.0",
"conventional-changelog-cli": "^2.2.2",
"fast-glob": "^3.2.11",
"husky": "^8.0.1",
"is-ci": "^3.0.1",
"lint-staged": "^13.0.3",
"turbo": "^1.4.3",
"typescript": "^4.7.4"
"tsup": "^6.2.3",
"turbo": "^1.5.3",
"typescript": "^4.8.3"
},
"resolutions": {
"@microsoft/tsdoc-config": "patch:@microsoft/tsdoc-config@npm:0.16.1#.yarn/patches/@microsoft-tsdoc-config-npm-0.16.1-81031b1bbf.patch"

View File

@@ -1,5 +1,5 @@
import { describe, test, expect } from 'vitest';
import { formatTag } from '../src';
import { formatTag } from '../src/index.js';
describe('Format Tag', () => {
test('GIVEN tag with a prefix THEN format tag to not contain the prefix', () => {

View File

@@ -1,11 +0,0 @@
import { createUnbuildConfig } from '../../build.config';
export default createUnbuildConfig({
entries: [
{ builder: 'rollup', input: 'src/index' },
{ builder: 'rollup', input: 'src/formatTag/index' },
],
preserveModules: false,
minify: true,
emitCJS: false,
});

View File

@@ -5,9 +5,9 @@
"private": true,
"scripts": {
"test": "vitest run",
"build": "unbuild",
"lint": "prettier --check . && TIMING=1 eslint src __tests__ --ext mjs,js,ts",
"format": "prettier --write . && TIMING=1 eslint src __tests__ --ext mjs,js,ts --fix",
"build": "tsup",
"lint": "prettier --check . && cross-env TIMING=1 eslint src __tests__ --ext mjs,js,ts",
"format": "prettier --write . && cross-env TIMING=1 eslint src __tests__ --ext mjs,js,ts --fix",
"fmt": "yarn format"
},
"main": "./dist/index.mjs",
@@ -43,20 +43,15 @@
"tslib": "^2.4.0"
},
"devDependencies": {
"@types/node": "^16.11.52",
"@typescript-eslint/eslint-plugin": "^5.33.1",
"@typescript-eslint/parser": "^5.33.1",
"@vitest/coverage-c8": "^0.22.1",
"eslint": "^8.22.0",
"eslint-config-marine": "^9.4.1",
"eslint-config-prettier": "^8.5.0",
"eslint-import-resolver-typescript": "^3.4.2",
"eslint-plugin-import": "^2.26.0",
"@types/node": "^16.11.60",
"@vitest/coverage-c8": "^0.23.4",
"cross-env": "^7.0.3",
"eslint": "^8.24.0",
"eslint-config-neon": "^0.1.33",
"prettier": "^2.7.1",
"rollup-plugin-typescript2": "^0.33.0",
"typescript": "^4.7.4",
"unbuild": "^0.8.9",
"vitest": "^0.22.1"
"tsup": "^6.2.3",
"typescript": "^4.8.3",
"vitest": "^0.23.4"
},
"engines": {
"node": ">=16.9.0"

View File

@@ -11,4 +11,4 @@ outputs:
description: 'The semver string that was extracted from this tag'
runs:
using: node16
main: ../../dist/index.mjs
main: ../../dist/formatTag/index.mjs

View File

@@ -1,4 +1,5 @@
export function formatTag(tag: string) {
// eslint-disable-next-line unicorn/no-unsafe-regex, prefer-named-capture-group
const parsed = /(^@.*\/(?<package>.*)@v?)?(?<semver>\d+.\d+.\d+)-?.*/.exec(tag);
if (parsed?.groups) {

View File

@@ -1,5 +1,5 @@
import { getInput, setOutput } from '@actions/core';
import { formatTag } from './formatTag';
import { formatTag } from './formatTag.js';
const tag = getInput('tag', { required: true });
const parsed = formatTag(tag);

View File

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

View File

@@ -51,6 +51,12 @@ runs:
files: ./packages/ws/coverage/cobertura-coverage.xml
flags: ws
- name: Upload Util Coverage
uses: codecov/codecov-action@v3
with:
files: ./packages/util/coverage/cobertura-coverage.xml
flags: util
- name: Upload Utilities Coverage
uses: codecov/codecov-action@v3
with:

View File

@@ -0,0 +1,7 @@
import { createTsupConfig } from '../../tsup.config.js';
export default createTsupConfig({
entry: ['src/index.ts', 'src/formatTag/index.ts'],
format: ['esm'],
minify: true,
});

View File

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

27
packages/api-extractor-utils/.gitignore vendored Normal file
View File

@@ -0,0 +1,27 @@
# Packages
node_modules/
# Log files
logs/
*.log
npm-debug.log*
# Runtime data
pids
*.pid
*.seed
# Env
.env
# Dist
dist/
typings/
docs/**/*
!docs/index.json
!docs/README.md
# Miscellaneous
.tmp/
coverage/
tsconfig.tsbuildinfo

View File

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

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,52 @@
{
"name": "@discordjs/api-extractor-utils",
"version": "1.0.0",
"description": "Utilities for api-extractor",
"private": true,
"scripts": {
"build": "tsup",
"lint": "prettier --check . && cross-env TIMING=1 eslint src --ext mjs,js,ts",
"format": "prettier --write . && cross-env TIMING=1 eslint src --ext mjs,js,ts --fix",
"fmt": "yarn format"
},
"main": "./dist/index.js",
"module": "./dist/index.mjs",
"types": "./dist/index.d.ts",
"directories": {
"lib": "src"
},
"files": [
"dist"
],
"contributors": [
"Suneet Tipirneni <suneettipirneni@icloud.com>"
],
"license": "Apache-2.0",
"repository": {
"type": "git",
"url": "git+https://github.com/discordjs/discord.js.git"
},
"bugs": {
"url": "https://github.com/discordjs/discord.js/issues"
},
"homepage": "https://discord.js.org",
"dependencies": {
"@microsoft/api-extractor-model": "7.24.0",
"@microsoft/tsdoc": "0.14.1"
},
"devDependencies": {
"@types/node": "^16.11.60",
"cross-env": "^7.0.3",
"eslint": "^8.24.0",
"eslint-config-neon": "^0.1.33",
"prettier": "^2.7.1",
"tsup": "^6.2.3",
"typescript": "^4.8.3"
},
"engines": {
"node": ">=16.9.0"
},
"publishConfig": {
"access": "public"
}
}

View File

@@ -1,37 +1,30 @@
import type { ApiReturnTypeMixin } from '@microsoft/api-extractor-model';
import {
ApiModel,
type ApiModel,
ApiDeclaredItem,
ApiPropertyItem,
ApiMethod,
ApiParameterListMixin,
ApiTypeParameterListMixin,
ApiClass,
ApiFunction,
type ApiPropertyItem,
type ApiMethod,
type ApiParameterListMixin,
type ApiTypeParameterListMixin,
type ApiClass,
type ApiFunction,
ApiItemKind,
ApiTypeAlias,
ApiEnum,
ApiInterface,
ApiMethodSignature,
ApiPropertySignature,
ApiVariable,
ApiItem,
ApiConstructor,
ApiItemContainerMixin,
type ApiTypeAlias,
type ApiEnum,
type ApiInterface,
type ApiMethodSignature,
type ApiPropertySignature,
type ApiVariable,
type ApiItem,
type ApiConstructor,
type ApiItemContainerMixin,
} from '@microsoft/api-extractor-model';
import { generateTypeParamData } from './TypeParameterMixin';
import { Visibility } from './Visibility';
import { createCommentNode } from './comment';
import type { DocBlockJSON } from './comment/CommentBlock';
import type { AnyDocNodeJSON } from './comment/CommentNode';
import { DocNodeContainerJSON, nodeContainer } from './comment/CommentNodeContainer';
import {
generatePath,
genParameter,
genReference,
genToken,
resolveName,
TokenDocumentation,
} from '~/util/parse.server';
import { generateTypeParamData } from './TypeParameterJSONEncoder.js';
import { type TokenDocumentation, resolveName, genReference, genToken, genParameter, generatePath } from './parse.js';
import type { DocBlockJSON } from './tsdoc/CommentBlock.js';
import type { AnyDocNodeJSON } from './tsdoc/CommentNode.js';
import { type DocNodeContainerJSON, nodeContainer } from './tsdoc/CommentNodeContainer.js';
import { createCommentNode } from './tsdoc/index.js';
export interface ReferenceData {
name: string;
@@ -39,9 +32,9 @@ export interface ReferenceData {
}
export interface InheritanceData {
parentKey: string;
parentName: string;
path: string;
parentKey: string;
}
export interface ApiInheritableJSON {
@@ -49,23 +42,23 @@ export interface ApiInheritableJSON {
}
export interface ApiItemJSON {
kind: string;
name: string;
referenceData: ReferenceData;
excerpt: string;
excerptTokens: TokenDocumentation[];
remarks: DocNodeContainerJSON | null;
summary: DocNodeContainerJSON | null;
deprecated: DocNodeContainerJSON | null;
comment: AnyDocNodeJSON | null;
containerKey: string;
deprecated: DocNodeContainerJSON | null;
excerpt: string;
excerptTokens: TokenDocumentation[];
kind: string;
name: string;
path: string[];
referenceData: ReferenceData;
remarks: DocNodeContainerJSON | null;
summary: DocNodeContainerJSON | null;
}
export interface ApiPropertyItemJSON extends ApiItemJSON, ApiInheritableJSON {
optional: boolean;
propertyTypeTokens: TokenDocumentation[];
readonly: boolean;
optional: boolean;
}
export interface ApiTypeParameterListJSON {
@@ -73,11 +66,11 @@ export interface ApiTypeParameterListJSON {
}
export interface ApiTypeParameterJSON {
name: string;
commentBlock: DocBlockJSON | null;
constraintTokens: TokenDocumentation[];
defaultTokens: TokenDocumentation[];
name: string;
optional: boolean;
commentBlock: DocBlockJSON | null;
}
export interface ApiParameterListJSON {
@@ -89,29 +82,31 @@ export interface ApiMethodSignatureJSON
ApiTypeParameterListJSON,
ApiParameterListJSON,
ApiInheritableJSON {
returnTypeTokens: TokenDocumentation[];
mergedSiblings: ApiMethodSignatureJSON[];
optional: boolean;
overloadIndex: number;
returnTypeTokens: TokenDocumentation[];
}
export interface ApiMethodJSON extends ApiMethodSignatureJSON {
mergedSiblings: ApiMethodJSON[];
protected: boolean;
static: boolean;
visibility: Visibility;
}
export interface ApiParameterJSON {
name: string;
isOptional: boolean;
tokens: TokenDocumentation[];
name: string;
paramCommentBlock: DocBlockJSON | null;
tokens: TokenDocumentation[];
}
export interface ApiClassJSON extends ApiItemJSON, ApiTypeParameterListJSON {
constructor: ApiConstructorJSON | null;
properties: ApiPropertyItemJSON[];
methods: ApiMethodJSON[];
extendsTokens: TokenDocumentation[];
implementsTokens: TokenDocumentation[][];
methods: ApiMethodJSON[];
properties: ApiPropertyItemJSON[];
}
export interface ApiTypeAliasJSON extends ApiItemJSON, ApiTypeParameterListJSON {
@@ -119,8 +114,8 @@ export interface ApiTypeAliasJSON extends ApiItemJSON, ApiTypeParameterListJSON
}
export interface EnumMemberData {
name: string;
initializerTokens: TokenDocumentation[];
name: string;
summary: DocNodeContainerJSON | null;
}
@@ -129,51 +124,55 @@ export interface ApiEnumJSON extends ApiItemJSON {
}
export interface ApiInterfaceJSON extends ApiItemJSON, ApiTypeParameterListJSON {
properties: ApiPropertyItemJSON[];
methods: ApiMethodSignatureJSON[];
extendsTokens: TokenDocumentation[][] | null;
methods: ApiMethodSignatureJSON[];
properties: ApiPropertyItemJSON[];
}
export interface ApiVariableJSON extends ApiItemJSON {
typeTokens: TokenDocumentation[];
readonly: boolean;
typeTokens: TokenDocumentation[];
}
export interface ApiFunctionJSON extends ApiItemJSON, ApiTypeParameterListJSON, ApiParameterListJSON {
returnTypeTokens: TokenDocumentation[];
mergedSiblings: ApiFunctionJSON[];
overloadIndex: number;
returnTypeTokens: TokenDocumentation[];
}
export interface ApiConstructorJSON extends ApiItemJSON, ApiParameterListJSON {
protected: boolean;
}
// eslint-disable-next-line @typescript-eslint/no-extraneous-class
export type FunctionLike = ApiDeclaredItem & ApiParameterListMixin & ApiReturnTypeMixin & ApiTypeParameterListMixin;
export class ApiNodeJSONEncoder {
public static encode(model: ApiModel, node: ApiItem) {
public static encode(model: ApiModel, node: ApiItem, version: string) {
if (!(node instanceof ApiDeclaredItem)) {
throw new Error(`Cannot serialize node of type ${node.kind}`);
console.log(`Cannot serialize node of type ${node.kind}`);
return undefined;
}
switch (node.kind) {
case ApiItemKind.Class:
return this.encodeClass(model, node as ApiClass);
return this.encodeClass(model, node as ApiClass, version);
case ApiItemKind.Function:
return this.encodeFunction(model, node as ApiFunction);
return this.encodeFunction(model, node as ApiFunction, version);
case ApiItemKind.Interface:
return this.encodeInterface(model, node as ApiInterface);
return this.encodeInterface(model, node as ApiInterface, version);
case ApiItemKind.TypeAlias:
return this.encodeTypeAlias(model, node as ApiTypeAlias);
return this.encodeTypeAlias(model, node as ApiTypeAlias, version);
case ApiItemKind.Enum:
return this.encodeEnum(model, node as ApiEnum);
return this.encodeEnum(model, node as ApiEnum, version);
case ApiItemKind.Variable:
return this.encodeVariable(model, node as ApiVariable);
return this.encodeVariable(model, node as ApiVariable, version);
default:
throw new Error(`Unknown API item kind: ${node.kind}`);
// console.log(`Unknown API item kind: ${node.kind}`);
return undefined;
}
}
public static encodeItem(model: ApiModel, item: ApiDeclaredItem): ApiItemJSON {
public static encodeItem(model: ApiModel, item: ApiDeclaredItem, version: string): ApiItemJSON {
const path = [];
for (const _item of item.getHierarchy()) {
switch (_item.kind) {
@@ -189,36 +188,41 @@ export class ApiNodeJSONEncoder {
return {
kind: item.kind,
name: resolveName(item),
referenceData: genReference(item),
referenceData: genReference(item, version),
excerpt: item.excerpt.text,
excerptTokens: item.excerpt.spannedTokens.map((token) => genToken(model, token)),
excerptTokens: item.excerpt.spannedTokens.map((token) => genToken(model, token, version)),
remarks: item.tsdocComment?.remarksBlock
? (createCommentNode(item.tsdocComment.remarksBlock, model, item.parent) as DocNodeContainerJSON)
? (createCommentNode(item.tsdocComment.remarksBlock, model, version, item.parent) as DocNodeContainerJSON)
: null,
summary: item.tsdocComment?.summarySection
? (createCommentNode(item.tsdocComment.summarySection, model, item.parent) as DocNodeContainerJSON)
? (createCommentNode(item.tsdocComment.summarySection, model, version, item.parent) as DocNodeContainerJSON)
: null,
deprecated: item.tsdocComment?.deprecatedBlock
? (createCommentNode(item.tsdocComment.deprecatedBlock, model, item.parent) as DocNodeContainerJSON)
? (createCommentNode(item.tsdocComment.deprecatedBlock, model, version, item.parent) as DocNodeContainerJSON)
: null,
path,
containerKey: item.containerKey,
comment: item.tsdocComment ? createCommentNode(item.tsdocComment, model, item.parent) : null,
comment: item.tsdocComment ? createCommentNode(item.tsdocComment, model, version, item.parent) : null,
};
}
public static encodeParameterList(
model: ApiModel,
item: ApiParameterListMixin & ApiDeclaredItem,
item: ApiDeclaredItem & ApiParameterListMixin,
version: string,
): { parameters: ApiParameterJSON[] } {
return {
parameters: item.parameters.map((param) => genParameter(model, param)),
parameters: item.parameters.map((param) => genParameter(model, param, version)),
};
}
public static encodeTypeParameterList(model: ApiModel, item: ApiTypeParameterListMixin & ApiDeclaredItem) {
public static encodeTypeParameterList(
model: ApiModel,
item: ApiDeclaredItem & ApiTypeParameterListMixin,
version: string,
): ApiTypeParameterListJSON {
return {
typeParameters: item.typeParameters.map((param) => generateTypeParamData(model, param, item.parent)),
typeParameters: item.typeParameters.map((param) => generateTypeParamData(model, param, version, item.parent)),
};
}
@@ -226,60 +230,90 @@ export class ApiNodeJSONEncoder {
model: ApiModel,
item: ApiPropertyItem,
parent: ApiItemContainerMixin,
version: string,
): ApiPropertyItemJSON {
return {
...this.encodeItem(model, item),
...this.encodeInheritanceData(item, parent),
propertyTypeTokens: item.propertyTypeExcerpt.spannedTokens.map((token) => genToken(model, token)),
...this.encodeItem(model, item, version),
...this.encodeInheritanceData(item, parent, version),
propertyTypeTokens: item.propertyTypeExcerpt.spannedTokens.map((token) => genToken(model, token, version)),
readonly: item.isReadonly,
optional: item.isOptional,
};
}
public static encodeInheritanceData(item: ApiDeclaredItem, parent: ApiItemContainerMixin): ApiInheritableJSON {
public static encodeInheritanceData(
item: ApiDeclaredItem,
parent: ApiItemContainerMixin,
version: string,
): ApiInheritableJSON {
return {
inheritanceData:
item.parent && item.parent.containerKey !== parent.containerKey
? {
parentKey: item.parent.containerKey,
parentName: item.parent.displayName,
path: generatePath(item.parent.getHierarchy()),
path: generatePath(item.parent.getHierarchy(), version),
}
: null,
};
}
public static encodeFunction(model: ApiModel, item: ApiFunction) {
public static encodeFunctionLike(model: ApiModel, item: FunctionLike, version: string) {
return {
...this.encodeItem(model, item),
...this.encodeParameterList(model, item),
...this.encodeTypeParameterList(model, item),
returnTypeTokens: item.returnTypeExcerpt.spannedTokens.map((token) => genToken(model, token)),
...this.encodeItem(model, item, version),
...this.encodeParameterList(model, item, version),
...this.encodeTypeParameterList(model, item, version),
returnTypeTokens: item.returnTypeExcerpt.spannedTokens.map((token) => genToken(model, token, version)),
overloadIndex: item.overloadIndex,
};
}
public static encodeFunction(model: ApiModel, item: FunctionLike, version: string, nested = false): ApiFunctionJSON {
return {
...this.encodeFunctionLike(model, item, version),
mergedSiblings: nested
? []
: item.getMergedSiblings().map((item) => this.encodeFunction(model, item as ApiFunction, version, true)),
};
}
public static encodeMethodSignature(
model: ApiModel,
item: ApiMethodSignature,
parent: ApiItemContainerMixin,
version: string,
nested = false,
): ApiMethodSignatureJSON {
return {
...this.encodeFunction(model, item),
...this.encodeInheritanceData(item, parent),
...this.encodeFunctionLike(model, item, version),
...this.encodeInheritanceData(item, parent, version),
optional: item.isOptional,
mergedSiblings: nested
? []
: item
.getMergedSiblings()
.map((item) => this.encodeMethodSignature(model, item as ApiMethodSignature, parent, version, true)),
};
}
public static encodeMethod(model: ApiModel, item: ApiMethod, parent: ApiItemContainerMixin): ApiMethodJSON {
public static encodeMethod(
model: ApiModel,
item: ApiMethod,
parent: ApiItemContainerMixin,
version: string,
nested = false,
): ApiMethodJSON {
return {
...this.encodeMethodSignature(model, item, parent),
...this.encodeMethodSignature(model, item, parent, version),
static: item.isStatic,
visibility: item.isProtected ? Visibility.Protected : Visibility.Public,
protected: item.isProtected,
mergedSiblings: nested
? []
: item.getMergedSiblings().map((item) => this.encodeMethod(model, item as ApiMethod, parent, version, true)),
};
}
public static encodeClass(model: ApiModel, item: ApiClass): ApiClassJSON {
public static encodeClass(model: ApiModel, item: ApiClass, version: string): ApiClassJSON {
const extendsExcerpt = item.extendsType?.excerpt;
const methods: ApiMethodJSON[] = [];
@@ -290,10 +324,10 @@ export class ApiNodeJSONEncoder {
for (const member of item.findMembersWithInheritance().items) {
switch (member.kind) {
case ApiItemKind.Method:
methods.push(this.encodeMethod(model, member as ApiMethod, item));
methods.push(this.encodeMethod(model, member as ApiMethod, item, version));
break;
case ApiItemKind.Property:
properties.push(this.encodeProperty(model, member as ApiPropertyItem, item));
properties.push(this.encodeProperty(model, member as ApiPropertyItem, item, version));
break;
case ApiItemKind.Constructor:
constructor = member as ApiConstructor;
@@ -304,48 +338,49 @@ export class ApiNodeJSONEncoder {
}
return {
...this.encodeItem(model, item),
...this.encodeTypeParameterList(model, item),
constructor: constructor ? this.encodeConstructor(model, constructor) : null,
extendsTokens: extendsExcerpt ? extendsExcerpt.spannedTokens.map((token) => genToken(model, token)) : [],
...this.encodeItem(model, item, version),
...this.encodeTypeParameterList(model, item, version),
constructor: constructor ? this.encodeConstructor(model, constructor, version) : null,
extendsTokens: extendsExcerpt ? extendsExcerpt.spannedTokens.map((token) => genToken(model, token, version)) : [],
implementsTokens: item.implementsTypes.map((excerpt) =>
excerpt.excerpt.spannedTokens.map((token) => genToken(model, token)),
excerpt.excerpt.spannedTokens.map((token) => genToken(model, token, version)),
),
methods,
properties,
};
}
public static encodeTypeAlias(model: ApiModel, item: ApiTypeAlias): ApiTypeAliasJSON {
public static encodeTypeAlias(model: ApiModel, item: ApiTypeAlias, version: string): ApiTypeAliasJSON {
return {
...this.encodeItem(model, item),
...this.encodeTypeParameterList(model, item),
typeTokens: item.typeExcerpt.spannedTokens.map((token) => genToken(model, token)),
...this.encodeItem(model, item, version),
...this.encodeTypeParameterList(model, item, version),
typeTokens: item.typeExcerpt.spannedTokens.map((token) => genToken(model, token, version)),
};
}
public static encodeEnum(model: ApiModel, item: ApiEnum): ApiEnumJSON {
public static encodeEnum(model: ApiModel, item: ApiEnum, version: string): ApiEnumJSON {
return {
...this.encodeItem(model, item),
...this.encodeItem(model, item, version),
members: item.members.map((member) => ({
name: member.name,
initializerTokens: member.initializerExcerpt?.spannedTokens.map((token) => genToken(model, token)) ?? [],
summary: member.tsdocComment ? nodeContainer(member.tsdocComment.summarySection, model, member) : null,
initializerTokens:
member.initializerExcerpt?.spannedTokens.map((token) => genToken(model, token, version)) ?? [],
summary: member.tsdocComment ? nodeContainer(member.tsdocComment.summarySection, model, version, member) : null,
})),
};
}
public static encodeInterface(model: ApiModel, item: ApiInterface): ApiInterfaceJSON {
public static encodeInterface(model: ApiModel, item: ApiInterface, version: string): ApiInterfaceJSON {
const methods: ApiMethodSignatureJSON[] = [];
const properties: ApiPropertyItemJSON[] = [];
for (const member of item.findMembersWithInheritance().items) {
switch (member.kind) {
case ApiItemKind.MethodSignature:
methods.push(this.encodeMethodSignature(model, member as ApiMethodSignature, item));
methods.push(this.encodeMethodSignature(model, member as ApiMethodSignature, item, version));
break;
case ApiItemKind.PropertySignature:
properties.push(this.encodeProperty(model, member as ApiPropertySignature, item));
properties.push(this.encodeProperty(model, member as ApiPropertySignature, item, version));
break;
default:
break;
@@ -353,28 +388,28 @@ export class ApiNodeJSONEncoder {
}
return {
...this.encodeItem(model, item),
...this.encodeTypeParameterList(model, item),
...this.encodeItem(model, item, version),
...this.encodeTypeParameterList(model, item, version),
extendsTokens: item.extendsTypes.map((excerpt) =>
excerpt.excerpt.spannedTokens.map((token) => genToken(model, token)),
excerpt.excerpt.spannedTokens.map((token) => genToken(model, token, version)),
),
methods,
properties,
};
}
public static encodeVariable(model: ApiModel, item: ApiVariable): ApiVariableJSON {
public static encodeVariable(model: ApiModel, item: ApiVariable, version: string): ApiVariableJSON {
return {
...this.encodeItem(model, item),
typeTokens: item.variableTypeExcerpt.spannedTokens.map((token) => genToken(model, token)),
...this.encodeItem(model, item, version),
typeTokens: item.variableTypeExcerpt.spannedTokens.map((token) => genToken(model, token, version)),
readonly: item.isReadonly,
};
}
public static encodeConstructor(model: ApiModel, item: ApiConstructor): ApiConstructorJSON {
public static encodeConstructor(model: ApiModel, item: ApiConstructor, version: string): ApiConstructorJSON {
return {
...this.encodeItem(model, item),
...this.encodeParameterList(model, item),
...this.encodeItem(model, item, version),
...this.encodeParameterList(model, item, version),
protected: item.isProtected,
};
}

View File

@@ -1,28 +1,31 @@
import type { ApiItem, ApiModel, TypeParameter } from '@microsoft/api-extractor-model';
import { block, DocBlockJSON } from './comment/CommentBlock';
import { genToken, TokenDocumentation } from '~/util/parse.server';
import type { TypeParameter, ApiModel, ApiItem } from '@microsoft/api-extractor-model';
import { type TokenDocumentation, genToken } from './parse.js';
import { type DocBlockJSON, block } from './tsdoc/CommentBlock.js';
export interface TypeParameterData {
name: string;
commentBlock: DocBlockJSON | null;
constraintTokens: TokenDocumentation[];
defaultTokens: TokenDocumentation[];
name: string;
optional: boolean;
commentBlock: DocBlockJSON | null;
}
export function generateTypeParamData(
model: ApiModel,
typeParam: TypeParameter,
version: string,
parentItem?: ApiItem,
): TypeParameterData {
const constraintTokens = typeParam.constraintExcerpt.spannedTokens.map((token) => genToken(model, token));
const defaultTokens = typeParam.defaultTypeExcerpt.spannedTokens.map((token) => genToken(model, token));
const constraintTokens = typeParam.constraintExcerpt.spannedTokens.map((token) => genToken(model, token, version));
const defaultTokens = typeParam.defaultTypeExcerpt.spannedTokens.map((token) => genToken(model, token, version));
return {
name: typeParam.name,
constraintTokens,
defaultTokens,
optional: typeParam.isOptional,
commentBlock: typeParam.tsdocTypeParamBlock ? block(typeParam.tsdocTypeParamBlock, model, parentItem) : null,
commentBlock: typeParam.tsdocTypeParamBlock
? block(typeParam.tsdocTypeParamBlock, model, version, parentItem)
: null,
};
}

View File

@@ -0,0 +1,4 @@
export * from './ApiNodeJSONEncoder.js';
export * from './parse.js';
export * from './tsdoc/index.js';
export * from './TypeParameterJSONEncoder.js';

View File

@@ -10,12 +10,12 @@ import {
type ApiPropertyItem,
type ExcerptToken,
type Parameter,
ApiFunction,
type ApiFunction,
} from '@microsoft/api-extractor-model';
import type { DocNode, DocParagraph, DocPlainText } from '@microsoft/tsdoc';
import { Meaning, ModuleSource } from '@microsoft/tsdoc/lib-commonjs/beta/DeclarationReference';
import { createCommentNode } from '~/DocModel/comment';
import type { DocBlockJSON } from '~/DocModel/comment/CommentBlock';
import { type Meaning, ModuleSource } from '@microsoft/tsdoc/lib-commonjs/beta/DeclarationReference';
import type { DocBlockJSON } from './tsdoc/CommentBlock.js';
import { createCommentNode } from './tsdoc/index.js';
export function findPackage(model: ApiModel, name: string): ApiPackage | undefined {
return (model.findMembersByName(name)[0] ?? model.findMembersByName(`@discordjs/${name}`)[0]) as
@@ -23,8 +23,9 @@ export function findPackage(model: ApiModel, name: string): ApiPackage | undefin
| undefined;
}
export function generatePath(items: readonly ApiItem[]) {
let path = '/docs/main/packages';
export function generatePath(items: readonly ApiItem[], version: string) {
let path = '/docs/packages';
for (const item of items) {
switch (item.kind) {
case ApiItemKind.Model:
@@ -39,7 +40,7 @@ export function generatePath(items: readonly ApiItem[]) {
const functionItem = item as ApiFunction;
path += `/${functionItem.displayName}${
functionItem.overloadIndex && functionItem.overloadIndex > 1 ? `:${functionItem.overloadIndex}` : ''
}`;
}:${item.kind}`;
break;
case ApiItemKind.Property:
case ApiItemKind.Method:
@@ -49,11 +50,12 @@ export function generatePath(items: readonly ApiItem[]) {
path += `#${item.displayName}`;
break;
default:
path += `/${item.displayName}`;
path += `/${item.displayName}:${item.kind}`;
}
}
return path.replace(/@discordjs\//, '');
// eslint-disable-next-line prefer-named-capture-group, unicorn/no-unsafe-regex
return path.replace(/@discordjs\/(.*)\/(.*)?/, `$1/${version}/$2`);
}
export function resolveDocComment(item: ApiDocumentedItem) {
@@ -69,26 +71,22 @@ export function resolveDocComment(item: ApiDocumentedItem) {
const { summarySection } = tsdocComment;
function recurseNodes(nodes: readonly DocNode[] | undefined): string | null {
if (!nodes) {
function recurseNodes(node: DocNode | undefined): string | null {
if (!node) {
return null;
}
for (const node of nodes) {
switch (node.kind) {
case 'Paragraph':
return recurseNodes((node as DocParagraph).nodes);
case 'PlainText':
return (node as DocPlainText).text;
default:
return null;
}
switch (node.kind) {
case 'Paragraph':
return recurseNodes(node as DocParagraph);
case 'PlainText':
return (node as DocPlainText).text;
default:
return null;
}
return null;
}
return recurseNodes(summarySection.nodes);
return recurseNodes(summarySection);
}
export function findReferences(model: ApiModel, excerpt: Excerpt) {
@@ -106,6 +104,7 @@ export function findReferences(model: ApiModel, excerpt: Excerpt) {
break;
}
default:
break;
}
@@ -141,16 +140,16 @@ export function getProperties(item: ApiItem) {
}
export interface TokenDocumentation {
text: string;
path: string | null;
kind: string;
path: string | null;
text: string;
}
export interface ParameterDocumentation {
name: string;
isOptional: boolean;
tokens: TokenDocumentation[];
name: string;
paramCommentBlock: DocBlockJSON | null;
tokens: TokenDocumentation[];
}
function createDapiTypesURL(meaning: Meaning, name: string) {
@@ -164,16 +163,16 @@ function createDapiTypesURL(meaning: Meaning, name: string) {
}
}
export function genReference(item: ApiItem) {
export function genReference(item: ApiItem, version: string) {
return {
name: resolveName(item),
path: generatePath(item.getHierarchy()),
path: generatePath(item.getHierarchy(), version),
};
}
export function genToken(model: ApiModel, token: ExcerptToken) {
export function genToken(model: ApiModel, token: ExcerptToken, version: string) {
if (token.canonicalReference) {
// @ts-expect-error
// @ts-expect-error: Symbol is not publicly accessible
token.canonicalReference._navigation = '.';
}
@@ -197,24 +196,26 @@ export function genToken(model: ApiModel, token: ExcerptToken) {
return {
kind: token.kind,
text: token.text,
path: item ? generatePath(item.getHierarchy()) : null,
path: item ? generatePath(item.getHierarchy(), version) : null,
};
}
export function genParameter(model: ApiModel, param: Parameter): ParameterDocumentation {
export function genParameter(model: ApiModel, param: Parameter, version: string): ParameterDocumentation {
return {
name: param.name,
isOptional: param.isOptional,
tokens: param.parameterTypeExcerpt.spannedTokens.map((token) => genToken(model, token)),
paramCommentBlock: param.tsdocParamBlock ? (createCommentNode(param.tsdocParamBlock, model) as DocBlockJSON) : null,
tokens: param.parameterTypeExcerpt.spannedTokens.map((token) => genToken(model, token, version)),
paramCommentBlock: param.tsdocParamBlock
? (createCommentNode(param.tsdocParamBlock, model, version) as DocBlockJSON)
: null,
};
}
export function getMembers(pkg: ApiPackage) {
export function getMembers(pkg: ApiPackage, version: string) {
return pkg.members[0]!.members.map((member) => ({
name: member.displayName,
kind: member.kind as string,
path: generatePath(member.getHierarchy()),
path: generatePath(member.getHierarchy(), version),
containerKey: member.containerKey,
overloadIndex: member.kind === 'Function' ? (member as ApiFunction).overloadIndex : null,
}));

View File

@@ -1,18 +1,18 @@
import type { ApiModel, ApiItem } from '@microsoft/api-extractor-model';
import type { DocBlock } from '@microsoft/tsdoc';
import { blockTag, type DocBlockTagJSON } from './CommentBlockTag.js';
import { type AnyDocNodeJSON, type DocNodeJSON, node } from './CommentNode.js';
import { createCommentNode } from '.';
import { blockTag, DocBlockTagJSON } from './CommentBlockTag';
import { AnyDocNodeJSON, DocNodeJSON, node } from './CommentNode';
export interface DocBlockJSON extends DocNodeJSON {
content: AnyDocNodeJSON[];
tag: DocBlockTagJSON;
}
export function block(block: DocBlock, model: ApiModel, parentItem?: ApiItem) {
export function block(block: DocBlock, model: ApiModel, version: string, parentItem?: ApiItem) {
return {
...node(block),
content: block.content.nodes.map((node) => createCommentNode(node, model, parentItem)),
content: block.content.nodes.map((node) => createCommentNode(node, model, version, parentItem)),
tag: blockTag(block.blockTag),
};
}

View File

@@ -1,5 +1,5 @@
import type { DocBlockTag } from '@microsoft/tsdoc';
import { type DocNodeJSON, node } from './CommentNode';
import { type DocNodeJSON, node } from './CommentNode.js';
export interface DocBlockTagJSON extends DocNodeJSON {
tagName: string;

View File

@@ -1,5 +1,5 @@
import type { DocCodeSpan } from '@microsoft/tsdoc';
import { DocNodeJSON, node } from './CommentNode';
import { type DocNodeJSON, node } from './CommentNode.js';
export interface DocCodeSpanJSON extends DocNodeJSON {
code: string;

View File

@@ -1,25 +1,25 @@
import type { DocNode, DocNodeKind } from '@microsoft/tsdoc';
import type { DocBlockJSON } from './CommentBlock';
import type { DocCodeSpanJSON } from './CommentCodeSpan';
import type { DocNodeContainerJSON } from './CommentNodeContainer';
import type { DocFencedCodeJSON } from './FencedCodeCommentNode';
import type { DocLinkTagJSON } from './LinkTagCommentNode';
import type { DocPlainTextJSON } from './PlainTextCommentNode';
import type { DocCommentJSON } from './RootComment';
import type { DocBlockJSON } from './CommentBlock.js';
import type { DocCodeSpanJSON } from './CommentCodeSpan.js';
import type { DocNodeContainerJSON } from './CommentNodeContainer.js';
import type { DocFencedCodeJSON } from './FencedCodeCommentNode.js';
import type { DocLinkTagJSON } from './LinkTagCommentNode.js';
import type { DocPlainTextJSON } from './PlainTextCommentNode.js';
import type { DocCommentJSON } from './RootComment.js';
export interface DocNodeJSON {
kind: DocNodeKind;
}
export type AnyDocNodeJSON =
| DocNodeJSON
| DocPlainTextJSON
| DocNodeContainerJSON
| DocLinkTagJSON
| DocFencedCodeJSON
| DocBlockJSON
| DocCodeSpanJSON
| DocCommentJSON
| DocCodeSpanJSON;
| DocFencedCodeJSON
| DocLinkTagJSON
| DocNodeContainerJSON
| DocNodeJSON
| DocPlainTextJSON;
export function node(node: DocNode): DocNodeJSON {
return {

View File

@@ -1,7 +1,7 @@
import type { ApiItem, ApiModel } from '@microsoft/api-extractor-model';
import type { DocNodeContainer } from '@microsoft/tsdoc';
import { type AnyDocNodeJSON, type DocNodeJSON, node } from './CommentNode.js';
import { createCommentNode } from '.';
import { AnyDocNodeJSON, DocNodeJSON, node } from './CommentNode';
export interface DocNodeContainerJSON extends DocNodeJSON {
nodes: AnyDocNodeJSON[];
@@ -10,10 +10,11 @@ export interface DocNodeContainerJSON extends DocNodeJSON {
export function nodeContainer(
container: DocNodeContainer,
model: ApiModel,
version: string,
parentItem?: ApiItem,
): DocNodeContainerJSON {
return {
...node(container),
nodes: container.nodes.map((node) => createCommentNode(node, model, parentItem)),
nodes: container.nodes.map((node) => createCommentNode(node, model, version, parentItem)),
};
}

View File

@@ -1,5 +1,5 @@
import type { DocFencedCode } from '@microsoft/tsdoc';
import { DocNodeJSON, node } from './CommentNode';
import { type DocNodeJSON, node } from './CommentNode.js';
export interface DocFencedCodeJSON extends DocNodeJSON {
code: string;

View File

@@ -1,18 +1,25 @@
import type { ApiItem, ApiModel } from '@microsoft/api-extractor-model';
import type { DocDeclarationReference, DocLinkTag } from '@microsoft/tsdoc';
import { DocNodeJSON, node } from './CommentNode';
import { generatePath, resolveName } from '~/util/parse.server';
import { resolveName, generatePath } from '../parse.js';
import { type DocNodeJSON, node } from './CommentNode.js';
interface LinkTagCodeLink {
kind: string;
name: string;
path: string;
}
export interface DocLinkTagJSON extends DocNodeJSON {
text: string | null;
codeDestination: LinkTagCodeLink | null;
text: string | null;
urlDestination: string | null;
}
export function genToken(
export function genLinkToken(
model: ApiModel,
ref: DocDeclarationReference,
context: ApiItem | null,
version: string,
): LinkTagCodeLink | null {
const item = model.resolveDeclarationReference(ref, context ?? undefined).resolvedApiItem ?? null;
@@ -23,24 +30,23 @@ export function genToken(
return {
name: resolveName(item),
kind: item.kind,
path: generatePath(item.getHierarchy()),
path: generatePath(item.getHierarchy(), version),
};
}
export interface LinkTagCodeLink {
name: string;
kind: string;
path: string;
}
export function linkTagNode(linkNode: DocLinkTag, model: ApiModel, parentItem?: ApiItem): DocLinkTagJSON {
export function linkTagNode(
linkNode: DocLinkTag,
model: ApiModel,
version: string,
parentItem?: ApiItem,
): DocLinkTagJSON {
// If we weren't provided a parent object, fallback to the package entrypoint.
const packageEntryPoint = linkNode.codeDestination?.importPath
? model.getAssociatedPackage()?.findEntryPointsByPath(linkNode.codeDestination.importPath)[0]
: null;
const codeDestination = linkNode.codeDestination
? genToken(model, linkNode.codeDestination, parentItem ?? packageEntryPoint ?? null)
? genLinkToken(model, linkNode.codeDestination, parentItem ?? packageEntryPoint ?? null, version)
: null;
const text = linkNode.linkText ?? null;
const urlDestination = linkNode.urlDestination ?? null;

View File

@@ -0,0 +1,19 @@
import type { ApiItem, ApiModel } from '@microsoft/api-extractor-model';
import type { DocParamBlock } from '@microsoft/tsdoc';
import { block, type DocBlockJSON } from './CommentBlock.js';
interface DocParamBlockJSON extends DocBlockJSON {
name: string;
}
export function paramBlock(
paramBlock: DocParamBlock,
model: ApiModel,
version: string,
parentItem?: ApiItem,
): DocParamBlockJSON {
return {
...block(paramBlock, model, version, parentItem),
name: paramBlock.parameterName,
};
}

View File

@@ -1,5 +1,5 @@
import type { DocPlainText } from '@microsoft/tsdoc';
import { DocNodeJSON, node } from './CommentNode';
import { type DocNodeJSON, node } from './CommentNode.js';
export interface DocPlainTextJSON extends DocNodeJSON {
text: string;

View File

@@ -0,0 +1,24 @@
import type { ApiItem, ApiModel } from '@microsoft/api-extractor-model';
import type { DocComment } from '@microsoft/tsdoc';
import { block, type DocBlockJSON } from './CommentBlock.js';
import { type DocNodeJSON, node } from './CommentNode.js';
import { createCommentNode } from '.';
export interface DocCommentJSON extends DocNodeJSON {
customBlocks: DocBlockJSON[];
deprecated: DocNodeJSON[];
remarks: DocNodeJSON[];
summary: DocNodeJSON[];
}
export function comment(comment: DocComment, model: ApiModel, version: string, parentItem?: ApiItem): DocCommentJSON {
return {
...node(comment),
summary: comment.summarySection.nodes.map((node) => createCommentNode(node, model, version, parentItem)),
remarks:
comment.remarksBlock?.content.nodes.map((node) => createCommentNode(node, model, version, parentItem)) ?? [],
deprecated:
comment.deprecatedBlock?.content.nodes.map((node) => createCommentNode(node, model, version, parentItem)) ?? [],
customBlocks: comment.customBlocks.map((_block) => block(_block, model, version, parentItem)),
};
}

View File

@@ -0,0 +1,62 @@
import type { ApiModel, ApiItem } from '@microsoft/api-extractor-model';
import {
type DocNode,
type DocPlainText,
type DocLinkTag,
type DocParagraph,
type DocFencedCode,
DocNodeKind,
type DocBlock,
type DocComment,
type DocCodeSpan,
type DocParamBlock,
} from '@microsoft/tsdoc';
import { block } from './CommentBlock.js';
import { codeSpan } from './CommentCodeSpan.js';
import { node as _node, type AnyDocNodeJSON } from './CommentNode.js';
import { nodeContainer } from './CommentNodeContainer.js';
import { fencedCode } from './FencedCodeCommentNode.js';
import { linkTagNode } from './LinkTagCommentNode.js';
import { paramBlock } from './ParamBlock.js';
import { plainTextNode } from './PlainTextCommentNode.js';
import { comment } from './RootComment.js';
export function createCommentNode(
node: DocNode,
model: ApiModel,
version: string,
parentItem?: ApiItem,
): AnyDocNodeJSON {
switch (node.kind) {
case DocNodeKind.PlainText:
return plainTextNode(node as DocPlainText);
case DocNodeKind.LinkTag:
return linkTagNode(node as DocLinkTag, model, version, parentItem);
case DocNodeKind.Paragraph:
case DocNodeKind.Section:
return nodeContainer(node as DocParagraph, model, version, parentItem);
case DocNodeKind.FencedCode:
return fencedCode(node as DocFencedCode);
case DocNodeKind.CodeSpan:
return codeSpan(node as DocCodeSpan);
case DocNodeKind.Block:
return block(node as DocBlock, model, version, parentItem);
case DocNodeKind.ParamBlock:
return paramBlock(node as DocParamBlock, model, version, parentItem);
case DocNodeKind.Comment:
return comment(node as DocComment, model, version, parentItem);
default:
return _node(node);
}
}
export * from './CommentNode.js';
export * from './CommentNodeContainer.js';
export * from './CommentBlock.js';
export * from './CommentBlockTag.js';
export * from './CommentCodeSpan.js';
export * from './FencedCodeCommentNode.js';
export * from './LinkTagCommentNode.js';
export * from './ParamBlock.js';
export * from './PlainTextCommentNode.js';
export * from './RootComment.js';

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,8 @@
{
"extends": "../../tsconfig.json",
"compilerOptions": {
"skipDefaultLibCheck": true,
"skipLibCheck": true
},
"include": ["src/**/*.ts"]
}

View File

@@ -0,0 +1,5 @@
import { createTsupConfig } from '../../tsup.config.js';
export default createTsupConfig({
minify: true,
});

View File

@@ -1,7 +1,3 @@
{
"extends": "../../.eslintrc.json",
"plugins": ["eslint-plugin-tsdoc"],
"rules": {
"tsdoc/syntax": "warn"
}
"extends": "../../.eslintrc.json"
}

View File

@@ -2,7 +2,20 @@
All notable changes to this project will be documented in this file.
# [@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)
# [@discordjs/builders@1.2.0](https://github.com/discordjs/discord.js/compare/@discordjs/builders@1.1.0...@discordjs/builders@1.2.0) - (2022-08-22)
## Features
- **website:** Show `constructor` information (#8540) ([e42fd16](https://github.com/discordjs/discord.js/commit/e42fd1636973b10dd7ed6fb4280ee1a4a8f82007))
- **website:** Show descriptions for `@typeParam` blocks (#8523) ([e475b63](https://github.com/discordjs/discord.js/commit/e475b63f257f6261d73cb89fee9ecbcdd84e2a6b))
- **website:** Show parameter descriptions (#8519) ([7f415a2](https://github.com/discordjs/discord.js/commit/7f415a2502bf7ce2025dbcfed9017b0635a19966))
- **WebSocketShard:** Support new resume url (#8480) ([bc06cc6](https://github.com/discordjs/discord.js/commit/bc06cc638d2f57ab5c600e8cdb6afc8eb2180166))
## Refactor
- Docs design (#8487) ([4ab1d09](https://github.com/discordjs/discord.js/commit/4ab1d09997a18879a9eb9bda39df6f15aa22557e))
# [@discordjs/builders@1.1.0](https://github.com/discordjs/discord.js/compare/@discordjs/builders@0.16.0...@discordjs/builders@1.1.0) - (2022-07-29)
## Bug Fixes
@@ -18,11 +31,9 @@ All notable changes to this project will be documented in this file.
- 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)
## Testing
## Info
- 1.0.0 release bump, no new features.
- **builders:** Improve coverage (#8274) ([b7e6238](https://github.com/discordjs/discord.js/commit/b7e62380f2e6b9324d6bba9b9eaa5315080bf66a))
# [@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)
@@ -63,14 +74,6 @@ All notable changes to this project will be documented in this file.
- 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
@@ -161,108 +164,3 @@ All notable changes to this project will be documented in this file.
## Typings
- Make `required` a boolean (#7307) ([c10afea](https://github.com/discordjs/discord.js/commit/c10afeadc702ab98bec5e077b3b92494a9596f9c))
# [0.11.0](https://github.com/discordjs/builders/compare/v0.10.0...v0.11.0) (2021-12-29)
## Bug Fixes
- **ApplicationCommandOptions:** clean up code for builder options ([#68](https://github.com/discordjs/builders/issues/68)) ([b5d0b15](https://github.com/discordjs/builders/commit/b5d0b157b1262bd01fa011f8e0cf33adb82776e7))
# [0.10.0](https://github.com/discordjs/builders/compare/v0.9.0...v0.10.0) (2021-12-24)
## Bug Fixes
- use zod instead of ow for max/min option validation ([#66](https://github.com/discordjs/builders/issues/66)) ([beb35fb](https://github.com/discordjs/builders/commit/beb35fb1f65bd6be2321e17cc792f67e8615fd48))
## Features
- add max/min option for int and number builder options ([#47](https://github.com/discordjs/builders/issues/47)) ([2e1e860](https://github.com/discordjs/builders/commit/2e1e860b46e3453398b20df63dabb6d4325e32d1))
# [0.9.0](https://github.com/discordjs/builders/compare/v0.8.2...v0.9.0) (2021-12-02)
## Bug Fixes
- replace ow with zod ([#58](https://github.com/discordjs/builders/issues/58)) ([0b6fb81](https://github.com/discordjs/builders/commit/0b6fb8161b858e42781855fb73aaa873fec58160))
## Features
- **SlashCommandBuilder:** add autocomplete ([#53](https://github.com/discordjs/builders/issues/53)) ([05b07a7](https://github.com/discordjs/builders/commit/05b07a7e88848188c27d7380d9f948cba25ef778))
## [0.8.2](https://github.com/discordjs/builders/compare/v0.8.1...v0.8.2) (2021-10-30)
## Bug Fixes
- downgrade ow because of esm issues ([#55](https://github.com/discordjs/builders/issues/55)) ([3722d2c](https://github.com/discordjs/builders/commit/3722d2c1109a7a5c0abad63c1a7eb944df6e46c8))
## [0.8.1](https://github.com/discordjs/builders/compare/v0.8.0...v0.8.1) (2021-10-29)
## Bug Fixes
- documentation ([e33ec8d](https://github.com/discordjs/builders/commit/e33ec8dfd5785312f82e0afb017a3dac614fd71d))
# [0.7.0](https://github.com/discordjs/builders/compare/v0.6.0...v0.7.0) (2021-10-18)
## Bug Fixes
- properly type `toJSON` methods ([#34](https://github.com/discordjs/builders/issues/34)) ([7723ad0](https://github.com/discordjs/builders/commit/7723ad0da169386e638188de220451a97513bc25))
## Features
- **ContextMenus:** add context menu command builder ([#29](https://github.com/discordjs/builders/issues/29)) ([f0641e5](https://github.com/discordjs/builders/commit/f0641e55733de8992600f3082bcf054e6f815cf7))
- add support for channel types on channel options ([#41](https://github.com/discordjs/builders/issues/41)) ([f6c187e](https://github.com/discordjs/builders/commit/f6c187e0ad6ebe03e65186ece3e95cb1db5aeb50))
# [0.6.0](https://github.com/discordjs/builders/compare/v0.5.0...v0.6.0) (2021-08-24)
## Bug Fixes
- **SlashCommandBuilder:** allow subcommands and groups to coexist at the root level ([#26](https://github.com/discordjs/builders/issues/26)) ([0be4daf](https://github.com/discordjs/builders/commit/0be4dafdfc0b5747c880be0078c00ada913eb4fb))
## Features
- create `Embed` builder ([#11](https://github.com/discordjs/builders/issues/11)) ([eb942a4](https://github.com/discordjs/builders/commit/eb942a4d1f3bcec9a4e370b6af602a713ad8f9b7))
- **SlashCommandBuilder:** create setDefaultPermission function ([#19](https://github.com/discordjs/builders/issues/19)) ([5d53759](https://github.com/discordjs/builders/commit/5d537593937a8da330153ce4711b7d093a80330e))
- **SlashCommands:** add number option type ([#23](https://github.com/discordjs/builders/issues/23)) ([1563991](https://github.com/discordjs/builders/commit/1563991d421bb07bf7a412c87e7613692d770f04))
# [0.5.0](https://github.com/discordjs/builders/compare/v0.3.0...v0.5.0) (2021-08-10)
## Features
- **Formatters:** add `formatEmoji` ([#20](https://github.com/discordjs/builders/issues/20)) ([c3d8bb5](https://github.com/discordjs/builders/commit/c3d8bb5363a1d46b45c0def4277da6921e2ba209))
# [0.4.0](https://github.com/discordjs/builders/compare/v0.3.0...v0.4.0) (2021-08-05)
## Features
- `sub command` => `subcommand` ([#18](https://github.com/discordjs/builders/pull/18)) ([95599c5](https://github.com/discordjs/builders/commit/95599c5b5366ebd054c4c277c52f1a44cda1209d))
# [0.3.0](https://github.com/discordjs/builders/compare/v0.2.0...v0.3.0) (2021-08-01)
## Bug Fixes
- **Shrug:** Update comment ([#14](https://github.com/discordjs/builders/issues/14)) ([6fa6c40](https://github.com/discordjs/builders/commit/6fa6c405f2ea733811677d3d1bfb1e2806d504d5))
- shrug face rendering ([#13](https://github.com/discordjs/builders/issues/13)) ([6ad24ec](https://github.com/discordjs/builders/commit/6ad24ecd96c82b0f576e78e9e53fc7bf9c36ef5d))
## Features
- **formatters:** mentions ([#9](https://github.com/discordjs/builders/issues/9)) ([f83fe99](https://github.com/discordjs/builders/commit/f83fe99b83188ed999845751ffb005c687dbd60a))
- **Formatters:** Add a spoiler function ([#16](https://github.com/discordjs/builders/issues/16)) ([c213a6a](https://github.com/discordjs/builders/commit/c213a6abb114f65653017a4edec4bdba2162d771))
- **SlashCommands:** add slash command builders ([#3](https://github.com/discordjs/builders/issues/3)) ([6aa3af0](https://github.com/discordjs/builders/commit/6aa3af07b0ee342fff91f080914bb12b3ab773f8))
- shrug, tableflip and unflip strings ([#5](https://github.com/discordjs/builders/issues/5)) ([de5fa82](https://github.com/discordjs/builders/commit/de5fa823cd6f1feba5b2d0a63b2cb1761dfd1814))
# [0.2.0](https://github.com/discordjs/builders/compare/v0.1.1...v0.2.0) (2021-07-03)
## Features
- **Formatters:** added `hyperlink` and `hideLinkEmbed` ([#4](https://github.com/discordjs/builders/issues/4)) ([c532daf](https://github.com/discordjs/builders/commit/c532daf2ba2feae75bf9668f63462e96a5314cff))
# [0.1.1](https://github.com/discordjs/builders/compare/v0.1.0...v0.1.1) (2021-06-30)
## Bug Fixes
- **Deps:** added `tslib` as dependency ([#2](https://github.com/discordjs/builders/issues/2)) ([5576ff3](https://github.com/discordjs/builders/commit/5576ff3b67136b957bed0ab8a4c655d5de322813))
# 0.1.0 (2021-06-30)
## Features
- added message formatters ([#1](https://github.com/discordjs/builders/issues/1)) ([765e46d](https://github.com/discordjs/builders/commit/765e46dac96c4e49d350243e5fad34c2bc738a7c))

View File

@@ -1,4 +1,9 @@
import { APIActionRowComponent, APIMessageActionRowComponent, ButtonStyle, ComponentType } from 'discord-api-types/v10';
import {
ButtonStyle,
ComponentType,
type APIActionRowComponent,
type APIMessageActionRowComponent,
} from 'discord-api-types/v10';
import { describe, test, expect } from 'vitest';
import {
ActionRowBuilder,
@@ -6,7 +11,7 @@ import {
createComponentBuilder,
SelectMenuBuilder,
SelectMenuOptionBuilder,
} from '../../src';
} from '../../src/index.js';
const rowWithButtonData: APIActionRowComponent<APIMessageActionRowComponent> = {
type: ComponentType.ActionRow,

View File

@@ -1,12 +1,12 @@
import {
APIButtonComponentWithCustomId,
APIButtonComponentWithURL,
ButtonStyle,
ComponentType,
type APIButtonComponentWithCustomId,
type APIButtonComponentWithURL,
} 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';
import { buttonLabelValidator, buttonStyleValidator } from '../../src/components/Assertions.js';
import { ButtonBuilder } from '../../src/components/button/Button.js';
const buttonComponent = () => new ButtonBuilder();
@@ -31,7 +31,7 @@ describe('Button Components', () => {
expect(() => buttonStyleValidator.parse(ButtonStyle.Secondary)).not.toThrowError();
});
test('GIVEN invalid style THEN validator does not throw', () => {
test('GIVEN invalid style THEN validator does throw', () => {
expect(() => buttonStyleValidator.parse(7)).toThrowError();
});
@@ -71,7 +71,7 @@ describe('Button Components', () => {
}).toThrowError();
expect(() => {
// @ts-expect-error
// @ts-expect-error: Invalid emoji
const button = buttonComponent().setEmoji('test');
button.toJSON();
}).toThrowError();
@@ -103,9 +103,9 @@ describe('Button Components', () => {
expect(() => buttonComponent().setStyle(24)).toThrowError();
expect(() => buttonComponent().setLabel(longStr)).toThrowError();
// @ts-expect-error
// @ts-expect-error: Invalid parameter for disabled
expect(() => buttonComponent().setDisabled(0)).toThrowError();
// @ts-expect-error
// @ts-expect-error: Invalid emoji
expect(() => buttonComponent().setEmoji('foo')).toThrowError();
expect(() => buttonComponent().setURL('foobar')).toThrowError();

View File

@@ -1,12 +1,12 @@
import {
APIActionRowComponent,
APIButtonComponent,
APIMessageActionRowComponent,
APISelectMenuComponent,
APITextInputComponent,
ButtonStyle,
ComponentType,
TextInputStyle,
type APIButtonComponent,
type APIMessageActionRowComponent,
type APISelectMenuComponent,
type APITextInputComponent,
type APIActionRowComponent,
} from 'discord-api-types/v10';
import { describe, test, expect } from 'vitest';
import {
@@ -15,7 +15,7 @@ import {
createComponentBuilder,
SelectMenuBuilder,
TextInputBuilder,
} from '../../src/index';
} from '../../src/index.js';
describe('createComponentBuilder', () => {
test.each([ButtonBuilder, SelectMenuBuilder, TextInputBuilder])(
@@ -67,7 +67,7 @@ describe('createComponentBuilder', () => {
});
test('GIVEN an unknown component type THEN throws error', () => {
// @ts-expect-error
// @ts-expect-error: Unknown component type
expect(() => createComponentBuilder({ type: 'invalid' })).toThrowError();
});
});

View File

@@ -1,6 +1,6 @@
import { APISelectMenuComponent, APISelectMenuOption, ComponentType } from 'discord-api-types/v10';
import { ComponentType, type APISelectMenuComponent, type APISelectMenuOption } from 'discord-api-types/v10';
import { describe, test, expect } from 'vitest';
import { SelectMenuBuilder, SelectMenuOptionBuilder } from '../../src/index';
import { SelectMenuBuilder, SelectMenuOptionBuilder } from '../../src/index.js';
const selectMenu = () => new SelectMenuBuilder();
const selectMenuOption = () => new SelectMenuOptionBuilder();
@@ -74,7 +74,8 @@ describe('Select Menu Components', () => {
]),
).not.toThrowError();
const options = new Array<APISelectMenuOption>(25).fill({ label: 'test', value: 'test' });
const options = Array.from<APISelectMenuOption>({ length: 25 }).fill({ label: 'test', value: 'test' });
expect(() => selectMenu().addOptions(...options)).not.toThrowError();
expect(() => selectMenu().setOptions(...options)).not.toThrowError();
expect(() => selectMenu().addOptions(options)).not.toThrowError();
@@ -83,12 +84,13 @@ describe('Select Menu Components', () => {
expect(() =>
selectMenu()
.addOptions({ label: 'test', value: 'test' })
.addOptions(...new Array<APISelectMenuOption>(24).fill({ label: 'test', value: 'test' })),
.addOptions(...Array.from<APISelectMenuOption>({ length: 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' })),
.addOptions(Array.from<APISelectMenuOption>({ length: 24 }).fill({ label: 'test', value: 'test' })),
).not.toThrowError();
});
@@ -96,33 +98,34 @@ describe('Select Menu Components', () => {
expect(() => selectMenu().setCustomId(longStr)).toThrowError();
expect(() => selectMenu().setMaxValues(30)).toThrowError();
expect(() => selectMenu().setMinValues(-20)).toThrowError();
// @ts-expect-error
// @ts-expect-error: Invalid disabled value
expect(() => selectMenu().setDisabled(0)).toThrowError();
expect(() => selectMenu().setPlaceholder(longStr)).toThrowError();
// @ts-expect-error
// @ts-expect-error: Invalid option
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
// @ts-expect-error: Invalid option
expect(() => selectMenu().addOptions({ label: 'test', value: 'test', default: 100 })).toThrowError();
// @ts-expect-error
// @ts-expect-error: Invalid option
expect(() => selectMenu().addOptions({ value: 'test' })).toThrowError();
// @ts-expect-error
// @ts-expect-error: Invalid option
expect(() => selectMenu().addOptions({ default: true })).toThrowError();
// @ts-expect-error
// @ts-expect-error: Invalid option
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
// @ts-expect-error: Invalid option
expect(() => selectMenu().addOptions([{ label: 'test', value: 'test', default: 100 }])).toThrowError();
// @ts-expect-error
// @ts-expect-error: Invalid option
expect(() => selectMenu().addOptions([{ value: 'test' }])).toThrowError();
// @ts-expect-error
// @ts-expect-error: Invalid option
expect(() => selectMenu().addOptions([{ default: true }])).toThrowError();
const tooManyOptions = new Array<APISelectMenuOption>(26).fill({ label: 'test', value: 'test' });
const tooManyOptions = Array.from<APISelectMenuOption>({ length: 26 }).fill({ label: 'test', value: 'test' });
expect(() => selectMenu().setOptions(...tooManyOptions)).toThrowError();
expect(() => selectMenu().setOptions(tooManyOptions)).toThrowError();
@@ -141,9 +144,9 @@ describe('Select Menu Components', () => {
selectMenuOption()
.setLabel(longStr)
.setValue(longStr)
// @ts-expect-error
// @ts-expect-error: Invalid default value
.setDefault(-1)
// @ts-expect-error
// @ts-expect-error: Invalid emoji
.setEmoji({ name: 1 })
.setDescription(longStr);
}).toThrowError();

View File

@@ -1,4 +1,4 @@
import { APITextInputComponent, ComponentType, TextInputStyle } from 'discord-api-types/v10';
import { ComponentType, TextInputStyle, type APITextInputComponent } from 'discord-api-types/v10';
import { describe, test, expect } from 'vitest';
import {
labelValidator,
@@ -7,10 +7,10 @@ import {
placeholderValidator,
valueValidator,
textInputStyleValidator,
} from '../../src/components/textInput/Assertions';
import { TextInputBuilder } from '../../src/components/textInput/TextInput';
} from '../../src/components/textInput/Assertions.js';
import { TextInputBuilder } from '../../src/components/textInput/TextInput.js';
const superLongStr = 'a'.repeat(5000);
const superLongStr = 'a'.repeat(5_000);
const textInputComponent = () => new TextInputBuilder();
@@ -47,7 +47,7 @@ describe('Text Input Components', () => {
});
test('GIVEN invalid min length THEN validator does throw 2', () => {
expect(() => maxLengthValidator.parse(4001)).toThrowError();
expect(() => maxLengthValidator.parse(4_001)).toThrowError();
});
test('GIVEN valid value THEN validator does not throw', () => {
@@ -85,7 +85,7 @@ describe('Text Input Components', () => {
expect(() => {
// Issue #8107
// @ts-expect-error: shapeshift maps the enum key to the value when parsing
// @ts-expect-error: Shapeshift maps the enum key to the value when parsing
textInputComponent().setCustomId('Custom').setLabel('Guess').setStyle('Short').toJSON();
}).not.toThrowError();
});

View File

@@ -1,6 +1,6 @@
import { PermissionFlagsBits } from 'discord-api-types/v10';
import { describe, test, expect } from 'vitest';
import { ContextMenuCommandAssertions, ContextMenuCommandBuilder } from '../../src/index';
import { ContextMenuCommandAssertions, ContextMenuCommandBuilder } from '../../src/index.js';
const getBuilder = () => new ContextMenuCommandBuilder();
@@ -105,9 +105,9 @@ describe('Context Menu Commands', () => {
});
test('GIVEN invalid name localizations THEN does throw error', () => {
// @ts-expect-error
// @ts-expect-error: Invalid localization
expect(() => getBuilder().setNameLocalization('en-U', 'foobar')).toThrowError();
// @ts-expect-error
// @ts-expect-error: Invalid localization
expect(() => getBuilder().setNameLocalizations({ 'en-U': 'foobar' })).toThrowError();
});

View File

@@ -1,15 +1,15 @@
import {
APIApplicationCommandAttachmentOption,
APIApplicationCommandBooleanOption,
APIApplicationCommandChannelOption,
APIApplicationCommandIntegerOption,
APIApplicationCommandMentionableOption,
APIApplicationCommandNumberOption,
APIApplicationCommandRoleOption,
APIApplicationCommandStringOption,
APIApplicationCommandUserOption,
ApplicationCommandOptionType,
ChannelType,
type APIApplicationCommandAttachmentOption,
type APIApplicationCommandBooleanOption,
type APIApplicationCommandChannelOption,
type APIApplicationCommandIntegerOption,
type APIApplicationCommandMentionableOption,
type APIApplicationCommandNumberOption,
type APIApplicationCommandRoleOption,
type APIApplicationCommandStringOption,
type APIApplicationCommandUserOption,
} from 'discord-api-types/v10';
import { describe, test, expect } from 'vitest';
import {
@@ -22,7 +22,7 @@ import {
SlashCommandRoleOption,
SlashCommandStringOption,
SlashCommandUserOption,
} from '../../../src/index';
} from '../../../src/index.js';
const getBooleanOption = () =>
new SlashCommandBooleanOption().setName('owo').setDescription('Testing 123').setRequired(true);
@@ -101,7 +101,8 @@ describe('Application Command toJSON() results', () => {
max_value: 10,
min_value: -1,
autocomplete: true,
// @ts-expect-error TODO: you *can* send an empty array with autocomplete: true, should correct that in types
// TODO
// @ts-expect-error You *can* send an empty array with autocomplete: true, should correct that in types
choices: [],
});
@@ -145,7 +146,8 @@ describe('Application Command toJSON() results', () => {
max_value: 10,
min_value: -1.23,
autocomplete: true,
// @ts-expect-error TODO: you *can* send an empty array with autocomplete: true, should correct that in types
// TODO
// @ts-expect-error You *can* send an empty array with autocomplete: true, should correct that in types
choices: [],
});
@@ -187,7 +189,8 @@ describe('Application Command toJSON() results', () => {
type: ApplicationCommandOptionType.String,
required: true,
autocomplete: true,
// @ts-expect-error TODO: you *can* send an empty array with autocomplete: true, should correct that in types
// TODO
// @ts-expect-error you *can* send an empty array with autocomplete: true, should correct that in types
choices: [],
});

View File

@@ -1,4 +1,4 @@
import { APIApplicationCommandOptionChoice, ChannelType, PermissionFlagsBits } from 'discord-api-types/v10';
import { ChannelType, PermissionFlagsBits, type APIApplicationCommandOptionChoice } from 'discord-api-types/v10';
import { describe, test, expect } from 'vitest';
import {
SlashCommandAssertions,
@@ -14,7 +14,7 @@ import {
SlashCommandSubcommandBuilder,
SlashCommandSubcommandGroupBuilder,
SlashCommandUserOption,
} from '../../../src/index';
} from '../../../src/index.js';
const largeArray = Array.from({ length: 26 }, () => 1 as unknown as APIApplicationCommandOptionChoice);
@@ -33,9 +33,7 @@ const getSubcommandGroup = () => new SlashCommandSubcommandGroupBuilder().setNam
const getSubcommand = () => new SlashCommandSubcommandBuilder().setName('owo').setDescription('Testing 123');
class Collection {
public get [Symbol.toStringTag]() {
return 'Map';
}
public readonly [Symbol.toStringTag] = 'Map';
}
describe('Slash Commands', () => {
@@ -178,7 +176,7 @@ describe('Slash Commands', () => {
});
test('GIVEN a builder with invalid autocomplete THEN does throw an error', () => {
// @ts-expect-error Checking if not providing anything, or an invalid return type causes an error
// @ts-expect-error: Checking if not providing anything, or an invalid return type causes an error
expect(() => getBuilder().addStringOption(getStringOption().setAutocomplete('not a boolean'))).toThrowError();
});
@@ -236,7 +234,7 @@ describe('Slash Commands', () => {
expect(() => {
getBuilder().addChannelOption(
getChannelOption().addChannelTypes(ChannelType.GuildNews, ChannelType.GuildText),
getChannelOption().addChannelTypes(ChannelType.GuildAnnouncement, ChannelType.GuildText),
);
}).not.toThrowError();
});
@@ -248,16 +246,16 @@ describe('Slash Commands', () => {
});
test('GIVEN a builder with invalid number min/max options THEN does throw an error', () => {
// @ts-expect-error
// @ts-expect-error: Invalid max value
expect(() => getBuilder().addNumberOption(getNumberOption().setMaxValue('test'))).toThrowError();
// @ts-expect-error
// @ts-expect-error: Invalid max value
expect(() => getBuilder().addIntegerOption(getIntegerOption().setMaxValue('test'))).toThrowError();
// @ts-expect-error
// @ts-expect-error: Invalid min value
expect(() => getBuilder().addNumberOption(getNumberOption().setMinValue('test'))).toThrowError();
// @ts-expect-error
// @ts-expect-error: Invalid min value
expect(() => getBuilder().addIntegerOption(getIntegerOption().setMinValue('test'))).toThrowError();
expect(() => getBuilder().addIntegerOption(getIntegerOption().setMinValue(1.5))).toThrowError();
@@ -294,10 +292,10 @@ describe('Slash Commands', () => {
});
test('GIVEN no valid return for an addOption method THEN throw error', () => {
// @ts-expect-error Checking if not providing anything, or an invalid return type causes an error
// @ts-expect-error: Checking if not providing anything, or an invalid return type causes an error
expect(() => getBuilder().addBooleanOption()).toThrowError();
// @ts-expect-error Checking if not providing anything, or an invalid return type causes an error
// @ts-expect-error: Checking if not providing anything, or an invalid return type causes an error
expect(() => getBuilder().addBooleanOption(getRoleOption())).toThrowError();
});
@@ -318,18 +316,18 @@ describe('Slash Commands', () => {
});
test('GIVEN invalid returns for builder THEN throw error', () => {
// @ts-expect-error Checking if not providing anything, or an invalid return type causes an error
// @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
// @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
// @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
// @ts-expect-error: Checking if not providing anything, or an invalid return type causes an error
expect(() => getBuilder().addBooleanOption(() => SlashCommandStringOption)).toThrowError();
// @ts-expect-error Checking if not providing anything, or an invalid return type causes an error
// @ts-expect-error: Checking if not providing anything, or an invalid return type causes an error
expect(() => getBuilder().addBooleanOption(() => new Collection())).toThrowError();
});
@@ -373,6 +371,18 @@ describe('Slash Commands', () => {
).not.toThrowError();
});
test('GIVEN builder with subcommand THEN has regular slash command fields', () => {
expect(() =>
getBuilder()
.setName('name')
.setDescription('description')
.addSubcommand((option) => option.setName('ye').setDescription('ye'))
.addSubcommand((option) => option.setName('no').setDescription('no'))
.setDMPermission(false)
.setDefaultMemberPermissions(1n),
).not.toThrowError();
});
test('GIVEN builder with already built subcommand group THEN does not throw error', () => {
expect(() => getNamedBuilder().addSubcommandGroup(getSubcommandGroup())).not.toThrowError();
});
@@ -389,30 +399,29 @@ describe('Slash Commands', () => {
test('GIVEN builder with a subcommand that tries to add an invalid result THEN throw error', () => {
expect(() =>
// @ts-expect-error Checking if check works JS-side too
// eslint-disable-next-line @typescript-eslint/no-unsafe-return, @typescript-eslint/no-unsafe-call
// @ts-expect-error: Checking if check works JS-side too
getNamedBuilder().addSubcommand(getSubcommand()).addInteger(getInteger()),
).toThrowError();
});
test('GIVEN no valid return for an addSubcommand(Group) method THEN throw error', () => {
// @ts-expect-error Checking if not providing anything, or an invalid return type causes an error
// @ts-expect-error: Checking if not providing anything, or an invalid return type causes an error
expect(() => getBuilder().addSubcommandGroup()).toThrowError();
// @ts-expect-error Checking if not providing anything, or an invalid return type causes an error
// @ts-expect-error: Checking if not providing anything, or an invalid return type causes an error
expect(() => getBuilder().addSubcommand()).toThrowError();
// @ts-expect-error Checking if not providing anything, or an invalid return type causes an error
// @ts-expect-error: Checking if not providing anything, or an invalid return type causes an error
expect(() => getBuilder().addSubcommand(getSubcommandGroup())).toThrowError();
});
});
describe('Subcommand group builder', () => {
test('GIVEN no valid subcommand THEN throw error', () => {
// @ts-expect-error Checking if not providing anything, or an invalid return type causes an error
// @ts-expect-error: Checking if not providing anything, or an invalid return type causes an error
expect(() => getSubcommandGroup().addSubcommand()).toThrowError();
// @ts-expect-error Checking if not providing anything, or an invalid return type causes an error
// @ts-expect-error: Checking if not providing anything, or an invalid return type causes an error
expect(() => getSubcommandGroup().addSubcommand(getSubcommandGroup())).toThrowError();
});
@@ -444,9 +453,9 @@ describe('Slash Commands', () => {
});
test('GIVEN invalid name localizations THEN does throw error', () => {
// @ts-expect-error
// @ts-expect-error: Invalid localization
expect(() => getBuilder().setNameLocalization('en-U', 'foobar')).toThrowError();
// @ts-expect-error
// @ts-expect-error: Invalid localization
expect(() => getBuilder().setNameLocalizations({ 'en-U': 'foobar' })).toThrowError();
});
@@ -467,9 +476,9 @@ describe('Slash Commands', () => {
});
test('GIVEN invalid description localizations THEN does throw error', () => {
// @ts-expect-error
// @ts-expect-error: Invalid localization description
expect(() => getBuilder().setDescriptionLocalization('en-U', 'foobar')).toThrowError();
// @ts-expect-error
// @ts-expect-error: Invalid localization description
expect(() => getBuilder().setDescriptionLocalizations({ 'en-U': 'foobar' })).toThrowError();
});

View File

@@ -1,22 +1,22 @@
import {
APIModalInteractionResponseCallbackData,
APITextInputComponent,
ComponentType,
TextInputStyle,
type APIModalInteractionResponseCallbackData,
type APITextInputComponent,
} from 'discord-api-types/v10';
import { describe, test, expect } from 'vitest';
import {
ActionRowBuilder,
ButtonBuilder,
ModalBuilder,
ModalActionRowComponentBuilder,
TextInputBuilder,
} from '../../src';
type ModalActionRowComponentBuilder,
} from '../../src/index.js';
import {
componentsValidator,
titleValidator,
validateRequiredParameters,
} from '../../src/interactions/modals/Assertions';
} from '../../src/interactions/modals/Assertions.js';
const modal = () => new ModalBuilder();
@@ -46,7 +46,7 @@ describe('Modals', () => {
test('GIVEN invalid required parameters THEN validator does throw', () => {
expect(() =>
// @ts-expect-error
// @ts-expect-error: Missing required parameter
validateRequiredParameters('123', undefined, [new ActionRowBuilder(), new ButtonBuilder()]),
).toThrowError();
});
@@ -66,7 +66,7 @@ describe('Modals', () => {
test('GIVEN invalid fields THEN builder does throw', () => {
expect(() => modal().setTitle('test').setCustomId('foobar').toJSON()).toThrowError();
// @ts-expect-error
// @ts-expect-error: CustomId is invalid
expect(() => modal().setTitle('test').setCustomId(42).toJSON()).toThrowError();
});

View File

@@ -1,5 +1,5 @@
import { describe, test, expect } from 'vitest';
import { EmbedBuilder, embedLength } from '../../src';
import { EmbedBuilder, embedLength } from '../../src/index.js';
const alpha = 'abcdefghijklmnopqrstuvwxyz';
@@ -74,7 +74,7 @@ describe('Embed', () => {
test('GIVEN an embed with an invalid description THEN throws error', () => {
const embed = new EmbedBuilder();
expect(() => embed.setDescription('a'.repeat(4097))).toThrowError();
expect(() => embed.setDescription('a'.repeat(4_097))).toThrowError();
});
});
@@ -130,11 +130,11 @@ describe('Embed', () => {
test('GIVEN an embed with an invalid color THEN throws error', () => {
const embed = new EmbedBuilder();
// @ts-expect-error
// @ts-expect-error: Invalid color
expect(() => embed.setColor('RED')).toThrowError();
// @ts-expect-error
// @ts-expect-error: Invalid color
expect(() => embed.setColor([42, 36])).toThrowError();
expect(() => embed.setColor([42, 36, 1000])).toThrowError();
expect(() => embed.setColor([42, 36, 1_000])).toThrowError();
});
});
@@ -307,7 +307,7 @@ describe('Embed', () => {
test('GIVEN an embed with invalid footer text THEN throws error', () => {
const embed = new EmbedBuilder();
expect(() => embed.setFooter({ text: 'a'.repeat(2049) })).toThrowError();
expect(() => embed.setFooter({ text: 'a'.repeat(2_049) })).toThrowError();
});
});
@@ -411,7 +411,7 @@ describe('Embed', () => {
test('4', () => {
const embed = new EmbedBuilder();
expect(() => embed.addFields({ name: '', value: 'a'.repeat(1025) })).toThrowError();
expect(() => embed.addFields({ name: '', value: 'a'.repeat(1_025) })).toThrowError();
});
});
});

View File

@@ -1,6 +1,8 @@
/* eslint-disable no-template-curly-in-string */
import { URL } from 'node:url';
import { describe, test, expect, vitest } from 'vitest';
import {
chatInputApplicationCommandMention,
blockQuote,
bold,
channelLink,
@@ -21,7 +23,7 @@ import {
TimestampStyles,
underscore,
userMention,
} from '../../src';
} from '../../src/index.js';
describe('Message formatters', () => {
describe('codeBlock', () => {
@@ -136,6 +138,26 @@ describe('Message formatters', () => {
expect(roleMention('815434166602170409')).toEqual('<@&815434166602170409>');
});
});
describe('chatInputApplicationCommandMention', () => {
test('GIVEN commandName and commandId THEN returns "</[commandName]:[commandId]>"', () => {
expect(chatInputApplicationCommandMention('airhorn', '815434166602170409')).toEqual(
'</airhorn:815434166602170409>',
);
});
test('GIVEN commandName, subcommandName, and commandId THEN returns "</[commandName] [subcommandName]:[commandId]>"', () => {
expect(chatInputApplicationCommandMention('airhorn', 'sub', '815434166602170409')).toEqual(
'</airhorn sub:815434166602170409>',
);
});
test('GIVEN commandName, subcommandGroupName, subcommandName, and commandId THEN returns "</[commandName] [subcommandGroupName] [subcommandName]:[commandId]>"', () => {
expect(chatInputApplicationCommandMention('airhorn', 'group', 'sub', '815434166602170409')).toEqual(
'</airhorn group sub:815434166602170409>',
);
});
});
});
describe('formatEmoji', () => {
@@ -183,7 +205,7 @@ describe('Message formatters', () => {
describe('time', () => {
test('GIVEN no arguments THEN returns "<t:${bigint}>"', () => {
vitest.useFakeTimers();
vitest.setSystemTime(1566424897579);
vitest.setSystemTime(1_566_424_897_579);
expect<`<t:${bigint}>`>(time()).toEqual('<t:1566424897>');
@@ -191,29 +213,29 @@ describe('Message formatters', () => {
});
test('GIVEN a date THEN returns "<t:${bigint}>"', () => {
expect<`<t:${bigint}>`>(time(new Date(1867424897579))).toEqual('<t:1867424897>');
expect<`<t:${bigint}>`>(time(new Date(1_867_424_897_579))).toEqual('<t:1867424897>');
});
test('GIVEN a date and a style from string THEN returns "<t:${bigint}:${style}>"', () => {
expect<`<t:${bigint}:d>`>(time(new Date(1867424897579), 'd')).toEqual('<t:1867424897:d>');
expect<`<t:${bigint}:d>`>(time(new Date(1_867_424_897_579), 'd')).toEqual('<t:1867424897:d>');
});
test('GIVEN a date and a format from enum THEN returns "<t:${bigint}:${style}>"', () => {
expect<`<t:${bigint}:R>`>(time(new Date(1867424897579), TimestampStyles.RelativeTime)).toEqual(
expect<`<t:${bigint}:R>`>(time(new Date(1_867_424_897_579), TimestampStyles.RelativeTime)).toEqual(
'<t:1867424897:R>',
);
});
test('GIVEN a date THEN returns "<t:${time}>"', () => {
expect<'<t:1867424897>'>(time(1867424897)).toEqual('<t:1867424897>');
expect<'<t:1867424897>'>(time(1_867_424_897)).toEqual('<t:1867424897>');
});
test('GIVEN a date and a style from string THEN returns "<t:${time}:${style}>"', () => {
expect<'<t:1867424897:d>'>(time(1867424897, 'd')).toEqual('<t:1867424897:d>');
expect<'<t:1867424897:d>'>(time(1_867_424_897, 'd')).toEqual('<t:1867424897:d>');
});
test('GIVEN a date and a format from enum THEN returns "<t:${time}:${style}>"', () => {
expect<'<t:1867424897:R>'>(time(1867424897, TimestampStyles.RelativeTime)).toEqual('<t:1867424897:R>');
expect<'<t:1867424897:R>'>(time(1_867_424_897, TimestampStyles.RelativeTime)).toEqual('<t:1867424897:R>');
});
});

View File

@@ -1,33 +1,5 @@
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();
});
});
import { enableValidators, disableValidators, isValidationEnabled } from '../src/index.js';
describe('validation', () => {
test('enables validation', () => {

View File

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

View File

@@ -1,24 +1,24 @@
{
"name": "@discordjs/builders",
"version": "1.1.0",
"version": "1.2.0",
"description": "A set of builders that you can use when creating your bot",
"scripts": {
"test": "vitest run",
"build": "unbuild",
"lint": "prettier --check . && TIMING=1 eslint src __tests__ --ext mjs,js,ts",
"format": "prettier --write . && TIMING=1 eslint src __tests__ --ext mjs,js,ts --fix",
"build": "tsup",
"lint": "prettier --check . && cross-env TIMING=1 eslint src __tests__ --ext mjs,js,ts",
"format": "prettier --write . && cross-env TIMING=1 eslint src __tests__ --ext mjs,js,ts --fix",
"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",
"docs": "downlevel-dts dist docs/dist --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.cjs",
"main": "./dist/index.js",
"module": "./dist/index.mjs",
"types": "./dist/index.d.ts",
"exports": {
"import": "./dist/index.mjs",
"require": "./dist/index.cjs",
"require": "./dist/index.js",
"types": "./dist/index.d.ts"
},
"directories": {
@@ -33,7 +33,7 @@
"Crawl <icrawltogo@gmail.com>",
"Amish Shah <amishshah.2k@gmail.com>",
"SpaceEEC <spaceeec@yahoo.com>",
"Antonio Roman <kyradiscord@gmail.com>"
"Aura Román <kyradiscord@gmail.com>"
],
"license": "Apache-2.0",
"keywords": [
@@ -54,8 +54,9 @@
},
"homepage": "https://discord.js.org",
"dependencies": {
"@sapphire/shapeshift": "^3.5.1",
"discord-api-types": "^0.37.3",
"@discordjs/util": "workspace:^",
"@sapphire/shapeshift": "^3.6.0",
"discord-api-types": "^0.37.11",
"fast-deep-equal": "^3.1.3",
"ts-mixer": "^6.0.1",
"tslib": "^2.4.0"
@@ -63,23 +64,17 @@
"devDependencies": {
"@discordjs/docgen": "workspace:^",
"@favware/cliff-jumper": "^1.8.7",
"@microsoft/api-extractor": "^7.29.3",
"@types/node": "^16.11.52",
"@typescript-eslint/eslint-plugin": "^5.33.1",
"@typescript-eslint/parser": "^5.33.1",
"@vitest/coverage-c8": "^0.22.1",
"downlevel-dts": "^0.10.0",
"eslint": "^8.22.0",
"eslint-config-marine": "^9.4.1",
"eslint-config-prettier": "^8.5.0",
"eslint-import-resolver-typescript": "^3.4.2",
"eslint-plugin-import": "^2.26.0",
"eslint-plugin-tsdoc": "^0.2.16",
"@microsoft/api-extractor": "^7.31.2",
"@types/node": "^16.11.60",
"@vitest/coverage-c8": "^0.23.4",
"cross-env": "^7.0.3",
"downlevel-dts": "^0.10.1",
"eslint": "^8.24.0",
"eslint-config-neon": "^0.1.33",
"prettier": "^2.7.1",
"rollup-plugin-typescript2": "^0.33.0",
"typescript": "^4.7.4",
"unbuild": "^0.8.9",
"vitest": "^0.22.1"
"tsup": "^6.2.3",
"typescript": "^4.8.3",
"vitest": "^0.23.4"
},
"engines": {
"node": ">=16.9.0"

View File

@@ -1,21 +1,23 @@
/* eslint-disable jsdoc/check-param-names */
import {
type APIActionRowComponent,
ComponentType,
APIMessageActionRowComponent,
APIModalActionRowComponent,
APIActionRowComponentTypes,
type APIMessageActionRowComponent,
type APIModalActionRowComponent,
type APIActionRowComponentTypes,
} from 'discord-api-types/v10';
import { ComponentBuilder } from './Component';
import { createComponentBuilder } from './Components';
import type { ButtonBuilder } from './button/Button';
import type { SelectMenuBuilder } from './selectMenu/SelectMenu';
import type { TextInputBuilder } from './textInput/TextInput';
import { normalizeArray, type RestOrArray } from '../util/normalizeArray';
import { normalizeArray, type RestOrArray } from '../util/normalizeArray.js';
import { ComponentBuilder } from './Component.js';
import { createComponentBuilder } from './Components.js';
import type { ButtonBuilder } from './button/Button.js';
import type { SelectMenuBuilder } from './selectMenu/SelectMenu.js';
import type { TextInputBuilder } from './textInput/TextInput.js';
export type MessageComponentBuilder =
| MessageActionRowComponentBuilder
| ActionRowBuilder<MessageActionRowComponentBuilder>;
export type ModalComponentBuilder = ModalActionRowComponentBuilder | ActionRowBuilder<ModalActionRowComponentBuilder>;
| ActionRowBuilder<MessageActionRowComponentBuilder>
| MessageActionRowComponentBuilder;
export type ModalComponentBuilder = ActionRowBuilder<ModalActionRowComponentBuilder> | ModalActionRowComponentBuilder;
export type MessageActionRowComponentBuilder = ButtonBuilder | SelectMenuBuilder;
export type ModalActionRowComponentBuilder = TextInputBuilder;
export type AnyComponentBuilder = MessageActionRowComponentBuilder | ModalActionRowComponentBuilder;
@@ -33,9 +35,43 @@ export class ActionRowBuilder<T extends AnyComponentBuilder> extends ComponentBu
*/
public readonly components: T[];
/**
* Creates a new action row from API data
*
* @param data - The API data to create this action row with
* @example
* Creating an action row from an API data object
* ```ts
* const actionRow = new ActionRowBuilder({
* components: [
* {
* custom_id: "custom id",
* label: "Type something",
* style: TextInputStyle.Short,
* type: ComponentType.TextInput,
* },
* ],
* });
* ```
* @example
* Creating an action row using setters and API data
* ```ts
* const actionRow = new ActionRowBuilder({
* components: [
* {
* custom_id: "custom id",
* label: "Click me",
* style: ButtonStyle.Primary,
* type: ComponentType.Button,
* },
* ],
* })
* .addComponents(button2, button3);
* ```
*/
public constructor({ components, ...data }: Partial<APIActionRowComponent<APIActionRowComponentTypes>> = {}) {
super({ type: ComponentType.ActionRow, ...data });
this.components = (components?.map((c) => createComponentBuilder(c)) ?? []) as T[];
this.components = (components?.map((component) => createComponentBuilder(component)) ?? []) as T[];
}
/**
@@ -62,7 +98,6 @@ export class ActionRowBuilder<T extends AnyComponentBuilder> extends ComponentBu
* {@inheritDoc ComponentBuilder.toJSON}
*/
public toJSON(): APIActionRowComponent<ReturnType<T['toJSON']>> {
// eslint-disable-next-line @typescript-eslint/consistent-type-assertions
return {
...this.data,
components: this.components.map((component) => component.toJSON()),

View File

@@ -1,7 +1,7 @@
import { s } from '@sapphire/shapeshift';
import { APIMessageComponentEmoji, ButtonStyle } from 'discord-api-types/v10';
import { SelectMenuOptionBuilder } from './selectMenu/SelectMenuOption';
import { isValidationEnabled } from '../util/validation';
import { ButtonStyle, type APIMessageComponentEmoji } from 'discord-api-types/v10';
import { isValidationEnabled } from '../util/validation.js';
import { SelectMenuOptionBuilder } from './selectMenu/SelectMenuOption.js';
export const customIdValidator = s.string
.lengthGreaterThanOrEqual(1)

View File

@@ -1,12 +1,12 @@
import type { JSONEncodable } from '@discordjs/util';
import type {
APIActionRowComponent,
APIActionRowComponentTypes,
APIBaseComponent,
ComponentType,
} from 'discord-api-types/v10';
import type { JSONEncodable } from '../util/jsonEncodable';
export type AnyAPIActionRowComponent = APIActionRowComponentTypes | APIActionRowComponent<APIActionRowComponentTypes>;
export type AnyAPIActionRowComponent = APIActionRowComponent<APIActionRowComponentTypes> | APIActionRowComponentTypes;
/**
* Represents a discord component

View File

@@ -1,14 +1,14 @@
import { APIMessageComponent, APIModalComponent, ComponentType } from 'discord-api-types/v10';
import { ComponentType, type APIMessageComponent, type APIModalComponent } from 'discord-api-types/v10';
import {
ActionRowBuilder,
type AnyComponentBuilder,
type MessageComponentBuilder,
type ModalComponentBuilder,
} from './ActionRow';
import { ComponentBuilder } from './Component';
import { ButtonBuilder } from './button/Button';
import { SelectMenuBuilder } from './selectMenu/SelectMenu';
import { TextInputBuilder } from './textInput/TextInput';
} from './ActionRow.js';
import { ComponentBuilder } from './Component.js';
import { ButtonBuilder } from './button/Button.js';
import { SelectMenuBuilder } from './selectMenu/SelectMenu.js';
import { TextInputBuilder } from './textInput/TextInput.js';
export interface MappedComponentTypes {
[ComponentType.ActionRow]: ActionRowBuilder<AnyComponentBuilder>;
@@ -23,7 +23,8 @@ export interface MappedComponentTypes {
* @param data - The api data to transform to a component class
*/
export function createComponentBuilder<T extends keyof MappedComponentTypes>(
data: (APIMessageComponent | APIModalComponent) & { type: T },
// eslint-disable-next-line @typescript-eslint/sort-type-union-intersection-members
data: (APIModalComponent | APIMessageComponent) & { type: T },
): MappedComponentTypes[T];
export function createComponentBuilder<C extends MessageComponentBuilder | ModalComponentBuilder>(data: C): C;
export function createComponentBuilder(
@@ -43,8 +44,7 @@ export function createComponentBuilder(
case ComponentType.TextInput:
return new TextInputBuilder(data);
default:
// @ts-expect-error
// eslint-disable-next-line @typescript-eslint/restrict-template-expressions
// @ts-expect-error: This case can still occur if we get a newer unsupported component type
throw new Error(`Cannot properly serialize component type: ${data.type}`);
}
}

View File

@@ -1,10 +1,10 @@
import {
ComponentType,
ButtonStyle,
type APIMessageComponentEmoji,
type APIButtonComponent,
type APIButtonComponentWithURL,
type APIButtonComponentWithCustomId,
type ButtonStyle,
} from 'discord-api-types/v10';
import {
buttonLabelValidator,
@@ -14,8 +14,8 @@ import {
emojiValidator,
urlValidator,
validateRequiredButtonParameters,
} from '../Assertions';
import { ComponentBuilder } from '../Component';
} from '../Assertions.js';
import { ComponentBuilder } from '../Component.js';
/**
* Represents a button component
@@ -23,31 +23,30 @@ import { ComponentBuilder } from '../Component';
export class ButtonBuilder extends ComponentBuilder<APIButtonComponent> {
/**
* Creates a new button from API data
* @param data - The API data to create this button with
*
* @param data - The API data to create this button with
* @example
* Creating a button from an API data object
* ```ts
* const button = new ButtonBuilder({
* style: 'primary',
* custom_id: 'a cool button',
* style: ButtonStyle.Primary,
* label: 'Click Me',
* emoji: {
* name: ':smile:',
* id: '12345678901234567890123456789012',
* name: 'smile',
* id: '123456789012345678',
* },
* custom_id: '12345678901234567890123456789012',
* });
* ```
*
* @example
* Creating a button using setters and API data
* ```ts
* const button = new ButtonBuilder({
* style: 'primary',
* style: ButtonStyle.Secondary,
* label: 'Click Me',
* })
* .setEmoji({ name: ':smile:', id: '12345678901234567890123456789012' })
* .setCustomId('12345678901234567890123456789012');
* .setEmoji({ name: '🙂' })
* .setCustomId('another cool button');
* ```
*/
public constructor(data?: Partial<APIButtonComponent>) {
@@ -70,7 +69,6 @@ export class ButtonBuilder extends ComponentBuilder<APIButtonComponent> {
* @remarks
* This method is only available to buttons using the `Link` button style.
* Only three types of URL schemes are currently supported: `https://`, `http://` and `discord://`
*
* @param url - The URL to open when this button is clicked
*/
public setURL(url: string) {
@@ -83,7 +81,6 @@ export class ButtonBuilder extends ComponentBuilder<APIButtonComponent> {
*
* @remarks
* This method is only applicable to buttons that are not using the `Link` button style.
*
* @param customId - The custom id to use for this button
*/
public setCustomId(customId: string) {
@@ -132,7 +129,7 @@ export class ButtonBuilder extends ComponentBuilder<APIButtonComponent> {
(this.data as APIButtonComponentWithCustomId).custom_id,
(this.data as APIButtonComponentWithURL).url,
);
// eslint-disable-next-line @typescript-eslint/consistent-type-assertions
return {
...this.data,
} as APIButtonComponent;

View File

@@ -1,6 +1,5 @@
import { APISelectMenuOption, ComponentType, type APISelectMenuComponent } from 'discord-api-types/v10';
import { SelectMenuOptionBuilder } from './SelectMenuOption';
import { normalizeArray, type RestOrArray } from '../../util/normalizeArray';
import { ComponentType, type APISelectMenuComponent, type APISelectMenuOption } from 'discord-api-types/v10';
import { normalizeArray, type RestOrArray } from '../../util/normalizeArray.js';
import {
customIdValidator,
disabledValidator,
@@ -9,8 +8,9 @@ import {
optionsLengthValidator,
placeholderValidator,
validateRequiredSelectMenuParameters,
} from '../Assertions';
import { ComponentBuilder } from '../Component';
} from '../Assertions.js';
import { ComponentBuilder } from '../Component.js';
import { SelectMenuOptionBuilder } from './SelectMenuOption.js';
/**
* Represents a select menu component
@@ -21,10 +21,41 @@ export class SelectMenuBuilder extends ComponentBuilder<APISelectMenuComponent>
*/
public readonly options: SelectMenuOptionBuilder[];
/**
* Creates a new select menu from API data
*
* @param data - The API data to create this select menu with
* @example
* Creating a select menu from an API data object
* ```ts
* const selectMenu = new SelectMenuBuilder({
* custom_id: 'a cool select menu',
* placeholder: 'select an option',
* max_values: 2,
* options: [
* { label: 'option 1', value: '1' },
* { label: 'option 2', value: '2' },
* { label: 'option 3', value: '3' },
* ],
* });
* ```
* @example
* Creating a select menu using setters and API data
* ```ts
* const selectMenu = new SelectMenuBuilder({
* custom_id: 'a cool select menu',
* })
* .setMinValues(1)
* .addOptions({
* label: 'Catchy',
* value: 'catch',
* });
* ```
*/
public constructor(data?: Partial<APISelectMenuComponent>) {
const { options, ...initData } = data ?? {};
super({ type: ComponentType.SelectMenu, ...initData });
this.options = options?.map((o) => new SelectMenuOptionBuilder(o)) ?? [];
this.options = options?.map((option) => new SelectMenuOptionBuilder(option)) ?? [];
}
/**
@@ -83,7 +114,8 @@ export class SelectMenuBuilder extends ComponentBuilder<APISelectMenuComponent>
* @param options - The options to add to this select menu
* @returns
*/
public addOptions(...options: RestOrArray<SelectMenuOptionBuilder | APISelectMenuOption>) {
public addOptions(...options: RestOrArray<APISelectMenuOption | SelectMenuOptionBuilder>) {
// eslint-disable-next-line no-param-reassign
options = normalizeArray(options);
optionsLengthValidator.parse(this.options.length + options.length);
this.options.push(
@@ -101,7 +133,8 @@ export class SelectMenuBuilder extends ComponentBuilder<APISelectMenuComponent>
*
* @param options - The options to set on this select menu
*/
public setOptions(...options: RestOrArray<SelectMenuOptionBuilder | APISelectMenuOption>) {
public setOptions(...options: RestOrArray<APISelectMenuOption | SelectMenuOptionBuilder>) {
// eslint-disable-next-line no-param-reassign
options = normalizeArray(options);
optionsLengthValidator.parse(options.length);
this.options.splice(
@@ -121,10 +154,10 @@ export class SelectMenuBuilder extends ComponentBuilder<APISelectMenuComponent>
*/
public toJSON(): APISelectMenuComponent {
validateRequiredSelectMenuParameters(this.options, this.data.custom_id);
// eslint-disable-next-line @typescript-eslint/consistent-type-assertions
return {
...this.data,
options: this.options.map((o) => o.toJSON()),
options: this.options.map((option) => option.toJSON()),
} as APISelectMenuComponent;
}
}

View File

@@ -1,17 +1,38 @@
import type { JSONEncodable } from '@discordjs/util';
import type { APIMessageComponentEmoji, APISelectMenuOption } from 'discord-api-types/v10';
import type { JSONEncodable } from '../../util/jsonEncodable';
import {
defaultValidator,
emojiValidator,
labelValueDescriptionValidator,
validateRequiredSelectMenuOptionParameters,
} from '../Assertions';
} from '../Assertions.js';
/**
* Represents a option within a select menu component
*/
export class SelectMenuOptionBuilder implements JSONEncodable<APISelectMenuOption> {
/**
* Creates a new select menu option from API data
*
* @param data - The API data to create this select menu option with
* @example
* Creating a select menu option from an API data object
* ```ts
* const selectMenuOption = new SelectMenuOptionBuilder({
* label: 'catchy label',
* value: '1',
* });
* ```
* @example
* Creating a select menu option using setters and API data
* ```ts
* const selectMenuOption = new SelectMenuOptionBuilder({
* default: true,
* value: '1',
* })
* .setLabel('woah')
* ```
*/
public constructor(public data: Partial<APISelectMenuOption> = {}) {}
/**
@@ -69,7 +90,7 @@ export class SelectMenuOptionBuilder implements JSONEncodable<APISelectMenuOptio
*/
public toJSON(): APISelectMenuOption {
validateRequiredSelectMenuOptionParameters(this.data.label, this.data.value);
// eslint-disable-next-line @typescript-eslint/consistent-type-assertions
return {
...this.data,
} as APISelectMenuOption;

View File

@@ -1,19 +1,19 @@
import { s } from '@sapphire/shapeshift';
import { TextInputStyle } from 'discord-api-types/v10';
import { isValidationEnabled } from '../../util/validation';
import { customIdValidator } from '../Assertions';
import { isValidationEnabled } from '../../util/validation.js';
import { customIdValidator } from '../Assertions.js';
export const textInputStyleValidator = s.nativeEnum(TextInputStyle);
export const minLengthValidator = s.number.int
.greaterThanOrEqual(0)
.lessThanOrEqual(4000)
.lessThanOrEqual(4_000)
.setValidationEnabled(isValidationEnabled);
export const maxLengthValidator = s.number.int
.greaterThanOrEqual(1)
.lessThanOrEqual(4000)
.lessThanOrEqual(4_000)
.setValidationEnabled(isValidationEnabled);
export const requiredValidator = s.boolean;
export const valueValidator = s.string.lengthLessThanOrEqual(4000).setValidationEnabled(isValidationEnabled);
export const valueValidator = s.string.lengthLessThanOrEqual(4_000).setValidationEnabled(isValidationEnabled);
export const placeholderValidator = s.string.lengthLessThanOrEqual(100).setValidationEnabled(isValidationEnabled);
export const labelValidator = s.string
.lengthGreaterThanOrEqual(1)

View File

@@ -1,5 +1,8 @@
import { isJSONEncodable, type Equatable, type JSONEncodable } from '@discordjs/util';
import { ComponentType, type TextInputStyle, type APITextInputComponent } from 'discord-api-types/v10';
import isEqual from 'fast-deep-equal';
import { customIdValidator } from '../Assertions.js';
import { ComponentBuilder } from '../Component.js';
import {
maxLengthValidator,
minLengthValidator,
@@ -9,16 +12,35 @@ import {
validateRequiredParameters,
labelValidator,
textInputStyleValidator,
} from './Assertions';
import type { Equatable } from '../../util/equatable';
import { isJSONEncodable, type JSONEncodable } from '../../util/jsonEncodable';
import { customIdValidator } from '../Assertions';
import { ComponentBuilder } from '../Component';
} from './Assertions.js';
export class TextInputBuilder
extends ComponentBuilder<APITextInputComponent>
implements Equatable<JSONEncodable<APITextInputComponent> | APITextInputComponent>
implements Equatable<APITextInputComponent | JSONEncodable<APITextInputComponent>>
{
/**
* Creates a new text input from API data
*
* @param data - The API data to create this text input with
* @example
* Creating a select menu option from an API data object
* ```ts
* const textInput = new TextInputBuilder({
* custom_id: 'a cool select menu',
* label: 'Type something',
* style: TextInputStyle.Short,
* });
* ```
* @example
* Creating a select menu option using setters and API data
* ```ts
* const textInput = new TextInputBuilder({
* label: 'Type something else',
* })
* .setCustomId('woah')
* .setStyle(TextInputStyle.Paragraph);
* ```
*/
public constructor(data?: APITextInputComponent & { type?: ComponentType.TextInput }) {
super({ type: ComponentType.TextInput, ...data });
}
@@ -108,7 +130,7 @@ export class TextInputBuilder
*/
public toJSON(): APITextInputComponent {
validateRequiredParameters(this.data.custom_id, this.data.style, this.data.label);
// eslint-disable-next-line @typescript-eslint/consistent-type-assertions
return {
...this.data,
} as APITextInputComponent;
@@ -117,7 +139,7 @@ export class TextInputBuilder
/**
* {@inheritDoc Equatable.equals}
*/
public equals(other: JSONEncodable<APITextInputComponent> | APITextInputComponent): boolean {
public equals(other: APITextInputComponent | JSONEncodable<APITextInputComponent>): boolean {
if (isJSONEncodable(other)) {
return isEqual(other.toJSON(), this.data);
}

View File

@@ -1,43 +1,42 @@
export * as EmbedAssertions from './messages/embed/Assertions';
export * from './messages/embed/Embed';
export * from './messages/formatters';
export * as EmbedAssertions from './messages/embed/Assertions.js';
export * from './messages/embed/Embed.js';
export * from './messages/formatters.js';
export * as ComponentAssertions from './components/Assertions';
export * from './components/ActionRow';
export * from './components/button/Button';
export * from './components/Component';
export * from './components/Components';
export * from './components/textInput/TextInput';
export * as TextInputAssertions from './components/textInput/Assertions';
export * from './interactions/modals/Modal';
export * as ModalAssertions from './interactions/modals/Assertions';
export * from './components/selectMenu/SelectMenu';
export * from './components/selectMenu/SelectMenuOption';
export * as ComponentAssertions from './components/Assertions.js';
export * from './components/ActionRow.js';
export * from './components/button/Button.js';
export * from './components/Component.js';
export * from './components/Components.js';
export * from './components/textInput/TextInput.js';
export * as TextInputAssertions from './components/textInput/Assertions.js';
export * from './interactions/modals/Modal.js';
export * as ModalAssertions from './interactions/modals/Assertions.js';
export * from './components/selectMenu/SelectMenu.js';
export * from './components/selectMenu/SelectMenuOption.js';
export * as SlashCommandAssertions from './interactions/slashCommands/Assertions';
export * from './interactions/slashCommands/SlashCommandBuilder';
export * from './interactions/slashCommands/SlashCommandSubcommands';
export * from './interactions/slashCommands/options/boolean';
export * from './interactions/slashCommands/options/channel';
export * from './interactions/slashCommands/options/integer';
export * from './interactions/slashCommands/options/mentionable';
export * from './interactions/slashCommands/options/number';
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 SlashCommandAssertions from './interactions/slashCommands/Assertions.js';
export * from './interactions/slashCommands/SlashCommandBuilder.js';
export * from './interactions/slashCommands/SlashCommandSubcommands.js';
export * from './interactions/slashCommands/options/boolean.js';
export * from './interactions/slashCommands/options/channel.js';
export * from './interactions/slashCommands/options/integer.js';
export * from './interactions/slashCommands/options/mentionable.js';
export * from './interactions/slashCommands/options/number.js';
export * from './interactions/slashCommands/options/role.js';
export * from './interactions/slashCommands/options/attachment.js';
export * from './interactions/slashCommands/options/string.js';
export * from './interactions/slashCommands/options/user.js';
export * from './interactions/slashCommands/mixins/ApplicationCommandNumericOptionMinMaxValueMixin.js';
export * from './interactions/slashCommands/mixins/ApplicationCommandOptionBase.js';
export * from './interactions/slashCommands/mixins/ApplicationCommandOptionChannelTypesMixin.js';
export * from './interactions/slashCommands/mixins/ApplicationCommandOptionWithChoicesAndAutocompleteMixin.js';
export * from './interactions/slashCommands/mixins/NameAndDescription.js';
export * from './interactions/slashCommands/mixins/SharedSlashCommandOptions.js';
export * as ContextMenuCommandAssertions from './interactions/contextMenuCommands/Assertions';
export * from './interactions/contextMenuCommands/ContextMenuCommandBuilder';
export * as ContextMenuCommandAssertions from './interactions/contextMenuCommands/Assertions.js';
export * from './interactions/contextMenuCommands/ContextMenuCommandBuilder.js';
export * from './util/jsonEncodable';
export * from './util/equatable';
export * from './util/componentUtil';
export * from './util/normalizeArray';
export * from './util/validation';
export * from './util/componentUtil.js';
export * from './util/normalizeArray.js';
export * from './util/validation.js';
export * from '@discordjs/util';

View File

@@ -1,11 +1,12 @@
import { s } from '@sapphire/shapeshift';
import { ApplicationCommandType } from 'discord-api-types/v10';
import type { ContextMenuCommandType } from './ContextMenuCommandBuilder';
import { isValidationEnabled } from '../../util/validation';
import { isValidationEnabled } from '../../util/validation.js';
import type { ContextMenuCommandType } from './ContextMenuCommandBuilder.js';
const namePredicate = s.string
.lengthGreaterThanOrEqual(1)
.lengthLessThanOrEqual(32)
// eslint-disable-next-line prefer-named-capture-group, unicorn/no-unsafe-regex
.regex(/^( *[\p{L}\p{N}\p{sc=Devanagari}\p{sc=Thai}_-]+ *)+$/u)
.setValidationEnabled(isValidationEnabled);
const typePredicate = s

View File

@@ -3,8 +3,9 @@ import type {
LocaleString,
LocalizationMap,
Permissions,
RESTPostAPIApplicationCommandsJSONBody,
RESTPostAPIContextMenuApplicationCommandsJSONBody,
} from 'discord-api-types/v10';
import { validateLocale, validateLocalizationMap } from '../slashCommands/Assertions.js';
import {
validateRequiredParameters,
validateName,
@@ -12,8 +13,7 @@ import {
validateDefaultPermission,
validateDefaultMemberPermissions,
validateDMPermission,
} from './Assertions';
import { validateLocale, validateLocalizationMap } from '../slashCommands/Assertions';
} from './Assertions.js';
export class ContextMenuCommandBuilder {
/**
@@ -81,10 +81,9 @@ export class ContextMenuCommandBuilder {
/**
* Sets whether the command is enabled by default when the application is added to a guild.
*
* **Note**: If set to `false`, you will have to later `PUT` the permissions for this command.
*
* @remarks
* 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
*
* @see https://discord.com/developers/docs/interactions/application-commands#permissions
* @deprecated Use {@link ContextMenuCommandBuilder.setDefaultMemberPermissions} or {@link ContextMenuCommandBuilder.setDMPermission} instead.
*/
@@ -100,10 +99,9 @@ export class ContextMenuCommandBuilder {
/**
* 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.
*
* @remarks
* 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) {
@@ -120,7 +118,6 @@ export class ContextMenuCommandBuilder {
* 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) {
@@ -169,18 +166,19 @@ export class ContextMenuCommandBuilder {
Reflect.set(this, 'name_localizations', {});
Object.entries(localizedNames).forEach((args) =>
this.setNameLocalization(...(args as [LocaleString, string | null])),
);
for (const args of Object.entries(localizedNames))
this.setNameLocalization(...(args as [LocaleString, string | null]));
return this;
}
/**
* Returns the final data that should be sent to Discord.
*
* **Note:** Calling this function will validate required properties based on their conditions.
* @remarks
* This method runs validations on the data before serializing it.
* As such, it may throw an error if the data is invalid.
*/
public toJSON(): RESTPostAPIApplicationCommandsJSONBody {
public toJSON(): RESTPostAPIContextMenuApplicationCommandsJSONBody {
validateRequiredParameters(this.name, this.type);
validateLocalizationMap(this.name_localizations);
@@ -189,4 +187,4 @@ export class ContextMenuCommandBuilder {
}
}
export type ContextMenuCommandType = ApplicationCommandType.User | ApplicationCommandType.Message;
export type ContextMenuCommandType = ApplicationCommandType.Message | ApplicationCommandType.User;

View File

@@ -1,7 +1,7 @@
import { s } from '@sapphire/shapeshift';
import { ActionRowBuilder, type ModalActionRowComponentBuilder } from '../../components/ActionRow';
import { customIdValidator } from '../../components/Assertions';
import { isValidationEnabled } from '../../util/validation';
import { ActionRowBuilder, type ModalActionRowComponentBuilder } from '../../components/ActionRow.js';
import { customIdValidator } from '../../components/Assertions.js';
import { isValidationEnabled } from '../../util/validation.js';
export const titleValidator = s.string
.lengthGreaterThanOrEqual(1)

View File

@@ -1,22 +1,23 @@
import type { JSONEncodable } from '@discordjs/util';
import type {
APIActionRowComponent,
APIModalActionRowComponent,
APIModalInteractionResponseCallbackData,
} from 'discord-api-types/v10';
import { titleValidator, validateRequiredParameters } from './Assertions';
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';
import { ActionRowBuilder, type ModalActionRowComponentBuilder } from '../../components/ActionRow.js';
import { customIdValidator } from '../../components/Assertions.js';
import { createComponentBuilder } from '../../components/Components.js';
import { normalizeArray, type RestOrArray } from '../../util/normalizeArray.js';
import { titleValidator, validateRequiredParameters } from './Assertions.js';
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)) ??
this.components = (components?.map((component) => createComponentBuilder(component)) ??
[]) as ActionRowBuilder<ModalActionRowComponentBuilder>[];
}
@@ -75,7 +76,7 @@ export class ModalBuilder implements JSONEncodable<APIModalInteractionResponseCa
*/
public toJSON(): APIModalInteractionResponseCallbackData {
validateRequiredParameters(this.data.custom_id, this.data.title, this.components);
// eslint-disable-next-line @typescript-eslint/consistent-type-assertions
return {
...this.data,
components: this.components.map((component) => component.toJSON()),

View File

@@ -1,9 +1,9 @@
import { s } from '@sapphire/shapeshift';
import { type APIApplicationCommandOptionChoice, Locale, LocalizationMap } from 'discord-api-types/v10';
import type { ToAPIApplicationCommandOptions } from './SlashCommandBuilder';
import type { SlashCommandSubcommandBuilder, SlashCommandSubcommandGroupBuilder } from './SlashCommandSubcommands';
import type { ApplicationCommandOptionBase } from './mixins/ApplicationCommandOptionBase';
import { isValidationEnabled } from '../../util/validation';
import { Locale, type APIApplicationCommandOptionChoice, type LocalizationMap } from 'discord-api-types/v10';
import { isValidationEnabled } from '../../util/validation.js';
import type { ToAPIApplicationCommandOptions } from './SlashCommandBuilder.js';
import type { SlashCommandSubcommandBuilder, SlashCommandSubcommandGroupBuilder } from './SlashCommandSubcommands.js';
import type { ApplicationCommandOptionBase } from './mixins/ApplicationCommandOptionBase.js';
const namePredicate = s.string
.lengthGreaterThanOrEqual(1)

View File

@@ -2,7 +2,7 @@ import type {
APIApplicationCommandOption,
LocalizationMap,
Permissions,
RESTPostAPIApplicationCommandsJSONBody,
RESTPostAPIChatInputApplicationCommandsJSONBody,
} from 'discord-api-types/v10';
import { mix } from 'ts-mixer';
import {
@@ -13,10 +13,10 @@ import {
validateDMPermission,
validateMaxOptionsLength,
validateRequiredParameters,
} from './Assertions';
import { SlashCommandSubcommandBuilder, SlashCommandSubcommandGroupBuilder } from './SlashCommandSubcommands';
import { SharedNameAndDescription } from './mixins/NameAndDescription';
import { SharedSlashCommandOptions } from './mixins/SharedSlashCommandOptions';
} from './Assertions.js';
import { SlashCommandSubcommandBuilder, SlashCommandSubcommandGroupBuilder } from './SlashCommandSubcommands.js';
import { SharedNameAndDescription } from './mixins/NameAndDescription.js';
import { SharedSlashCommandOptions } from './mixins/SharedSlashCommandOptions.js';
@mix(SharedSlashCommandOptions, SharedNameAndDescription)
export class SlashCommandBuilder {
@@ -67,9 +67,11 @@ export class SlashCommandBuilder {
/**
* Returns the final data that should be sent to Discord.
*
* **Note:** Calling this function will validate required properties based on their conditions.
* @remarks
* This method runs validations on the data before serializing it.
* As such, it may throw an error if the data is invalid.
*/
public toJSON(): RESTPostAPIApplicationCommandsJSONBody {
public toJSON(): RESTPostAPIChatInputApplicationCommandsJSONBody {
validateRequiredParameters(this.name, this.description, this.options);
validateLocalizationMap(this.name_localizations);
@@ -84,10 +86,9 @@ export class SlashCommandBuilder {
/**
* Sets whether the command is enabled by default when the application is added to a guild.
*
* **Note**: If set to `false`, you will have to later `PUT` the permissions for this command.
*
* @remarks
* 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
*
* @see https://discord.com/developers/docs/interactions/application-commands#permissions
* @deprecated Use {@link (SlashCommandBuilder:class).setDefaultMemberPermissions} or {@link (SlashCommandBuilder:class).setDMPermission} instead.
*/
@@ -103,10 +104,9 @@ export class SlashCommandBuilder {
/**
* 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.
*
* @remarks
* 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) {
@@ -123,7 +123,6 @@ export class SlashCommandBuilder {
* 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) {
@@ -191,8 +190,7 @@ export class SlashCommandBuilder {
export interface SlashCommandBuilder extends SharedNameAndDescription, SharedSlashCommandOptions {}
export interface SlashCommandSubcommandsOnlyBuilder
extends SharedNameAndDescription,
Pick<SlashCommandBuilder, 'toJSON' | 'addSubcommand' | 'addSubcommandGroup'> {}
extends Omit<SlashCommandBuilder, Exclude<keyof SharedSlashCommandOptions, 'options'>> {}
export interface SlashCommandOptionsOnlyBuilder
extends SharedNameAndDescription,
@@ -200,5 +198,5 @@ export interface SlashCommandOptionsOnlyBuilder
Pick<SlashCommandBuilder, 'toJSON'> {}
export interface ToAPIApplicationCommandOptions {
toJSON: () => APIApplicationCommandOption;
toJSON(): APIApplicationCommandOption;
}

View File

@@ -1,14 +1,14 @@
import {
APIApplicationCommandSubcommandGroupOption,
APIApplicationCommandSubcommandOption,
ApplicationCommandOptionType,
type APIApplicationCommandSubcommandGroupOption,
type APIApplicationCommandSubcommandOption,
} from 'discord-api-types/v10';
import { mix } from 'ts-mixer';
import { assertReturnOfBuilder, validateMaxOptionsLength, validateRequiredParameters } from './Assertions';
import type { ToAPIApplicationCommandOptions } from './SlashCommandBuilder';
import type { ApplicationCommandOptionBase } from './mixins/ApplicationCommandOptionBase';
import { SharedNameAndDescription } from './mixins/NameAndDescription';
import { SharedSlashCommandOptions } from './mixins/SharedSlashCommandOptions';
import { assertReturnOfBuilder, validateMaxOptionsLength, validateRequiredParameters } from './Assertions.js';
import type { ToAPIApplicationCommandOptions } from './SlashCommandBuilder.js';
import type { ApplicationCommandOptionBase } from './mixins/ApplicationCommandOptionBase.js';
import { SharedNameAndDescription } from './mixins/NameAndDescription.js';
import { SharedSlashCommandOptions } from './mixins/SharedSlashCommandOptions.js';
/**
* Represents a folder for subcommands

View File

@@ -1,5 +1,6 @@
export abstract class ApplicationCommandNumericOptionMinMaxValueMixin {
public readonly max_value?: number;
public readonly min_value?: number;
/**

View File

@@ -1,6 +1,6 @@
import type { APIApplicationCommandBasicOption, ApplicationCommandOptionType } from 'discord-api-types/v10';
import { SharedNameAndDescription } from './NameAndDescription';
import { validateRequiredParameters, validateRequired, validateLocalizationMap } from '../Assertions';
import { validateRequiredParameters, validateRequired, validateLocalizationMap } from '../Assertions.js';
import { SharedNameAndDescription } from './NameAndDescription.js';
export abstract class ApplicationCommandOptionBase extends SharedNameAndDescription {
public abstract readonly type: ApplicationCommandOptionType;

View File

@@ -6,11 +6,12 @@ const allowedChannelTypes = [
ChannelType.GuildText,
ChannelType.GuildVoice,
ChannelType.GuildCategory,
ChannelType.GuildNews,
ChannelType.GuildNewsThread,
ChannelType.GuildPublicThread,
ChannelType.GuildPrivateThread,
ChannelType.GuildAnnouncement,
ChannelType.AnnouncementThread,
ChannelType.PublicThread,
ChannelType.PrivateThread,
ChannelType.GuildStageVoice,
ChannelType.GuildForum,
] as const;
export type ApplicationCommandOptionAllowedChannelTypes = typeof allowedChannelTypes[number];

View File

@@ -1,9 +1,9 @@
import { s } from '@sapphire/shapeshift';
import { APIApplicationCommandOptionChoice, ApplicationCommandOptionType } from 'discord-api-types/v10';
import { localizationMapPredicate, validateChoicesLength } from '../Assertions';
import { ApplicationCommandOptionType, type APIApplicationCommandOptionChoice } from 'discord-api-types/v10';
import { localizationMapPredicate, validateChoicesLength } from '../Assertions.js';
const stringPredicate = s.string.lengthGreaterThanOrEqual(1).lengthLessThanOrEqual(100);
const numberPredicate = s.number.greaterThan(-Infinity).lessThan(Infinity);
const numberPredicate = s.number.greaterThan(Number.NEGATIVE_INFINITY).lessThan(Number.POSITIVE_INFINITY);
const choicesPredicate = s.object({
name: stringPredicate,
name_localizations: localizationMapPredicate,
@@ -11,8 +11,9 @@ const choicesPredicate = s.object({
}).array;
const booleanPredicate = s.boolean;
export class ApplicationCommandOptionWithChoicesAndAutocompleteMixin<T extends string | number> {
export class ApplicationCommandOptionWithChoicesAndAutocompleteMixin<T extends number | string> {
public readonly choices?: APIApplicationCommandOptionChoice<T>[];
public readonly autocomplete?: boolean;
// Since this is present and this is a mixin, this is needed
@@ -65,6 +66,7 @@ export class ApplicationCommandOptionWithChoicesAndAutocompleteMixin<T extends s
/**
* Marks the option as autocompletable
*
* @param autocomplete - If this option should be autocompletable
*/
public setAutocomplete(autocomplete: boolean): this {

View File

@@ -1,10 +1,13 @@
import type { LocaleString, LocalizationMap } from 'discord-api-types/v10';
import { validateDescription, validateLocale, validateName } from '../Assertions';
import { validateDescription, validateLocale, validateName } from '../Assertions.js';
export class SharedNameAndDescription {
public readonly name!: string;
public readonly name_localizations?: LocalizationMap;
public readonly description!: string;
public readonly description_localizations?: LocalizationMap;
/**
@@ -72,9 +75,10 @@ export class SharedNameAndDescription {
Reflect.set(this, 'name_localizations', {});
Object.entries(localizedNames).forEach((args) =>
this.setNameLocalization(...(args as [LocaleString, string | null])),
);
for (const args of Object.entries(localizedNames)) {
this.setNameLocalization(...(args as [LocaleString, string | null]));
}
return this;
}
@@ -114,9 +118,10 @@ export class SharedNameAndDescription {
}
Reflect.set(this, 'description_localizations', {});
Object.entries(localizedDescriptions).forEach((args) =>
this.setDescriptionLocalization(...(args as [LocaleString, string | null])),
);
for (const args of Object.entries(localizedDescriptions)) {
this.setDescriptionLocalization(...(args as [LocaleString, string | null]));
}
return this;
}
}

View File

@@ -1,15 +1,15 @@
import type { ApplicationCommandOptionBase } from './ApplicationCommandOptionBase';
import { assertReturnOfBuilder, validateMaxOptionsLength } from '../Assertions';
import { assertReturnOfBuilder, validateMaxOptionsLength } from '../Assertions.js';
import type { ToAPIApplicationCommandOptions } from '../SlashCommandBuilder';
import { SlashCommandAttachmentOption } from '../options/attachment';
import { SlashCommandBooleanOption } from '../options/boolean';
import { SlashCommandChannelOption } from '../options/channel';
import { SlashCommandIntegerOption } from '../options/integer';
import { SlashCommandMentionableOption } from '../options/mentionable';
import { SlashCommandNumberOption } from '../options/number';
import { SlashCommandRoleOption } from '../options/role';
import { SlashCommandStringOption } from '../options/string';
import { SlashCommandUserOption } from '../options/user';
import { SlashCommandAttachmentOption } from '../options/attachment.js';
import { SlashCommandBooleanOption } from '../options/boolean.js';
import { SlashCommandChannelOption } from '../options/channel.js';
import { SlashCommandIntegerOption } from '../options/integer.js';
import { SlashCommandMentionableOption } from '../options/mentionable.js';
import { SlashCommandNumberOption } from '../options/number.js';
import { SlashCommandRoleOption } from '../options/role.js';
import { SlashCommandStringOption } from '../options/string.js';
import { SlashCommandUserOption } from '../options/user.js';
import type { ApplicationCommandOptionBase } from './ApplicationCommandOptionBase.js';
export class SharedSlashCommandOptions<ShouldOmitSubcommandFunctions = true> {
public readonly options!: ToAPIApplicationCommandOptions[];
@@ -83,15 +83,15 @@ export class SharedSlashCommandOptions<ShouldOmitSubcommandFunctions = true> {
*/
public addStringOption(
input:
| SlashCommandStringOption
| Omit<SlashCommandStringOption, 'setAutocomplete'>
| Omit<SlashCommandStringOption, 'addChoices'>
| Omit<SlashCommandStringOption, 'setAutocomplete'>
| SlashCommandStringOption
| ((
builder: SlashCommandStringOption,
) =>
| SlashCommandStringOption
| Omit<SlashCommandStringOption, 'addChoices'>
| Omit<SlashCommandStringOption, 'setAutocomplete'>
| Omit<SlashCommandStringOption, 'addChoices'>),
| SlashCommandStringOption),
) {
return this._sharedAddOptionMethod(input, SlashCommandStringOption);
}
@@ -103,15 +103,15 @@ export class SharedSlashCommandOptions<ShouldOmitSubcommandFunctions = true> {
*/
public addIntegerOption(
input:
| SlashCommandIntegerOption
| Omit<SlashCommandIntegerOption, 'setAutocomplete'>
| Omit<SlashCommandIntegerOption, 'addChoices'>
| Omit<SlashCommandIntegerOption, 'setAutocomplete'>
| SlashCommandIntegerOption
| ((
builder: SlashCommandIntegerOption,
) =>
| SlashCommandIntegerOption
| Omit<SlashCommandIntegerOption, 'addChoices'>
| Omit<SlashCommandIntegerOption, 'setAutocomplete'>
| Omit<SlashCommandIntegerOption, 'addChoices'>),
| SlashCommandIntegerOption),
) {
return this._sharedAddOptionMethod(input, SlashCommandIntegerOption);
}
@@ -123,25 +123,25 @@ export class SharedSlashCommandOptions<ShouldOmitSubcommandFunctions = true> {
*/
public addNumberOption(
input:
| SlashCommandNumberOption
| Omit<SlashCommandNumberOption, 'setAutocomplete'>
| Omit<SlashCommandNumberOption, 'addChoices'>
| Omit<SlashCommandNumberOption, 'setAutocomplete'>
| SlashCommandNumberOption
| ((
builder: SlashCommandNumberOption,
) =>
| SlashCommandNumberOption
| Omit<SlashCommandNumberOption, 'addChoices'>
| Omit<SlashCommandNumberOption, 'setAutocomplete'>
| Omit<SlashCommandNumberOption, 'addChoices'>),
| SlashCommandNumberOption),
) {
return this._sharedAddOptionMethod(input, SlashCommandNumberOption);
}
private _sharedAddOptionMethod<T extends ApplicationCommandOptionBase>(
input:
| T
| Omit<T, 'setAutocomplete'>
| Omit<T, 'addChoices'>
| ((builder: T) => T | Omit<T, 'setAutocomplete'> | Omit<T, 'addChoices'>),
| Omit<T, 'setAutocomplete'>
| T
| ((builder: T) => Omit<T, 'addChoices'> | Omit<T, 'setAutocomplete'> | T),
Instance: new () => T,
): ShouldOmitSubcommandFunctions extends true ? Omit<this, 'addSubcommand' | 'addSubcommandGroup'> : this {
const { options } = this;

View File

@@ -1,5 +1,5 @@
import { APIApplicationCommandAttachmentOption, ApplicationCommandOptionType } from 'discord-api-types/v10';
import { ApplicationCommandOptionBase } from '../mixins/ApplicationCommandOptionBase';
import { ApplicationCommandOptionType, type APIApplicationCommandAttachmentOption } from 'discord-api-types/v10';
import { ApplicationCommandOptionBase } from '../mixins/ApplicationCommandOptionBase.js';
export class SlashCommandAttachmentOption extends ApplicationCommandOptionBase {
public override readonly type = ApplicationCommandOptionType.Attachment as const;

View File

@@ -1,5 +1,5 @@
import { APIApplicationCommandBooleanOption, ApplicationCommandOptionType } from 'discord-api-types/v10';
import { ApplicationCommandOptionBase } from '../mixins/ApplicationCommandOptionBase';
import { ApplicationCommandOptionType, type APIApplicationCommandBooleanOption } from 'discord-api-types/v10';
import { ApplicationCommandOptionBase } from '../mixins/ApplicationCommandOptionBase.js';
export class SlashCommandBooleanOption extends ApplicationCommandOptionBase {
public readonly type = ApplicationCommandOptionType.Boolean as const;

View File

@@ -1,7 +1,7 @@
import { APIApplicationCommandChannelOption, ApplicationCommandOptionType } from 'discord-api-types/v10';
import { ApplicationCommandOptionType, type APIApplicationCommandChannelOption } from 'discord-api-types/v10';
import { mix } from 'ts-mixer';
import { ApplicationCommandOptionBase } from '../mixins/ApplicationCommandOptionBase';
import { ApplicationCommandOptionChannelTypesMixin } from '../mixins/ApplicationCommandOptionChannelTypesMixin';
import { ApplicationCommandOptionBase } from '../mixins/ApplicationCommandOptionBase.js';
import { ApplicationCommandOptionChannelTypesMixin } from '../mixins/ApplicationCommandOptionChannelTypesMixin.js';
@mix(ApplicationCommandOptionChannelTypesMixin)
export class SlashCommandChannelOption extends ApplicationCommandOptionBase {

View File

@@ -1,9 +1,9 @@
import { s } from '@sapphire/shapeshift';
import { APIApplicationCommandIntegerOption, ApplicationCommandOptionType } from 'discord-api-types/v10';
import { ApplicationCommandOptionType, type APIApplicationCommandIntegerOption } from 'discord-api-types/v10';
import { mix } from 'ts-mixer';
import { ApplicationCommandNumericOptionMinMaxValueMixin } from '../mixins/ApplicationCommandNumericOptionMinMaxValueMixin';
import { ApplicationCommandOptionBase } from '../mixins/ApplicationCommandOptionBase';
import { ApplicationCommandOptionWithChoicesAndAutocompleteMixin } from '../mixins/ApplicationCommandOptionWithChoicesAndAutocompleteMixin';
import { ApplicationCommandNumericOptionMinMaxValueMixin } from '../mixins/ApplicationCommandNumericOptionMinMaxValueMixin.js';
import { ApplicationCommandOptionBase } from '../mixins/ApplicationCommandOptionBase.js';
import { ApplicationCommandOptionWithChoicesAndAutocompleteMixin } from '../mixins/ApplicationCommandOptionWithChoicesAndAutocompleteMixin.js';
const numberValidator = s.number.int;

View File

@@ -1,5 +1,5 @@
import { APIApplicationCommandMentionableOption, ApplicationCommandOptionType } from 'discord-api-types/v10';
import { ApplicationCommandOptionBase } from '../mixins/ApplicationCommandOptionBase';
import { ApplicationCommandOptionType, type APIApplicationCommandMentionableOption } from 'discord-api-types/v10';
import { ApplicationCommandOptionBase } from '../mixins/ApplicationCommandOptionBase.js';
export class SlashCommandMentionableOption extends ApplicationCommandOptionBase {
public readonly type = ApplicationCommandOptionType.Mentionable as const;

View File

@@ -1,9 +1,9 @@
import { s } from '@sapphire/shapeshift';
import { APIApplicationCommandNumberOption, ApplicationCommandOptionType } from 'discord-api-types/v10';
import { ApplicationCommandOptionType, type APIApplicationCommandNumberOption } from 'discord-api-types/v10';
import { mix } from 'ts-mixer';
import { ApplicationCommandNumericOptionMinMaxValueMixin } from '../mixins/ApplicationCommandNumericOptionMinMaxValueMixin';
import { ApplicationCommandOptionBase } from '../mixins/ApplicationCommandOptionBase';
import { ApplicationCommandOptionWithChoicesAndAutocompleteMixin } from '../mixins/ApplicationCommandOptionWithChoicesAndAutocompleteMixin';
import { ApplicationCommandNumericOptionMinMaxValueMixin } from '../mixins/ApplicationCommandNumericOptionMinMaxValueMixin.js';
import { ApplicationCommandOptionBase } from '../mixins/ApplicationCommandOptionBase.js';
import { ApplicationCommandOptionWithChoicesAndAutocompleteMixin } from '../mixins/ApplicationCommandOptionWithChoicesAndAutocompleteMixin.js';
const numberValidator = s.number;

View File

@@ -1,5 +1,5 @@
import { APIApplicationCommandRoleOption, ApplicationCommandOptionType } from 'discord-api-types/v10';
import { ApplicationCommandOptionBase } from '../mixins/ApplicationCommandOptionBase';
import { ApplicationCommandOptionType, type APIApplicationCommandRoleOption } from 'discord-api-types/v10';
import { ApplicationCommandOptionBase } from '../mixins/ApplicationCommandOptionBase.js';
export class SlashCommandRoleOption extends ApplicationCommandOptionBase {
public override readonly type = ApplicationCommandOptionType.Role as const;

View File

@@ -1,16 +1,18 @@
import { s } from '@sapphire/shapeshift';
import { APIApplicationCommandStringOption, ApplicationCommandOptionType } from 'discord-api-types/v10';
import { ApplicationCommandOptionType, type APIApplicationCommandStringOption } from 'discord-api-types/v10';
import { mix } from 'ts-mixer';
import { ApplicationCommandOptionBase } from '../mixins/ApplicationCommandOptionBase';
import { ApplicationCommandOptionWithChoicesAndAutocompleteMixin } from '../mixins/ApplicationCommandOptionWithChoicesAndAutocompleteMixin';
import { ApplicationCommandOptionBase } from '../mixins/ApplicationCommandOptionBase.js';
import { ApplicationCommandOptionWithChoicesAndAutocompleteMixin } from '../mixins/ApplicationCommandOptionWithChoicesAndAutocompleteMixin.js';
const minLengthValidator = s.number.greaterThanOrEqual(0).lessThanOrEqual(6000);
const maxLengthValidator = s.number.greaterThanOrEqual(1).lessThanOrEqual(6000);
const minLengthValidator = s.number.greaterThanOrEqual(0).lessThanOrEqual(6_000);
const maxLengthValidator = s.number.greaterThanOrEqual(1).lessThanOrEqual(6_000);
@mix(ApplicationCommandOptionWithChoicesAndAutocompleteMixin)
export class SlashCommandStringOption extends ApplicationCommandOptionBase {
public readonly type = ApplicationCommandOptionType.String as const;
public readonly max_length?: number;
public readonly min_length?: number;
/**

View File

@@ -1,5 +1,5 @@
import { APIApplicationCommandUserOption, ApplicationCommandOptionType } from 'discord-api-types/v10';
import { ApplicationCommandOptionBase } from '../mixins/ApplicationCommandOptionBase';
import { ApplicationCommandOptionType, type APIApplicationCommandUserOption } from 'discord-api-types/v10';
import { ApplicationCommandOptionBase } from '../mixins/ApplicationCommandOptionBase.js';
export class SlashCommandUserOption extends ApplicationCommandOptionBase {
public readonly type = ApplicationCommandOptionType.User as const;

View File

@@ -1,6 +1,6 @@
import { s } from '@sapphire/shapeshift';
import type { APIEmbedField } from 'discord-api-types/v10';
import { isValidationEnabled } from '../../util/validation';
import { isValidationEnabled } from '../../util/validation.js';
export const fieldNamePredicate = s.string
.lengthGreaterThanOrEqual(1)
@@ -9,7 +9,7 @@ export const fieldNamePredicate = s.string
export const fieldValuePredicate = s.string
.lengthGreaterThanOrEqual(1)
.lengthLessThanOrEqual(1024)
.lengthLessThanOrEqual(1_024)
.setValidationEnabled(isValidationEnabled);
export const fieldInlinePredicate = s.boolean.optional;
@@ -64,12 +64,12 @@ export const colorPredicate = s.number.int
export const descriptionPredicate = s.string
.lengthGreaterThanOrEqual(1)
.lengthLessThanOrEqual(4096)
.lengthLessThanOrEqual(4_096)
.nullable.setValidationEnabled(isValidationEnabled);
export const footerTextPredicate = s.string
.lengthGreaterThanOrEqual(1)
.lengthLessThanOrEqual(2048)
.lengthLessThanOrEqual(2_048)
.nullable.setValidationEnabled(isValidationEnabled);
export const embedFooterPredicate = s

View File

@@ -1,4 +1,5 @@
import type { APIEmbed, APIEmbedAuthor, APIEmbedField, APIEmbedFooter, APIEmbedImage } from 'discord-api-types/v10';
import { normalizeArray, type RestOrArray } from '../../util/normalizeArray.js';
import {
colorPredicate,
descriptionPredicate,
@@ -10,8 +11,7 @@ import {
titlePredicate,
urlPredicate,
validateFieldLength,
} from './Assertions';
import { normalizeArray, type RestOrArray } from '../../util/normalizeArray';
} from './Assertions.js';
export type RGBTuple = [red: number, green: number, blue: number];
@@ -26,11 +26,11 @@ export interface IconData {
proxyIconURL?: string;
}
export type EmbedAuthorData = Omit<APIEmbedAuthor, 'icon_url' | 'proxy_icon_url'> & IconData;
export type EmbedAuthorData = IconData & Omit<APIEmbedAuthor, 'icon_url' | 'proxy_icon_url'>;
export type EmbedAuthorOptions = Omit<EmbedAuthorData, 'proxyIconURL'>;
export type EmbedFooterData = Omit<APIEmbedFooter, 'icon_url' | 'proxy_icon_url'> & IconData;
export type EmbedFooterData = IconData & Omit<APIEmbedFooter, 'icon_url' | 'proxy_icon_url'>;
export type EmbedFooterOptions = Omit<EmbedFooterData, 'proxyIconURL'>;
@@ -57,7 +57,6 @@ export class EmbedBuilder {
* @remarks
* This method accepts either an array of fields or a variable number of field parameters.
* The maximum amount of fields that can be added is 25.
*
* @example
* Using an array
* ```ts
@@ -65,7 +64,6 @@ export class EmbedBuilder {
* const embed = new EmbedBuilder()
* .addFields(fields);
* ```
*
* @example
* Using rest parameters (variadic)
* ```ts
@@ -75,10 +73,10 @@ export class EmbedBuilder {
* { name: 'Field 2', value: 'Value 2' },
* );
* ```
*
* @param fields - The fields to add
*/
public addFields(...fields: RestOrArray<APIEmbedField>): this {
// eslint-disable-next-line no-param-reassign
fields = normalizeArray(fields);
// Ensure adding these fields won't exceed the 25 field limit
validateFieldLength(fields.length, this.data.fields);
@@ -100,26 +98,22 @@ export class EmbedBuilder {
* The maximum amount of fields that can be added is 25.
*
* It's useful for modifying and adjusting order of the already-existing fields of an embed.
*
* @example
* Remove the first field
* ```ts
* embed.spliceFields(0, 1);
* ```
*
* @example
* Remove the first n fields
* ```ts
* const n = 4
* embed.spliceFields(0, n);
* ```
*
* @example
* Remove the last field
* ```ts
* embed.spliceFields(-1, 1);
* ```
*
* @param index - The index to start at
* @param deleteCount - The number of fields to remove
* @param fields - The replacing field objects
@@ -143,7 +137,6 @@ export class EmbedBuilder {
* it splices the entire array of fields, replacing them with the provided fields.
*
* You can set a maximum of 25 fields.
*
* @param fields - The fields to set
*/
public setFields(...fields: RestOrArray<APIEmbedField>) {
@@ -175,7 +168,7 @@ export class EmbedBuilder {
*
* @param color - The color of the embed
*/
public setColor(color: number | RGBTuple | null): this {
public setColor(color: RGBTuple | number | null): this {
// Data assertions
colorPredicate.parse(color);
@@ -184,6 +177,7 @@ export class EmbedBuilder {
this.data.color = (red << 16) + (green << 8) + blue;
return this;
}
this.data.color = color ?? undefined;
return this;
}
@@ -250,7 +244,7 @@ export class EmbedBuilder {
*
* @param timestamp - The timestamp or date
*/
public setTimestamp(timestamp: number | Date | null = Date.now()): this {
public setTimestamp(timestamp: Date | number | null = Date.now()): this {
// Data assertions
timestampPredicate.parse(timestamp);

View File

@@ -1,4 +1,4 @@
import type { URL } from 'url';
import type { URL } from 'node:url';
import type { Snowflake } from 'discord-api-types/globals';
/**
@@ -95,8 +95,7 @@ export function hideLinkEmbed<C extends string>(url: C): `<${C}>`;
* @param url - The URL to wrap
*/
export function hideLinkEmbed(url: URL): `<${string}>`;
export function hideLinkEmbed(url: string | URL) {
// eslint-disable-next-line @typescript-eslint/restrict-template-expressions
export function hideLinkEmbed(url: URL | string) {
return `<${url}>`;
}
@@ -141,8 +140,7 @@ export function hyperlink<C extends string, U extends string, T extends string>(
url: U,
title: T,
): `[${C}](${U} "${T}")`;
export function hyperlink(content: string, url: string | URL, title?: string) {
// eslint-disable-next-line @typescript-eslint/restrict-template-expressions
export function hyperlink(content: string, url: URL | string, title?: string) {
return title ? `[${content}](${url} "${title}")` : `[${content}](${url})`;
}
@@ -182,6 +180,75 @@ export function roleMention<C extends Snowflake>(roleId: C): `<@&${C}>` {
return `<@&${roleId}>`;
}
/**
* Formats an application command name, subcommand group name, subcommand name, and ID into an application command mention
*
* @param commandName - The application command name to format
* @param subcommandGroupName - The subcommand group name to format
* @param subcommandName - The subcommand name to format
* @param commandId - The application command ID to format
*/
export function chatInputApplicationCommandMention<
N extends string,
G extends string,
S extends string,
I extends Snowflake,
>(commandName: N, subcommandGroupName: G, subcommandName: S, commandId: I): `</${N} ${G} ${S}:${I}>`;
/**
* Formats an application command name, subcommand name, and ID into an application command mention
*
* @param commandName - The application command name to format
* @param subcommandName - The subcommand name to format
* @param commandId - The application command ID to format
*/
export function chatInputApplicationCommandMention<N extends string, S extends string, I extends Snowflake>(
commandName: N,
subcommandName: S,
commandId: I,
): `</${N} ${S}:${I}>`;
/**
* Formats an application command name and ID into an application command mention
*
* @param commandName - The application command name to format
* @param commandId - The application command ID to format
*/
export function chatInputApplicationCommandMention<N extends string, I extends Snowflake>(
commandName: N,
commandId: I,
): `</${N}:${I}>`;
/**
* Formats an application command name, subcommand group name, subcommand name, and ID into an application command mention
*
* @param commandName - The application command name to format
* @param subcommandGroupName - The subcommand group name to format
* @param subcommandName - The subcommand name to format
* @param commandId - The application command ID to format
*/
export function chatInputApplicationCommandMention<
N extends string,
G extends Snowflake | string,
S extends Snowflake | string,
I extends Snowflake,
>(
commandName: N,
subcommandGroupName: G,
subcommandName?: S,
commandId?: I,
): `</${N} ${G} ${S}:${I}>` | `</${N} ${G}:${S}>` | `</${N}:${G}>` {
if (typeof commandId !== 'undefined') {
return `</${commandName} ${subcommandGroupName} ${subcommandName!}:${commandId}>`;
}
if (typeof subcommandName !== 'undefined') {
return `</${commandName} ${subcommandGroupName}:${subcommandName}>`;
}
return `</${commandName}:${subcommandGroupName}>`;
}
/**
* Formats an emoji ID into a fully qualified emoji identifier
*
@@ -203,7 +270,7 @@ export function formatEmoji<C extends Snowflake>(emojiId: C, animated?: true): `
* @param emojiId - The emoji ID to format
* @param animated - Whether the emoji is animated or not. Defaults to `false`
*/
export function formatEmoji<C extends Snowflake>(emojiId: C, animated = false): `<a:_:${C}>` | `<:_:${C}>` {
export function formatEmoji<C extends Snowflake>(emojiId: C, animated = false): `<:_:${C}>` | `<a:_:${C}>` {
return `<${animated ? 'a' : ''}:_:${emojiId}>`;
}
@@ -293,9 +360,10 @@ export function time<C extends number>(seconds: C): `<t:${C}>`;
* @param style - The style to use
*/
export function time<C extends number, S extends TimestampStylesString>(seconds: C, style: S): `<t:${C}:${S}>`;
export function time(timeOrSeconds?: number | Date, style?: TimestampStylesString): string {
export function time(timeOrSeconds?: Date | number, style?: TimestampStylesString): string {
if (typeof timeOrSeconds !== 'number') {
timeOrSeconds = Math.floor((timeOrSeconds?.getTime() ?? Date.now()) / 1000);
// eslint-disable-next-line no-param-reassign
timeOrSeconds = Math.floor((timeOrSeconds?.getTime() ?? Date.now()) / 1_000);
}
return typeof style === 'string' ? `<t:${timeOrSeconds}:${style}>` : `<t:${timeOrSeconds}>`;

View File

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

View File

@@ -1,7 +1,3 @@
{
"extends": "../../.eslintrc.json",
"plugins": ["eslint-plugin-tsdoc"],
"rules": {
"tsdoc/syntax": "warn"
}
"extends": "../../.eslintrc.json"
}

View File

@@ -2,6 +2,27 @@
All notable changes to this project will be documented in this file.
# [@discordjs/collection@1.1.0](https://github.com/discordjs/discord.js/compare/@discordjs/collection@1.0.1...@discordjs/collection@1.1.0) - (2022-08-22)
## Bug Fixes
- Use proper format for `@link` text (#8384) ([2655639](https://github.com/discordjs/discord.js/commit/26556390a3800e954974a00c1328ff47d3e67e9a))
## Documentation
- Fence examples in codeblocks ([193b252](https://github.com/discordjs/discord.js/commit/193b252672440a860318d3c2968aedd9cb88e0ce))
- Use link tags (#8382) ([5494791](https://github.com/discordjs/discord.js/commit/549479131318c659f86f0eb18578d597e22522d3))
## Features
- **website:** Show `constructor` information (#8540) ([e42fd16](https://github.com/discordjs/discord.js/commit/e42fd1636973b10dd7ed6fb4280ee1a4a8f82007))
- **website:** Show descriptions for `@typeParam` blocks (#8523) ([e475b63](https://github.com/discordjs/discord.js/commit/e475b63f257f6261d73cb89fee9ecbcdd84e2a6b))
## Refactor
- **website:** Adjust typography (#8503) ([0f83402](https://github.com/discordjs/discord.js/commit/0f834029850d2448981596cf082ff59917018d66))
- Docs design (#8487) ([4ab1d09](https://github.com/discordjs/discord.js/commit/4ab1d09997a18879a9eb9bda39df6f15aa22557e))
# [@discordjs/collection@0.8.0](https://github.com/discordjs/discord.js/compare/@discordjs/collection@0.7.0...@discordjs/collection@0.8.0) - (2022-07-17)
## Bug Fixes
@@ -57,36 +78,3 @@ All notable changes to this project will be documented in this file.
- Add `ReadonlyCollection` (#7245) ([db25f52](https://github.com/discordjs/discord.js/commit/db25f529b26d7c819c1c42ad3e26c2263ea2da0e))
- **Collection:** Union types on `intersect` and `difference` (#7196) ([1f9b922](https://github.com/discordjs/discord.js/commit/1f9b9225f2066e9cc66c3355417139fd25cc403c))
# [0.4.0](https://github.com/discordjs/collection/compare/v0.3.2...v0.4.0) (2021-12-24)
## Features
- add #reverse ([#48](https://github.com/discordjs/collection/issues/48)) ([8bcb5e2](https://github.com/discordjs/collection/commit/8bcb5e21bcc15f5b77612d8ff03dec6c37f4d449))
- add Collection#ensure ([#52](https://github.com/discordjs/collection/issues/52)) ([3809eb4](https://github.com/discordjs/collection/commit/3809eb4d18e70459355d310919a3f57747eee3dd))
# [0.3.2](https://github.com/discordjs/collection/compare/v0.3.1...v0.3.2) (2021-10-29)
## Bug Fixes
- update doc engine ([4c0e24f](https://github.com/discordjs/collection/commit/4c0e24fae0323db9de1991db9cfacc093d529abc))
# [0.3.0](https://github.com/discordjs/collection/compare/v0.2.4...v0.3.0) (2021-10-29)
## Features
- add Collection#at() and Collection#keyAt() ([#46](https://github.com/discordjs/collection/issues/46)) ([66b30b9](https://github.com/discordjs/collection/commit/66b30b91069502493383c059cc38e27c152bf541))
- improve documentation and resolve [#49](https://github.com/discordjs/collection/issues/49) ([aec01c6](https://github.com/discordjs/collection/commit/aec01c6ae3ff50b0b5f7c070bff10f01bf98d803))
- ts-docgen ([463b131](https://github.com/discordjs/collection/commit/463b1314e60f2debc526454a6ccd7ce8a9a4ae8a))
# [0.2.4](https://github.com/discordjs/collection/compare/v0.2.3...v0.2.4) (2021-10-27)
## Bug Fixes
- minification of names ([bd2fe2a](https://github.com/discordjs/collection/commit/bd2fe2a47c38f634b0334fe6e89f30f6f6a0b1f5))
# [0.2.3](https://github.com/discordjs/collection/compare/v0.2.2...v0.2.3) (2021-10-27)
### Bug Fixes
- building with useDefineForClassFields false ([2a571d5](https://github.com/discordjs/collection/commit/2a571d5a2c90ed8b708c3c5c017e2f225cd494e9))

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