mirror of
https://github.com/discordjs/discord.js.git
synced 2026-05-23 20:10:08 +00:00
Compare commits
167 Commits
@discordjs
...
@discordjs
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
c69f512450 | ||
|
|
4a07f9eaa1 | ||
|
|
64cd53c4c2 | ||
|
|
d79aa2d0d0 | ||
|
|
822b7f234a | ||
|
|
8ca407e089 | ||
|
|
0126d9b810 | ||
|
|
e9931229ae | ||
|
|
1486bc9336 | ||
|
|
16fcdc3687 | ||
|
|
8622939229 | ||
|
|
2487e3bf76 | ||
|
|
578bc951bd | ||
|
|
1244854e13 | ||
|
|
b1e190c4f0 | ||
|
|
fc8ed816e6 | ||
|
|
abb7226af3 | ||
|
|
30ceaf7e47 | ||
|
|
9b40a79b3e | ||
|
|
0b12d6fa10 | ||
|
|
b106956308 | ||
|
|
6f1f465a77 | ||
|
|
eb98372dcd | ||
|
|
5048a3d17a | ||
|
|
f0497343f1 | ||
|
|
f6f15d8e87 | ||
|
|
14bbc9150a | ||
|
|
a7f816eeb7 | ||
|
|
802b2394b0 | ||
|
|
c446a84570 | ||
|
|
9cf0a4904b | ||
|
|
25dc146247 | ||
|
|
a2b08aaf3b | ||
|
|
eba9cc6038 | ||
|
|
145eb2fc5d | ||
|
|
8444576f45 | ||
|
|
6d43e26676 | ||
|
|
2fc3d86f56 | ||
|
|
8a8d519c9c | ||
|
|
669c3cd256 | ||
|
|
678ceaa014 | ||
|
|
0785353efe | ||
|
|
8323926304 | ||
|
|
bccc2c8e89 | ||
|
|
1d72663e92 | ||
|
|
d0a2a6227d | ||
|
|
735e0bf52e | ||
|
|
1c5b78fd21 | ||
|
|
053da5bc91 | ||
|
|
fc9653f5ae | ||
|
|
22ac6b4660 | ||
|
|
d14d47b62f | ||
|
|
a9f003ac9b | ||
|
|
1d4cdee321 | ||
|
|
8e1afaebdb | ||
|
|
32523325c6 | ||
|
|
7a9e52e63a | ||
|
|
d11edc6397 | ||
|
|
96304d7cc8 | ||
|
|
f9e9bfdedc | ||
|
|
ce1f5c8d47 | ||
|
|
03fb5b0a2f | ||
|
|
ce991dd1d8 | ||
|
|
dbca93098c | ||
|
|
dd5a08944c | ||
|
|
8e98ba94d2 | ||
|
|
74dc8c10d5 | ||
|
|
8d07ea9a62 | ||
|
|
d8e774138d | ||
|
|
55c3ee20ae | ||
|
|
c3341570d9 | ||
|
|
f3ce4a75d0 | ||
|
|
4ffdada4f7 | ||
|
|
8b3d006118 | ||
|
|
d08a57cadd | ||
|
|
0dc68445a1 | ||
|
|
a7ad7e75ce | ||
|
|
f79ccb4971 | ||
|
|
6f2b223c8b | ||
|
|
a4777aa9b0 | ||
|
|
f072d3d916 | ||
|
|
0238588067 | ||
|
|
1d460e0434 | ||
|
|
b9c62ac0f0 | ||
|
|
df46ab8061 | ||
|
|
b7eb96d456 | ||
|
|
f77612a55e | ||
|
|
9b4116b659 | ||
|
|
8a91d7c256 | ||
|
|
3b7ba4062e | ||
|
|
edadb9fe5d | ||
|
|
4bdb0593ae | ||
|
|
fd97da9b6c | ||
|
|
d5dcddd350 | ||
|
|
40324574eb | ||
|
|
1398af66f0 | ||
|
|
682e0e1802 | ||
|
|
13baf75cae | ||
|
|
1d6b31b78d | ||
|
|
5f093dde24 | ||
|
|
b58e6a65ad | ||
|
|
204f4dd7c4 | ||
|
|
249ba0a9a6 | ||
|
|
92933c2b61 | ||
|
|
abd3fc8ceb | ||
|
|
84059b6b25 | ||
|
|
6da405668f | ||
|
|
58d2a1e6d7 | ||
|
|
7b5c688844 | ||
|
|
28bc4f42c6 | ||
|
|
5b4672bad3 | ||
|
|
a57b9ba5c4 | ||
|
|
32da9b3868 | ||
|
|
70806b401e | ||
|
|
0674820723 | ||
|
|
2d5bce274c | ||
|
|
331dedcb9d | ||
|
|
103e1bd843 | ||
|
|
ffafde0b6b | ||
|
|
28422eea58 | ||
|
|
c826ad3ade | ||
|
|
17559becef | ||
|
|
b31a23b37c | ||
|
|
8e4f77a63b | ||
|
|
b16ab8c69f | ||
|
|
cf8570c19c | ||
|
|
f0ab393411 | ||
|
|
11e02f1e5d | ||
|
|
206523587a | ||
|
|
ac3bc6a2db | ||
|
|
af295acedc | ||
|
|
caa5c0332f | ||
|
|
434f696397 | ||
|
|
6062d361fb | ||
|
|
2ecb862e76 | ||
|
|
360936140b | ||
|
|
0b56184ba7 | ||
|
|
a55545850a | ||
|
|
f16b11a91d | ||
|
|
0fb2694871 | ||
|
|
ee030003ec | ||
|
|
29c51be1f4 | ||
|
|
43a78be70b | ||
|
|
92c0c60519 | ||
|
|
ba3e0ed348 | ||
|
|
f7ce9f8533 | ||
|
|
00990c93ae | ||
|
|
c076b0d8cb | ||
|
|
d297fb0b69 | ||
|
|
24c128d649 | ||
|
|
ec7c6e3d3e | ||
|
|
6dfb9bbc48 | ||
|
|
4644e45e85 | ||
|
|
1e001601c8 | ||
|
|
1aec243b1d | ||
|
|
191951ac28 | ||
|
|
4fb4492b17 | ||
|
|
abb968de81 | ||
|
|
d9e53093f5 | ||
|
|
e5678f4656 | ||
|
|
9f18036078 | ||
|
|
474eae0afc | ||
|
|
caeb66e150 | ||
|
|
7623fc552e | ||
|
|
230c43e97d | ||
|
|
4e3fa586b5 | ||
|
|
6bb1474d20 |
@@ -1,9 +1,12 @@
|
||||
{
|
||||
"root": true,
|
||||
"extends": "marine/prettier/node",
|
||||
"extends": ["neon/common", "neon/node", "neon/typescript", "neon/prettier"],
|
||||
"parserOptions": {
|
||||
"project": "./tsconfig.eslint.json"
|
||||
},
|
||||
"rules": {
|
||||
"@typescript-eslint/consistent-type-definitions": ["error", "interface"]
|
||||
},
|
||||
"ignorePatterns": ["**/dist/*"],
|
||||
"env": {
|
||||
"jest": true
|
||||
|
||||
2
.github/ISSUE_TEMPLATE/bug_report.yml
vendored
2
.github/ISSUE_TEMPLATE/bug_report.yml
vendored
@@ -52,7 +52,7 @@ body:
|
||||
id: djs-version
|
||||
attributes:
|
||||
label: Package version
|
||||
description: Which version of are you using? Run `npm list <package>` in your project directory and paste the output.
|
||||
description: Which version of the package are you using? Run `npm list <package>` in your project directory and paste the output.
|
||||
placeholder: We no longer support version 12 or earlier of discord.js
|
||||
validations:
|
||||
required: true
|
||||
|
||||
2
.github/ISSUE_TEMPLATE/feature_request.yml
vendored
2
.github/ISSUE_TEMPLATE/feature_request.yml
vendored
@@ -5,7 +5,7 @@ body:
|
||||
- type: markdown
|
||||
attributes:
|
||||
value: |
|
||||
We can only implement features that Discord publishes, documents and merges into the Discord API documentation.
|
||||
We can only implement features that Discord publishes, documents, and merges into the Discord API documentation.
|
||||
We do not implement unreleased features.
|
||||
Use Discord for questions: https://discord.gg/djs
|
||||
- type: dropdown
|
||||
|
||||
6
.github/workflows/documentation.yml
vendored
6
.github/workflows/documentation.yml
vendored
@@ -123,14 +123,14 @@ jobs:
|
||||
path: 'out'
|
||||
|
||||
- name: Extract package and semver from tag
|
||||
if: ${{ github.event.inputs.ref_type == 'tag' || env.BRANCH_OR_TAG == 'tag' }}
|
||||
if: ${{ env.BRANCH_OR_TAG == 'tag' }}
|
||||
id: extract-tag
|
||||
uses: ./packages/actions/src/formatTag
|
||||
with:
|
||||
tag: ${{ env.BRANCH_NAME }}
|
||||
|
||||
- name: Move docs to correct directory
|
||||
if: ${{ (github.event.inputs.ref_type == 'tag' || env.BRANCH_OR_TAG == 'tag') && matrix.package == steps.extract-tag.outputs.package }}
|
||||
if: ${{ env.BRANCH_OR_TAG == 'tag' && matrix.package == steps.extract-tag.outputs.package }}
|
||||
env:
|
||||
PACKAGE: ${{ steps.extract-tag.outputs.package }}
|
||||
SEMVER: ${{ steps.extract-tag.outputs.semver }}
|
||||
@@ -142,7 +142,7 @@ jobs:
|
||||
fi
|
||||
|
||||
- name: Move docs to correct directory
|
||||
if: ${{ github.event.inputs.ref_type == 'branch' || env.BRANCH_OR_TAG == 'branch' }}
|
||||
if: ${{ env.BRANCH_OR_TAG == 'branch' }}
|
||||
env:
|
||||
PACKAGE: ${{ matrix.package }}
|
||||
run: |
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
#!/bin/sh
|
||||
. "$(dirname "$0")/_/husky.sh"
|
||||
|
||||
yarn build && yarn lint-staged
|
||||
yarn build && yarn workspace @discordjs/website run build:local && yarn lint-staged
|
||||
|
||||
@@ -1,95 +0,0 @@
|
||||
import { relative, resolve } from 'node:path';
|
||||
import glob from 'fast-glob';
|
||||
import isCi from 'is-ci';
|
||||
import typescript from 'rollup-plugin-typescript2';
|
||||
import { defineBuildConfig, BuildEntry } from 'unbuild';
|
||||
|
||||
interface ConfigOptions {
|
||||
entries: (BuildEntry | string)[];
|
||||
minify: boolean;
|
||||
emitCJS: boolean;
|
||||
externals: string[];
|
||||
cjsBridge: boolean;
|
||||
sourcemap: boolean;
|
||||
preserveModules: boolean;
|
||||
preserveModulesRoot: string;
|
||||
declaration: boolean;
|
||||
typeCheck: boolean;
|
||||
}
|
||||
|
||||
export function createUnbuildConfig({
|
||||
entries = [{ builder: 'rollup', input: 'src/index' }],
|
||||
minify = false,
|
||||
emitCJS = true,
|
||||
cjsBridge = true,
|
||||
externals = [],
|
||||
sourcemap = true,
|
||||
preserveModules = true,
|
||||
preserveModulesRoot = 'src',
|
||||
declaration = true,
|
||||
typeCheck = isCi,
|
||||
}: Partial<ConfigOptions> = {}) {
|
||||
const files = glob
|
||||
.sync('**', { cwd: 'src' })
|
||||
.map((file) => [`${file.slice(0, -2)}cjs`, `${file.slice(0, -2)}mjs`])
|
||||
.flat();
|
||||
|
||||
return defineBuildConfig({
|
||||
entries,
|
||||
clean: true,
|
||||
rollup: {
|
||||
esbuild: {
|
||||
minify,
|
||||
minifyIdentifiers: false,
|
||||
},
|
||||
emitCJS,
|
||||
cjsBridge,
|
||||
json: {
|
||||
namedExports: false,
|
||||
preferConst: true,
|
||||
},
|
||||
},
|
||||
|
||||
externals: [...files, ...externals],
|
||||
|
||||
hooks: {
|
||||
'rollup:options': (_, options) => {
|
||||
// @ts-expect-error: This will always be an array
|
||||
// eslint-disable-next-line @typescript-eslint/no-unsafe-assignment
|
||||
options.output![0] = {
|
||||
// @ts-expect-error: This will always be an array
|
||||
...options.output![0],
|
||||
sourcemap,
|
||||
preserveModules,
|
||||
preserveModulesRoot,
|
||||
};
|
||||
|
||||
if (emitCJS) {
|
||||
// @ts-expect-error: This will always be an array
|
||||
// eslint-disable-next-line @typescript-eslint/no-unsafe-assignment
|
||||
options.output![1] = {
|
||||
// @ts-expect-error: This will always be an array
|
||||
...options.output![1],
|
||||
sourcemap,
|
||||
preserveModules,
|
||||
preserveModulesRoot,
|
||||
};
|
||||
}
|
||||
|
||||
if (declaration) {
|
||||
options.plugins?.unshift(
|
||||
typescript({
|
||||
check: typeCheck,
|
||||
tsconfig: relative(__dirname, resolve(process.cwd(), 'tsconfig.json')),
|
||||
tsconfigOverride: {
|
||||
compilerOptions: {
|
||||
emitDeclarationOnly: true,
|
||||
},
|
||||
},
|
||||
}),
|
||||
);
|
||||
}
|
||||
},
|
||||
},
|
||||
});
|
||||
}
|
||||
13
package.json
13
package.json
@@ -18,7 +18,7 @@
|
||||
"Amish Shah <amishshah.2k@gmail.com>",
|
||||
"Vlad Frangu <kingdgrizzle@gmail.com>",
|
||||
"SpaceEEC <spaceeec@yahoo.com>",
|
||||
"Antonio Roman <kyradiscord@gmail.com>"
|
||||
"Aura Román <kyradiscord@gmail.com>"
|
||||
],
|
||||
"keywords": [
|
||||
"discord",
|
||||
@@ -37,18 +37,17 @@
|
||||
},
|
||||
"homepage": "https://discord.js.org",
|
||||
"devDependencies": {
|
||||
"@commitlint/cli": "^17.0.3",
|
||||
"@commitlint/config-angular": "^17.0.3",
|
||||
"@commitlint/cli": "^17.1.2",
|
||||
"@commitlint/config-angular": "^17.1.0",
|
||||
"@favware/cliff-jumper": "^1.8.7",
|
||||
"@favware/npm-deprecate": "^1.0.5",
|
||||
"@types/is-ci": "^3.0.0",
|
||||
"conventional-changelog-cli": "^2.2.2",
|
||||
"fast-glob": "^3.2.11",
|
||||
"husky": "^8.0.1",
|
||||
"is-ci": "^3.0.1",
|
||||
"lint-staged": "^13.0.3",
|
||||
"turbo": "^1.4.3",
|
||||
"typescript": "^4.7.4"
|
||||
"tsup": "^6.2.3",
|
||||
"turbo": "^1.5.3",
|
||||
"typescript": "^4.8.3"
|
||||
},
|
||||
"resolutions": {
|
||||
"@microsoft/tsdoc-config": "patch:@microsoft/tsdoc-config@npm:0.16.1#.yarn/patches/@microsoft-tsdoc-config-npm-0.16.1-81031b1bbf.patch"
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
import { describe, test, expect } from 'vitest';
|
||||
import { formatTag } from '../src';
|
||||
import { formatTag } from '../src/index.js';
|
||||
|
||||
describe('Format Tag', () => {
|
||||
test('GIVEN tag with a prefix THEN format tag to not contain the prefix', () => {
|
||||
|
||||
@@ -1,11 +0,0 @@
|
||||
import { createUnbuildConfig } from '../../build.config';
|
||||
|
||||
export default createUnbuildConfig({
|
||||
entries: [
|
||||
{ builder: 'rollup', input: 'src/index' },
|
||||
{ builder: 'rollup', input: 'src/formatTag/index' },
|
||||
],
|
||||
preserveModules: false,
|
||||
minify: true,
|
||||
emitCJS: false,
|
||||
});
|
||||
@@ -5,9 +5,9 @@
|
||||
"private": true,
|
||||
"scripts": {
|
||||
"test": "vitest run",
|
||||
"build": "unbuild",
|
||||
"lint": "prettier --check . && TIMING=1 eslint src __tests__ --ext mjs,js,ts",
|
||||
"format": "prettier --write . && TIMING=1 eslint src __tests__ --ext mjs,js,ts --fix",
|
||||
"build": "tsup",
|
||||
"lint": "prettier --check . && cross-env TIMING=1 eslint src __tests__ --ext mjs,js,ts",
|
||||
"format": "prettier --write . && cross-env TIMING=1 eslint src __tests__ --ext mjs,js,ts --fix",
|
||||
"fmt": "yarn format"
|
||||
},
|
||||
"main": "./dist/index.mjs",
|
||||
@@ -43,20 +43,15 @@
|
||||
"tslib": "^2.4.0"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@types/node": "^16.11.52",
|
||||
"@typescript-eslint/eslint-plugin": "^5.33.1",
|
||||
"@typescript-eslint/parser": "^5.33.1",
|
||||
"@vitest/coverage-c8": "^0.22.1",
|
||||
"eslint": "^8.22.0",
|
||||
"eslint-config-marine": "^9.4.1",
|
||||
"eslint-config-prettier": "^8.5.0",
|
||||
"eslint-import-resolver-typescript": "^3.4.2",
|
||||
"eslint-plugin-import": "^2.26.0",
|
||||
"@types/node": "^16.11.60",
|
||||
"@vitest/coverage-c8": "^0.23.4",
|
||||
"cross-env": "^7.0.3",
|
||||
"eslint": "^8.24.0",
|
||||
"eslint-config-neon": "^0.1.33",
|
||||
"prettier": "^2.7.1",
|
||||
"rollup-plugin-typescript2": "^0.33.0",
|
||||
"typescript": "^4.7.4",
|
||||
"unbuild": "^0.8.9",
|
||||
"vitest": "^0.22.1"
|
||||
"tsup": "^6.2.3",
|
||||
"typescript": "^4.8.3",
|
||||
"vitest": "^0.23.4"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=16.9.0"
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
export function formatTag(tag: string) {
|
||||
// eslint-disable-next-line unicorn/no-unsafe-regex, prefer-named-capture-group
|
||||
const parsed = /(^@.*\/(?<package>.*)@v?)?(?<semver>\d+.\d+.\d+)-?.*/.exec(tag);
|
||||
|
||||
if (parsed?.groups) {
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
import { getInput, setOutput } from '@actions/core';
|
||||
import { formatTag } from './formatTag';
|
||||
import { formatTag } from './formatTag.js';
|
||||
|
||||
const tag = getInput('tag', { required: true });
|
||||
const parsed = formatTag(tag);
|
||||
|
||||
@@ -1 +1 @@
|
||||
export * from './formatTag/formatTag';
|
||||
export * from './formatTag/formatTag.js';
|
||||
|
||||
7
packages/actions/tsup.config.js
Normal file
7
packages/actions/tsup.config.js
Normal file
@@ -0,0 +1,7 @@
|
||||
import { createTsupConfig } from '../../tsup.config.js';
|
||||
|
||||
export default createTsupConfig({
|
||||
entry: ['src/index.ts', 'src/formatTag/index.ts'],
|
||||
format: ['esm'],
|
||||
minify: true,
|
||||
});
|
||||
3
packages/api-extractor-utils/.eslintrc.json
Normal file
3
packages/api-extractor-utils/.eslintrc.json
Normal file
@@ -0,0 +1,3 @@
|
||||
{
|
||||
"extends": "../../.eslintrc.json"
|
||||
}
|
||||
27
packages/api-extractor-utils/.gitignore
vendored
Normal file
27
packages/api-extractor-utils/.gitignore
vendored
Normal file
@@ -0,0 +1,27 @@
|
||||
# Packages
|
||||
node_modules/
|
||||
|
||||
# Log files
|
||||
logs/
|
||||
*.log
|
||||
npm-debug.log*
|
||||
|
||||
# Runtime data
|
||||
pids
|
||||
*.pid
|
||||
*.seed
|
||||
|
||||
# Env
|
||||
.env
|
||||
|
||||
# Dist
|
||||
dist/
|
||||
typings/
|
||||
docs/**/*
|
||||
!docs/index.json
|
||||
!docs/README.md
|
||||
|
||||
# Miscellaneous
|
||||
.tmp/
|
||||
coverage/
|
||||
tsconfig.tsbuildinfo
|
||||
8
packages/api-extractor-utils/.prettierignore
Normal file
8
packages/api-extractor-utils/.prettierignore
Normal file
@@ -0,0 +1,8 @@
|
||||
# Autogenerated
|
||||
CHANGELOG.md
|
||||
.turbo
|
||||
dist/
|
||||
docs/**/*
|
||||
!docs/index.yml
|
||||
!docs/README.md
|
||||
coverage/
|
||||
190
packages/api-extractor-utils/LICENSE
Normal file
190
packages/api-extractor-utils/LICENSE
Normal file
@@ -0,0 +1,190 @@
|
||||
Apache License
|
||||
Version 2.0, January 2004
|
||||
http://www.apache.org/licenses/
|
||||
|
||||
TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
|
||||
|
||||
1. Definitions.
|
||||
|
||||
"License" shall mean the terms and conditions for use, reproduction,
|
||||
and distribution as defined by Sections 1 through 9 of this document.
|
||||
|
||||
"Licensor" shall mean the copyright owner or entity authorized by
|
||||
the copyright owner that is granting the License.
|
||||
|
||||
"Legal Entity" shall mean the union of the acting entity and all
|
||||
other entities that control, are controlled by, or are under common
|
||||
control with that entity. For the purposes of this definition,
|
||||
"control" means (i) the power, direct or indirect, to cause the
|
||||
direction or management of such entity, whether by contract or
|
||||
otherwise, or (ii) ownership of fifty percent (50%) or more of the
|
||||
outstanding shares, or (iii) beneficial ownership of such entity.
|
||||
|
||||
"You" (or "Your") shall mean an individual or Legal Entity
|
||||
exercising permissions granted by this License.
|
||||
|
||||
"Source" form shall mean the preferred form for making modifications,
|
||||
including but not limited to software source code, documentation
|
||||
source, and configuration files.
|
||||
|
||||
"Object" form shall mean any form resulting from mechanical
|
||||
transformation or translation of a Source form, including but
|
||||
not limited to compiled object code, generated documentation,
|
||||
and conversions to other media types.
|
||||
|
||||
"Work" shall mean the work of authorship, whether in Source or
|
||||
Object form, made available under the License, as indicated by a
|
||||
copyright notice that is included in or attached to the work
|
||||
(an example is provided in the Appendix below).
|
||||
|
||||
"Derivative Works" shall mean any work, whether in Source or Object
|
||||
form, that is based on (or derived from) the Work and for which the
|
||||
editorial revisions, annotations, elaborations, or other modifications
|
||||
represent, as a whole, an original work of authorship. For the purposes
|
||||
of this License, Derivative Works shall not include works that remain
|
||||
separable from, or merely link (or bind by name) to the interfaces of,
|
||||
the Work and Derivative Works thereof.
|
||||
|
||||
"Contribution" shall mean any work of authorship, including
|
||||
the original version of the Work and any modifications or additions
|
||||
to that Work or Derivative Works thereof, that is intentionally
|
||||
submitted to Licensor for inclusion in the Work by the copyright owner
|
||||
or by an individual or Legal Entity authorized to submit on behalf of
|
||||
the copyright owner. For the purposes of this definition, "submitted"
|
||||
means any form of electronic, verbal, or written communication sent
|
||||
to the Licensor or its representatives, including but not limited to
|
||||
communication on electronic mailing lists, source code control systems,
|
||||
and issue tracking systems that are managed by, or on behalf of, the
|
||||
Licensor for the purpose of discussing and improving the Work, but
|
||||
excluding communication that is conspicuously marked or otherwise
|
||||
designated in writing by the copyright owner as "Not a Contribution."
|
||||
|
||||
"Contributor" shall mean Licensor and any individual or Legal Entity
|
||||
on behalf of whom a Contribution has been received by Licensor and
|
||||
subsequently incorporated within the Work.
|
||||
|
||||
2. Grant of Copyright License. Subject to the terms and conditions of
|
||||
this License, each Contributor hereby grants to You a perpetual,
|
||||
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
|
||||
copyright license to reproduce, prepare Derivative Works of,
|
||||
publicly display, publicly perform, sublicense, and distribute the
|
||||
Work and such Derivative Works in Source or Object form.
|
||||
|
||||
3. Grant of Patent License. Subject to the terms and conditions of
|
||||
this License, each Contributor hereby grants to You a perpetual,
|
||||
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
|
||||
(except as stated in this section) patent license to make, have made,
|
||||
use, offer to sell, sell, import, and otherwise transfer the Work,
|
||||
where such license applies only to those patent claims licensable
|
||||
by such Contributor that are necessarily infringed by their
|
||||
Contribution(s) alone or by combination of their Contribution(s)
|
||||
with the Work to which such Contribution(s) was submitted. If You
|
||||
institute patent litigation against any entity (including a
|
||||
cross-claim or counterclaim in a lawsuit) alleging that the Work
|
||||
or a Contribution incorporated within the Work constitutes direct
|
||||
or contributory patent infringement, then any patent licenses
|
||||
granted to You under this License for that Work shall terminate
|
||||
as of the date such litigation is filed.
|
||||
|
||||
4. Redistribution. You may reproduce and distribute copies of the
|
||||
Work or Derivative Works thereof in any medium, with or without
|
||||
modifications, and in Source or Object form, provided that You
|
||||
meet the following conditions:
|
||||
|
||||
(a) You must give any other recipients of the Work or
|
||||
Derivative Works a copy of this License; and
|
||||
|
||||
(b) You must cause any modified files to carry prominent notices
|
||||
stating that You changed the files; and
|
||||
|
||||
(c) You must retain, in the Source form of any Derivative Works
|
||||
that You distribute, all copyright, patent, trademark, and
|
||||
attribution notices from the Source form of the Work,
|
||||
excluding those notices that do not pertain to any part of
|
||||
the Derivative Works; and
|
||||
|
||||
(d) If the Work includes a "NOTICE" text file as part of its
|
||||
distribution, then any Derivative Works that You distribute must
|
||||
include a readable copy of the attribution notices contained
|
||||
within such NOTICE file, excluding those notices that do not
|
||||
pertain to any part of the Derivative Works, in at least one
|
||||
of the following places: within a NOTICE text file distributed
|
||||
as part of the Derivative Works; within the Source form or
|
||||
documentation, if provided along with the Derivative Works; or,
|
||||
within a display generated by the Derivative Works, if and
|
||||
wherever such third-party notices normally appear. The contents
|
||||
of the NOTICE file are for informational purposes only and
|
||||
do not modify the License. You may add Your own attribution
|
||||
notices within Derivative Works that You distribute, alongside
|
||||
or as an addendum to the NOTICE text from the Work, provided
|
||||
that such additional attribution notices cannot be construed
|
||||
as modifying the License.
|
||||
|
||||
You may add Your own copyright statement to Your modifications and
|
||||
may provide additional or different license terms and conditions
|
||||
for use, reproduction, or distribution of Your modifications, or
|
||||
for any such Derivative Works as a whole, provided Your use,
|
||||
reproduction, and distribution of the Work otherwise complies with
|
||||
the conditions stated in this License.
|
||||
|
||||
5. Submission of Contributions. Unless You explicitly state otherwise,
|
||||
any Contribution intentionally submitted for inclusion in the Work
|
||||
by You to the Licensor shall be under the terms and conditions of
|
||||
this License, without any additional terms or conditions.
|
||||
Notwithstanding the above, nothing herein shall supersede or modify
|
||||
the terms of any separate license agreement you may have executed
|
||||
with Licensor regarding such Contributions.
|
||||
|
||||
6. Trademarks. This License does not grant permission to use the trade
|
||||
names, trademarks, service marks, or product names of the Licensor,
|
||||
except as required for reasonable and customary use in describing the
|
||||
origin of the Work and reproducing the content of the NOTICE file.
|
||||
|
||||
7. Disclaimer of Warranty. Unless required by applicable law or
|
||||
agreed to in writing, Licensor provides the Work (and each
|
||||
Contributor provides its Contributions) on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
|
||||
implied, including, without limitation, any warranties or conditions
|
||||
of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
|
||||
PARTICULAR PURPOSE. You are solely responsible for determining the
|
||||
appropriateness of using or redistributing the Work and assume any
|
||||
risks associated with Your exercise of permissions under this License.
|
||||
|
||||
8. Limitation of Liability. In no event and under no legal theory,
|
||||
whether in tort (including negligence), contract, or otherwise,
|
||||
unless required by applicable law (such as deliberate and grossly
|
||||
negligent acts) or agreed to in writing, shall any Contributor be
|
||||
liable to You for damages, including any direct, indirect, special,
|
||||
incidental, or consequential damages of any character arising as a
|
||||
result of this License or out of the use or inability to use the
|
||||
Work (including but not limited to damages for loss of goodwill,
|
||||
work stoppage, computer failure or malfunction, or any and all
|
||||
other commercial damages or losses), even if such Contributor
|
||||
has been advised of the possibility of such damages.
|
||||
|
||||
9. Accepting Warranty or Additional Liability. While redistributing
|
||||
the Work or Derivative Works thereof, You may choose to offer,
|
||||
and charge a fee for, acceptance of support, warranty, indemnity,
|
||||
or other liability obligations and/or rights consistent with this
|
||||
License. However, in accepting such obligations, You may act only
|
||||
on Your own behalf and on Your sole responsibility, not on behalf
|
||||
of any other Contributor, and only if You agree to indemnify,
|
||||
defend, and hold each Contributor harmless for any liability
|
||||
incurred by, or claims asserted against, such Contributor by reason
|
||||
of your accepting any such warranty or additional liability.
|
||||
|
||||
END OF TERMS AND CONDITIONS
|
||||
|
||||
Copyright 2022 Noel Buechler
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
34
packages/api-extractor-utils/README.md
Normal file
34
packages/api-extractor-utils/README.md
Normal file
@@ -0,0 +1,34 @@
|
||||
<div align="center">
|
||||
<br />
|
||||
<p>
|
||||
<a href="https://discord.js.org"><img src="https://discord.js.org/static/logo.svg" width="546" alt="discord.js" /></a>
|
||||
</p>
|
||||
<br />
|
||||
<p>
|
||||
<a href="https://discord.gg/djs"><img src="https://img.shields.io/discord/222078108977594368?color=5865F2&logo=discord&logoColor=white" alt="Discord server" /></a>
|
||||
<a href="https://github.com/discordjs/discord.js/actions"><img src="https://github.com/discordjs/discord.js/actions/workflows/test.yml/badge.svg" alt="Build status" /></a>
|
||||
</p>
|
||||
<p>
|
||||
<a href="https://vercel.com/?utm_source=discordjs&utm_campaign=oss"><img src="https://raw.githubusercontent.com/discordjs/discord.js/main/.github/powered-by-vercel.svg" alt="Vercel" /></a>
|
||||
</p>
|
||||
</div>
|
||||
|
||||
## Links
|
||||
|
||||
- [Website](https://discord.js.org/) ([source](https://github.com/discordjs/discord.js/tree/main/packages/website))
|
||||
- [Documentation](https://discord.js.org/#/docs)
|
||||
- [Guide](https://discordjs.guide/) ([source](https://github.com/discordjs/guide))
|
||||
See also the [Update Guide](https://discordjs.guide/additional-info/changes-in-v14.html), including updated and removed items in the library.
|
||||
- [discord.js Discord server](https://discord.gg/djs)
|
||||
- [Discord API Discord server](https://discord.gg/discord-api)
|
||||
- [GitHub](https://github.com/discordjs/discord.js/tree/main/packages/scripts)
|
||||
- [Related libraries](https://discord.com/developers/docs/topics/community-resources#libraries)
|
||||
|
||||
## Contributing
|
||||
|
||||
See [the contribution guide](https://github.com/discordjs/discord.js/blob/main/.github/CONTRIBUTING.md) if you'd like to submit a PR.
|
||||
|
||||
## Help
|
||||
|
||||
If you don't understand something in the documentation, you are experiencing problems, or you just need a gentle
|
||||
nudge in the right direction, please don't hesitate to join our official [discord.js Server](https://discord.gg/djs).
|
||||
52
packages/api-extractor-utils/package.json
Normal file
52
packages/api-extractor-utils/package.json
Normal file
@@ -0,0 +1,52 @@
|
||||
{
|
||||
"name": "@discordjs/api-extractor-utils",
|
||||
"version": "1.0.0",
|
||||
"description": "Utilities for api-extractor",
|
||||
"private": true,
|
||||
"scripts": {
|
||||
"build": "tsup",
|
||||
"lint": "prettier --check . && cross-env TIMING=1 eslint src --ext mjs,js,ts",
|
||||
"format": "prettier --write . && cross-env TIMING=1 eslint src --ext mjs,js,ts --fix",
|
||||
"fmt": "yarn format"
|
||||
},
|
||||
"main": "./dist/index.js",
|
||||
"module": "./dist/index.mjs",
|
||||
"types": "./dist/index.d.ts",
|
||||
"directories": {
|
||||
"lib": "src"
|
||||
},
|
||||
"files": [
|
||||
"dist"
|
||||
],
|
||||
"contributors": [
|
||||
"Suneet Tipirneni <suneettipirneni@icloud.com>"
|
||||
],
|
||||
"license": "Apache-2.0",
|
||||
"repository": {
|
||||
"type": "git",
|
||||
"url": "git+https://github.com/discordjs/discord.js.git"
|
||||
},
|
||||
"bugs": {
|
||||
"url": "https://github.com/discordjs/discord.js/issues"
|
||||
},
|
||||
"homepage": "https://discord.js.org",
|
||||
"dependencies": {
|
||||
"@microsoft/api-extractor-model": "7.24.0",
|
||||
"@microsoft/tsdoc": "0.14.1"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@types/node": "^16.11.60",
|
||||
"cross-env": "^7.0.3",
|
||||
"eslint": "^8.24.0",
|
||||
"eslint-config-neon": "^0.1.33",
|
||||
"prettier": "^2.7.1",
|
||||
"tsup": "^6.2.3",
|
||||
"typescript": "^4.8.3"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=16.9.0"
|
||||
},
|
||||
"publishConfig": {
|
||||
"access": "public"
|
||||
}
|
||||
}
|
||||
@@ -1,37 +1,30 @@
|
||||
import type { ApiReturnTypeMixin } from '@microsoft/api-extractor-model';
|
||||
import {
|
||||
ApiModel,
|
||||
type ApiModel,
|
||||
ApiDeclaredItem,
|
||||
ApiPropertyItem,
|
||||
ApiMethod,
|
||||
ApiParameterListMixin,
|
||||
ApiTypeParameterListMixin,
|
||||
ApiClass,
|
||||
ApiFunction,
|
||||
type ApiPropertyItem,
|
||||
type ApiMethod,
|
||||
type ApiParameterListMixin,
|
||||
type ApiTypeParameterListMixin,
|
||||
type ApiClass,
|
||||
type ApiFunction,
|
||||
ApiItemKind,
|
||||
ApiTypeAlias,
|
||||
ApiEnum,
|
||||
ApiInterface,
|
||||
ApiMethodSignature,
|
||||
ApiPropertySignature,
|
||||
ApiVariable,
|
||||
ApiItem,
|
||||
ApiConstructor,
|
||||
ApiItemContainerMixin,
|
||||
type ApiTypeAlias,
|
||||
type ApiEnum,
|
||||
type ApiInterface,
|
||||
type ApiMethodSignature,
|
||||
type ApiPropertySignature,
|
||||
type ApiVariable,
|
||||
type ApiItem,
|
||||
type ApiConstructor,
|
||||
type ApiItemContainerMixin,
|
||||
} from '@microsoft/api-extractor-model';
|
||||
import { generateTypeParamData } from './TypeParameterMixin';
|
||||
import { Visibility } from './Visibility';
|
||||
import { createCommentNode } from './comment';
|
||||
import type { DocBlockJSON } from './comment/CommentBlock';
|
||||
import type { AnyDocNodeJSON } from './comment/CommentNode';
|
||||
import { DocNodeContainerJSON, nodeContainer } from './comment/CommentNodeContainer';
|
||||
import {
|
||||
generatePath,
|
||||
genParameter,
|
||||
genReference,
|
||||
genToken,
|
||||
resolveName,
|
||||
TokenDocumentation,
|
||||
} from '~/util/parse.server';
|
||||
import { generateTypeParamData } from './TypeParameterJSONEncoder.js';
|
||||
import { type TokenDocumentation, resolveName, genReference, genToken, genParameter, generatePath } from './parse.js';
|
||||
import type { DocBlockJSON } from './tsdoc/CommentBlock.js';
|
||||
import type { AnyDocNodeJSON } from './tsdoc/CommentNode.js';
|
||||
import { type DocNodeContainerJSON, nodeContainer } from './tsdoc/CommentNodeContainer.js';
|
||||
import { createCommentNode } from './tsdoc/index.js';
|
||||
|
||||
export interface ReferenceData {
|
||||
name: string;
|
||||
@@ -39,9 +32,9 @@ export interface ReferenceData {
|
||||
}
|
||||
|
||||
export interface InheritanceData {
|
||||
parentKey: string;
|
||||
parentName: string;
|
||||
path: string;
|
||||
parentKey: string;
|
||||
}
|
||||
|
||||
export interface ApiInheritableJSON {
|
||||
@@ -49,23 +42,23 @@ export interface ApiInheritableJSON {
|
||||
}
|
||||
|
||||
export interface ApiItemJSON {
|
||||
kind: string;
|
||||
name: string;
|
||||
referenceData: ReferenceData;
|
||||
excerpt: string;
|
||||
excerptTokens: TokenDocumentation[];
|
||||
remarks: DocNodeContainerJSON | null;
|
||||
summary: DocNodeContainerJSON | null;
|
||||
deprecated: DocNodeContainerJSON | null;
|
||||
comment: AnyDocNodeJSON | null;
|
||||
containerKey: string;
|
||||
deprecated: DocNodeContainerJSON | null;
|
||||
excerpt: string;
|
||||
excerptTokens: TokenDocumentation[];
|
||||
kind: string;
|
||||
name: string;
|
||||
path: string[];
|
||||
referenceData: ReferenceData;
|
||||
remarks: DocNodeContainerJSON | null;
|
||||
summary: DocNodeContainerJSON | null;
|
||||
}
|
||||
|
||||
export interface ApiPropertyItemJSON extends ApiItemJSON, ApiInheritableJSON {
|
||||
optional: boolean;
|
||||
propertyTypeTokens: TokenDocumentation[];
|
||||
readonly: boolean;
|
||||
optional: boolean;
|
||||
}
|
||||
|
||||
export interface ApiTypeParameterListJSON {
|
||||
@@ -73,11 +66,11 @@ export interface ApiTypeParameterListJSON {
|
||||
}
|
||||
|
||||
export interface ApiTypeParameterJSON {
|
||||
name: string;
|
||||
commentBlock: DocBlockJSON | null;
|
||||
constraintTokens: TokenDocumentation[];
|
||||
defaultTokens: TokenDocumentation[];
|
||||
name: string;
|
||||
optional: boolean;
|
||||
commentBlock: DocBlockJSON | null;
|
||||
}
|
||||
|
||||
export interface ApiParameterListJSON {
|
||||
@@ -89,29 +82,31 @@ export interface ApiMethodSignatureJSON
|
||||
ApiTypeParameterListJSON,
|
||||
ApiParameterListJSON,
|
||||
ApiInheritableJSON {
|
||||
returnTypeTokens: TokenDocumentation[];
|
||||
mergedSiblings: ApiMethodSignatureJSON[];
|
||||
optional: boolean;
|
||||
overloadIndex: number;
|
||||
returnTypeTokens: TokenDocumentation[];
|
||||
}
|
||||
|
||||
export interface ApiMethodJSON extends ApiMethodSignatureJSON {
|
||||
mergedSiblings: ApiMethodJSON[];
|
||||
protected: boolean;
|
||||
static: boolean;
|
||||
visibility: Visibility;
|
||||
}
|
||||
|
||||
export interface ApiParameterJSON {
|
||||
name: string;
|
||||
isOptional: boolean;
|
||||
tokens: TokenDocumentation[];
|
||||
name: string;
|
||||
paramCommentBlock: DocBlockJSON | null;
|
||||
tokens: TokenDocumentation[];
|
||||
}
|
||||
|
||||
export interface ApiClassJSON extends ApiItemJSON, ApiTypeParameterListJSON {
|
||||
constructor: ApiConstructorJSON | null;
|
||||
properties: ApiPropertyItemJSON[];
|
||||
methods: ApiMethodJSON[];
|
||||
extendsTokens: TokenDocumentation[];
|
||||
implementsTokens: TokenDocumentation[][];
|
||||
methods: ApiMethodJSON[];
|
||||
properties: ApiPropertyItemJSON[];
|
||||
}
|
||||
|
||||
export interface ApiTypeAliasJSON extends ApiItemJSON, ApiTypeParameterListJSON {
|
||||
@@ -119,8 +114,8 @@ export interface ApiTypeAliasJSON extends ApiItemJSON, ApiTypeParameterListJSON
|
||||
}
|
||||
|
||||
export interface EnumMemberData {
|
||||
name: string;
|
||||
initializerTokens: TokenDocumentation[];
|
||||
name: string;
|
||||
summary: DocNodeContainerJSON | null;
|
||||
}
|
||||
|
||||
@@ -129,51 +124,55 @@ export interface ApiEnumJSON extends ApiItemJSON {
|
||||
}
|
||||
|
||||
export interface ApiInterfaceJSON extends ApiItemJSON, ApiTypeParameterListJSON {
|
||||
properties: ApiPropertyItemJSON[];
|
||||
methods: ApiMethodSignatureJSON[];
|
||||
extendsTokens: TokenDocumentation[][] | null;
|
||||
methods: ApiMethodSignatureJSON[];
|
||||
properties: ApiPropertyItemJSON[];
|
||||
}
|
||||
|
||||
export interface ApiVariableJSON extends ApiItemJSON {
|
||||
typeTokens: TokenDocumentation[];
|
||||
readonly: boolean;
|
||||
typeTokens: TokenDocumentation[];
|
||||
}
|
||||
|
||||
export interface ApiFunctionJSON extends ApiItemJSON, ApiTypeParameterListJSON, ApiParameterListJSON {
|
||||
returnTypeTokens: TokenDocumentation[];
|
||||
mergedSiblings: ApiFunctionJSON[];
|
||||
overloadIndex: number;
|
||||
returnTypeTokens: TokenDocumentation[];
|
||||
}
|
||||
|
||||
export interface ApiConstructorJSON extends ApiItemJSON, ApiParameterListJSON {
|
||||
protected: boolean;
|
||||
}
|
||||
|
||||
// eslint-disable-next-line @typescript-eslint/no-extraneous-class
|
||||
export type FunctionLike = ApiDeclaredItem & ApiParameterListMixin & ApiReturnTypeMixin & ApiTypeParameterListMixin;
|
||||
|
||||
export class ApiNodeJSONEncoder {
|
||||
public static encode(model: ApiModel, node: ApiItem) {
|
||||
public static encode(model: ApiModel, node: ApiItem, version: string) {
|
||||
if (!(node instanceof ApiDeclaredItem)) {
|
||||
throw new Error(`Cannot serialize node of type ${node.kind}`);
|
||||
console.log(`Cannot serialize node of type ${node.kind}`);
|
||||
return undefined;
|
||||
}
|
||||
|
||||
switch (node.kind) {
|
||||
case ApiItemKind.Class:
|
||||
return this.encodeClass(model, node as ApiClass);
|
||||
return this.encodeClass(model, node as ApiClass, version);
|
||||
case ApiItemKind.Function:
|
||||
return this.encodeFunction(model, node as ApiFunction);
|
||||
return this.encodeFunction(model, node as ApiFunction, version);
|
||||
case ApiItemKind.Interface:
|
||||
return this.encodeInterface(model, node as ApiInterface);
|
||||
return this.encodeInterface(model, node as ApiInterface, version);
|
||||
case ApiItemKind.TypeAlias:
|
||||
return this.encodeTypeAlias(model, node as ApiTypeAlias);
|
||||
return this.encodeTypeAlias(model, node as ApiTypeAlias, version);
|
||||
case ApiItemKind.Enum:
|
||||
return this.encodeEnum(model, node as ApiEnum);
|
||||
return this.encodeEnum(model, node as ApiEnum, version);
|
||||
case ApiItemKind.Variable:
|
||||
return this.encodeVariable(model, node as ApiVariable);
|
||||
return this.encodeVariable(model, node as ApiVariable, version);
|
||||
default:
|
||||
throw new Error(`Unknown API item kind: ${node.kind}`);
|
||||
// console.log(`Unknown API item kind: ${node.kind}`);
|
||||
return undefined;
|
||||
}
|
||||
}
|
||||
|
||||
public static encodeItem(model: ApiModel, item: ApiDeclaredItem): ApiItemJSON {
|
||||
public static encodeItem(model: ApiModel, item: ApiDeclaredItem, version: string): ApiItemJSON {
|
||||
const path = [];
|
||||
for (const _item of item.getHierarchy()) {
|
||||
switch (_item.kind) {
|
||||
@@ -189,36 +188,41 @@ export class ApiNodeJSONEncoder {
|
||||
return {
|
||||
kind: item.kind,
|
||||
name: resolveName(item),
|
||||
referenceData: genReference(item),
|
||||
referenceData: genReference(item, version),
|
||||
excerpt: item.excerpt.text,
|
||||
excerptTokens: item.excerpt.spannedTokens.map((token) => genToken(model, token)),
|
||||
excerptTokens: item.excerpt.spannedTokens.map((token) => genToken(model, token, version)),
|
||||
remarks: item.tsdocComment?.remarksBlock
|
||||
? (createCommentNode(item.tsdocComment.remarksBlock, model, item.parent) as DocNodeContainerJSON)
|
||||
? (createCommentNode(item.tsdocComment.remarksBlock, model, version, item.parent) as DocNodeContainerJSON)
|
||||
: null,
|
||||
summary: item.tsdocComment?.summarySection
|
||||
? (createCommentNode(item.tsdocComment.summarySection, model, item.parent) as DocNodeContainerJSON)
|
||||
? (createCommentNode(item.tsdocComment.summarySection, model, version, item.parent) as DocNodeContainerJSON)
|
||||
: null,
|
||||
deprecated: item.tsdocComment?.deprecatedBlock
|
||||
? (createCommentNode(item.tsdocComment.deprecatedBlock, model, item.parent) as DocNodeContainerJSON)
|
||||
? (createCommentNode(item.tsdocComment.deprecatedBlock, model, version, item.parent) as DocNodeContainerJSON)
|
||||
: null,
|
||||
path,
|
||||
containerKey: item.containerKey,
|
||||
comment: item.tsdocComment ? createCommentNode(item.tsdocComment, model, item.parent) : null,
|
||||
comment: item.tsdocComment ? createCommentNode(item.tsdocComment, model, version, item.parent) : null,
|
||||
};
|
||||
}
|
||||
|
||||
public static encodeParameterList(
|
||||
model: ApiModel,
|
||||
item: ApiParameterListMixin & ApiDeclaredItem,
|
||||
item: ApiDeclaredItem & ApiParameterListMixin,
|
||||
version: string,
|
||||
): { parameters: ApiParameterJSON[] } {
|
||||
return {
|
||||
parameters: item.parameters.map((param) => genParameter(model, param)),
|
||||
parameters: item.parameters.map((param) => genParameter(model, param, version)),
|
||||
};
|
||||
}
|
||||
|
||||
public static encodeTypeParameterList(model: ApiModel, item: ApiTypeParameterListMixin & ApiDeclaredItem) {
|
||||
public static encodeTypeParameterList(
|
||||
model: ApiModel,
|
||||
item: ApiDeclaredItem & ApiTypeParameterListMixin,
|
||||
version: string,
|
||||
): ApiTypeParameterListJSON {
|
||||
return {
|
||||
typeParameters: item.typeParameters.map((param) => generateTypeParamData(model, param, item.parent)),
|
||||
typeParameters: item.typeParameters.map((param) => generateTypeParamData(model, param, version, item.parent)),
|
||||
};
|
||||
}
|
||||
|
||||
@@ -226,60 +230,90 @@ export class ApiNodeJSONEncoder {
|
||||
model: ApiModel,
|
||||
item: ApiPropertyItem,
|
||||
parent: ApiItemContainerMixin,
|
||||
version: string,
|
||||
): ApiPropertyItemJSON {
|
||||
return {
|
||||
...this.encodeItem(model, item),
|
||||
...this.encodeInheritanceData(item, parent),
|
||||
propertyTypeTokens: item.propertyTypeExcerpt.spannedTokens.map((token) => genToken(model, token)),
|
||||
...this.encodeItem(model, item, version),
|
||||
...this.encodeInheritanceData(item, parent, version),
|
||||
propertyTypeTokens: item.propertyTypeExcerpt.spannedTokens.map((token) => genToken(model, token, version)),
|
||||
readonly: item.isReadonly,
|
||||
optional: item.isOptional,
|
||||
};
|
||||
}
|
||||
|
||||
public static encodeInheritanceData(item: ApiDeclaredItem, parent: ApiItemContainerMixin): ApiInheritableJSON {
|
||||
public static encodeInheritanceData(
|
||||
item: ApiDeclaredItem,
|
||||
parent: ApiItemContainerMixin,
|
||||
version: string,
|
||||
): ApiInheritableJSON {
|
||||
return {
|
||||
inheritanceData:
|
||||
item.parent && item.parent.containerKey !== parent.containerKey
|
||||
? {
|
||||
parentKey: item.parent.containerKey,
|
||||
parentName: item.parent.displayName,
|
||||
path: generatePath(item.parent.getHierarchy()),
|
||||
path: generatePath(item.parent.getHierarchy(), version),
|
||||
}
|
||||
: null,
|
||||
};
|
||||
}
|
||||
|
||||
public static encodeFunction(model: ApiModel, item: ApiFunction) {
|
||||
public static encodeFunctionLike(model: ApiModel, item: FunctionLike, version: string) {
|
||||
return {
|
||||
...this.encodeItem(model, item),
|
||||
...this.encodeParameterList(model, item),
|
||||
...this.encodeTypeParameterList(model, item),
|
||||
returnTypeTokens: item.returnTypeExcerpt.spannedTokens.map((token) => genToken(model, token)),
|
||||
...this.encodeItem(model, item, version),
|
||||
...this.encodeParameterList(model, item, version),
|
||||
...this.encodeTypeParameterList(model, item, version),
|
||||
returnTypeTokens: item.returnTypeExcerpt.spannedTokens.map((token) => genToken(model, token, version)),
|
||||
overloadIndex: item.overloadIndex,
|
||||
};
|
||||
}
|
||||
|
||||
public static encodeFunction(model: ApiModel, item: FunctionLike, version: string, nested = false): ApiFunctionJSON {
|
||||
return {
|
||||
...this.encodeFunctionLike(model, item, version),
|
||||
mergedSiblings: nested
|
||||
? []
|
||||
: item.getMergedSiblings().map((item) => this.encodeFunction(model, item as ApiFunction, version, true)),
|
||||
};
|
||||
}
|
||||
|
||||
public static encodeMethodSignature(
|
||||
model: ApiModel,
|
||||
item: ApiMethodSignature,
|
||||
parent: ApiItemContainerMixin,
|
||||
version: string,
|
||||
nested = false,
|
||||
): ApiMethodSignatureJSON {
|
||||
return {
|
||||
...this.encodeFunction(model, item),
|
||||
...this.encodeInheritanceData(item, parent),
|
||||
...this.encodeFunctionLike(model, item, version),
|
||||
...this.encodeInheritanceData(item, parent, version),
|
||||
optional: item.isOptional,
|
||||
mergedSiblings: nested
|
||||
? []
|
||||
: item
|
||||
.getMergedSiblings()
|
||||
.map((item) => this.encodeMethodSignature(model, item as ApiMethodSignature, parent, version, true)),
|
||||
};
|
||||
}
|
||||
|
||||
public static encodeMethod(model: ApiModel, item: ApiMethod, parent: ApiItemContainerMixin): ApiMethodJSON {
|
||||
public static encodeMethod(
|
||||
model: ApiModel,
|
||||
item: ApiMethod,
|
||||
parent: ApiItemContainerMixin,
|
||||
version: string,
|
||||
nested = false,
|
||||
): ApiMethodJSON {
|
||||
return {
|
||||
...this.encodeMethodSignature(model, item, parent),
|
||||
...this.encodeMethodSignature(model, item, parent, version),
|
||||
static: item.isStatic,
|
||||
visibility: item.isProtected ? Visibility.Protected : Visibility.Public,
|
||||
protected: item.isProtected,
|
||||
mergedSiblings: nested
|
||||
? []
|
||||
: item.getMergedSiblings().map((item) => this.encodeMethod(model, item as ApiMethod, parent, version, true)),
|
||||
};
|
||||
}
|
||||
|
||||
public static encodeClass(model: ApiModel, item: ApiClass): ApiClassJSON {
|
||||
public static encodeClass(model: ApiModel, item: ApiClass, version: string): ApiClassJSON {
|
||||
const extendsExcerpt = item.extendsType?.excerpt;
|
||||
|
||||
const methods: ApiMethodJSON[] = [];
|
||||
@@ -290,10 +324,10 @@ export class ApiNodeJSONEncoder {
|
||||
for (const member of item.findMembersWithInheritance().items) {
|
||||
switch (member.kind) {
|
||||
case ApiItemKind.Method:
|
||||
methods.push(this.encodeMethod(model, member as ApiMethod, item));
|
||||
methods.push(this.encodeMethod(model, member as ApiMethod, item, version));
|
||||
break;
|
||||
case ApiItemKind.Property:
|
||||
properties.push(this.encodeProperty(model, member as ApiPropertyItem, item));
|
||||
properties.push(this.encodeProperty(model, member as ApiPropertyItem, item, version));
|
||||
break;
|
||||
case ApiItemKind.Constructor:
|
||||
constructor = member as ApiConstructor;
|
||||
@@ -304,48 +338,49 @@ export class ApiNodeJSONEncoder {
|
||||
}
|
||||
|
||||
return {
|
||||
...this.encodeItem(model, item),
|
||||
...this.encodeTypeParameterList(model, item),
|
||||
constructor: constructor ? this.encodeConstructor(model, constructor) : null,
|
||||
extendsTokens: extendsExcerpt ? extendsExcerpt.spannedTokens.map((token) => genToken(model, token)) : [],
|
||||
...this.encodeItem(model, item, version),
|
||||
...this.encodeTypeParameterList(model, item, version),
|
||||
constructor: constructor ? this.encodeConstructor(model, constructor, version) : null,
|
||||
extendsTokens: extendsExcerpt ? extendsExcerpt.spannedTokens.map((token) => genToken(model, token, version)) : [],
|
||||
implementsTokens: item.implementsTypes.map((excerpt) =>
|
||||
excerpt.excerpt.spannedTokens.map((token) => genToken(model, token)),
|
||||
excerpt.excerpt.spannedTokens.map((token) => genToken(model, token, version)),
|
||||
),
|
||||
methods,
|
||||
properties,
|
||||
};
|
||||
}
|
||||
|
||||
public static encodeTypeAlias(model: ApiModel, item: ApiTypeAlias): ApiTypeAliasJSON {
|
||||
public static encodeTypeAlias(model: ApiModel, item: ApiTypeAlias, version: string): ApiTypeAliasJSON {
|
||||
return {
|
||||
...this.encodeItem(model, item),
|
||||
...this.encodeTypeParameterList(model, item),
|
||||
typeTokens: item.typeExcerpt.spannedTokens.map((token) => genToken(model, token)),
|
||||
...this.encodeItem(model, item, version),
|
||||
...this.encodeTypeParameterList(model, item, version),
|
||||
typeTokens: item.typeExcerpt.spannedTokens.map((token) => genToken(model, token, version)),
|
||||
};
|
||||
}
|
||||
|
||||
public static encodeEnum(model: ApiModel, item: ApiEnum): ApiEnumJSON {
|
||||
public static encodeEnum(model: ApiModel, item: ApiEnum, version: string): ApiEnumJSON {
|
||||
return {
|
||||
...this.encodeItem(model, item),
|
||||
...this.encodeItem(model, item, version),
|
||||
members: item.members.map((member) => ({
|
||||
name: member.name,
|
||||
initializerTokens: member.initializerExcerpt?.spannedTokens.map((token) => genToken(model, token)) ?? [],
|
||||
summary: member.tsdocComment ? nodeContainer(member.tsdocComment.summarySection, model, member) : null,
|
||||
initializerTokens:
|
||||
member.initializerExcerpt?.spannedTokens.map((token) => genToken(model, token, version)) ?? [],
|
||||
summary: member.tsdocComment ? nodeContainer(member.tsdocComment.summarySection, model, version, member) : null,
|
||||
})),
|
||||
};
|
||||
}
|
||||
|
||||
public static encodeInterface(model: ApiModel, item: ApiInterface): ApiInterfaceJSON {
|
||||
public static encodeInterface(model: ApiModel, item: ApiInterface, version: string): ApiInterfaceJSON {
|
||||
const methods: ApiMethodSignatureJSON[] = [];
|
||||
const properties: ApiPropertyItemJSON[] = [];
|
||||
|
||||
for (const member of item.findMembersWithInheritance().items) {
|
||||
switch (member.kind) {
|
||||
case ApiItemKind.MethodSignature:
|
||||
methods.push(this.encodeMethodSignature(model, member as ApiMethodSignature, item));
|
||||
methods.push(this.encodeMethodSignature(model, member as ApiMethodSignature, item, version));
|
||||
break;
|
||||
case ApiItemKind.PropertySignature:
|
||||
properties.push(this.encodeProperty(model, member as ApiPropertySignature, item));
|
||||
properties.push(this.encodeProperty(model, member as ApiPropertySignature, item, version));
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
@@ -353,28 +388,28 @@ export class ApiNodeJSONEncoder {
|
||||
}
|
||||
|
||||
return {
|
||||
...this.encodeItem(model, item),
|
||||
...this.encodeTypeParameterList(model, item),
|
||||
...this.encodeItem(model, item, version),
|
||||
...this.encodeTypeParameterList(model, item, version),
|
||||
extendsTokens: item.extendsTypes.map((excerpt) =>
|
||||
excerpt.excerpt.spannedTokens.map((token) => genToken(model, token)),
|
||||
excerpt.excerpt.spannedTokens.map((token) => genToken(model, token, version)),
|
||||
),
|
||||
methods,
|
||||
properties,
|
||||
};
|
||||
}
|
||||
|
||||
public static encodeVariable(model: ApiModel, item: ApiVariable): ApiVariableJSON {
|
||||
public static encodeVariable(model: ApiModel, item: ApiVariable, version: string): ApiVariableJSON {
|
||||
return {
|
||||
...this.encodeItem(model, item),
|
||||
typeTokens: item.variableTypeExcerpt.spannedTokens.map((token) => genToken(model, token)),
|
||||
...this.encodeItem(model, item, version),
|
||||
typeTokens: item.variableTypeExcerpt.spannedTokens.map((token) => genToken(model, token, version)),
|
||||
readonly: item.isReadonly,
|
||||
};
|
||||
}
|
||||
|
||||
public static encodeConstructor(model: ApiModel, item: ApiConstructor): ApiConstructorJSON {
|
||||
public static encodeConstructor(model: ApiModel, item: ApiConstructor, version: string): ApiConstructorJSON {
|
||||
return {
|
||||
...this.encodeItem(model, item),
|
||||
...this.encodeParameterList(model, item),
|
||||
...this.encodeItem(model, item, version),
|
||||
...this.encodeParameterList(model, item, version),
|
||||
protected: item.isProtected,
|
||||
};
|
||||
}
|
||||
@@ -1,28 +1,31 @@
|
||||
import type { ApiItem, ApiModel, TypeParameter } from '@microsoft/api-extractor-model';
|
||||
import { block, DocBlockJSON } from './comment/CommentBlock';
|
||||
import { genToken, TokenDocumentation } from '~/util/parse.server';
|
||||
import type { TypeParameter, ApiModel, ApiItem } from '@microsoft/api-extractor-model';
|
||||
import { type TokenDocumentation, genToken } from './parse.js';
|
||||
import { type DocBlockJSON, block } from './tsdoc/CommentBlock.js';
|
||||
|
||||
export interface TypeParameterData {
|
||||
name: string;
|
||||
commentBlock: DocBlockJSON | null;
|
||||
constraintTokens: TokenDocumentation[];
|
||||
defaultTokens: TokenDocumentation[];
|
||||
name: string;
|
||||
optional: boolean;
|
||||
commentBlock: DocBlockJSON | null;
|
||||
}
|
||||
|
||||
export function generateTypeParamData(
|
||||
model: ApiModel,
|
||||
typeParam: TypeParameter,
|
||||
version: string,
|
||||
parentItem?: ApiItem,
|
||||
): TypeParameterData {
|
||||
const constraintTokens = typeParam.constraintExcerpt.spannedTokens.map((token) => genToken(model, token));
|
||||
const defaultTokens = typeParam.defaultTypeExcerpt.spannedTokens.map((token) => genToken(model, token));
|
||||
const constraintTokens = typeParam.constraintExcerpt.spannedTokens.map((token) => genToken(model, token, version));
|
||||
const defaultTokens = typeParam.defaultTypeExcerpt.spannedTokens.map((token) => genToken(model, token, version));
|
||||
|
||||
return {
|
||||
name: typeParam.name,
|
||||
constraintTokens,
|
||||
defaultTokens,
|
||||
optional: typeParam.isOptional,
|
||||
commentBlock: typeParam.tsdocTypeParamBlock ? block(typeParam.tsdocTypeParamBlock, model, parentItem) : null,
|
||||
commentBlock: typeParam.tsdocTypeParamBlock
|
||||
? block(typeParam.tsdocTypeParamBlock, model, version, parentItem)
|
||||
: null,
|
||||
};
|
||||
}
|
||||
4
packages/api-extractor-utils/src/index.ts
Normal file
4
packages/api-extractor-utils/src/index.ts
Normal file
@@ -0,0 +1,4 @@
|
||||
export * from './ApiNodeJSONEncoder.js';
|
||||
export * from './parse.js';
|
||||
export * from './tsdoc/index.js';
|
||||
export * from './TypeParameterJSONEncoder.js';
|
||||
@@ -10,12 +10,12 @@ import {
|
||||
type ApiPropertyItem,
|
||||
type ExcerptToken,
|
||||
type Parameter,
|
||||
ApiFunction,
|
||||
type ApiFunction,
|
||||
} from '@microsoft/api-extractor-model';
|
||||
import type { DocNode, DocParagraph, DocPlainText } from '@microsoft/tsdoc';
|
||||
import { Meaning, ModuleSource } from '@microsoft/tsdoc/lib-commonjs/beta/DeclarationReference';
|
||||
import { createCommentNode } from '~/DocModel/comment';
|
||||
import type { DocBlockJSON } from '~/DocModel/comment/CommentBlock';
|
||||
import { type Meaning, ModuleSource } from '@microsoft/tsdoc/lib-commonjs/beta/DeclarationReference';
|
||||
import type { DocBlockJSON } from './tsdoc/CommentBlock.js';
|
||||
import { createCommentNode } from './tsdoc/index.js';
|
||||
|
||||
export function findPackage(model: ApiModel, name: string): ApiPackage | undefined {
|
||||
return (model.findMembersByName(name)[0] ?? model.findMembersByName(`@discordjs/${name}`)[0]) as
|
||||
@@ -23,8 +23,9 @@ export function findPackage(model: ApiModel, name: string): ApiPackage | undefin
|
||||
| undefined;
|
||||
}
|
||||
|
||||
export function generatePath(items: readonly ApiItem[]) {
|
||||
let path = '/docs/main/packages';
|
||||
export function generatePath(items: readonly ApiItem[], version: string) {
|
||||
let path = '/docs/packages';
|
||||
|
||||
for (const item of items) {
|
||||
switch (item.kind) {
|
||||
case ApiItemKind.Model:
|
||||
@@ -39,7 +40,7 @@ export function generatePath(items: readonly ApiItem[]) {
|
||||
const functionItem = item as ApiFunction;
|
||||
path += `/${functionItem.displayName}${
|
||||
functionItem.overloadIndex && functionItem.overloadIndex > 1 ? `:${functionItem.overloadIndex}` : ''
|
||||
}`;
|
||||
}:${item.kind}`;
|
||||
break;
|
||||
case ApiItemKind.Property:
|
||||
case ApiItemKind.Method:
|
||||
@@ -49,11 +50,12 @@ export function generatePath(items: readonly ApiItem[]) {
|
||||
path += `#${item.displayName}`;
|
||||
break;
|
||||
default:
|
||||
path += `/${item.displayName}`;
|
||||
path += `/${item.displayName}:${item.kind}`;
|
||||
}
|
||||
}
|
||||
|
||||
return path.replace(/@discordjs\//, '');
|
||||
// eslint-disable-next-line prefer-named-capture-group, unicorn/no-unsafe-regex
|
||||
return path.replace(/@discordjs\/(.*)\/(.*)?/, `$1/${version}/$2`);
|
||||
}
|
||||
|
||||
export function resolveDocComment(item: ApiDocumentedItem) {
|
||||
@@ -69,26 +71,22 @@ export function resolveDocComment(item: ApiDocumentedItem) {
|
||||
|
||||
const { summarySection } = tsdocComment;
|
||||
|
||||
function recurseNodes(nodes: readonly DocNode[] | undefined): string | null {
|
||||
if (!nodes) {
|
||||
function recurseNodes(node: DocNode | undefined): string | null {
|
||||
if (!node) {
|
||||
return null;
|
||||
}
|
||||
|
||||
for (const node of nodes) {
|
||||
switch (node.kind) {
|
||||
case 'Paragraph':
|
||||
return recurseNodes((node as DocParagraph).nodes);
|
||||
case 'PlainText':
|
||||
return (node as DocPlainText).text;
|
||||
default:
|
||||
return null;
|
||||
}
|
||||
switch (node.kind) {
|
||||
case 'Paragraph':
|
||||
return recurseNodes(node as DocParagraph);
|
||||
case 'PlainText':
|
||||
return (node as DocPlainText).text;
|
||||
default:
|
||||
return null;
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
return recurseNodes(summarySection.nodes);
|
||||
return recurseNodes(summarySection);
|
||||
}
|
||||
|
||||
export function findReferences(model: ApiModel, excerpt: Excerpt) {
|
||||
@@ -106,6 +104,7 @@ export function findReferences(model: ApiModel, excerpt: Excerpt) {
|
||||
|
||||
break;
|
||||
}
|
||||
|
||||
default:
|
||||
break;
|
||||
}
|
||||
@@ -141,16 +140,16 @@ export function getProperties(item: ApiItem) {
|
||||
}
|
||||
|
||||
export interface TokenDocumentation {
|
||||
text: string;
|
||||
path: string | null;
|
||||
kind: string;
|
||||
path: string | null;
|
||||
text: string;
|
||||
}
|
||||
|
||||
export interface ParameterDocumentation {
|
||||
name: string;
|
||||
isOptional: boolean;
|
||||
tokens: TokenDocumentation[];
|
||||
name: string;
|
||||
paramCommentBlock: DocBlockJSON | null;
|
||||
tokens: TokenDocumentation[];
|
||||
}
|
||||
|
||||
function createDapiTypesURL(meaning: Meaning, name: string) {
|
||||
@@ -164,16 +163,16 @@ function createDapiTypesURL(meaning: Meaning, name: string) {
|
||||
}
|
||||
}
|
||||
|
||||
export function genReference(item: ApiItem) {
|
||||
export function genReference(item: ApiItem, version: string) {
|
||||
return {
|
||||
name: resolveName(item),
|
||||
path: generatePath(item.getHierarchy()),
|
||||
path: generatePath(item.getHierarchy(), version),
|
||||
};
|
||||
}
|
||||
|
||||
export function genToken(model: ApiModel, token: ExcerptToken) {
|
||||
export function genToken(model: ApiModel, token: ExcerptToken, version: string) {
|
||||
if (token.canonicalReference) {
|
||||
// @ts-expect-error
|
||||
// @ts-expect-error: Symbol is not publicly accessible
|
||||
token.canonicalReference._navigation = '.';
|
||||
}
|
||||
|
||||
@@ -197,24 +196,26 @@ export function genToken(model: ApiModel, token: ExcerptToken) {
|
||||
return {
|
||||
kind: token.kind,
|
||||
text: token.text,
|
||||
path: item ? generatePath(item.getHierarchy()) : null,
|
||||
path: item ? generatePath(item.getHierarchy(), version) : null,
|
||||
};
|
||||
}
|
||||
|
||||
export function genParameter(model: ApiModel, param: Parameter): ParameterDocumentation {
|
||||
export function genParameter(model: ApiModel, param: Parameter, version: string): ParameterDocumentation {
|
||||
return {
|
||||
name: param.name,
|
||||
isOptional: param.isOptional,
|
||||
tokens: param.parameterTypeExcerpt.spannedTokens.map((token) => genToken(model, token)),
|
||||
paramCommentBlock: param.tsdocParamBlock ? (createCommentNode(param.tsdocParamBlock, model) as DocBlockJSON) : null,
|
||||
tokens: param.parameterTypeExcerpt.spannedTokens.map((token) => genToken(model, token, version)),
|
||||
paramCommentBlock: param.tsdocParamBlock
|
||||
? (createCommentNode(param.tsdocParamBlock, model, version) as DocBlockJSON)
|
||||
: null,
|
||||
};
|
||||
}
|
||||
|
||||
export function getMembers(pkg: ApiPackage) {
|
||||
export function getMembers(pkg: ApiPackage, version: string) {
|
||||
return pkg.members[0]!.members.map((member) => ({
|
||||
name: member.displayName,
|
||||
kind: member.kind as string,
|
||||
path: generatePath(member.getHierarchy()),
|
||||
path: generatePath(member.getHierarchy(), version),
|
||||
containerKey: member.containerKey,
|
||||
overloadIndex: member.kind === 'Function' ? (member as ApiFunction).overloadIndex : null,
|
||||
}));
|
||||
@@ -1,18 +1,18 @@
|
||||
import type { ApiModel, ApiItem } from '@microsoft/api-extractor-model';
|
||||
import type { DocBlock } from '@microsoft/tsdoc';
|
||||
import { blockTag, type DocBlockTagJSON } from './CommentBlockTag.js';
|
||||
import { type AnyDocNodeJSON, type DocNodeJSON, node } from './CommentNode.js';
|
||||
import { createCommentNode } from '.';
|
||||
import { blockTag, DocBlockTagJSON } from './CommentBlockTag';
|
||||
import { AnyDocNodeJSON, DocNodeJSON, node } from './CommentNode';
|
||||
|
||||
export interface DocBlockJSON extends DocNodeJSON {
|
||||
content: AnyDocNodeJSON[];
|
||||
tag: DocBlockTagJSON;
|
||||
}
|
||||
|
||||
export function block(block: DocBlock, model: ApiModel, parentItem?: ApiItem) {
|
||||
export function block(block: DocBlock, model: ApiModel, version: string, parentItem?: ApiItem) {
|
||||
return {
|
||||
...node(block),
|
||||
content: block.content.nodes.map((node) => createCommentNode(node, model, parentItem)),
|
||||
content: block.content.nodes.map((node) => createCommentNode(node, model, version, parentItem)),
|
||||
tag: blockTag(block.blockTag),
|
||||
};
|
||||
}
|
||||
@@ -1,5 +1,5 @@
|
||||
import type { DocBlockTag } from '@microsoft/tsdoc';
|
||||
import { type DocNodeJSON, node } from './CommentNode';
|
||||
import { type DocNodeJSON, node } from './CommentNode.js';
|
||||
|
||||
export interface DocBlockTagJSON extends DocNodeJSON {
|
||||
tagName: string;
|
||||
@@ -1,5 +1,5 @@
|
||||
import type { DocCodeSpan } from '@microsoft/tsdoc';
|
||||
import { DocNodeJSON, node } from './CommentNode';
|
||||
import { type DocNodeJSON, node } from './CommentNode.js';
|
||||
|
||||
export interface DocCodeSpanJSON extends DocNodeJSON {
|
||||
code: string;
|
||||
@@ -1,25 +1,25 @@
|
||||
import type { DocNode, DocNodeKind } from '@microsoft/tsdoc';
|
||||
import type { DocBlockJSON } from './CommentBlock';
|
||||
import type { DocCodeSpanJSON } from './CommentCodeSpan';
|
||||
import type { DocNodeContainerJSON } from './CommentNodeContainer';
|
||||
import type { DocFencedCodeJSON } from './FencedCodeCommentNode';
|
||||
import type { DocLinkTagJSON } from './LinkTagCommentNode';
|
||||
import type { DocPlainTextJSON } from './PlainTextCommentNode';
|
||||
import type { DocCommentJSON } from './RootComment';
|
||||
import type { DocBlockJSON } from './CommentBlock.js';
|
||||
import type { DocCodeSpanJSON } from './CommentCodeSpan.js';
|
||||
import type { DocNodeContainerJSON } from './CommentNodeContainer.js';
|
||||
import type { DocFencedCodeJSON } from './FencedCodeCommentNode.js';
|
||||
import type { DocLinkTagJSON } from './LinkTagCommentNode.js';
|
||||
import type { DocPlainTextJSON } from './PlainTextCommentNode.js';
|
||||
import type { DocCommentJSON } from './RootComment.js';
|
||||
|
||||
export interface DocNodeJSON {
|
||||
kind: DocNodeKind;
|
||||
}
|
||||
|
||||
export type AnyDocNodeJSON =
|
||||
| DocNodeJSON
|
||||
| DocPlainTextJSON
|
||||
| DocNodeContainerJSON
|
||||
| DocLinkTagJSON
|
||||
| DocFencedCodeJSON
|
||||
| DocBlockJSON
|
||||
| DocCodeSpanJSON
|
||||
| DocCommentJSON
|
||||
| DocCodeSpanJSON;
|
||||
| DocFencedCodeJSON
|
||||
| DocLinkTagJSON
|
||||
| DocNodeContainerJSON
|
||||
| DocNodeJSON
|
||||
| DocPlainTextJSON;
|
||||
|
||||
export function node(node: DocNode): DocNodeJSON {
|
||||
return {
|
||||
@@ -1,7 +1,7 @@
|
||||
import type { ApiItem, ApiModel } from '@microsoft/api-extractor-model';
|
||||
import type { DocNodeContainer } from '@microsoft/tsdoc';
|
||||
import { type AnyDocNodeJSON, type DocNodeJSON, node } from './CommentNode.js';
|
||||
import { createCommentNode } from '.';
|
||||
import { AnyDocNodeJSON, DocNodeJSON, node } from './CommentNode';
|
||||
|
||||
export interface DocNodeContainerJSON extends DocNodeJSON {
|
||||
nodes: AnyDocNodeJSON[];
|
||||
@@ -10,10 +10,11 @@ export interface DocNodeContainerJSON extends DocNodeJSON {
|
||||
export function nodeContainer(
|
||||
container: DocNodeContainer,
|
||||
model: ApiModel,
|
||||
version: string,
|
||||
parentItem?: ApiItem,
|
||||
): DocNodeContainerJSON {
|
||||
return {
|
||||
...node(container),
|
||||
nodes: container.nodes.map((node) => createCommentNode(node, model, parentItem)),
|
||||
nodes: container.nodes.map((node) => createCommentNode(node, model, version, parentItem)),
|
||||
};
|
||||
}
|
||||
@@ -1,5 +1,5 @@
|
||||
import type { DocFencedCode } from '@microsoft/tsdoc';
|
||||
import { DocNodeJSON, node } from './CommentNode';
|
||||
import { type DocNodeJSON, node } from './CommentNode.js';
|
||||
|
||||
export interface DocFencedCodeJSON extends DocNodeJSON {
|
||||
code: string;
|
||||
@@ -1,18 +1,25 @@
|
||||
import type { ApiItem, ApiModel } from '@microsoft/api-extractor-model';
|
||||
import type { DocDeclarationReference, DocLinkTag } from '@microsoft/tsdoc';
|
||||
import { DocNodeJSON, node } from './CommentNode';
|
||||
import { generatePath, resolveName } from '~/util/parse.server';
|
||||
import { resolveName, generatePath } from '../parse.js';
|
||||
import { type DocNodeJSON, node } from './CommentNode.js';
|
||||
|
||||
interface LinkTagCodeLink {
|
||||
kind: string;
|
||||
name: string;
|
||||
path: string;
|
||||
}
|
||||
|
||||
export interface DocLinkTagJSON extends DocNodeJSON {
|
||||
text: string | null;
|
||||
codeDestination: LinkTagCodeLink | null;
|
||||
text: string | null;
|
||||
urlDestination: string | null;
|
||||
}
|
||||
|
||||
export function genToken(
|
||||
export function genLinkToken(
|
||||
model: ApiModel,
|
||||
ref: DocDeclarationReference,
|
||||
context: ApiItem | null,
|
||||
version: string,
|
||||
): LinkTagCodeLink | null {
|
||||
const item = model.resolveDeclarationReference(ref, context ?? undefined).resolvedApiItem ?? null;
|
||||
|
||||
@@ -23,24 +30,23 @@ export function genToken(
|
||||
return {
|
||||
name: resolveName(item),
|
||||
kind: item.kind,
|
||||
path: generatePath(item.getHierarchy()),
|
||||
path: generatePath(item.getHierarchy(), version),
|
||||
};
|
||||
}
|
||||
|
||||
export interface LinkTagCodeLink {
|
||||
name: string;
|
||||
kind: string;
|
||||
path: string;
|
||||
}
|
||||
|
||||
export function linkTagNode(linkNode: DocLinkTag, model: ApiModel, parentItem?: ApiItem): DocLinkTagJSON {
|
||||
export function linkTagNode(
|
||||
linkNode: DocLinkTag,
|
||||
model: ApiModel,
|
||||
version: string,
|
||||
parentItem?: ApiItem,
|
||||
): DocLinkTagJSON {
|
||||
// If we weren't provided a parent object, fallback to the package entrypoint.
|
||||
const packageEntryPoint = linkNode.codeDestination?.importPath
|
||||
? model.getAssociatedPackage()?.findEntryPointsByPath(linkNode.codeDestination.importPath)[0]
|
||||
: null;
|
||||
|
||||
const codeDestination = linkNode.codeDestination
|
||||
? genToken(model, linkNode.codeDestination, parentItem ?? packageEntryPoint ?? null)
|
||||
? genLinkToken(model, linkNode.codeDestination, parentItem ?? packageEntryPoint ?? null, version)
|
||||
: null;
|
||||
const text = linkNode.linkText ?? null;
|
||||
const urlDestination = linkNode.urlDestination ?? null;
|
||||
19
packages/api-extractor-utils/src/tsdoc/ParamBlock.ts
Normal file
19
packages/api-extractor-utils/src/tsdoc/ParamBlock.ts
Normal file
@@ -0,0 +1,19 @@
|
||||
import type { ApiItem, ApiModel } from '@microsoft/api-extractor-model';
|
||||
import type { DocParamBlock } from '@microsoft/tsdoc';
|
||||
import { block, type DocBlockJSON } from './CommentBlock.js';
|
||||
|
||||
interface DocParamBlockJSON extends DocBlockJSON {
|
||||
name: string;
|
||||
}
|
||||
|
||||
export function paramBlock(
|
||||
paramBlock: DocParamBlock,
|
||||
model: ApiModel,
|
||||
version: string,
|
||||
parentItem?: ApiItem,
|
||||
): DocParamBlockJSON {
|
||||
return {
|
||||
...block(paramBlock, model, version, parentItem),
|
||||
name: paramBlock.parameterName,
|
||||
};
|
||||
}
|
||||
@@ -1,5 +1,5 @@
|
||||
import type { DocPlainText } from '@microsoft/tsdoc';
|
||||
import { DocNodeJSON, node } from './CommentNode';
|
||||
import { type DocNodeJSON, node } from './CommentNode.js';
|
||||
|
||||
export interface DocPlainTextJSON extends DocNodeJSON {
|
||||
text: string;
|
||||
24
packages/api-extractor-utils/src/tsdoc/RootComment.ts
Normal file
24
packages/api-extractor-utils/src/tsdoc/RootComment.ts
Normal file
@@ -0,0 +1,24 @@
|
||||
import type { ApiItem, ApiModel } from '@microsoft/api-extractor-model';
|
||||
import type { DocComment } from '@microsoft/tsdoc';
|
||||
import { block, type DocBlockJSON } from './CommentBlock.js';
|
||||
import { type DocNodeJSON, node } from './CommentNode.js';
|
||||
import { createCommentNode } from '.';
|
||||
|
||||
export interface DocCommentJSON extends DocNodeJSON {
|
||||
customBlocks: DocBlockJSON[];
|
||||
deprecated: DocNodeJSON[];
|
||||
remarks: DocNodeJSON[];
|
||||
summary: DocNodeJSON[];
|
||||
}
|
||||
|
||||
export function comment(comment: DocComment, model: ApiModel, version: string, parentItem?: ApiItem): DocCommentJSON {
|
||||
return {
|
||||
...node(comment),
|
||||
summary: comment.summarySection.nodes.map((node) => createCommentNode(node, model, version, parentItem)),
|
||||
remarks:
|
||||
comment.remarksBlock?.content.nodes.map((node) => createCommentNode(node, model, version, parentItem)) ?? [],
|
||||
deprecated:
|
||||
comment.deprecatedBlock?.content.nodes.map((node) => createCommentNode(node, model, version, parentItem)) ?? [],
|
||||
customBlocks: comment.customBlocks.map((_block) => block(_block, model, version, parentItem)),
|
||||
};
|
||||
}
|
||||
62
packages/api-extractor-utils/src/tsdoc/index.ts
Normal file
62
packages/api-extractor-utils/src/tsdoc/index.ts
Normal file
@@ -0,0 +1,62 @@
|
||||
import type { ApiModel, ApiItem } from '@microsoft/api-extractor-model';
|
||||
import {
|
||||
type DocNode,
|
||||
type DocPlainText,
|
||||
type DocLinkTag,
|
||||
type DocParagraph,
|
||||
type DocFencedCode,
|
||||
DocNodeKind,
|
||||
type DocBlock,
|
||||
type DocComment,
|
||||
type DocCodeSpan,
|
||||
type DocParamBlock,
|
||||
} from '@microsoft/tsdoc';
|
||||
import { block } from './CommentBlock.js';
|
||||
import { codeSpan } from './CommentCodeSpan.js';
|
||||
import { node as _node, type AnyDocNodeJSON } from './CommentNode.js';
|
||||
import { nodeContainer } from './CommentNodeContainer.js';
|
||||
import { fencedCode } from './FencedCodeCommentNode.js';
|
||||
import { linkTagNode } from './LinkTagCommentNode.js';
|
||||
import { paramBlock } from './ParamBlock.js';
|
||||
import { plainTextNode } from './PlainTextCommentNode.js';
|
||||
import { comment } from './RootComment.js';
|
||||
|
||||
export function createCommentNode(
|
||||
node: DocNode,
|
||||
model: ApiModel,
|
||||
version: string,
|
||||
parentItem?: ApiItem,
|
||||
): AnyDocNodeJSON {
|
||||
switch (node.kind) {
|
||||
case DocNodeKind.PlainText:
|
||||
return plainTextNode(node as DocPlainText);
|
||||
case DocNodeKind.LinkTag:
|
||||
return linkTagNode(node as DocLinkTag, model, version, parentItem);
|
||||
case DocNodeKind.Paragraph:
|
||||
case DocNodeKind.Section:
|
||||
return nodeContainer(node as DocParagraph, model, version, parentItem);
|
||||
case DocNodeKind.FencedCode:
|
||||
return fencedCode(node as DocFencedCode);
|
||||
case DocNodeKind.CodeSpan:
|
||||
return codeSpan(node as DocCodeSpan);
|
||||
case DocNodeKind.Block:
|
||||
return block(node as DocBlock, model, version, parentItem);
|
||||
case DocNodeKind.ParamBlock:
|
||||
return paramBlock(node as DocParamBlock, model, version, parentItem);
|
||||
case DocNodeKind.Comment:
|
||||
return comment(node as DocComment, model, version, parentItem);
|
||||
default:
|
||||
return _node(node);
|
||||
}
|
||||
}
|
||||
|
||||
export * from './CommentNode.js';
|
||||
export * from './CommentNodeContainer.js';
|
||||
export * from './CommentBlock.js';
|
||||
export * from './CommentBlockTag.js';
|
||||
export * from './CommentCodeSpan.js';
|
||||
export * from './FencedCodeCommentNode.js';
|
||||
export * from './LinkTagCommentNode.js';
|
||||
export * from './ParamBlock.js';
|
||||
export * from './PlainTextCommentNode.js';
|
||||
export * from './RootComment.js';
|
||||
20
packages/api-extractor-utils/tsconfig.eslint.json
Normal file
20
packages/api-extractor-utils/tsconfig.eslint.json
Normal file
@@ -0,0 +1,20 @@
|
||||
{
|
||||
"extends": "./tsconfig.json",
|
||||
"compilerOptions": {
|
||||
"allowJs": true
|
||||
},
|
||||
"include": [
|
||||
"**/*.ts",
|
||||
"**/*.tsx",
|
||||
"**/*.js",
|
||||
"**/*.mjs",
|
||||
"**/*.jsx",
|
||||
"**/*.test.ts",
|
||||
"**/*.test.js",
|
||||
"**/*.test.mjs",
|
||||
"**/*.spec.ts",
|
||||
"**/*.spec.js",
|
||||
"**/*.spec.mjs"
|
||||
],
|
||||
"exclude": []
|
||||
}
|
||||
8
packages/api-extractor-utils/tsconfig.json
Normal file
8
packages/api-extractor-utils/tsconfig.json
Normal file
@@ -0,0 +1,8 @@
|
||||
{
|
||||
"extends": "../../tsconfig.json",
|
||||
"compilerOptions": {
|
||||
"skipDefaultLibCheck": true,
|
||||
"skipLibCheck": true
|
||||
},
|
||||
"include": ["src/**/*.ts"]
|
||||
}
|
||||
5
packages/api-extractor-utils/tsup.config.js
Normal file
5
packages/api-extractor-utils/tsup.config.js
Normal file
@@ -0,0 +1,5 @@
|
||||
import { createTsupConfig } from '../../tsup.config.js';
|
||||
|
||||
export default createTsupConfig({
|
||||
minify: true,
|
||||
});
|
||||
@@ -1,7 +1,3 @@
|
||||
{
|
||||
"extends": "../../.eslintrc.json",
|
||||
"plugins": ["eslint-plugin-tsdoc"],
|
||||
"rules": {
|
||||
"tsdoc/syntax": "warn"
|
||||
}
|
||||
"extends": "../../.eslintrc.json"
|
||||
}
|
||||
|
||||
@@ -1,4 +1,9 @@
|
||||
import { APIActionRowComponent, APIMessageActionRowComponent, ButtonStyle, ComponentType } from 'discord-api-types/v10';
|
||||
import {
|
||||
ButtonStyle,
|
||||
ComponentType,
|
||||
type APIActionRowComponent,
|
||||
type APIMessageActionRowComponent,
|
||||
} from 'discord-api-types/v10';
|
||||
import { describe, test, expect } from 'vitest';
|
||||
import {
|
||||
ActionRowBuilder,
|
||||
@@ -6,7 +11,7 @@ import {
|
||||
createComponentBuilder,
|
||||
SelectMenuBuilder,
|
||||
SelectMenuOptionBuilder,
|
||||
} from '../../src';
|
||||
} from '../../src/index.js';
|
||||
|
||||
const rowWithButtonData: APIActionRowComponent<APIMessageActionRowComponent> = {
|
||||
type: ComponentType.ActionRow,
|
||||
|
||||
@@ -1,12 +1,12 @@
|
||||
import {
|
||||
APIButtonComponentWithCustomId,
|
||||
APIButtonComponentWithURL,
|
||||
ButtonStyle,
|
||||
ComponentType,
|
||||
type APIButtonComponentWithCustomId,
|
||||
type APIButtonComponentWithURL,
|
||||
} from 'discord-api-types/v10';
|
||||
import { describe, test, expect } from 'vitest';
|
||||
import { buttonLabelValidator, buttonStyleValidator } from '../../src/components/Assertions';
|
||||
import { ButtonBuilder } from '../../src/components/button/Button';
|
||||
import { buttonLabelValidator, buttonStyleValidator } from '../../src/components/Assertions.js';
|
||||
import { ButtonBuilder } from '../../src/components/button/Button.js';
|
||||
|
||||
const buttonComponent = () => new ButtonBuilder();
|
||||
|
||||
@@ -31,7 +31,7 @@ describe('Button Components', () => {
|
||||
expect(() => buttonStyleValidator.parse(ButtonStyle.Secondary)).not.toThrowError();
|
||||
});
|
||||
|
||||
test('GIVEN invalid style THEN validator does not throw', () => {
|
||||
test('GIVEN invalid style THEN validator does throw', () => {
|
||||
expect(() => buttonStyleValidator.parse(7)).toThrowError();
|
||||
});
|
||||
|
||||
@@ -71,7 +71,7 @@ describe('Button Components', () => {
|
||||
}).toThrowError();
|
||||
|
||||
expect(() => {
|
||||
// @ts-expect-error
|
||||
// @ts-expect-error: Invalid emoji
|
||||
const button = buttonComponent().setEmoji('test');
|
||||
button.toJSON();
|
||||
}).toThrowError();
|
||||
@@ -103,9 +103,9 @@ describe('Button Components', () => {
|
||||
|
||||
expect(() => buttonComponent().setStyle(24)).toThrowError();
|
||||
expect(() => buttonComponent().setLabel(longStr)).toThrowError();
|
||||
// @ts-expect-error
|
||||
// @ts-expect-error: Invalid parameter for disabled
|
||||
expect(() => buttonComponent().setDisabled(0)).toThrowError();
|
||||
// @ts-expect-error
|
||||
// @ts-expect-error: Invalid emoji
|
||||
expect(() => buttonComponent().setEmoji('foo')).toThrowError();
|
||||
|
||||
expect(() => buttonComponent().setURL('foobar')).toThrowError();
|
||||
|
||||
@@ -1,12 +1,12 @@
|
||||
import {
|
||||
APIActionRowComponent,
|
||||
APIButtonComponent,
|
||||
APIMessageActionRowComponent,
|
||||
APISelectMenuComponent,
|
||||
APITextInputComponent,
|
||||
ButtonStyle,
|
||||
ComponentType,
|
||||
TextInputStyle,
|
||||
type APIButtonComponent,
|
||||
type APIMessageActionRowComponent,
|
||||
type APISelectMenuComponent,
|
||||
type APITextInputComponent,
|
||||
type APIActionRowComponent,
|
||||
} from 'discord-api-types/v10';
|
||||
import { describe, test, expect } from 'vitest';
|
||||
import {
|
||||
@@ -15,7 +15,7 @@ import {
|
||||
createComponentBuilder,
|
||||
SelectMenuBuilder,
|
||||
TextInputBuilder,
|
||||
} from '../../src/index';
|
||||
} from '../../src/index.js';
|
||||
|
||||
describe('createComponentBuilder', () => {
|
||||
test.each([ButtonBuilder, SelectMenuBuilder, TextInputBuilder])(
|
||||
@@ -67,7 +67,7 @@ describe('createComponentBuilder', () => {
|
||||
});
|
||||
|
||||
test('GIVEN an unknown component type THEN throws error', () => {
|
||||
// @ts-expect-error
|
||||
// @ts-expect-error: Unknown component type
|
||||
expect(() => createComponentBuilder({ type: 'invalid' })).toThrowError();
|
||||
});
|
||||
});
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
import { APISelectMenuComponent, APISelectMenuOption, ComponentType } from 'discord-api-types/v10';
|
||||
import { ComponentType, type APISelectMenuComponent, type APISelectMenuOption } from 'discord-api-types/v10';
|
||||
import { describe, test, expect } from 'vitest';
|
||||
import { SelectMenuBuilder, SelectMenuOptionBuilder } from '../../src/index';
|
||||
import { SelectMenuBuilder, SelectMenuOptionBuilder } from '../../src/index.js';
|
||||
|
||||
const selectMenu = () => new SelectMenuBuilder();
|
||||
const selectMenuOption = () => new SelectMenuOptionBuilder();
|
||||
@@ -74,7 +74,8 @@ describe('Select Menu Components', () => {
|
||||
]),
|
||||
).not.toThrowError();
|
||||
|
||||
const options = new Array<APISelectMenuOption>(25).fill({ label: 'test', value: 'test' });
|
||||
const options = Array.from<APISelectMenuOption>({ length: 25 }).fill({ label: 'test', value: 'test' });
|
||||
|
||||
expect(() => selectMenu().addOptions(...options)).not.toThrowError();
|
||||
expect(() => selectMenu().setOptions(...options)).not.toThrowError();
|
||||
expect(() => selectMenu().addOptions(options)).not.toThrowError();
|
||||
@@ -83,12 +84,13 @@ describe('Select Menu Components', () => {
|
||||
expect(() =>
|
||||
selectMenu()
|
||||
.addOptions({ label: 'test', value: 'test' })
|
||||
.addOptions(...new Array<APISelectMenuOption>(24).fill({ label: 'test', value: 'test' })),
|
||||
|
||||
.addOptions(...Array.from<APISelectMenuOption>({ length: 24 }).fill({ label: 'test', value: 'test' })),
|
||||
).not.toThrowError();
|
||||
expect(() =>
|
||||
selectMenu()
|
||||
.addOptions([{ label: 'test', value: 'test' }])
|
||||
.addOptions(new Array<APISelectMenuOption>(24).fill({ label: 'test', value: 'test' })),
|
||||
.addOptions(Array.from<APISelectMenuOption>({ length: 24 }).fill({ label: 'test', value: 'test' })),
|
||||
).not.toThrowError();
|
||||
});
|
||||
|
||||
@@ -96,33 +98,34 @@ describe('Select Menu Components', () => {
|
||||
expect(() => selectMenu().setCustomId(longStr)).toThrowError();
|
||||
expect(() => selectMenu().setMaxValues(30)).toThrowError();
|
||||
expect(() => selectMenu().setMinValues(-20)).toThrowError();
|
||||
// @ts-expect-error
|
||||
// @ts-expect-error: Invalid disabled value
|
||||
expect(() => selectMenu().setDisabled(0)).toThrowError();
|
||||
expect(() => selectMenu().setPlaceholder(longStr)).toThrowError();
|
||||
// @ts-expect-error
|
||||
// @ts-expect-error: Invalid option
|
||||
expect(() => selectMenu().addOptions({ label: 'test' })).toThrowError();
|
||||
expect(() => selectMenu().addOptions({ label: longStr, value: 'test' })).toThrowError();
|
||||
expect(() => selectMenu().addOptions({ value: longStr, label: 'test' })).toThrowError();
|
||||
expect(() => selectMenu().addOptions({ label: 'test', value: 'test', description: longStr })).toThrowError();
|
||||
// @ts-expect-error
|
||||
// @ts-expect-error: Invalid option
|
||||
expect(() => selectMenu().addOptions({ label: 'test', value: 'test', default: 100 })).toThrowError();
|
||||
// @ts-expect-error
|
||||
// @ts-expect-error: Invalid option
|
||||
expect(() => selectMenu().addOptions({ value: 'test' })).toThrowError();
|
||||
// @ts-expect-error
|
||||
// @ts-expect-error: Invalid option
|
||||
expect(() => selectMenu().addOptions({ default: true })).toThrowError();
|
||||
// @ts-expect-error
|
||||
// @ts-expect-error: Invalid option
|
||||
expect(() => selectMenu().addOptions([{ label: 'test' }])).toThrowError();
|
||||
expect(() => selectMenu().addOptions([{ label: longStr, value: 'test' }])).toThrowError();
|
||||
expect(() => selectMenu().addOptions([{ value: longStr, label: 'test' }])).toThrowError();
|
||||
expect(() => selectMenu().addOptions([{ label: 'test', value: 'test', description: longStr }])).toThrowError();
|
||||
// @ts-expect-error
|
||||
// @ts-expect-error: Invalid option
|
||||
expect(() => selectMenu().addOptions([{ label: 'test', value: 'test', default: 100 }])).toThrowError();
|
||||
// @ts-expect-error
|
||||
// @ts-expect-error: Invalid option
|
||||
expect(() => selectMenu().addOptions([{ value: 'test' }])).toThrowError();
|
||||
// @ts-expect-error
|
||||
// @ts-expect-error: Invalid option
|
||||
expect(() => selectMenu().addOptions([{ default: true }])).toThrowError();
|
||||
|
||||
const tooManyOptions = new Array<APISelectMenuOption>(26).fill({ label: 'test', value: 'test' });
|
||||
const tooManyOptions = Array.from<APISelectMenuOption>({ length: 26 }).fill({ label: 'test', value: 'test' });
|
||||
|
||||
expect(() => selectMenu().setOptions(...tooManyOptions)).toThrowError();
|
||||
expect(() => selectMenu().setOptions(tooManyOptions)).toThrowError();
|
||||
|
||||
@@ -141,9 +144,9 @@ describe('Select Menu Components', () => {
|
||||
selectMenuOption()
|
||||
.setLabel(longStr)
|
||||
.setValue(longStr)
|
||||
// @ts-expect-error
|
||||
// @ts-expect-error: Invalid default value
|
||||
.setDefault(-1)
|
||||
// @ts-expect-error
|
||||
// @ts-expect-error: Invalid emoji
|
||||
.setEmoji({ name: 1 })
|
||||
.setDescription(longStr);
|
||||
}).toThrowError();
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
import { APITextInputComponent, ComponentType, TextInputStyle } from 'discord-api-types/v10';
|
||||
import { ComponentType, TextInputStyle, type APITextInputComponent } from 'discord-api-types/v10';
|
||||
import { describe, test, expect } from 'vitest';
|
||||
import {
|
||||
labelValidator,
|
||||
@@ -7,10 +7,10 @@ import {
|
||||
placeholderValidator,
|
||||
valueValidator,
|
||||
textInputStyleValidator,
|
||||
} from '../../src/components/textInput/Assertions';
|
||||
import { TextInputBuilder } from '../../src/components/textInput/TextInput';
|
||||
} from '../../src/components/textInput/Assertions.js';
|
||||
import { TextInputBuilder } from '../../src/components/textInput/TextInput.js';
|
||||
|
||||
const superLongStr = 'a'.repeat(5000);
|
||||
const superLongStr = 'a'.repeat(5_000);
|
||||
|
||||
const textInputComponent = () => new TextInputBuilder();
|
||||
|
||||
@@ -47,7 +47,7 @@ describe('Text Input Components', () => {
|
||||
});
|
||||
|
||||
test('GIVEN invalid min length THEN validator does throw 2', () => {
|
||||
expect(() => maxLengthValidator.parse(4001)).toThrowError();
|
||||
expect(() => maxLengthValidator.parse(4_001)).toThrowError();
|
||||
});
|
||||
|
||||
test('GIVEN valid value THEN validator does not throw', () => {
|
||||
@@ -85,7 +85,7 @@ describe('Text Input Components', () => {
|
||||
|
||||
expect(() => {
|
||||
// Issue #8107
|
||||
// @ts-expect-error: shapeshift maps the enum key to the value when parsing
|
||||
// @ts-expect-error: Shapeshift maps the enum key to the value when parsing
|
||||
textInputComponent().setCustomId('Custom').setLabel('Guess').setStyle('Short').toJSON();
|
||||
}).not.toThrowError();
|
||||
});
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
import { PermissionFlagsBits } from 'discord-api-types/v10';
|
||||
import { describe, test, expect } from 'vitest';
|
||||
import { ContextMenuCommandAssertions, ContextMenuCommandBuilder } from '../../src/index';
|
||||
import { ContextMenuCommandAssertions, ContextMenuCommandBuilder } from '../../src/index.js';
|
||||
|
||||
const getBuilder = () => new ContextMenuCommandBuilder();
|
||||
|
||||
@@ -105,9 +105,9 @@ describe('Context Menu Commands', () => {
|
||||
});
|
||||
|
||||
test('GIVEN invalid name localizations THEN does throw error', () => {
|
||||
// @ts-expect-error
|
||||
// @ts-expect-error: Invalid localization
|
||||
expect(() => getBuilder().setNameLocalization('en-U', 'foobar')).toThrowError();
|
||||
// @ts-expect-error
|
||||
// @ts-expect-error: Invalid localization
|
||||
expect(() => getBuilder().setNameLocalizations({ 'en-U': 'foobar' })).toThrowError();
|
||||
});
|
||||
|
||||
|
||||
@@ -1,15 +1,15 @@
|
||||
import {
|
||||
APIApplicationCommandAttachmentOption,
|
||||
APIApplicationCommandBooleanOption,
|
||||
APIApplicationCommandChannelOption,
|
||||
APIApplicationCommandIntegerOption,
|
||||
APIApplicationCommandMentionableOption,
|
||||
APIApplicationCommandNumberOption,
|
||||
APIApplicationCommandRoleOption,
|
||||
APIApplicationCommandStringOption,
|
||||
APIApplicationCommandUserOption,
|
||||
ApplicationCommandOptionType,
|
||||
ChannelType,
|
||||
type APIApplicationCommandAttachmentOption,
|
||||
type APIApplicationCommandBooleanOption,
|
||||
type APIApplicationCommandChannelOption,
|
||||
type APIApplicationCommandIntegerOption,
|
||||
type APIApplicationCommandMentionableOption,
|
||||
type APIApplicationCommandNumberOption,
|
||||
type APIApplicationCommandRoleOption,
|
||||
type APIApplicationCommandStringOption,
|
||||
type APIApplicationCommandUserOption,
|
||||
} from 'discord-api-types/v10';
|
||||
import { describe, test, expect } from 'vitest';
|
||||
import {
|
||||
@@ -22,7 +22,7 @@ import {
|
||||
SlashCommandRoleOption,
|
||||
SlashCommandStringOption,
|
||||
SlashCommandUserOption,
|
||||
} from '../../../src/index';
|
||||
} from '../../../src/index.js';
|
||||
|
||||
const getBooleanOption = () =>
|
||||
new SlashCommandBooleanOption().setName('owo').setDescription('Testing 123').setRequired(true);
|
||||
@@ -101,7 +101,8 @@ describe('Application Command toJSON() results', () => {
|
||||
max_value: 10,
|
||||
min_value: -1,
|
||||
autocomplete: true,
|
||||
// @ts-expect-error TODO: you *can* send an empty array with autocomplete: true, should correct that in types
|
||||
// TODO
|
||||
// @ts-expect-error You *can* send an empty array with autocomplete: true, should correct that in types
|
||||
choices: [],
|
||||
});
|
||||
|
||||
@@ -145,7 +146,8 @@ describe('Application Command toJSON() results', () => {
|
||||
max_value: 10,
|
||||
min_value: -1.23,
|
||||
autocomplete: true,
|
||||
// @ts-expect-error TODO: you *can* send an empty array with autocomplete: true, should correct that in types
|
||||
// TODO
|
||||
// @ts-expect-error You *can* send an empty array with autocomplete: true, should correct that in types
|
||||
choices: [],
|
||||
});
|
||||
|
||||
@@ -187,7 +189,8 @@ describe('Application Command toJSON() results', () => {
|
||||
type: ApplicationCommandOptionType.String,
|
||||
required: true,
|
||||
autocomplete: true,
|
||||
// @ts-expect-error TODO: you *can* send an empty array with autocomplete: true, should correct that in types
|
||||
// TODO
|
||||
// @ts-expect-error you *can* send an empty array with autocomplete: true, should correct that in types
|
||||
choices: [],
|
||||
});
|
||||
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
import { APIApplicationCommandOptionChoice, ChannelType, PermissionFlagsBits } from 'discord-api-types/v10';
|
||||
import { ChannelType, PermissionFlagsBits, type APIApplicationCommandOptionChoice } from 'discord-api-types/v10';
|
||||
import { describe, test, expect } from 'vitest';
|
||||
import {
|
||||
SlashCommandAssertions,
|
||||
@@ -14,7 +14,7 @@ import {
|
||||
SlashCommandSubcommandBuilder,
|
||||
SlashCommandSubcommandGroupBuilder,
|
||||
SlashCommandUserOption,
|
||||
} from '../../../src/index';
|
||||
} from '../../../src/index.js';
|
||||
|
||||
const largeArray = Array.from({ length: 26 }, () => 1 as unknown as APIApplicationCommandOptionChoice);
|
||||
|
||||
@@ -33,9 +33,7 @@ const getSubcommandGroup = () => new SlashCommandSubcommandGroupBuilder().setNam
|
||||
const getSubcommand = () => new SlashCommandSubcommandBuilder().setName('owo').setDescription('Testing 123');
|
||||
|
||||
class Collection {
|
||||
public get [Symbol.toStringTag]() {
|
||||
return 'Map';
|
||||
}
|
||||
public readonly [Symbol.toStringTag] = 'Map';
|
||||
}
|
||||
|
||||
describe('Slash Commands', () => {
|
||||
@@ -178,7 +176,7 @@ describe('Slash Commands', () => {
|
||||
});
|
||||
|
||||
test('GIVEN a builder with invalid autocomplete THEN does throw an error', () => {
|
||||
// @ts-expect-error Checking if not providing anything, or an invalid return type causes an error
|
||||
// @ts-expect-error: Checking if not providing anything, or an invalid return type causes an error
|
||||
expect(() => getBuilder().addStringOption(getStringOption().setAutocomplete('not a boolean'))).toThrowError();
|
||||
});
|
||||
|
||||
@@ -236,7 +234,7 @@ describe('Slash Commands', () => {
|
||||
|
||||
expect(() => {
|
||||
getBuilder().addChannelOption(
|
||||
getChannelOption().addChannelTypes(ChannelType.GuildNews, ChannelType.GuildText),
|
||||
getChannelOption().addChannelTypes(ChannelType.GuildAnnouncement, ChannelType.GuildText),
|
||||
);
|
||||
}).not.toThrowError();
|
||||
});
|
||||
@@ -248,16 +246,16 @@ describe('Slash Commands', () => {
|
||||
});
|
||||
|
||||
test('GIVEN a builder with invalid number min/max options THEN does throw an error', () => {
|
||||
// @ts-expect-error
|
||||
// @ts-expect-error: Invalid max value
|
||||
expect(() => getBuilder().addNumberOption(getNumberOption().setMaxValue('test'))).toThrowError();
|
||||
|
||||
// @ts-expect-error
|
||||
// @ts-expect-error: Invalid max value
|
||||
expect(() => getBuilder().addIntegerOption(getIntegerOption().setMaxValue('test'))).toThrowError();
|
||||
|
||||
// @ts-expect-error
|
||||
// @ts-expect-error: Invalid min value
|
||||
expect(() => getBuilder().addNumberOption(getNumberOption().setMinValue('test'))).toThrowError();
|
||||
|
||||
// @ts-expect-error
|
||||
// @ts-expect-error: Invalid min value
|
||||
expect(() => getBuilder().addIntegerOption(getIntegerOption().setMinValue('test'))).toThrowError();
|
||||
|
||||
expect(() => getBuilder().addIntegerOption(getIntegerOption().setMinValue(1.5))).toThrowError();
|
||||
@@ -294,10 +292,10 @@ describe('Slash Commands', () => {
|
||||
});
|
||||
|
||||
test('GIVEN no valid return for an addOption method THEN throw error', () => {
|
||||
// @ts-expect-error Checking if not providing anything, or an invalid return type causes an error
|
||||
// @ts-expect-error: Checking if not providing anything, or an invalid return type causes an error
|
||||
expect(() => getBuilder().addBooleanOption()).toThrowError();
|
||||
|
||||
// @ts-expect-error Checking if not providing anything, or an invalid return type causes an error
|
||||
// @ts-expect-error: Checking if not providing anything, or an invalid return type causes an error
|
||||
expect(() => getBuilder().addBooleanOption(getRoleOption())).toThrowError();
|
||||
});
|
||||
|
||||
@@ -318,18 +316,18 @@ describe('Slash Commands', () => {
|
||||
});
|
||||
|
||||
test('GIVEN invalid returns for builder THEN throw error', () => {
|
||||
// @ts-expect-error Checking if not providing anything, or an invalid return type causes an error
|
||||
// @ts-expect-error: Checking if not providing anything, or an invalid return type causes an error
|
||||
expect(() => getBuilder().addBooleanOption(true)).toThrowError();
|
||||
|
||||
// @ts-expect-error Checking if not providing anything, or an invalid return type causes an error
|
||||
// @ts-expect-error: Checking if not providing anything, or an invalid return type causes an error
|
||||
expect(() => getBuilder().addBooleanOption(null)).toThrowError();
|
||||
|
||||
// @ts-expect-error Checking if not providing anything, or an invalid return type causes an error
|
||||
// @ts-expect-error: Checking if not providing anything, or an invalid return type causes an error
|
||||
expect(() => getBuilder().addBooleanOption(undefined)).toThrowError();
|
||||
|
||||
// @ts-expect-error Checking if not providing anything, or an invalid return type causes an error
|
||||
// @ts-expect-error: Checking if not providing anything, or an invalid return type causes an error
|
||||
expect(() => getBuilder().addBooleanOption(() => SlashCommandStringOption)).toThrowError();
|
||||
// @ts-expect-error Checking if not providing anything, or an invalid return type causes an error
|
||||
// @ts-expect-error: Checking if not providing anything, or an invalid return type causes an error
|
||||
expect(() => getBuilder().addBooleanOption(() => new Collection())).toThrowError();
|
||||
});
|
||||
|
||||
@@ -373,6 +371,18 @@ describe('Slash Commands', () => {
|
||||
).not.toThrowError();
|
||||
});
|
||||
|
||||
test('GIVEN builder with subcommand THEN has regular slash command fields', () => {
|
||||
expect(() =>
|
||||
getBuilder()
|
||||
.setName('name')
|
||||
.setDescription('description')
|
||||
.addSubcommand((option) => option.setName('ye').setDescription('ye'))
|
||||
.addSubcommand((option) => option.setName('no').setDescription('no'))
|
||||
.setDMPermission(false)
|
||||
.setDefaultMemberPermissions(1n),
|
||||
).not.toThrowError();
|
||||
});
|
||||
|
||||
test('GIVEN builder with already built subcommand group THEN does not throw error', () => {
|
||||
expect(() => getNamedBuilder().addSubcommandGroup(getSubcommandGroup())).not.toThrowError();
|
||||
});
|
||||
@@ -389,30 +399,29 @@ describe('Slash Commands', () => {
|
||||
|
||||
test('GIVEN builder with a subcommand that tries to add an invalid result THEN throw error', () => {
|
||||
expect(() =>
|
||||
// @ts-expect-error Checking if check works JS-side too
|
||||
// eslint-disable-next-line @typescript-eslint/no-unsafe-return, @typescript-eslint/no-unsafe-call
|
||||
// @ts-expect-error: Checking if check works JS-side too
|
||||
getNamedBuilder().addSubcommand(getSubcommand()).addInteger(getInteger()),
|
||||
).toThrowError();
|
||||
});
|
||||
|
||||
test('GIVEN no valid return for an addSubcommand(Group) method THEN throw error', () => {
|
||||
// @ts-expect-error Checking if not providing anything, or an invalid return type causes an error
|
||||
// @ts-expect-error: Checking if not providing anything, or an invalid return type causes an error
|
||||
expect(() => getBuilder().addSubcommandGroup()).toThrowError();
|
||||
|
||||
// @ts-expect-error Checking if not providing anything, or an invalid return type causes an error
|
||||
// @ts-expect-error: Checking if not providing anything, or an invalid return type causes an error
|
||||
expect(() => getBuilder().addSubcommand()).toThrowError();
|
||||
|
||||
// @ts-expect-error Checking if not providing anything, or an invalid return type causes an error
|
||||
// @ts-expect-error: Checking if not providing anything, or an invalid return type causes an error
|
||||
expect(() => getBuilder().addSubcommand(getSubcommandGroup())).toThrowError();
|
||||
});
|
||||
});
|
||||
|
||||
describe('Subcommand group builder', () => {
|
||||
test('GIVEN no valid subcommand THEN throw error', () => {
|
||||
// @ts-expect-error Checking if not providing anything, or an invalid return type causes an error
|
||||
// @ts-expect-error: Checking if not providing anything, or an invalid return type causes an error
|
||||
expect(() => getSubcommandGroup().addSubcommand()).toThrowError();
|
||||
|
||||
// @ts-expect-error Checking if not providing anything, or an invalid return type causes an error
|
||||
// @ts-expect-error: Checking if not providing anything, or an invalid return type causes an error
|
||||
expect(() => getSubcommandGroup().addSubcommand(getSubcommandGroup())).toThrowError();
|
||||
});
|
||||
|
||||
@@ -444,9 +453,9 @@ describe('Slash Commands', () => {
|
||||
});
|
||||
|
||||
test('GIVEN invalid name localizations THEN does throw error', () => {
|
||||
// @ts-expect-error
|
||||
// @ts-expect-error: Invalid localization
|
||||
expect(() => getBuilder().setNameLocalization('en-U', 'foobar')).toThrowError();
|
||||
// @ts-expect-error
|
||||
// @ts-expect-error: Invalid localization
|
||||
expect(() => getBuilder().setNameLocalizations({ 'en-U': 'foobar' })).toThrowError();
|
||||
});
|
||||
|
||||
@@ -467,9 +476,9 @@ describe('Slash Commands', () => {
|
||||
});
|
||||
|
||||
test('GIVEN invalid description localizations THEN does throw error', () => {
|
||||
// @ts-expect-error
|
||||
// @ts-expect-error: Invalid localization description
|
||||
expect(() => getBuilder().setDescriptionLocalization('en-U', 'foobar')).toThrowError();
|
||||
// @ts-expect-error
|
||||
// @ts-expect-error: Invalid localization description
|
||||
expect(() => getBuilder().setDescriptionLocalizations({ 'en-U': 'foobar' })).toThrowError();
|
||||
});
|
||||
|
||||
|
||||
@@ -1,22 +1,22 @@
|
||||
import {
|
||||
APIModalInteractionResponseCallbackData,
|
||||
APITextInputComponent,
|
||||
ComponentType,
|
||||
TextInputStyle,
|
||||
type APIModalInteractionResponseCallbackData,
|
||||
type APITextInputComponent,
|
||||
} from 'discord-api-types/v10';
|
||||
import { describe, test, expect } from 'vitest';
|
||||
import {
|
||||
ActionRowBuilder,
|
||||
ButtonBuilder,
|
||||
ModalBuilder,
|
||||
ModalActionRowComponentBuilder,
|
||||
TextInputBuilder,
|
||||
} from '../../src';
|
||||
type ModalActionRowComponentBuilder,
|
||||
} from '../../src/index.js';
|
||||
import {
|
||||
componentsValidator,
|
||||
titleValidator,
|
||||
validateRequiredParameters,
|
||||
} from '../../src/interactions/modals/Assertions';
|
||||
} from '../../src/interactions/modals/Assertions.js';
|
||||
|
||||
const modal = () => new ModalBuilder();
|
||||
|
||||
@@ -46,7 +46,7 @@ describe('Modals', () => {
|
||||
|
||||
test('GIVEN invalid required parameters THEN validator does throw', () => {
|
||||
expect(() =>
|
||||
// @ts-expect-error
|
||||
// @ts-expect-error: Missing required parameter
|
||||
validateRequiredParameters('123', undefined, [new ActionRowBuilder(), new ButtonBuilder()]),
|
||||
).toThrowError();
|
||||
});
|
||||
@@ -66,7 +66,7 @@ describe('Modals', () => {
|
||||
test('GIVEN invalid fields THEN builder does throw', () => {
|
||||
expect(() => modal().setTitle('test').setCustomId('foobar').toJSON()).toThrowError();
|
||||
|
||||
// @ts-expect-error
|
||||
// @ts-expect-error: CustomId is invalid
|
||||
expect(() => modal().setTitle('test').setCustomId(42).toJSON()).toThrowError();
|
||||
});
|
||||
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
import { describe, test, expect } from 'vitest';
|
||||
import { EmbedBuilder, embedLength } from '../../src';
|
||||
import { EmbedBuilder, embedLength } from '../../src/index.js';
|
||||
|
||||
const alpha = 'abcdefghijklmnopqrstuvwxyz';
|
||||
|
||||
@@ -74,7 +74,7 @@ describe('Embed', () => {
|
||||
test('GIVEN an embed with an invalid description THEN throws error', () => {
|
||||
const embed = new EmbedBuilder();
|
||||
|
||||
expect(() => embed.setDescription('a'.repeat(4097))).toThrowError();
|
||||
expect(() => embed.setDescription('a'.repeat(4_097))).toThrowError();
|
||||
});
|
||||
});
|
||||
|
||||
@@ -130,11 +130,11 @@ describe('Embed', () => {
|
||||
test('GIVEN an embed with an invalid color THEN throws error', () => {
|
||||
const embed = new EmbedBuilder();
|
||||
|
||||
// @ts-expect-error
|
||||
// @ts-expect-error: Invalid color
|
||||
expect(() => embed.setColor('RED')).toThrowError();
|
||||
// @ts-expect-error
|
||||
// @ts-expect-error: Invalid color
|
||||
expect(() => embed.setColor([42, 36])).toThrowError();
|
||||
expect(() => embed.setColor([42, 36, 1000])).toThrowError();
|
||||
expect(() => embed.setColor([42, 36, 1_000])).toThrowError();
|
||||
});
|
||||
});
|
||||
|
||||
@@ -307,7 +307,7 @@ describe('Embed', () => {
|
||||
test('GIVEN an embed with invalid footer text THEN throws error', () => {
|
||||
const embed = new EmbedBuilder();
|
||||
|
||||
expect(() => embed.setFooter({ text: 'a'.repeat(2049) })).toThrowError();
|
||||
expect(() => embed.setFooter({ text: 'a'.repeat(2_049) })).toThrowError();
|
||||
});
|
||||
});
|
||||
|
||||
@@ -411,7 +411,7 @@ describe('Embed', () => {
|
||||
test('4', () => {
|
||||
const embed = new EmbedBuilder();
|
||||
|
||||
expect(() => embed.addFields({ name: '', value: 'a'.repeat(1025) })).toThrowError();
|
||||
expect(() => embed.addFields({ name: '', value: 'a'.repeat(1_025) })).toThrowError();
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
@@ -1,6 +1,8 @@
|
||||
/* eslint-disable no-template-curly-in-string */
|
||||
import { URL } from 'node:url';
|
||||
import { describe, test, expect, vitest } from 'vitest';
|
||||
import {
|
||||
chatInputApplicationCommandMention,
|
||||
blockQuote,
|
||||
bold,
|
||||
channelLink,
|
||||
@@ -21,7 +23,7 @@ import {
|
||||
TimestampStyles,
|
||||
underscore,
|
||||
userMention,
|
||||
} from '../../src';
|
||||
} from '../../src/index.js';
|
||||
|
||||
describe('Message formatters', () => {
|
||||
describe('codeBlock', () => {
|
||||
@@ -136,6 +138,26 @@ describe('Message formatters', () => {
|
||||
expect(roleMention('815434166602170409')).toEqual('<@&815434166602170409>');
|
||||
});
|
||||
});
|
||||
|
||||
describe('chatInputApplicationCommandMention', () => {
|
||||
test('GIVEN commandName and commandId THEN returns "</[commandName]:[commandId]>"', () => {
|
||||
expect(chatInputApplicationCommandMention('airhorn', '815434166602170409')).toEqual(
|
||||
'</airhorn:815434166602170409>',
|
||||
);
|
||||
});
|
||||
|
||||
test('GIVEN commandName, subcommandName, and commandId THEN returns "</[commandName] [subcommandName]:[commandId]>"', () => {
|
||||
expect(chatInputApplicationCommandMention('airhorn', 'sub', '815434166602170409')).toEqual(
|
||||
'</airhorn sub:815434166602170409>',
|
||||
);
|
||||
});
|
||||
|
||||
test('GIVEN commandName, subcommandGroupName, subcommandName, and commandId THEN returns "</[commandName] [subcommandGroupName] [subcommandName]:[commandId]>"', () => {
|
||||
expect(chatInputApplicationCommandMention('airhorn', 'group', 'sub', '815434166602170409')).toEqual(
|
||||
'</airhorn group sub:815434166602170409>',
|
||||
);
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
describe('formatEmoji', () => {
|
||||
@@ -183,7 +205,7 @@ describe('Message formatters', () => {
|
||||
describe('time', () => {
|
||||
test('GIVEN no arguments THEN returns "<t:${bigint}>"', () => {
|
||||
vitest.useFakeTimers();
|
||||
vitest.setSystemTime(1566424897579);
|
||||
vitest.setSystemTime(1_566_424_897_579);
|
||||
|
||||
expect<`<t:${bigint}>`>(time()).toEqual('<t:1566424897>');
|
||||
|
||||
@@ -191,29 +213,29 @@ describe('Message formatters', () => {
|
||||
});
|
||||
|
||||
test('GIVEN a date THEN returns "<t:${bigint}>"', () => {
|
||||
expect<`<t:${bigint}>`>(time(new Date(1867424897579))).toEqual('<t:1867424897>');
|
||||
expect<`<t:${bigint}>`>(time(new Date(1_867_424_897_579))).toEqual('<t:1867424897>');
|
||||
});
|
||||
|
||||
test('GIVEN a date and a style from string THEN returns "<t:${bigint}:${style}>"', () => {
|
||||
expect<`<t:${bigint}:d>`>(time(new Date(1867424897579), 'd')).toEqual('<t:1867424897:d>');
|
||||
expect<`<t:${bigint}:d>`>(time(new Date(1_867_424_897_579), 'd')).toEqual('<t:1867424897:d>');
|
||||
});
|
||||
|
||||
test('GIVEN a date and a format from enum THEN returns "<t:${bigint}:${style}>"', () => {
|
||||
expect<`<t:${bigint}:R>`>(time(new Date(1867424897579), TimestampStyles.RelativeTime)).toEqual(
|
||||
expect<`<t:${bigint}:R>`>(time(new Date(1_867_424_897_579), TimestampStyles.RelativeTime)).toEqual(
|
||||
'<t:1867424897:R>',
|
||||
);
|
||||
});
|
||||
|
||||
test('GIVEN a date THEN returns "<t:${time}>"', () => {
|
||||
expect<'<t:1867424897>'>(time(1867424897)).toEqual('<t:1867424897>');
|
||||
expect<'<t:1867424897>'>(time(1_867_424_897)).toEqual('<t:1867424897>');
|
||||
});
|
||||
|
||||
test('GIVEN a date and a style from string THEN returns "<t:${time}:${style}>"', () => {
|
||||
expect<'<t:1867424897:d>'>(time(1867424897, 'd')).toEqual('<t:1867424897:d>');
|
||||
expect<'<t:1867424897:d>'>(time(1_867_424_897, 'd')).toEqual('<t:1867424897:d>');
|
||||
});
|
||||
|
||||
test('GIVEN a date and a format from enum THEN returns "<t:${time}:${style}>"', () => {
|
||||
expect<'<t:1867424897:R>'>(time(1867424897, TimestampStyles.RelativeTime)).toEqual('<t:1867424897:R>');
|
||||
expect<'<t:1867424897:R>'>(time(1_867_424_897, TimestampStyles.RelativeTime)).toEqual('<t:1867424897:R>');
|
||||
});
|
||||
});
|
||||
|
||||
|
||||
@@ -6,7 +6,7 @@ import {
|
||||
enableValidators,
|
||||
disableValidators,
|
||||
isValidationEnabled,
|
||||
} from '../src/index';
|
||||
} from '../src/index.js';
|
||||
|
||||
describe('isEquatable', () => {
|
||||
test('returns true if the object is equatable', () => {
|
||||
|
||||
@@ -1,3 +0,0 @@
|
||||
import { createUnbuildConfig } from '../../build.config';
|
||||
|
||||
export default createUnbuildConfig();
|
||||
@@ -4,21 +4,21 @@
|
||||
"description": "A set of builders that you can use when creating your bot",
|
||||
"scripts": {
|
||||
"test": "vitest run",
|
||||
"build": "unbuild",
|
||||
"lint": "prettier --check . && TIMING=1 eslint src __tests__ --ext mjs,js,ts",
|
||||
"format": "prettier --write . && TIMING=1 eslint src __tests__ --ext mjs,js,ts --fix",
|
||||
"build": "tsup",
|
||||
"lint": "prettier --check . && cross-env TIMING=1 eslint src __tests__ --ext mjs,js,ts",
|
||||
"format": "prettier --write . && cross-env TIMING=1 eslint src __tests__ --ext mjs,js,ts --fix",
|
||||
"fmt": "yarn format",
|
||||
"docs": "downlevel-dts . docs --to=3.7 && docgen -i src/index.ts -c docs/index.json -o docs/docs.json --typescript && api-extractor run --local",
|
||||
"docs": "downlevel-dts dist docs/dist --to=3.7 && docgen -i src/index.ts -c docs/index.json -o docs/docs.json --typescript && api-extractor run --local",
|
||||
"prepack": "yarn lint && yarn test && yarn build",
|
||||
"changelog": "git cliff --prepend ./CHANGELOG.md -u -c ./cliff.toml -r ../../ --include-path 'packages/builders/*'",
|
||||
"release": "cliff-jumper"
|
||||
},
|
||||
"main": "./dist/index.cjs",
|
||||
"main": "./dist/index.js",
|
||||
"module": "./dist/index.mjs",
|
||||
"types": "./dist/index.d.ts",
|
||||
"exports": {
|
||||
"import": "./dist/index.mjs",
|
||||
"require": "./dist/index.cjs",
|
||||
"require": "./dist/index.js",
|
||||
"types": "./dist/index.d.ts"
|
||||
},
|
||||
"directories": {
|
||||
@@ -33,7 +33,7 @@
|
||||
"Crawl <icrawltogo@gmail.com>",
|
||||
"Amish Shah <amishshah.2k@gmail.com>",
|
||||
"SpaceEEC <spaceeec@yahoo.com>",
|
||||
"Antonio Roman <kyradiscord@gmail.com>"
|
||||
"Aura Román <kyradiscord@gmail.com>"
|
||||
],
|
||||
"license": "Apache-2.0",
|
||||
"keywords": [
|
||||
@@ -54,8 +54,8 @@
|
||||
},
|
||||
"homepage": "https://discord.js.org",
|
||||
"dependencies": {
|
||||
"@sapphire/shapeshift": "^3.5.1",
|
||||
"discord-api-types": "^0.37.3",
|
||||
"@sapphire/shapeshift": "^3.6.0",
|
||||
"discord-api-types": "^0.37.10",
|
||||
"fast-deep-equal": "^3.1.3",
|
||||
"ts-mixer": "^6.0.1",
|
||||
"tslib": "^2.4.0"
|
||||
@@ -63,23 +63,17 @@
|
||||
"devDependencies": {
|
||||
"@discordjs/docgen": "workspace:^",
|
||||
"@favware/cliff-jumper": "^1.8.7",
|
||||
"@microsoft/api-extractor": "^7.29.3",
|
||||
"@types/node": "^16.11.52",
|
||||
"@typescript-eslint/eslint-plugin": "^5.33.1",
|
||||
"@typescript-eslint/parser": "^5.33.1",
|
||||
"@vitest/coverage-c8": "^0.22.1",
|
||||
"downlevel-dts": "^0.10.0",
|
||||
"eslint": "^8.22.0",
|
||||
"eslint-config-marine": "^9.4.1",
|
||||
"eslint-config-prettier": "^8.5.0",
|
||||
"eslint-import-resolver-typescript": "^3.4.2",
|
||||
"eslint-plugin-import": "^2.26.0",
|
||||
"eslint-plugin-tsdoc": "^0.2.16",
|
||||
"@microsoft/api-extractor": "^7.31.2",
|
||||
"@types/node": "^16.11.60",
|
||||
"@vitest/coverage-c8": "^0.23.4",
|
||||
"cross-env": "^7.0.3",
|
||||
"downlevel-dts": "^0.10.1",
|
||||
"eslint": "^8.24.0",
|
||||
"eslint-config-neon": "^0.1.33",
|
||||
"prettier": "^2.7.1",
|
||||
"rollup-plugin-typescript2": "^0.33.0",
|
||||
"typescript": "^4.7.4",
|
||||
"unbuild": "^0.8.9",
|
||||
"vitest": "^0.22.1"
|
||||
"tsup": "^6.2.3",
|
||||
"typescript": "^4.8.3",
|
||||
"vitest": "^0.23.4"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=16.9.0"
|
||||
|
||||
@@ -1,21 +1,23 @@
|
||||
/* eslint-disable jsdoc/check-param-names */
|
||||
|
||||
import {
|
||||
type APIActionRowComponent,
|
||||
ComponentType,
|
||||
APIMessageActionRowComponent,
|
||||
APIModalActionRowComponent,
|
||||
APIActionRowComponentTypes,
|
||||
type APIMessageActionRowComponent,
|
||||
type APIModalActionRowComponent,
|
||||
type APIActionRowComponentTypes,
|
||||
} from 'discord-api-types/v10';
|
||||
import { ComponentBuilder } from './Component';
|
||||
import { createComponentBuilder } from './Components';
|
||||
import type { ButtonBuilder } from './button/Button';
|
||||
import type { SelectMenuBuilder } from './selectMenu/SelectMenu';
|
||||
import type { TextInputBuilder } from './textInput/TextInput';
|
||||
import { normalizeArray, type RestOrArray } from '../util/normalizeArray';
|
||||
import { normalizeArray, type RestOrArray } from '../util/normalizeArray.js';
|
||||
import { ComponentBuilder } from './Component.js';
|
||||
import { createComponentBuilder } from './Components.js';
|
||||
import type { ButtonBuilder } from './button/Button.js';
|
||||
import type { SelectMenuBuilder } from './selectMenu/SelectMenu.js';
|
||||
import type { TextInputBuilder } from './textInput/TextInput.js';
|
||||
|
||||
export type MessageComponentBuilder =
|
||||
| MessageActionRowComponentBuilder
|
||||
| ActionRowBuilder<MessageActionRowComponentBuilder>;
|
||||
export type ModalComponentBuilder = ModalActionRowComponentBuilder | ActionRowBuilder<ModalActionRowComponentBuilder>;
|
||||
| ActionRowBuilder<MessageActionRowComponentBuilder>
|
||||
| MessageActionRowComponentBuilder;
|
||||
export type ModalComponentBuilder = ActionRowBuilder<ModalActionRowComponentBuilder> | ModalActionRowComponentBuilder;
|
||||
export type MessageActionRowComponentBuilder = ButtonBuilder | SelectMenuBuilder;
|
||||
export type ModalActionRowComponentBuilder = TextInputBuilder;
|
||||
export type AnyComponentBuilder = MessageActionRowComponentBuilder | ModalActionRowComponentBuilder;
|
||||
@@ -33,9 +35,43 @@ export class ActionRowBuilder<T extends AnyComponentBuilder> extends ComponentBu
|
||||
*/
|
||||
public readonly components: T[];
|
||||
|
||||
/**
|
||||
* Creates a new action row from API data
|
||||
*
|
||||
* @param data - The API data to create this action row with
|
||||
* @example
|
||||
* Creating an action row from an API data object
|
||||
* ```ts
|
||||
* const actionRow = new ActionRowBuilder({
|
||||
* components: [
|
||||
* {
|
||||
* custom_id: "custom id",
|
||||
* label: "Type something",
|
||||
* style: TextInputStyle.Short,
|
||||
* type: ComponentType.TextInput,
|
||||
* },
|
||||
* ],
|
||||
* });
|
||||
* ```
|
||||
* @example
|
||||
* Creating an action row using setters and API data
|
||||
* ```ts
|
||||
* const actionRow = new ActionRowBuilder({
|
||||
* components: [
|
||||
* {
|
||||
* custom_id: "custom id",
|
||||
* label: "Click me",
|
||||
* style: ButtonStyle.Primary,
|
||||
* type: ComponentType.Button,
|
||||
* },
|
||||
* ],
|
||||
* })
|
||||
* .addComponents(button2, button3);
|
||||
* ```
|
||||
*/
|
||||
public constructor({ components, ...data }: Partial<APIActionRowComponent<APIActionRowComponentTypes>> = {}) {
|
||||
super({ type: ComponentType.ActionRow, ...data });
|
||||
this.components = (components?.map((c) => createComponentBuilder(c)) ?? []) as T[];
|
||||
this.components = (components?.map((component) => createComponentBuilder(component)) ?? []) as T[];
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -62,7 +98,6 @@ export class ActionRowBuilder<T extends AnyComponentBuilder> extends ComponentBu
|
||||
* {@inheritDoc ComponentBuilder.toJSON}
|
||||
*/
|
||||
public toJSON(): APIActionRowComponent<ReturnType<T['toJSON']>> {
|
||||
// eslint-disable-next-line @typescript-eslint/consistent-type-assertions
|
||||
return {
|
||||
...this.data,
|
||||
components: this.components.map((component) => component.toJSON()),
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
import { s } from '@sapphire/shapeshift';
|
||||
import { APIMessageComponentEmoji, ButtonStyle } from 'discord-api-types/v10';
|
||||
import { SelectMenuOptionBuilder } from './selectMenu/SelectMenuOption';
|
||||
import { isValidationEnabled } from '../util/validation';
|
||||
import { ButtonStyle, type APIMessageComponentEmoji } from 'discord-api-types/v10';
|
||||
import { isValidationEnabled } from '../util/validation.js';
|
||||
import { SelectMenuOptionBuilder } from './selectMenu/SelectMenuOption.js';
|
||||
|
||||
export const customIdValidator = s.string
|
||||
.lengthGreaterThanOrEqual(1)
|
||||
|
||||
@@ -6,7 +6,7 @@ import type {
|
||||
} from 'discord-api-types/v10';
|
||||
import type { JSONEncodable } from '../util/jsonEncodable';
|
||||
|
||||
export type AnyAPIActionRowComponent = APIActionRowComponentTypes | APIActionRowComponent<APIActionRowComponentTypes>;
|
||||
export type AnyAPIActionRowComponent = APIActionRowComponent<APIActionRowComponentTypes> | APIActionRowComponentTypes;
|
||||
|
||||
/**
|
||||
* Represents a discord component
|
||||
|
||||
@@ -1,14 +1,14 @@
|
||||
import { APIMessageComponent, APIModalComponent, ComponentType } from 'discord-api-types/v10';
|
||||
import { ComponentType, type APIMessageComponent, type APIModalComponent } from 'discord-api-types/v10';
|
||||
import {
|
||||
ActionRowBuilder,
|
||||
type AnyComponentBuilder,
|
||||
type MessageComponentBuilder,
|
||||
type ModalComponentBuilder,
|
||||
} from './ActionRow';
|
||||
import { ComponentBuilder } from './Component';
|
||||
import { ButtonBuilder } from './button/Button';
|
||||
import { SelectMenuBuilder } from './selectMenu/SelectMenu';
|
||||
import { TextInputBuilder } from './textInput/TextInput';
|
||||
} from './ActionRow.js';
|
||||
import { ComponentBuilder } from './Component.js';
|
||||
import { ButtonBuilder } from './button/Button.js';
|
||||
import { SelectMenuBuilder } from './selectMenu/SelectMenu.js';
|
||||
import { TextInputBuilder } from './textInput/TextInput.js';
|
||||
|
||||
export interface MappedComponentTypes {
|
||||
[ComponentType.ActionRow]: ActionRowBuilder<AnyComponentBuilder>;
|
||||
@@ -23,7 +23,8 @@ export interface MappedComponentTypes {
|
||||
* @param data - The api data to transform to a component class
|
||||
*/
|
||||
export function createComponentBuilder<T extends keyof MappedComponentTypes>(
|
||||
data: (APIMessageComponent | APIModalComponent) & { type: T },
|
||||
// eslint-disable-next-line @typescript-eslint/sort-type-union-intersection-members
|
||||
data: (APIModalComponent | APIMessageComponent) & { type: T },
|
||||
): MappedComponentTypes[T];
|
||||
export function createComponentBuilder<C extends MessageComponentBuilder | ModalComponentBuilder>(data: C): C;
|
||||
export function createComponentBuilder(
|
||||
@@ -43,8 +44,7 @@ export function createComponentBuilder(
|
||||
case ComponentType.TextInput:
|
||||
return new TextInputBuilder(data);
|
||||
default:
|
||||
// @ts-expect-error
|
||||
// eslint-disable-next-line @typescript-eslint/restrict-template-expressions
|
||||
// @ts-expect-error: This case can still occur if we get a newer unsupported component type
|
||||
throw new Error(`Cannot properly serialize component type: ${data.type}`);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,10 +1,10 @@
|
||||
import {
|
||||
ComponentType,
|
||||
ButtonStyle,
|
||||
type APIMessageComponentEmoji,
|
||||
type APIButtonComponent,
|
||||
type APIButtonComponentWithURL,
|
||||
type APIButtonComponentWithCustomId,
|
||||
type ButtonStyle,
|
||||
} from 'discord-api-types/v10';
|
||||
import {
|
||||
buttonLabelValidator,
|
||||
@@ -14,8 +14,8 @@ import {
|
||||
emojiValidator,
|
||||
urlValidator,
|
||||
validateRequiredButtonParameters,
|
||||
} from '../Assertions';
|
||||
import { ComponentBuilder } from '../Component';
|
||||
} from '../Assertions.js';
|
||||
import { ComponentBuilder } from '../Component.js';
|
||||
|
||||
/**
|
||||
* Represents a button component
|
||||
@@ -23,31 +23,30 @@ import { ComponentBuilder } from '../Component';
|
||||
export class ButtonBuilder extends ComponentBuilder<APIButtonComponent> {
|
||||
/**
|
||||
* Creates a new button from API data
|
||||
* @param data - The API data to create this button with
|
||||
*
|
||||
* @param data - The API data to create this button with
|
||||
* @example
|
||||
* Creating a button from an API data object
|
||||
* ```ts
|
||||
* const button = new ButtonBuilder({
|
||||
* style: 'primary',
|
||||
* custom_id: 'a cool button',
|
||||
* style: ButtonStyle.Primary,
|
||||
* label: 'Click Me',
|
||||
* emoji: {
|
||||
* name: ':smile:',
|
||||
* id: '12345678901234567890123456789012',
|
||||
* name: 'smile',
|
||||
* id: '123456789012345678',
|
||||
* },
|
||||
* custom_id: '12345678901234567890123456789012',
|
||||
* });
|
||||
* ```
|
||||
*
|
||||
* @example
|
||||
* Creating a button using setters and API data
|
||||
* ```ts
|
||||
* const button = new ButtonBuilder({
|
||||
* style: 'primary',
|
||||
* style: ButtonStyle.Secondary,
|
||||
* label: 'Click Me',
|
||||
* })
|
||||
* .setEmoji({ name: ':smile:', id: '12345678901234567890123456789012' })
|
||||
* .setCustomId('12345678901234567890123456789012');
|
||||
* .setEmoji({ name: '🙂' })
|
||||
* .setCustomId('another cool button');
|
||||
* ```
|
||||
*/
|
||||
public constructor(data?: Partial<APIButtonComponent>) {
|
||||
@@ -70,7 +69,6 @@ export class ButtonBuilder extends ComponentBuilder<APIButtonComponent> {
|
||||
* @remarks
|
||||
* This method is only available to buttons using the `Link` button style.
|
||||
* Only three types of URL schemes are currently supported: `https://`, `http://` and `discord://`
|
||||
*
|
||||
* @param url - The URL to open when this button is clicked
|
||||
*/
|
||||
public setURL(url: string) {
|
||||
@@ -83,7 +81,6 @@ export class ButtonBuilder extends ComponentBuilder<APIButtonComponent> {
|
||||
*
|
||||
* @remarks
|
||||
* This method is only applicable to buttons that are not using the `Link` button style.
|
||||
*
|
||||
* @param customId - The custom id to use for this button
|
||||
*/
|
||||
public setCustomId(customId: string) {
|
||||
@@ -132,7 +129,7 @@ export class ButtonBuilder extends ComponentBuilder<APIButtonComponent> {
|
||||
(this.data as APIButtonComponentWithCustomId).custom_id,
|
||||
(this.data as APIButtonComponentWithURL).url,
|
||||
);
|
||||
// eslint-disable-next-line @typescript-eslint/consistent-type-assertions
|
||||
|
||||
return {
|
||||
...this.data,
|
||||
} as APIButtonComponent;
|
||||
|
||||
@@ -1,6 +1,5 @@
|
||||
import { APISelectMenuOption, ComponentType, type APISelectMenuComponent } from 'discord-api-types/v10';
|
||||
import { SelectMenuOptionBuilder } from './SelectMenuOption';
|
||||
import { normalizeArray, type RestOrArray } from '../../util/normalizeArray';
|
||||
import { ComponentType, type APISelectMenuComponent, type APISelectMenuOption } from 'discord-api-types/v10';
|
||||
import { normalizeArray, type RestOrArray } from '../../util/normalizeArray.js';
|
||||
import {
|
||||
customIdValidator,
|
||||
disabledValidator,
|
||||
@@ -9,8 +8,9 @@ import {
|
||||
optionsLengthValidator,
|
||||
placeholderValidator,
|
||||
validateRequiredSelectMenuParameters,
|
||||
} from '../Assertions';
|
||||
import { ComponentBuilder } from '../Component';
|
||||
} from '../Assertions.js';
|
||||
import { ComponentBuilder } from '../Component.js';
|
||||
import { SelectMenuOptionBuilder } from './SelectMenuOption.js';
|
||||
|
||||
/**
|
||||
* Represents a select menu component
|
||||
@@ -21,10 +21,41 @@ export class SelectMenuBuilder extends ComponentBuilder<APISelectMenuComponent>
|
||||
*/
|
||||
public readonly options: SelectMenuOptionBuilder[];
|
||||
|
||||
/**
|
||||
* Creates a new select menu from API data
|
||||
*
|
||||
* @param data - The API data to create this select menu with
|
||||
* @example
|
||||
* Creating a select menu from an API data object
|
||||
* ```ts
|
||||
* const selectMenu = new SelectMenuBuilder({
|
||||
* custom_id: 'a cool select menu',
|
||||
* placeholder: 'select an option',
|
||||
* max_values: 2,
|
||||
* options: [
|
||||
* { label: 'option 1', value: '1' },
|
||||
* { label: 'option 2', value: '2' },
|
||||
* { label: 'option 3', value: '3' },
|
||||
* ],
|
||||
* });
|
||||
* ```
|
||||
* @example
|
||||
* Creating a select menu using setters and API data
|
||||
* ```ts
|
||||
* const selectMenu = new SelectMenuBuilder({
|
||||
* custom_id: 'a cool select menu',
|
||||
* })
|
||||
* .setMinValues(1)
|
||||
* .addOptions({
|
||||
* label: 'Catchy',
|
||||
* value: 'catch',
|
||||
* });
|
||||
* ```
|
||||
*/
|
||||
public constructor(data?: Partial<APISelectMenuComponent>) {
|
||||
const { options, ...initData } = data ?? {};
|
||||
super({ type: ComponentType.SelectMenu, ...initData });
|
||||
this.options = options?.map((o) => new SelectMenuOptionBuilder(o)) ?? [];
|
||||
this.options = options?.map((option) => new SelectMenuOptionBuilder(option)) ?? [];
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -83,7 +114,8 @@ export class SelectMenuBuilder extends ComponentBuilder<APISelectMenuComponent>
|
||||
* @param options - The options to add to this select menu
|
||||
* @returns
|
||||
*/
|
||||
public addOptions(...options: RestOrArray<SelectMenuOptionBuilder | APISelectMenuOption>) {
|
||||
public addOptions(...options: RestOrArray<APISelectMenuOption | SelectMenuOptionBuilder>) {
|
||||
// eslint-disable-next-line no-param-reassign
|
||||
options = normalizeArray(options);
|
||||
optionsLengthValidator.parse(this.options.length + options.length);
|
||||
this.options.push(
|
||||
@@ -101,7 +133,8 @@ export class SelectMenuBuilder extends ComponentBuilder<APISelectMenuComponent>
|
||||
*
|
||||
* @param options - The options to set on this select menu
|
||||
*/
|
||||
public setOptions(...options: RestOrArray<SelectMenuOptionBuilder | APISelectMenuOption>) {
|
||||
public setOptions(...options: RestOrArray<APISelectMenuOption | SelectMenuOptionBuilder>) {
|
||||
// eslint-disable-next-line no-param-reassign
|
||||
options = normalizeArray(options);
|
||||
optionsLengthValidator.parse(options.length);
|
||||
this.options.splice(
|
||||
@@ -121,10 +154,10 @@ export class SelectMenuBuilder extends ComponentBuilder<APISelectMenuComponent>
|
||||
*/
|
||||
public toJSON(): APISelectMenuComponent {
|
||||
validateRequiredSelectMenuParameters(this.options, this.data.custom_id);
|
||||
// eslint-disable-next-line @typescript-eslint/consistent-type-assertions
|
||||
|
||||
return {
|
||||
...this.data,
|
||||
options: this.options.map((o) => o.toJSON()),
|
||||
options: this.options.map((option) => option.toJSON()),
|
||||
} as APISelectMenuComponent;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,17 +1,38 @@
|
||||
import type { APIMessageComponentEmoji, APISelectMenuOption } from 'discord-api-types/v10';
|
||||
import type { JSONEncodable } from '../../util/jsonEncodable';
|
||||
|
||||
import type { JSONEncodable } from '../../util/jsonEncodable.js';
|
||||
import {
|
||||
defaultValidator,
|
||||
emojiValidator,
|
||||
labelValueDescriptionValidator,
|
||||
validateRequiredSelectMenuOptionParameters,
|
||||
} from '../Assertions';
|
||||
} from '../Assertions.js';
|
||||
|
||||
/**
|
||||
* Represents a option within a select menu component
|
||||
*/
|
||||
export class SelectMenuOptionBuilder implements JSONEncodable<APISelectMenuOption> {
|
||||
/**
|
||||
* Creates a new select menu option from API data
|
||||
*
|
||||
* @param data - The API data to create this select menu option with
|
||||
* @example
|
||||
* Creating a select menu option from an API data object
|
||||
* ```ts
|
||||
* const selectMenuOption = new SelectMenuOptionBuilder({
|
||||
* label: 'catchy label',
|
||||
* value: '1',
|
||||
* });
|
||||
* ```
|
||||
* @example
|
||||
* Creating a select menu option using setters and API data
|
||||
* ```ts
|
||||
* const selectMenuOption = new SelectMenuOptionBuilder({
|
||||
* default: true,
|
||||
* value: '1',
|
||||
* })
|
||||
* .setLabel('woah')
|
||||
* ```
|
||||
*/
|
||||
public constructor(public data: Partial<APISelectMenuOption> = {}) {}
|
||||
|
||||
/**
|
||||
@@ -69,7 +90,7 @@ export class SelectMenuOptionBuilder implements JSONEncodable<APISelectMenuOptio
|
||||
*/
|
||||
public toJSON(): APISelectMenuOption {
|
||||
validateRequiredSelectMenuOptionParameters(this.data.label, this.data.value);
|
||||
// eslint-disable-next-line @typescript-eslint/consistent-type-assertions
|
||||
|
||||
return {
|
||||
...this.data,
|
||||
} as APISelectMenuOption;
|
||||
|
||||
@@ -1,19 +1,19 @@
|
||||
import { s } from '@sapphire/shapeshift';
|
||||
import { TextInputStyle } from 'discord-api-types/v10';
|
||||
import { isValidationEnabled } from '../../util/validation';
|
||||
import { customIdValidator } from '../Assertions';
|
||||
import { isValidationEnabled } from '../../util/validation.js';
|
||||
import { customIdValidator } from '../Assertions.js';
|
||||
|
||||
export const textInputStyleValidator = s.nativeEnum(TextInputStyle);
|
||||
export const minLengthValidator = s.number.int
|
||||
.greaterThanOrEqual(0)
|
||||
.lessThanOrEqual(4000)
|
||||
.lessThanOrEqual(4_000)
|
||||
.setValidationEnabled(isValidationEnabled);
|
||||
export const maxLengthValidator = s.number.int
|
||||
.greaterThanOrEqual(1)
|
||||
.lessThanOrEqual(4000)
|
||||
.lessThanOrEqual(4_000)
|
||||
.setValidationEnabled(isValidationEnabled);
|
||||
export const requiredValidator = s.boolean;
|
||||
export const valueValidator = s.string.lengthLessThanOrEqual(4000).setValidationEnabled(isValidationEnabled);
|
||||
export const valueValidator = s.string.lengthLessThanOrEqual(4_000).setValidationEnabled(isValidationEnabled);
|
||||
export const placeholderValidator = s.string.lengthLessThanOrEqual(100).setValidationEnabled(isValidationEnabled);
|
||||
export const labelValidator = s.string
|
||||
.lengthGreaterThanOrEqual(1)
|
||||
|
||||
@@ -1,5 +1,9 @@
|
||||
import { ComponentType, type TextInputStyle, type APITextInputComponent } from 'discord-api-types/v10';
|
||||
import isEqual from 'fast-deep-equal';
|
||||
import type { Equatable } from '../../util/equatable';
|
||||
import { isJSONEncodable, type JSONEncodable } from '../../util/jsonEncodable.js';
|
||||
import { customIdValidator } from '../Assertions.js';
|
||||
import { ComponentBuilder } from '../Component.js';
|
||||
import {
|
||||
maxLengthValidator,
|
||||
minLengthValidator,
|
||||
@@ -9,16 +13,35 @@ import {
|
||||
validateRequiredParameters,
|
||||
labelValidator,
|
||||
textInputStyleValidator,
|
||||
} from './Assertions';
|
||||
import type { Equatable } from '../../util/equatable';
|
||||
import { isJSONEncodable, type JSONEncodable } from '../../util/jsonEncodable';
|
||||
import { customIdValidator } from '../Assertions';
|
||||
import { ComponentBuilder } from '../Component';
|
||||
} from './Assertions.js';
|
||||
|
||||
export class TextInputBuilder
|
||||
extends ComponentBuilder<APITextInputComponent>
|
||||
implements Equatable<JSONEncodable<APITextInputComponent> | APITextInputComponent>
|
||||
implements Equatable<APITextInputComponent | JSONEncodable<APITextInputComponent>>
|
||||
{
|
||||
/**
|
||||
* Creates a new text input from API data
|
||||
*
|
||||
* @param data - The API data to create this text input with
|
||||
* @example
|
||||
* Creating a select menu option from an API data object
|
||||
* ```ts
|
||||
* const textInput = new TextInputBuilder({
|
||||
* custom_id: 'a cool select menu',
|
||||
* label: 'Type something',
|
||||
* style: TextInputStyle.Short,
|
||||
* });
|
||||
* ```
|
||||
* @example
|
||||
* Creating a select menu option using setters and API data
|
||||
* ```ts
|
||||
* const textInput = new TextInputBuilder({
|
||||
* label: 'Type something else',
|
||||
* })
|
||||
* .setCustomId('woah')
|
||||
* .setStyle(TextInputStyle.Paragraph);
|
||||
* ```
|
||||
*/
|
||||
public constructor(data?: APITextInputComponent & { type?: ComponentType.TextInput }) {
|
||||
super({ type: ComponentType.TextInput, ...data });
|
||||
}
|
||||
@@ -108,7 +131,7 @@ export class TextInputBuilder
|
||||
*/
|
||||
public toJSON(): APITextInputComponent {
|
||||
validateRequiredParameters(this.data.custom_id, this.data.style, this.data.label);
|
||||
// eslint-disable-next-line @typescript-eslint/consistent-type-assertions
|
||||
|
||||
return {
|
||||
...this.data,
|
||||
} as APITextInputComponent;
|
||||
@@ -117,7 +140,7 @@ export class TextInputBuilder
|
||||
/**
|
||||
* {@inheritDoc Equatable.equals}
|
||||
*/
|
||||
public equals(other: JSONEncodable<APITextInputComponent> | APITextInputComponent): boolean {
|
||||
public equals(other: APITextInputComponent | JSONEncodable<APITextInputComponent>): boolean {
|
||||
if (isJSONEncodable(other)) {
|
||||
return isEqual(other.toJSON(), this.data);
|
||||
}
|
||||
|
||||
@@ -1,43 +1,43 @@
|
||||
export * as EmbedAssertions from './messages/embed/Assertions';
|
||||
export * from './messages/embed/Embed';
|
||||
export * from './messages/formatters';
|
||||
export * as EmbedAssertions from './messages/embed/Assertions.js';
|
||||
export * from './messages/embed/Embed.js';
|
||||
export * from './messages/formatters.js';
|
||||
|
||||
export * as ComponentAssertions from './components/Assertions';
|
||||
export * from './components/ActionRow';
|
||||
export * from './components/button/Button';
|
||||
export * from './components/Component';
|
||||
export * from './components/Components';
|
||||
export * from './components/textInput/TextInput';
|
||||
export * as TextInputAssertions from './components/textInput/Assertions';
|
||||
export * from './interactions/modals/Modal';
|
||||
export * as ModalAssertions from './interactions/modals/Assertions';
|
||||
export * from './components/selectMenu/SelectMenu';
|
||||
export * from './components/selectMenu/SelectMenuOption';
|
||||
export * as ComponentAssertions from './components/Assertions.js';
|
||||
export * from './components/ActionRow.js';
|
||||
export * from './components/button/Button.js';
|
||||
export * from './components/Component.js';
|
||||
export * from './components/Components.js';
|
||||
export * from './components/textInput/TextInput.js';
|
||||
export * as TextInputAssertions from './components/textInput/Assertions.js';
|
||||
export * from './interactions/modals/Modal.js';
|
||||
export * as ModalAssertions from './interactions/modals/Assertions.js';
|
||||
export * from './components/selectMenu/SelectMenu.js';
|
||||
export * from './components/selectMenu/SelectMenuOption.js';
|
||||
|
||||
export * as SlashCommandAssertions from './interactions/slashCommands/Assertions';
|
||||
export * from './interactions/slashCommands/SlashCommandBuilder';
|
||||
export * from './interactions/slashCommands/SlashCommandSubcommands';
|
||||
export * from './interactions/slashCommands/options/boolean';
|
||||
export * from './interactions/slashCommands/options/channel';
|
||||
export * from './interactions/slashCommands/options/integer';
|
||||
export * from './interactions/slashCommands/options/mentionable';
|
||||
export * from './interactions/slashCommands/options/number';
|
||||
export * from './interactions/slashCommands/options/role';
|
||||
export * from './interactions/slashCommands/options/attachment';
|
||||
export * from './interactions/slashCommands/options/string';
|
||||
export * from './interactions/slashCommands/options/user';
|
||||
export * from './interactions/slashCommands/mixins/ApplicationCommandNumericOptionMinMaxValueMixin';
|
||||
export * from './interactions/slashCommands/mixins/ApplicationCommandOptionBase';
|
||||
export * from './interactions/slashCommands/mixins/ApplicationCommandOptionChannelTypesMixin';
|
||||
export * from './interactions/slashCommands/mixins/ApplicationCommandOptionWithChoicesAndAutocompleteMixin';
|
||||
export * from './interactions/slashCommands/mixins/NameAndDescription';
|
||||
export * from './interactions/slashCommands/mixins/SharedSlashCommandOptions';
|
||||
export * as SlashCommandAssertions from './interactions/slashCommands/Assertions.js';
|
||||
export * from './interactions/slashCommands/SlashCommandBuilder.js';
|
||||
export * from './interactions/slashCommands/SlashCommandSubcommands.js';
|
||||
export * from './interactions/slashCommands/options/boolean.js';
|
||||
export * from './interactions/slashCommands/options/channel.js';
|
||||
export * from './interactions/slashCommands/options/integer.js';
|
||||
export * from './interactions/slashCommands/options/mentionable.js';
|
||||
export * from './interactions/slashCommands/options/number.js';
|
||||
export * from './interactions/slashCommands/options/role.js';
|
||||
export * from './interactions/slashCommands/options/attachment.js';
|
||||
export * from './interactions/slashCommands/options/string.js';
|
||||
export * from './interactions/slashCommands/options/user.js';
|
||||
export * from './interactions/slashCommands/mixins/ApplicationCommandNumericOptionMinMaxValueMixin.js';
|
||||
export * from './interactions/slashCommands/mixins/ApplicationCommandOptionBase.js';
|
||||
export * from './interactions/slashCommands/mixins/ApplicationCommandOptionChannelTypesMixin.js';
|
||||
export * from './interactions/slashCommands/mixins/ApplicationCommandOptionWithChoicesAndAutocompleteMixin.js';
|
||||
export * from './interactions/slashCommands/mixins/NameAndDescription.js';
|
||||
export * from './interactions/slashCommands/mixins/SharedSlashCommandOptions.js';
|
||||
|
||||
export * as ContextMenuCommandAssertions from './interactions/contextMenuCommands/Assertions';
|
||||
export * from './interactions/contextMenuCommands/ContextMenuCommandBuilder';
|
||||
export * as ContextMenuCommandAssertions from './interactions/contextMenuCommands/Assertions.js';
|
||||
export * from './interactions/contextMenuCommands/ContextMenuCommandBuilder.js';
|
||||
|
||||
export * from './util/jsonEncodable';
|
||||
export * from './util/equatable';
|
||||
export * from './util/componentUtil';
|
||||
export * from './util/normalizeArray';
|
||||
export * from './util/validation';
|
||||
export * from './util/jsonEncodable.js';
|
||||
export * from './util/equatable.js';
|
||||
export * from './util/componentUtil.js';
|
||||
export * from './util/normalizeArray.js';
|
||||
export * from './util/validation.js';
|
||||
|
||||
@@ -1,11 +1,12 @@
|
||||
import { s } from '@sapphire/shapeshift';
|
||||
import { ApplicationCommandType } from 'discord-api-types/v10';
|
||||
import type { ContextMenuCommandType } from './ContextMenuCommandBuilder';
|
||||
import { isValidationEnabled } from '../../util/validation';
|
||||
import { isValidationEnabled } from '../../util/validation.js';
|
||||
import type { ContextMenuCommandType } from './ContextMenuCommandBuilder.js';
|
||||
|
||||
const namePredicate = s.string
|
||||
.lengthGreaterThanOrEqual(1)
|
||||
.lengthLessThanOrEqual(32)
|
||||
// eslint-disable-next-line prefer-named-capture-group, unicorn/no-unsafe-regex
|
||||
.regex(/^( *[\p{L}\p{N}\p{sc=Devanagari}\p{sc=Thai}_-]+ *)+$/u)
|
||||
.setValidationEnabled(isValidationEnabled);
|
||||
const typePredicate = s
|
||||
|
||||
@@ -3,8 +3,9 @@ import type {
|
||||
LocaleString,
|
||||
LocalizationMap,
|
||||
Permissions,
|
||||
RESTPostAPIApplicationCommandsJSONBody,
|
||||
RESTPostAPIContextMenuApplicationCommandsJSONBody,
|
||||
} from 'discord-api-types/v10';
|
||||
import { validateLocale, validateLocalizationMap } from '../slashCommands/Assertions.js';
|
||||
import {
|
||||
validateRequiredParameters,
|
||||
validateName,
|
||||
@@ -12,8 +13,7 @@ import {
|
||||
validateDefaultPermission,
|
||||
validateDefaultMemberPermissions,
|
||||
validateDMPermission,
|
||||
} from './Assertions';
|
||||
import { validateLocale, validateLocalizationMap } from '../slashCommands/Assertions';
|
||||
} from './Assertions.js';
|
||||
|
||||
export class ContextMenuCommandBuilder {
|
||||
/**
|
||||
@@ -81,10 +81,9 @@ export class ContextMenuCommandBuilder {
|
||||
/**
|
||||
* Sets whether the command is enabled by default when the application is added to a guild.
|
||||
*
|
||||
* **Note**: If set to `false`, you will have to later `PUT` the permissions for this command.
|
||||
*
|
||||
* @remarks
|
||||
* If set to `false`, you will have to later `PUT` the permissions for this command.
|
||||
* @param value - Whether or not to enable this command by default
|
||||
*
|
||||
* @see https://discord.com/developers/docs/interactions/application-commands#permissions
|
||||
* @deprecated Use {@link ContextMenuCommandBuilder.setDefaultMemberPermissions} or {@link ContextMenuCommandBuilder.setDMPermission} instead.
|
||||
*/
|
||||
@@ -100,10 +99,9 @@ export class ContextMenuCommandBuilder {
|
||||
/**
|
||||
* Sets the default permissions a member should have in order to run the command.
|
||||
*
|
||||
* **Note:** You can set this to `'0'` to disable the command by default.
|
||||
*
|
||||
* @remarks
|
||||
* You can set this to `'0'` to disable the command by default.
|
||||
* @param permissions - The permissions bit field to set
|
||||
*
|
||||
* @see https://discord.com/developers/docs/interactions/application-commands#permissions
|
||||
*/
|
||||
public setDefaultMemberPermissions(permissions: Permissions | bigint | number | null | undefined) {
|
||||
@@ -120,7 +118,6 @@ export class ContextMenuCommandBuilder {
|
||||
* By default, commands are visible.
|
||||
*
|
||||
* @param enabled - If the command should be enabled in DMs
|
||||
*
|
||||
* @see https://discord.com/developers/docs/interactions/application-commands#permissions
|
||||
*/
|
||||
public setDMPermission(enabled: boolean | null | undefined) {
|
||||
@@ -169,18 +166,19 @@ export class ContextMenuCommandBuilder {
|
||||
|
||||
Reflect.set(this, 'name_localizations', {});
|
||||
|
||||
Object.entries(localizedNames).forEach((args) =>
|
||||
this.setNameLocalization(...(args as [LocaleString, string | null])),
|
||||
);
|
||||
for (const args of Object.entries(localizedNames))
|
||||
this.setNameLocalization(...(args as [LocaleString, string | null]));
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the final data that should be sent to Discord.
|
||||
*
|
||||
* **Note:** Calling this function will validate required properties based on their conditions.
|
||||
* @remarks
|
||||
* This method runs validations on the data before serializing it.
|
||||
* As such, it may throw an error if the data is invalid.
|
||||
*/
|
||||
public toJSON(): RESTPostAPIApplicationCommandsJSONBody {
|
||||
public toJSON(): RESTPostAPIContextMenuApplicationCommandsJSONBody {
|
||||
validateRequiredParameters(this.name, this.type);
|
||||
|
||||
validateLocalizationMap(this.name_localizations);
|
||||
@@ -189,4 +187,4 @@ export class ContextMenuCommandBuilder {
|
||||
}
|
||||
}
|
||||
|
||||
export type ContextMenuCommandType = ApplicationCommandType.User | ApplicationCommandType.Message;
|
||||
export type ContextMenuCommandType = ApplicationCommandType.Message | ApplicationCommandType.User;
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
import { s } from '@sapphire/shapeshift';
|
||||
import { ActionRowBuilder, type ModalActionRowComponentBuilder } from '../../components/ActionRow';
|
||||
import { customIdValidator } from '../../components/Assertions';
|
||||
import { isValidationEnabled } from '../../util/validation';
|
||||
import { ActionRowBuilder, type ModalActionRowComponentBuilder } from '../../components/ActionRow.js';
|
||||
import { customIdValidator } from '../../components/Assertions.js';
|
||||
import { isValidationEnabled } from '../../util/validation.js';
|
||||
|
||||
export const titleValidator = s.string
|
||||
.lengthGreaterThanOrEqual(1)
|
||||
|
||||
@@ -3,20 +3,21 @@ import type {
|
||||
APIModalActionRowComponent,
|
||||
APIModalInteractionResponseCallbackData,
|
||||
} from 'discord-api-types/v10';
|
||||
import { titleValidator, validateRequiredParameters } from './Assertions';
|
||||
import { ActionRowBuilder, type ModalActionRowComponentBuilder } from '../../components/ActionRow';
|
||||
import { customIdValidator } from '../../components/Assertions';
|
||||
import { createComponentBuilder } from '../../components/Components';
|
||||
import { ActionRowBuilder, type ModalActionRowComponentBuilder } from '../../components/ActionRow.js';
|
||||
import { customIdValidator } from '../../components/Assertions.js';
|
||||
import { createComponentBuilder } from '../../components/Components.js';
|
||||
import type { JSONEncodable } from '../../util/jsonEncodable';
|
||||
import { normalizeArray, type RestOrArray } from '../../util/normalizeArray';
|
||||
import { normalizeArray, type RestOrArray } from '../../util/normalizeArray.js';
|
||||
import { titleValidator, validateRequiredParameters } from './Assertions.js';
|
||||
|
||||
export class ModalBuilder implements JSONEncodable<APIModalInteractionResponseCallbackData> {
|
||||
public readonly data: Partial<APIModalInteractionResponseCallbackData>;
|
||||
|
||||
public readonly components: ActionRowBuilder<ModalActionRowComponentBuilder>[] = [];
|
||||
|
||||
public constructor({ components, ...data }: Partial<APIModalInteractionResponseCallbackData> = {}) {
|
||||
this.data = { ...data };
|
||||
this.components = (components?.map((c) => createComponentBuilder(c)) ??
|
||||
this.components = (components?.map((component) => createComponentBuilder(component)) ??
|
||||
[]) as ActionRowBuilder<ModalActionRowComponentBuilder>[];
|
||||
}
|
||||
|
||||
@@ -75,7 +76,7 @@ export class ModalBuilder implements JSONEncodable<APIModalInteractionResponseCa
|
||||
*/
|
||||
public toJSON(): APIModalInteractionResponseCallbackData {
|
||||
validateRequiredParameters(this.data.custom_id, this.data.title, this.components);
|
||||
// eslint-disable-next-line @typescript-eslint/consistent-type-assertions
|
||||
|
||||
return {
|
||||
...this.data,
|
||||
components: this.components.map((component) => component.toJSON()),
|
||||
|
||||
@@ -1,9 +1,9 @@
|
||||
import { s } from '@sapphire/shapeshift';
|
||||
import { type APIApplicationCommandOptionChoice, Locale, LocalizationMap } from 'discord-api-types/v10';
|
||||
import type { ToAPIApplicationCommandOptions } from './SlashCommandBuilder';
|
||||
import type { SlashCommandSubcommandBuilder, SlashCommandSubcommandGroupBuilder } from './SlashCommandSubcommands';
|
||||
import type { ApplicationCommandOptionBase } from './mixins/ApplicationCommandOptionBase';
|
||||
import { isValidationEnabled } from '../../util/validation';
|
||||
import { Locale, type APIApplicationCommandOptionChoice, type LocalizationMap } from 'discord-api-types/v10';
|
||||
import { isValidationEnabled } from '../../util/validation.js';
|
||||
import type { ToAPIApplicationCommandOptions } from './SlashCommandBuilder.js';
|
||||
import type { SlashCommandSubcommandBuilder, SlashCommandSubcommandGroupBuilder } from './SlashCommandSubcommands.js';
|
||||
import type { ApplicationCommandOptionBase } from './mixins/ApplicationCommandOptionBase.js';
|
||||
|
||||
const namePredicate = s.string
|
||||
.lengthGreaterThanOrEqual(1)
|
||||
|
||||
@@ -2,7 +2,7 @@ import type {
|
||||
APIApplicationCommandOption,
|
||||
LocalizationMap,
|
||||
Permissions,
|
||||
RESTPostAPIApplicationCommandsJSONBody,
|
||||
RESTPostAPIChatInputApplicationCommandsJSONBody,
|
||||
} from 'discord-api-types/v10';
|
||||
import { mix } from 'ts-mixer';
|
||||
import {
|
||||
@@ -13,10 +13,10 @@ import {
|
||||
validateDMPermission,
|
||||
validateMaxOptionsLength,
|
||||
validateRequiredParameters,
|
||||
} from './Assertions';
|
||||
import { SlashCommandSubcommandBuilder, SlashCommandSubcommandGroupBuilder } from './SlashCommandSubcommands';
|
||||
import { SharedNameAndDescription } from './mixins/NameAndDescription';
|
||||
import { SharedSlashCommandOptions } from './mixins/SharedSlashCommandOptions';
|
||||
} from './Assertions.js';
|
||||
import { SlashCommandSubcommandBuilder, SlashCommandSubcommandGroupBuilder } from './SlashCommandSubcommands.js';
|
||||
import { SharedNameAndDescription } from './mixins/NameAndDescription.js';
|
||||
import { SharedSlashCommandOptions } from './mixins/SharedSlashCommandOptions.js';
|
||||
|
||||
@mix(SharedSlashCommandOptions, SharedNameAndDescription)
|
||||
export class SlashCommandBuilder {
|
||||
@@ -67,9 +67,11 @@ export class SlashCommandBuilder {
|
||||
/**
|
||||
* Returns the final data that should be sent to Discord.
|
||||
*
|
||||
* **Note:** Calling this function will validate required properties based on their conditions.
|
||||
* @remarks
|
||||
* This method runs validations on the data before serializing it.
|
||||
* As such, it may throw an error if the data is invalid.
|
||||
*/
|
||||
public toJSON(): RESTPostAPIApplicationCommandsJSONBody {
|
||||
public toJSON(): RESTPostAPIChatInputApplicationCommandsJSONBody {
|
||||
validateRequiredParameters(this.name, this.description, this.options);
|
||||
|
||||
validateLocalizationMap(this.name_localizations);
|
||||
@@ -84,10 +86,9 @@ export class SlashCommandBuilder {
|
||||
/**
|
||||
* Sets whether the command is enabled by default when the application is added to a guild.
|
||||
*
|
||||
* **Note**: If set to `false`, you will have to later `PUT` the permissions for this command.
|
||||
*
|
||||
* @remarks
|
||||
* If set to `false`, you will have to later `PUT` the permissions for this command.
|
||||
* @param value - Whether or not to enable this command by default
|
||||
*
|
||||
* @see https://discord.com/developers/docs/interactions/application-commands#permissions
|
||||
* @deprecated Use {@link (SlashCommandBuilder:class).setDefaultMemberPermissions} or {@link (SlashCommandBuilder:class).setDMPermission} instead.
|
||||
*/
|
||||
@@ -103,10 +104,9 @@ export class SlashCommandBuilder {
|
||||
/**
|
||||
* Sets the default permissions a member should have in order to run the command.
|
||||
*
|
||||
* **Note:** You can set this to `'0'` to disable the command by default.
|
||||
*
|
||||
* @remarks
|
||||
* You can set this to `'0'` to disable the command by default.
|
||||
* @param permissions - The permissions bit field to set
|
||||
*
|
||||
* @see https://discord.com/developers/docs/interactions/application-commands#permissions
|
||||
*/
|
||||
public setDefaultMemberPermissions(permissions: Permissions | bigint | number | null | undefined) {
|
||||
@@ -123,7 +123,6 @@ export class SlashCommandBuilder {
|
||||
* By default, commands are visible.
|
||||
*
|
||||
* @param enabled - If the command should be enabled in DMs
|
||||
*
|
||||
* @see https://discord.com/developers/docs/interactions/application-commands#permissions
|
||||
*/
|
||||
public setDMPermission(enabled: boolean | null | undefined) {
|
||||
@@ -191,8 +190,7 @@ export class SlashCommandBuilder {
|
||||
export interface SlashCommandBuilder extends SharedNameAndDescription, SharedSlashCommandOptions {}
|
||||
|
||||
export interface SlashCommandSubcommandsOnlyBuilder
|
||||
extends SharedNameAndDescription,
|
||||
Pick<SlashCommandBuilder, 'toJSON' | 'addSubcommand' | 'addSubcommandGroup'> {}
|
||||
extends Omit<SlashCommandBuilder, Exclude<keyof SharedSlashCommandOptions, 'options'>> {}
|
||||
|
||||
export interface SlashCommandOptionsOnlyBuilder
|
||||
extends SharedNameAndDescription,
|
||||
@@ -200,5 +198,5 @@ export interface SlashCommandOptionsOnlyBuilder
|
||||
Pick<SlashCommandBuilder, 'toJSON'> {}
|
||||
|
||||
export interface ToAPIApplicationCommandOptions {
|
||||
toJSON: () => APIApplicationCommandOption;
|
||||
toJSON(): APIApplicationCommandOption;
|
||||
}
|
||||
|
||||
@@ -1,14 +1,14 @@
|
||||
import {
|
||||
APIApplicationCommandSubcommandGroupOption,
|
||||
APIApplicationCommandSubcommandOption,
|
||||
ApplicationCommandOptionType,
|
||||
type APIApplicationCommandSubcommandGroupOption,
|
||||
type APIApplicationCommandSubcommandOption,
|
||||
} from 'discord-api-types/v10';
|
||||
import { mix } from 'ts-mixer';
|
||||
import { assertReturnOfBuilder, validateMaxOptionsLength, validateRequiredParameters } from './Assertions';
|
||||
import type { ToAPIApplicationCommandOptions } from './SlashCommandBuilder';
|
||||
import type { ApplicationCommandOptionBase } from './mixins/ApplicationCommandOptionBase';
|
||||
import { SharedNameAndDescription } from './mixins/NameAndDescription';
|
||||
import { SharedSlashCommandOptions } from './mixins/SharedSlashCommandOptions';
|
||||
import { assertReturnOfBuilder, validateMaxOptionsLength, validateRequiredParameters } from './Assertions.js';
|
||||
import type { ToAPIApplicationCommandOptions } from './SlashCommandBuilder.js';
|
||||
import type { ApplicationCommandOptionBase } from './mixins/ApplicationCommandOptionBase.js';
|
||||
import { SharedNameAndDescription } from './mixins/NameAndDescription.js';
|
||||
import { SharedSlashCommandOptions } from './mixins/SharedSlashCommandOptions.js';
|
||||
|
||||
/**
|
||||
* Represents a folder for subcommands
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
export abstract class ApplicationCommandNumericOptionMinMaxValueMixin {
|
||||
public readonly max_value?: number;
|
||||
|
||||
public readonly min_value?: number;
|
||||
|
||||
/**
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
import type { APIApplicationCommandBasicOption, ApplicationCommandOptionType } from 'discord-api-types/v10';
|
||||
import { SharedNameAndDescription } from './NameAndDescription';
|
||||
import { validateRequiredParameters, validateRequired, validateLocalizationMap } from '../Assertions';
|
||||
import { validateRequiredParameters, validateRequired, validateLocalizationMap } from '../Assertions.js';
|
||||
import { SharedNameAndDescription } from './NameAndDescription.js';
|
||||
|
||||
export abstract class ApplicationCommandOptionBase extends SharedNameAndDescription {
|
||||
public abstract readonly type: ApplicationCommandOptionType;
|
||||
|
||||
@@ -6,11 +6,12 @@ const allowedChannelTypes = [
|
||||
ChannelType.GuildText,
|
||||
ChannelType.GuildVoice,
|
||||
ChannelType.GuildCategory,
|
||||
ChannelType.GuildNews,
|
||||
ChannelType.GuildNewsThread,
|
||||
ChannelType.GuildPublicThread,
|
||||
ChannelType.GuildPrivateThread,
|
||||
ChannelType.GuildAnnouncement,
|
||||
ChannelType.AnnouncementThread,
|
||||
ChannelType.PublicThread,
|
||||
ChannelType.PrivateThread,
|
||||
ChannelType.GuildStageVoice,
|
||||
ChannelType.GuildForum,
|
||||
] as const;
|
||||
|
||||
export type ApplicationCommandOptionAllowedChannelTypes = typeof allowedChannelTypes[number];
|
||||
|
||||
@@ -1,9 +1,9 @@
|
||||
import { s } from '@sapphire/shapeshift';
|
||||
import { APIApplicationCommandOptionChoice, ApplicationCommandOptionType } from 'discord-api-types/v10';
|
||||
import { localizationMapPredicate, validateChoicesLength } from '../Assertions';
|
||||
import { ApplicationCommandOptionType, type APIApplicationCommandOptionChoice } from 'discord-api-types/v10';
|
||||
import { localizationMapPredicate, validateChoicesLength } from '../Assertions.js';
|
||||
|
||||
const stringPredicate = s.string.lengthGreaterThanOrEqual(1).lengthLessThanOrEqual(100);
|
||||
const numberPredicate = s.number.greaterThan(-Infinity).lessThan(Infinity);
|
||||
const numberPredicate = s.number.greaterThan(Number.NEGATIVE_INFINITY).lessThan(Number.POSITIVE_INFINITY);
|
||||
const choicesPredicate = s.object({
|
||||
name: stringPredicate,
|
||||
name_localizations: localizationMapPredicate,
|
||||
@@ -11,8 +11,9 @@ const choicesPredicate = s.object({
|
||||
}).array;
|
||||
const booleanPredicate = s.boolean;
|
||||
|
||||
export class ApplicationCommandOptionWithChoicesAndAutocompleteMixin<T extends string | number> {
|
||||
export class ApplicationCommandOptionWithChoicesAndAutocompleteMixin<T extends number | string> {
|
||||
public readonly choices?: APIApplicationCommandOptionChoice<T>[];
|
||||
|
||||
public readonly autocomplete?: boolean;
|
||||
|
||||
// Since this is present and this is a mixin, this is needed
|
||||
@@ -65,6 +66,7 @@ export class ApplicationCommandOptionWithChoicesAndAutocompleteMixin<T extends s
|
||||
|
||||
/**
|
||||
* Marks the option as autocompletable
|
||||
*
|
||||
* @param autocomplete - If this option should be autocompletable
|
||||
*/
|
||||
public setAutocomplete(autocomplete: boolean): this {
|
||||
|
||||
@@ -1,10 +1,13 @@
|
||||
import type { LocaleString, LocalizationMap } from 'discord-api-types/v10';
|
||||
import { validateDescription, validateLocale, validateName } from '../Assertions';
|
||||
import { validateDescription, validateLocale, validateName } from '../Assertions.js';
|
||||
|
||||
export class SharedNameAndDescription {
|
||||
public readonly name!: string;
|
||||
|
||||
public readonly name_localizations?: LocalizationMap;
|
||||
|
||||
public readonly description!: string;
|
||||
|
||||
public readonly description_localizations?: LocalizationMap;
|
||||
|
||||
/**
|
||||
@@ -72,9 +75,10 @@ export class SharedNameAndDescription {
|
||||
|
||||
Reflect.set(this, 'name_localizations', {});
|
||||
|
||||
Object.entries(localizedNames).forEach((args) =>
|
||||
this.setNameLocalization(...(args as [LocaleString, string | null])),
|
||||
);
|
||||
for (const args of Object.entries(localizedNames)) {
|
||||
this.setNameLocalization(...(args as [LocaleString, string | null]));
|
||||
}
|
||||
|
||||
return this;
|
||||
}
|
||||
|
||||
@@ -114,9 +118,10 @@ export class SharedNameAndDescription {
|
||||
}
|
||||
|
||||
Reflect.set(this, 'description_localizations', {});
|
||||
Object.entries(localizedDescriptions).forEach((args) =>
|
||||
this.setDescriptionLocalization(...(args as [LocaleString, string | null])),
|
||||
);
|
||||
for (const args of Object.entries(localizedDescriptions)) {
|
||||
this.setDescriptionLocalization(...(args as [LocaleString, string | null]));
|
||||
}
|
||||
|
||||
return this;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,15 +1,15 @@
|
||||
import type { ApplicationCommandOptionBase } from './ApplicationCommandOptionBase';
|
||||
import { assertReturnOfBuilder, validateMaxOptionsLength } from '../Assertions';
|
||||
import { assertReturnOfBuilder, validateMaxOptionsLength } from '../Assertions.js';
|
||||
import type { ToAPIApplicationCommandOptions } from '../SlashCommandBuilder';
|
||||
import { SlashCommandAttachmentOption } from '../options/attachment';
|
||||
import { SlashCommandBooleanOption } from '../options/boolean';
|
||||
import { SlashCommandChannelOption } from '../options/channel';
|
||||
import { SlashCommandIntegerOption } from '../options/integer';
|
||||
import { SlashCommandMentionableOption } from '../options/mentionable';
|
||||
import { SlashCommandNumberOption } from '../options/number';
|
||||
import { SlashCommandRoleOption } from '../options/role';
|
||||
import { SlashCommandStringOption } from '../options/string';
|
||||
import { SlashCommandUserOption } from '../options/user';
|
||||
import { SlashCommandAttachmentOption } from '../options/attachment.js';
|
||||
import { SlashCommandBooleanOption } from '../options/boolean.js';
|
||||
import { SlashCommandChannelOption } from '../options/channel.js';
|
||||
import { SlashCommandIntegerOption } from '../options/integer.js';
|
||||
import { SlashCommandMentionableOption } from '../options/mentionable.js';
|
||||
import { SlashCommandNumberOption } from '../options/number.js';
|
||||
import { SlashCommandRoleOption } from '../options/role.js';
|
||||
import { SlashCommandStringOption } from '../options/string.js';
|
||||
import { SlashCommandUserOption } from '../options/user.js';
|
||||
import type { ApplicationCommandOptionBase } from './ApplicationCommandOptionBase.js';
|
||||
|
||||
export class SharedSlashCommandOptions<ShouldOmitSubcommandFunctions = true> {
|
||||
public readonly options!: ToAPIApplicationCommandOptions[];
|
||||
@@ -83,15 +83,15 @@ export class SharedSlashCommandOptions<ShouldOmitSubcommandFunctions = true> {
|
||||
*/
|
||||
public addStringOption(
|
||||
input:
|
||||
| SlashCommandStringOption
|
||||
| Omit<SlashCommandStringOption, 'setAutocomplete'>
|
||||
| Omit<SlashCommandStringOption, 'addChoices'>
|
||||
| Omit<SlashCommandStringOption, 'setAutocomplete'>
|
||||
| SlashCommandStringOption
|
||||
| ((
|
||||
builder: SlashCommandStringOption,
|
||||
) =>
|
||||
| SlashCommandStringOption
|
||||
| Omit<SlashCommandStringOption, 'addChoices'>
|
||||
| Omit<SlashCommandStringOption, 'setAutocomplete'>
|
||||
| Omit<SlashCommandStringOption, 'addChoices'>),
|
||||
| SlashCommandStringOption),
|
||||
) {
|
||||
return this._sharedAddOptionMethod(input, SlashCommandStringOption);
|
||||
}
|
||||
@@ -103,15 +103,15 @@ export class SharedSlashCommandOptions<ShouldOmitSubcommandFunctions = true> {
|
||||
*/
|
||||
public addIntegerOption(
|
||||
input:
|
||||
| SlashCommandIntegerOption
|
||||
| Omit<SlashCommandIntegerOption, 'setAutocomplete'>
|
||||
| Omit<SlashCommandIntegerOption, 'addChoices'>
|
||||
| Omit<SlashCommandIntegerOption, 'setAutocomplete'>
|
||||
| SlashCommandIntegerOption
|
||||
| ((
|
||||
builder: SlashCommandIntegerOption,
|
||||
) =>
|
||||
| SlashCommandIntegerOption
|
||||
| Omit<SlashCommandIntegerOption, 'addChoices'>
|
||||
| Omit<SlashCommandIntegerOption, 'setAutocomplete'>
|
||||
| Omit<SlashCommandIntegerOption, 'addChoices'>),
|
||||
| SlashCommandIntegerOption),
|
||||
) {
|
||||
return this._sharedAddOptionMethod(input, SlashCommandIntegerOption);
|
||||
}
|
||||
@@ -123,25 +123,25 @@ export class SharedSlashCommandOptions<ShouldOmitSubcommandFunctions = true> {
|
||||
*/
|
||||
public addNumberOption(
|
||||
input:
|
||||
| SlashCommandNumberOption
|
||||
| Omit<SlashCommandNumberOption, 'setAutocomplete'>
|
||||
| Omit<SlashCommandNumberOption, 'addChoices'>
|
||||
| Omit<SlashCommandNumberOption, 'setAutocomplete'>
|
||||
| SlashCommandNumberOption
|
||||
| ((
|
||||
builder: SlashCommandNumberOption,
|
||||
) =>
|
||||
| SlashCommandNumberOption
|
||||
| Omit<SlashCommandNumberOption, 'addChoices'>
|
||||
| Omit<SlashCommandNumberOption, 'setAutocomplete'>
|
||||
| Omit<SlashCommandNumberOption, 'addChoices'>),
|
||||
| SlashCommandNumberOption),
|
||||
) {
|
||||
return this._sharedAddOptionMethod(input, SlashCommandNumberOption);
|
||||
}
|
||||
|
||||
private _sharedAddOptionMethod<T extends ApplicationCommandOptionBase>(
|
||||
input:
|
||||
| T
|
||||
| Omit<T, 'setAutocomplete'>
|
||||
| Omit<T, 'addChoices'>
|
||||
| ((builder: T) => T | Omit<T, 'setAutocomplete'> | Omit<T, 'addChoices'>),
|
||||
| Omit<T, 'setAutocomplete'>
|
||||
| T
|
||||
| ((builder: T) => Omit<T, 'addChoices'> | Omit<T, 'setAutocomplete'> | T),
|
||||
Instance: new () => T,
|
||||
): ShouldOmitSubcommandFunctions extends true ? Omit<this, 'addSubcommand' | 'addSubcommandGroup'> : this {
|
||||
const { options } = this;
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
import { APIApplicationCommandAttachmentOption, ApplicationCommandOptionType } from 'discord-api-types/v10';
|
||||
import { ApplicationCommandOptionBase } from '../mixins/ApplicationCommandOptionBase';
|
||||
import { ApplicationCommandOptionType, type APIApplicationCommandAttachmentOption } from 'discord-api-types/v10';
|
||||
import { ApplicationCommandOptionBase } from '../mixins/ApplicationCommandOptionBase.js';
|
||||
|
||||
export class SlashCommandAttachmentOption extends ApplicationCommandOptionBase {
|
||||
public override readonly type = ApplicationCommandOptionType.Attachment as const;
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
import { APIApplicationCommandBooleanOption, ApplicationCommandOptionType } from 'discord-api-types/v10';
|
||||
import { ApplicationCommandOptionBase } from '../mixins/ApplicationCommandOptionBase';
|
||||
import { ApplicationCommandOptionType, type APIApplicationCommandBooleanOption } from 'discord-api-types/v10';
|
||||
import { ApplicationCommandOptionBase } from '../mixins/ApplicationCommandOptionBase.js';
|
||||
|
||||
export class SlashCommandBooleanOption extends ApplicationCommandOptionBase {
|
||||
public readonly type = ApplicationCommandOptionType.Boolean as const;
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
import { APIApplicationCommandChannelOption, ApplicationCommandOptionType } from 'discord-api-types/v10';
|
||||
import { ApplicationCommandOptionType, type APIApplicationCommandChannelOption } from 'discord-api-types/v10';
|
||||
import { mix } from 'ts-mixer';
|
||||
import { ApplicationCommandOptionBase } from '../mixins/ApplicationCommandOptionBase';
|
||||
import { ApplicationCommandOptionChannelTypesMixin } from '../mixins/ApplicationCommandOptionChannelTypesMixin';
|
||||
import { ApplicationCommandOptionBase } from '../mixins/ApplicationCommandOptionBase.js';
|
||||
import { ApplicationCommandOptionChannelTypesMixin } from '../mixins/ApplicationCommandOptionChannelTypesMixin.js';
|
||||
|
||||
@mix(ApplicationCommandOptionChannelTypesMixin)
|
||||
export class SlashCommandChannelOption extends ApplicationCommandOptionBase {
|
||||
|
||||
@@ -1,9 +1,9 @@
|
||||
import { s } from '@sapphire/shapeshift';
|
||||
import { APIApplicationCommandIntegerOption, ApplicationCommandOptionType } from 'discord-api-types/v10';
|
||||
import { ApplicationCommandOptionType, type APIApplicationCommandIntegerOption } from 'discord-api-types/v10';
|
||||
import { mix } from 'ts-mixer';
|
||||
import { ApplicationCommandNumericOptionMinMaxValueMixin } from '../mixins/ApplicationCommandNumericOptionMinMaxValueMixin';
|
||||
import { ApplicationCommandOptionBase } from '../mixins/ApplicationCommandOptionBase';
|
||||
import { ApplicationCommandOptionWithChoicesAndAutocompleteMixin } from '../mixins/ApplicationCommandOptionWithChoicesAndAutocompleteMixin';
|
||||
import { ApplicationCommandNumericOptionMinMaxValueMixin } from '../mixins/ApplicationCommandNumericOptionMinMaxValueMixin.js';
|
||||
import { ApplicationCommandOptionBase } from '../mixins/ApplicationCommandOptionBase.js';
|
||||
import { ApplicationCommandOptionWithChoicesAndAutocompleteMixin } from '../mixins/ApplicationCommandOptionWithChoicesAndAutocompleteMixin.js';
|
||||
|
||||
const numberValidator = s.number.int;
|
||||
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
import { APIApplicationCommandMentionableOption, ApplicationCommandOptionType } from 'discord-api-types/v10';
|
||||
import { ApplicationCommandOptionBase } from '../mixins/ApplicationCommandOptionBase';
|
||||
import { ApplicationCommandOptionType, type APIApplicationCommandMentionableOption } from 'discord-api-types/v10';
|
||||
import { ApplicationCommandOptionBase } from '../mixins/ApplicationCommandOptionBase.js';
|
||||
|
||||
export class SlashCommandMentionableOption extends ApplicationCommandOptionBase {
|
||||
public readonly type = ApplicationCommandOptionType.Mentionable as const;
|
||||
|
||||
@@ -1,9 +1,9 @@
|
||||
import { s } from '@sapphire/shapeshift';
|
||||
import { APIApplicationCommandNumberOption, ApplicationCommandOptionType } from 'discord-api-types/v10';
|
||||
import { ApplicationCommandOptionType, type APIApplicationCommandNumberOption } from 'discord-api-types/v10';
|
||||
import { mix } from 'ts-mixer';
|
||||
import { ApplicationCommandNumericOptionMinMaxValueMixin } from '../mixins/ApplicationCommandNumericOptionMinMaxValueMixin';
|
||||
import { ApplicationCommandOptionBase } from '../mixins/ApplicationCommandOptionBase';
|
||||
import { ApplicationCommandOptionWithChoicesAndAutocompleteMixin } from '../mixins/ApplicationCommandOptionWithChoicesAndAutocompleteMixin';
|
||||
import { ApplicationCommandNumericOptionMinMaxValueMixin } from '../mixins/ApplicationCommandNumericOptionMinMaxValueMixin.js';
|
||||
import { ApplicationCommandOptionBase } from '../mixins/ApplicationCommandOptionBase.js';
|
||||
import { ApplicationCommandOptionWithChoicesAndAutocompleteMixin } from '../mixins/ApplicationCommandOptionWithChoicesAndAutocompleteMixin.js';
|
||||
|
||||
const numberValidator = s.number;
|
||||
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
import { APIApplicationCommandRoleOption, ApplicationCommandOptionType } from 'discord-api-types/v10';
|
||||
import { ApplicationCommandOptionBase } from '../mixins/ApplicationCommandOptionBase';
|
||||
import { ApplicationCommandOptionType, type APIApplicationCommandRoleOption } from 'discord-api-types/v10';
|
||||
import { ApplicationCommandOptionBase } from '../mixins/ApplicationCommandOptionBase.js';
|
||||
|
||||
export class SlashCommandRoleOption extends ApplicationCommandOptionBase {
|
||||
public override readonly type = ApplicationCommandOptionType.Role as const;
|
||||
|
||||
@@ -1,16 +1,18 @@
|
||||
import { s } from '@sapphire/shapeshift';
|
||||
import { APIApplicationCommandStringOption, ApplicationCommandOptionType } from 'discord-api-types/v10';
|
||||
import { ApplicationCommandOptionType, type APIApplicationCommandStringOption } from 'discord-api-types/v10';
|
||||
import { mix } from 'ts-mixer';
|
||||
import { ApplicationCommandOptionBase } from '../mixins/ApplicationCommandOptionBase';
|
||||
import { ApplicationCommandOptionWithChoicesAndAutocompleteMixin } from '../mixins/ApplicationCommandOptionWithChoicesAndAutocompleteMixin';
|
||||
import { ApplicationCommandOptionBase } from '../mixins/ApplicationCommandOptionBase.js';
|
||||
import { ApplicationCommandOptionWithChoicesAndAutocompleteMixin } from '../mixins/ApplicationCommandOptionWithChoicesAndAutocompleteMixin.js';
|
||||
|
||||
const minLengthValidator = s.number.greaterThanOrEqual(0).lessThanOrEqual(6000);
|
||||
const maxLengthValidator = s.number.greaterThanOrEqual(1).lessThanOrEqual(6000);
|
||||
const minLengthValidator = s.number.greaterThanOrEqual(0).lessThanOrEqual(6_000);
|
||||
const maxLengthValidator = s.number.greaterThanOrEqual(1).lessThanOrEqual(6_000);
|
||||
|
||||
@mix(ApplicationCommandOptionWithChoicesAndAutocompleteMixin)
|
||||
export class SlashCommandStringOption extends ApplicationCommandOptionBase {
|
||||
public readonly type = ApplicationCommandOptionType.String as const;
|
||||
|
||||
public readonly max_length?: number;
|
||||
|
||||
public readonly min_length?: number;
|
||||
|
||||
/**
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
import { APIApplicationCommandUserOption, ApplicationCommandOptionType } from 'discord-api-types/v10';
|
||||
import { ApplicationCommandOptionBase } from '../mixins/ApplicationCommandOptionBase';
|
||||
import { ApplicationCommandOptionType, type APIApplicationCommandUserOption } from 'discord-api-types/v10';
|
||||
import { ApplicationCommandOptionBase } from '../mixins/ApplicationCommandOptionBase.js';
|
||||
|
||||
export class SlashCommandUserOption extends ApplicationCommandOptionBase {
|
||||
public readonly type = ApplicationCommandOptionType.User as const;
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
import { s } from '@sapphire/shapeshift';
|
||||
import type { APIEmbedField } from 'discord-api-types/v10';
|
||||
import { isValidationEnabled } from '../../util/validation';
|
||||
import { isValidationEnabled } from '../../util/validation.js';
|
||||
|
||||
export const fieldNamePredicate = s.string
|
||||
.lengthGreaterThanOrEqual(1)
|
||||
@@ -9,7 +9,7 @@ export const fieldNamePredicate = s.string
|
||||
|
||||
export const fieldValuePredicate = s.string
|
||||
.lengthGreaterThanOrEqual(1)
|
||||
.lengthLessThanOrEqual(1024)
|
||||
.lengthLessThanOrEqual(1_024)
|
||||
.setValidationEnabled(isValidationEnabled);
|
||||
|
||||
export const fieldInlinePredicate = s.boolean.optional;
|
||||
@@ -64,12 +64,12 @@ export const colorPredicate = s.number.int
|
||||
|
||||
export const descriptionPredicate = s.string
|
||||
.lengthGreaterThanOrEqual(1)
|
||||
.lengthLessThanOrEqual(4096)
|
||||
.lengthLessThanOrEqual(4_096)
|
||||
.nullable.setValidationEnabled(isValidationEnabled);
|
||||
|
||||
export const footerTextPredicate = s.string
|
||||
.lengthGreaterThanOrEqual(1)
|
||||
.lengthLessThanOrEqual(2048)
|
||||
.lengthLessThanOrEqual(2_048)
|
||||
.nullable.setValidationEnabled(isValidationEnabled);
|
||||
|
||||
export const embedFooterPredicate = s
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
import type { APIEmbed, APIEmbedAuthor, APIEmbedField, APIEmbedFooter, APIEmbedImage } from 'discord-api-types/v10';
|
||||
import { normalizeArray, type RestOrArray } from '../../util/normalizeArray.js';
|
||||
import {
|
||||
colorPredicate,
|
||||
descriptionPredicate,
|
||||
@@ -10,8 +11,7 @@ import {
|
||||
titlePredicate,
|
||||
urlPredicate,
|
||||
validateFieldLength,
|
||||
} from './Assertions';
|
||||
import { normalizeArray, type RestOrArray } from '../../util/normalizeArray';
|
||||
} from './Assertions.js';
|
||||
|
||||
export type RGBTuple = [red: number, green: number, blue: number];
|
||||
|
||||
@@ -26,11 +26,11 @@ export interface IconData {
|
||||
proxyIconURL?: string;
|
||||
}
|
||||
|
||||
export type EmbedAuthorData = Omit<APIEmbedAuthor, 'icon_url' | 'proxy_icon_url'> & IconData;
|
||||
export type EmbedAuthorData = IconData & Omit<APIEmbedAuthor, 'icon_url' | 'proxy_icon_url'>;
|
||||
|
||||
export type EmbedAuthorOptions = Omit<EmbedAuthorData, 'proxyIconURL'>;
|
||||
|
||||
export type EmbedFooterData = Omit<APIEmbedFooter, 'icon_url' | 'proxy_icon_url'> & IconData;
|
||||
export type EmbedFooterData = IconData & Omit<APIEmbedFooter, 'icon_url' | 'proxy_icon_url'>;
|
||||
|
||||
export type EmbedFooterOptions = Omit<EmbedFooterData, 'proxyIconURL'>;
|
||||
|
||||
@@ -57,7 +57,6 @@ export class EmbedBuilder {
|
||||
* @remarks
|
||||
* This method accepts either an array of fields or a variable number of field parameters.
|
||||
* The maximum amount of fields that can be added is 25.
|
||||
*
|
||||
* @example
|
||||
* Using an array
|
||||
* ```ts
|
||||
@@ -65,7 +64,6 @@ export class EmbedBuilder {
|
||||
* const embed = new EmbedBuilder()
|
||||
* .addFields(fields);
|
||||
* ```
|
||||
*
|
||||
* @example
|
||||
* Using rest parameters (variadic)
|
||||
* ```ts
|
||||
@@ -75,10 +73,10 @@ export class EmbedBuilder {
|
||||
* { name: 'Field 2', value: 'Value 2' },
|
||||
* );
|
||||
* ```
|
||||
*
|
||||
* @param fields - The fields to add
|
||||
*/
|
||||
public addFields(...fields: RestOrArray<APIEmbedField>): this {
|
||||
// eslint-disable-next-line no-param-reassign
|
||||
fields = normalizeArray(fields);
|
||||
// Ensure adding these fields won't exceed the 25 field limit
|
||||
validateFieldLength(fields.length, this.data.fields);
|
||||
@@ -100,26 +98,22 @@ export class EmbedBuilder {
|
||||
* The maximum amount of fields that can be added is 25.
|
||||
*
|
||||
* It's useful for modifying and adjusting order of the already-existing fields of an embed.
|
||||
*
|
||||
* @example
|
||||
* Remove the first field
|
||||
* ```ts
|
||||
* embed.spliceFields(0, 1);
|
||||
* ```
|
||||
*
|
||||
* @example
|
||||
* Remove the first n fields
|
||||
* ```ts
|
||||
* const n = 4
|
||||
* embed.spliceFields(0, n);
|
||||
* ```
|
||||
*
|
||||
* @example
|
||||
* Remove the last field
|
||||
* ```ts
|
||||
* embed.spliceFields(-1, 1);
|
||||
* ```
|
||||
*
|
||||
* @param index - The index to start at
|
||||
* @param deleteCount - The number of fields to remove
|
||||
* @param fields - The replacing field objects
|
||||
@@ -143,7 +137,6 @@ export class EmbedBuilder {
|
||||
* it splices the entire array of fields, replacing them with the provided fields.
|
||||
*
|
||||
* You can set a maximum of 25 fields.
|
||||
*
|
||||
* @param fields - The fields to set
|
||||
*/
|
||||
public setFields(...fields: RestOrArray<APIEmbedField>) {
|
||||
@@ -175,7 +168,7 @@ export class EmbedBuilder {
|
||||
*
|
||||
* @param color - The color of the embed
|
||||
*/
|
||||
public setColor(color: number | RGBTuple | null): this {
|
||||
public setColor(color: RGBTuple | number | null): this {
|
||||
// Data assertions
|
||||
colorPredicate.parse(color);
|
||||
|
||||
@@ -184,6 +177,7 @@ export class EmbedBuilder {
|
||||
this.data.color = (red << 16) + (green << 8) + blue;
|
||||
return this;
|
||||
}
|
||||
|
||||
this.data.color = color ?? undefined;
|
||||
return this;
|
||||
}
|
||||
@@ -250,7 +244,7 @@ export class EmbedBuilder {
|
||||
*
|
||||
* @param timestamp - The timestamp or date
|
||||
*/
|
||||
public setTimestamp(timestamp: number | Date | null = Date.now()): this {
|
||||
public setTimestamp(timestamp: Date | number | null = Date.now()): this {
|
||||
// Data assertions
|
||||
timestampPredicate.parse(timestamp);
|
||||
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
import type { URL } from 'url';
|
||||
import type { URL } from 'node:url';
|
||||
import type { Snowflake } from 'discord-api-types/globals';
|
||||
|
||||
/**
|
||||
@@ -95,8 +95,7 @@ export function hideLinkEmbed<C extends string>(url: C): `<${C}>`;
|
||||
* @param url - The URL to wrap
|
||||
*/
|
||||
export function hideLinkEmbed(url: URL): `<${string}>`;
|
||||
export function hideLinkEmbed(url: string | URL) {
|
||||
// eslint-disable-next-line @typescript-eslint/restrict-template-expressions
|
||||
export function hideLinkEmbed(url: URL | string) {
|
||||
return `<${url}>`;
|
||||
}
|
||||
|
||||
@@ -141,8 +140,7 @@ export function hyperlink<C extends string, U extends string, T extends string>(
|
||||
url: U,
|
||||
title: T,
|
||||
): `[${C}](${U} "${T}")`;
|
||||
export function hyperlink(content: string, url: string | URL, title?: string) {
|
||||
// eslint-disable-next-line @typescript-eslint/restrict-template-expressions
|
||||
export function hyperlink(content: string, url: URL | string, title?: string) {
|
||||
return title ? `[${content}](${url} "${title}")` : `[${content}](${url})`;
|
||||
}
|
||||
|
||||
@@ -182,6 +180,75 @@ export function roleMention<C extends Snowflake>(roleId: C): `<@&${C}>` {
|
||||
return `<@&${roleId}>`;
|
||||
}
|
||||
|
||||
/**
|
||||
* Formats an application command name, subcommand group name, subcommand name, and ID into an application command mention
|
||||
*
|
||||
* @param commandName - The application command name to format
|
||||
* @param subcommandGroupName - The subcommand group name to format
|
||||
* @param subcommandName - The subcommand name to format
|
||||
* @param commandId - The application command ID to format
|
||||
*/
|
||||
export function chatInputApplicationCommandMention<
|
||||
N extends string,
|
||||
G extends string,
|
||||
S extends string,
|
||||
I extends Snowflake,
|
||||
>(commandName: N, subcommandGroupName: G, subcommandName: S, commandId: I): `</${N} ${G} ${S}:${I}>`;
|
||||
|
||||
/**
|
||||
* Formats an application command name, subcommand name, and ID into an application command mention
|
||||
*
|
||||
* @param commandName - The application command name to format
|
||||
* @param subcommandName - The subcommand name to format
|
||||
* @param commandId - The application command ID to format
|
||||
*/
|
||||
export function chatInputApplicationCommandMention<N extends string, S extends string, I extends Snowflake>(
|
||||
commandName: N,
|
||||
subcommandName: S,
|
||||
commandId: I,
|
||||
): `</${N} ${S}:${I}>`;
|
||||
|
||||
/**
|
||||
* Formats an application command name and ID into an application command mention
|
||||
*
|
||||
* @param commandName - The application command name to format
|
||||
* @param commandId - The application command ID to format
|
||||
*/
|
||||
export function chatInputApplicationCommandMention<N extends string, I extends Snowflake>(
|
||||
commandName: N,
|
||||
commandId: I,
|
||||
): `</${N}:${I}>`;
|
||||
|
||||
/**
|
||||
* Formats an application command name, subcommand group name, subcommand name, and ID into an application command mention
|
||||
*
|
||||
* @param commandName - The application command name to format
|
||||
* @param subcommandGroupName - The subcommand group name to format
|
||||
* @param subcommandName - The subcommand name to format
|
||||
* @param commandId - The application command ID to format
|
||||
*/
|
||||
export function chatInputApplicationCommandMention<
|
||||
N extends string,
|
||||
G extends Snowflake | string,
|
||||
S extends Snowflake | string,
|
||||
I extends Snowflake,
|
||||
>(
|
||||
commandName: N,
|
||||
subcommandGroupName: G,
|
||||
subcommandName?: S,
|
||||
commandId?: I,
|
||||
): `</${N} ${G} ${S}:${I}>` | `</${N} ${G}:${S}>` | `</${N}:${G}>` {
|
||||
if (typeof commandId !== 'undefined') {
|
||||
return `</${commandName} ${subcommandGroupName} ${subcommandName!}:${commandId}>`;
|
||||
}
|
||||
|
||||
if (typeof subcommandName !== 'undefined') {
|
||||
return `</${commandName} ${subcommandGroupName}:${subcommandName}>`;
|
||||
}
|
||||
|
||||
return `</${commandName}:${subcommandGroupName}>`;
|
||||
}
|
||||
|
||||
/**
|
||||
* Formats an emoji ID into a fully qualified emoji identifier
|
||||
*
|
||||
@@ -203,7 +270,7 @@ export function formatEmoji<C extends Snowflake>(emojiId: C, animated?: true): `
|
||||
* @param emojiId - The emoji ID to format
|
||||
* @param animated - Whether the emoji is animated or not. Defaults to `false`
|
||||
*/
|
||||
export function formatEmoji<C extends Snowflake>(emojiId: C, animated = false): `<a:_:${C}>` | `<:_:${C}>` {
|
||||
export function formatEmoji<C extends Snowflake>(emojiId: C, animated = false): `<:_:${C}>` | `<a:_:${C}>` {
|
||||
return `<${animated ? 'a' : ''}:_:${emojiId}>`;
|
||||
}
|
||||
|
||||
@@ -293,9 +360,10 @@ export function time<C extends number>(seconds: C): `<t:${C}>`;
|
||||
* @param style - The style to use
|
||||
*/
|
||||
export function time<C extends number, S extends TimestampStylesString>(seconds: C, style: S): `<t:${C}:${S}>`;
|
||||
export function time(timeOrSeconds?: number | Date, style?: TimestampStylesString): string {
|
||||
export function time(timeOrSeconds?: Date | number, style?: TimestampStylesString): string {
|
||||
if (typeof timeOrSeconds !== 'number') {
|
||||
timeOrSeconds = Math.floor((timeOrSeconds?.getTime() ?? Date.now()) / 1000);
|
||||
// eslint-disable-next-line no-param-reassign
|
||||
timeOrSeconds = Math.floor((timeOrSeconds?.getTime() ?? Date.now()) / 1_000);
|
||||
}
|
||||
|
||||
return typeof style === 'string' ? `<t:${timeOrSeconds}:${style}>` : `<t:${timeOrSeconds}>`;
|
||||
|
||||
@@ -8,11 +8,12 @@ export interface Equatable<T> {
|
||||
/**
|
||||
* Whether or not this is equal to another structure
|
||||
*/
|
||||
equals: (other: T) => boolean;
|
||||
equals(other: T): boolean;
|
||||
}
|
||||
|
||||
/**
|
||||
* Indicates if an object is equatable or not.
|
||||
*
|
||||
* @param maybeEquatable - The object to check against
|
||||
*/
|
||||
export function isEquatable(maybeEquatable: unknown): maybeEquatable is Equatable<unknown> {
|
||||
|
||||
@@ -7,11 +7,12 @@ export interface JSONEncodable<T> {
|
||||
/**
|
||||
* Transforms this object to its JSON format
|
||||
*/
|
||||
toJSON: () => T;
|
||||
toJSON(): T;
|
||||
}
|
||||
|
||||
/**
|
||||
* Indicates if an object is encodable or not.
|
||||
*
|
||||
* @param maybeEncodable - The object to check against
|
||||
*/
|
||||
export function isJSONEncodable(maybeEncodable: unknown): maybeEncodable is JSONEncodable<unknown> {
|
||||
|
||||
3
packages/builders/tsup.config.js
Normal file
3
packages/builders/tsup.config.js
Normal file
@@ -0,0 +1,3 @@
|
||||
import { createTsupConfig } from '../../tsup.config.js';
|
||||
|
||||
export default createTsupConfig();
|
||||
@@ -1,7 +1,3 @@
|
||||
{
|
||||
"extends": "../../.eslintrc.json",
|
||||
"plugins": ["eslint-plugin-tsdoc"],
|
||||
"rules": {
|
||||
"tsdoc/syntax": "warn"
|
||||
}
|
||||
"extends": "../../.eslintrc.json"
|
||||
}
|
||||
|
||||
@@ -1,5 +1,7 @@
|
||||
/* eslint-disable unicorn/no-array-method-this-argument */
|
||||
/* eslint-disable id-length */
|
||||
import { describe, test, expect } from 'vitest';
|
||||
import { Collection } from '../src';
|
||||
import { Collection } from '../src/index.js';
|
||||
|
||||
type TestCollection = Collection<string, number>;
|
||||
|
||||
@@ -18,7 +20,6 @@ function createTestCollection(): TestCollection {
|
||||
function expectInvalidFunctionError(cb: () => unknown, val?: unknown): void {
|
||||
expect(() => {
|
||||
cb();
|
||||
// eslint-disable-next-line @typescript-eslint/restrict-template-expressions
|
||||
}).toThrowError(new TypeError(`${val} is not a function`));
|
||||
}
|
||||
|
||||
@@ -131,9 +132,9 @@ describe('each() tests', () => {
|
||||
const coll = createTestCollection();
|
||||
|
||||
test('throws if fn is not a function', () => {
|
||||
// @ts-expect-error
|
||||
// @ts-expect-error: Invalid function
|
||||
expectInvalidFunctionError(() => coll.each());
|
||||
// @ts-expect-error
|
||||
// @ts-expect-error: Invalid function
|
||||
expectInvalidFunctionError(() => coll.each(123), 123);
|
||||
});
|
||||
|
||||
@@ -152,7 +153,7 @@ describe('each() tests', () => {
|
||||
describe('ensure() tests', () => {
|
||||
test('throws if defaultValueGenerator is not a function', () => {
|
||||
const coll = createTestCollection();
|
||||
// @ts-expect-error
|
||||
// @ts-expect-error: Invalid function
|
||||
expectInvalidFunctionError(() => coll.ensure('d', 'abc'), 'abc');
|
||||
});
|
||||
|
||||
@@ -176,7 +177,7 @@ describe('equals() tests', () => {
|
||||
const coll2 = createTestCollection();
|
||||
|
||||
test('returns false if no collection is passed', () => {
|
||||
// @ts-expect-error
|
||||
// @ts-expect-error: Invalid function
|
||||
expect(coll1.equals()).toBeFalsy();
|
||||
});
|
||||
|
||||
@@ -198,9 +199,9 @@ describe('every() tests', () => {
|
||||
const coll = createTestCollection();
|
||||
|
||||
test('throws if fn is not a function', () => {
|
||||
// @ts-expect-error
|
||||
// @ts-expect-error: Invalid function
|
||||
expectInvalidFunctionError(() => coll.every());
|
||||
// @ts-expect-error
|
||||
// @ts-expect-error: Invalid function
|
||||
expectInvalidFunctionError(() => coll.every(123), 123);
|
||||
});
|
||||
|
||||
@@ -224,9 +225,9 @@ describe('filter() tests', () => {
|
||||
const coll = createTestCollection();
|
||||
|
||||
test('throws if fn is not a function', () => {
|
||||
// @ts-expect-error
|
||||
// @ts-expect-error: Invalid function
|
||||
expectInvalidFunctionError(() => coll.filter());
|
||||
// @ts-expect-error
|
||||
// @ts-expect-error: Invalid function
|
||||
expectInvalidFunctionError(() => coll.filter(123), 123);
|
||||
});
|
||||
|
||||
@@ -251,9 +252,9 @@ describe('find() tests', () => {
|
||||
const coll = createTestCollection();
|
||||
|
||||
test('throws if fn is not a function', () => {
|
||||
// @ts-expect-error
|
||||
// @ts-expect-error: Invalid function
|
||||
expectInvalidFunctionError(() => createCollection().find());
|
||||
// @ts-expect-error
|
||||
// @ts-expect-error: Invalid function
|
||||
expectInvalidFunctionError(() => createCollection().find(123), 123);
|
||||
});
|
||||
|
||||
@@ -275,9 +276,9 @@ describe('findKey() tests', () => {
|
||||
const coll = createTestCollection();
|
||||
|
||||
test('throws if fn is not a function', () => {
|
||||
// @ts-expect-error
|
||||
// @ts-expect-error: Invalid function
|
||||
expectInvalidFunctionError(() => coll.findKey());
|
||||
// @ts-expect-error
|
||||
// @ts-expect-error: Invalid function
|
||||
expectInvalidFunctionError(() => coll.findKey(123), 123);
|
||||
});
|
||||
|
||||
@@ -506,9 +507,9 @@ describe('map() tests', () => {
|
||||
const coll = createTestCollection();
|
||||
|
||||
test('throws if fn is not a function', () => {
|
||||
// @ts-expect-error
|
||||
// @ts-expect-error: Invalid function
|
||||
expectInvalidFunctionError(() => coll.map());
|
||||
// @ts-expect-error
|
||||
// @ts-expect-error: Invalid function
|
||||
expectInvalidFunctionError(() => coll.map(123), 123);
|
||||
});
|
||||
|
||||
@@ -529,9 +530,9 @@ describe('mapValues() tests', () => {
|
||||
const coll = createTestCollection();
|
||||
|
||||
test('throws if fn is not a function', () => {
|
||||
// @ts-expect-error
|
||||
// @ts-expect-error: Invalid function
|
||||
expectInvalidFunctionError(() => coll.mapValues());
|
||||
// @ts-expect-error
|
||||
// @ts-expect-error: Invalid function
|
||||
expectInvalidFunctionError(() => coll.mapValues(123), 123);
|
||||
});
|
||||
|
||||
@@ -606,9 +607,9 @@ describe('partition() tests', () => {
|
||||
const coll = createTestCollection();
|
||||
|
||||
test('throws if fn is not a function', () => {
|
||||
// @ts-expect-error
|
||||
// @ts-expect-error: Invalid function
|
||||
expectInvalidFunctionError(() => coll.partition());
|
||||
// @ts-expect-error
|
||||
// @ts-expect-error: Invalid function
|
||||
expectInvalidFunctionError(() => coll.partition(123), 123);
|
||||
});
|
||||
|
||||
@@ -690,9 +691,9 @@ describe('reduce() tests', () => {
|
||||
const coll = createTestCollection();
|
||||
|
||||
test('throws if fn is not a function', () => {
|
||||
// @ts-expect-error
|
||||
// @ts-expect-error: Invalid function
|
||||
expectInvalidFunctionError(() => coll.reduce());
|
||||
// @ts-expect-error
|
||||
// @ts-expect-error: Invalid function
|
||||
expectInvalidFunctionError(() => coll.reduce(123), 123);
|
||||
});
|
||||
|
||||
@@ -729,19 +730,15 @@ describe('some() tests', () => {
|
||||
const coll = createTestCollection();
|
||||
|
||||
test('throws if fn is not a function', () => {
|
||||
// @ts-expect-error
|
||||
// @ts-expect-error: Invalid function
|
||||
expectInvalidFunctionError(() => coll.some());
|
||||
// @ts-expect-error
|
||||
// @ts-expect-error: Invalid function
|
||||
expectInvalidFunctionError(() => coll.some(123), 123);
|
||||
});
|
||||
|
||||
test('returns false if no items pass the predicate', () => {
|
||||
expect(coll.some((v) => v > 3)).toBeFalsy();
|
||||
});
|
||||
|
||||
test('returns true if at least one item passes the predicate', () => {
|
||||
expect(coll.some((x) => x === 2)).toBeTruthy();
|
||||
});
|
||||
});
|
||||
|
||||
describe('sort() tests', () => {
|
||||
@@ -777,9 +774,9 @@ describe('sweep() test', () => {
|
||||
const coll = createTestCollection();
|
||||
|
||||
test('throws if fn is not a function', () => {
|
||||
// @ts-expect-error
|
||||
// @ts-expect-error: Invalid function
|
||||
expectInvalidFunctionError(() => coll.sweep());
|
||||
// @ts-expect-error
|
||||
// @ts-expect-error: Invalid function
|
||||
expectInvalidFunctionError(() => coll.sweep(123), 123);
|
||||
});
|
||||
|
||||
@@ -804,9 +801,9 @@ describe('tap() tests', () => {
|
||||
const coll = createTestCollection();
|
||||
|
||||
test('throws if fn is not a function', () => {
|
||||
// @ts-expect-error
|
||||
// @ts-expect-error: Invalid function
|
||||
expectInvalidFunctionError(() => coll.tap());
|
||||
// @ts-expect-error
|
||||
// @ts-expect-error: Invalid function
|
||||
expectInvalidFunctionError(() => coll.tap(123), 123);
|
||||
});
|
||||
|
||||
|
||||
@@ -1,3 +0,0 @@
|
||||
import { createUnbuildConfig } from '../../build.config';
|
||||
|
||||
export default createUnbuildConfig();
|
||||
@@ -4,21 +4,21 @@
|
||||
"description": "Utility data structure used in discord.js",
|
||||
"scripts": {
|
||||
"test": "vitest run",
|
||||
"build": "unbuild",
|
||||
"lint": "prettier --check . && TIMING=1 eslint src __tests__ --ext mjs,js,ts",
|
||||
"format": "prettier --write . && TIMING=1 eslint src __tests__ --ext mjs,js,ts --fix",
|
||||
"build": "tsup",
|
||||
"lint": "prettier --check . && cross-env TIMING=1 eslint src __tests__ --ext mjs,js,ts",
|
||||
"format": "prettier --write . && cross-env TIMING=1 eslint src __tests__ --ext mjs,js,ts --fix",
|
||||
"fmt": "yarn format",
|
||||
"docs": "downlevel-dts . docs --to=3.7 && docgen -i src/index.ts -c docs/index.json -o docs/docs.json --typescript && api-extractor run --local",
|
||||
"docs": "downlevel-dts dist docs/dist --to=3.7 && docgen -i src/index.ts -c docs/index.json -o docs/docs.json --typescript && api-extractor run --local",
|
||||
"prepack": "yarn lint && yarn test && yarn build",
|
||||
"changelog": "git cliff --prepend ./CHANGELOG.md -u -c ./cliff.toml -r ../../ --include-path 'packages/collection/*'",
|
||||
"release": "cliff-jumper"
|
||||
},
|
||||
"main": "./dist/index.cjs",
|
||||
"main": "./dist/index.js",
|
||||
"module": "./dist/index.mjs",
|
||||
"types": "./dist/index.d.ts",
|
||||
"exports": {
|
||||
"import": "./dist/index.mjs",
|
||||
"require": "./dist/index.cjs",
|
||||
"require": "./dist/index.js",
|
||||
"types": "./dist/index.d.ts"
|
||||
},
|
||||
"directories": {
|
||||
@@ -33,7 +33,7 @@
|
||||
"Amish Shah <amishshah.2k@gmail.com>",
|
||||
"SpaceEEC <spaceeec@yahoo.com>",
|
||||
"Vlad Frangu <kingdgrizzle@gmail.com>",
|
||||
"Antonio Roman <kyradiscord@gmail.com>"
|
||||
"Aura Román <kyradiscord@gmail.com>"
|
||||
],
|
||||
"license": "Apache-2.0",
|
||||
"keywords": [
|
||||
@@ -52,23 +52,17 @@
|
||||
"devDependencies": {
|
||||
"@discordjs/docgen": "workspace:^",
|
||||
"@favware/cliff-jumper": "^1.8.7",
|
||||
"@microsoft/api-extractor": "^7.29.3",
|
||||
"@types/node": "^16.11.52",
|
||||
"@typescript-eslint/eslint-plugin": "^5.33.1",
|
||||
"@typescript-eslint/parser": "^5.33.1",
|
||||
"@vitest/coverage-c8": "^0.22.1",
|
||||
"downlevel-dts": "^0.10.0",
|
||||
"eslint": "^8.22.0",
|
||||
"eslint-config-marine": "^9.4.1",
|
||||
"eslint-config-prettier": "^8.5.0",
|
||||
"eslint-import-resolver-typescript": "^3.4.2",
|
||||
"eslint-plugin-import": "^2.26.0",
|
||||
"eslint-plugin-tsdoc": "^0.2.16",
|
||||
"@microsoft/api-extractor": "^7.31.2",
|
||||
"@types/node": "^16.11.60",
|
||||
"@vitest/coverage-c8": "^0.23.4",
|
||||
"cross-env": "^7.0.3",
|
||||
"downlevel-dts": "^0.10.1",
|
||||
"eslint": "^8.24.0",
|
||||
"eslint-config-neon": "^0.1.33",
|
||||
"prettier": "^2.7.1",
|
||||
"rollup-plugin-typescript2": "^0.33.0",
|
||||
"typescript": "^4.7.4",
|
||||
"unbuild": "^0.8.9",
|
||||
"vitest": "^0.22.1"
|
||||
"tsup": "^6.2.3",
|
||||
"typescript": "^4.8.3",
|
||||
"vitest": "^0.23.4"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=16.9.0"
|
||||
|
||||
@@ -1,10 +1,11 @@
|
||||
/* eslint-disable @typescript-eslint/restrict-template-expressions */
|
||||
/* eslint-disable id-length */
|
||||
/* eslint-disable no-param-reassign */
|
||||
/**
|
||||
* @internal
|
||||
*/
|
||||
export interface CollectionConstructor {
|
||||
new (): Collection<unknown, unknown>;
|
||||
new <K, V>(entries?: ReadonlyArray<readonly [K, V]> | null): Collection<K, V>;
|
||||
new <K, V>(entries?: readonly (readonly [K, V])[] | null): Collection<K, V>;
|
||||
new <K, V>(iterable: Iterable<readonly [K, V]>): Collection<K, V>;
|
||||
readonly prototype: Collection<unknown, unknown>;
|
||||
readonly [Symbol.species]: CollectionConstructor;
|
||||
@@ -13,8 +14,11 @@ export interface CollectionConstructor {
|
||||
/**
|
||||
* Represents an immutable version of a collection
|
||||
*/
|
||||
export type ReadonlyCollection<K, V> = ReadonlyMap<K, V> &
|
||||
Omit<Collection<K, V>, 'forEach' | 'ensure' | 'reverse' | 'sweep' | 'sort' | 'get' | 'set' | 'delete'>;
|
||||
export type ReadonlyCollection<K, V> = Omit<
|
||||
Collection<K, V>,
|
||||
'delete' | 'ensure' | 'forEach' | 'get' | 'reverse' | 'set' | 'sort' | 'sweep'
|
||||
> &
|
||||
ReadonlyMap<K, V>;
|
||||
|
||||
/**
|
||||
* Separate interface for the constructor so that emitted js does not have a constructor that overwrites itself
|
||||
@@ -38,7 +42,6 @@ export class Collection<K, V> extends Map<K, V> {
|
||||
*
|
||||
* @param key - The key to get if it exists, or set otherwise
|
||||
* @param defaultValueGenerator - A function that generates the default value
|
||||
*
|
||||
* @example
|
||||
* ```ts
|
||||
* collection.ensure(guildId, () => defaultGuildConfig);
|
||||
@@ -56,7 +59,6 @@ export class Collection<K, V> extends Map<K, V> {
|
||||
* Checks if all of the elements exist in the collection.
|
||||
*
|
||||
* @param keys - The keys of the elements to check for
|
||||
*
|
||||
* @returns `true` if all of the elements exist, `false` if at least one does not exist.
|
||||
*/
|
||||
public hasAll(...keys: K[]) {
|
||||
@@ -67,7 +69,6 @@ export class Collection<K, V> extends Map<K, V> {
|
||||
* Checks if any of the elements exist in the collection.
|
||||
*
|
||||
* @param keys - The keys of the elements to check for
|
||||
*
|
||||
* @returns `true` if any of the elements exist, `false` if none exist.
|
||||
*/
|
||||
public hasAny(...keys: K[]) {
|
||||
@@ -78,18 +79,15 @@ export class Collection<K, V> extends Map<K, V> {
|
||||
* Obtains the first value(s) in this collection.
|
||||
*
|
||||
* @param amount - Amount of values to obtain from the beginning
|
||||
*
|
||||
* @returns A single value if no amount is provided or an array of values, starting from the end if amount is negative
|
||||
*/
|
||||
public first(): V | undefined;
|
||||
public first(amount: number): V[];
|
||||
public first(amount?: number): V | V[] | undefined {
|
||||
// eslint-disable-next-line @typescript-eslint/no-unsafe-return
|
||||
if (typeof amount === 'undefined') return this.values().next().value;
|
||||
if (amount < 0) return this.last(amount * -1);
|
||||
amount = Math.min(this.size, amount);
|
||||
const iter = this.values();
|
||||
// eslint-disable-next-line @typescript-eslint/no-unsafe-return
|
||||
return Array.from({ length: amount }, (): V => iter.next().value);
|
||||
}
|
||||
|
||||
@@ -97,19 +95,16 @@ export class Collection<K, V> extends Map<K, V> {
|
||||
* Obtains the first key(s) in this collection.
|
||||
*
|
||||
* @param amount - Amount of keys to obtain from the beginning
|
||||
*
|
||||
* @returns A single key if no amount is provided or an array of keys, starting from the end if
|
||||
* amount is negative
|
||||
*/
|
||||
public firstKey(): K | undefined;
|
||||
public firstKey(amount: number): K[];
|
||||
public firstKey(amount?: number): K | K[] | undefined {
|
||||
// eslint-disable-next-line @typescript-eslint/no-unsafe-return
|
||||
if (typeof amount === 'undefined') return this.keys().next().value;
|
||||
if (amount < 0) return this.lastKey(amount * -1);
|
||||
amount = Math.min(this.size, amount);
|
||||
const iter = this.keys();
|
||||
// eslint-disable-next-line @typescript-eslint/no-unsafe-return
|
||||
return Array.from({ length: amount }, (): K => iter.next().value);
|
||||
}
|
||||
|
||||
@@ -117,7 +112,6 @@ export class Collection<K, V> extends Map<K, V> {
|
||||
* Obtains the last value(s) in this collection.
|
||||
*
|
||||
* @param amount - Amount of values to obtain from the end
|
||||
*
|
||||
* @returns A single value if no amount is provided or an array of values, starting from the start if
|
||||
* amount is negative
|
||||
*/
|
||||
@@ -135,7 +129,6 @@ export class Collection<K, V> extends Map<K, V> {
|
||||
* Obtains the last key(s) in this collection.
|
||||
*
|
||||
* @param amount - Amount of keys to obtain from the end
|
||||
*
|
||||
* @returns A single key if no amount is provided or an array of keys, starting from the start if
|
||||
* amount is negative
|
||||
*/
|
||||
@@ -179,7 +172,6 @@ export class Collection<K, V> extends Map<K, V> {
|
||||
* Obtains unique random value(s) from this collection.
|
||||
*
|
||||
* @param amount - Amount of values to obtain randomly
|
||||
*
|
||||
* @returns A single value if no amount is provided or an array of values
|
||||
*/
|
||||
public random(): V | undefined;
|
||||
@@ -198,7 +190,6 @@ export class Collection<K, V> extends Map<K, V> {
|
||||
* Obtains unique random key(s) from this collection.
|
||||
*
|
||||
* @param amount - Amount of keys to obtain randomly
|
||||
*
|
||||
* @returns A single key if no amount is provided or an array
|
||||
*/
|
||||
public randomKey(): K | undefined;
|
||||
@@ -227,31 +218,31 @@ export class Collection<K, V> extends Map<K, V> {
|
||||
/**
|
||||
* Searches for a single item where the given function returns a truthy value. This behaves like
|
||||
* {@link https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/find | Array.find()}.
|
||||
* <warn>All collections used in Discord.js are mapped using their `id` property, and if you want to find by id you
|
||||
* All collections used in Discord.js are mapped using their `id` property, and if you want to find by id you
|
||||
* should use the `get` method. See
|
||||
* {@link https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Map/get | MDN} for details.</warn>
|
||||
* {@link https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Map/get | MDN} for details.
|
||||
*
|
||||
* @param fn - The function to test with (should return boolean)
|
||||
* @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;
|
||||
public find(fn: (value: V, key: K, collection: this) => unknown): V | undefined;
|
||||
public find<This, V2 extends V>(
|
||||
fn: (this: This, value: V, key: K, collection: this) => value is V2,
|
||||
thisArg: This,
|
||||
): V2 | undefined;
|
||||
public find<This>(fn: (this: This, value: V, key: K, collection: this) => boolean, thisArg: This): V | undefined;
|
||||
public find(fn: (value: V, key: K, collection: this) => boolean, thisArg?: unknown): V | undefined {
|
||||
public find<This>(fn: (this: This, value: V, key: K, collection: this) => unknown, thisArg: This): V | undefined;
|
||||
public find(fn: (value: V, key: K, collection: this) => unknown, thisArg?: unknown): V | undefined {
|
||||
if (typeof fn !== 'function') throw new TypeError(`${fn} is not a function`);
|
||||
if (typeof thisArg !== 'undefined') fn = fn.bind(thisArg);
|
||||
for (const [key, val] of this) {
|
||||
if (fn(val, key, this)) return val;
|
||||
}
|
||||
|
||||
return undefined;
|
||||
}
|
||||
|
||||
@@ -262,25 +253,25 @@ export class Collection<K, V> extends Map<K, V> {
|
||||
*
|
||||
* @param fn - The function to test with (should return boolean)
|
||||
* @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;
|
||||
public findKey(fn: (value: V, key: K, collection: this) => unknown): K | undefined;
|
||||
public findKey<This, K2 extends K>(
|
||||
fn: (this: This, value: V, key: K, collection: this) => key is K2,
|
||||
thisArg: This,
|
||||
): K2 | undefined;
|
||||
public findKey<This>(fn: (this: This, value: V, key: K, collection: this) => boolean, thisArg: This): K | undefined;
|
||||
public findKey(fn: (value: V, key: K, collection: this) => boolean, thisArg?: unknown): K | undefined {
|
||||
public findKey<This>(fn: (this: This, value: V, key: K, collection: this) => unknown, thisArg: This): K | undefined;
|
||||
public findKey(fn: (value: V, key: K, collection: this) => unknown, thisArg?: unknown): K | undefined {
|
||||
if (typeof fn !== 'function') throw new TypeError(`${fn} is not a function`);
|
||||
if (typeof thisArg !== 'undefined') fn = fn.bind(thisArg);
|
||||
for (const [key, val] of this) {
|
||||
if (fn(val, key, this)) return key;
|
||||
}
|
||||
|
||||
return undefined;
|
||||
}
|
||||
|
||||
@@ -289,18 +280,18 @@ export class Collection<K, V> extends Map<K, V> {
|
||||
*
|
||||
* @param fn - Function used to test (should return a boolean)
|
||||
* @param thisArg - Value to use as `this` when executing function
|
||||
*
|
||||
* @returns The number of removed entries
|
||||
*/
|
||||
public sweep(fn: (value: V, key: K, collection: this) => boolean): number;
|
||||
public sweep<T>(fn: (this: T, value: V, key: K, collection: this) => boolean, thisArg: T): number;
|
||||
public sweep(fn: (value: V, key: K, collection: this) => boolean, thisArg?: unknown): number {
|
||||
public sweep(fn: (value: V, key: K, collection: this) => unknown): number;
|
||||
public sweep<T>(fn: (this: T, value: V, key: K, collection: this) => unknown, thisArg: T): number;
|
||||
public sweep(fn: (value: V, key: K, collection: this) => unknown, thisArg?: unknown): number {
|
||||
if (typeof fn !== 'function') throw new TypeError(`${fn} is not a function`);
|
||||
if (typeof thisArg !== 'undefined') fn = fn.bind(thisArg);
|
||||
const previousSize = this.size;
|
||||
for (const [key, val] of this) {
|
||||
if (fn(val, key, this)) this.delete(key);
|
||||
}
|
||||
|
||||
return previousSize - this.size;
|
||||
}
|
||||
|
||||
@@ -311,7 +302,6 @@ export class Collection<K, V> extends Map<K, V> {
|
||||
*
|
||||
* @param fn - The function to test with (should return boolean)
|
||||
* @param thisArg - Value to use as `this` when executing function
|
||||
*
|
||||
* @example
|
||||
* ```ts
|
||||
* collection.filter(user => user.username === 'Bob');
|
||||
@@ -319,7 +309,7 @@ export class Collection<K, V> extends Map<K, V> {
|
||||
*/
|
||||
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>;
|
||||
public filter(fn: (value: V, key: K, collection: this) => boolean): Collection<K, V>;
|
||||
public filter(fn: (value: V, key: K, collection: this) => unknown): Collection<K, V>;
|
||||
public filter<This, K2 extends K>(
|
||||
fn: (this: This, value: V, key: K, collection: this) => key is K2,
|
||||
thisArg: This,
|
||||
@@ -328,14 +318,15 @@ export class Collection<K, V> extends Map<K, V> {
|
||||
fn: (this: This, value: V, key: K, collection: this) => value is V2,
|
||||
thisArg: This,
|
||||
): Collection<K, V2>;
|
||||
public filter<This>(fn: (this: This, value: V, key: K, collection: this) => boolean, thisArg: This): Collection<K, V>;
|
||||
public filter(fn: (value: V, key: K, collection: this) => boolean, thisArg?: unknown): Collection<K, V> {
|
||||
public filter<This>(fn: (this: This, value: V, key: K, collection: this) => unknown, thisArg: This): Collection<K, V>;
|
||||
public filter(fn: (value: V, key: K, collection: this) => unknown, thisArg?: unknown): Collection<K, V> {
|
||||
if (typeof fn !== 'function') throw new TypeError(`${fn} is not a function`);
|
||||
if (typeof thisArg !== 'undefined') fn = fn.bind(thisArg);
|
||||
const results = new this.constructor[Symbol.species]<K, V>();
|
||||
for (const [key, val] of this) {
|
||||
if (fn(val, key, this)) results.set(key, val);
|
||||
}
|
||||
|
||||
return results;
|
||||
}
|
||||
|
||||
@@ -345,7 +336,6 @@ export class Collection<K, V> extends Map<K, V> {
|
||||
*
|
||||
* @param fn - Function used to test (should return a boolean)
|
||||
* @param thisArg - Value to use as `this` when executing function
|
||||
*
|
||||
* @example
|
||||
* ```ts
|
||||
* const [big, small] = collection.partition(guild => guild.memberCount > 250);
|
||||
@@ -357,7 +347,7 @@ export class Collection<K, V> extends Map<K, V> {
|
||||
public partition<V2 extends V>(
|
||||
fn: (value: V, key: K, collection: this) => value is V2,
|
||||
): [Collection<K, V2>, Collection<K, Exclude<V, V2>>];
|
||||
public partition(fn: (value: V, key: K, collection: this) => boolean): [Collection<K, V>, Collection<K, V>];
|
||||
public partition(fn: (value: V, key: K, collection: this) => unknown): [Collection<K, V>, Collection<K, V>];
|
||||
public partition<This, K2 extends K>(
|
||||
fn: (this: This, value: V, key: K, collection: this) => key is K2,
|
||||
thisArg: This,
|
||||
@@ -367,11 +357,11 @@ export class Collection<K, V> extends Map<K, V> {
|
||||
thisArg: This,
|
||||
): [Collection<K, V2>, Collection<K, Exclude<V, V2>>];
|
||||
public partition<This>(
|
||||
fn: (this: This, value: V, key: K, collection: this) => boolean,
|
||||
fn: (this: This, value: V, key: K, collection: this) => unknown,
|
||||
thisArg: This,
|
||||
): [Collection<K, V>, Collection<K, V>];
|
||||
public partition(
|
||||
fn: (value: V, key: K, collection: this) => boolean,
|
||||
fn: (value: V, key: K, collection: this) => unknown,
|
||||
thisArg?: unknown,
|
||||
): [Collection<K, V>, Collection<K, V>] {
|
||||
if (typeof fn !== 'function') throw new TypeError(`${fn} is not a function`);
|
||||
@@ -387,6 +377,7 @@ export class Collection<K, V> extends Map<K, V> {
|
||||
results[1].set(key, val);
|
||||
}
|
||||
}
|
||||
|
||||
return results;
|
||||
}
|
||||
|
||||
@@ -396,7 +387,6 @@ export class Collection<K, V> extends Map<K, V> {
|
||||
*
|
||||
* @param fn - Function that produces a new Collection
|
||||
* @param thisArg - Value to use as `this` when executing function
|
||||
*
|
||||
* @example
|
||||
* ```ts
|
||||
* collection.flatMap(guild => guild.members.cache);
|
||||
@@ -408,6 +398,7 @@ export class Collection<K, V> extends Map<K, V> {
|
||||
thisArg: This,
|
||||
): Collection<K, T>;
|
||||
public flatMap<T>(fn: (value: V, key: K, collection: this) => Collection<K, T>, thisArg?: unknown): Collection<K, T> {
|
||||
// eslint-disable-next-line unicorn/no-array-method-this-argument
|
||||
const collections = this.map(fn, thisArg);
|
||||
return new this.constructor[Symbol.species]<K, T>().concat(...collections);
|
||||
}
|
||||
@@ -418,7 +409,6 @@ export class Collection<K, V> extends Map<K, V> {
|
||||
*
|
||||
* @param fn - Function that produces an element of the new array, taking three arguments
|
||||
* @param thisArg - Value to use as `this` when executing function
|
||||
*
|
||||
* @example
|
||||
* ```ts
|
||||
* collection.map(user => user.tag);
|
||||
@@ -431,9 +421,7 @@ export class Collection<K, V> extends Map<K, V> {
|
||||
if (typeof thisArg !== 'undefined') fn = fn.bind(thisArg);
|
||||
const iter = this.entries();
|
||||
return Array.from({ length: this.size }, (): T => {
|
||||
// eslint-disable-next-line @typescript-eslint/no-unsafe-assignment
|
||||
const [key, value] = iter.next().value;
|
||||
// eslint-disable-next-line @typescript-eslint/no-unsafe-argument
|
||||
return fn(value, key, this);
|
||||
});
|
||||
}
|
||||
@@ -444,7 +432,6 @@ export class Collection<K, V> extends Map<K, V> {
|
||||
*
|
||||
* @param fn - Function that produces an element of the new collection, taking three arguments
|
||||
* @param thisArg - Value to use as `this` when executing function
|
||||
*
|
||||
* @example
|
||||
* ```ts
|
||||
* collection.mapValues(user => user.tag);
|
||||
@@ -466,20 +453,20 @@ export class Collection<K, V> extends Map<K, V> {
|
||||
*
|
||||
* @param fn - Function used to test (should return a boolean)
|
||||
* @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;
|
||||
public some(fn: (value: V, key: K, collection: this) => boolean, thisArg?: unknown): boolean {
|
||||
public some(fn: (value: V, key: K, collection: this) => unknown): boolean;
|
||||
public some<T>(fn: (this: T, value: V, key: K, collection: this) => unknown, thisArg: T): boolean;
|
||||
public some(fn: (value: V, key: K, collection: this) => unknown, thisArg?: unknown): boolean {
|
||||
if (typeof fn !== 'function') throw new TypeError(`${fn} is not a function`);
|
||||
if (typeof thisArg !== 'undefined') fn = fn.bind(thisArg);
|
||||
for (const [key, val] of this) {
|
||||
if (fn(val, key, this)) return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
@@ -489,7 +476,6 @@ export class Collection<K, V> extends Map<K, V> {
|
||||
*
|
||||
* @param fn - Function used to test (should return a boolean)
|
||||
* @param thisArg - Value to use as `this` when executing function
|
||||
*
|
||||
* @example
|
||||
* ```ts
|
||||
* collection.every(user => !user.bot);
|
||||
@@ -497,7 +483,7 @@ export class Collection<K, V> extends Map<K, V> {
|
||||
*/
|
||||
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>;
|
||||
public every(fn: (value: V, key: K, collection: this) => boolean): boolean;
|
||||
public every(fn: (value: V, key: K, collection: this) => unknown): boolean;
|
||||
public every<This, K2 extends K>(
|
||||
fn: (this: This, value: V, key: K, collection: this) => key is K2,
|
||||
thisArg: This,
|
||||
@@ -506,13 +492,14 @@ export class Collection<K, V> extends Map<K, V> {
|
||||
fn: (this: This, value: V, key: K, collection: this) => value is V2,
|
||||
thisArg: This,
|
||||
): this is Collection<K, V2>;
|
||||
public every<This>(fn: (this: This, value: V, key: K, collection: this) => boolean, thisArg: This): boolean;
|
||||
public every(fn: (value: V, key: K, collection: this) => boolean, thisArg?: unknown): boolean {
|
||||
public every<This>(fn: (this: This, value: V, key: K, collection: this) => unknown, thisArg: This): boolean;
|
||||
public every(fn: (value: V, key: K, collection: this) => unknown, thisArg?: unknown): boolean {
|
||||
if (typeof fn !== 'function') throw new TypeError(`${fn} is not a function`);
|
||||
if (typeof thisArg !== 'undefined') fn = fn.bind(thisArg);
|
||||
for (const [key, val] of this) {
|
||||
if (!fn(val, key, this)) return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
@@ -523,7 +510,6 @@ export class Collection<K, V> extends Map<K, V> {
|
||||
* @param fn - Function used to reduce, taking four arguments; `accumulator`, `currentValue`, `currentKey`,
|
||||
* and `collection`
|
||||
* @param initialValue - Starting value for the accumulator
|
||||
*
|
||||
* @example
|
||||
* ```ts
|
||||
* collection.reduce((acc, guild) => acc + guild.memberCount, 0);
|
||||
@@ -538,6 +524,7 @@ export class Collection<K, V> extends Map<K, V> {
|
||||
for (const [key, val] of this) accumulator = fn(accumulator, val, key, this);
|
||||
return accumulator;
|
||||
}
|
||||
|
||||
let first = true;
|
||||
for (const [key, val] of this) {
|
||||
if (first) {
|
||||
@@ -545,6 +532,7 @@ export class Collection<K, V> extends Map<K, V> {
|
||||
first = false;
|
||||
continue;
|
||||
}
|
||||
|
||||
accumulator = fn(accumulator, val, key, this);
|
||||
}
|
||||
|
||||
@@ -563,7 +551,6 @@ export class Collection<K, V> extends Map<K, V> {
|
||||
*
|
||||
* @param fn - Function to execute for each element
|
||||
* @param thisArg - Value to use as `this` when executing function
|
||||
*
|
||||
* @example
|
||||
* ```ts
|
||||
* collection
|
||||
@@ -576,6 +563,7 @@ export class Collection<K, V> extends Map<K, V> {
|
||||
public each<T>(fn: (this: T, value: V, key: K, collection: this) => void, thisArg: T): this;
|
||||
public each(fn: (value: V, key: K, collection: this) => void, thisArg?: unknown): this {
|
||||
if (typeof fn !== 'function') throw new TypeError(`${fn} is not a function`);
|
||||
// eslint-disable-next-line unicorn/no-array-method-this-argument
|
||||
this.forEach(fn as (value: V, key: K, map: Map<K, V>) => void, thisArg);
|
||||
return this;
|
||||
}
|
||||
@@ -585,7 +573,6 @@ export class Collection<K, V> extends Map<K, V> {
|
||||
*
|
||||
* @param fn - Function to execute
|
||||
* @param thisArg - Value to use as `this` when executing function
|
||||
*
|
||||
* @example
|
||||
* ```ts
|
||||
* collection
|
||||
@@ -619,7 +606,6 @@ export class Collection<K, V> extends Map<K, V> {
|
||||
* Combines this collection with others into a new collection. None of the source collections are modified.
|
||||
*
|
||||
* @param collections - Collections to merge
|
||||
*
|
||||
* @example
|
||||
* ```ts
|
||||
* const newColl = someColl.concat(someOtherColl, anotherColl, ohBoyAColl);
|
||||
@@ -630,6 +616,7 @@ export class Collection<K, V> extends Map<K, V> {
|
||||
for (const coll of collections) {
|
||||
for (const [key, val] of coll) newColl.set(key, val);
|
||||
}
|
||||
|
||||
return newColl;
|
||||
}
|
||||
|
||||
@@ -639,11 +626,9 @@ export class Collection<K, V> extends Map<K, V> {
|
||||
* the collections may be different objects, but contain the same data.
|
||||
*
|
||||
* @param collection - Collection to compare with
|
||||
*
|
||||
* @returns Whether the collections have identical contents
|
||||
*/
|
||||
public equals(collection: ReadonlyCollection<K, V>) {
|
||||
// eslint-disable-next-line @typescript-eslint/no-unnecessary-condition
|
||||
if (!collection) return false; // runtime check
|
||||
if (this === collection) return true;
|
||||
if (this.size !== collection.size) return false;
|
||||
@@ -652,6 +637,7 @@ export class Collection<K, V> extends Map<K, V> {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
@@ -662,7 +648,6 @@ export class Collection<K, V> extends Map<K, V> {
|
||||
*
|
||||
* @param compareFunction - Specifies a function that defines the sort order.
|
||||
* 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);
|
||||
@@ -679,6 +664,7 @@ export class Collection<K, V> extends Map<K, V> {
|
||||
for (const [k, v] of entries) {
|
||||
super.set(k, v);
|
||||
}
|
||||
|
||||
return this;
|
||||
}
|
||||
|
||||
@@ -694,6 +680,7 @@ export class Collection<K, V> extends Map<K, V> {
|
||||
coll.set(k, v);
|
||||
}
|
||||
}
|
||||
|
||||
return coll;
|
||||
}
|
||||
|
||||
@@ -702,24 +689,26 @@ export class Collection<K, V> extends Map<K, V> {
|
||||
*
|
||||
* @param other - The other Collection to filter against
|
||||
*/
|
||||
public difference<T>(other: ReadonlyCollection<K, T>): Collection<K, V | T> {
|
||||
const coll = new this.constructor[Symbol.species]<K, V | T>();
|
||||
public difference<T>(other: ReadonlyCollection<K, T>): Collection<K, T | V> {
|
||||
const coll = new this.constructor[Symbol.species]<K, T | V>();
|
||||
for (const [k, v] of other) {
|
||||
if (!this.has(k)) coll.set(k, v);
|
||||
}
|
||||
|
||||
for (const [k, v] of this) {
|
||||
if (!other.has(k)) coll.set(k, v);
|
||||
}
|
||||
|
||||
return coll;
|
||||
}
|
||||
|
||||
/**
|
||||
* Merges two Collections together into a new Collection.
|
||||
*
|
||||
* @param other - The other Collection to merge with
|
||||
* @param whenInSelf - Function getting the result if the entry only exists in this Collection
|
||||
* @param whenInOther - Function getting the result if the entry only exists in the other Collection
|
||||
* @param whenInBoth - Function getting the result if the entry exists in both Collections
|
||||
*
|
||||
* @example
|
||||
* ```ts
|
||||
* // Sums up the entries in two collections.
|
||||
@@ -730,7 +719,6 @@ export class Collection<K, V> extends Map<K, V> {
|
||||
* (x, y) => ({ keep: true, value: x + y }),
|
||||
* );
|
||||
* ```
|
||||
*
|
||||
* @example
|
||||
* ```ts
|
||||
* // Intersects two collections in a left-biased manner.
|
||||
@@ -765,6 +753,7 @@ export class Collection<K, V> extends Map<K, V> {
|
||||
if (r.keep) coll.set(k, r.value);
|
||||
}
|
||||
}
|
||||
|
||||
return coll;
|
||||
}
|
||||
|
||||
@@ -776,7 +765,6 @@ export class Collection<K, V> extends Map<K, V> {
|
||||
* @param compareFunction - Specifies a function that defines the sort order.
|
||||
* 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.sorted((userA, userB) => userA.createdTimestamp - userB.createdTimestamp);
|
||||
@@ -800,7 +788,6 @@ export class Collection<K, V> extends Map<K, V> {
|
||||
*
|
||||
* @param entries - The list of entries
|
||||
* @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);
|
||||
@@ -819,6 +806,7 @@ export class Collection<K, V> extends Map<K, V> {
|
||||
coll.set(k, v);
|
||||
}
|
||||
}
|
||||
|
||||
return coll;
|
||||
}
|
||||
}
|
||||
@@ -826,7 +814,7 @@ export class Collection<K, V> extends Map<K, V> {
|
||||
/**
|
||||
* @internal
|
||||
*/
|
||||
export type Keep<V> = { keep: true; value: V } | { keep: false };
|
||||
export type Keep<V> = { keep: false } | { keep: true; value: V };
|
||||
|
||||
/**
|
||||
* @internal
|
||||
|
||||
@@ -1 +1 @@
|
||||
export * from './collection';
|
||||
export * from './collection.js';
|
||||
|
||||
3
packages/collection/tsup.config.js
Normal file
3
packages/collection/tsup.config.js
Normal file
@@ -0,0 +1,3 @@
|
||||
import { createTsupConfig } from '../../tsup.config.js';
|
||||
|
||||
export default createTsupConfig();
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user