Compare commits

...

71 Commits

Author SHA1 Message Date
iCrawl
19e1f5d0ca chore(proxy): release @discordjs/proxy@1.1.0 2022-08-22 10:04:03 +02:00
iCrawl
3621e5efbd chore(rest): release @discordjs/rest@1.1.0 2022-08-22 10:01:34 +02:00
iCrawl
d2f5b5b539 chore(ws): release @discordjs/ws@0.3.0 2022-08-22 09:57:26 +02:00
iCrawl
9ed11a4c19 chore: deps 2022-08-22 09:56:42 +02:00
Suneet Tipirneni
e42fd16369 feat(website): Show constructor information (#8540) 2022-08-22 09:45:53 +02:00
Jiralite
dd44e8b6ec fix(proxyRequests): Typo in error message (#8537)
fix(proxyRequests): typo in error message

Co-authored-by: kodiakhq[bot] <49736102+kodiakhq[bot]@users.noreply.github.com>
2022-08-21 20:39:40 +00:00
Synbulat Biishev
3bef9018c0 fix(GuildMemberManager): add() method throws an error (#8539)
* fix(GuildMemberManager): `add()` method throws an error

* chore: update comment
2022-08-21 20:32:56 +00:00
Jiralite
23a0b6ccf2 fix(Guild): Widget channel types and fixes (#8530)
fix: various widget fixes

Co-authored-by: kodiakhq[bot] <49736102+kodiakhq[bot]@users.noreply.github.com>
2022-08-21 09:28:31 +00:00
Jiralite
b3f7c32f7f types: Allow choice's value type to be strictly inferred (#8529)
* types: stricter types for choices in options

* test: add choice tests

Co-authored-by: kodiakhq[bot] <49736102+kodiakhq[bot]@users.noreply.github.com>
2022-08-20 20:29:16 +00:00
Jiralite
0dba8adbd2 types(GuildAuditLogs): Allow fetching to return all possible values (#8522)
types: allow everything to be returned upon fetching

Co-authored-by: kodiakhq[bot] <49736102+kodiakhq[bot]@users.noreply.github.com>
2022-08-20 19:03:36 +00:00
Jiralite
2b8074dd12 refactor(GuildAuditLogsEntry): Remove guild from application command permission update extra (#8520)
refactor(GuildAuditLogsEntry): remove guild extra

Co-authored-by: kodiakhq[bot] <49736102+kodiakhq[bot]@users.noreply.github.com>
2022-08-20 18:51:39 +00:00
InkoHX
16bbc8aa20 types: Correct EventEmitter.on (static) return type (#8524)
types: Correct EventEmitter.on (static) return type

Co-authored-by: kodiakhq[bot] <49736102+kodiakhq[bot]@users.noreply.github.com>
2022-08-20 18:45:56 +00:00
Jiralite
7a3d18dd6d types(GuildAuditLogs): Remove static Entry (#8521)
types(GuildAuditLogs): remove static `Entry`

Co-authored-by: kodiakhq[bot] <49736102+kodiakhq[bot]@users.noreply.github.com>
2022-08-20 18:34:32 +00:00
Jiralite
4882b17a77 types: Disallow some channel types from webhook creation (#8531)
types: disallow some channel types from webhook creation
2022-08-20 18:26:33 +00:00
Suneet Tipirneni
8028813825 feat(website): render @defaultValue blocks (#8527)
feat(website): render @defaultValue blocks
2022-08-19 18:24:55 +02:00
Suneet Tipirneni
47f2990b89 feat(website): show inherited members (#8526)
* feat(website): show inherited members

* fix: use passHref
2022-08-19 18:22:22 +02:00
Suneet Tipirneni
e475b63f25 feat(website): show descriptions for @typeParam blocks (#8523) 2022-08-19 10:55:43 +02:00
iCrawl
673262d38c feat: deprecation badges 2022-08-18 18:47:44 +02:00
Suneet Tipirneni
7f415a2502 feat(website): show parameter descriptions (#8519)
Co-authored-by: Noel <buechler.noel@outlook.com>
2022-08-18 18:38:27 +02:00
DD
cda3f005b1 feat(GuildMemberManager): addRole and removeRole (#8510)
Co-authored-by: kodiakhq[bot] <49736102+kodiakhq[bot]@users.noreply.github.com>
2022-08-18 10:58:35 +02:00
Synbulat Biishev
f9c25ddcfe feat: deprecate ActionRow.from() (#8504)
* feat: deprecate `ActionRow.from()`

* feat: deprecate `ActionRow.from()`

Co-authored-by: kodiakhq[bot] <49736102+kodiakhq[bot]@users.noreply.github.com>
2022-08-18 07:06:01 +00:00
iCrawl
74740260a7 ci: fix if statement, again 2022-08-17 23:51:07 +02:00
iCrawl
1008e3d4a7 ci: fix if check 2022-08-17 23:46:22 +02:00
iCrawl
17ab0e652c refactor: inline table of contents 2022-08-17 23:21:23 +02:00
Noel
872ce801a0 revert: "refactor(website): use mantine code blocks" (#8514) 2022-08-17 23:04:47 +02:00
Suneet Tipirneni
0bf3df30da refactor(website): use mantine code blocks (#8512) 2022-08-17 22:38:11 +02:00
iCrawl
20680efbc9 feat: more visibly annotate optionals 2022-08-17 22:16:22 +02:00
Jiralite
7701331b1c ci: Remove management of chore label (#8508)
Co-authored-by: kodiakhq[bot] <49736102+kodiakhq[bot]@users.noreply.github.com>
2022-08-17 20:12:54 +00:00
Suneet Tipirneni
0be85fd101 feat(website): render @deprecated and @remarks blocks (#8511) 2022-08-17 21:51:29 +02:00
iCrawl
e147c5bd64 fix: codelisting 2022-08-17 21:24:38 +02:00
iCrawl
2f1ec7401c feat: table of contents / method visibility / property modifiers 2022-08-17 21:12:09 +02:00
Suneet Tipirneni
0f83402985 refactor(website): adjust typography (#8503) 2022-08-17 10:17:09 +02:00
Parbez
d97cd936fd chore: bump vitest and add @vitest/coverage-c8 (#8507) 2022-08-17 09:44:21 +02:00
Jiralite
812f7f1ea8 types: Implement max/min values for autocomplete (#8498)
* types: implement max/min values for autocomplete

* refactor: deduplicate options

Co-authored-by: kodiakhq[bot] <49736102+kodiakhq[bot]@users.noreply.github.com>
2022-08-16 20:37:08 +00:00
Jiralite
7d2507279c docs(GuildAuditLogsEntry): Correct action wording (#8499)
docs(GuildAuditLogsEntry): fix `action` wording

Co-authored-by: kodiakhq[bot] <49736102+kodiakhq[bot]@users.noreply.github.com>
2022-08-16 20:30:07 +00:00
Rodry
c31a5cfcc8 types(ModalMessageModalSubmitInteraction): channelId is not nullable (#8496)
Co-authored-by: kodiakhq[bot] <49736102+kodiakhq[bot]@users.noreply.github.com>
2022-08-16 15:38:30 +00:00
DD
acdafe60c7 fix(WebSocketShard#destroy): wait for close and cleanup listeners (#8479)
Co-authored-by: kodiakhq[bot] <49736102+kodiakhq[bot]@users.noreply.github.com>
2022-08-16 15:33:00 +00:00
DD
4fd42528fe fix(WebSocketManager#connect): check if we have enough sessions (#8481)
* fix(WebSocketManager#connect): check if we have enough sessions

* fix: more useful error message

* fix: tests

Co-authored-by: kodiakhq[bot] <49736102+kodiakhq[bot]@users.noreply.github.com>
2022-08-16 15:28:01 +00:00
ZyX
ebaf158006 types: change type of ApplicationCommandSubCommand.options (#8476)
* types: change type of ApplicationCommandSubCommand.options

* types: change type of ApplicationCommandSubCommand.options

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

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

Co-authored-by: Vlad Frangu <kingdgrizzle@gmail.com>
Co-authored-by: Jiralite <33201955+Jiralite@users.noreply.github.com>
2022-08-16 14:39:16 +00:00
Suneet Tipirneni
7116647947 feat(website): render tsdoc examples (#8494) 2022-08-16 16:33:49 +02:00
iCrawl
c99b808882 ci: fix workflow 2022-08-16 16:24:07 +02:00
iCrawl
a1dddd6b2c build: only build web on vercel 2022-08-16 16:07:08 +02:00
iCrawl
b3db9eef32 build: force a docs rebuild 2022-08-16 15:51:51 +02:00
iCrawl
501945215b ci: use concurrency 2022-08-16 11:00:17 +02:00
iCrawl
e82b2e49f5 fix: use correct env file 2022-08-15 19:17:41 +02:00
iCrawl
5f42b5af30 feat: fetch from local when developing or CI build 2022-08-15 19:13:01 +02:00
iCrawl
35e79b389d fix: correctly handle overflowing content 2022-08-15 18:35:34 +02:00
iCrawl
5dc7946df2 fix: properly render critical styles on the server 2022-08-15 18:23:10 +02:00
iCrawl
1e00f5789e chore: enable kodiak for auto merges 2022-08-15 16:56:30 +02:00
iCrawl
85cb0f25c7 build: run build with concurrency but everything else parallel 2022-08-15 16:16:12 +02:00
iCrawl
3cc893a282 build: enable parallel building for turbo 2022-08-15 16:12:45 +02:00
Marcus Otterström
fc99bf431a Specify time unit in awaitModalSubmit (#8484) 2022-08-15 16:07:03 +02:00
Noel
4ab1d09997 refactor: docs design (#8487) 2022-08-15 14:48:00 +02:00
iCrawl
d09ef1e425 build: switch back to turbo for speedz 2022-08-15 14:19:17 +02:00
iCrawl
d56590a11d chore: use external collection for docgen 2022-08-15 13:50:41 +02:00
iCrawl
c052f56f3e ci: fix typechecking in ci 2022-08-15 00:42:33 +02:00
iCrawl
cb856860b7 ci: install dev deps everywhere 2022-08-14 21:30:55 +02:00
iCrawl
4cf265c7c6 ci: exclude shared match 2022-08-14 21:21:17 +02:00
iCrawl
3ec7ef07a0 ci: correctly reference job 2022-08-14 21:17:12 +02:00
iCrawl
90e7aea443 ci: check for shared additionally to packages 2022-08-14 21:04:51 +02:00
iCrawl
1211c7fc10 ci: fix dependency 2022-08-14 20:12:58 +02:00
iCrawl
84a4b1f58a ci: only test run affected packages 2022-08-14 20:12:02 +02:00
iCrawl
193b252672 docs: fence examples in codeblocks 2022-08-14 19:25:25 +02:00
DD
bc06cc638d feat(WebSocketShard): support new resume url (#8480) 2022-08-14 12:01:35 +02:00
iCrawl
d08da8a212 refactor: properly handling spacing 2022-08-13 20:42:03 +02:00
iCrawl
5360099e5f build: don't build website on ci, let vercel handle it on changes 2022-08-13 20:14:28 +02:00
Suneet Tipirneni
fd4844ddb9 feat(website): add support for function overloads (#8474)
Co-authored-by: Noel <buechler.noel@outlook.com>
2022-08-13 20:14:23 +02:00
iCrawl
8e69efde04 feat(website): breadcrumbs layout 2022-08-12 17:04:12 +02:00
iCrawl
2447165c82 fix(website): accessibility 2022-08-12 17:03:04 +02:00
Jiralite
c97977a3e8 fix(Embed): Reference video in video (#8473) 2022-08-12 05:09:44 +02:00
iCrawl
7666a6c341 chore: update changelog 2022-08-10 20:56:22 +02:00
152 changed files with 4843 additions and 3803 deletions

11
.github/.kodiak.toml vendored Normal file
View File

@@ -0,0 +1,11 @@
version = 1
[merge]
require_automerge_label = false
blocking_labels = ['blocked']
method = 'squash'
[merge.message]
title = 'pull_request_title'
strip_html_comments = true
include_coauthors = true

View File

@@ -1,13 +0,0 @@
#!/bin/bash
git diff HEAD^ HEAD --quiet .
if [[ "$VERCEL_GIT_COMMIT_REF" == "main" || $? -eq 1 ]]; then
# Proceed with the build
echo "✅ - Proceed"
exit 1;
else
# Don't build
echo "🛑 - Build cancelled"
exit 0;
fi

4
.github/labeler.yml vendored
View File

@@ -1,7 +1,3 @@
chore:
- any: ['*']
all: ['!packages/*', '!packages/**/*']
'packages:builders':
- packages/builders/*
- packages/builders/**/*

View File

@@ -3,8 +3,6 @@ on:
push:
branches:
- 'main'
- 'stable'
- '!docs'
tags:
- '**'
workflow_dispatch:
@@ -12,15 +10,28 @@ on:
ref:
description: 'The branch, tag or SHA to checkout'
required: true
ref_type:
type: choice
description: 'Branch or tag'
options:
- branch
- tag
required: true
concurrency:
group: ${{ github.workflow }}-${{ github.head_ref || github.ref }}
cancel-in-progress: true
jobs:
build:
name: Build documentation
runs-on: ubuntu-latest
if: github.repository_owner == 'discordjs'
env:
TURBO_TOKEN: ${{ secrets.TURBO_TOKEN }}
TURBO_TEAM: ${{ secrets.TURBO_TEAM }}
outputs:
BRANCH_NAME: ${{ steps.env.outputs.BRANCH_NAME }}
BRANCH_OR_TAG: ${{ steps.env.outputs.BRANCH_OR_TAG }}
SHA: ${{ steps.env.outputs.SHA }}
if: github.repository_owner == 'discordjs'
steps:
- name: Checkout repository
uses: actions/checkout@v3
@@ -32,7 +43,6 @@ jobs:
with:
node-version: 16
cache: 'yarn'
cache-dependency-path: yarn.lock
- name: Install dependencies
run: yarn --immutable
@@ -72,8 +82,10 @@ jobs:
package: ['builders', 'collection', 'discord.js', 'proxy', 'rest', 'voice', 'ws']
runs-on: ubuntu-latest
env:
TURBO_TOKEN: ${{ secrets.TURBO_TOKEN }}
TURBO_TEAM: ${{ secrets.TURBO_TEAM }}
BRANCH_NAME: ${{ github.event.inputs.ref || needs.build.outputs.BRANCH_NAME }}
BRANCH_OR_TAG: ${{ needs.build.outputs.BRANCH_OR_TAG }}
BRANCH_OR_TAG: ${{ github.event.inputs.ref_type || needs.build.outputs.BRANCH_OR_TAG }}
SHA: ${{ needs.build.outputs.SHA }}
steps:
- name: Checkout repository
@@ -84,7 +96,6 @@ jobs:
with:
node-version: 16
cache: 'yarn'
cache-dependency-path: yarn.lock
- name: Install dependencies
run: yarn --immutable
@@ -112,14 +123,14 @@ jobs:
path: 'out'
- name: Extract package and semver from tag
if: ${{ github.event.inputs.ref || env.BRANCH_OR_TAG == 'tag' }}
if: ${{ github.event.inputs.ref_type == 'tag' || env.BRANCH_OR_TAG == 'tag' }}
id: extract-tag
uses: ./packages/actions/src/formatTag
with:
tag: ${{ env.BRANCH_NAME }}
- name: Move docs to correct directory
if: ${{ (github.event.inputs.ref || env.BRANCH_OR_TAG == 'tag') && matrix.package == steps.extract-tag.outputs.package }}
if: ${{ (github.event.inputs.ref_type == 'tag' || 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 }}
@@ -131,7 +142,7 @@ jobs:
fi
- name: Move docs to correct directory
if: ${{ !github.event.inputs.ref && env.BRANCH_OR_TAG == 'branch' }}
if: ${{ github.event.inputs.ref_type == 'branch' || env.BRANCH_OR_TAG == 'branch' }}
env:
PACKAGE: ${{ matrix.package }}
run: |

View File

@@ -1,8 +1,8 @@
name: npm auto deprecate
on:
workflow_dispatch:
schedule:
- cron: '0 1 * * *'
workflow_dispatch:
jobs:
npm-auto-deprecate:
name: npm auto deprecate
@@ -17,7 +17,6 @@ jobs:
with:
node-version: 16
cache: 'yarn'
cache-dependency-path: yarn.lock
- name: Install dependencies
run: yarn --immutable

View File

@@ -1,8 +1,8 @@
name: Publish dev docker images
on:
workflow_dispatch:
schedule:
- cron: '0 */12 * * *'
workflow_dispatch:
jobs:
docker-publish:
name: Docker publish

View File

@@ -1,8 +1,8 @@
name: Publish dev
on:
workflow_dispatch:
schedule:
- cron: '0 */12 * * *'
workflow_dispatch:
jobs:
npm-publish:
name: npm publish
@@ -25,6 +25,9 @@ jobs:
- package: '@discordjs/ws'
folder: 'ws'
runs-on: ubuntu-latest
env:
TURBO_TOKEN: ${{ secrets.TURBO_TOKEN }}
TURBO_TEAM: ${{ secrets.TURBO_TEAM }}
if: github.repository_owner == 'discordjs'
steps:
- name: Checkout repository
@@ -36,7 +39,6 @@ jobs:
node-version: 16
registry-url: https://registry.npmjs.org/
cache: 'yarn'
cache-dependency-path: yarn.lock
- name: Install dependencies
run: yarn --immutable

View File

@@ -1,9 +1,18 @@
name: Tests
on: [push, pull_request]
on:
push:
pull_request:
concurrency:
group: ${{ github.workflow }}-${{ github.head_ref || github.ref }}
cancel-in-progress: true
jobs:
tests:
name: Tests
runs-on: ubuntu-latest
env:
TURBO_TOKEN: ${{ secrets.TURBO_TOKEN }}
TURBO_TEAM: ${{ secrets.TURBO_TEAM }}
NEXT_PUBLIC_LOCAL_DEV: true
steps:
- name: Checkout repository
uses: actions/checkout@v3
@@ -13,10 +22,9 @@ jobs:
with:
node-version: 16
cache: 'yarn'
cache-dependency-path: yarn.lock
- name: Install dependencies
run: yarn --immutable
run: yarn install --immutable
- name: Build dependencies
run: yarn build
@@ -28,5 +36,5 @@ jobs:
run: yarn test
- name: Upload Coverage
uses: ./packages/actions/src/uploadCoverage
if: github.repository_owner == 'discordjs'
uses: ./packages/actions/src/uploadCoverage

View File

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

View File

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

View File

@@ -1,5 +1,6 @@
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';
@@ -26,7 +27,7 @@ export function createUnbuildConfig({
preserveModules = true,
preserveModulesRoot = 'src',
declaration = true,
typeCheck = false,
typeCheck = isCi,
}: Partial<ConfigOptions> = {}) {
const files = glob
.sync('**', { cwd: 'src' })
@@ -45,6 +46,7 @@ export function createUnbuildConfig({
cjsBridge,
json: {
namedExports: false,
preferConst: true,
},
},

View File

@@ -4,13 +4,13 @@
"description": "A powerful library for interacting with the Discord API",
"private": true,
"scripts": {
"build": "yarn workspaces foreach --parallel --topological run build",
"test": "yarn workspaces foreach --parallel --topological run test",
"lint": "yarn workspaces foreach --parallel --topological run lint",
"format": "yarn workspaces foreach --parallel --topological run format",
"fmt": "yarn format",
"build": "turbo run build",
"test": "turbo run test --parallel",
"lint": "turbo run lint --parallel",
"format": "turbo run format --parallel",
"fmt": "turbo run format --parallel",
"postinstall": "is-ci || husky install",
"docs": "yarn workspaces foreach --parallel --topological run docs",
"docs": "turbo run docs --parallel",
"update": "yarn upgrade-interactive"
},
"contributors": [
@@ -39,25 +39,18 @@
"devDependencies": {
"@commitlint/cli": "^17.0.3",
"@commitlint/config-angular": "^17.0.3",
"@favware/cliff-jumper": "^1.8.6",
"@favware/cliff-jumper": "^1.8.7",
"@favware/npm-deprecate": "^1.0.5",
"@typescript-eslint/eslint-plugin": "^5.33.0",
"@typescript-eslint/parser": "^5.33.0",
"@types/is-ci": "^3.0.0",
"conventional-changelog-cli": "^2.2.2",
"eslint": "^8.21.0",
"eslint-config-marine": "^9.4.1",
"eslint-config-prettier": "^8.5.0",
"eslint-import-resolver-typescript": "^3.4.0",
"eslint-plugin-import": "^2.26.0",
"fast-glob": "^3.2.11",
"husky": "^8.0.1",
"is-ci": "^3.0.1",
"lint-staged": "^13.0.3",
"prettier": "^2.7.1",
"turbo": "^1.4.3",
"typescript": "^4.7.4"
},
"resolutions": {
"rollup-plugin-typescript2@0.32.1": "patch:rollup-plugin-typescript2@npm:0.32.1#.yarn/patches/rollup-plugin-typescript2-npm-0.32.1-b5887420f2.patch",
"@microsoft/tsdoc-config": "patch:@microsoft/tsdoc-config@npm:0.16.1#.yarn/patches/@microsoft-tsdoc-config-npm-0.16.1-81031b1bbf.patch"
},
"engines": {

View File

@@ -6,8 +6,8 @@
"scripts": {
"test": "vitest run",
"build": "unbuild",
"lint": "prettier --check . && eslint src __tests__ --ext mjs,js,ts",
"format": "prettier --write . && eslint src __tests__ --ext mjs,js,ts --fix",
"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",
"fmt": "yarn format"
},
"main": "./dist/index.mjs",
@@ -43,14 +43,20 @@
"tslib": "^2.4.0"
},
"devDependencies": {
"@types/node": "^16.11.47",
"c8": "^7.12.0",
"eslint": "^8.21.0",
"@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",
"prettier": "^2.7.1",
"rollup-plugin-typescript2": "0.32.1",
"rollup-plugin-typescript2": "^0.33.0",
"typescript": "^4.7.4",
"unbuild": "^0.8.4",
"vitest": "^0.21.1"
"unbuild": "^0.8.9",
"vitest": "^0.22.1"
},
"engines": {
"node": ">=16.9.0"

View File

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

View File

@@ -5,8 +5,8 @@
"scripts": {
"test": "vitest run",
"build": "unbuild",
"lint": "prettier --check . && eslint src __tests__ --ext mjs,js,ts",
"format": "prettier --write . && eslint src __tests__ --ext mjs,js,ts --fix",
"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",
"fmt": "yarn format",
"docs": "downlevel-dts . docs --to=3.7 && docgen -i src/index.ts -c docs/index.json -o docs/docs.json --typescript && api-extractor run --local",
"prepack": "yarn lint && yarn test && yarn build",
@@ -55,24 +55,31 @@
"homepage": "https://discord.js.org",
"dependencies": {
"@sapphire/shapeshift": "^3.5.1",
"discord-api-types": "^0.36.3",
"discord-api-types": "^0.37.3",
"fast-deep-equal": "^3.1.3",
"ts-mixer": "^6.0.1",
"tslib": "^2.4.0"
},
"devDependencies": {
"@discordjs/docgen": "workspace:^",
"@favware/cliff-jumper": "^1.8.6",
"@microsoft/api-extractor": "^7.29.2",
"@types/node": "^16.11.47",
"c8": "^7.12.0",
"@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.21.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",
"prettier": "^2.7.1",
"rollup-plugin-typescript2": "0.32.1",
"rollup-plugin-typescript2": "^0.33.0",
"typescript": "^4.7.4",
"unbuild": "^0.8.4",
"vitest": "^0.21.1"
"unbuild": "^0.8.9",
"vitest": "^0.22.1"
},
"engines": {
"node": ">=16.9.0"

View File

@@ -22,6 +22,8 @@ export type AnyComponentBuilder = MessageActionRowComponentBuilder | ModalAction
/**
* Represents an action row component
*
* @typeParam T - The types of components this action row holds
*/
export class ActionRowBuilder<T extends AnyComponentBuilder> extends ComponentBuilder<
APIActionRowComponent<APIMessageActionRowComponent | APIModalActionRowComponent>
@@ -56,6 +58,9 @@ export class ActionRowBuilder<T extends AnyComponentBuilder> extends ComponentBu
return this;
}
/**
* {@inheritDoc ComponentBuilder.toJSON}
*/
public toJSON(): APIActionRowComponent<ReturnType<T['toJSON']>> {
// eslint-disable-next-line @typescript-eslint/consistent-type-assertions
return {

View File

@@ -10,6 +10,8 @@ export type AnyAPIActionRowComponent = APIActionRowComponentTypes | APIActionRow
/**
* Represents a discord component
*
* @typeParam DataType - The type of internal API data that is stored within the component
*/
export abstract class ComponentBuilder<
DataType extends Partial<APIBaseComponent<ComponentType>> = APIBaseComponent<ComponentType>,
@@ -20,6 +22,13 @@ export abstract class ComponentBuilder<
*/
public readonly data: Partial<DataType>;
/**
* Serializes this component to an API-compatible JSON object
*
* @remarks
* This method runs validations on the data before serializing it.
* As such, it may throw an error if the data is invalid.
*/
public abstract toJSON(): AnyAPIActionRowComponent;
public constructor(data: Partial<DataType>) {

View File

@@ -21,6 +21,35 @@ import { ComponentBuilder } from '../Component';
* Represents a button component
*/
export class ButtonBuilder extends ComponentBuilder<APIButtonComponent> {
/**
* Creates a new button from API data
* @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',
* label: 'Click Me',
* emoji: {
* name: ':smile:',
* id: '12345678901234567890123456789012',
* },
* custom_id: '12345678901234567890123456789012',
* });
* ```
*
* @example
* Creating a button using setters and API data
* ```ts
* const button = new ButtonBuilder({
* style: 'primary',
* label: 'Click Me',
* })
* .setEmoji({ name: ':smile:', id: '12345678901234567890123456789012' })
* .setCustomId('12345678901234567890123456789012');
* ```
*/
public constructor(data?: Partial<APIButtonComponent>) {
super({ type: ComponentType.Button, ...data });
}
@@ -38,6 +67,10 @@ export class ButtonBuilder extends ComponentBuilder<APIButtonComponent> {
/**
* Sets the URL for this button
*
* @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) {
@@ -48,6 +81,9 @@ export class ButtonBuilder extends ComponentBuilder<APIButtonComponent> {
/**
* Sets the custom id for this button
*
* @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) {
@@ -85,6 +121,9 @@ export class ButtonBuilder extends ComponentBuilder<APIButtonComponent> {
return this;
}
/**
* {@inheritDoc ComponentBuilder.toJSON}
*/
public toJSON(): APIButtonComponent {
validateRequiredButtonParameters(
this.data.style,

View File

@@ -116,6 +116,9 @@ export class SelectMenuBuilder extends ComponentBuilder<APISelectMenuComponent>
return this;
}
/**
* {@inheritDoc ComponentBuilder.toJSON}
*/
public toJSON(): APISelectMenuComponent {
validateRequiredSelectMenuParameters(this.options, this.data.custom_id);
// eslint-disable-next-line @typescript-eslint/consistent-type-assertions

View File

@@ -1,4 +1,5 @@
import type { APIMessageComponentEmoji, APISelectMenuOption } from 'discord-api-types/v10';
import type { JSONEncodable } from '../../util/jsonEncodable';
import {
defaultValidator,
@@ -10,7 +11,7 @@ import {
/**
* Represents a option within a select menu component
*/
export class SelectMenuOptionBuilder {
export class SelectMenuOptionBuilder implements JSONEncodable<APISelectMenuOption> {
public constructor(public data: Partial<APISelectMenuOption> = {}) {}
/**
@@ -63,6 +64,9 @@ export class SelectMenuOptionBuilder {
return this;
}
/**
* {@inheritDoc ComponentBuilder.toJSON}
*/
public toJSON(): APISelectMenuOption {
validateRequiredSelectMenuOptionParameters(this.data.label, this.data.value);
// eslint-disable-next-line @typescript-eslint/consistent-type-assertions

View File

@@ -10,11 +10,15 @@ import {
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';
export class TextInputBuilder extends ComponentBuilder<APITextInputComponent> {
export class TextInputBuilder
extends ComponentBuilder<APITextInputComponent>
implements Equatable<JSONEncodable<APITextInputComponent> | APITextInputComponent>
{
public constructor(data?: APITextInputComponent & { type?: ComponentType.TextInput }) {
super({ type: ComponentType.TextInput, ...data });
}
@@ -99,6 +103,9 @@ export class TextInputBuilder extends ComponentBuilder<APITextInputComponent> {
return this;
}
/**
* {@inheritDoc ComponentBuilder.toJSON}
*/
public toJSON(): APITextInputComponent {
validateRequiredParameters(this.data.custom_id, this.data.style, this.data.label);
// eslint-disable-next-line @typescript-eslint/consistent-type-assertions
@@ -107,6 +114,9 @@ export class TextInputBuilder extends ComponentBuilder<APITextInputComponent> {
} as APITextInputComponent;
}
/**
* {@inheritDoc Equatable.equals}
*/
public equals(other: JSONEncodable<APITextInputComponent> | APITextInputComponent): boolean {
if (isJSONEncodable(other)) {
return isEqual(other.toJSON(), this.data);

View File

@@ -35,7 +35,7 @@ export class ContextMenuCommandBuilder {
* Whether the command is enabled by default when the app is added to a guild
*
* @deprecated This property is deprecated and will be removed in the future.
* You should use `setDefaultMemberPermissions` or `setDMPermission` instead.
* You should use {@link ContextMenuCommandBuilder.setDefaultMemberPermissions} or {@link ContextMenuCommandBuilder.setDMPermission} instead.
*/
public readonly default_permission: boolean | undefined = undefined;
@@ -86,7 +86,7 @@ export class ContextMenuCommandBuilder {
* @param value - Whether or not to enable this command by default
*
* @see https://discord.com/developers/docs/interactions/application-commands#permissions
* @deprecated Use `setDefaultMemberPermissions` or `setDMPermission` instead.
* @deprecated Use {@link ContextMenuCommandBuilder.setDefaultMemberPermissions} or {@link ContextMenuCommandBuilder.setDMPermission} instead.
*/
public setDefaultPermission(value: boolean) {
// Assert the value matches the conditions

View File

@@ -70,6 +70,9 @@ export class ModalBuilder implements JSONEncodable<APIModalInteractionResponseCa
return this;
}
/**
* {@inheritDoc ComponentBuilder.toJSON}
*/
public toJSON(): APIModalInteractionResponseCallbackData {
validateRequiredParameters(this.data.custom_id, this.data.title, this.components);
// eslint-disable-next-line @typescript-eslint/consistent-type-assertions

View File

@@ -49,7 +49,7 @@ export class SlashCommandBuilder {
* Whether the command is enabled by default when the app is added to a guild
*
* @deprecated This property is deprecated and will be removed in the future.
* You should use `setDefaultMemberPermissions` or `setDMPermission` instead.
* You should use {@link (SlashCommandBuilder:class).setDefaultMemberPermissions} or {@link (SlashCommandBuilder:class).setDMPermission} instead.
*/
public readonly default_permission: boolean | undefined = undefined;
@@ -89,7 +89,7 @@ export class SlashCommandBuilder {
* @param value - Whether or not to enable this command by default
*
* @see https://discord.com/developers/docs/interactions/application-commands#permissions
* @deprecated Use `setDefaultMemberPermissions` or `setDMPermission` instead.
* @deprecated Use {@link (SlashCommandBuilder:class).setDefaultMemberPermissions} or {@link (SlashCommandBuilder:class).setDMPermission} instead.
*/
public setDefaultPermission(value: boolean) {
// Assert the value matches the conditions

View File

@@ -14,6 +14,9 @@ export class SlashCommandIntegerOption
{
public readonly type = ApplicationCommandOptionType.Integer as const;
/**
* {@inheritDoc ApplicationCommandNumericOptionMinMaxValueMixin.setMaxValue}
*/
public setMaxValue(max: number): this {
numberValidator.parse(max);
@@ -22,6 +25,9 @@ export class SlashCommandIntegerOption
return this;
}
/**
* {@inheritDoc ApplicationCommandNumericOptionMinMaxValueMixin.setMinValue}
*/
public setMinValue(min: number): this {
numberValidator.parse(min);

View File

@@ -14,6 +14,9 @@ export class SlashCommandNumberOption
{
public readonly type = ApplicationCommandOptionType.Number as const;
/**
* {@inheritDoc ApplicationCommandNumericOptionMinMaxValueMixin.setMaxValue}
*/
public setMaxValue(max: number): this {
numberValidator.parse(max);
@@ -22,6 +25,9 @@ export class SlashCommandNumberOption
return this;
}
/**
* {@inheritDoc ApplicationCommandNumericOptionMinMaxValueMixin.setMinValue}
*/
public setMinValue(min: number): this {
numberValidator.parse(min);

View File

@@ -52,9 +52,31 @@ export class EmbedBuilder {
}
/**
* Adds fields to the embed (max 25)
* Appends fields to the embed
*
* @param fields The fields to add
* @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
* const fields: APIEmbedField[] = ...;
* const embed = new EmbedBuilder()
* .addFields(fields);
* ```
*
* @example
* Using rest parameters (variadic)
* ```ts
* const embed = new EmbedBuilder()
* .addFields(
* { name: 'Field 1', value: 'Value 1' },
* { name: 'Field 2', value: 'Value 2' },
* );
* ```
*
* @param fields - The fields to add
*/
public addFields(...fields: RestOrArray<APIEmbedField>): this {
fields = normalizeArray(fields);
@@ -70,11 +92,37 @@ export class EmbedBuilder {
}
/**
* Removes, replaces, or inserts fields in the embed (max 25)
* Removes, replaces, or inserts fields in the embed.
*
* @param index The index to start at
* @param deleteCount The number of fields to remove
* @param fields The replacing field objects
* @remarks
* This method behaves similarly
* to {@link https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/slice | Array.prototype.splice}.
* 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
*/
public spliceFields(index: number, deleteCount: number, ...fields: APIEmbedField[]): this {
// Ensure adding these fields won't exceed the 25 field limit
@@ -88,8 +136,15 @@ export class EmbedBuilder {
}
/**
* Sets the embed's fields (max 25).
* @param fields The fields to set
* Sets the embed's fields
*
* @remarks
* This method is an alias for {@link EmbedBuilder.spliceFields}. More specifically,
* 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>) {
this.spliceFields(0, this.data.fields?.length ?? 0, ...normalizeArray(fields));
@@ -99,7 +154,7 @@ export class EmbedBuilder {
/**
* Sets the author of this embed
*
* @param options The options for the author
* @param options - The options for the author
*/
public setAuthor(options: EmbedAuthorOptions | null): this {
@@ -118,7 +173,7 @@ export class EmbedBuilder {
/**
* Sets the color of this embed
*
* @param color The color of the embed
* @param color - The color of the embed
*/
public setColor(color: number | RGBTuple | null): this {
// Data assertions
@@ -136,7 +191,7 @@ export class EmbedBuilder {
/**
* Sets the description of this embed
*
* @param description The description
* @param description - The description
*/
public setDescription(description: string | null): this {
// Data assertions
@@ -149,7 +204,7 @@ export class EmbedBuilder {
/**
* Sets the footer of this embed
*
* @param options The options for the footer
* @param options - The options for the footer
*/
public setFooter(options: EmbedFooterOptions | null): this {
if (options === null) {
@@ -167,7 +222,7 @@ export class EmbedBuilder {
/**
* Sets the image of this embed
*
* @param url The URL of the image
* @param url - The URL of the image
*/
public setImage(url: string | null): this {
// Data assertions
@@ -180,7 +235,7 @@ export class EmbedBuilder {
/**
* Sets the thumbnail of this embed
*
* @param url The URL of the thumbnail
* @param url - The URL of the thumbnail
*/
public setThumbnail(url: string | null): this {
// Data assertions
@@ -193,7 +248,7 @@ export class EmbedBuilder {
/**
* Sets the timestamp of this embed
*
* @param timestamp The timestamp or date
* @param timestamp - The timestamp or date
*/
public setTimestamp(timestamp: number | Date | null = Date.now()): this {
// Data assertions
@@ -206,7 +261,7 @@ export class EmbedBuilder {
/**
* Sets the title of this embed
*
* @param title The title
* @param title - The title
*/
public setTitle(title: string | null): this {
// Data assertions
@@ -219,7 +274,7 @@ export class EmbedBuilder {
/**
* Sets the URL of this embed
*
* @param url The URL
* @param url - The URL
*/
public setURL(url: string | null): this {
// Data assertions

View File

@@ -1,3 +1,9 @@
/**
* Represents a structure that can be checked against another
* given structure for equality
*
* @typeParam T - The type of object to compare the current object to
*/
export interface Equatable<T> {
/**
* Whether or not this is equal to another structure

View File

@@ -1,3 +1,8 @@
/**
* Represents an object capable of representing itself as a JSON object
*
* @typeParam T - The JSON type corresponding to {@link JSONEncodable.toJSON} outputs.
*/
export interface JSONEncodable<T> {
/**
* Transforms this object to its JSON format

View File

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

View File

@@ -5,8 +5,8 @@
"scripts": {
"test": "vitest run",
"build": "unbuild",
"lint": "prettier --check . && eslint src __tests__ --ext mjs,js,ts",
"format": "prettier --write . && eslint src __tests__ --ext mjs,js,ts --fix",
"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",
"fmt": "yarn format",
"docs": "downlevel-dts . docs --to=3.7 && docgen -i src/index.ts -c docs/index.json -o docs/docs.json --typescript && api-extractor run --local",
"prepack": "yarn lint && yarn test && yarn build",
@@ -51,17 +51,24 @@
"homepage": "https://discord.js.org",
"devDependencies": {
"@discordjs/docgen": "workspace:^",
"@favware/cliff-jumper": "^1.8.6",
"@microsoft/api-extractor": "^7.29.2",
"@types/node": "^16.11.47",
"c8": "^7.12.0",
"@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.21.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",
"prettier": "^2.7.1",
"rollup-plugin-typescript2": "0.32.1",
"rollup-plugin-typescript2": "^0.33.0",
"typescript": "^4.7.4",
"unbuild": "^0.8.4",
"vitest": "^0.21.1"
"unbuild": "^0.8.9",
"vitest": "^0.22.1"
},
"engines": {
"node": ">=16.9.0"

View File

@@ -28,6 +28,9 @@ export interface Collection<K, V> extends Map<K, V> {
/**
* A Map with additional utility methods. This is used throughout discord.js rather than Arrays for anything that has
* an ID, for significantly improved performance and ease-of-use.
*
* @typeParam K - The key type this collection holds
* @typeParam V - The value type this collection holds
*/
export class Collection<K, V> extends Map<K, V> {
/**
@@ -37,7 +40,9 @@ export class Collection<K, V> extends Map<K, V> {
* @param defaultValueGenerator - A function that generates the default value
*
* @example
* ```ts
* collection.ensure(guildId, () => defaultGuildConfig);
* ```
*/
public ensure(key: K, defaultValueGenerator: (key: K, collection: this) => V): V {
if (this.has(key)) return this.get(key)!;
@@ -230,7 +235,9 @@ export class Collection<K, V> extends Map<K, V> {
* @param thisArg - Value to use as `this` when executing function
*
* @example
* ```ts
* collection.find(user => user.username === 'Bob');
* ```
*/
public find<V2 extends V>(fn: (value: V, key: K, collection: this) => value is V2): V2 | undefined;
public find(fn: (value: V, key: K, collection: this) => boolean): V | undefined;
@@ -257,7 +264,9 @@ export class Collection<K, V> extends Map<K, V> {
* @param thisArg - Value to use as `this` when executing function
*
* @example
* ```ts
* collection.findKey(user => user.username === 'Bob');
* ```
*/
public findKey<K2 extends K>(fn: (value: V, key: K, collection: this) => key is K2): K2 | undefined;
public findKey(fn: (value: V, key: K, collection: this) => boolean): K | undefined;
@@ -304,7 +313,9 @@ export class Collection<K, V> extends Map<K, V> {
* @param thisArg - Value to use as `this` when executing function
*
* @example
* ```ts
* collection.filter(user => user.username === 'Bob');
* ```
*/
public filter<K2 extends K>(fn: (value: V, key: K, collection: this) => key is K2): Collection<K2, V>;
public filter<V2 extends V>(fn: (value: V, key: K, collection: this) => value is V2): Collection<K, V2>;
@@ -336,7 +347,9 @@ export class Collection<K, V> extends Map<K, V> {
* @param thisArg - Value to use as `this` when executing function
*
* @example
* ```ts
* const [big, small] = collection.partition(guild => guild.memberCount > 250);
* ```
*/
public partition<K2 extends K>(
fn: (value: V, key: K, collection: this) => key is K2,
@@ -385,7 +398,9 @@ export class Collection<K, V> extends Map<K, V> {
* @param thisArg - Value to use as `this` when executing function
*
* @example
* ```ts
* collection.flatMap(guild => guild.members.cache);
* ```
*/
public flatMap<T>(fn: (value: V, key: K, collection: this) => Collection<K, T>): Collection<K, T>;
public flatMap<T, This>(
@@ -405,7 +420,9 @@ export class Collection<K, V> extends Map<K, V> {
* @param thisArg - Value to use as `this` when executing function
*
* @example
* ```ts
* collection.map(user => user.tag);
* ```
*/
public map<T>(fn: (value: V, key: K, collection: this) => T): T[];
public map<This, T>(fn: (this: This, value: V, key: K, collection: this) => T, thisArg: This): T[];
@@ -429,7 +446,9 @@ export class Collection<K, V> extends Map<K, V> {
* @param thisArg - Value to use as `this` when executing function
*
* @example
* ```ts
* collection.mapValues(user => user.tag);
* ```
*/
public mapValues<T>(fn: (value: V, key: K, collection: this) => T): Collection<K, T>;
public mapValues<This, T>(fn: (this: This, value: V, key: K, collection: this) => T, thisArg: This): Collection<K, T>;
@@ -449,7 +468,9 @@ export class Collection<K, V> extends Map<K, V> {
* @param thisArg - Value to use as `this` when executing function
*
* @example
* ```ts
* collection.some(user => user.discriminator === '0000');
* ```
*/
public some(fn: (value: V, key: K, collection: this) => boolean): boolean;
public some<T>(fn: (this: T, value: V, key: K, collection: this) => boolean, thisArg: T): boolean;
@@ -470,7 +491,9 @@ export class Collection<K, V> extends Map<K, V> {
* @param thisArg - Value to use as `this` when executing function
*
* @example
* ```ts
* collection.every(user => !user.bot);
* ```
*/
public every<K2 extends K>(fn: (value: V, key: K, collection: this) => key is K2): this is Collection<K2, V>;
public every<V2 extends V>(fn: (value: V, key: K, collection: this) => value is V2): this is Collection<K, V2>;
@@ -502,7 +525,9 @@ export class Collection<K, V> extends Map<K, V> {
* @param initialValue - Starting value for the accumulator
*
* @example
* ```ts
* collection.reduce((acc, guild) => acc + guild.memberCount, 0);
* ```
*/
public reduce<T>(fn: (accumulator: T, value: V, key: K, collection: this) => T, initialValue?: T): T {
if (typeof fn !== 'function') throw new TypeError(`${fn} is not a function`);
@@ -540,10 +565,12 @@ export class Collection<K, V> extends Map<K, V> {
* @param thisArg - Value to use as `this` when executing function
*
* @example
* ```ts
* collection
* .each(user => console.log(user.username))
* .filter(user => user.bot)
* .each(user => console.log(user.username));
* ```
*/
public each(fn: (value: V, key: K, collection: this) => void): this;
public each<T>(fn: (this: T, value: V, key: K, collection: this) => void, thisArg: T): this;
@@ -560,10 +587,12 @@ export class Collection<K, V> extends Map<K, V> {
* @param thisArg - Value to use as `this` when executing function
*
* @example
* ```ts
* collection
* .tap(coll => console.log(coll.size))
* .filter(user => user.bot)
* .tap(coll => console.log(coll.size))
* ```
*/
public tap(fn: (collection: this) => void): this;
public tap<T>(fn: (this: T, collection: this) => void, thisArg: T): this;
@@ -578,7 +607,9 @@ export class Collection<K, V> extends Map<K, V> {
* Creates an identical shallow copy of this collection.
*
* @example
* ```ts
* const newColl = someColl.clone();
* ```
*/
public clone(): Collection<K, V> {
return new this.constructor[Symbol.species](this);
@@ -590,7 +621,9 @@ export class Collection<K, V> extends Map<K, V> {
* @param collections - Collections to merge
*
* @example
* ```ts
* const newColl = someColl.concat(someOtherColl, anotherColl, ohBoyAColl);
* ```
*/
public concat(...collections: ReadonlyCollection<K, V>[]) {
const newColl = this.clone();
@@ -631,7 +664,9 @@ export class Collection<K, V> extends Map<K, V> {
* If omitted, the collection is sorted according to each character's Unicode code point value, according to the string conversion of each element.
*
* @example
* ```ts
* collection.sort((userA, userB) => userA.createdTimestamp - userB.createdTimestamp);
* ```
*/
public sort(compareFunction: Comparator<K, V> = Collection.defaultSort) {
const entries = [...this.entries()];
@@ -686,6 +721,7 @@ export class Collection<K, V> extends Map<K, V> {
* @param whenInBoth - Function getting the result if the entry exists in both Collections
*
* @example
* ```ts
* // Sums up the entries in two collections.
* coll.merge(
* other,
@@ -693,8 +729,10 @@ export class Collection<K, V> extends Map<K, V> {
* y => ({ keep: true, value: y }),
* (x, y) => ({ keep: true, value: x + y }),
* );
* ```
*
* @example
* ```ts
* // Intersects two collections in a left-biased manner.
* coll.merge(
* other,
@@ -702,6 +740,7 @@ export class Collection<K, V> extends Map<K, V> {
* y => ({ keep: false }),
* (x, _) => ({ keep: true, value: x }),
* );
* ```
*/
public merge<T, R>(
other: ReadonlyCollection<K, T>,
@@ -739,7 +778,9 @@ export class Collection<K, V> extends Map<K, V> {
* according to the string conversion of each element.
*
* @example
* ```ts
* collection.sorted((userA, userB) => userA.createdTimestamp - userB.createdTimestamp);
* ```
*/
public sorted(compareFunction: Comparator<K, V> = Collection.defaultSort) {
return new this.constructor[Symbol.species](this).sort((av, bv, ak, bk) => compareFunction(av, bv, ak, bk));
@@ -761,8 +802,10 @@ export class Collection<K, V> extends Map<K, V> {
* @param combine - Function to combine an existing entry with a new one
*
* @example
* ```ts
* Collection.combineEntries([["a", 1], ["b", 2], ["a", 2]], (x, y) => x + y);
* // returns Collection { "a" => 3, "b" => 2 }
* ```
*/
public static combineEntries<K, V>(
entries: Iterable<[K, V]>,

View File

@@ -95,7 +95,7 @@ All notable changes to this project will be documented in this file.
- 14.0.1 release bump, no new features.
# [14.0.0](https://github.com/discordjs/discord.js/compare/13.10.1...14.0.0) - (2022-07-17)
# [14.0.0](https://github.com/discordjs/discord.js/compare/13.10.2...14.0.0) - (2022-07-17)
## Bug Fixes
@@ -501,6 +501,12 @@ All notable changes to this project will be documented in this file.
- AssertType -> expectType ([3f36746](https://github.com/discordjs/discord.js/commit/3f36746561a40cd61a7cd2e054b7ef80d58fc707))
- Fix cache types resolving to `never` (#7164) ([c978dbb](https://github.com/discordjs/discord.js/commit/c978dbb6233bcd85408caf0bca7619c9c5d508f0))
# [13.10.2](https://github.com/discordjs/discord.js/compare/13.10.1...13.10.2) - (2022-08-10)
## Typings
- **Message:** Correct `bulkDelete` return type (v13) (#8469) ([03c59e3](https://github.com/discordjs/discord.js/commit/03c59e3a837edcaa428549c8387ef4d29e3ef6e4))
# [13.10.1](https://github.com/discordjs/discord.js/compare/13.10.0...13.10.1) - (2022-08-10)
## Bug Fixes

View File

@@ -54,19 +54,19 @@
"@discordjs/rest": "workspace:^",
"@sapphire/snowflake": "^3.2.2",
"@types/ws": "^8.5.3",
"discord-api-types": "^0.36.3",
"discord-api-types": "^0.37.3",
"fast-deep-equal": "^3.1.3",
"lodash.snakecase": "^4.1.1",
"tslib": "^2.4.0",
"undici": "^5.8.2",
"undici": "^5.9.1",
"ws": "^8.8.1"
},
"devDependencies": {
"@discordjs/docgen": "workspace:^",
"@favware/cliff-jumper": "^1.8.6",
"@types/node": "^16.11.47",
"@favware/cliff-jumper": "^1.8.7",
"@types/node": "^16.11.52",
"dtslint": "^4.2.1",
"eslint": "^8.21.0",
"eslint": "^8.22.0",
"jest": "^28.1.3",
"prettier": "^2.7.1",
"tsd": "^0.22.0",

View File

@@ -164,7 +164,7 @@ class GuildChannelManager extends CachedManager {
/**
* @typedef {ChannelWebhookCreateOptions} WebhookCreateOptions
* @property {GuildChannelResolvable} channel The channel to create the webhook for
* @property {TextChannel|NewsChannel|VoiceChannel|Snowflake} channel The channel to create the webhook for
*/
/**

View File

@@ -1,6 +1,5 @@
'use strict';
const { Buffer } = require('node:buffer');
const { setTimeout, clearTimeout } = require('node:timers');
const { Collection } = require('@discordjs/collection');
const { makeURLSearchParams } = require('@discordjs/rest');
@@ -128,8 +127,12 @@ class GuildMemberManager extends CachedManager {
resolvedOptions.roles = resolvedRoles;
}
const data = await this.client.rest.put(Routes.guildMember(this.guild.id, userId), { body: resolvedOptions });
// Data is an empty buffer if the member is already part of the guild.
return data instanceof Buffer ? (options.fetchWhenExisting === false ? null : this.fetch(userId)) : this._add(data);
// Data is an empty Uint8Array if the member is already part of the guild.
return data instanceof Uint8Array
? options.fetchWhenExisting === false
? null
: this.fetch(userId)
: this._add(data);
}
/**
@@ -441,6 +444,42 @@ class GuildMemberManager extends CachedManager {
return this.guild.bans.remove(user, reason);
}
/**
* Options used for adding or removing a role from a member.
* @typedef {Object} AddOrRemoveGuildMemberRoleOptions
* @property {GuildMemberResolvable} user The user to add/remove the role from
* @property {RoleResolvable} role The role to add/remove
* @property {string} [reason] Reason for adding/removing the role
*/
/**
* Adds a role to a member.
* @param {AddOrRemoveGuildMemberRoleOptions} options Options for adding the role
* @returns {Promise<GuildMember|User|Snowflake>}
*/
async addRole(options) {
const { user, role, reason } = options;
const userId = this.guild.members.resolveId(user);
const roleId = this.guild.roles.resolveId(role);
await this.client.rest.put(Routes.guildMemberRole(this.guild.id, userId, roleId), { reason });
return this.resolve(user) ?? this.client.users.resolve(user) ?? userId;
}
/**
* Removes a role from a member.
* @param {AddOrRemoveGuildMemberRoleOptions} options Options for removing the role
* @returns {Promise<GuildMember|User|Snowflake>}
*/
async removeRole(options) {
const { user, role, reason } = options;
const userId = this.guild.members.resolveId(user);
const roleId = this.guild.roles.resolveId(role);
await this.client.rest.delete(Routes.guildMemberRole(this.guild.id, userId, roleId), { reason });
return this.resolve(user) ?? this.client.users.resolve(user) ?? userId;
}
async _fetchSingle({ user, cache, force = false }) {
if (!force) {
const existing = this.cache.get(user);

View File

@@ -1,5 +1,6 @@
'use strict';
const { deprecate } = require('node:util');
const { isJSONEncodable } = require('@discordjs/builders');
const Component = require('./Component');
const { createComponent } = require('../util/Components');
@@ -24,6 +25,7 @@ class ActionRow extends Component {
* Creates a new action row builder from JSON data
* @param {JSONEncodable<APIActionRowComponent>|APIActionRowComponent} other The other data
* @returns {ActionRowBuilder}
* @deprecated Use {@link ActionRowBuilder.from()} instead.
*/
static from(other) {
if (isJSONEncodable(other)) {
@@ -41,4 +43,6 @@ class ActionRow extends Component {
}
}
ActionRow.from = deprecate(ActionRow.from, 'ActionRow.from() is deprecated. Use ActionRowBuilder.from() instead.');
module.exports = ActionRow;

View File

@@ -115,10 +115,10 @@ class Embed {
get video() {
if (!this.data.video) return null;
return {
url: this.data.image.url,
proxyURL: this.data.image.proxy_url,
height: this.data.image.height,
width: this.data.image.width,
url: this.data.video.url,
proxyURL: this.data.video.proxy_url,
height: this.data.video.height,
width: this.data.video.width,
};
}

View File

@@ -216,6 +216,8 @@ class Guild extends AnonymousGuild {
* @type {?boolean}
*/
this.widgetEnabled = data.widget_enabled;
} else {
this.widgetEnabled ??= null;
}
if ('widget_channel_id' in data) {
@@ -224,6 +226,8 @@ class Guild extends AnonymousGuild {
* @type {?string}
*/
this.widgetChannelId = data.widget_channel_id;
} else {
this.widgetChannelId ??= null;
}
if ('explicit_content_filter' in data) {
@@ -489,7 +493,7 @@ class Guild extends AnonymousGuild {
/**
* Widget channel for this guild
* @type {?TextChannel}
* @type {?(TextChannel|NewsChannel|VoiceChannel|StageChannel)}
* @readonly
*/
get widgetChannel() {
@@ -656,14 +660,14 @@ class Guild extends AnonymousGuild {
* Data for the Guild Widget Settings object
* @typedef {Object} GuildWidgetSettings
* @property {boolean} enabled Whether the widget is enabled
* @property {?GuildChannel} channel The widget invite channel
* @property {?(TextChannel|NewsChannel|VoiceChannel|StageChannel)} channel The widget invite channel
*/
/**
* The Guild Widget Settings object
* @typedef {Object} GuildWidgetSettingsData
* @property {boolean} enabled Whether the widget is enabled
* @property {?GuildChannelResolvable} channel The widget invite channel
* @property {?(TextChannel|NewsChannel|VoiceChannel|StageChannel|Snowflake)} channel The widget invite channel
*/
/**

View File

@@ -106,7 +106,7 @@ class GuildAuditLogsEntry {
this.actionType = GuildAuditLogsEntry.actionType(data.action_type);
/**
* Specific action type of this entry in its string presentation
* The type of action that occured.
* @type {AuditLogEvent}
*/
this.action = data.action_type;
@@ -220,7 +220,6 @@ class GuildAuditLogsEntry {
case AuditLogEvent.ApplicationCommandPermissionUpdate:
this.extra = {
applicationId: data.options.application_id,
guild: guild.client.guilds.cache.get(data.options.guild_id) ?? { id: data.options.guild_id },
};
break;

View File

@@ -255,7 +255,7 @@ class InteractionResponses {
* An object containing the same properties as {@link CollectorOptions}, but a few less:
* @typedef {Object} AwaitModalSubmitOptions
* @property {CollectorFilter} [filter] The filter applied to this collector
* @property {number} time Time to wait for an interaction before rejecting
* @property {number} time Time in milliseconds to wait for an interaction before rejecting
*/
/**

View File

@@ -192,7 +192,10 @@ declare module 'node:events' {
class EventEmitter {
// Add type overloads for client events.
public static once<K extends keyof ClientEvents>(eventEmitter: Client, eventName: K): Promise<ClientEvents[K]>;
public static on<K extends keyof ClientEvents>(eventEmitter: Client, eventName: K): AsyncIterator<ClientEvents[K]>;
public static on<K extends keyof ClientEvents>(
eventEmitter: Client,
eventName: K,
): AsyncIterableIterator<ClientEvents[K]>;
}
}
@@ -1124,7 +1127,7 @@ export class Guild extends AnonymousGuild {
public vanityURLUses: number | null;
public get voiceAdapterCreator(): InternalDiscordGatewayAdapterCreator;
public voiceStates: VoiceStateManager;
public get widgetChannel(): TextChannel | null;
public get widgetChannel(): TextChannel | NewsChannel | VoiceBasedChannel | null;
public widgetChannelId: Snowflake | null;
public widgetEnabled: boolean | null;
public get maximumBitrate(): number;
@@ -1178,35 +1181,37 @@ export class Guild extends AnonymousGuild {
public toJSON(): unknown;
}
export class GuildAuditLogs<T extends GuildAuditLogsResolvable = null> {
export class GuildAuditLogs<T extends GuildAuditLogsResolvable = AuditLogEvent> {
private constructor(guild: Guild, data: RawGuildAuditLogData);
private applicationCommands: Collection<Snowflake, ApplicationCommand>;
private webhooks: Collection<Snowflake, Webhook>;
private integrations: Collection<Snowflake | string, Integration>;
private guildScheduledEvents: Collection<Snowflake, GuildScheduledEvent>;
public entries: Collection<Snowflake, GuildAuditLogsEntry<T>>;
public static Entry: typeof GuildAuditLogsEntry;
public toJSON(): unknown;
}
export class GuildAuditLogsEntry<
TAction extends GuildAuditLogsResolvable = null,
TAction extends GuildAuditLogsResolvable = AuditLogEvent,
TActionType extends GuildAuditLogsActionType = TAction extends keyof GuildAuditLogsTypes
? GuildAuditLogsTypes[TAction][1]
: 'All',
: GuildAuditLogsActionType,
TTargetType extends GuildAuditLogsTargetType = TAction extends keyof GuildAuditLogsTypes
? GuildAuditLogsTypes[TAction][0]
: 'Unknown',
: GuildAuditLogsTargetType,
TResolvedType = TAction extends null ? AuditLogEvent : TAction,
> {
private constructor(logs: GuildAuditLogs, guild: Guild, data: RawGuildAuditLogEntryData);
public static Targets: GuildAuditLogsTargets;
public action: TAction;
public action: TResolvedType;
public actionType: TActionType;
public changes: AuditLogChange[];
public get createdAt(): Date;
public get createdTimestamp(): number;
public executor: User | null;
public extra: TAction extends keyof GuildAuditLogsEntryExtraField ? GuildAuditLogsEntryExtraField[TAction] : null;
public extra: TResolvedType extends keyof GuildAuditLogsEntryExtraField
? GuildAuditLogsEntryExtraField[TResolvedType]
: null;
public id: Snowflake;
public reason: string | null;
public target: TTargetType extends keyof GuildAuditLogsEntryTargetField<TActionType>
@@ -1970,6 +1975,7 @@ export class ModalSubmitFields {
export interface ModalMessageModalSubmitInteraction<Cached extends CacheType = CacheType>
extends ModalSubmitInteraction<Cached> {
message: Message<BooleanCache<Cached>>;
channelId: Snowflake;
update(options: InteractionUpdateOptions & { fetchReply: true }): Promise<Message>;
update(
options: string | MessagePayload | InteractionUpdateOptions,
@@ -3406,6 +3412,12 @@ export class GuildManager extends CachedManager<Snowflake, Guild, GuildResolvabl
public fetch(options?: FetchGuildsOptions): Promise<Collection<Snowflake, OAuth2Guild>>;
}
export interface AddOrRemoveGuildMemberRoleOptions {
user: GuildMemberResolvable;
role: RoleResolvable;
reason?: string;
}
export class GuildMemberManager extends CachedManager<Snowflake, GuildMember, GuildMemberResolvable> {
private constructor(guild: Guild, iterable?: Iterable<RawGuildMemberData>);
public guild: Guild;
@@ -3428,6 +3440,8 @@ export class GuildMemberManager extends CachedManager<Snowflake, GuildMember, Gu
public prune(options?: GuildPruneMembersOptions): Promise<number>;
public search(options: GuildSearchMembersOptions): Promise<Collection<Snowflake, GuildMember>>;
public unban(user: UserResolvable, reason?: string): Promise<User | null>;
public addRole(options: AddOrRemoveGuildMemberRoleOptions): Promise<GuildMember | User | Snowflake>;
public removeRole(options: AddOrRemoveGuildMemberRoleOptions): Promise<GuildMember | User | Snowflake>;
}
export class GuildBanManager extends CachedManager<Snowflake, GuildBan, GuildBanResolvable> {
@@ -3823,27 +3837,57 @@ export interface ApplicationCommandAttachmentOption extends BaseApplicationComma
type: ApplicationCommandOptionType.Attachment;
}
export interface ApplicationCommandAutocompleteOption extends Omit<BaseApplicationCommandOptionsData, 'autocomplete'> {
type:
| ApplicationCommandOptionType.String
| ApplicationCommandOptionType.Number
| ApplicationCommandOptionType.Integer;
export interface ApplicationCommandAutocompleteNumericOption
extends Omit<BaseApplicationCommandOptionsData, 'autocomplete'> {
type: CommandOptionNumericResolvableType;
minValue?: number;
maxValue?: number;
autocomplete: true;
}
export interface ApplicationCommandChoicesData extends Omit<BaseApplicationCommandOptionsData, 'autocomplete'> {
export interface ApplicationCommandAutocompleteStringOption
extends Omit<BaseApplicationCommandOptionsData, 'autocomplete'> {
type: ApplicationCommandOptionType.String;
minLength?: number;
maxLength?: number;
autocomplete: true;
}
export interface ApplicationCommandAutocompleteNumericOptionData
extends Omit<BaseApplicationCommandOptionsData, 'autocomplete'> {
type: CommandOptionNumericResolvableType;
minValue?: number;
min_value?: number;
maxValue?: number;
max_value?: number;
autocomplete: true;
}
export interface ApplicationCommandAutocompleteStringOptionData
extends Omit<BaseApplicationCommandOptionsData, 'autocomplete'> {
type: ApplicationCommandOptionType.String;
minLength?: number;
min_length?: number;
maxLength?: number;
max_length?: number;
autocomplete: true;
}
export interface ApplicationCommandChoicesData<Type extends string | number = string | number>
extends Omit<BaseApplicationCommandOptionsData, 'autocomplete'> {
type: CommandOptionChoiceResolvableType;
choices?: ApplicationCommandOptionChoiceData[];
choices?: ApplicationCommandOptionChoiceData<Type>[];
autocomplete?: false;
}
export interface ApplicationCommandChoicesOption extends Omit<BaseApplicationCommandOptionsData, 'autocomplete'> {
export interface ApplicationCommandChoicesOption<Type extends string | number = string | number>
extends Omit<BaseApplicationCommandOptionsData, 'autocomplete'> {
type: CommandOptionChoiceResolvableType;
choices?: ApplicationCommandOptionChoiceData[];
choices?: ApplicationCommandOptionChoiceData<Type>[];
autocomplete?: false;
}
export interface ApplicationCommandNumericOptionData extends ApplicationCommandChoicesData {
export interface ApplicationCommandNumericOptionData extends ApplicationCommandChoicesData<number> {
type: CommandOptionNumericResolvableType;
minValue?: number;
min_value?: number;
@@ -3851,7 +3895,7 @@ export interface ApplicationCommandNumericOptionData extends ApplicationCommandC
max_value?: number;
}
export interface ApplicationCommandStringOptionData extends ApplicationCommandChoicesData {
export interface ApplicationCommandStringOptionData extends ApplicationCommandChoicesData<string> {
type: ApplicationCommandOptionType.String;
minLength?: number;
min_length?: number;
@@ -3863,13 +3907,13 @@ export interface ApplicationCommandBooleanOptionData extends BaseApplicationComm
type: ApplicationCommandOptionType.Boolean;
}
export interface ApplicationCommandNumericOption extends ApplicationCommandChoicesOption {
export interface ApplicationCommandNumericOption extends ApplicationCommandChoicesOption<number> {
type: CommandOptionNumericResolvableType;
minValue?: number;
maxValue?: number;
}
export interface ApplicationCommandStringOption extends ApplicationCommandChoicesOption {
export interface ApplicationCommandStringOption extends ApplicationCommandChoicesOption<string> {
type: ApplicationCommandOptionType.String;
minLength?: number;
maxLength?: number;
@@ -3891,23 +3935,12 @@ export interface ApplicationCommandSubGroup extends Omit<BaseApplicationCommandO
export interface ApplicationCommandSubCommandData extends Omit<BaseApplicationCommandOptionsData, 'required'> {
type: ApplicationCommandOptionType.Subcommand;
options?: (
| ApplicationCommandChoicesData
| ApplicationCommandNonOptionsData
| ApplicationCommandChannelOptionData
| ApplicationCommandAutocompleteOption
| ApplicationCommandNumericOptionData
| ApplicationCommandRoleOptionData
| ApplicationCommandUserOptionData
| ApplicationCommandMentionableOptionData
| ApplicationCommandStringOptionData
| ApplicationCommandBooleanOption
)[];
options?: Exclude<ApplicationCommandOptionData, ApplicationCommandSubGroupData | ApplicationCommandSubCommandData>[];
}
export interface ApplicationCommandSubCommand extends Omit<BaseApplicationCommandOptionsData, 'required'> {
type: ApplicationCommandOptionType.Subcommand;
options?: (ApplicationCommandChoicesOption | ApplicationCommandNonOptions | ApplicationCommandChannelOption)[];
options?: Exclude<ApplicationCommandOption, ApplicationCommandSubGroup | ApplicationCommandSubCommand>[];
}
export interface ApplicationCommandNonOptionsData extends BaseApplicationCommandOptionsData {
@@ -3922,8 +3955,8 @@ export type ApplicationCommandOptionData =
| ApplicationCommandSubGroupData
| ApplicationCommandNonOptionsData
| ApplicationCommandChannelOptionData
| ApplicationCommandChoicesData
| ApplicationCommandAutocompleteOption
| ApplicationCommandAutocompleteNumericOptionData
| ApplicationCommandAutocompleteStringOptionData
| ApplicationCommandNumericOptionData
| ApplicationCommandStringOptionData
| ApplicationCommandRoleOptionData
@@ -3934,9 +3967,10 @@ export type ApplicationCommandOptionData =
export type ApplicationCommandOption =
| ApplicationCommandSubGroup
| ApplicationCommandAutocompleteNumericOption
| ApplicationCommandAutocompleteStringOption
| ApplicationCommandNonOptions
| ApplicationCommandChannelOption
| ApplicationCommandChoicesOption
| ApplicationCommandNumericOption
| ApplicationCommandStringOption
| ApplicationCommandRoleOption
@@ -3946,10 +3980,10 @@ export type ApplicationCommandOption =
| ApplicationCommandAttachmentOption
| ApplicationCommandSubCommand;
export interface ApplicationCommandOptionChoiceData {
export interface ApplicationCommandOptionChoiceData<Value extends string | number = string | number> {
name: string;
nameLocalizations?: LocalizationMap;
value: string | number;
value: Value;
}
export interface ApplicationCommandPermissions {
@@ -4123,7 +4157,7 @@ export interface ChannelWebhookCreateOptions {
}
export interface WebhookCreateOptions extends ChannelWebhookCreateOptions {
channel: GuildChannelResolvable;
channel: TextChannel | NewsChannel | VoiceChannel | Snowflake;
}
export interface ClientEvents {
@@ -4704,7 +4738,7 @@ export interface GuildAuditLogsEntryExtraField {
[AuditLogEvent.StageInstanceCreate]: StageChannel | { id: Snowflake };
[AuditLogEvent.StageInstanceDelete]: StageChannel | { id: Snowflake };
[AuditLogEvent.StageInstanceUpdate]: StageChannel | { id: Snowflake };
[AuditLogEvent.ApplicationCommandPermissionUpdate]: { applicationId: Snowflake; guild: Guild | { id: Snowflake } };
[AuditLogEvent.ApplicationCommandPermissionUpdate]: { applicationId: Snowflake };
}
export interface GuildAuditLogsEntryTargetField<TActionType extends GuildAuditLogsActionType> {
@@ -4796,7 +4830,7 @@ export interface GuildCreateOptions {
export interface GuildWidgetSettings {
enabled: boolean;
channel: NonThreadGuildBasedChannel | null;
channel: TextChannel | NewsChannel | VoiceBasedChannel | null;
}
export interface GuildEditData {
@@ -4874,7 +4908,7 @@ export interface GuildPruneMembersOptions {
export interface GuildWidgetSettingsData {
enabled: boolean;
channel: GuildChannelResolvable | null;
channel: TextChannel | NewsChannel | VoiceBasedChannel | Snowflake | null;
}
export interface GuildSearchMembersOptions {

View File

@@ -134,6 +134,8 @@ import {
Webhook,
WebhookClient,
InteractionWebhook,
GuildAuditLogsActionType,
GuildAuditLogsTargetType,
} from '.';
import { expectAssignable, expectNotAssignable, expectNotType, expectType } from 'tsd';
import type { ContextMenuCommandBuilder, SlashCommandBuilder } from '@discordjs/builders';
@@ -1100,6 +1102,7 @@ expectAssignable<'death'>(ShardEvents.Death);
expectAssignable<1>(Status.Connecting);
declare const applicationCommandData: ApplicationCommandData;
declare const applicationCommandOptionData: ApplicationCommandOptionData;
declare const applicationCommandResolvable: ApplicationCommandResolvable;
declare const applicationCommandManager: ApplicationCommandManager;
{
@@ -1119,6 +1122,24 @@ declare const applicationCommandManager: ApplicationCommandManager;
expectType<Promise<Collection<Snowflake, ApplicationCommand>>>(
applicationCommandManager.set([applicationCommandData], '0'),
);
// Test inference of choice values.
if ('choices' in applicationCommandOptionData) {
if (applicationCommandOptionData.type === ApplicationCommandOptionType.String) {
expectType<string>(applicationCommandOptionData.choices[0]!.value);
expectNotType<number>(applicationCommandOptionData.choices[0]!.value);
}
if (applicationCommandOptionData.type === ApplicationCommandOptionType.Integer) {
expectType<number>(applicationCommandOptionData.choices[0]!.value);
expectNotType<string>(applicationCommandOptionData.choices[0]!.value);
}
if (applicationCommandOptionData.type === ApplicationCommandOptionType.Number) {
expectType<number>(applicationCommandOptionData.choices[0]!.value);
expectNotType<string>(applicationCommandOptionData.choices[0]!.value);
}
}
}
declare const applicationNonChoiceOptionData: ApplicationCommandOptionData & {
@@ -1533,7 +1554,7 @@ expectType<Promise<GuildAuditLogs<AuditLogEvent.IntegrationUpdate>>>(
);
expectType<Promise<GuildAuditLogs<null>>>(guild.fetchAuditLogs({ type: null }));
expectType<Promise<GuildAuditLogs<null>>>(guild.fetchAuditLogs());
expectType<Promise<GuildAuditLogs<AuditLogEvent>>>(guild.fetchAuditLogs());
expectType<Promise<GuildAuditLogsEntry<AuditLogEvent.MemberKick, 'Delete', 'User'> | undefined>>(
guild.fetchAuditLogs({ type: AuditLogEvent.MemberKick }).then(al => al.entries.first()),
@@ -1542,10 +1563,10 @@ expectAssignable<Promise<GuildAuditLogsEntry<AuditLogEvent.MemberKick, 'Delete',
guild.fetchAuditLogs({ type: AuditLogEvent.MemberKick }).then(al => al.entries.first()),
);
expectType<Promise<GuildAuditLogsEntry<null, 'All', 'Unknown'> | undefined>>(
expectType<Promise<GuildAuditLogsEntry<null, GuildAuditLogsActionType, GuildAuditLogsTargetType> | undefined>>(
guild.fetchAuditLogs({ type: null }).then(al => al.entries.first()),
);
expectType<Promise<GuildAuditLogsEntry<null, 'All', 'Unknown'> | undefined>>(
expectType<Promise<GuildAuditLogsEntry<null, GuildAuditLogsActionType, GuildAuditLogsTargetType> | undefined>>(
guild.fetchAuditLogs().then(al => al.entries.first()),
);

View File

@@ -1,3 +1,9 @@
import { createUnbuildConfig } from '../../build.config';
export default createUnbuildConfig({ minify: true, externals: ['package.cjs', 'package.mjs'] });
export default createUnbuildConfig({
entries: [
{ builder: 'rollup', input: 'src/index' },
{ builder: 'rollup', input: 'src/cli' },
],
minify: true,
});

View File

@@ -1,17 +1,17 @@
{
"name": "@discordjs/docgen",
"version": "0.12.0",
"version": "0.12.1",
"description": "The docs.json generator for discord.js and its related projects",
"scripts": {
"build": "unbuild",
"lint": "prettier --check . && eslint src --ext mjs,js,ts",
"format": "prettier --write . && eslint src --ext mjs,js,ts --fix",
"lint": "prettier --check . && TIMING=1 eslint src --ext mjs,js,ts",
"format": "prettier --write . && TIMING=1 eslint src --ext mjs,js,ts --fix",
"fmt": "yarn format",
"prepack": "yarn lint && yarn test && yarn build",
"prepack": "yarn format && yarn build",
"changelog": "git cliff --prepend ./CHANGELOG.md -u -c ./cliff.toml -r ../../ --include-path 'packages/docgen/*'",
"release": "cliff-jumper"
},
"bin": "./dist/index.cjs",
"bin": "./dist/cli.cjs",
"directories": {
"lib": "src"
},
@@ -42,23 +42,31 @@
},
"homepage": "https://discord.js.org",
"dependencies": {
"@discordjs/collection": "workspace:^",
"commander": "^9.4.0",
"jsdoc-to-markdown": "^7.1.1",
"tslib": "^2.4.0",
"typedoc": "^0.23.10"
},
"devDependencies": {
"@favware/cliff-jumper": "^1.8.6",
"@favware/cliff-jumper": "^1.8.7",
"@types/jsdoc-to-markdown": "^7.0.3",
"@types/node": "^16.11.47",
"eslint": "^8.21.0",
"@types/node": "^16.11.52",
"@typescript-eslint/eslint-plugin": "^5.33.1",
"@typescript-eslint/parser": "^5.33.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",
"prettier": "^2.7.1",
"rollup-plugin-typescript2": "0.32.1",
"rollup-plugin-typescript2": "^0.33.0",
"typescript": "^4.7.4",
"unbuild": "^0.8.4"
"unbuild": "^0.8.9"
},
"engines": {
"node": ">=16.9.0"
},
"publishConfig": {
"access": "public"
}
}

View File

@@ -0,0 +1,25 @@
#!/usr/bin/env node
import { createCommand } from 'commander';
import { build } from './index.js';
import packageFile from '../package.json';
export interface CLIOptions {
input: string[];
custom: string;
root: string;
output: string;
typescript: boolean;
}
const command = createCommand()
.version(packageFile.version)
.option('-i, --input <string...>', 'Source directories to parse JSDocs in')
.option('-c, --custom <string>', 'Custom docs definition file to use')
.option('-r, --root [string]', 'Root directory of the project', '.')
.option('-o, --output <string>', 'Path to output file')
.option('--typescript', '', false);
const program = command.parse(process.argv);
const options = program.opts<CLIOptions>();
build(options);

View File

@@ -1,5 +1,4 @@
import { dirname, join, relative } from 'node:path';
import { Collection } from '@discordjs/collection';
import type { DeclarationReflection } from 'typedoc';
import type { ChildTypes, Class, Config, CustomDocs, RootTypes } from './interfaces/index.js';
import { DocumentedClass } from './types/class.js';
@@ -13,15 +12,15 @@ import { DocumentedTypeDef } from './types/typedef.js';
import packageFile from '../package.json';
export class Documentation {
public readonly classes = new Collection<string, DocumentedClass>();
public readonly classes = new Map<string, DocumentedClass>();
public readonly functions = new Collection<string, DocumentedMethod>();
public readonly functions = new Map<string, DocumentedMethod>();
public readonly interfaces = new Collection<string, DocumentedInterface>();
public readonly interfaces = new Map<string, DocumentedInterface>();
public readonly typedefs = new Collection<string, DocumentedTypeDef>();
public readonly typedefs = new Map<string, DocumentedTypeDef>();
public readonly externals = new Collection<string, DocumentedExternal>();
public readonly externals = new Map<string, DocumentedExternal>();
public constructor(
data: RootTypes[] | DeclarationReflection[],
@@ -244,11 +243,11 @@ export class Documentation {
format: Documentation.FORMAT_VERSION,
date: Date.now(),
},
classes: this.classes.map((c) => c.serialize()),
functions: this.functions.map((f) => f.serialize()),
interfaces: this.interfaces.map((i) => i.serialize()),
typedefs: this.typedefs.map((t) => t.serialize()),
externals: this.externals.map((e) => e.serialize()),
classes: [...this.classes.values()].map((c) => c.serialize()),
functions: [...this.functions.values()].map((f) => f.serialize()),
interfaces: [...this.interfaces.values()].map((i) => i.serialize()),
typedefs: [...this.typedefs.values()].map((t) => t.serialize()),
externals: [...this.externals.values()].map((e) => e.serialize()),
custom: this.custom,
};
}

View File

@@ -1,20 +1,10 @@
#!/usr/bin/env node
import { readFileSync, writeFileSync } from 'node:fs';
import { join, basename, extname, dirname, relative } from 'node:path';
import { createCommand } from 'commander';
import { dirname, join, extname, basename, relative } from 'node:path';
import jsdoc2md from 'jsdoc-to-markdown';
import { Application, DeclarationReflection, TSConfigReader } from 'typedoc';
import { Documentation } from './documentation.js';
import type { ChildTypes, CustomDocs, RootTypes } from './interfaces/index.js';
import packageFile from '../package.json';
interface CLIOptions {
input: string[];
custom: string;
root: string;
output: string;
typescript: boolean;
}
import { type DeclarationReflection, Application, TSConfigReader } from 'typedoc';
import type { CLIOptions } from './cli';
import { Documentation } from './documentation';
import type { RootTypes, ChildTypes, CustomDocs } from './interfaces';
interface CustomFiles {
id?: string;
@@ -27,79 +17,70 @@ interface CustomFiles {
}[];
}
const command = createCommand()
.version(packageFile.version)
.option('-i, --input <string...>', 'Source directories to parse JSDocs in')
.option('-c, --custom <string>', 'Custom docs definition file to use')
.option('-r, --root [string]', 'Root directory of the project', '.')
.option('-o, --output <string>', 'Path to output file')
.option('--typescript', '', false);
const program = command.parse(process.argv);
const options = program.opts<CLIOptions>();
let data: (RootTypes & ChildTypes)[] | DeclarationReflection[] = [];
if (options.typescript) {
console.log('Parsing Typescript in source files...');
const app = new Application();
app.options.addReader(new TSConfigReader());
app.bootstrap({ entryPoints: options.input });
const project = app.convert();
if (project) {
// @ts-expect-error
data = app.serializer.toObject(project).children!;
console.log(`${data.length} items parsed.`);
}
} else {
console.log('Parsing JSDocs in source files...');
data = jsdoc2md.getTemplateDataSync({ files: options.input }) as (RootTypes & ChildTypes)[];
console.log(`${data.length} JSDoc items parsed.`);
}
const custom: Record<string, CustomDocs> = {};
if (options.custom) {
console.log('Loading custom docs files...');
const customDir = dirname(options.custom);
const file = readFileSync(options.custom, 'utf-8');
const data = JSON.parse(file) as CustomFiles[];
for (const category of data) {
const categoryId = category.id ?? category.name.toLowerCase();
const dir = join(customDir, category.path ?? categoryId);
custom[categoryId] = {
name: category.name || category.id!,
files: {},
};
for (const f of category.files) {
const fileRootPath = join(dir, f.path);
const extension = extname(f.path);
const fileId = f.id ?? basename(f.path, extension);
const fileData = readFileSync(fileRootPath, 'utf-8');
custom[categoryId]!.files[fileId] = {
name: f.name,
type: extension.toLowerCase().replace(/^\./, ''),
content: fileData,
path: relative(options.root, fileRootPath).replace(/\\/g, '/'),
};
export function build({ input, custom: customDocs, root, output, typescript }: CLIOptions) {
let data: (RootTypes & ChildTypes)[] | DeclarationReflection[] = [];
if (typescript) {
console.log('Parsing Typescript in source files...');
const app = new Application();
app.options.addReader(new TSConfigReader());
app.bootstrap({ entryPoints: input });
const project = app.convert();
if (project) {
// @ts-expect-error
data = app.serializer.toObject(project).children!;
console.log(`${data.length} items parsed.`);
}
} else {
console.log('Parsing JSDocs in source files...');
data = jsdoc2md.getTemplateDataSync({ files: input }) as (RootTypes & ChildTypes)[];
console.log(`${data.length} JSDoc items parsed.`);
}
const fileCount = Object.keys(custom)
.map((k) => Object.keys(custom[k]!))
.reduce((prev, c) => prev + c.length, 0);
const categoryCount = Object.keys(custom).length;
console.log(
`${fileCount} custom docs file${fileCount === 1 ? '' : 's'} in ` +
`${categoryCount} categor${categoryCount === 1 ? 'y' : 'ies'} loaded.`,
);
}
const custom: Record<string, CustomDocs> = {};
if (customDocs) {
console.log('Loading custom docs files...');
const customDir = dirname(customDocs);
const file = readFileSync(customDocs, 'utf-8');
const data = JSON.parse(file) as CustomFiles[];
console.log(`Serializing documentation with format version ${Documentation.FORMAT_VERSION}...`);
const docs = new Documentation(data, options, custom);
for (const category of data) {
const categoryId = category.id ?? category.name.toLowerCase();
const dir = join(customDir, category.path ?? categoryId);
custom[categoryId] = {
name: category.name || category.id!,
files: {},
};
if (options.output) {
console.log(`Writing to ${options.output}...`);
writeFileSync(options.output, JSON.stringify(docs.serialize()));
for (const f of category.files) {
const fileRootPath = join(dir, f.path);
const extension = extname(f.path);
const fileId = f.id ?? basename(f.path, extension);
const fileData = readFileSync(fileRootPath, 'utf-8');
custom[categoryId]!.files[fileId] = {
name: f.name,
type: extension.toLowerCase().replace(/^\./, ''),
content: fileData,
path: relative(root, fileRootPath).replace(/\\/g, '/'),
};
}
}
const fileCount = Object.keys(custom)
.map((k) => Object.keys(custom[k]!))
.reduce((prev, c) => prev + c.length, 0);
const categoryCount = Object.keys(custom).length;
console.log(
`${fileCount} custom docs file${fileCount === 1 ? '' : 's'} in ` +
`${categoryCount} categor${categoryCount === 1 ? 'y' : 'ies'} loaded.`,
);
}
console.log(`Serializing documentation with format version ${Documentation.FORMAT_VERSION}...`);
const docs = new Documentation(data, { input, custom: customDocs, root, output, typescript }, custom);
if (output) {
console.log(`Writing to ${output}...`);
writeFileSync(output, JSON.stringify(docs.serialize()));
}
console.log('Done!');
}
console.log('Done!');

View File

@@ -1,7 +1,7 @@
import type { Type } from './index.js';
export interface Return {
type: Type;
type: Required<Type>;
nullable?: boolean;
description?: string;
}

View File

@@ -1,3 +1,3 @@
export interface Type {
names?: string[];
names?: string[] | undefined;
}

View File

@@ -1,7 +1,7 @@
import type { Type } from './index.js';
export interface VarType extends Type {
type?: Required<Type>;
description?: string;
nullable?: boolean;
type?: Required<Type> | undefined;
description?: string | undefined;
nullable?: boolean | undefined;
}

View File

@@ -1,5 +1,4 @@
import { parse } from 'node:path';
import { Collection } from '@discordjs/collection';
import type { DeclarationReflection } from 'typedoc';
import { DocumentedConstructor } from './constructor.js';
import { DocumentedEvent } from './event.js';
@@ -12,11 +11,11 @@ import type { Class, Config } from '../interfaces/index.js';
import { parseType } from '../util/parseType.js';
export class DocumentedClass extends DocumentedItem<Class | DeclarationReflection> {
public readonly props = new Collection<string, DocumentedMember>();
public readonly props = new Map<string, DocumentedMember>();
public readonly methods = new Collection<string, DocumentedMethod>();
public readonly methods = new Map<string, DocumentedMethod>();
public readonly events = new Collection<string, DocumentedEvent>();
public readonly events = new Map<string, DocumentedEvent>();
public construct: DocumentedConstructor | null = null;
@@ -120,9 +119,9 @@ export class DocumentedClass extends DocumentedItem<Class | DeclarationReflectio
.trim() ?? true
: undefined,
construct: this.construct?.serialize(),
props: this.props.size ? this.props.map((p) => p.serialize()) : undefined,
methods: this.methods.size ? this.methods.map((m) => m.serialize()) : undefined,
events: this.events.size ? this.events.map((e) => e.serialize()) : undefined,
props: this.props.size ? [...this.props.values()].map((p) => p.serialize()) : undefined,
methods: this.methods.size ? [...this.methods.values()].map((m) => m.serialize()) : undefined,
events: this.events.size ? [...this.events.values()].map((e) => e.serialize()) : undefined,
meta,
};
}
@@ -138,9 +137,9 @@ export class DocumentedClass extends DocumentedItem<Class | DeclarationReflectio
abstract: data.virtual,
deprecated: data.deprecated,
construct: this.construct?.serialize(),
props: this.props.size ? this.props.map((p) => p.serialize()) : undefined,
methods: this.methods.size ? this.methods.map((m) => m.serialize()) : undefined,
events: this.events.size ? this.events.map((e) => e.serialize()) : undefined,
props: this.props.size ? [...this.props.values()].map((p) => p.serialize()) : undefined,
methods: this.methods.size ? [...this.methods.values()].map((m) => m.serialize()) : undefined,
events: this.events.size ? [...this.events.values()].map((e) => e.serialize()) : undefined,
meta: new DocumentedItemMeta(data.meta, this.config).serialize(),
};
}

View File

@@ -4,8 +4,8 @@
"description": "Lightweight HTTP proxy for Discord's API, brought to you as a container 📦",
"scripts": {
"build": "unbuild",
"lint": "prettier --check . && eslint src --ext mjs,js,ts",
"format": "prettier --write . && eslint src --ext mjs,js,ts --fix",
"lint": "prettier --check . && TIMING=1 eslint src --ext mjs,js,ts",
"format": "prettier --write . && TIMING=1 eslint src --ext mjs,js,ts --fix",
"fmt": "yarn format",
"prepack": "yarn lint && yarn test && yarn build",
"changelog": "git cliff --prepend ./CHANGELOG.md -u -c ./cliff.toml -r ../../ --include-path 'packages/proxy-container/*'"
@@ -49,12 +49,18 @@
"tslib": "^2.4.0"
},
"devDependencies": {
"@types/node": "^16.11.47",
"eslint": "^8.21.0",
"@types/node": "^16.11.52",
"@typescript-eslint/eslint-plugin": "^5.33.1",
"@typescript-eslint/parser": "^5.33.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",
"prettier": "^2.7.1",
"rollup-plugin-typescript2": "0.32.1",
"rollup-plugin-typescript2": "^0.33.0",
"typescript": "^4.7.4",
"unbuild": "^0.8.4"
"unbuild": "^0.8.9"
},
"engines": {
"node": ">=16.9.0"

View File

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

View File

@@ -2,6 +2,40 @@
All notable changes to this project will be documented in this file.
# [@discordjs/proxy@1.1.0](https://github.com/discordjs/discord.js/tree/@discordjs/proxy@1.1.0) - (2022-08-22)
## Bug Fixes
- **proxyRequests:** Typo in error message (#8537) ([dd44e8b](https://github.com/discordjs/discord.js/commit/dd44e8b6ec141e630af4543bd3babcce39aa2887))
- **proxy-container:** Proper deps (#8120) ([17867f9](https://github.com/discordjs/discord.js/commit/17867f9154d0dd16357f4ff29da641e23a33a9fa))
- **proxy:** Add docs script ([a45bef4](https://github.com/discordjs/discord.js/commit/a45bef4cad77dac1a4138fd0d52b769ce09b5678))
## Documentation
- Add codecov coverage badge to readmes (#8226) ([f6db285](https://github.com/discordjs/discord.js/commit/f6db285c073898a749fe4591cbd4463d1896daf5))
## Features
- **website:** Show `constructor` information (#8540) ([e42fd16](https://github.com/discordjs/discord.js/commit/e42fd1636973b10dd7ed6fb4280ee1a4a8f82007))
- Codecov (#8219) ([f10f4cd](https://github.com/discordjs/discord.js/commit/f10f4cdcd88ca6be7ec735ed3a415ba13da83db0))
- Proxy container (#8000) ([2681929](https://github.com/discordjs/discord.js/commit/2681929e4263032ad34a99ecb42465c320b271ba))
- **docgen:** Update typedoc ([b3346f4](https://github.com/discordjs/discord.js/commit/b3346f4b9b3d4f96443506643d4631dc1c6d7b21))
- Website (#8043) ([127931d](https://github.com/discordjs/discord.js/commit/127931d1df7a2a5c27923c2f2151dbf3824e50cc))
- **docgen:** Typescript support ([3279b40](https://github.com/discordjs/discord.js/commit/3279b40912e6aa61507bedb7db15a2b8668de44b))
- Docgen package (#8029) ([8b979c0](https://github.com/discordjs/discord.js/commit/8b979c0245c42fd824d8e98745ee869f5360fc86))
- 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/proxy (#7925) ([1ba2d2a](https://github.com/discordjs/discord.js/commit/1ba2d2a898613e5fcc119a97dce935f4db91162c))
## Refactor
- Docs design (#8487) ([4ab1d09](https://github.com/discordjs/discord.js/commit/4ab1d09997a18879a9eb9bda39df6f15aa22557e))
- Move all the config files to root (#8033) ([769ea0b](https://github.com/discordjs/discord.js/commit/769ea0bfe78c4f1d413c6b397c604ffe91e39c6a))
## Styling
- Cleanup tests and tsup configs ([6b8ef20](https://github.com/discordjs/discord.js/commit/6b8ef20cb3af5b5cfd176dd0aa0a1a1e98551629))
# [@discordjs/proxy@1.0.0](https://github.com/discordjs/discord.js/tree/@discordjs/proxy@1.1.0) - (2022-07-17)
## Bug Fixes

View File

@@ -1,12 +1,12 @@
{
"name": "@discordjs/proxy",
"version": "1.0.1",
"version": "1.1.0",
"description": "Tools for running an HTTP proxy for Discord's API",
"scripts": {
"test": "vitest run",
"build": "unbuild",
"lint": "prettier --check . && eslint src __tests__ --ext mjs,js,ts",
"format": "prettier --write . && eslint src __tests__ --ext mjs,js,ts --fix",
"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",
"fmt": "yarn format",
"docs": "downlevel-dts . docs --to=3.7 && docgen -i src/index.ts -c docs/index.json -o docs/docs.json --typescript && api-extractor run --local",
"prepack": "yarn lint && yarn test && yarn build",
@@ -56,23 +56,29 @@
"dependencies": {
"@discordjs/rest": "^1.0.0",
"tslib": "^2.4.0",
"undici": "^5.8.2"
"undici": "^5.9.1"
},
"devDependencies": {
"@discordjs/docgen": "workspace:^",
"@favware/cliff-jumper": "^1.8.6",
"@microsoft/api-extractor": "^7.29.2",
"@types/node": "^16.11.47",
"@favware/cliff-jumper": "^1.8.7",
"@microsoft/api-extractor": "^7.29.3",
"@types/node": "^16.11.52",
"@types/supertest": "^2.0.12",
"c8": "^7.12.0",
"@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.21.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",
"prettier": "^2.7.1",
"rollup-plugin-typescript2": "0.32.1",
"rollup-plugin-typescript2": "^0.33.0",
"supertest": "^6.2.4",
"typescript": "^4.7.4",
"unbuild": "^0.8.4",
"vitest": "^0.21.1"
"unbuild": "^0.8.9",
"vitest": "^0.22.1"
},
"engines": {
"node": ">=16.9.0"

View File

@@ -19,7 +19,7 @@ export function proxyRequests(rest: REST): RequestHandler {
if (!method || !url) {
throw new TypeError(
'Invalid request. Missing method and/or url, implying that this is not a Server IncomingMesage',
'Invalid request. Missing method and/or url, implying that this is not a Server IncomingMessage',
);
}

View File

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

View File

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

View File

@@ -2,6 +2,18 @@
All notable changes to this project will be documented in this file.
# [@discordjs/rest@1.1.0](https://github.com/discordjs/discord.js/compare/@discordjs/rest@1.0.1...@discordjs/rest@1.1.0) - (2022-08-22)
## Features
- **website:** Show `constructor` information (#8540) ([e42fd16](https://github.com/discordjs/discord.js/commit/e42fd1636973b10dd7ed6fb4280ee1a4a8f82007))
- **website:** Render `@defaultValue` blocks (#8527) ([8028813](https://github.com/discordjs/discord.js/commit/8028813825e7708915ea892760c1003afd60df2f))
- **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/rest@0.6.0](https://github.com/discordjs/discord.js/compare/@discordjs/rest@0.5.0...@discordjs/rest@0.6.0) - (2022-07-17)
## Documentation

View File

@@ -1,12 +1,12 @@
{
"name": "@discordjs/rest",
"version": "1.0.1",
"version": "1.1.0",
"description": "The REST API for discord.js",
"scripts": {
"test": "vitest run",
"build": "unbuild",
"lint": "prettier --check . && eslint src __tests__ --ext mjs,js,ts",
"format": "prettier --write . && eslint src __tests__ --ext mjs,js,ts --fix",
"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",
"fmt": "yarn format",
"docs": "downlevel-dts . docs --to=3.7 && docgen -i src/index.ts -c docs/index.json -o docs/docs.json --typescript && api-extractor run --local",
"prepack": "yarn lint && yarn test && yarn build",
@@ -53,26 +53,33 @@
"homepage": "https://discord.js.org",
"dependencies": {
"@discordjs/collection": "workspace:^",
"@sapphire/async-queue": "^1.4.0",
"@sapphire/async-queue": "^1.5.0",
"@sapphire/snowflake": "^3.2.2",
"discord-api-types": "^0.36.3",
"discord-api-types": "^0.37.3",
"file-type": "^17.1.6",
"tslib": "^2.4.0",
"undici": "^5.8.2"
"undici": "^5.9.1"
},
"devDependencies": {
"@discordjs/docgen": "workspace:^",
"@favware/cliff-jumper": "^1.8.6",
"@microsoft/api-extractor": "^7.29.2",
"@types/node": "^16.11.47",
"c8": "^7.12.0",
"@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.21.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",
"prettier": "^2.7.1",
"rollup-plugin-typescript2": "0.32.1",
"rollup-plugin-typescript2": "^0.33.0",
"typescript": "^4.7.4",
"unbuild": "^0.8.4",
"vitest": "^0.21.1"
"unbuild": "^0.8.9",
"vitest": "^0.22.1"
},
"engines": {
"node": ">=16.9.0"

View File

@@ -15,7 +15,7 @@ export interface BaseImageURLOptions {
/**
* The extension to use for the image URL
*
* @default 'webp'
* @defaultValue `'webp'`
*/
extension?: ImageExtension;
/**
@@ -41,7 +41,7 @@ export interface MakeURLOptions {
/**
* The extension to use for the image URL
*
* @default 'webp'
* @defaultValue `'webp'`
*/
extension?: string | undefined;
/**

View File

@@ -25,45 +25,45 @@ export interface RESTOptions {
agent: Dispatcher;
/**
* The base api path, without version
* @default 'https://discord.com/api'
* @defaultValue `'https://discord.com/api'`
*/
api: string;
/**
* The authorization prefix to use for requests, useful if you want to use
* bearer tokens
*
* @default 'Bot'
* @defaultValue `'Bot'`
*/
authPrefix: 'Bot' | 'Bearer';
/**
* The cdn path
*
* @default 'https://cdn.discordapp.com'
* @defaultValue 'https://cdn.discordapp.com'
*/
cdn: string;
/**
* Additional headers to send for all API requests
*
* @default {}
* @defaultValue `{}`
*/
headers: Record<string, string>;
/**
* The number of invalid REST requests (those that return 401, 403, or 429) in a 10 minute window between emitted warnings (0 for no warnings).
* That is, if set to 500, warnings will be emitted at invalid request number 500, 1000, 1500, and so on.
*
* @default 0
* @defaultValue `0`
*/
invalidRequestWarningInterval: number;
/**
* How many requests to allow sending per second (Infinity for unlimited, 50 for the standard global limit used by Discord)
*
* @default 50
* @defaultValue `50`
*/
globalRequestsPerSecond: number;
/**
* The extra offset to add to rate limits in milliseconds
*
* @default 50
* @defaultValue `50`
*/
offset: number;
/**
@@ -72,50 +72,50 @@ export interface RESTOptions {
* (e.g. `/channels` to match any route starting with `/channels` such as `/channels/:id/messages`)
* for which to throw {@link RateLimitError}s. All other request routes will be queued normally
*
* @default null
* @defaultValue `null`
*/
rejectOnRateLimit: string[] | RateLimitQueueFilter | null;
/**
* The number of retries for errors with the 500 code, or errors
* that timeout
*
* @default 3
* @defaultValue `3`
*/
retries: number;
/**
* The time to wait in milliseconds before a request is aborted
*
* @default 15_000
* @defaultValue `15_000`
*/
timeout: number;
/**
* Extra information to add to the user agent
*
* @default `Node.js ${process.version}`
* @defaultValue `Node.js ${process.version}`
*/
userAgentAppendix: string;
/**
* The version of the API to use
*
* @default '10'
* @defaultValue `'10'`
*/
version: string;
/**
* The amount of time in milliseconds that passes between each hash sweep. (defaults to 4h)
*
* @default 14_400_000
* @defaultValue `14_400_000`
*/
hashSweepInterval: number;
/**
* The maximum amount of time a hash can exist in milliseconds without being hit with a request (defaults to 24h)
*
* @default 86_400_000
* @defaultValue `86_400_000`
*/
hashLifetime: number;
/**
* The amount of time in milliseconds that passes between each hash sweep. (defaults to 1h)
*
* @default 3_600_000
* @defaultValue `3_600_000`
*/
handlerSweepInterval: number;
}

View File

@@ -50,13 +50,13 @@ export interface RequestData {
/**
* If this request needs the `Authorization` header
*
* @default true
* @defaultValue `true`
*/
auth?: boolean;
/**
* The authorization prefix to use for this request, useful if you use this with bearer tokens
*
* @default 'Bot'
* @defaultValue `'Bot'`
*/
authPrefix?: 'Bot' | 'Bearer';
/**
@@ -65,7 +65,7 @@ export interface RequestData {
*/
body?: BodyInit | unknown;
/**
* The {@link https://undici.nodejs.org/#/docs/api/Agent Agent} to use for the request.
* The {@link https://undici.nodejs.org/#/docs/api/Agent | Agent} to use for the request.
*/
dispatcher?: Agent;
/**
@@ -92,7 +92,7 @@ export interface RequestData {
/**
* If this request should be versioned
*
* @default true
* @defaultValue `true`
*/
versioned?: boolean;
}
@@ -174,7 +174,7 @@ export interface RequestManager {
*/
export class RequestManager extends EventEmitter {
/**
* The {@link https://undici.nodejs.org/#/docs/api/Agent Agent} for all requests
* The {@link https://undici.nodejs.org/#/docs/api/Agent | Agent} for all requests
* performed by this manager.
*/
public agent: Dispatcher | null = null;
@@ -342,7 +342,7 @@ export class RequestManager extends EventEmitter {
* @param hash - The hash for the route
* @param majorParameter - The major parameter for this handler
*
* @private
* @internal
*/
private createHandler(hash: string, majorParameter: string) {
// Create the async request queue to handle requests
@@ -487,7 +487,7 @@ export class RequestManager extends EventEmitter {
* @param endpoint - The raw endpoint to generalize
* @param method - The HTTP method this endpoint is called without
*
* @private
* @internal
*/
private static generateRouteData(endpoint: RouteLike, method: RequestMethod): RouteData {
const majorIdMatch = /^\/(?:channels|guilds|webhooks)\/(\d{16,19})/.exec(endpoint);

View File

@@ -3,13 +3,27 @@ import type { RequestOptions } from '../REST';
import type { HandlerRequestData, RouteData } from '../RequestManager';
export interface IHandler {
/**
* Queues a request to be sent
*
* @param routeId - The generalized api route with literal ids for major parameters
* @param url - The url to do the request on
* @param options - All the information needed to make a request
* @param requestData - Extra data from the user's request needed for errors and additional processing
*/
queueRequest: (
routeId: RouteData,
url: string,
options: RequestOptions,
requestData: HandlerRequestData,
) => Promise<Dispatcher.ResponseData>;
/**
* If the bucket is currently inactive (no pending requests)
*/
// eslint-disable-next-line @typescript-eslint/method-signature-style -- This is meant to be a getter returning a bool
get inactive(): boolean;
/**
* The unique id of the handler
*/
readonly id: string;
}

View File

@@ -30,7 +30,7 @@ const enum QueueType {
*/
export class SequentialHandler implements IHandler {
/**
* The unique id of the handler
* {@inheritDoc IHandler.id}
*/
public readonly id: string;
@@ -87,7 +87,7 @@ export class SequentialHandler implements IHandler {
}
/**
* If the bucket is currently inactive (no pending requests)
* {@inheritDoc IHandler.inactive}
*/
public get inactive(): boolean {
return (
@@ -161,12 +161,7 @@ export class SequentialHandler implements IHandler {
}
/**
* Queues a request to be sent
*
* @param routeId - The generalized api route with literal ids for major parameters
* @param url - The url to do the request on
* @param options - All the information needed to make a request
* @param requestData - Extra data from the user's request needed for errors and additional processing
* {@inheritDoc IHandler.queueRequest}
*/
public async queueRequest(
routeId: RouteData,

View File

@@ -6,8 +6,8 @@
"scripts": {
"test": "vitest run",
"build": "unbuild",
"lint": "prettier --check . && eslint src --ext mjs,js,ts",
"format": "prettier --write . && eslint src --ext mjs,js,ts --fix",
"lint": "prettier --check . && TIMING=1 eslint src --ext mjs,js,ts",
"format": "prettier --write . && TIMING=1 eslint src --ext mjs,js,ts --fix",
"fmt": "yarn format"
},
"main": "./dist/index.cjs",
@@ -48,14 +48,20 @@
"tslib": "^2.4.0"
},
"devDependencies": {
"@types/node": "^16.11.47",
"c8": "^7.12.0",
"eslint": "^8.21.0",
"@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",
"prettier": "^2.7.1",
"rollup-plugin-typescript2": "0.32.1",
"rollup-plugin-typescript2": "^0.33.0",
"typescript": "^4.7.4",
"unbuild": "^0.8.4",
"vitest": "^0.21.1"
"unbuild": "^0.8.9",
"vitest": "^0.22.1"
},
"engines": {
"node": ">=16.9.0"

View File

@@ -1,5 +1,9 @@
{
"extends": "../../.eslintrc.json",
"plugins": ["eslint-plugin-tsdoc"],
"rules": {
"tsdoc/syntax": "warn"
},
"parserOptions": {
"project": "./tsconfig.eslint.json",
"extraFileExtensions": [".mjs"]

View File

@@ -5,8 +5,8 @@
"scripts": {
"build": "unbuild",
"test": "jest --coverage",
"lint": "prettier --check . && eslint src __tests__ --ext mjs,js,ts",
"format": "prettier --write . && eslint src __tests__ --ext mjs,js,ts --fix",
"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",
"fmt": "yarn format",
"docs": "downlevel-dts . docs --to=3.7 && docgen -i src/index.ts -c docs/index.json -o docs/docs.json --typescript && api-extractor run --local",
"prepack": "yarn lint && yarn test && yarn build",
@@ -53,7 +53,7 @@
"homepage": "https://discord.js.org",
"dependencies": {
"@types/ws": "^8.5.3",
"discord-api-types": "^0.36.3",
"discord-api-types": "^0.37.3",
"prism-media": "^1.3.4",
"tslib": "^2.4.0",
"ws": "^8.8.1"
@@ -63,21 +63,27 @@
"@babel/preset-env": "^7.18.10",
"@babel/preset-typescript": "^7.18.6",
"@discordjs/docgen": "workspace:^",
"@discordjs/scripts": "workspace:^",
"@favware/cliff-jumper": "^1.8.6",
"@microsoft/api-extractor": "^7.29.2",
"@types/jest": "^28.1.6",
"@types/node": "^16.11.47",
"@favware/cliff-jumper": "^1.8.7",
"@microsoft/api-extractor": "^7.29.3",
"@types/jest": "^28.1.7",
"@types/node": "^16.11.52",
"@typescript-eslint/eslint-plugin": "^5.33.1",
"@typescript-eslint/parser": "^5.33.1",
"downlevel-dts": "^0.10.0",
"eslint": "^8.21.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",
"jest": "^28.1.3",
"jest-websocket-mock": "^2.4.0",
"mock-socket": "^9.1.5",
"prettier": "^2.7.1",
"rollup-plugin-typescript2": "0.32.1",
"rollup-plugin-typescript2": "^0.33.0",
"tweetnacl": "^1.0.3",
"typescript": "^4.7.4",
"unbuild": "^0.8.4"
"unbuild": "^0.8.9"
},
"engines": {
"node": ">=16.9.0"

View File

@@ -53,7 +53,7 @@ export enum VoiceConnectionStatus {
*/
export interface VoiceConnectionSignallingState {
status: VoiceConnectionStatus.Signalling;
subscription?: PlayerSubscription;
subscription?: PlayerSubscription | undefined;
adapter: DiscordGatewayAdapterImplementerMethods;
}
@@ -88,7 +88,7 @@ export enum VoiceConnectionDisconnectReason {
*/
export interface VoiceConnectionDisconnectedBaseState {
status: VoiceConnectionStatus.Disconnected;
subscription?: PlayerSubscription;
subscription?: PlayerSubscription | undefined;
adapter: DiscordGatewayAdapterImplementerMethods;
}
@@ -128,7 +128,7 @@ export type VoiceConnectionDisconnectedState =
export interface VoiceConnectionConnectingState {
status: VoiceConnectionStatus.Connecting;
networking: Networking;
subscription?: PlayerSubscription;
subscription?: PlayerSubscription | undefined;
adapter: DiscordGatewayAdapterImplementerMethods;
}
@@ -139,7 +139,7 @@ export interface VoiceConnectionConnectingState {
export interface VoiceConnectionReadyState {
status: VoiceConnectionStatus.Ready;
networking: Networking;
subscription?: PlayerSubscription;
subscription?: PlayerSubscription | undefined;
adapter: DiscordGatewayAdapterImplementerMethods;
}
@@ -165,22 +165,22 @@ export type VoiceConnectionState =
export interface VoiceConnection extends EventEmitter {
/**
* Emitted when there is an error emitted from the voice connection
* @event
* @eventProperty
*/
on(event: 'error', listener: (error: Error) => void): this;
/**
* Emitted debugging information about the voice connection
* @event
* @eventProperty
*/
on(event: 'debug', listener: (message: string) => void): this;
/**
* Emitted when the state of the voice connection changes
* @event
* @eventProperty
*/
on(event: 'stateChange', listener: (oldState: VoiceConnectionState, newState: VoiceConnectionState) => void): this;
/**
* Emitted when the state of the voice connection changes to a specific status
* @event
* @eventProperty
*/
on<T extends VoiceConnectionStatus>(
event: T,
@@ -688,7 +688,7 @@ export class VoiceConnection extends EventEmitter {
*
* @param subscription - The removed subscription
*/
private onSubscriptionRemoved(subscription: PlayerSubscription) {
protected onSubscriptionRemoved(subscription: PlayerSubscription) {
if (this.state.status !== VoiceConnectionStatus.Destroyed && this.state.subscription === subscription) {
this.state = {
...this.state,

View File

@@ -154,27 +154,27 @@ export type AudioPlayerState =
export interface AudioPlayer extends EventEmitter {
/**
* Emitted when there is an error emitted from the audio resource played by the audio player
* @event
* @eventProperty
*/
on(event: 'error', listener: (error: AudioPlayerError) => void): this;
/**
* Emitted debugging information about the audio player
* @event
* @eventProperty
*/
on(event: 'debug', listener: (message: string) => void): this;
/**
* Emitted when the state of the audio player changes
* @event
* @eventProperty
*/
on(event: 'stateChange', listener: (oldState: AudioPlayerState, newState: AudioPlayerState) => void): this;
/**
* Emitted when the audio player is subscribed to a voice connection
* @event
* @eventProperty
*/
on(event: 'subscribe' | 'unsubscribe', listener: (subscription: PlayerSubscription) => void): this;
/**
* Emitted when the status of state changes to a specific status
* @event
* @eventProperty
*/
on<T extends AudioPlayerStatus>(
event: T,

View File

@@ -13,6 +13,6 @@ export class AudioPlayerError extends Error {
super(error.message);
this.resource = resource;
this.name = error.name;
this.stack = error.stack;
this.stack = error.stack!;
}
}

View File

@@ -7,7 +7,7 @@ import { noop } from '../util/util';
/**
* Options that are set when creating a new audio resource.
*
* @template T - the type for the metadata (if any) of the audio resource
* @typeParam T - the type for the metadata (if any) of the audio resource
*/
export interface CreateAudioResourceOptions<T> {
/**
@@ -38,7 +38,7 @@ export interface CreateAudioResourceOptions<T> {
/**
* Represents an audio resource that can be played by an audio player.
*
* @template T - the type for the metadata (if any) of the audio resource
* @typeParam T - the type for the metadata (if any) of the audio resource
*/
export class AudioResource<T = unknown> {
/**
@@ -73,7 +73,7 @@ export class AudioResource<T = unknown> {
/**
* The audio player that the resource is subscribed to, if any.
*/
public audioPlayer?: AudioPlayer;
public audioPlayer?: AudioPlayer | undefined;
/**
* The playback duration of this audio resource, given in milliseconds.
@@ -204,7 +204,7 @@ export function inferStreamType(stream: Readable): {
* @param input - The resource to play
* @param options - Configurable options for creating the resource
*
* @template T - the type for the metadata (if any) of the audio resource
* @typeParam T - the type for the metadata (if any) of the audio resource
*/
export function createAudioResource<T>(
input: string | Readable,
@@ -228,7 +228,7 @@ export function createAudioResource<T>(
* @param input - The resource to play
* @param options - Configurable options for creating the resource
*
* @template T - the type for the metadata (if any) of the audio resource
* @typeParam T - the type for the metadata (if any) of the audio resource
*/
export function createAudioResource<T extends null | undefined>(
input: string | Readable,
@@ -248,7 +248,7 @@ export function createAudioResource<T extends null | undefined>(
* @param input - The resource to play
* @param options - Configurable options for creating the resource
*
* @template T - the type for the metadata (if any) of the audio resource
* @typeParam T - the type for the metadata (if any) of the audio resource
*/
export function createAudioResource<T>(
input: string | Readable,

View File

@@ -10,7 +10,7 @@ export interface CreateVoiceConnectionOptions {
* If true, debug messages will be enabled for the voice connection and its
* related components. Defaults to false.
*/
debug?: boolean;
debug?: boolean | undefined;
adapterCreator: DiscordGatewayAdapterCreator;
}

View File

@@ -81,7 +81,7 @@ export interface NetworkingReadyState {
udp: VoiceUDPSocket;
connectionOptions: ConnectionOptions;
connectionData: ConnectionData;
preparedPacket?: Buffer;
preparedPacket?: Buffer | undefined;
}
/**
@@ -94,7 +94,7 @@ export interface NetworkingResumingState {
udp: VoiceUDPSocket;
connectionOptions: ConnectionOptions;
connectionData: ConnectionData;
preparedPacket?: Buffer;
preparedPacket?: Buffer | undefined;
}
/**
@@ -155,7 +155,7 @@ export interface Networking extends EventEmitter {
/**
* Debug event for Networking.
*
* @event
* @eventProperty
*/
on(event: 'debug', listener: (message: string) => void): this;
on(event: 'error', listener: (error: Error) => void): this;

View File

@@ -10,13 +10,13 @@ export interface VoiceWebSocket extends EventEmitter {
/**
* Debug event for VoiceWebSocket.
*
* @event
* @eventProperty
*/
on(event: 'debug', listener: (message: string) => void): this;
/**
* Packet event.
*
* @event
* @eventProperty
*/
on(event: 'packet', listener: (packet: any) => void): this;
}

View File

@@ -4,13 +4,13 @@ import { EventEmitter } from 'node:events';
export interface SpeakingMap extends EventEmitter {
/**
* Emitted when a user starts speaking.
* @event
* @eventProperty
*/
on(event: 'start', listener: (userId: string) => void): this;
/**
* Emitted when a user ends speaking.
* @event
* @eventProperty
*/
on(event: 'end', listener: (userId: string) => void): this;
}

View File

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

View File

@@ -0,0 +1 @@
NEXT_PUBLIC_LOCAL_DEV=true

View File

@@ -5,15 +5,16 @@
"private": true,
"scripts": {
"test": "vitest run",
"build": "yarn build:css && yarn build:next",
"build:local": "yarn run --top-level docs --force && yarn build:prod",
"build:prod": "yarn build:css && yarn build:next",
"build:next": "next build",
"build:css": "yarn generate:css",
"dev": "concurrently 'yarn dev:css' 'yarn dev:next'",
"dev": "yarn run --top-level docs && concurrently 'yarn dev:css' 'yarn dev:next'",
"dev:next": "next dev",
"dev:css": "yarn generate:css --watch",
"generate:css": "unocss 'src/**/*.tsx' --out-file ./src/styles/unocss.css",
"lint": "prettier --check . && eslint src --ext mjs,js,ts,tsx",
"format": "prettier --write . && eslint src --ext mjs,js,ts,tsx --fix"
"lint": "prettier --check . && TIMING=1 eslint src --ext mjs,js,ts,tsx",
"format": "prettier --write . && TIMING=1 eslint src --ext mjs,js,ts,tsx --fix"
},
"main": "./dist/index.js",
"module": "./dist/index.mjs",
@@ -47,12 +48,18 @@
},
"homepage": "https://discord.js.org",
"dependencies": {
"@microsoft/api-extractor-model": "^7.23.0",
"@emotion/react": "^11.10.0",
"@emotion/server": "^11.10.0",
"@mantine/core": "^5.2.0",
"@mantine/hooks": "^5.2.0",
"@mantine/next": "^5.2.0",
"@mantine/nprogress": "^5.2.0",
"@mantine/spotlight": "^5.2.0",
"@microsoft/api-extractor-model": "^7.23.1",
"@microsoft/tsdoc": "0.14.1",
"@microsoft/tsdoc-config": "0.16.1",
"@vscode/codicons": "^0.0.32",
"framer-motion": "^7.0.1",
"next": "^12.2.4",
"next": "^12.2.5",
"react": "^18.2.0",
"react-dom": "^18.2.0",
"react-icons": "^4.4.0",
@@ -60,37 +67,32 @@
"sharp": "^0.30.7"
},
"devDependencies": {
"@testing-library/cypress": "^8.0.3",
"@testing-library/dom": "^8.17.1",
"@testing-library/jest-dom": "^5.16.5",
"@testing-library/react": "^13.3.0",
"@testing-library/user-event": "^14.4.3",
"@types/node": "^16.11.47",
"@types/node": "^16.11.52",
"@types/react-dom": "^18.0.6",
"@types/react-syntax-highlighter": "^15.5.4",
"@typescript-eslint/eslint-plugin": "^5.33.0",
"@typescript-eslint/parser": "^5.33.0",
"@unocss/cli": "^0.45.5",
"@unocss/preset-web-fonts": "^0.45.5",
"@unocss/reset": "^0.45.5",
"@vitejs/plugin-react": "^2.0.0",
"c8": "^7.12.0",
"@typescript-eslint/eslint-plugin": "^5.33.1",
"@typescript-eslint/parser": "^5.33.1",
"@unocss/cli": "^0.45.9",
"@unocss/preset-web-fonts": "^0.45.9",
"@unocss/reset": "^0.45.9",
"@vitejs/plugin-react": "^2.0.1",
"@vitest/coverage-c8": "^0.22.1",
"concurrently": "^7.3.0",
"cypress": "^10.4.0",
"eslint": "^8.21.0",
"eslint": "^8.22.0",
"eslint-config-marine": "^9.4.1",
"eslint-config-prettier": "^8.5.0",
"eslint-import-resolver-typescript": "^3.4.0",
"eslint-import-resolver-typescript": "^3.4.2",
"eslint-plugin-import": "^2.26.0",
"eslint-plugin-react": "^7.30.1",
"eslint-plugin-react-hooks": "^4.6.0",
"happy-dom": "^6.0.4",
"msw": "^0.44.2",
"prettier": "^2.7.1",
"typescript": "^4.7.4",
"unocss": "^0.45.5",
"vercel": "^27.4.0",
"vitest": "^0.21.1"
"unocss": "^0.45.9",
"vercel": "^28.1.0",
"vitest": "^0.22.1"
},
"engines": {
"node": ">=16.9.0"

View File

@@ -0,0 +1,381 @@
import {
ApiModel,
ApiDeclaredItem,
ApiPropertyItem,
ApiMethod,
ApiParameterListMixin,
ApiTypeParameterListMixin,
ApiClass,
ApiFunction,
ApiItemKind,
ApiTypeAlias,
ApiEnum,
ApiInterface,
ApiMethodSignature,
ApiPropertySignature,
ApiVariable,
ApiItem,
ApiConstructor,
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';
export interface ReferenceData {
name: string;
path: string;
}
export interface InheritanceData {
parentName: string;
path: string;
parentKey: string;
}
export interface ApiInheritableJSON {
inheritanceData: InheritanceData | null;
}
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;
path: string[];
}
export interface ApiPropertyItemJSON extends ApiItemJSON, ApiInheritableJSON {
propertyTypeTokens: TokenDocumentation[];
readonly: boolean;
optional: boolean;
}
export interface ApiTypeParameterListJSON {
typeParameters: ApiTypeParameterJSON[];
}
export interface ApiTypeParameterJSON {
name: string;
constraintTokens: TokenDocumentation[];
defaultTokens: TokenDocumentation[];
optional: boolean;
commentBlock: DocBlockJSON | null;
}
export interface ApiParameterListJSON {
parameters: ApiParameterJSON[];
}
export interface ApiMethodSignatureJSON
extends ApiItemJSON,
ApiTypeParameterListJSON,
ApiParameterListJSON,
ApiInheritableJSON {
returnTypeTokens: TokenDocumentation[];
optional: boolean;
overloadIndex: number;
}
export interface ApiMethodJSON extends ApiMethodSignatureJSON {
static: boolean;
visibility: Visibility;
}
export interface ApiParameterJSON {
name: string;
isOptional: boolean;
tokens: TokenDocumentation[];
paramCommentBlock: DocBlockJSON | null;
}
export interface ApiClassJSON extends ApiItemJSON, ApiTypeParameterListJSON {
constructor: ApiConstructorJSON | null;
properties: ApiPropertyItemJSON[];
methods: ApiMethodJSON[];
extendsTokens: TokenDocumentation[];
implementsTokens: TokenDocumentation[][];
}
export interface ApiTypeAliasJSON extends ApiItemJSON, ApiTypeParameterListJSON {
typeTokens: TokenDocumentation[];
}
export interface EnumMemberData {
name: string;
initializerTokens: TokenDocumentation[];
summary: DocNodeContainerJSON | null;
}
export interface ApiEnumJSON extends ApiItemJSON {
members: EnumMemberData[];
}
export interface ApiInterfaceJSON extends ApiItemJSON, ApiTypeParameterListJSON {
properties: ApiPropertyItemJSON[];
methods: ApiMethodSignatureJSON[];
extendsTokens: TokenDocumentation[][] | null;
}
export interface ApiVariableJSON extends ApiItemJSON {
typeTokens: TokenDocumentation[];
readonly: boolean;
}
export interface ApiFunctionJSON extends ApiItemJSON, ApiTypeParameterListJSON, ApiParameterListJSON {
returnTypeTokens: TokenDocumentation[];
overloadIndex: number;
}
export interface ApiConstructorJSON extends ApiItemJSON, ApiParameterListJSON {
protected: boolean;
}
// eslint-disable-next-line @typescript-eslint/no-extraneous-class
export class ApiNodeJSONEncoder {
public static encode(model: ApiModel, node: ApiItem) {
if (!(node instanceof ApiDeclaredItem)) {
throw new Error(`Cannot serialize node of type ${node.kind}`);
}
switch (node.kind) {
case ApiItemKind.Class:
return this.encodeClass(model, node as ApiClass);
case ApiItemKind.Function:
return this.encodeFunction(model, node as ApiFunction);
case ApiItemKind.Interface:
return this.encodeInterface(model, node as ApiInterface);
case ApiItemKind.TypeAlias:
return this.encodeTypeAlias(model, node as ApiTypeAlias);
case ApiItemKind.Enum:
return this.encodeEnum(model, node as ApiEnum);
case ApiItemKind.Variable:
return this.encodeVariable(model, node as ApiVariable);
default:
throw new Error(`Unknown API item kind: ${node.kind}`);
}
}
public static encodeItem(model: ApiModel, item: ApiDeclaredItem): ApiItemJSON {
const path = [];
for (const _item of item.getHierarchy()) {
switch (_item.kind) {
case 'None':
case 'EntryPoint':
case 'Model':
break;
default:
path.push(resolveName(_item));
}
}
return {
kind: item.kind,
name: resolveName(item),
referenceData: genReference(item),
excerpt: item.excerpt.text,
excerptTokens: item.excerpt.spannedTokens.map((token) => genToken(model, token)),
remarks: item.tsdocComment?.remarksBlock
? (createCommentNode(item.tsdocComment.remarksBlock, model, item.parent) as DocNodeContainerJSON)
: null,
summary: item.tsdocComment?.summarySection
? (createCommentNode(item.tsdocComment.summarySection, model, item.parent) as DocNodeContainerJSON)
: null,
deprecated: item.tsdocComment?.deprecatedBlock
? (createCommentNode(item.tsdocComment.deprecatedBlock, model, item.parent) as DocNodeContainerJSON)
: null,
path,
containerKey: item.containerKey,
comment: item.tsdocComment ? createCommentNode(item.tsdocComment, model, item.parent) : null,
};
}
public static encodeParameterList(
model: ApiModel,
item: ApiParameterListMixin & ApiDeclaredItem,
): { parameters: ApiParameterJSON[] } {
return {
parameters: item.parameters.map((param) => genParameter(model, param)),
};
}
public static encodeTypeParameterList(model: ApiModel, item: ApiTypeParameterListMixin & ApiDeclaredItem) {
return {
typeParameters: item.typeParameters.map((param) => generateTypeParamData(model, param, item.parent)),
};
}
public static encodeProperty(
model: ApiModel,
item: ApiPropertyItem,
parent: ApiItemContainerMixin,
): ApiPropertyItemJSON {
return {
...this.encodeItem(model, item),
...this.encodeInheritanceData(item, parent),
propertyTypeTokens: item.propertyTypeExcerpt.spannedTokens.map((token) => genToken(model, token)),
readonly: item.isReadonly,
optional: item.isOptional,
};
}
public static encodeInheritanceData(item: ApiDeclaredItem, parent: ApiItemContainerMixin): ApiInheritableJSON {
return {
inheritanceData:
item.parent && item.parent.containerKey !== parent.containerKey
? {
parentKey: item.parent.containerKey,
parentName: item.parent.displayName,
path: generatePath(item.parent.getHierarchy()),
}
: null,
};
}
public static encodeFunction(model: ApiModel, item: ApiFunction) {
return {
...this.encodeItem(model, item),
...this.encodeParameterList(model, item),
...this.encodeTypeParameterList(model, item),
returnTypeTokens: item.returnTypeExcerpt.spannedTokens.map((token) => genToken(model, token)),
overloadIndex: item.overloadIndex,
};
}
public static encodeMethodSignature(
model: ApiModel,
item: ApiMethodSignature,
parent: ApiItemContainerMixin,
): ApiMethodSignatureJSON {
return {
...this.encodeFunction(model, item),
...this.encodeInheritanceData(item, parent),
optional: item.isOptional,
};
}
public static encodeMethod(model: ApiModel, item: ApiMethod, parent: ApiItemContainerMixin): ApiMethodJSON {
return {
...this.encodeMethodSignature(model, item, parent),
static: item.isStatic,
visibility: item.isProtected ? Visibility.Protected : Visibility.Public,
};
}
public static encodeClass(model: ApiModel, item: ApiClass): ApiClassJSON {
const extendsExcerpt = item.extendsType?.excerpt;
const methods: ApiMethodJSON[] = [];
const properties: ApiPropertyItemJSON[] = [];
let constructor: ApiConstructor | undefined;
for (const member of item.findMembersWithInheritance().items) {
switch (member.kind) {
case ApiItemKind.Method:
methods.push(this.encodeMethod(model, member as ApiMethod, item));
break;
case ApiItemKind.Property:
properties.push(this.encodeProperty(model, member as ApiPropertyItem, item));
break;
case ApiItemKind.Constructor:
constructor = member as ApiConstructor;
break;
default:
break;
}
}
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)) : [],
implementsTokens: item.implementsTypes.map((excerpt) =>
excerpt.excerpt.spannedTokens.map((token) => genToken(model, token)),
),
methods,
properties,
};
}
public static encodeTypeAlias(model: ApiModel, item: ApiTypeAlias): ApiTypeAliasJSON {
return {
...this.encodeItem(model, item),
...this.encodeTypeParameterList(model, item),
typeTokens: item.typeExcerpt.spannedTokens.map((token) => genToken(model, token)),
};
}
public static encodeEnum(model: ApiModel, item: ApiEnum): ApiEnumJSON {
return {
...this.encodeItem(model, item),
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,
})),
};
}
public static encodeInterface(model: ApiModel, item: ApiInterface): 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));
break;
case ApiItemKind.PropertySignature:
properties.push(this.encodeProperty(model, member as ApiPropertySignature, item));
break;
default:
break;
}
}
return {
...this.encodeItem(model, item),
...this.encodeTypeParameterList(model, item),
extendsTokens: item.extendsTypes.map((excerpt) =>
excerpt.excerpt.spannedTokens.map((token) => genToken(model, token)),
),
methods,
properties,
};
}
public static encodeVariable(model: ApiModel, item: ApiVariable): ApiVariableJSON {
return {
...this.encodeItem(model, item),
typeTokens: item.variableTypeExcerpt.spannedTokens.map((token) => genToken(model, token)),
readonly: item.isReadonly,
};
}
public static encodeConstructor(model: ApiModel, item: ApiConstructor): ApiConstructorJSON {
return {
...this.encodeItem(model, item),
...this.encodeParameterList(model, item),
protected: item.isProtected,
};
}
}

View File

@@ -1,55 +0,0 @@
import {
type ApiClass,
type ApiModel,
ApiItemKind,
type ApiMethod,
type ApiPropertyItem,
} from '@microsoft/api-extractor-model';
import { DocItem } from './DocItem';
import { DocMethod } from './DocMethod';
import { DocProperty } from './DocProperty';
import { TypeParameterMixin } from './TypeParameterMixin';
import { type TokenDocumentation, genToken } from '~/util/parse.server';
export class DocClass extends TypeParameterMixin(DocItem<ApiClass>) {
public readonly extendsTokens: TokenDocumentation[] | null;
public readonly implementsTokens: TokenDocumentation[][];
public readonly methods: DocMethod[] = [];
public readonly properties: DocProperty[] = [];
public constructor(model: ApiModel, item: ApiClass) {
super(model, item);
const extendsExcerpt = item.extendsType?.excerpt;
this.extendsTokens = extendsExcerpt
? extendsExcerpt.spannedTokens.map((token) => genToken(this.model, token))
: null;
this.implementsTokens = item.implementsTypes.map((excerpt) =>
excerpt.excerpt.spannedTokens.map((token) => genToken(this.model, token)),
);
for (const member of item.members) {
switch (member.kind) {
case ApiItemKind.Method:
this.methods.push(new DocMethod(this.model, member as ApiMethod));
break;
case ApiItemKind.Property:
this.properties.push(new DocProperty(this.model, member as ApiPropertyItem));
break;
default:
break;
}
}
}
public override toJSON() {
return {
...super.toJSON(),
extendsTokens: this.extendsTokens,
implementsTokens: this.implementsTokens,
methods: this.methods.map((method) => method.toJSON()),
properties: this.properties.map((prop) => prop.toJSON()),
};
}
}

View File

@@ -1,33 +0,0 @@
import type { ApiEnum, ApiModel } from '@microsoft/api-extractor-model';
import { DocItem } from './DocItem';
import { CommentNodeContainer } from './comment/CommentNodeContainer';
import { genToken, TokenDocumentation } from '~/util/parse.server';
export interface EnumMemberData {
name: string;
initializerTokens: TokenDocumentation[];
summary: ReturnType<DocItem['toJSON']>['summary'];
}
export class DocEnum extends DocItem<ApiEnum> {
public readonly members: EnumMemberData[] = [];
public constructor(model: ApiModel, item: ApiEnum) {
super(model, item);
this.members = item.members.map((member) => ({
name: member.name,
initializerTokens: member.initializerExcerpt?.spannedTokens.map((token) => genToken(this.model, token)) ?? [],
summary: member.tsdocComment
? new CommentNodeContainer(member.tsdocComment.summarySection, model, member).toJSON()
: null,
}));
}
public override toJSON() {
return {
...super.toJSON(),
members: this.members,
};
}
}

View File

@@ -1,26 +0,0 @@
import type { ApiFunction, ApiModel, ApiParameterListMixin } from '@microsoft/api-extractor-model';
import { DocItem } from './DocItem';
import { TypeParameterMixin } from './TypeParameterMixin';
import { type TokenDocumentation, genToken, genParameter, ParameterDocumentation } from '~/util/parse.server';
export class DocFunction extends TypeParameterMixin(DocItem<ApiFunction>) {
public readonly returnTypeTokens: TokenDocumentation[];
public readonly overloadIndex: number;
public readonly parameters: ParameterDocumentation[];
public constructor(model: ApiModel, item: ApiFunction) {
super(model, item);
this.returnTypeTokens = item.returnTypeExcerpt.spannedTokens.map((token) => genToken(this.model, token));
this.overloadIndex = item.overloadIndex;
this.parameters = (item as ApiParameterListMixin).parameters.map((param) => genParameter(this.model, param));
}
public override toJSON() {
return {
...super.toJSON(),
parameters: this.parameters,
returnTypeTokens: this.returnTypeTokens,
overloadIndex: this.overloadIndex,
};
}
}

View File

@@ -1,48 +0,0 @@
import { DocItem } from './DocItem';
import { DocMethodSignature } from './DocMethodSignature';
import { DocProperty } from './DocProperty';
import { TypeParameterMixin } from './TypeParameterMixin';
import {
ApiInterface,
ApiItemKind,
ApiMethodSignature,
ApiModel,
ApiPropertySignature,
} from '~/util/api-extractor.server';
import { type TokenDocumentation, genToken } from '~/util/parse.server';
export class DocInterface extends TypeParameterMixin(DocItem<ApiInterface>) {
public readonly extendsTokens: TokenDocumentation[][] | null;
public readonly methods: DocMethodSignature[] = [];
public readonly properties: DocProperty[] = [];
public constructor(model: ApiModel, item: ApiInterface) {
super(model, item);
this.extendsTokens = item.extendsTypes.map((excerpt) =>
excerpt.excerpt.spannedTokens.map((token) => genToken(this.model, token)),
);
for (const member of item.members) {
switch (member.kind) {
case ApiItemKind.MethodSignature:
this.methods.push(new DocMethodSignature(this.model, member as ApiMethodSignature));
break;
case ApiItemKind.PropertySignature:
this.properties.push(new DocProperty(this.model, member as ApiPropertySignature));
break;
default:
break;
}
}
}
public override toJSON() {
return {
...super.toJSON(),
extendsTokens: this.extendsTokens,
methods: this.methods.map((method) => method.toJSON()),
properties: this.properties.map((prop) => prop.toJSON()),
};
}
}

View File

@@ -1,46 +0,0 @@
import type { ApiModel, ApiDeclaredItem } from '@microsoft/api-extractor-model';
import { CommentNodeContainer } from './comment/CommentNodeContainer';
import type { ReferenceData } from '~/util/model.server';
import { resolveName, genReference, TokenDocumentation, genToken } from '~/util/parse.server';
export type DocItemConstructor<T = DocItem> = new (...args: any[]) => T;
export class DocItem<T extends ApiDeclaredItem = ApiDeclaredItem> {
public readonly item: T;
public readonly name: string;
public readonly referenceData: ReferenceData;
public readonly model: ApiModel;
public readonly excerpt: string;
public readonly excerptTokens: TokenDocumentation[] = [];
public readonly kind: string;
public readonly remarks: CommentNodeContainer | null;
public readonly summary: CommentNodeContainer | null;
public constructor(model: ApiModel, item: T) {
this.item = item;
this.kind = item.kind;
this.model = model;
this.name = resolveName(item);
this.referenceData = genReference(item);
this.excerpt = item.excerpt.text;
this.excerptTokens = item.excerpt.spannedTokens.map((token) => genToken(model, token));
this.remarks = item.tsdocComment?.remarksBlock
? new CommentNodeContainer(item.tsdocComment.remarksBlock.content, model, item.parent)
: null;
this.summary = item.tsdocComment?.summarySection
? new CommentNodeContainer(item.tsdocComment.summarySection, model, item.parent)
: null;
}
public toJSON() {
return {
name: this.name,
referenceData: this.referenceData,
summary: this.summary?.toJSON() ?? null,
excerpt: this.excerpt,
excerptTokens: this.excerptTokens,
kind: this.kind,
remarks: this.remarks?.toJSON() ?? null,
};
}
}

View File

@@ -1,25 +0,0 @@
import type { ApiMethod, ApiModel } from '@microsoft/api-extractor-model';
import { DocFunction } from './DocFunction';
import { Visibility } from './Visibility';
export class DocMethod extends DocFunction {
public readonly static: boolean;
public readonly optional: boolean;
public readonly visibility: Visibility;
public constructor(model: ApiModel, item: ApiMethod) {
super(model, item);
this.static = item.isStatic;
this.optional = item.isOptional;
this.visibility = item.isProtected ? Visibility.Protected : Visibility.Public;
}
public override toJSON() {
return {
...super.toJSON(),
static: this.static,
optional: this.optional,
visibility: this.visibility,
};
}
}

View File

@@ -1,18 +0,0 @@
import type { ApiMethodSignature, ApiModel } from '@microsoft/api-extractor-model';
import { DocFunction } from './DocFunction';
export class DocMethodSignature extends DocFunction {
public readonly optional: boolean;
public constructor(model: ApiModel, item: ApiMethodSignature) {
super(model, item);
this.optional = item.isOptional;
}
public override toJSON() {
return {
...super.toJSON(),
optional: this.optional,
};
}
}

View File

@@ -1,25 +0,0 @@
import type { ApiPropertyItem, ApiModel, ApiPropertySignature } from '@microsoft/api-extractor-model';
import { DocItem } from './DocItem';
import { type TokenDocumentation, genToken } from '~/util/parse.server';
export class DocProperty extends DocItem<ApiPropertyItem> {
public readonly propertyTypeTokens: TokenDocumentation[];
public readonly readonly: boolean;
public readonly optional: boolean;
public constructor(model: ApiModel, item: ApiPropertyItem | ApiPropertySignature) {
super(model, item);
this.propertyTypeTokens = item.propertyTypeExcerpt.spannedTokens.map((token) => genToken(this.model, token));
this.readonly = item.isReadonly;
this.optional = item.isOptional;
}
public override toJSON() {
return {
...super.toJSON(),
propertyTypeTokens: this.propertyTypeTokens,
readonly: this.readonly,
optional: this.optional,
};
}
}

View File

@@ -1,20 +0,0 @@
import type { ApiModel, ApiTypeAlias } from '@microsoft/api-extractor-model';
import { DocItem } from './DocItem';
import { TypeParameterMixin } from './TypeParameterMixin';
import { type TokenDocumentation, genToken } from '~/util/parse.server';
export class DocTypeAlias extends TypeParameterMixin(DocItem<ApiTypeAlias>) {
public readonly typeTokens: TokenDocumentation[];
public constructor(model: ApiModel, item: ApiTypeAlias) {
super(model, item);
this.typeTokens = item.typeExcerpt.spannedTokens.map((token) => genToken(model, token));
}
public override toJSON() {
return {
...super.toJSON(),
typeTokens: this.typeTokens,
};
}
}

View File

@@ -1,22 +0,0 @@
import type { ApiModel, ApiVariable } from '@microsoft/api-extractor-model';
import { DocItem } from './DocItem';
import { genToken, TokenDocumentation } from '~/util/parse.server';
export class DocVariable extends DocItem<ApiVariable> {
public readonly typeTokens: TokenDocumentation[] = [];
public readonly readonly: boolean;
public constructor(model: ApiModel, item: ApiVariable) {
super(model, item);
this.typeTokens = item.variableTypeExcerpt.spannedTokens.map((token) => genToken(model, token));
this.readonly = item.isReadonly;
}
public override toJSON() {
return {
...super.toJSON(),
typeTokens: this.typeTokens,
readonly: this.readonly,
};
}
}

View File

@@ -1,24 +1,28 @@
import type { ApiItem, ApiModel, ApiTypeParameterListMixin } from '@microsoft/api-extractor-model';
import type { DocItemConstructor } from './DocItem';
import { generateTypeParamData, TypeParameterData } from '~/util/parse.server';
import type { ApiItem, ApiModel, TypeParameter } from '@microsoft/api-extractor-model';
import { block, DocBlockJSON } from './comment/CommentBlock';
import { genToken, TokenDocumentation } from '~/util/parse.server';
export function TypeParameterMixin<TBase extends DocItemConstructor>(Base: TBase) {
return class Mixed extends Base {
public readonly typeParameters: TypeParameterData[] = [];
export interface TypeParameterData {
name: string;
constraintTokens: TokenDocumentation[];
defaultTokens: TokenDocumentation[];
optional: boolean;
commentBlock: DocBlockJSON | null;
}
public constructor(...args: any[]);
public constructor(model: ApiModel, item: ApiItem) {
super(model, item);
this.typeParameters = (item as ApiTypeParameterListMixin).typeParameters.map((typeParam) =>
generateTypeParamData(this.model, typeParam),
);
}
export function generateTypeParamData(
model: ApiModel,
typeParam: TypeParameter,
parentItem?: ApiItem,
): TypeParameterData {
const constraintTokens = typeParam.constraintExcerpt.spannedTokens.map((token) => genToken(model, token));
const defaultTokens = typeParam.defaultTypeExcerpt.spannedTokens.map((token) => genToken(model, token));
public override toJSON() {
return {
...super.toJSON(),
typeParameterData: this.typeParameters,
};
}
return {
name: typeParam.name,
constraintTokens,
defaultTokens,
optional: typeParam.isOptional,
commentBlock: typeParam.tsdocTypeParamBlock ? block(typeParam.tsdocTypeParamBlock, model, parentItem) : null,
};
}

View File

@@ -0,0 +1,18 @@
import type { ApiModel, ApiItem } from '@microsoft/api-extractor-model';
import type { DocBlock } from '@microsoft/tsdoc';
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) {
return {
...node(block),
content: block.content.nodes.map((node) => createCommentNode(node, model, parentItem)),
tag: blockTag(block.blockTag),
};
}

View File

@@ -0,0 +1,13 @@
import type { DocBlockTag } from '@microsoft/tsdoc';
import { type DocNodeJSON, node } from './CommentNode';
export interface DocBlockTagJSON extends DocNodeJSON {
tagName: string;
}
export function blockTag(blockTag: DocBlockTag): DocBlockTagJSON {
return {
...node(blockTag),
tagName: blockTag.tagName,
};
}

View File

@@ -0,0 +1,13 @@
import type { DocCodeSpan } from '@microsoft/tsdoc';
import { DocNodeJSON, node } from './CommentNode';
export interface DocCodeSpanJSON extends DocNodeJSON {
code: string;
}
export function codeSpan(codeSpan: DocCodeSpan): DocCodeSpanJSON {
return {
...node(codeSpan),
code: codeSpan.code,
};
}

View File

@@ -1,22 +1,28 @@
import type { ApiItem, ApiModel } from '@microsoft/api-extractor-model';
import type { DocNode } from '@microsoft/tsdoc';
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';
export class CommentNode<T extends DocNode = DocNode> {
public readonly node: T;
public readonly kind: string;
public readonly model: ApiModel;
public readonly parentItem: ApiItem | null;
public constructor(node: T, model: ApiModel, parentItem?: ApiItem) {
this.node = node;
this.kind = node.kind;
this.model = model;
this.parentItem = parentItem ?? null;
}
public toJSON() {
return {
kind: this.kind,
};
}
export interface DocNodeJSON {
kind: DocNodeKind;
}
export type AnyDocNodeJSON =
| DocNodeJSON
| DocPlainTextJSON
| DocNodeContainerJSON
| DocLinkTagJSON
| DocFencedCodeJSON
| DocBlockJSON
| DocCommentJSON
| DocCodeSpanJSON;
export function node(node: DocNode): DocNodeJSON {
return {
kind: node.kind as DocNodeKind,
};
}

View File

@@ -1,20 +1,19 @@
import type { ApiItem, ApiModel } from '@microsoft/api-extractor-model';
import type { DocNodeContainer } from '@microsoft/tsdoc';
import { createCommentNode } from '.';
import { CommentNode } from './CommentNode';
import { AnyDocNodeJSON, DocNodeJSON, node } from './CommentNode';
export class CommentNodeContainer<T extends DocNodeContainer = DocNodeContainer> extends CommentNode<DocNodeContainer> {
public readonly nodes: CommentNode[];
public constructor(container: T, model: ApiModel, parentItem?: ApiItem) {
super(container, model, parentItem);
this.nodes = container.nodes.map((node) => createCommentNode(node, model, parentItem));
}
public override toJSON() {
return {
...super.toJSON(),
nodes: this.nodes.map((node) => node.toJSON()),
};
}
export interface DocNodeContainerJSON extends DocNodeJSON {
nodes: AnyDocNodeJSON[];
}
export function nodeContainer(
container: DocNodeContainer,
model: ApiModel,
parentItem?: ApiItem,
): DocNodeContainerJSON {
return {
...node(container),
nodes: container.nodes.map((node) => createCommentNode(node, model, parentItem)),
};
}

View File

@@ -1,22 +1,15 @@
import type { ApiModel, ApiItem } from '@microsoft/api-extractor-model';
import type { DocFencedCode } from '@microsoft/tsdoc';
import { CommentNode } from './CommentNode';
import { DocNodeJSON, node } from './CommentNode';
export class FencedCodeCommentNode extends CommentNode<DocFencedCode> {
public readonly code: string;
public readonly language: string;
public constructor(node: DocFencedCode, model: ApiModel, parentItem?: ApiItem) {
super(node, model, parentItem);
this.code = node.code;
this.language = node.language;
}
public override toJSON() {
return {
...super.toJSON(),
code: this.code,
language: this.language,
};
}
export interface DocFencedCodeJSON extends DocNodeJSON {
code: string;
language: string;
}
export function fencedCode(fencedCode: DocFencedCode) {
return {
...node(fencedCode),
language: fencedCode.language,
code: fencedCode.code,
};
}

View File

@@ -1,18 +1,20 @@
import type { ApiItem, ApiModel } from '@microsoft/api-extractor-model';
import type { DocDeclarationReference, DocLinkTag } from '@microsoft/tsdoc';
import { CommentNode } from './CommentNode';
import { DocNodeJSON, node } from './CommentNode';
import { generatePath, resolveName } from '~/util/parse.server';
export interface DocLinkTagJSON extends DocNodeJSON {
text: string | null;
codeDestination: LinkTagCodeLink | null;
urlDestination: string | null;
}
export function genToken(
model: ApiModel,
ref: DocDeclarationReference,
context: ApiItem | null,
): LinkTagCodeLink | null {
if (!context) {
return null;
}
const item = model.resolveDeclarationReference(ref, context).resolvedApiItem ?? null;
const item = model.resolveDeclarationReference(ref, context ?? undefined).resolvedApiItem ?? null;
if (!item) {
return null;
@@ -31,24 +33,22 @@ export interface LinkTagCodeLink {
path: string;
}
export class LinkTagCommentNode extends CommentNode<DocLinkTag> {
public readonly codeDestination: LinkTagCodeLink | null;
public readonly text: string | null;
public readonly urlDestination: string | null;
export function linkTagNode(linkNode: DocLinkTag, model: ApiModel, 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;
public constructor(node: DocLinkTag, model: ApiModel, parentItem?: ApiItem) {
super(node, model, parentItem);
this.codeDestination = node.codeDestination ? genToken(model, node.codeDestination, this.parentItem) : null;
this.text = node.linkText ?? null;
this.urlDestination = node.urlDestination ?? null;
}
const codeDestination = linkNode.codeDestination
? genToken(model, linkNode.codeDestination, parentItem ?? packageEntryPoint ?? null)
: null;
const text = linkNode.linkText ?? null;
const urlDestination = linkNode.urlDestination ?? null;
public override toJSON() {
return {
...super.toJSON(),
text: this.text,
codeDestination: this.codeDestination,
urlDestination: this.urlDestination,
};
}
return {
...node(linkNode),
text,
codeDestination,
urlDestination,
};
}

View File

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

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