From 21a8da190314d97da9fd3ef0f77f9c7c6e64bba9 Mon Sep 17 00:00:00 2001 From: Julian Vennen Date: Tue, 3 Sep 2024 13:54:19 +0200 Subject: [PATCH] Upgrade ESLint, fix many jsdoc warnings --- eslint.config.mjs | 47 ++ index.js | 5 +- package-lock.json | 427 +++++++++--------- package.json | 6 +- src/apis/YouTubePlaylist.js | 18 +- src/apis/Zendesk.js | 14 +- src/automod/AutoModManager.js | 26 +- src/automod/RepeatedMessage.js | 41 +- src/automod/SafeSearch.js | 16 +- src/bot/Bot.js | 8 +- src/bot/Cache.js | 4 +- src/bot/Config.js | 23 +- src/bot/Database.js | 23 +- src/bot/Logger.js | 21 +- src/bot/Request.js | 12 +- src/commands/Command.js | 22 +- src/commands/CommandManager.js | 37 +- src/commands/ExecutableCommand.js | 20 +- src/commands/ParentCommand.js | 8 +- src/commands/SubCommand.js | 4 +- src/commands/SubCommandGroup.js | 16 +- src/commands/bot/ImportCommand.js | 12 +- src/commands/bot/InfoCommand.js | 9 +- src/commands/external/ArticleCommand.js | 9 +- src/commands/external/VideoCommand.js | 2 +- src/commands/guild/IDCommand.js | 15 +- src/commands/guild/PurgeCommand.js | 23 +- .../moderation/ModerationClearCommand.js | 2 +- .../moderation/ModerationListCommand.js | 6 +- .../settings/AbstractChannelCommand.js | 2 +- .../settings/AttachmentCoolDownCommand.js | 1 - src/commands/settings/CapsCommand.js | 2 +- src/commands/settings/HelpCenterCommand.js | 8 +- src/commands/settings/PlaylistCommand.js | 2 +- .../settings/SettingsOverviewCommand.js | 6 +- .../auto-response/AddAutoResponseCommand.js | 2 +- .../auto-response/EditAutoResponseCommand.js | 4 +- .../settings/bad-word/AddBadWordCommand.js | 2 +- .../settings/bad-word/EditBadWordCommand.js | 8 +- .../settings/invites/ShowInvitesCommand.js | 12 +- .../muted-role/AbstractMutedRoleCommand.js | 6 +- src/commands/user/AvatarCommand.js | 2 +- src/commands/user/BanCommand.js | 8 +- src/commands/user/KickCommand.js | 8 +- src/commands/user/MuteCommand.js | 8 +- src/commands/user/PardonCommand.js | 4 +- src/commands/user/SoftBanCommand.js | 8 +- src/commands/user/StrikeCommand.js | 10 +- src/commands/user/StrikePurgeCommand.js | 8 +- src/commands/user/UnbanCommand.js | 4 +- src/commands/user/UnmuteCommand.js | 4 +- src/commands/user/UserCommand.js | 4 +- src/commands/user/UserInfoCommand.js | 6 +- src/database/AutoResponse.js | 28 +- src/database/BadWord.js | 32 +- src/database/ChatTriggeredFeature.js | 40 +- src/database/Confirmation.js | 6 +- src/database/Moderation.js | 76 ++-- src/database/Punishment.js | 3 +- src/database/export/Exporter.js | 7 +- src/database/export/Importer.js | 14 +- src/database/export/ModBotImporter.js | 7 +- src/database/export/VortexImporter.js | 28 +- src/database/migrations/Migration.js | 4 + src/database/triggers/RegexTrigger.js | 2 +- src/database/triggers/Trigger.js | 20 +- src/discord/ChannelWrapper.js | 10 +- src/discord/GuildWrapper.js | 36 +- src/discord/MemberWrapper.js | 109 ++--- src/discord/RateLimiter.js | 8 +- src/discord/UserWrapper.js | 2 +- .../SlashCommandPermissionManager.js | 8 +- .../SlashCommandPermissionManagerV2.js | 9 +- .../SlashCommandPermissionManagerV3.js | 17 +- .../SlashCommandPermissionManagers.js | 2 +- .../SlashCommandPermissionOverrides.js | 18 +- src/embeds/BetterButtonBuilder.js | 3 +- src/embeds/EmbedWrapper.js | 2 +- src/embeds/ErrorEmbed.js | 2 +- src/embeds/KeyValueEmbed.js | 12 +- src/embeds/LineEmbed.js | 4 +- src/embeds/ModerationEmbed.js | 4 + src/events/EventListener.js | 2 +- src/events/EventManager.js | 8 +- src/events/discord/BanRemoveEventListener.js | 2 +- src/events/discord/ErrorEventListener.js | 2 +- .../GuildAuditLogCreateEventListener.js | 4 +- .../discord/GuildDeleteEventListener.js | 2 +- .../discord/GuildMemberRemoveEventListener.js | 2 +- .../discord/MessageDeleteBulkEventListener.js | 2 +- .../discord/MessageDeleteEventListener.js | 2 +- src/events/discord/WarnEventListener.js | 2 +- .../GuildMemberAddEventListener.js | 4 +- .../InteractionCreateEventListener.js | 2 +- .../messageCreate/AutoModEventListener.js | 2 +- .../AutoResponseEventListener.js | 5 +- .../MessageCreateEventListener.js | 2 +- .../MessageUpdateEventListener.js | 2 +- src/interval/Interval.js | 4 +- src/interval/IntervalManager.js | 4 +- src/purge/PurgeFilter.js | 2 +- src/settings/ChannelSettings.js | 18 +- src/settings/GuildSettings.js | 58 +-- src/settings/Settings.js | 47 +- src/settings/TypeChecker.js | 30 +- src/settings/UserSettings.js | 6 +- src/util/channels.js | 4 +- src/util/colors.js | 4 +- src/util/format.js | 10 +- src/util/fsutils.js | 4 +- src/util/interaction.js | 6 +- src/util/timeutils.js | 8 +- src/util/util.js | 39 +- 113 files changed, 1018 insertions(+), 789 deletions(-) create mode 100644 eslint.config.mjs diff --git a/eslint.config.mjs b/eslint.config.mjs new file mode 100644 index 000000000..fcce5d8be --- /dev/null +++ b/eslint.config.mjs @@ -0,0 +1,47 @@ +import jsdoc from 'eslint-plugin-jsdoc'; +import json from 'eslint-plugin-json'; +import globals from 'globals'; +import js from '@eslint/js'; + +export default [ + js.configs.recommended, + json.configs.recommended, + jsdoc.configs['flat/recommended'], + { + files: ['**/*.js'], + plugins: { + jsdoc, + }, + rules: { + 'jsdoc/require-param-description': 'off', + 'jsdoc/require-returns-description': 'off', + 'jsdoc/require-property-description': 'off', + } + }, + { + languageOptions: { + globals: { + ...globals.node, + }, + + ecmaVersion: 'latest', + sourceType: 'module', + }, + + rules: { + indent: ['error', 4, { + SwitchCase: 1, + }], + + 'linebreak-style': ['error', 'unix'], + + 'no-unused-vars': ['error', { + vars: 'all', + args: 'none', + ignoreRestSiblings: false, + }], + + semi: ['error', 'always'], + }, + } +]; \ No newline at end of file diff --git a/index.js b/index.js index 925ee35c3..31ed2057a 100644 --- a/index.js +++ b/index.js @@ -7,6 +7,9 @@ import RestEventManagerEventManager from './src/events/rest/RestEventManager.js' import commandManager from './src/commands/CommandManager.js'; import IntervalManager from './src/interval/IntervalManager.js'; +/** + * + */ async function start() { await logger.debug('Loading settings'); await config.load(); @@ -34,7 +37,7 @@ start().catch(async (error) => { await logger.critical('Bot crashed', error); } catch (e) { - console.error('Failed to send fatal error to monitoring'); + console.error('Failed to send fatal error to monitoring', e); } console.error(error); process.exit(1); diff --git a/package-lock.json b/package-lock.json index 360dce451..710ca2b90 100644 --- a/package-lock.json +++ b/package-lock.json @@ -23,9 +23,9 @@ }, "devDependencies": { "@types/node": "^22.5.2", - "eslint": "^8.36.0", - "eslint-plugin-jsdoc": "^40.1.0", - "eslint-plugin-json": "^3.1.0" + "eslint": "^9.9.1", + "eslint-plugin-jsdoc": "^50.2.2", + "eslint-plugin-json": "^4.0.1" }, "engines": { "node": ">=20.0.0" @@ -171,17 +171,17 @@ "integrity": "sha512-urGGYeWtWNYMKnYlZnOnDHm8fVRffQs3U0SpE8RHeiuLKb/u92APS8HoQnPTFbnXmY1vVnXjXO4dOxcAn3J+DA==" }, "node_modules/@es-joy/jsdoccomment": { - "version": "0.37.1", - "resolved": "https://registry.npmjs.org/@es-joy/jsdoccomment/-/jsdoccomment-0.37.1.tgz", - "integrity": "sha512-5vxWJ1gEkEF0yRd0O+uK6dHJf7adrxwQSX8PuRiPfFSAbNLnY0ZJfXaZucoz14Jj2N11xn2DnlEPwWRpYpvRjg==", + "version": "0.48.0", + "resolved": "https://registry.npmjs.org/@es-joy/jsdoccomment/-/jsdoccomment-0.48.0.tgz", + "integrity": "sha512-G6QUWIcC+KvSwXNsJyDTHvqUdNoAVJPPgkc3+Uk4WBKqZvoXhlvazOgm9aL0HwihJLQf0l+tOE2UFzXBqCqgDw==", "dev": true, "dependencies": { - "comment-parser": "1.3.1", - "esquery": "^1.5.0", - "jsdoc-type-pratt-parser": "~4.0.0" + "comment-parser": "1.4.1", + "esquery": "^1.6.0", + "jsdoc-type-pratt-parser": "~4.1.0" }, "engines": { - "node": "^14 || ^16 || ^17 || ^18 || ^19 || ^20" + "node": ">=16" } }, "node_modules/@eslint-community/eslint-utils": { @@ -208,16 +208,30 @@ "node": "^12.0.0 || ^14.0.0 || >=16.0.0" } }, + "node_modules/@eslint/config-array": { + "version": "0.18.0", + "resolved": "https://registry.npmjs.org/@eslint/config-array/-/config-array-0.18.0.tgz", + "integrity": "sha512-fTxvnS1sRMu3+JjXwJG0j/i4RT9u4qJ+lqS/yCGap4lH4zZGzQ7tu+xZqQmcMZq5OBZDL4QRxQzRjkWcGt8IVw==", + "dev": true, + "dependencies": { + "@eslint/object-schema": "^2.1.4", + "debug": "^4.3.1", + "minimatch": "^3.1.2" + }, + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + } + }, "node_modules/@eslint/eslintrc": { - "version": "2.1.4", - "resolved": "https://registry.npmjs.org/@eslint/eslintrc/-/eslintrc-2.1.4.tgz", - "integrity": "sha512-269Z39MS6wVJtsoUl10L60WdkhJVdPG24Q4eZTH3nnF6lpvSShEK3wQjDX9JRWAUPvPh7COouPpU9IrqaZFvtQ==", + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/@eslint/eslintrc/-/eslintrc-3.1.0.tgz", + "integrity": "sha512-4Bfj15dVJdoy3RfZmmo86RK1Fwzn6SstsvK9JS+BaVKqC6QQQQyXekNaC+g+LKNgkQ+2VhGAzm6hO40AhMR3zQ==", "dev": true, "dependencies": { "ajv": "^6.12.4", "debug": "^4.3.2", - "espree": "^9.6.0", - "globals": "^13.19.0", + "espree": "^10.0.1", + "globals": "^14.0.0", "ignore": "^5.2.0", "import-fresh": "^3.2.1", "js-yaml": "^4.1.0", @@ -225,19 +239,28 @@ "strip-json-comments": "^3.1.1" }, "engines": { - "node": "^12.22.0 || ^14.17.0 || >=16.0.0" + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" }, "funding": { "url": "https://opencollective.com/eslint" } }, "node_modules/@eslint/js": { - "version": "8.57.0", - "resolved": "https://registry.npmjs.org/@eslint/js/-/js-8.57.0.tgz", - "integrity": "sha512-Ys+3g2TaW7gADOJzPt83SJtCDhMjndcDMFVQ/Tj9iA1BfJzFKD9mAUXT3OenpuPHbI6P/myECxRJrofUsDx/5g==", + "version": "9.9.1", + "resolved": "https://registry.npmjs.org/@eslint/js/-/js-9.9.1.tgz", + "integrity": "sha512-xIDQRsfg5hNBqHz04H1R3scSVwmI+KUbqjsQKHKQ1DAUSaUjYPReZZmS/5PNiKu1fUvzDd6H7DEDKACSEhu+TQ==", "dev": true, "engines": { - "node": "^12.22.0 || ^14.17.0 || >=16.0.0" + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + } + }, + "node_modules/@eslint/object-schema": { + "version": "2.1.4", + "resolved": "https://registry.npmjs.org/@eslint/object-schema/-/object-schema-2.1.4.tgz", + "integrity": "sha512-BsWiH1yFGjXXS2yvrf5LyuoSIIbPrGUWob917o+BTKuZ7qJdxX8aJLRxs1fS9n6r7vESrq1OUqb68dANcFXuQQ==", + "dev": true, + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" } }, "node_modules/@google-cloud/common": { @@ -366,21 +389,6 @@ "node": ">=6" } }, - "node_modules/@humanwhocodes/config-array": { - "version": "0.11.14", - "resolved": "https://registry.npmjs.org/@humanwhocodes/config-array/-/config-array-0.11.14.tgz", - "integrity": "sha512-3T8LkOmg45BV5FICb15QQMsyUSWrQ8AygVfC7ZG32zOalnqrilm018ZVCw0eapXux8FtA33q8PSRSstjee3jSg==", - "deprecated": "Use @eslint/config-array instead", - "dev": true, - "dependencies": { - "@humanwhocodes/object-schema": "^2.0.2", - "debug": "^4.3.1", - "minimatch": "^3.0.5" - }, - "engines": { - "node": ">=10.10.0" - } - }, "node_modules/@humanwhocodes/module-importer": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/@humanwhocodes/module-importer/-/module-importer-1.0.1.tgz", @@ -394,12 +402,18 @@ "url": "https://github.com/sponsors/nzakas" } }, - "node_modules/@humanwhocodes/object-schema": { - "version": "2.0.3", - "resolved": "https://registry.npmjs.org/@humanwhocodes/object-schema/-/object-schema-2.0.3.tgz", - "integrity": "sha512-93zYdMES/c1D69yZiKDBj0V24vqNzB/koF26KPaagAfd3P/4gUlh3Dys5ogAK+Exi9QyzlD8x/08Zt7wIKcDcA==", - "deprecated": "Use @eslint/object-schema instead", - "dev": true + "node_modules/@humanwhocodes/retry": { + "version": "0.3.0", + "resolved": "https://registry.npmjs.org/@humanwhocodes/retry/-/retry-0.3.0.tgz", + "integrity": "sha512-d2CGZR2o7fS6sWB7DG/3a95bGKQyHMACZ5aW8qGkkqQpUoZV6C0X7Pc7l4ZNMZkfNBf4VWNe9E1jRsf0G146Ew==", + "dev": true, + "engines": { + "node": ">=18.18" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/nzakas" + } }, "node_modules/@js-sdsl/ordered-map": { "version": "4.4.2", @@ -458,6 +472,18 @@ "node": ">=8.0.0" } }, + "node_modules/@pkgr/core": { + "version": "0.1.1", + "resolved": "https://registry.npmjs.org/@pkgr/core/-/core-0.1.1.tgz", + "integrity": "sha512-cq8o4cWH0ibXh9VGi5P20Tu9XF/0fFXl9EUinr9QfTM7a7p0oTA4iJRCQWppXR1Pg8dSM0UCItCkPwsk9qWWYA==", + "dev": true, + "engines": { + "node": "^12.20.0 || ^14.18.0 || >=16.0.0" + }, + "funding": { + "url": "https://opencollective.com/unts" + } + }, "node_modules/@protobufjs/aspromise": { "version": "1.1.2", "resolved": "https://registry.npmjs.org/@protobufjs/aspromise/-/aspromise-1.1.2.tgz", @@ -619,12 +645,6 @@ "@types/node": "*" } }, - "node_modules/@ungap/structured-clone": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/@ungap/structured-clone/-/structured-clone-1.2.0.tgz", - "integrity": "sha512-zuVdFrMJiuCDQUMCzQaD6KL28MjnqqN8XnAqiEq9PNm/hCPTSGfrXCOfwj1ow4LFb/tNymJPwsNbVePc1xFqrQ==", - "dev": true - }, "node_modules/@vladfrangu/async_event_emitter": { "version": "2.4.6", "resolved": "https://registry.npmjs.org/@vladfrangu/async_event_emitter/-/async_event_emitter-2.4.6.tgz", @@ -715,6 +735,15 @@ "url": "https://github.com/chalk/ansi-styles?sponsor=1" } }, + "node_modules/are-docs-informative": { + "version": "0.0.2", + "resolved": "https://registry.npmjs.org/are-docs-informative/-/are-docs-informative-0.0.2.tgz", + "integrity": "sha512-ixiS0nLNNG5jNQzgZJNoUpBKdo9yTYZMGJ+QgT2jmjR7G7+QHRCc4v6LQ3NgE7EBJq+o0ams3waJwkrlBom8Ig==", + "dev": true, + "engines": { + "node": ">=14" + } + }, "node_modules/argparse": { "version": "2.0.1", "resolved": "https://registry.npmjs.org/argparse/-/argparse-2.0.1.tgz", @@ -899,9 +928,9 @@ } }, "node_modules/comment-parser": { - "version": "1.3.1", - "resolved": "https://registry.npmjs.org/comment-parser/-/comment-parser-1.3.1.tgz", - "integrity": "sha512-B52sN2VNghyq5ofvUsqZjmk6YkihBX5vMSChmSK9v4ShjKf3Vk5Xcmgpw4o+iIgtrnM/u5FiMpz9VKb8lpBveA==", + "version": "1.4.1", + "resolved": "https://registry.npmjs.org/comment-parser/-/comment-parser-1.4.1.tgz", + "integrity": "sha512-buhp5kePrmda3vhc5B9t7pUQXAb2Tnd0qgpkIhPhkHXxJpiPJ11H0ZEU0oBpJ2QztSbzG/ZxMj/CHsYJqRHmyg==", "dev": true, "engines": { "node": ">= 12.0.0" @@ -1057,18 +1086,6 @@ "resolved": "https://registry.npmjs.org/discord-api-types/-/discord-api-types-0.37.97.tgz", "integrity": "sha512-No1BXPcVkyVD4ZVmbNgDKaBoqgeQ+FJpzZ8wqHkfmBnTZig1FcH3iPPersiK1TUIAzgClh2IvOuVUYfcWLQAOA==" }, - "node_modules/doctrine": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/doctrine/-/doctrine-3.0.0.tgz", - "integrity": "sha512-yS+Q5i3hBf7GBkd4KG8a7eBNNWNGLTaEwwYWUijIYM7zrlYDM0BFXHjjPWlWZ1Rg7UaddZeIDmi9jF3HmqiQ2w==", - "dev": true, - "dependencies": { - "esutils": "^2.0.2" - }, - "engines": { - "node": ">=6.0.0" - } - }, "node_modules/dot-prop": { "version": "6.0.1", "resolved": "https://registry.npmjs.org/dot-prop/-/dot-prop-6.0.1.tgz", @@ -1139,6 +1156,12 @@ "node": ">= 0.4" } }, + "node_modules/es-module-lexer": { + "version": "1.5.4", + "resolved": "https://registry.npmjs.org/es-module-lexer/-/es-module-lexer-1.5.4.tgz", + "integrity": "sha512-MVNK56NiMrOwitFB7cqDwq0CQutbw+0BvLshJSse0MUNU+y1FC3bUS/AQg7oUng+/wKrrki7JfmwtVHkVfPLlw==", + "dev": true + }, "node_modules/escalade": { "version": "3.2.0", "resolved": "https://registry.npmjs.org/escalade/-/escalade-3.2.0.tgz", @@ -1160,41 +1183,37 @@ } }, "node_modules/eslint": { - "version": "8.57.0", - "resolved": "https://registry.npmjs.org/eslint/-/eslint-8.57.0.tgz", - "integrity": "sha512-dZ6+mexnaTIbSBZWgou51U6OmzIhYM2VcNdtiTtI7qPNZm35Akpr0f6vtw3w1Kmn5PYo+tZVfh13WrhpS6oLqQ==", + "version": "9.9.1", + "resolved": "https://registry.npmjs.org/eslint/-/eslint-9.9.1.tgz", + "integrity": "sha512-dHvhrbfr4xFQ9/dq+jcVneZMyRYLjggWjk6RVsIiHsP8Rz6yZ8LvZ//iU4TrZF+SXWG+JkNF2OyiZRvzgRDqMg==", "dev": true, "dependencies": { "@eslint-community/eslint-utils": "^4.2.0", - "@eslint-community/regexpp": "^4.6.1", - "@eslint/eslintrc": "^2.1.4", - "@eslint/js": "8.57.0", - "@humanwhocodes/config-array": "^0.11.14", + "@eslint-community/regexpp": "^4.11.0", + "@eslint/config-array": "^0.18.0", + "@eslint/eslintrc": "^3.1.0", + "@eslint/js": "9.9.1", "@humanwhocodes/module-importer": "^1.0.1", + "@humanwhocodes/retry": "^0.3.0", "@nodelib/fs.walk": "^1.2.8", - "@ungap/structured-clone": "^1.2.0", "ajv": "^6.12.4", "chalk": "^4.0.0", "cross-spawn": "^7.0.2", "debug": "^4.3.2", - "doctrine": "^3.0.0", "escape-string-regexp": "^4.0.0", - "eslint-scope": "^7.2.2", - "eslint-visitor-keys": "^3.4.3", - "espree": "^9.6.1", - "esquery": "^1.4.2", + "eslint-scope": "^8.0.2", + "eslint-visitor-keys": "^4.0.0", + "espree": "^10.1.0", + "esquery": "^1.5.0", "esutils": "^2.0.2", "fast-deep-equal": "^3.1.3", - "file-entry-cache": "^6.0.1", + "file-entry-cache": "^8.0.0", "find-up": "^5.0.0", "glob-parent": "^6.0.2", - "globals": "^13.19.0", - "graphemer": "^1.4.0", "ignore": "^5.2.0", "imurmurhash": "^0.1.4", "is-glob": "^4.0.0", "is-path-inside": "^3.0.3", - "js-yaml": "^4.1.0", "json-stable-stringify-without-jsonify": "^1.0.1", "levn": "^0.4.1", "lodash.merge": "^4.6.2", @@ -1208,57 +1227,69 @@ "eslint": "bin/eslint.js" }, "engines": { - "node": "^12.22.0 || ^14.17.0 || >=16.0.0" + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" }, "funding": { - "url": "https://opencollective.com/eslint" + "url": "https://eslint.org/donate" + }, + "peerDependencies": { + "jiti": "*" + }, + "peerDependenciesMeta": { + "jiti": { + "optional": true + } } }, "node_modules/eslint-plugin-jsdoc": { - "version": "40.3.0", - "resolved": "https://registry.npmjs.org/eslint-plugin-jsdoc/-/eslint-plugin-jsdoc-40.3.0.tgz", - "integrity": "sha512-EhCqpzRkxoT2DUB4AnrU0ggBYvTh3bWrLZzQTupq6vSVE6XzNwJVKsOHa41GCoevnsWMBNmoDVjXWGqckjuG1g==", + "version": "50.2.2", + "resolved": "https://registry.npmjs.org/eslint-plugin-jsdoc/-/eslint-plugin-jsdoc-50.2.2.tgz", + "integrity": "sha512-i0ZMWA199DG7sjxlzXn5AeYZxpRfMJjDPUl7lL9eJJX8TPRoIaxJU4ys/joP5faM5AXE1eqW/dslCj3uj4Nqpg==", "dev": true, "dependencies": { - "@es-joy/jsdoccomment": "~0.37.0", - "comment-parser": "1.3.1", - "debug": "^4.3.4", + "@es-joy/jsdoccomment": "~0.48.0", + "are-docs-informative": "^0.0.2", + "comment-parser": "1.4.1", + "debug": "^4.3.6", "escape-string-regexp": "^4.0.0", - "esquery": "^1.5.0", - "semver": "^7.3.8", - "spdx-expression-parse": "^3.0.1" + "espree": "^10.1.0", + "esquery": "^1.6.0", + "parse-imports": "^2.1.1", + "semver": "^7.6.3", + "spdx-expression-parse": "^4.0.0", + "synckit": "^0.9.1" }, "engines": { - "node": "^14 || ^16 || ^17 || ^18 || ^19" + "node": ">=18" }, "peerDependencies": { - "eslint": "^7.0.0 || ^8.0.0" + "eslint": "^7.0.0 || ^8.0.0 || ^9.0.0" } }, "node_modules/eslint-plugin-json": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/eslint-plugin-json/-/eslint-plugin-json-3.1.0.tgz", - "integrity": "sha512-MrlG2ynFEHe7wDGwbUuFPsaT2b1uhuEFhJ+W1f1u+1C2EkXmTYJp4B1aAdQQ8M+CC3t//N/oRKiIVw14L2HR1g==", + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/eslint-plugin-json/-/eslint-plugin-json-4.0.1.tgz", + "integrity": "sha512-3An5ISV5dq/kHfXdNyY5TUe2ONC3yXFSkLX2gu+W8xAhKhfvrRvkSAeKXCxZqZ0KJLX15ojBuLPyj+UikQMkOA==", "dev": true, "dependencies": { "lodash": "^4.17.21", "vscode-json-languageservice": "^4.1.6" }, "engines": { - "node": ">=12.0" + "node": ">=18.0" } }, "node_modules/eslint-scope": { - "version": "7.2.2", - "resolved": "https://registry.npmjs.org/eslint-scope/-/eslint-scope-7.2.2.tgz", - "integrity": "sha512-dOt21O7lTMhDM+X9mB4GX+DZrZtCUJPL/wlcTqxyrx5IvO0IYtILdtrQGQp+8n5S0gwSVmOf9NQrjMOgfQZlIg==", + "version": "8.0.2", + "resolved": "https://registry.npmjs.org/eslint-scope/-/eslint-scope-8.0.2.tgz", + "integrity": "sha512-6E4xmrTw5wtxnLA5wYL3WDfhZ/1bUBGOXV0zQvVRDOtrR8D0p6W7fs3JweNYhwRYeGvd/1CKX2se0/2s7Q/nJA==", "dev": true, "dependencies": { "esrecurse": "^4.3.0", "estraverse": "^5.2.0" }, "engines": { - "node": "^12.22.0 || ^14.17.0 || >=16.0.0" + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" }, "funding": { "url": "https://opencollective.com/eslint" @@ -1276,18 +1307,42 @@ "url": "https://opencollective.com/eslint" } }, + "node_modules/eslint/node_modules/eslint-visitor-keys": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-4.0.0.tgz", + "integrity": "sha512-OtIRv/2GyiF6o/d8K7MYKKbXrOUBIK6SfkIRM4Z0dY3w+LiQ0vy3F57m0Z71bjbyeiWFiHJ8brqnmE6H6/jEuw==", + "dev": true, + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + }, + "funding": { + "url": "https://opencollective.com/eslint" + } + }, "node_modules/espree": { - "version": "9.6.1", - "resolved": "https://registry.npmjs.org/espree/-/espree-9.6.1.tgz", - "integrity": "sha512-oruZaFkjorTpF32kDSI5/75ViwGeZginGGy2NoOSg3Q9bnwlnmDm4HLnkl0RE3n+njDXR037aY1+x58Z/zFdwQ==", + "version": "10.1.0", + "resolved": "https://registry.npmjs.org/espree/-/espree-10.1.0.tgz", + "integrity": "sha512-M1M6CpiE6ffoigIOWYO9UDP8TMUw9kqb21tf+08IgDYjCsOvCuDt4jQcZmoYxx+w7zlKw9/N0KXfto+I8/FrXA==", "dev": true, "dependencies": { - "acorn": "^8.9.0", + "acorn": "^8.12.0", "acorn-jsx": "^5.3.2", - "eslint-visitor-keys": "^3.4.1" + "eslint-visitor-keys": "^4.0.0" }, "engines": { - "node": "^12.22.0 || ^14.17.0 || >=16.0.0" + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + }, + "funding": { + "url": "https://opencollective.com/eslint" + } + }, + "node_modules/espree/node_modules/eslint-visitor-keys": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-4.0.0.tgz", + "integrity": "sha512-OtIRv/2GyiF6o/d8K7MYKKbXrOUBIK6SfkIRM4Z0dY3w+LiQ0vy3F57m0Z71bjbyeiWFiHJ8brqnmE6H6/jEuw==", + "dev": true, + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" }, "funding": { "url": "https://opencollective.com/eslint" @@ -1394,15 +1449,15 @@ } }, "node_modules/file-entry-cache": { - "version": "6.0.1", - "resolved": "https://registry.npmjs.org/file-entry-cache/-/file-entry-cache-6.0.1.tgz", - "integrity": "sha512-7Gps/XWymbLk2QLYK4NzpMOrYjMhdIxXuIvy2QBsLE6ljuodKvdkWs/cpyJJ3CVIVpH0Oi1Hvg1ovbMzLdFBBg==", + "version": "8.0.0", + "resolved": "https://registry.npmjs.org/file-entry-cache/-/file-entry-cache-8.0.0.tgz", + "integrity": "sha512-XXTUwCvisa5oacNGRP9SfNtYBNAMi+RPwBFmblZEF7N7swHYQS6/Zfk7SRwx4D5j3CH211YNRco1DEMNVfZCnQ==", "dev": true, "dependencies": { - "flat-cache": "^3.0.4" + "flat-cache": "^4.0.0" }, "engines": { - "node": "^10.12.0 || >=12.0.0" + "node": ">=16.0.0" } }, "node_modules/find-up": { @@ -1422,17 +1477,16 @@ } }, "node_modules/flat-cache": { - "version": "3.2.0", - "resolved": "https://registry.npmjs.org/flat-cache/-/flat-cache-3.2.0.tgz", - "integrity": "sha512-CYcENa+FtcUKLmhhqyctpclsq7QF38pKjZHsGNiSQF5r4FtoKDWabFDl3hzaEQMvT1LHEysw5twgLvpYYb4vbw==", + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/flat-cache/-/flat-cache-4.0.1.tgz", + "integrity": "sha512-f7ccFPK3SXFHpx15UIGyRJ/FJQctuKZ0zVuN3frBo4HnK3cay9VEW0R6yPYFHC0AgqhukPzKjq22t5DmAyqGyw==", "dev": true, "dependencies": { "flatted": "^3.2.9", - "keyv": "^4.5.3", - "rimraf": "^3.0.2" + "keyv": "^4.5.4" }, "engines": { - "node": "^10.12.0 || >=12.0.0" + "node": ">=16" } }, "node_modules/flatted": { @@ -1462,12 +1516,6 @@ "node": ">= 14.17" } }, - "node_modules/fs.realpath": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/fs.realpath/-/fs.realpath-1.0.0.tgz", - "integrity": "sha512-OO0pH2lK6a0hZnAdau5ItzHPI6pUlvI7jMVnxUQRtw4owF2wk8lOSabtGDCTP4Ggrg2MbGnWO9X8K1t4+fGMDw==", - "dev": true - }, "node_modules/function-bind": { "version": "1.1.2", "resolved": "https://registry.npmjs.org/function-bind/-/function-bind-1.1.2.tgz", @@ -1556,27 +1604,6 @@ "url": "https://github.com/sponsors/sindresorhus" } }, - "node_modules/glob": { - "version": "7.2.3", - "resolved": "https://registry.npmjs.org/glob/-/glob-7.2.3.tgz", - "integrity": "sha512-nFR0zLpU2YCaRxwoCJvL6UvCH2JFyFVIvwTLsIf21AuHlMskA1hhTdk+LlYJtOlYt9v6dvszD2BGRqBL+iQK9Q==", - "deprecated": "Glob versions prior to v9 are no longer supported", - "dev": true, - "dependencies": { - "fs.realpath": "^1.0.0", - "inflight": "^1.0.4", - "inherits": "2", - "minimatch": "^3.1.1", - "once": "^1.3.0", - "path-is-absolute": "^1.0.0" - }, - "engines": { - "node": "*" - }, - "funding": { - "url": "https://github.com/sponsors/isaacs" - } - }, "node_modules/glob-parent": { "version": "6.0.2", "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-6.0.2.tgz", @@ -1590,15 +1617,12 @@ } }, "node_modules/globals": { - "version": "13.24.0", - "resolved": "https://registry.npmjs.org/globals/-/globals-13.24.0.tgz", - "integrity": "sha512-AhO5QUcj8llrbG09iWhPU2B204J1xnPeL8kQmVorSsy+Sjj1sk8gIyh6cUocGmH4L0UuhAJy+hJMRA4mgA4mFQ==", + "version": "14.0.0", + "resolved": "https://registry.npmjs.org/globals/-/globals-14.0.0.tgz", + "integrity": "sha512-oahGvuMGQlPw/ivIYBjVSrWAfWLBeku5tpPE2fOPLi+WHffIWbuh2tCjhyQhTBPMf5E9jDEH4FOmTYgYwbKwtQ==", "dev": true, - "dependencies": { - "type-fest": "^0.20.2" - }, "engines": { - "node": ">=8" + "node": ">=18" }, "funding": { "url": "https://github.com/sponsors/sindresorhus" @@ -1693,12 +1717,6 @@ "url": "https://github.com/sindresorhus/got?sponsor=1" } }, - "node_modules/graphemer": { - "version": "1.4.0", - "resolved": "https://registry.npmjs.org/graphemer/-/graphemer-1.4.0.tgz", - "integrity": "sha512-EtKwoO6kxCL9WO5xipiHTZlSzBm7WLT627TqC/uVRd0HKmq8NXyebnNYxDoBi7wt8eTWrUrKXCOVaFq9x1kgag==", - "dev": true - }, "node_modules/gtoken": { "version": "7.1.0", "resolved": "https://registry.npmjs.org/gtoken/-/gtoken-7.1.0.tgz", @@ -1877,17 +1895,6 @@ "node": ">=0.8.19" } }, - "node_modules/inflight": { - "version": "1.0.6", - "resolved": "https://registry.npmjs.org/inflight/-/inflight-1.0.6.tgz", - "integrity": "sha512-k92I/b08q4wvFscXCLvqfsHCrjrF7yiXsQuIVvVE7N82W3+aqpzuUdBbfhWcy/FZR3/4IgflMgKLOsvPDrGCJA==", - "deprecated": "This module is not supported, and leaks memory. Do not use it. Check out lru-cache if you want a good and tested way to coalesce async requests by a key value, which is much more comprehensive and powerful.", - "dev": true, - "dependencies": { - "once": "^1.3.0", - "wrappy": "1" - } - }, "node_modules/inherits": { "version": "2.0.4", "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.4.tgz", @@ -1982,9 +1989,9 @@ } }, "node_modules/jsdoc-type-pratt-parser": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/jsdoc-type-pratt-parser/-/jsdoc-type-pratt-parser-4.0.0.tgz", - "integrity": "sha512-YtOli5Cmzy3q4dP26GraSOeAhqecewG04hoO8DY56CH4KJ9Fvv5qKWUCCo3HZob7esJQHCv6/+bnTy72xZZaVQ==", + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/jsdoc-type-pratt-parser/-/jsdoc-type-pratt-parser-4.1.0.tgz", + "integrity": "sha512-Hicd6JK5Njt2QB6XYFS7ok9e37O8AYk3jTcppG4YVQnYjOemymvTcmc7OWsmq/Qqj5TdRFO5/x/tIPmBeRtGHg==", "dev": true, "engines": { "node": ">=12.0.0" @@ -2352,6 +2359,19 @@ "node": ">=6" } }, + "node_modules/parse-imports": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/parse-imports/-/parse-imports-2.1.1.tgz", + "integrity": "sha512-TDT4HqzUiTMO1wJRwg/t/hYk8Wdp3iF/ToMIlAoVQfL1Xs/sTxq1dKWSMjMbQmIarfWKymOyly40+zmPHXMqCA==", + "dev": true, + "dependencies": { + "es-module-lexer": "^1.5.3", + "slashes": "^3.0.12" + }, + "engines": { + "node": ">= 18" + } + }, "node_modules/path-exists": { "version": "4.0.0", "resolved": "https://registry.npmjs.org/path-exists/-/path-exists-4.0.0.tgz", @@ -2361,15 +2381,6 @@ "node": ">=8" } }, - "node_modules/path-is-absolute": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/path-is-absolute/-/path-is-absolute-1.0.1.tgz", - "integrity": "sha512-AVbw3UJ2e9bq64vSaS9Am0fje1Pa8pbGqTTsmXfaIiMpnr5DlDhfJOuLj9Sf95ZPVDAUerDfEk88MPmPe7UCQg==", - "dev": true, - "engines": { - "node": ">=0.10.0" - } - }, "node_modules/path-key": { "version": "3.1.1", "resolved": "https://registry.npmjs.org/path-key/-/path-key-3.1.1.tgz", @@ -2567,22 +2578,6 @@ "node": ">=0.10.0" } }, - "node_modules/rimraf": { - "version": "3.0.2", - "resolved": "https://registry.npmjs.org/rimraf/-/rimraf-3.0.2.tgz", - "integrity": "sha512-JZkJMZkAGFFPP2YqXZXPbMlMBgsxzE8ILs4lMIX/2o0L9UBw9O/Y3o6wFw/i9YLapcUJWwqbi3kdxIPdC62TIA==", - "deprecated": "Rimraf versions prior to v4 are no longer supported", - "dev": true, - "dependencies": { - "glob": "^7.1.3" - }, - "bin": { - "rimraf": "bin.js" - }, - "funding": { - "url": "https://github.com/sponsors/isaacs" - } - }, "node_modules/run-parallel": { "version": "1.2.0", "resolved": "https://registry.npmjs.org/run-parallel/-/run-parallel-1.2.0.tgz", @@ -2701,6 +2696,12 @@ "url": "https://github.com/sponsors/ljharb" } }, + "node_modules/slashes": { + "version": "3.0.12", + "resolved": "https://registry.npmjs.org/slashes/-/slashes-3.0.12.tgz", + "integrity": "sha512-Q9VME8WyGkc7pJf6QEkj3wE+2CnvZMI+XJhwdTPR8Z/kWQRXi7boAWLDibRPyHRTUTPx5FaU7MsyrjI3yLB4HA==", + "dev": true + }, "node_modules/spdx-exceptions": { "version": "2.5.0", "resolved": "https://registry.npmjs.org/spdx-exceptions/-/spdx-exceptions-2.5.0.tgz", @@ -2708,9 +2709,9 @@ "dev": true }, "node_modules/spdx-expression-parse": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/spdx-expression-parse/-/spdx-expression-parse-3.0.1.tgz", - "integrity": "sha512-cbqHunsQWnJNE6KhVSMsMeH5H/L9EpymbzqTQ3uLwNCLZ1Q481oWaofqH7nO6V07xlXwY6PhQdQ2IedWx/ZK4Q==", + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/spdx-expression-parse/-/spdx-expression-parse-4.0.0.tgz", + "integrity": "sha512-Clya5JIij/7C6bRR22+tnGXbc4VKlibKSVj2iHvVeX5iMW7s1SIQlqu699JkODJJIhh/pUu8L0/VLh8xflD+LQ==", "dev": true, "dependencies": { "spdx-exceptions": "^2.1.0", @@ -2811,6 +2812,22 @@ "node": ">=8" } }, + "node_modules/synckit": { + "version": "0.9.1", + "resolved": "https://registry.npmjs.org/synckit/-/synckit-0.9.1.tgz", + "integrity": "sha512-7gr8p9TQP6RAHusBOSLs46F4564ZrjV8xFmw5zCmgmhGUcw2hxsShhJ6CEiHQMgPDwAQ1fWHPM0ypc4RMAig4A==", + "dev": true, + "dependencies": { + "@pkgr/core": "^0.1.0", + "tslib": "^2.6.2" + }, + "engines": { + "node": "^14.18.0 || >=16.0.0" + }, + "funding": { + "url": "https://opencollective.com/unts" + } + }, "node_modules/teeny-request": { "version": "9.0.0", "resolved": "https://registry.npmjs.org/teeny-request/-/teeny-request-9.0.0.tgz", @@ -2890,18 +2907,6 @@ "node": ">= 0.8.0" } }, - "node_modules/type-fest": { - "version": "0.20.2", - "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-0.20.2.tgz", - "integrity": "sha512-Ne+eE4r0/iWnpAxD852z3A+N0Bt5RN//NjJwRd2VFHEmrywxf5vsZlh4R6lixl6B+wz/8d+maTSAkN1FIkI3LQ==", - "dev": true, - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, "node_modules/undici": { "version": "6.19.8", "resolved": "https://registry.npmjs.org/undici/-/undici-6.19.8.tgz", diff --git a/package.json b/package.json index 8365344f8..d8fcefd7c 100644 --- a/package.json +++ b/package.json @@ -36,9 +36,9 @@ }, "devDependencies": { "@types/node": "^22.5.2", - "eslint": "^8.36.0", - "eslint-plugin-jsdoc": "^40.1.0", - "eslint-plugin-json": "^3.1.0" + "eslint": "^9.9.1", + "eslint-plugin-jsdoc": "^50.2.2", + "eslint-plugin-json": "^4.0.1" }, "lint-staged": { "*.js": [ diff --git a/src/apis/YouTubePlaylist.js b/src/apis/YouTubePlaylist.js index 2ada320a9..7c7f85bf0 100644 --- a/src/apis/YouTubePlaylist.js +++ b/src/apis/YouTubePlaylist.js @@ -10,39 +10,39 @@ const CACHE_DURATION = 10 * 60 * 1000; const cache = new Cache(); /** - * @typedef {Object} PlaylistResponse + * @typedef {object} PlaylistResponse * @property {PlaylistResponseData} data * @property {string} etag * @property {string} nextPageToken */ /** - * @typedef {Object} PlaylistResponseData + * @typedef {object} PlaylistResponseData * @property {PageInfo} pageInfo * @property {YouTubeVideo[]} items */ /** - * @typedef {Object} PageInfo + * @typedef {object} PageInfo * @property {number} totalResults * @property {number} resultsPerPage */ /** - * @typedef {Object} YouTubeVideo + * @typedef {object} YouTubeVideo * @property {string} etag * @property {YouTubeVideoSnippet} snippet */ /** - * @typedef {Object} YouTubeVideoSnippet + * @typedef {object} YouTubeVideoSnippet * @property {string} title * @property {string} description * @property {SnippetResourceId} resourceId */ /** - * @typedef {Object} SnippetResourceId + * @typedef {object} SnippetResourceId * @property {string} videoId */ @@ -56,7 +56,7 @@ export default class YouTubePlaylist { /** * is this a valid playlist id * @param {string} id - * @return {Promise} + * @returns {Promise} */ static async isValidPlaylist(id) { const response = await youtube.playlists.list({ @@ -77,7 +77,7 @@ export default class YouTubePlaylist { /** * get all videos in this playlist - * @return {Promise} + * @returns {Promise} */ async getVideos() { const cacheEntry = cache.getEntry(this.#id); @@ -109,7 +109,7 @@ export default class YouTubePlaylist { * search for videos in this playlist * searches in title and description * @param {string} query - * @return {Promise<(import('fuse.js').Fuse.FuseResult)[]>} + * @returns {Promise<(import('fuse.js').Fuse.FuseResult)[]>} */ async searchVideos(query) { const videos = await this.getVideos(); diff --git a/src/apis/Zendesk.js b/src/apis/Zendesk.js index 5e469e220..ae4f75acf 100644 --- a/src/apis/Zendesk.js +++ b/src/apis/Zendesk.js @@ -1,7 +1,7 @@ import got from 'got'; /** - * @typedef {Object} ZendeskArticle + * @typedef {object} ZendeskArticle * @property {number} id article id * @property {string} url api url * @property {string} html_url url to public article page @@ -11,7 +11,7 @@ import got from 'got'; */ /** - * @typedef {Object} ZendeskArticleSuggestion + * @typedef {object} ZendeskArticleSuggestion * @property {string} title * @property {string} category_title * @property {string} url @@ -29,7 +29,7 @@ export default class Zendesk { /** * search articles * @param {string} query - * @return {Promise<{count: number, results: ZendeskArticle[]}>} + * @returns {Promise<{count: number, results: ZendeskArticle[]}>} */ async searchArticles(query) { return this.#request(`api/v2/help_center/articles/search.json?query=${encodeURIComponent(query)}`); @@ -38,7 +38,7 @@ export default class Zendesk { /** * get article suggestions * @param {string} query - * @return {Promise} + * @returns {Promise} */ async getArticleSuggestions(query) { const data = await this.#request(`hc/api/internal/instant_search.json?query=${encodeURIComponent(query)}`); @@ -48,7 +48,7 @@ export default class Zendesk { /** * get a single article * @param {string|number} id - * @return {Promise} + * @returns {Promise} */ async getArticle(id) { /** @type {{article: ZendeskArticle}} */ @@ -58,7 +58,7 @@ export default class Zendesk { /** * @param {number} [results] maximum number of articles that will be returned - * @return {Promise} + * @returns {Promise} */ async getArticles(results = 100) { /** @type {{articles: ZendeskArticle[]}} */ @@ -68,7 +68,7 @@ export default class Zendesk { /** * get promoted articles - * @return {Promise} + * @returns {Promise} */ async getPromotedArticles() { const articles = await this.getArticles(); diff --git a/src/automod/AutoModManager.js b/src/automod/AutoModManager.js index 9f19c1d39..75d913761 100644 --- a/src/automod/AutoModManager.js +++ b/src/automod/AutoModManager.js @@ -49,7 +49,7 @@ export class AutoModManager { /** * run all checks on a message * @param {import('discord.js').Message} message - * @return {Promise} + * @returns {Promise} */ async checkMessage(message) { await this.#runChecks(message, ...this.#CONTENT_CHECKS, ...this.#COOLDOWN_CHECKS); @@ -58,7 +58,7 @@ export class AutoModManager { /** * run all content checks on a message, don't run any cooldown checks * @param {import('discord.js').Message} message - * @return {Promise} + * @returns {Promise} */ async checkMessageEdit(message) { await this.#runChecks(message, ...this.#CONTENT_CHECKS); @@ -68,7 +68,7 @@ export class AutoModManager { * * @param {import('discord.js').Message} message * @param {(message: import('discord.js').Message) => Promise} checks - * @return {Promise} + * @returns {Promise} */ async #runChecks(message, ...checks) { if (await this.#ignoredByAutomod(message)) { @@ -93,7 +93,7 @@ export class AutoModManager { /** * @param {import('discord.js').Message} message - * @return {Promise} + * @returns {Promise} */ async #ignoredByAutomod(message) { if (!message.guild || message.system || message.author.bot) { @@ -108,7 +108,7 @@ export class AutoModManager { * @param {import('discord.js').Message} message * @param {?string} reason * @param {string} warning - * @return {Promise} + * @returns {Promise} */ async #deleteAndWarn(message, reason, warning) { try { @@ -129,7 +129,7 @@ export class AutoModManager { * send a temporary warning message mentioning the user * @param {import('discord.js').Message} message * @param {string} warning - * @return {Promise} + * @returns {Promise} */ async #sendWarning(message, warning) { try { @@ -145,7 +145,7 @@ export class AutoModManager { /** * @param {import('discord.js').Message} message - * @return {Promise} has the message been deleted + * @returns {Promise} has the message been deleted */ async #safeSearchDetection(message) { if (!await this.#safeSearch.isEnabledInGuild(message.guild) || (/** @type {import('discord.js').TextBasedChannelFields} */ message.channel).nsfw) { @@ -169,7 +169,7 @@ export class AutoModManager { /** * @param {import('discord.js').Message} message - * @return {Promise} has the message been deleted + * @returns {Promise} has the message been deleted */ async #badWords(message) { let channel = message.channel; @@ -232,7 +232,7 @@ export class AutoModManager { /** * @param {import('discord.js').Message} message - * @return {Promise} has the message been deleted + * @returns {Promise} has the message been deleted */ async #caps(message) { const guildSettings = await GuildSettings.get(message.guild.id); @@ -252,7 +252,7 @@ export class AutoModManager { /** * @param {import('discord.js').Message} message - * @return {Promise} has the message been deleted + * @returns {Promise} has the message been deleted */ async #invites(message) { if (!this.includesInvite(message.content)) { @@ -277,7 +277,7 @@ export class AutoModManager { /** * @param {import('discord.js').Message} message - * @return {Promise} has the message been deleted + * @returns {Promise} has the message been deleted */ async linkCoolDown(message) { if (!message.content.match(/https?:\/\//i)) { @@ -303,7 +303,7 @@ export class AutoModManager { /** * @param {import('discord.js').Message} message - * @return {Promise} has the message been deleted + * @returns {Promise} has the message been deleted */ async attachmentCoolDown(message) { if (!message.attachments.size) { @@ -329,7 +329,7 @@ export class AutoModManager { /** * @param {import('discord.js').Message} message - * @return {Promise} + * @returns {Promise} */ async spam(message) { const guildSettings = await GuildSettings.get(message.guild.id); diff --git a/src/automod/RepeatedMessage.js b/src/automod/RepeatedMessage.js index f1436e74a..d8e9da982 100644 --- a/src/automod/RepeatedMessage.js +++ b/src/automod/RepeatedMessage.js @@ -2,6 +2,10 @@ import {Collection, userMention} from 'discord.js'; import {compareTwoStrings} from 'string-similarity'; import bot from '../bot/Bot.js'; +/** + * @import {Message} from 'discord.js'; + */ + export default class RepeatedMessage { /** @@ -30,7 +34,7 @@ export default class RepeatedMessage { warned = false; /** - * @param {import('discord.js').Message} message + * @param {Message} message */ constructor(message) { this.#key = this.constructor.getKey(message); @@ -41,7 +45,7 @@ export default class RepeatedMessage { * Are these messages similar enough? * @param {Message} messageA * @param {Message} messageB - * @return {boolean} + * @returns {boolean} */ similarEnough(messageA, messageB) { const similarity = compareTwoStrings(messageA.content, messageB.content); @@ -50,7 +54,8 @@ export default class RepeatedMessage { /** * get count of similar messages - * @return {number} + * @param {Message} newMessage + * @returns {number} */ getSimilarMessageCount(newMessage) { return this.getSimilarMessages(newMessage).length; @@ -58,8 +63,8 @@ export default class RepeatedMessage { /** * get similar messages - * @param {import('discord.js')} newMessage - * @return {import('discord.js')[]} + * @param {Message} newMessage + * @returns {Message[]} */ getSimilarMessages(newMessage) { let similarMessages = []; @@ -73,7 +78,7 @@ export default class RepeatedMessage { /** * how many messages are cached for this member? - * @return {Number} + * @returns {number} */ getMessageCount() { return this.#messages.length; @@ -94,7 +99,7 @@ export default class RepeatedMessage { } /** - * @return {Promise} + * @returns {Promise} */ async deleteAll() { return this.delete(this.#messages, 'Fast message spam'); @@ -103,7 +108,7 @@ export default class RepeatedMessage { /** * delete similar messages * @param {Message} message - * @return {Promise} + * @returns {Promise} */ async deleteSimilar(message) { return this.delete(this.getSimilarMessages(message), 'Repeated messages'); @@ -112,7 +117,7 @@ export default class RepeatedMessage { /** * delete an array of messages if possible * @param {import('discord.js').Message[]} messages - * @param {String} reason + * @param {string} reason * @returns {Promise} */ async delete(messages, reason) { @@ -129,20 +134,12 @@ export default class RepeatedMessage { /** * get the key of this message * @param {Message} message - * @return {string} + * @returns {string} */ static getKey(message) { return `${message.guild.id}-${message.author.id}`; } - /** - * @param key - * @return {RepeatedMessage} - */ - static get(key) { - return this.#members.get(key); - } - /** * add this message to the correct cache * @param {import('discord.js').Message} message @@ -162,9 +159,9 @@ export default class RepeatedMessage { /** * remove this message if it is fast message spam * @param {import('discord.js').Message} message - * @param {Number} count maximum allowed number of messages per minute + * @param {number} count maximum allowed number of messages per minute * @param {number} timeout reply timeout in ms - * @return {Promise} was this message deleted + * @returns {Promise} was this message deleted */ static async checkSpam(message, count, timeout) { const cache = this.#members.get(this.getKey(message)); @@ -184,9 +181,9 @@ export default class RepeatedMessage { /** * remove this message if it is repeated * @param {import('discord.js').Message} message - * @param {Number} count maximum allowed number of similar messages per minute + * @param {number} count maximum allowed number of similar messages per minute * @param {number} timeout reply timeout in ms - * @return {Promise} was this message deleted + * @returns {Promise} was this message deleted */ static async checkSimilar(message, count, timeout) { const cache = this.#members.get(this.getKey(message)); diff --git a/src/automod/SafeSearch.js b/src/automod/SafeSearch.js index 44a3e5846..5c8888060 100644 --- a/src/automod/SafeSearch.js +++ b/src/automod/SafeSearch.js @@ -5,6 +5,10 @@ import database from '../bot/Database.js'; import logger from '../bot/Logger.js'; import cloudVision from '../apis/CloudVision.js'; +/** + * @import {google} from '@google-cloud/vision'; + */ + const CACHE_DURATION = 60 * 60 * 1000; export default class SafeSearch { @@ -12,14 +16,14 @@ export default class SafeSearch { /** * A map of hashes to resolve functions that are currently waiting for a response from the api - * @type {Map} + * @type {Map} */ #requesting = new Map(); /** * is safe search filtering enabled in this guild * @param {import('discord.js').Guild} guild - * @return {Promise} + * @returns {Promise} */ async isEnabledInGuild(guild) { if (!cloudVision.isEnabled) { @@ -33,7 +37,7 @@ export default class SafeSearch { /** * detect images in this message using the safe search api * @param {import('discord.js').Message} message - * @return {Promise} + * @returns {Promise} */ async detect(message) { /** @type {import('discord.js').Collection} */ @@ -63,7 +67,7 @@ export default class SafeSearch { /** * @param {import('discord.js').Attachment} image - * @return {Promise} + * @returns {Promise} */ async request(image) { const hash = await new Request(image.proxyURL).getHash(); @@ -104,7 +108,7 @@ export default class SafeSearch { /** * @param {string} hash - * @return {Promise} + * @returns {Promise} */ async #getFromDatabase(hash) { const result = await database.query('SELECT data FROM safeSearch WHERE hash = ?', hash); @@ -117,7 +121,7 @@ export default class SafeSearch { /** * convert a likelihood to a number for easy comparison * @param {string} likelihood - * @return {number} + * @returns {number} */ getLikelihoodAsNumber(likelihood) { switch (likelihood) { diff --git a/src/bot/Bot.js b/src/bot/Bot.js index a3d83510f..9283331d0 100644 --- a/src/bot/Bot.js +++ b/src/bot/Bot.js @@ -11,6 +11,10 @@ import config from './Config.js'; import GuildWrapper from '../discord/GuildWrapper.js'; import MessageDeleteEmbed from '../embeds/MessageDeleteEmbed.js'; +/** + * @import {Message} from 'discord.js'; + */ + export class Bot { /** * @type {import('discord.js').Client} @@ -45,7 +49,7 @@ export class Bot { } /** - * @return {import('discord.js').Client} + * @returns {import('discord.js').Client} */ get client() { return this.#client; @@ -97,7 +101,7 @@ export class Bot { * log that a message has been deleted * @param {import('discord.js').Message} message * @param {string} reason - * @return {Promise} + * @returns {Promise} */ async logMessageDeletion(message, reason) { const guild = new GuildWrapper(message.guild); diff --git a/src/bot/Cache.js b/src/bot/Cache.js index 4679a1412..f678badbc 100644 --- a/src/bot/Cache.js +++ b/src/bot/Cache.js @@ -17,7 +17,7 @@ export default class Cache { /** * get the value of a cache entry * @param {K} key - * @return {?V} + * @returns {?V} */ get(key) { return this.getEntry(key)?.value; @@ -26,7 +26,7 @@ export default class Cache { /** * get a cache entry * @param {K} key - * @return {?CacheEntry} + * @returns {?CacheEntry} */ getEntry(key) { return this.#cache.get(key); diff --git a/src/bot/Config.js b/src/bot/Config.js index a45d97146..038b2452c 100644 --- a/src/bot/Config.js +++ b/src/bot/Config.js @@ -2,7 +2,7 @@ import logger from './Logger.js'; import {exists, readJSON} from '../util/fsutils.js'; /** - * @typedef {Object} ConfigData + * @typedef {object} ConfigData * @property {string} authToken * @property {DatabaseConfig} database * @property {?string} googleApiKey @@ -13,36 +13,41 @@ import {exists, readJSON} from '../util/fsutils.js'; */ /** - * @typedef {Object} GoogleCloudConfig + * @typedef {object} GoogleCloudConfig * @property {GoogleCloudCredentials} credentials * @property {CloudLoggingConfig} logging * @property {VisionConfig} vision */ /** - * @typedef {Object} DatabaseConfig + * @typedef {object} DatabaseConfig + * @property {string} host + * @property {string} user + * @property {string} password + * @property {string} database + * @property {number} port */ /** - * @typedef {Object} VisionConfig + * @typedef {object} VisionConfig * @property {boolean} enabled */ /** - * @typedef {Object} CloudLoggingConfig google cloud monitoring + * @typedef {object} CloudLoggingConfig google cloud monitoring * @property {boolean} enabled * @property {string} projectId * @property {string} logName */ /** - * @typedef {Object} GoogleCloudCredentials + * @typedef {object} GoogleCloudCredentials * @property {string} client_email * @property {string} private_key */ /** - * @typedef {Object} Emojis + * @typedef {object} Emojis * @property {?string} source * @property {?string} privacy * @property {?string} invite @@ -79,7 +84,7 @@ export class Config { #data; /** - * @return {ConfigData} + * @returns {ConfigData} */ get data() { return this.#data; @@ -184,7 +189,7 @@ export class Config { /** * parse an environment variable as a boolean * @param {string} string - * @return {boolean} + * @returns {boolean} */ #parseBooleanFromEnv(string) { return ['1', 'true', 'y'].includes(string?.toLowerCase?.()); diff --git a/src/bot/Database.js b/src/bot/Database.js index 8b1316d0e..4707b7c07 100644 --- a/src/bot/Database.js +++ b/src/bot/Database.js @@ -7,6 +7,10 @@ import BadWordVisionMigration from '../database/migrations/BadWordVisionMigratio import AutoResponseVisionMigration from '../database/migrations/AutoResponseVisionMigration.js'; import DMMigration from '../database/migrations/DMMigration.js'; +/** + * @import {QueryError} from 'mysql2'; + */ + export class Database { /** * @type {import('mysql2').Connection} @@ -14,7 +18,7 @@ export class Database { #connection = null; /** - * @type {{resolve: function, reject: function}[]} + * @type {{resolve: Function, reject: Function}[]} */ #waiting = []; @@ -35,7 +39,6 @@ export class Database { /** * Wait until a working MySQL connection is available - * * @returns {Promise} */ waitForConnection() { @@ -61,7 +64,7 @@ export class Database { } this.#waiting = []; } catch (error) { - return this.#handleFatalError(error); + this.#handleFatalError(error); } } @@ -76,8 +79,7 @@ export class Database { /** * Handle connection error - * - * @param err + * @param {QueryError} err * @private */ #handleFatalError(err) { @@ -96,8 +98,7 @@ export class Database { /** * Create required tables - * - * @return {Promise} + * @returns {Promise} */ async createTables() { await this.query('CREATE TABLE IF NOT EXISTS `channels` (`id` VARCHAR(20) NOT NULL, `config` TEXT NOT NULL, PRIMARY KEY (`id`), `guildid` VARCHAR(20))'); @@ -134,10 +135,9 @@ export class Database { /** * Execute query and return all results - * * @param {string} sql * @param {string|number|null} values - * @returns {Promise} + * @returns {Promise} */ async queryAll(sql, ...values) { await this.waitForConnection(); @@ -151,10 +151,9 @@ export class Database { /** * Execute query and return the first result - * * @param {string} sql * @param {*} values - * @returns {Promise} + * @returns {Promise} */ async query(sql, ...values) { return (await this.queryAll(sql, ...values))[0] ?? null; @@ -163,7 +162,7 @@ export class Database { /** * Escape table/column names * @param {string|string[]} ids - * @return {string} + * @returns {string} */ escapeId(ids) { return this.#connection.escapeId(ids); diff --git a/src/bot/Logger.js b/src/bot/Logger.js index 0b725caaa..24793806a 100644 --- a/src/bot/Logger.js +++ b/src/bot/Logger.js @@ -16,7 +16,7 @@ export class Logger { } /** - * @param {String|Object} message + * @param {string | object} message * @param {Error} [error] * @returns {Promise} */ @@ -25,7 +25,7 @@ export class Logger { } /** - * @param {String|Object} message + * @param {string | object} message * @param {Error} [error] * @returns {Promise} */ @@ -34,7 +34,7 @@ export class Logger { } /** - * @param {String|Object} message + * @param {string | object} message * @param {Error} [error] * @returns {Promise} */ @@ -43,7 +43,7 @@ export class Logger { } /** - * @param {String|Object} message + * @param {string | object} message * @param {Error} [error] * @returns {Promise} */ @@ -52,7 +52,7 @@ export class Logger { } /** - * @param {String|Object} message + * @param {string | object} message * @param {Error} [error] * @returns {Promise} */ @@ -61,7 +61,7 @@ export class Logger { } /** - * @param {String|Object} message + * @param {string | object} message * @param {Error} [error] * @returns {Promise} */ @@ -69,10 +69,15 @@ export class Logger { return this.#logMessage('CRITICAL', console.error, message, error); } + /** + * @callback logFunction + * @param {string | object} message + */ + /** * @param {string} severity - * @param {function(string|object)} logFunction - * @param {String|Object} message + * @param {logFunction} logFunction + * @param {string | object} message * @param {Error} [error] * @returns {Promise} */ diff --git a/src/bot/Request.js b/src/bot/Request.js index 1e66a0e69..d1a1dfe38 100644 --- a/src/bot/Request.js +++ b/src/bot/Request.js @@ -6,13 +6,13 @@ export default class Request { request; /** - * @type {String} + * @type {string} */ response; /** * parsed JSON response - * @type {Object} + * @type {object} */ JSON; @@ -23,7 +23,7 @@ export default class Request { /** * get raw data - * @return {Promise} + * @returns {Promise} */ async get() { this.request = await got.get(this.url, this.options); @@ -33,7 +33,7 @@ export default class Request { /** * get JSON data and parse it - * @return {Promise} + * @returns {Promise} */ async getJSON() { await this.get(); @@ -41,14 +41,14 @@ export default class Request { this.JSON = JSON.parse(this.response); } catch (e) { - throw new Error(`Failed to parse JSON response of ${this.url}`); + throw new Error(`Failed to parse JSON response of ${this.url}`, e); } return this; } /** * request this url and return a sha256 hash of the raw body - * @return {Promise} + * @returns {Promise} */ async getHash() { const response = await got.get(this.url, this.options); diff --git a/src/commands/Command.js b/src/commands/Command.js index 429753c7d..803c6ad5b 100644 --- a/src/commands/Command.js +++ b/src/commands/Command.js @@ -19,7 +19,7 @@ export default class Command extends ExecutableCommand { * * For slash commands this is not checked by ModBot and is only used to register commands on Discord * For context menus, buttons and other interactions ModBot emulate Discord's permission system - * @return {?import('discord.js').PermissionsBitField} + * @returns {?import('discord.js').PermissionsBitField} */ getDefaultMemberPermissions() { return null; @@ -28,7 +28,7 @@ export default class Command extends ExecutableCommand { /** * add options to slash command builder * @param {import('discord.js').SlashCommandBuilder} builder - * @return {import('discord.js').SlashCommandBuilder} + * @returns {import('discord.js').SlashCommandBuilder} */ buildOptions(builder) { return super.buildOptions(builder); @@ -36,7 +36,7 @@ export default class Command extends ExecutableCommand { /** * build this slash command - * @return {SlashCommandBuilder} + * @returns {SlashCommandBuilder} */ buildSlashCommand() { const builder = new SlashCommandBuilder() @@ -51,7 +51,7 @@ export default class Command extends ExecutableCommand { /** * does this command support user context menus - * @return {boolean} + * @returns {boolean} */ supportsUserCommands() { return false; @@ -59,7 +59,7 @@ export default class Command extends ExecutableCommand { /** * build user context menu - * @return {ContextMenuCommandBuilder} + * @returns {ContextMenuCommandBuilder} */ buildUserCommand() { return new ContextMenuCommandBuilder() @@ -72,7 +72,7 @@ export default class Command extends ExecutableCommand { /** * execute a user context menu * @param {import('discord.js').UserContextMenuCommandInteraction} interaction - * @return {Promise} + * @returns {Promise} */ async executeUserMenu(interaction) { @@ -80,7 +80,7 @@ export default class Command extends ExecutableCommand { /** * does this command support message context menus - * @return {boolean} + * @returns {boolean} */ supportsMessageCommands() { return false; @@ -88,7 +88,7 @@ export default class Command extends ExecutableCommand { /** * build message context menu - * @return {ContextMenuCommandBuilder} + * @returns {ContextMenuCommandBuilder} */ buildMessageCommand() { return new ContextMenuCommandBuilder() @@ -101,7 +101,7 @@ export default class Command extends ExecutableCommand { /** * execute a message context menu * @param {import('discord.js').MessageContextMenuCommandInteraction} interaction - * @return {Promise} + * @returns {Promise} */ async executeMessageMenu(interaction) { @@ -110,7 +110,7 @@ export default class Command extends ExecutableCommand { /** * is this command available in all guilds? * if not this command will manually be registered in all guilds where - * @return {boolean} + * @returns {boolean} */ isAvailableInAllGuilds() { return true; @@ -119,7 +119,7 @@ export default class Command extends ExecutableCommand { /** * is this command available in this guild? * @param {import('discord.js').Guild} guild - * @return {Promise} + * @returns {Promise} */ async isAvailableIn(guild) { return false; diff --git a/src/commands/CommandManager.js b/src/commands/CommandManager.js index 7ae775040..2a68ce2b7 100644 --- a/src/commands/CommandManager.js +++ b/src/commands/CommandManager.js @@ -42,6 +42,11 @@ import logger from '../bot/Logger.js'; import SafeSearchCommand from './settings/SafeSearchCommand.js'; import SlashCommandPermissionManagers from '../discord/permissions/SlashCommandPermissionManagers.js'; +/** + * @import Command from './Command.js'; + * @import ExecutableCommand from './ExecutableCommand.js'; + */ + const cooldowns = new Cache(); export class CommandManager { @@ -91,7 +96,7 @@ export class CommandManager { ]; /** - * @return {Command[]} + * @returns {Command[]} */ getCommands() { return this.#commands; @@ -99,7 +104,7 @@ export class CommandManager { /** * register all slash commands - * @return {Promise} + * @returns {Promise} */ async register() { const globalCommands = this.#commands.filter(command => command.isAvailableInAllGuilds()); @@ -133,7 +138,7 @@ export class CommandManager { /** * * @param {Command[]} commands - * @return {import('discord.js').ApplicationCommandDataResolvable[]} + * @returns {import('discord.js').ApplicationCommandDataResolvable[]} */ buildCommands(commands) { const result = []; @@ -152,7 +157,7 @@ export class CommandManager { /** * find a command with this name * @param {string} name - * @return {Command} + * @returns {Command} */ findCommand(name) { return this.getCommands().find(c => c.getName() === name.toLowerCase()) ?? null; @@ -162,7 +167,7 @@ export class CommandManager { * check if this command can be executed in this context * @param {?ExecutableCommand} command * @param {import('discord.js').Interaction} interaction - * @return {Promise} is command executable + * @returns {Promise} is command executable */ async checkCommandAvailability(command, interaction) { if (!command) { @@ -199,7 +204,7 @@ export class CommandManager { /** * @param {import('discord.js').Interaction} interaction * @param {Error|import('discord.js').DiscordAPIError} error - * @return {Promise} + * @returns {Promise} */ async handleCommandError(interaction, error) { const name = [ @@ -219,7 +224,7 @@ export class CommandManager { /** * @param {import('discord.js').ChatInputCommandInteraction} interaction - * @return {Promise} + * @returns {Promise} */ async execute(interaction) { const command = this.findCommand(interaction.commandName); @@ -237,7 +242,7 @@ export class CommandManager { /** * @param {import('discord.js').AutocompleteInteraction} interaction - * @return {Promise} + * @returns {Promise} */ async autocomplete(interaction) { const command = this.findCommand(interaction.commandName); @@ -262,7 +267,7 @@ export class CommandManager { /** * @param {import('discord.js').UserContextMenuCommandInteraction} interaction - * @return {Promise} + * @returns {Promise} */ async executeUserMenu(interaction) { const command = this.findCommand(interaction.commandName); @@ -280,7 +285,7 @@ export class CommandManager { /** * @param {import('discord.js').MessageContextMenuCommandInteraction} interaction - * @return {Promise} + * @returns {Promise} */ async executeMessageMenu(interaction) { const command = this.findCommand(interaction.commandName); @@ -298,7 +303,7 @@ export class CommandManager { /** * @param {import('discord.js').ButtonInteraction} interaction - * @return {Promise} + * @returns {Promise} */ async executeButton(interaction) { if (!interaction.customId) { @@ -324,7 +329,7 @@ export class CommandManager { /** * @param {import('discord.js').ModalSubmitInteraction} interaction - * @return {Promise} + * @returns {Promise} */ async executeModal(interaction) { const command = this.findCommandByCustomId(interaction.customId); @@ -346,7 +351,7 @@ export class CommandManager { /** * @param {import('discord.js').AnySelectMenuInteraction} interaction - * @return {Promise} + * @returns {Promise} */ async executeSelectMenu(interaction) { const command = this.findCommandByCustomId(interaction.customId); @@ -368,7 +373,7 @@ export class CommandManager { /** * @param {?string} id - * @return {?Command} + * @returns {?Command} */ findCommandByCustomId(id) { if (!id) { @@ -381,7 +386,7 @@ export class CommandManager { /** * @param {import('discord.js').Interaction} interaction * @param {Command} command - * @return {Promise} + * @returns {Promise} */ async checkMemberPermissions(interaction, command) { const permission = await this.hasPermission(interaction, command); @@ -394,7 +399,7 @@ export class CommandManager { /** * @param {import('discord.js').Interaction} interaction * @param {Command} command - * @return {Promise} + * @returns {Promise} */ async hasPermission(interaction, command) { return SlashCommandPermissionManagers diff --git a/src/commands/ExecutableCommand.js b/src/commands/ExecutableCommand.js index 31df1c220..96cc2f6f2 100644 --- a/src/commands/ExecutableCommand.js +++ b/src/commands/ExecutableCommand.js @@ -4,7 +4,7 @@ export default class ExecutableCommand { /** * @abstract - * @return {string} + * @returns {string} */ getName() { return 'unknown'; @@ -12,7 +12,7 @@ export default class ExecutableCommand { /** * @abstract - * @return {string} + * @returns {string} */ getDescription() { return 'unknown'; @@ -20,7 +20,7 @@ export default class ExecutableCommand { /** * get command cool down in seconds - * @return {number} + * @returns {number} */ getCoolDown() { return 0; @@ -28,14 +28,14 @@ export default class ExecutableCommand { /** * is this command available in direct messages - * @return {boolean} + * @returns {boolean} */ isAvailableInDMs() { return false; } /** - * @return {import('discord.js').PermissionsBitField} + * @returns {import('discord.js').PermissionsBitField} */ getRequiredBotPermissions() { return new PermissionsBitField(); @@ -47,7 +47,7 @@ export default class ExecutableCommand { /** * @param {import('discord.js').AutocompleteInteraction} interaction - * @return {Promise} + * @returns {Promise} */ async complete(interaction) { return []; @@ -57,7 +57,7 @@ export default class ExecutableCommand { * execute a slash command * @abstract * @param {import('discord.js').ChatInputCommandInteraction} interaction - * @return {Promise} + * @returns {Promise} */ async execute(interaction) { @@ -66,7 +66,7 @@ export default class ExecutableCommand { /** * handle a button press * @param {import('discord.js').ButtonInteraction} interaction - * @return {Promise} + * @returns {Promise} */ async executeButton(interaction) { @@ -75,7 +75,7 @@ export default class ExecutableCommand { /** * handle data submitted from a modal * @param {import('discord.js').ModalSubmitInteraction} interaction - * @return {Promise} + * @returns {Promise} */ async executeModal(interaction) { @@ -84,7 +84,7 @@ export default class ExecutableCommand { /** * handle data submitted from a modal * @param {import('discord.js').AnySelectMenuInteraction} interaction - * @return {Promise} + * @returns {Promise} */ async executeSelectMenu(interaction) { diff --git a/src/commands/ParentCommand.js b/src/commands/ParentCommand.js index ec297975b..01cc49729 100644 --- a/src/commands/ParentCommand.js +++ b/src/commands/ParentCommand.js @@ -10,7 +10,7 @@ import commandManager from './CommandManager.js'; export default class ParentCommand extends Command { /** * @abstract - * @return {(SubCommand|SubCommandGroup)[]} + * @returns {(SubCommand|SubCommandGroup)[]} */ getChildren() { return []; @@ -18,7 +18,7 @@ export default class ParentCommand extends Command { /** * build this slash command - * @return {SlashCommandBuilder} + * @returns {SlashCommandBuilder} */ buildSlashCommand() { const builder = new SlashCommandBuilder() @@ -42,7 +42,7 @@ export default class ParentCommand extends Command { * find a child by the custom id of the moderation * must use syntax 'command:subcommand:other-data' * @param {import('discord.js').Interaction} interaction - * @return {SubCommand|SubCommandGroup|null} + * @returns {SubCommand|SubCommandGroup|null} */ #findChildByCustomId(interaction) { const name = interaction.customId.split(':')[1]; @@ -53,7 +53,7 @@ export default class ParentCommand extends Command { /** * find a child by the sub command name * @param {import('discord.js').Interaction} interaction - * @return {SubCommand|SubCommandGroup|null} + * @returns {SubCommand|SubCommandGroup|null} */ #findChildByName(interaction) { const name = interaction.options.getSubcommandGroup() diff --git a/src/commands/SubCommand.js b/src/commands/SubCommand.js index 8bdedb153..cd492eb46 100644 --- a/src/commands/SubCommand.js +++ b/src/commands/SubCommand.js @@ -7,7 +7,7 @@ export default class SubCommand extends ExecutableCommand { /** * add options to slash command builder * @param {import('discord.js').SlashCommandSubcommandBuilder} builder - * @return {import('discord.js').SlashCommandSubcommandBuilder} + * @returns {import('discord.js').SlashCommandSubcommandBuilder} */ buildOptions(builder) { return super.buildOptions(builder); @@ -15,7 +15,7 @@ export default class SubCommand extends ExecutableCommand { /** * @param {import('discord.js').SlashCommandSubcommandBuilder} builder - * @return {import('discord.js').SlashCommandSubcommandBuilder} + * @returns {import('discord.js').SlashCommandSubcommandBuilder} */ buildSubCommand(builder) { builder.setName(this.getName()); diff --git a/src/commands/SubCommandGroup.js b/src/commands/SubCommandGroup.js index a79ddafc8..65910b443 100644 --- a/src/commands/SubCommandGroup.js +++ b/src/commands/SubCommandGroup.js @@ -1,11 +1,15 @@ import ExecutableCommand from './ExecutableCommand.js'; import commandManager from './CommandManager.js'; +/** + * @import SubCommand from './SubCommand.js'; + */ + export default class SubCommandGroup extends ExecutableCommand { /** * @abstract - * @return {string} + * @returns {string} */ getName() { return 'unknown'; @@ -13,7 +17,7 @@ export default class SubCommandGroup extends ExecutableCommand { /** * @abstract - * @return {string} + * @returns {string} */ getDescription() { return 'unknown'; @@ -21,7 +25,7 @@ export default class SubCommandGroup extends ExecutableCommand { /** * @abstract - * @return {SubCommand[]} + * @returns {SubCommand[]} */ getChildren() { return []; @@ -29,7 +33,7 @@ export default class SubCommandGroup extends ExecutableCommand { /** * @param {import('discord.js').SlashCommandSubcommandGroupBuilder} builder - * @return {import('discord.js').SlashCommandSubcommandGroupBuilder} + * @returns {import('discord.js').SlashCommandSubcommandGroupBuilder} */ buildSubCommandGroup(builder) { builder.setName(this.getName()); @@ -45,7 +49,7 @@ export default class SubCommandGroup extends ExecutableCommand { /** * find a child by the sub command name * @param {import('discord.js').Interaction} interaction - * @return {SubCommand|null} + * @returns {SubCommand|null} */ #findChildByName(interaction) { const name = interaction.options.getSubcommand(); @@ -56,7 +60,7 @@ export default class SubCommandGroup extends ExecutableCommand { * find a child by the custom id of the moderation * must use syntax 'command:subcommand:other-data' * @param {import('discord.js').Interaction} interaction - * @return {Promise} + * @returns {Promise} */ async #findChildByCustomId(interaction) { const name = interaction.customId.split(':')[2]; diff --git a/src/commands/bot/ImportCommand.js b/src/commands/bot/ImportCommand.js index 35bec88b8..e26ec56aa 100644 --- a/src/commands/bot/ImportCommand.js +++ b/src/commands/bot/ImportCommand.js @@ -6,6 +6,10 @@ import {gunzip as gunzipCb} from 'zlib'; import VortexImporter from '../../database/export/VortexImporter.js'; import ModBotImporter from '../../database/export/ModBotImporter.js'; +/** + * @import Importer from '../../database/export/Importer.js'; + */ + const gunzip = promisify(gunzipCb); export default class ImportCommand extends Command { @@ -39,7 +43,7 @@ export default class ImportCommand extends Command { try { data = await gunzip(data.buffer); } - catch (e) { + catch { await interaction.editReply('Failed to decompress gzip data. Make sure the file you\'re trying to upload is valid gzip.'); return; } @@ -54,7 +58,7 @@ export default class ImportCommand extends Command { try { data = JSON.parse(data.toString()); } - catch (e) { + catch { await interaction.editReply('Failed to parse JSON data. Make sure the file you\'re trying to upload is valid JSON.'); return; } @@ -87,9 +91,9 @@ export default class ImportCommand extends Command { /** * get the correct importer for this datatype - * @param {Object} data + * @param {object} data * @param {import('discord.js').Interaction} interaction - * @return {Importer|null} + * @returns {Importer|null} */ getImporter(data, interaction) { if (!data.dataType) diff --git a/src/commands/bot/InfoCommand.js b/src/commands/bot/InfoCommand.js index 52a759b90..8d8780129 100644 --- a/src/commands/bot/InfoCommand.js +++ b/src/commands/bot/InfoCommand.js @@ -33,6 +33,9 @@ export const PERMISSIONS = new PermissionsBitField() export const INVITE_LINK = `https://discord.com/oauth2/authorize?client_id=${CLIENT_ID}&scope=${SCOPES.join('%20')}&permissions=${PERMISSIONS.bitfield}`; export const VERSION = await getPackageVersion(); +/** + * @returns {Promise} + */ async function getPackageVersion() { try { const pkgJson = JSON.parse((await readFile('package.json')).toString()); @@ -44,9 +47,13 @@ async function getPackageVersion() { } export const COMMIT = await getGitCommit(); + +/** + * @returns {Promise} + */ async function getGitCommit() { if (process.env.MODBOT_COMMIT_HASH) { - return process.env.MODBOT_COMMIT_HASH; + return /** @type {string} */ process.env.MODBOT_COMMIT_HASH; } try { diff --git a/src/commands/external/ArticleCommand.js b/src/commands/external/ArticleCommand.js index fedc9b3d7..05d80f08a 100644 --- a/src/commands/external/ArticleCommand.js +++ b/src/commands/external/ArticleCommand.js @@ -18,6 +18,11 @@ import {SELECT_MENU_OPTIONS_LIMIT, SELECT_MENU_TITLE_LIMIT} from '../../util/api import Cache from '../../bot/Cache.js'; import ErrorEmbed from '../../embeds/ErrorEmbed.js'; +/** + * @import {ZendeskArticle} from '../../apis/Zendesk.js'; + */ + + const completions = new Cache(); const CACHE_DURATION = 60 * 60 * 1000; const ARTICLE_EMBED_PREVIEW_LENGTH = 1000; @@ -125,7 +130,7 @@ export default class ArticleCommand extends Command { * @param {import('discord.js').Snowflake} userId id of the user that executed the command * @param {number} [index] * @param {?import('discord.js').Snowflake} mention user to mention in the message - * @return {{embeds: EmbedBuilder[], components: ActionRowBuilder[], fetchReply: boolean, content: ?string}} + * @returns {{embeds: EmbedBuilder[], components: ActionRowBuilder[], fetchReply: boolean, content: ?string}} */ generateMessage(results, article, userId, index = 0, mention = null) { for (const result of results) { @@ -159,7 +164,7 @@ export default class ArticleCommand extends Command { * get a description from the HTML body of an article * @param {import('discord.js').APISelectMenuOption} result * @param {string} body website body - * @return {EmbedBuilder} + * @returns {EmbedBuilder} */ createEmbed(result, body) { const embed = new EmbedBuilder() diff --git a/src/commands/external/VideoCommand.js b/src/commands/external/VideoCommand.js index 6fba720a2..b2f8e220e 100644 --- a/src/commands/external/VideoCommand.js +++ b/src/commands/external/VideoCommand.js @@ -92,7 +92,7 @@ export default class VideoCommand extends Command { * @param {import('discord.js').Snowflake} userId id of the user that executed this command * @param {number} [index] * @param {?import('discord.js').Snowflake} mention user to mention in the message - * @return {{content: string, components: ActionRowBuilder[], fetchReply: boolean}} + * @returns {{content: string, components: ActionRowBuilder[], fetchReply: boolean}} */ generateMessage(videos, userId, index = 0, mention = null) { for (const result of videos) { diff --git a/src/commands/guild/IDCommand.js b/src/commands/guild/IDCommand.js index fc6540f20..ad4d3c2e8 100644 --- a/src/commands/guild/IDCommand.js +++ b/src/commands/guild/IDCommand.js @@ -5,6 +5,11 @@ import colors from '../../util/colors.js'; import {FETCH_BAN_PAGE_SIZE} from '../../util/apiLimits.js'; import ErrorEmbed from '../../embeds/ErrorEmbed.js'; +/** + * @import {User} from 'discord.js'; + * @import EmbedWrapper from '../../embeds/EmbedWrapper.js'; + */ + export default class IDCommand extends Command { getDefaultMemberPermissions() { @@ -40,7 +45,7 @@ export default class IDCommand extends Command { const bans = await this.#fetchAndFilterBans(interaction, query.toLowerCase()); if (!bans.size && !users.size) { - return await interaction.editReply(ErrorEmbed.message('No users found')); + return void await interaction.editReply(ErrorEmbed.message('No users found')); } await interaction.editReply(this.#generateResultEmbed(query, Array.from(users.concat(bans).values()))); @@ -48,10 +53,10 @@ export default class IDCommand extends Command { /** * generate an embed of results - * @param {String} query + * @param {string} query * @param {(import('discord.js').GuildMember|import('discord.js').GuildBan)[]} results * @param {boolean} [stillSearching] - * @return {{embeds: EmbedWrapper[]}} + * @returns {{embeds: EmbedWrapper[]}} */ #generateResultEmbed(query, results, stillSearching = false) { const embed = new LineEmbed() @@ -74,7 +79,7 @@ export default class IDCommand extends Command { /** * @param {import('discord.js').Interaction} interaction * @param {string} user - * @return {Promise>} + * @returns {Promise>} */ async #fetchAndFilterBans(interaction, user) { return (await this.#fetchAllBans(interaction)) @@ -84,7 +89,7 @@ export default class IDCommand extends Command { /** * fetch all bans * @param {import('discord.js').Interaction} interaction - * @return {Promise>} + * @returns {Promise>} */ async #fetchAllBans(interaction) { let bans = new Collection(); diff --git a/src/commands/guild/PurgeCommand.js b/src/commands/guild/PurgeCommand.js index f1c9388fc..d9b32b713 100644 --- a/src/commands/guild/PurgeCommand.js +++ b/src/commands/guild/PurgeCommand.js @@ -8,6 +8,11 @@ import {PurgeUserFilter} from '../../purge/PurgeUserFilter.js'; import PurgeRegexFilter from '../../purge/PurgeRegexFilter.js'; import PurgeAgeFilter from '../../purge/PurgeAgeFilter.js'; +/** + * @import PurgeFilter from '../../purge/PurgeFilter.js'; + * @import {Message} from 'discord.js'; + */ + const REGEX_REGEX = /^\/(.*)\/([gimsuy]*)$/; export default class PurgeCommand extends Command { @@ -104,24 +109,6 @@ export default class PurgeCommand extends Command { }); } - /** - * check if any contents of the message trigger this function - * @param {Message} message - * @param {(string) => boolean} fn - * @return {boolean} - */ - matches(message, fn) { - const contents = []; - contents.push(message.content); - for (const embed of message.embeds) { - contents.push(embed.description, embed.title, embed.footer?.text, embed.author?.name); - for (const field of embed.fields) { - contents.push(field.name, field.value); - } - } - return contents.filter(s => !!s).some(fn); - } - getDescription() { return 'Bulk delete messages matching a filter'; } diff --git a/src/commands/moderation/ModerationClearCommand.js b/src/commands/moderation/ModerationClearCommand.js index 21bf78fbf..3e689dd58 100644 --- a/src/commands/moderation/ModerationClearCommand.js +++ b/src/commands/moderation/ModerationClearCommand.js @@ -49,7 +49,7 @@ export default class ModerationClearCommand extends SubCommand { return; } - /** @property {Number} affectedRows */ + /** @property {number} affectedRows */ const deletion = await database.queryAll('DELETE FROM moderations WHERE guildid = ? AND userid = ?', interaction.guildId, member.user.id); await interaction.update({ diff --git a/src/commands/moderation/ModerationListCommand.js b/src/commands/moderation/ModerationListCommand.js index 80796d743..8186fe14b 100644 --- a/src/commands/moderation/ModerationListCommand.js +++ b/src/commands/moderation/ModerationListCommand.js @@ -8,6 +8,10 @@ import config from '../../bot/Config.js'; import icons from '../../util/icons.js'; import MemberWrapper from '../../discord/MemberWrapper.js'; +/** + * @import EmbedWrapper from '../../embeds/EmbedWrapper.js'; + */ + /** * number of moderations that will be displayed on a single page * keep embed length limitations in mind when changing this number! @@ -59,7 +63,7 @@ export default class ModerationListCommand extends SubCommand { * @param {MemberWrapper} member * @param {Moderation[]} moderations * @param {number} page - * @return {Promise<{ephemeral: boolean, embeds: EmbedWrapper[]}>} + * @returns {Promise<{ephemeral: boolean, embeds: EmbedWrapper[]}>} */ async generateMessage(member, moderations, page = 1) { const lastPage = Math.ceil(moderations.length / MODERATIONS_PER_PAGE); diff --git a/src/commands/settings/AbstractChannelCommand.js b/src/commands/settings/AbstractChannelCommand.js index 70b40d546..5e94daf22 100644 --- a/src/commands/settings/AbstractChannelCommand.js +++ b/src/commands/settings/AbstractChannelCommand.js @@ -9,7 +9,7 @@ import ErrorEmbed from '../../embeds/ErrorEmbed.js'; export default class AbstractChannelCommand extends SubCommand { /** * @param {import('discord.js').Interaction} interaction - * @return {Promise} + * @returns {Promise} */ async getChannel(interaction) { const channelId = interaction.options.getChannel('channel')?.id; diff --git a/src/commands/settings/AttachmentCoolDownCommand.js b/src/commands/settings/AttachmentCoolDownCommand.js index 8182883c7..bfa4b96ee 100644 --- a/src/commands/settings/AttachmentCoolDownCommand.js +++ b/src/commands/settings/AttachmentCoolDownCommand.js @@ -3,7 +3,6 @@ import {formatTime, parseTime} from '../../util/timeutils.js'; import GuildSettings from '../../settings/GuildSettings.js'; import EmbedWrapper from '../../embeds/EmbedWrapper.js'; import colors from '../../util/colors.js'; -import ErrorEmbed from '../../embeds/ErrorEmbed.js'; export default class AttachmentCoolDownCommand extends SubCommand { diff --git a/src/commands/settings/CapsCommand.js b/src/commands/settings/CapsCommand.js index d118ad6b6..b0b4f4722 100644 --- a/src/commands/settings/CapsCommand.js +++ b/src/commands/settings/CapsCommand.js @@ -27,7 +27,7 @@ export default class CapsCommand extends SubCommand { * * @param {import('discord.js').Interaction} interaction * @param {boolean} enabled - * @return {Promise<{components: ActionRowBuilder[], embeds: EmbedWrapper[]}>} + * @returns {Promise<{components: ActionRowBuilder[], embeds: EmbedWrapper[]}>} */ async change(interaction, enabled) { const guildSettings = await GuildSettings.get(interaction.guild.id); diff --git a/src/commands/settings/HelpCenterCommand.js b/src/commands/settings/HelpCenterCommand.js index 8930aa0cf..4b06b697c 100644 --- a/src/commands/settings/HelpCenterCommand.js +++ b/src/commands/settings/HelpCenterCommand.js @@ -70,7 +70,7 @@ export default class HelpCenterCommand extends SubCommand { /** * @param {string} domain - * @return {?string} + * @returns {?string} */ findDomain(domain) { const match = domain.match(/^(?:https?:\/\/)?([\w.]+)(?:[/?].*)?$/i); @@ -84,7 +84,7 @@ export default class HelpCenterCommand extends SubCommand { /** * resolve the zendesk help center name * @param {string} domain - * @return {Promise} + * @returns {Promise} */ async findHelpCenterName(domain) { if (domain.includes('.') && !ZENDESK_REGEX.test(domain)) { @@ -106,14 +106,14 @@ export default class HelpCenterCommand extends SubCommand { /** * find a CNAME record pointing to a zendesk help center * @param {string} domain - * @return {Promise} + * @returns {Promise} */ async resolveCNAME(domain) { try { const result = await resolveCname(domain); return result.find(entry => entry.endsWith('.zendesk.com')) ?? null; } - catch (e) { + catch { return null; } } diff --git a/src/commands/settings/PlaylistCommand.js b/src/commands/settings/PlaylistCommand.js index abb5b515e..83a0e4b22 100644 --- a/src/commands/settings/PlaylistCommand.js +++ b/src/commands/settings/PlaylistCommand.js @@ -67,7 +67,7 @@ export default class PlaylistCommand extends SubCommand { /** * @param {string} url - * @return {?string} + * @returns {?string} */ getPlaylistId(url) { const match = url.match(PLAYLIST_REGEX); diff --git a/src/commands/settings/SettingsOverviewCommand.js b/src/commands/settings/SettingsOverviewCommand.js index 17a11fcb8..560b91127 100644 --- a/src/commands/settings/SettingsOverviewCommand.js +++ b/src/commands/settings/SettingsOverviewCommand.js @@ -5,6 +5,10 @@ import {componentEmojiIfExists} from '../../util/format.js'; import icons from '../../util/icons.js'; import BetterButtonBuilder from '../../embeds/BetterButtonBuilder.js'; +/** + * @import {ButtonBuilder} from 'discord.js'; + */ + export default class SettingsOverviewCommand extends SubCommand { async execute(interaction) { @@ -18,7 +22,7 @@ export default class SettingsOverviewCommand extends SubCommand { /** * * @param {import('discord.js').Interaction} interaction - * @return {Promise<{components: ActionRowBuilder[], ephemeral: boolean, embeds: import('discord.js').EmbedBuilder[]}>} + * @returns {Promise<{components: ActionRowBuilder[], ephemeral: boolean, embeds: import('discord.js').EmbedBuilder[]}>} */ async buildMessage(interaction) { const guildSettings = await GuildSettings.get(interaction.guildId); diff --git a/src/commands/settings/auto-response/AddAutoResponseCommand.js b/src/commands/settings/auto-response/AddAutoResponseCommand.js index d936c1ffc..e8575154c 100644 --- a/src/commands/settings/auto-response/AddAutoResponseCommand.js +++ b/src/commands/settings/auto-response/AddAutoResponseCommand.js @@ -178,7 +178,7 @@ export default class AddAutoResponseCommand extends SubCommand { * @param {string} trigger * @param {string} response * @param {?boolean} enableVision - * @return {Promise<*>} + * @returns {Promise<*>} */ async create( interaction, diff --git a/src/commands/settings/auto-response/EditAutoResponseCommand.js b/src/commands/settings/auto-response/EditAutoResponseCommand.js index 9452d9b56..2016808e5 100644 --- a/src/commands/settings/auto-response/EditAutoResponseCommand.js +++ b/src/commands/settings/auto-response/EditAutoResponseCommand.js @@ -98,7 +98,7 @@ export default class EditAutoResponseCommand extends CompletingAutoResponseComma * @param {?boolean} global * @param {?string} type * @param {?boolean} vision - * @return {Promise} + * @returns {Promise} */ async showModal(interaction, autoResponse, global, type, vision) { global ??= autoResponse.global; @@ -240,7 +240,7 @@ export default class EditAutoResponseCommand extends CompletingAutoResponseComma * @param {string} trigger * @param {string} response * @param {?boolean} vision - * @return {Promise<*>} + * @returns {Promise<*>} */ async update( interaction, diff --git a/src/commands/settings/bad-word/AddBadWordCommand.js b/src/commands/settings/bad-word/AddBadWordCommand.js index b460113d7..fa506ac78 100644 --- a/src/commands/settings/bad-word/AddBadWordCommand.js +++ b/src/commands/settings/bad-word/AddBadWordCommand.js @@ -245,7 +245,7 @@ export default class AddBadWordCommand extends AddAutoResponseCommand { * @param {?number} priority * @param {?string} dm * @param {?boolean} enableVision - * @return {Promise<*>} + * @returns {Promise<*>} */ async create( interaction, diff --git a/src/commands/settings/bad-word/EditBadWordCommand.js b/src/commands/settings/bad-word/EditBadWordCommand.js index 80cc5ee08..9007e1afa 100644 --- a/src/commands/settings/bad-word/EditBadWordCommand.js +++ b/src/commands/settings/bad-word/EditBadWordCommand.js @@ -16,6 +16,10 @@ import Punishment from '../../../database/Punishment.js'; import {SELECT_MENU_OPTIONS_LIMIT} from '../../../util/apiLimits.js'; import config from '../../../bot/Config.js'; +/** + * @import {PunishmentAction} from '../../../database/Punishment.js'; + */ + export default class EditBadWordCommand extends CompletingBadWordCommand { buildOptions(builder) { @@ -125,7 +129,7 @@ export default class EditBadWordCommand extends CompletingBadWordCommand { * @param {?string} type * @param {?string} punishment * @param {?boolean} vision - * @return {Promise} + * @returns {Promise} */ async showModal( interaction, @@ -349,7 +353,7 @@ export default class EditBadWordCommand extends CompletingBadWordCommand { * @param {number} priority * @param {?string} dm * @param {?boolean} vision - * @return {Promise<*>} + * @returns {Promise<*>} */ async update( interaction, diff --git a/src/commands/settings/invites/ShowInvitesCommand.js b/src/commands/settings/invites/ShowInvitesCommand.js index f16c5129b..e3a14b27c 100644 --- a/src/commands/settings/invites/ShowInvitesCommand.js +++ b/src/commands/settings/invites/ShowInvitesCommand.js @@ -5,10 +5,20 @@ import {channelMention} from 'discord.js'; import colors from '../../../util/colors.js'; import ChannelSettings from '../../../settings/ChannelSettings.js'; +/** + * Get the string representation of the allowed status + * @param {boolean} boolean + * @returns {string} + */ function allowed(boolean) { return boolean ? 'allowed' : 'forbidden'; } +/** + * Get the color representation of the allowed status + * @param {boolean} boolean + * @returns {number} + */ function color(boolean) { return boolean ? colors.GREEN : colors.RED; } @@ -17,7 +27,7 @@ function color(boolean) { * generate an invite embed * @param {import('discord.js').Snowflake} guildId * @param {?import('discord.js').Channel} channel - * @return {Promise<{ephemeral: boolean, embeds: EmbedWrapper[]}>} + * @returns {Promise<{ephemeral: boolean, embeds: EmbedWrapper[]}>} */ export async function getEmbed(guildId, channel = null) { const embed = new EmbedWrapper(), diff --git a/src/commands/settings/muted-role/AbstractMutedRoleCommand.js b/src/commands/settings/muted-role/AbstractMutedRoleCommand.js index 86c0e6df1..473a595dc 100644 --- a/src/commands/settings/muted-role/AbstractMutedRoleCommand.js +++ b/src/commands/settings/muted-role/AbstractMutedRoleCommand.js @@ -30,7 +30,7 @@ export default class AbstractMutedRoleCommand extends SubCommand { /** * @param {import('discord.js').ChatInputCommandInteraction} interaction * @param {import('discord.js').Role} role - * @return {Promise} + * @returns {Promise} */ async setMutedRole(interaction, role) { if (!role.editable) { @@ -57,7 +57,7 @@ export default class AbstractMutedRoleCommand extends SubCommand { /** * @param {import('discord.js').Interaction} interaction * @param {import('discord.js').Role} role - * @return {Promise} + * @returns {Promise} */ async updatePermissionOverrides(interaction, role) { await interaction.reply({ @@ -81,7 +81,7 @@ export default class AbstractMutedRoleCommand extends SubCommand { * @param {GuildSettings} guildSettings * @param {import('discord.js').Interaction} interaction * @param {import('discord.js').Role} role - * @return {Promise} has an error occurred + * @returns {Promise} has an error occurred */ async transferOldMutes(guildSettings, interaction, role) { const guild = new GuildWrapper(interaction.guild); diff --git a/src/commands/user/AvatarCommand.js b/src/commands/user/AvatarCommand.js index 6926d5409..7fce5d31b 100644 --- a/src/commands/user/AvatarCommand.js +++ b/src/commands/user/AvatarCommand.js @@ -52,7 +52,7 @@ export default class AvatarCommand extends Command { * @param {import('discord.js').User} user * @param {import('discord.js').Guild|null} guild * @param {boolean} useServerProfile - * @return {Promise<{ephemeral: boolean, embeds: EmbedBuilder[]}>} + * @returns {Promise<{ephemeral: boolean, embeds: EmbedBuilder[]}>} */ async buildMessage(user, guild, useServerProfile = true) { let url = user.displayAvatarURL(IMAGE_OPTIONS); diff --git a/src/commands/user/BanCommand.js b/src/commands/user/BanCommand.js index e59dfa349..84b29b685 100644 --- a/src/commands/user/BanCommand.js +++ b/src/commands/user/BanCommand.js @@ -17,6 +17,10 @@ import CommentInput from '../../modals/inputs/CommentInput.js'; import DeleteMessageHistoryInput from '../../modals/inputs/DeleteMessageHistoryInput.js'; import DurationInput from '../../modals/inputs/DurationInput.js'; +/** + * @import {DurationConfirmationData} from './UserCommand.js'; + */ + /** * @typedef {DurationConfirmationData} BanConfirmationData * @property {?number} deleteMessageTime @@ -72,7 +76,7 @@ export default class BanCommand extends UserCommand { * @param {?string} comment * @param {?number} duration * @param {?number} deleteMessageTime - * @return {Promise} + * @returns {Promise} */ async ban(interaction, member, reason, comment, duration, deleteMessageTime) { reason = reason || 'No reason provided'; @@ -127,7 +131,7 @@ export default class BanCommand extends UserCommand { * prompt user for ban reason, duration and more * @param {import('discord.js').Interaction} interaction * @param {?MemberWrapper} member - * @return {Promise} + * @returns {Promise} */ async promptForData(interaction, member) { if (!member) { diff --git a/src/commands/user/KickCommand.js b/src/commands/user/KickCommand.js index 9435c2b1f..bd3be0358 100644 --- a/src/commands/user/KickCommand.js +++ b/src/commands/user/KickCommand.js @@ -14,6 +14,10 @@ import {deferReplyOnce, replyOrEdit} from '../../util/interaction.js'; import ReasonInput from '../../modals/inputs/ReasonInput.js'; import CommentInput from '../../modals/inputs/CommentInput.js'; +/** + * @import {ConfirmationData} from './UserCommand.js'; + */ + export default class KickCommand extends UserCommand { getDefaultMemberPermissions() { @@ -44,7 +48,7 @@ export default class KickCommand extends UserCommand { * @param {?MemberWrapper} member * @param {?string} reason * @param {?string} comment - * @return {Promise} + * @returns {Promise} */ async kick(interaction, member, reason, comment) { await deferReplyOnce(interaction); @@ -91,7 +95,7 @@ export default class KickCommand extends UserCommand { /** * @param {import('discord.js').Interaction} interaction * @param {?MemberWrapper} member - * @return {Promise} + * @returns {Promise} */ async promptForData(interaction, member) { if (!member) { diff --git a/src/commands/user/MuteCommand.js b/src/commands/user/MuteCommand.js index dc1530283..873d63a23 100644 --- a/src/commands/user/MuteCommand.js +++ b/src/commands/user/MuteCommand.js @@ -17,6 +17,10 @@ import ReasonInput from '../../modals/inputs/ReasonInput.js'; import CommentInput from '../../modals/inputs/CommentInput.js'; import DurationInput from '../../modals/inputs/DurationInput.js'; +/** + * @import {DurationConfirmationData} from './UserCommand.js'; + */ + export default class MuteCommand extends UserCommand { @@ -61,7 +65,7 @@ export default class MuteCommand extends UserCommand { * @param {?string} reason * @param {?string} comment * @param {?number} duration - * @return {Promise} + * @returns {Promise} */ async mute(interaction, member, reason, comment, duration) { await deferReplyOnce(interaction); @@ -126,7 +130,7 @@ export default class MuteCommand extends UserCommand { * prompt user for mute reason and duration * @param {import('discord.js').Interaction} interaction * @param {?MemberWrapper} member - * @return {Promise} + * @returns {Promise} */ async promptForData(interaction, member) { if (!member) { diff --git a/src/commands/user/PardonCommand.js b/src/commands/user/PardonCommand.js index 2dbc3aecd..0ce86ca8e 100644 --- a/src/commands/user/PardonCommand.js +++ b/src/commands/user/PardonCommand.js @@ -55,7 +55,7 @@ export default class PardonCommand extends UserCommand { * @param {?string} comment * @param {import('discord.js').User} moderator * @param {?number} count - * @return {Promise} + * @returns {Promise} */ async pardon(interaction, member, reason, comment, moderator, count) { await deferReplyOnce(interaction); @@ -89,7 +89,7 @@ export default class PardonCommand extends UserCommand { /** * @param {import('discord.js').Interaction} interaction * @param {?MemberWrapper} member - * @return {Promise} + * @returns {Promise} */ async promptForData(interaction, member) { if (!member) { diff --git a/src/commands/user/SoftBanCommand.js b/src/commands/user/SoftBanCommand.js index 595b68216..dcb3ee471 100644 --- a/src/commands/user/SoftBanCommand.js +++ b/src/commands/user/SoftBanCommand.js @@ -16,6 +16,10 @@ import ReasonInput from '../../modals/inputs/ReasonInput.js'; import CommentInput from '../../modals/inputs/CommentInput.js'; import DeleteMessageHistoryInput from '../../modals/inputs/DeleteMessageHistoryInput.js'; +/** + * @import {ConfirmationData} from './UserCommand.js'; + */ + /** * @typedef {ConfirmationData} SoftBanConfirmationData * @property {?number} deleteMessageTime @@ -59,7 +63,7 @@ export default class SoftBanCommand extends UserCommand { * @param {?string} reason * @param {?string} comment * @param {?number} deleteMessageTime - * @return {Promise} + * @returns {Promise} */ async softBan(interaction, member, reason, comment, deleteMessageTime) { await deferReplyOnce(interaction); @@ -103,7 +107,7 @@ export default class SoftBanCommand extends UserCommand { * prompt user for soft-ban reason and more * @param {import('discord.js').Interaction} interaction * @param {?MemberWrapper} member - * @return {Promise} + * @returns {Promise} */ async promptForData(interaction, member) { if (!member) { diff --git a/src/commands/user/StrikeCommand.js b/src/commands/user/StrikeCommand.js index a3f862dc6..95d71960e 100644 --- a/src/commands/user/StrikeCommand.js +++ b/src/commands/user/StrikeCommand.js @@ -18,6 +18,10 @@ import ReasonInput from '../../modals/inputs/ReasonInput.js'; import CommentInput from '../../modals/inputs/CommentInput.js'; import CountInput from '../../modals/inputs/CountInput.js'; +/** + * @import {ConfirmationData} from './UserCommand.js'; + */ + /** * @typedef {ConfirmationData} StrikeConfirmationData * @property {?number} count @@ -28,7 +32,7 @@ export default class StrikeCommand extends UserCommand { /** * add options to slash command builder * @param {import('discord.js').SlashCommandBuilder} builder - * @return {import('discord.js').SlashCommandBuilder} + * @returns {import('discord.js').SlashCommandBuilder} */ buildOptions(builder) { super.buildOptions(builder); @@ -72,7 +76,7 @@ export default class StrikeCommand extends UserCommand { * @param {?string} reason * @param {?string} comment * @param {?number} count - * @return {Promise} + * @returns {Promise} */ async strike(interaction, member, reason, comment, count) { await deferReplyOnce(interaction); @@ -125,7 +129,7 @@ export default class StrikeCommand extends UserCommand { * prompt user for strike reason and count * @param {import('discord.js').Interaction} interaction * @param {?MemberWrapper} member - * @return {Promise} + * @returns {Promise} */ async promptForData(interaction, member) { if (!member) { diff --git a/src/commands/user/StrikePurgeCommand.js b/src/commands/user/StrikePurgeCommand.js index 73a0611e2..7d08b1e95 100644 --- a/src/commands/user/StrikePurgeCommand.js +++ b/src/commands/user/StrikePurgeCommand.js @@ -16,6 +16,10 @@ import CommentInput from '../../modals/inputs/CommentInput.js'; import CountInput from '../../modals/inputs/CountInput.js'; import TextInput from '../../modals/inputs/TextInput.js'; +/** + * @import {StrikeConfirmationData} from './StrikeCommand.js'; + */ + /** * @typedef {StrikeConfirmationData} StrikePurgeConfirmationData * @property {number} limit @@ -65,7 +69,7 @@ export default class StrikePurgeCommand extends StrikeCommand { * @param {?string} comment * @param {?number} count * @param {?number} limit - * @return {Promise} + * @returns {Promise} */ async strikePurge(interaction, member, reason, comment, count, limit) { await deferReplyOnce(interaction); @@ -132,7 +136,7 @@ export default class StrikePurgeCommand extends StrikeCommand { * prompt user for strike reason, count and message test limit * @param {import('discord.js').Interaction} interaction * @param {?MemberWrapper} member - * @return {Promise} + * @returns {Promise} */ async promptForData(interaction, member) { if (!member) { diff --git a/src/commands/user/UnbanCommand.js b/src/commands/user/UnbanCommand.js index 445c2f22e..ca71f445a 100644 --- a/src/commands/user/UnbanCommand.js +++ b/src/commands/user/UnbanCommand.js @@ -39,7 +39,7 @@ export default class UnbanCommand extends UserCommand { * @param {?string} reason * @param {?string} comment * @param {import('discord.js').User} moderator - * @return {Promise} + * @returns {Promise} */ async unban(interaction, member, reason, comment, moderator) { if (!member) { @@ -67,7 +67,7 @@ export default class UnbanCommand extends UserCommand { /** * @param {import('discord.js').Interaction} interaction * @param {?MemberWrapper} member - * @return {Promise} + * @returns {Promise} */ async promptForData(interaction, member) { if (!member) { diff --git a/src/commands/user/UnmuteCommand.js b/src/commands/user/UnmuteCommand.js index 677ef4ef2..b101eb38d 100644 --- a/src/commands/user/UnmuteCommand.js +++ b/src/commands/user/UnmuteCommand.js @@ -39,7 +39,7 @@ export default class UnmuteCommand extends UserCommand { * @param {?string} reason * @param {?string} comment * @param {import('discord.js').User} moderator - * @return {Promise} + * @returns {Promise} */ async unmute(interaction, member, reason, comment, moderator) { if (!member) { @@ -67,7 +67,7 @@ export default class UnmuteCommand extends UserCommand { /** * @param {import('discord.js').Interaction} interaction * @param {?MemberWrapper} member - * @return {Promise} + * @returns {Promise} */ async promptForData(interaction, member) { if (!member) { diff --git a/src/commands/user/UserCommand.js b/src/commands/user/UserCommand.js index 49bb90037..c8035e015 100644 --- a/src/commands/user/UserCommand.js +++ b/src/commands/user/UserCommand.js @@ -67,7 +67,7 @@ export default class UserCommand extends Command { * check if this member can be moderated by this moderator * @param {import('discord.js').Interaction} interaction * @param {?MemberWrapper} member - * @return {Promise} + * @returns {Promise} */ async checkPermissions(interaction, member) { if (!member) { @@ -92,7 +92,7 @@ export default class UserCommand extends Command { * @param {import('discord.js').Interaction} interaction * @param {MemberWrapper} member * @param {ConfirmationData} data data that will be saved for the confirmation - * @return {Promise} should the punishment be executed now + * @returns {Promise} should the punishment be executed now */ async preventDuplicateModeration(interaction, member, data = {}) { const customIdParts = (interaction.customId ?? '').split(':'); diff --git a/src/commands/user/UserInfoCommand.js b/src/commands/user/UserInfoCommand.js index d08ec687b..a72f1eeb8 100644 --- a/src/commands/user/UserInfoCommand.js +++ b/src/commands/user/UserInfoCommand.js @@ -9,6 +9,10 @@ import ErrorEmbed from '../../embeds/ErrorEmbed.js'; import {componentEmojiIfExists, inlineEmojiIfExists} from '../../util/format.js'; import BetterButtonBuilder from '../../embeds/BetterButtonBuilder.js'; +/** + * @import {EmbedBuilder, ButtonBuilder} from 'discord.js'; + */ + export default class UserInfoCommand extends Command { getDefaultMemberPermissions() { @@ -62,7 +66,7 @@ export default class UserInfoCommand extends Command { * generate user message with embed and buttons * @param {import('discord.js').User} user * @param {import('discord.js').Interaction} interaction - * @return {Promise<{embeds: EmbedBuilder[], components: ActionRowBuilder[]}>} + * @returns {Promise<{embeds: EmbedBuilder[], components: ActionRowBuilder[]}>} */ async generateUserMessage(user, interaction) { const memberWrapper = new MemberWrapper(user, new GuildWrapper(interaction.guild)); diff --git a/src/database/AutoResponse.js b/src/database/AutoResponse.js index a1040b82c..5a6f3bf65 100644 --- a/src/database/AutoResponse.js +++ b/src/database/AutoResponse.js @@ -4,6 +4,12 @@ import {channelMention} from 'discord.js'; import colors from '../util/colors.js'; import ChatFeatureEmbed from '../embeds/ChatFeatureEmbed.js'; +/** + * @import {Trigger} from './triggers/Trigger.js'; + * @import {Punishment} from './Punishment.js'; + * @import {EmbedWrapper} from '../embeds/EmbedWrapper.js'; + */ + /** * Class representing an auto response */ @@ -16,14 +22,14 @@ export default class AutoResponse extends ChatTriggeredFeature { /** * constructor - create an auto response * @param {import('discord.js').Snowflake} gid guild ID - * @param {Object} json options + * @param {object} json options * @param {Trigger} json.trigger filter that triggers the response - * @param {String} json.response message to send to the channel - * @param {Boolean} json.global does this apply to all channels in this guild + * @param {string} json.response message to send to the channel + * @param {boolean} json.global does this apply to all channels in this guild * @param {import('discord.js').Snowflake[]} [json.channels] channels that this applies to * @param {boolean} [json.enableVision] enable vision api for this auto response - * @param {Number} [id] id in DB - * @return {AutoResponse} the auto response + * @param {number} [id] id in DB + * @returns {AutoResponse} the auto response */ constructor(gid, json, id) { super(id, json.trigger); @@ -43,7 +49,7 @@ export default class AutoResponse extends ChatTriggeredFeature { /** * check if the types of this object are a valid auto-response - * @param {Object} json + * @param {object} json */ static checkTypes(json) { TypeChecker.assertOfTypes(json, ['object'], 'Data object'); @@ -74,8 +80,8 @@ export default class AutoResponse extends ChatTriggeredFeature { /** * generate an Embed displaying the info of this response - * @param {String} title - * @param {Number} color + * @param {string} title + * @param {number} color * @returns {EmbedWrapper} */ embed(title = 'Auto-response', color = colors.GREEN) { @@ -87,9 +93,9 @@ export default class AutoResponse extends ChatTriggeredFeature { * @param {import('discord.js').Snowflake} guildID * @param {boolean} global * @param {import('discord.js').Snowflake[]|null} channels - * @param {String} triggerType - * @param {String} triggerContent - * @param {String} responseText + * @param {string} triggerType + * @param {string} triggerContent + * @param {string} responseText * @param {?boolean} enableVision * @returns {Promise<{success:boolean, response: ?AutoResponse, message: ?string}>} */ diff --git a/src/database/BadWord.js b/src/database/BadWord.js index 961a7b928..9f7657f68 100644 --- a/src/database/BadWord.js +++ b/src/database/BadWord.js @@ -6,6 +6,12 @@ import colors from '../util/colors.js'; import ChatFeatureEmbed from '../embeds/ChatFeatureEmbed.js'; import {EMBED_FIELD_LIMIT} from '../util/apiLimits.js'; +/** + * @import {Trigger} from './triggers/Trigger.js'; + * @import {Punishment} from './Punishment.js'; + * @import {EmbedWrapper} from '../embeds/EmbedWrapper.js'; + */ + /** * Class representing a bad word */ @@ -29,17 +35,17 @@ export default class BadWord extends ChatTriggeredFeature { /** * constructor - create a bad word * @param {import('discord.js').Snowflake} gid guild ID - * @param {Object} json options + * @param {object} json options * @param {Trigger} json.trigger filter that triggers the bad word - * @param {String|Punishment} json.punishment punishment for the members which trigger this - * @param {String} [json.response] a message that is sent by this filter. It's automatically deleted after 5 seconds - * @param {Boolean} json.global does this apply to all channels in this guild + * @param {string|Punishment} json.punishment punishment for the members which trigger this + * @param {string} [json.response] a message that is sent by this filter. It's automatically deleted after 5 seconds + * @param {boolean} json.global does this apply to all channels in this guild * @param {import('discord.js').Snowflake[]} [json.channels] channels that this applies to - * @param {Number} [json.priority] badword priority (higher -> more important) + * @param {number} [json.priority] badword priority (higher -> more important) * @param {?string} [json.dm] direct message to send to the user * @param {boolean} [json.enableVision] enable vision api for this badword - * @param {Number} [id] id in DB - * @return {BadWord} + * @param {number} [id] id in DB + * @returns {BadWord} */ constructor(gid, json, id) { super(id, json.trigger); @@ -76,7 +82,7 @@ export default class BadWord extends ChatTriggeredFeature { /** * check if the types of this object are a valid auto-response - * @param {Object} json + * @param {object} json */ static checkTypes(json) { TypeChecker.assertOfTypes(json, ['object'], 'Data object'); @@ -118,8 +124,8 @@ export default class BadWord extends ChatTriggeredFeature { /** * generate an Embed displaying the info of this bad word - * @param {String} title - * @param {Number} color + * @param {string} title + * @param {number} color * @returns {EmbedWrapper} */ embed(title = 'Bad-word', color = colors.GREEN) { @@ -135,9 +141,9 @@ export default class BadWord extends ChatTriggeredFeature { * @param {import('discord.js').Snowflake} guildID * @param {boolean} global * @param {import('discord.js').Snowflake[]|null} channels - * @param {String} triggerType - * @param {String} triggerContent - * @param {String} [response] response to bad-word + * @param {string} triggerType + * @param {string} triggerContent + * @param {string} [response] response to bad-word * @param {?string} punishment * @param {?number} duration * @param {?number} priority diff --git a/src/database/ChatTriggeredFeature.js b/src/database/ChatTriggeredFeature.js index f8679d9b8..7af993e8e 100644 --- a/src/database/ChatTriggeredFeature.js +++ b/src/database/ChatTriggeredFeature.js @@ -5,9 +5,13 @@ import {EMBED_DESCRIPTION_LIMIT} from '../util/apiLimits.js'; import colors from '../util/colors.js'; import Triggers from './triggers/Triggers.js'; +/** + * @import {Trigger} from './triggers/Trigger.js'; + */ + /** * Config cache time (ms) - * @type {Number} + * @type {number} */ const cacheDuration = 10 * 60 * 1000; @@ -26,19 +30,19 @@ export default class ChatTriggeredFeature { /** * Possible trigger types - * @type {String[]} + * @type {string[]} */ static triggerTypes = ['regex', 'include', 'match', 'phishing']; /** * table name - * @type {String} + * @type {string} */ static tableName; /** * column names - * @type {String[]} + * @type {string[]} */ static columns; @@ -69,7 +73,7 @@ export default class ChatTriggeredFeature { enableVision = false; /** - * @param {Number} id ID in the database + * @param {number} id ID in the database * @param {Trigger} trigger */ constructor(id, trigger) { @@ -109,7 +113,7 @@ export default class ChatTriggeredFeature { /** * get the placeholder text for this trigger type * @param {string} type - * @return {string} + * @returns {string} */ static getTriggerPlaceholder(type) { switch (type) { @@ -145,7 +149,7 @@ export default class ChatTriggeredFeature { /** * get an overview of this object - * @return {string} + * @returns {string} * @abstract */ getOverview() { @@ -154,7 +158,7 @@ export default class ChatTriggeredFeature { /** * get escaped table name - * @return {string} + * @returns {string} */ static get escapedTableName() { return database.escapeId(this.tableName); @@ -164,7 +168,7 @@ export default class ChatTriggeredFeature { * get an overview of all objects of this type for this guild * @param {import('discord.js').Guild} guild * @param {string} name feature name (e.g. Auto-responses or Bad-words). - * @return {Promise} + * @returns {Promise} */ static async getGuildOverview(guild, name) { const objects = await this.getAll(guild.id); @@ -202,7 +206,7 @@ export default class ChatTriggeredFeature { /** * Save to db and cache * @async - * @return {Promise} id in db + * @returns {Promise} id in db */ async save() { if (this.id) { @@ -220,7 +224,7 @@ export default class ChatTriggeredFeature { } else { const columns = database.escapeId(this.constructor.columns); const values = ',?'.repeat(this.constructor.columns.length).slice(1); - /** @property {Number} insertId*/ + /** @property {number} insertId*/ const dbEntry = await database.queryAll( `INSERT INTO ${this.constructor.escapedTableName} (${columns}) VALUES (${values})`, ...this.serialize()); @@ -263,7 +267,7 @@ export default class ChatTriggeredFeature { /** * create this object from data retrieved from the database - * @param data + * @param {object} data * @returns {this} */ static fromData(data) { @@ -275,7 +279,7 @@ export default class ChatTriggeredFeature { /** * Get a single bad word / auto response - * @param {String|Number} id + * @param {string|number} id * @param {import('discord.js').Snowflake} guildid * @returns {Promise} */ @@ -290,8 +294,8 @@ export default class ChatTriggeredFeature { /** * get a trigger - * @param {String} type trigger type - * @param {String} value trigger value + * @param {string} type trigger type + * @param {string} value trigger value * @returns {{trigger: ?Trigger, success: boolean, message: ?string}} */ static getTrigger(type, value) { @@ -304,7 +308,7 @@ export default class ChatTriggeredFeature { let content = value, flags; if (type === 'regex') { - /** @type {String[]}*/ + /** @type {string[]}*/ let parts = value.split(/(?} + * @returns {Collection} */ static async get(channelId, guildId) { @@ -346,7 +350,7 @@ export default class ChatTriggeredFeature { * Get all items for a guild * @async * @param {import('discord.js').Snowflake} guildId - * @return {Promise>} + * @returns {Promise>} */ static async getAll(guildId) { const result = await database.queryAll( diff --git a/src/database/Confirmation.js b/src/database/Confirmation.js index 52f2994cc..3090f6d38 100644 --- a/src/database/Confirmation.js +++ b/src/database/Confirmation.js @@ -20,7 +20,7 @@ export default class Confirmation { /** * @template T * @param {number|string} id - * @return {Promise|null>} + * @returns {Promise|null>} */ static async get(id) { if (typeof id === 'string') { @@ -37,7 +37,7 @@ export default class Confirmation { /** * save this confirmation - * @return {Promise} + * @returns {Promise} */ async save() { if (this.id) { @@ -53,7 +53,7 @@ export default class Confirmation { /** * delete this confirmation - * @return {Promise} + * @returns {Promise} */ async delete() { if (this.id) { diff --git a/src/database/Moderation.js b/src/database/Moderation.js index 230a3efdb..6548633ee 100644 --- a/src/database/Moderation.js +++ b/src/database/Moderation.js @@ -10,10 +10,14 @@ import {formatTime} from '../util/timeutils.js'; import MemberWrapper from '../discord/MemberWrapper.js'; import GuildWrapper from '../discord/GuildWrapper.js'; +/** + * @import {Message} from 'discord.js'; + */ + export default class Moderation { /** - * @type {Number} + * @type {number} */ id; @@ -29,43 +33,43 @@ export default class Moderation { /** * moderation actions: - * * ban - * * unban - * * kick - * * mute - * * unmute - * * softban - * * strike - * * pardon - * @type {String} + * - ban + * - unban + * - kick + * - mute + * - unmute + * - softban + * - strike + * - pardon + * @type {string} */ action; /** * UNIX timestamp of creation (in seconds) - * @type {Number} + * @type {number} */ created; /** * e.g. strike count - * @type {Number} + * @type {number} */ value; /** * UNIX timestamp of expiration (in seconds) - * @type {Number} + * @type {number} */ expireTime; /** - * @type {?String} + * @type {?string} */ reason; /** - * @type {?String} + * @type {?string} */ comment; @@ -80,15 +84,15 @@ export default class Moderation { active; /** - * @param {Object} data - * @param {Number} [data.id] + * @param {object} data + * @param {number} [data.id] * @param {import('discord.js').Snowflake} data.guildid * @param {import('discord.js').Snowflake} data.userid - * @param {String} data.action + * @param {string} data.action * @param {?string|number} [data.created] - * @param {Number} [data.value] - * @param {String} [data.reason] - * @param {String} [data.comment] + * @param {number} [data.value] + * @param {string} [data.reason] + * @param {string} [data.comment] * @param {?string|number} [data.expireTime] * @param {import('discord.js').Snowflake} data.moderator * @param {boolean} [data.active] @@ -109,7 +113,7 @@ export default class Moderation { /** * check if the types of this object are a valid Moderation - * @param {Object} data + * @param {object} data */ static checkTypes(data) { TypeChecker.assertOfTypes(data, ['object'], 'Data object'); @@ -129,7 +133,7 @@ export default class Moderation { /** * escaped database fields - * @return {string[]} + * @returns {string[]} */ static getFields() { return ['id', 'guildid', 'userid', 'action', 'created', 'value', 'expireTime', 'reason', 'comment', 'moderator', 'active'] @@ -141,7 +145,7 @@ export default class Moderation { * @param {WhereParameter[]} params * @param {?number} limit * @param {boolean} sortAscending - * @return {Promise} + * @returns {Promise} */ static async select(params, limit = null, sortAscending = true) { const where = params.join(' AND '); @@ -162,7 +166,7 @@ export default class Moderation { * get all moderations for a guild or member * @param {import('discord.js').Snowflake} guildId * @param {import('discord.js').Snowflake} [userId] - * @return {Promise} + * @returns {Promise} */ static async getAll(guildId, userId = null) { const params = [new WhereParameter('guildid', guildId)]; @@ -178,7 +182,7 @@ export default class Moderation { * get a moderation * @param {import('discord.js').Snowflake} guildId * @param {number} id - * @return {Promise} + * @returns {Promise} */ static async get(guildId, id) { return (await this.select([ @@ -190,7 +194,7 @@ export default class Moderation { /** * insert multiple moderations at once * @param {Moderation[]} moderations - * @return {Promise} + * @returns {Promise} */ static async bulkSave(moderations) { if(!Array.isArray(moderations) || !moderations.length) { @@ -210,7 +214,7 @@ export default class Moderation { /** * get duration in seconds - * @return {null|number} + * @returns {null|number} */ getDuration() { if (!this.expireTime) return null; @@ -219,7 +223,7 @@ export default class Moderation { /** * add this moderation to the database - * @return {Promise} + * @returns {Promise} */ async save() { const fields = this.constructor.getFields().slice(1); @@ -240,7 +244,7 @@ export default class Moderation { /** * log this moderation to the guild's log channel * @param {?number} total total strike count - * @return {Promise} + * @returns {Promise} */ async log(total = null) { const user = await this.getUser(); @@ -271,7 +275,7 @@ export default class Moderation { /** * Delete this moderation from the database - * @return {Promise} + * @returns {Promise} */ async delete() { return database.query('DELETE FROM moderations WHERE id = ?', this.id); @@ -279,7 +283,7 @@ export default class Moderation { /** * get all parameters of this moderation - * @return {(import('discord.js').Snowflake|String|Number)[]} + * @returns {(import('discord.js').Snowflake|string|number)[]} */ getParameters() { return [this.guildid, this.userid, this.action, this.created, this.value, this.expireTime, this.reason, this.comment, this.moderator, this.active]; @@ -287,7 +291,7 @@ export default class Moderation { /** * fetch the user targeted by this moderation. - * @return {Promise} + * @returns {Promise} */ async getUser() { return await (new UserWrapper(this.userid)).fetchUser(); @@ -295,7 +299,7 @@ export default class Moderation { /** * fetch the guild this moderation was executed in. - * @return {Promise} + * @returns {Promise} */ async getGuildWrapper() { return await GuildWrapper.fetch(this.guildid); @@ -303,7 +307,7 @@ export default class Moderation { /** * fetch the user targeted by this moderation. - * @return {Promise} + * @returns {Promise} */ async getMemberWrapper() { return new MemberWrapper(await this.getUser(), await this.getGuildWrapper()); @@ -311,7 +315,7 @@ export default class Moderation { /** * fetch the moderator who executed this moderation. - * @return {Promise} + * @returns {Promise} */ async getModerator() { if (!this.moderator) { diff --git a/src/database/Punishment.js b/src/database/Punishment.js index ee8d92ec8..8c74de1b3 100644 --- a/src/database/Punishment.js +++ b/src/database/Punishment.js @@ -18,7 +18,7 @@ export default class Punishment { message = null; /** - * @param {Object} raw + * @param {object} raw * @param {PunishmentAction} raw.action * @param {?number|string} [raw.duration] * @param {?string} [raw.message] @@ -34,6 +34,7 @@ export default class Punishment { * @param {PunishmentAction} action * @param {?string} duration * @param {?string} message + * @returns {Punishment} */ static from(action, duration = null, message = null) { return new this({action, duration: parseTime(duration), message}); diff --git a/src/database/export/Exporter.js b/src/database/export/Exporter.js index e5ce30fe3..87acf1fe6 100644 --- a/src/database/export/Exporter.js +++ b/src/database/export/Exporter.js @@ -4,6 +4,11 @@ import Moderation from '../Moderation.js'; import AutoResponse from '../AutoResponse.js'; import BadWord from '../BadWord.js'; +/** + * @import {ChatTriggeredFeature} from '../ChatTriggeredFeature.js'; + * @import {GuildSettingsJSON} from '../../settings/GuildSettings.js'; + */ + export default class Exporter { /** @@ -50,7 +55,7 @@ export default class Exporter { /** * get all data of this guild as a JSON string - * @return {Promise} + * @returns {Promise} */ async export() { await Promise.all([ diff --git a/src/database/export/Importer.js b/src/database/export/Importer.js index be053fe61..91de66c62 100644 --- a/src/database/export/Importer.js +++ b/src/database/export/Importer.js @@ -1,8 +1,14 @@ +/** + * @class Importer + * @classdesc Base class for importing data into the DB + * @abstract + */ export default class Importer { /** * import all data to the DB - * @return {Promise} + * @returns {Promise} + * @abstract */ async import() { throw new Error('Method not implemented'); @@ -11,6 +17,7 @@ export default class Importer { /** * verify that all data is of correct types before importing * @throws {TypeError} + * @abstract */ checkAllTypes() { throw new Error('Method not implemented'); @@ -18,9 +25,10 @@ export default class Importer { /** * generate an embed showing an overview of imported data - * @return {import('discord.js').EmbedBuilder} + * @returns {import('discord.js').EmbedBuilder} + * @abstract */ generateEmbed() { - + throw new Error('Method not implemented'); } } diff --git a/src/database/export/ModBotImporter.js b/src/database/export/ModBotImporter.js index 4fe475c1a..fc24b41c8 100644 --- a/src/database/export/ModBotImporter.js +++ b/src/database/export/ModBotImporter.js @@ -8,6 +8,11 @@ import {EmbedBuilder} from 'discord.js'; import GuildWrapper from '../../discord/GuildWrapper.js'; import {asyncFilter} from '../../util/util.js'; +/** + * @import {Client, Snowflake} from 'discord.js'; + * @import {Exporter} from './Exporter.js'; + */ + export default class ModBotImporter extends Importer { /** @@ -68,7 +73,7 @@ export default class ModBotImporter extends Importer { /** * import all data to the DB - * @return {Promise} + * @returns {Promise} */ async import() { await Promise.all([ diff --git a/src/database/export/VortexImporter.js b/src/database/export/VortexImporter.js index d6fcb47e8..e6d170679 100644 --- a/src/database/export/VortexImporter.js +++ b/src/database/export/VortexImporter.js @@ -5,7 +5,7 @@ import {EmbedBuilder} from 'discord.js'; import bot from '../../bot/Bot.js'; /** - * @typedef {Object} VortexModeration + * @typedef {object} VortexModeration * @property {number} value * @property {import('discord.js').Snowflake} id */ @@ -14,30 +14,30 @@ export default class VortexImporter extends Importer { /** * key: userid * value: timestamp - * @type {Object} + * @type {object} */ tempmutes; /** * key: userid * value: strike count - * @type {Object} + * @type {object} */ strikes; /** * key: userid * value: timestamp - * @type {Object} + * @type {object} */ tempbans; /** * @param {import('discord.js').Snowflake} guildID - * @param {Object} data JSON exported data from vortex - * @param {Object} data.tempmutes - * @param {Object} data.strikes - * @param {Object} data.tempbans + * @param {object} data JSON exported data from vortex + * @param {object} data.tempmutes + * @param {object} data.strikes + * @param {object} data.tempbans */ constructor(guildID, data) { super(); @@ -48,8 +48,8 @@ export default class VortexImporter extends Importer { } /** - * @param {Object} object - * @return {VortexModeration[]} + * @param {object} object + * @returns {VortexModeration[]} */ keyValueArray(object) { const result = []; @@ -98,8 +98,8 @@ export default class VortexImporter extends Importer { /** * @param {VortexModeration} moderation - * @param {String} type - * @return {Moderation} + * @param {string} type + * @returns {Moderation} */ _timedModeration(moderation, type) { return new Moderation({ @@ -107,14 +107,14 @@ export default class VortexImporter extends Importer { userid: moderation.id, action: type, expireTime: moderation.value, - reason: /** @type {String} */'Imported from Vortex', + reason: /** @type {string} */'Imported from Vortex', moderator: bot.client.user.id }); } /** * @param {VortexModeration} moderation - * @return {Moderation} + * @returns {Moderation} * @private */ _strike(moderation) { diff --git a/src/database/migrations/Migration.js b/src/database/migrations/Migration.js index b47b8ad46..618d4bfd6 100644 --- a/src/database/migrations/Migration.js +++ b/src/database/migrations/Migration.js @@ -1,3 +1,7 @@ +/** + * @import Database from '../bot/Database' + */ + /** * @class Migration * @classdesc Base class for all migrations diff --git a/src/database/triggers/RegexTrigger.js b/src/database/triggers/RegexTrigger.js index 23f2705e0..151cace8c 100644 --- a/src/database/triggers/RegexTrigger.js +++ b/src/database/triggers/RegexTrigger.js @@ -9,7 +9,7 @@ export default class RegexTrigger extends Trigger { } /** - * @return {string} + * @returns {string} */ asContentString() { return `/${this.content}/${this.flags ?? ''}`; diff --git a/src/database/triggers/Trigger.js b/src/database/triggers/Trigger.js index 6e80b1cc9..4a8db5d15 100644 --- a/src/database/triggers/Trigger.js +++ b/src/database/triggers/Trigger.js @@ -5,25 +5,25 @@ import {inlineCode} from 'discord.js'; */ export default class Trigger { /** - * @type {String} + * @type {string} */ type; /** - * @type {String} + * @type {string} */ content; /** - * @type {String} + * @type {string} */ flags; /** - * @param {Object} data - * @property {String} type - * @property {String} content - * @property {String} [flags] + * @param {object} data + * @property {string} type + * @property {string} content + * @property {string} [flags] */ constructor(data) { this.type = data.type; @@ -39,7 +39,7 @@ export default class Trigger { } /** - * @return {string} + * @returns {string} */ asContentString() { return this.content; @@ -48,7 +48,7 @@ export default class Trigger { /** * Convert this trigger to a regex trigger. * This is only supported for include and match types. - * @return {Trigger} + * @returns {Trigger} * @abstract */ toRegex() { @@ -56,7 +56,7 @@ export default class Trigger { } /** - * @param {String} content + * @param {string} content * @returns {boolean} * @abstract */ diff --git a/src/discord/ChannelWrapper.js b/src/discord/ChannelWrapper.js index a406a1ff0..a45596077 100644 --- a/src/discord/ChannelWrapper.js +++ b/src/discord/ChannelWrapper.js @@ -37,7 +37,7 @@ export default class ChannelWrapper { /** * @param {import("discord.js").Snowflake} id - * @return {Promise} + * @returns {Promise} */ static async fetch(id) { try { @@ -94,7 +94,7 @@ export default class ChannelWrapper { /** * get the emoji for this channel type - * @return {import('discord.js').APIMessageComponentEmoji} + * @returns {import('discord.js').APIMessageComponentEmoji} */ getChannelEmoji() { const id = this.getChannelEmojiId(); @@ -102,7 +102,7 @@ export default class ChannelWrapper { } /** - * @return {import('discord.js').Snowflake|null} + * @returns {import('discord.js').Snowflake|null} */ getChannelEmojiId() { const emojis = config.data.emoji; @@ -134,7 +134,7 @@ export default class ChannelWrapper { * Fetch messages (even more than 100) from a channel * @param {number} count * @param {import('discord.js').Snowflake|null} before - * @return {Promise>} fetched messages + * @returns {Promise>} fetched messages */ async getMessages(count = 100, before = null) { let messages = new Collection(); @@ -156,7 +156,7 @@ export default class ChannelWrapper { /** * * @param {import('discord.js').Snowflake[]} messages - * @return {Promise} + * @returns {Promise} */ async bulkDelete(messages) { while (messages.length) { diff --git a/src/discord/GuildWrapper.js b/src/discord/GuildWrapper.js index eb8c6293b..e4ff159bb 100644 --- a/src/discord/GuildWrapper.js +++ b/src/discord/GuildWrapper.js @@ -5,6 +5,10 @@ import GuildSettings from '../settings/GuildSettings.js'; import database from '../bot/Database.js'; import logger from '../bot/Logger.js'; +/** + * @import {Guild, Role, Message} from 'discord.js'; + */ + export default class GuildWrapper { /** @@ -20,7 +24,7 @@ export default class GuildWrapper { guild; /** - * @param {import(discord.js).Guild} guild + * @param {Guild} guild */ constructor(guild) { this.guild = guild; @@ -28,7 +32,7 @@ export default class GuildWrapper { /** * @param {import("discord.js").Snowflake} id - * @return {Promise} + * @returns {Promise} */ static async fetch(id) { try { @@ -44,7 +48,7 @@ export default class GuildWrapper { /** * get the guild settings of this guild - * @return {Promise} + * @returns {Promise} */ async getSettings() { return GuildSettings.get(this.guild.id); @@ -54,7 +58,7 @@ export default class GuildWrapper { * fetch a guild member * @param {import('discord.js').Snowflake} id user id * @param {boolean} [force] bypass cache - * @return {Promise} + * @returns {Promise} */ async fetchMember(id, force = false) { try { @@ -76,7 +80,7 @@ export default class GuildWrapper { /** * fetch a role * @param {import('discord.js').Snowflake} id role id - * @return {Promise} + * @returns {Promise} */ async fetchRole(id) { try { @@ -98,7 +102,7 @@ export default class GuildWrapper { /** * fetch a ban * @param {import('discord.js').Snowflake} id user id - * @return {Promise} + * @returns {Promise} */ async fetchBan(id) { try { @@ -117,7 +121,7 @@ export default class GuildWrapper { /** * fetch a channel * @param {import("discord.js").Snowflake} id channel id - * @return {Promise} + * @returns {Promise} */ async fetchChannel(id) { try { @@ -140,8 +144,8 @@ export default class GuildWrapper { /** * try to send a dm * @param {import("discord.js").User} user - * @param {String} message - * @return {Promise} was this successful + * @param {string} message + * @returns {Promise} was this successful */ async sendDM(user, message) { if (!await this.fetchMember(user.id)) return false; @@ -164,7 +168,7 @@ export default class GuildWrapper { * send a message to a channel * @param {import('discord.js').Snowflake} channelId * @param {import('discord.js').MessagePayload|import('discord.js').MessageOptions} options - * @return {Promise} Discord message (if it was sent) + * @returns {Promise} Discord message (if it was sent) */ async sendMessageToChannel(channelId, options) { if (!channelId) { @@ -197,7 +201,7 @@ export default class GuildWrapper { /** * send this message to the guild's log channel * @param {import('discord.js').MessagePayload|import('discord.js').MessageCreateOptions} options - * @return {Promise} Discord message (if it was sent) + * @returns {Promise} Discord message (if it was sent) */ async log(options) { const settings = await this.getSettings(); @@ -207,7 +211,7 @@ export default class GuildWrapper { /** * send this message to the guild's message log channel * @param {import('discord.js').MessagePayload|import('discord.js').MessageCreateOptions} options - * @return {Promise} Discord message (if it was sent) + * @returns {Promise} Discord message (if it was sent) */ async logMessage(options) { const settings = await this.getSettings(); @@ -217,7 +221,7 @@ export default class GuildWrapper { /** * send this message to the guild's join log channel * @param {import('discord.js').MessagePayload|import('discord.js').MessageCreateOptions} options - * @return {Promise} Discord message (if it was sent) + * @returns {Promise} Discord message (if it was sent) */ async logJoin(options) { const settings = await this.getSettings(); @@ -226,7 +230,7 @@ export default class GuildWrapper { /** * delete ALL data for this guild - * @return {Promise} + * @returns {Promise} */ async deleteData() { return Promise.all([ @@ -240,8 +244,8 @@ export default class GuildWrapper { /** * get a guild from cache or create a new one - * @param {import("discord.js".Guild)} guild - * @return {GuildWrapper} + * @param {Guild} guild + * @returns {GuildWrapper} * @deprecated */ static get(guild) { diff --git a/src/discord/MemberWrapper.js b/src/discord/MemberWrapper.js index 22a5609bc..c88c92e80 100644 --- a/src/discord/MemberWrapper.js +++ b/src/discord/MemberWrapper.js @@ -8,6 +8,11 @@ import Moderation from '../database/Moderation.js'; import UserWrapper from './UserWrapper.js'; import ErrorEmbed from '../embeds/ErrorEmbed.js'; +/** + * @import {User} from 'discord.js'; + * @import {Punishment} from '../database/Punishment.js'; + */ + export default class MemberWrapper { /** @@ -39,7 +44,7 @@ export default class MemberWrapper { * must follow the format 'action:id' or 'action:id:other-data' * @param {import('discord.js').Interaction} interaction * @param {number} position which position the user id is at. E.g. 2 for 'command:subcommand:id' or 3 for 'command:group:subcommand:id' - * @return {Promise} + * @returns {Promise} */ static async getMemberFromCustomId(interaction, position = 1) { const id = interaction.customId.split(':').at(position); @@ -56,7 +61,7 @@ export default class MemberWrapper { * get member by guild and user id * @param {import('discord.js').Interaction} interaction * @param {import('discord.js').Snowflake} id user id - * @return {Promise} + * @returns {Promise} */ static async getMember(interaction, id) { const user = await (new UserWrapper(id)).fetchUser(); @@ -80,7 +85,7 @@ export default class MemberWrapper { /** * get the member or user object - * @return {Promise} + * @returns {Promise} */ async getMemberOrUser() { return this.member ?? await this.fetchMember() ?? this.user; @@ -88,7 +93,7 @@ export default class MemberWrapper { /** * get the display name of this member - * @return {Promise} + * @returns {Promise} */ async displayName() { return (await this.getMemberOrUser()).displayName; @@ -96,7 +101,7 @@ export default class MemberWrapper { /** * get the avatar url of this member - * @return {Promise} + * @returns {Promise} */ async displayAvatarURL() { return (await this.getMemberOrUser()).displayAvatarURL(); @@ -104,7 +109,7 @@ export default class MemberWrapper { /** * get all moderations for this member - * @return {Promise} + * @returns {Promise} */ async getModerations() { return await Moderation.getAll(this.guild.guild.id, this.user.id); @@ -113,7 +118,7 @@ export default class MemberWrapper { /** * get the active moderation of this type * @param {string} type - * @return {Promise} + * @returns {Promise} */ async getActiveModeration(type) { const moderation = await database.query( @@ -130,7 +135,7 @@ export default class MemberWrapper { /** * get ban status, end timestamp and reason - * @return {Promise<{banned: boolean, end: ?number, reason: string, comment: ?string}>} + * @returns {Promise<{banned: boolean, end: ?number, reason: string, comment: ?string}>} */ async getBanInfo() { const ban = await this.getActiveModeration('ban'); @@ -171,7 +176,7 @@ export default class MemberWrapper { /** * get muted status, end timestamp and reason - * @return {Promise<{muted: boolean, end: ?number, reason: string, comment: ?string}>} + * @returns {Promise<{muted: boolean, end: ?number, reason: string, comment: ?string}>} */ async getMuteInfo() { if (!this.member) await this.fetchMember(true); @@ -223,7 +228,7 @@ export default class MemberWrapper { /** * get the guild settings - * @return {Promise} + * @returns {Promise} */ async getGuildSettings() { return GuildSettings.get(this.guild.guild.id); @@ -231,7 +236,7 @@ export default class MemberWrapper { /** * fetch the muted role, return null if no muted role is set or the muted role doesn't exist. - * @return {Promise} + * @returns {Promise} */ async getMutedRole() { const settings = await this.getGuildSettings(); @@ -244,7 +249,7 @@ export default class MemberWrapper { /** * is this member protected - * @return {Promise} + * @returns {Promise} */ async isProtected() { if (!await this.fetchMember()) { @@ -257,7 +262,7 @@ export default class MemberWrapper { /** * can the bot moderate this member - * @return {Promise} + * @returns {Promise} */ async isModerateable() { return this.isModerateableBy(await this.guild.guild.members.fetchMe()); @@ -266,7 +271,7 @@ export default class MemberWrapper { /** * can this member be moderated by this moderator * @param {import('discord.js').GuildMember} moderator - * @return {Promise} + * @returns {Promise} */ async isModerateableBy(moderator) { if (await this.isProtected()) { @@ -283,7 +288,7 @@ export default class MemberWrapper { /** * shorten a reason to a length below 512 * @param {string} reason - * @return {string} + * @returns {string} * @private */ _shortenReason(reason) { @@ -292,11 +297,11 @@ export default class MemberWrapper { /** * strike this member - * @param {String} reason - * @param {?String} comment + * @param {string} reason + * @param {?string} comment * @param {User|import('discord.js').ClientUser} moderator * @param {number} amount - * @return {Promise} + * @returns {Promise} */ async strike(reason, comment, moderator, amount = 1){ await this.dmPunishedUser('striked', reason, null, 'in'); @@ -309,7 +314,7 @@ export default class MemberWrapper { /** * get the - * @return {Promise} + * @returns {Promise} */ async getStrikeSum() { return (await database.query( @@ -321,10 +326,10 @@ export default class MemberWrapper { /** * execute this punishment * @param {Punishment} punishment - * @param {String} reason + * @param {string} reason * @param {?string} comment * @param {boolean} [allowEmpty] return if there is no punishment instead of throwing an exception - * @return {Promise} + * @returns {Promise} */ async executePunishment(punishment, reason, comment, allowEmpty = false) { if (!punishment) { @@ -360,11 +365,11 @@ export default class MemberWrapper { /** * pardon strikes from this member - * @param {String} reason - * @param {?String} comment + * @param {string} reason + * @param {?string} comment * @param {User|import('discord.js').ClientUser} moderator * @param {number} amount - * @return {Promise} + * @returns {Promise} */ async pardon(reason, comment, moderator, amount = 1){ await this.guild.sendDM(this.user, `${amount} strikes have been pardoned in ${bold(this.guild.guild.name)} | ${reason}`); @@ -374,12 +379,12 @@ export default class MemberWrapper { /** * ban this user from this guild - * @param {String} reason - * @param {?String} comment + * @param {string} reason + * @param {?string} comment * @param {User|import('discord.js').ClientUser} moderator * @param {?number} [duration] * @param {?number} [deleteMessageSeconds] - * @return {Promise} + * @returns {Promise} */ async ban(reason, comment, moderator, duration, deleteMessageSeconds){ deleteMessageSeconds ??= 60 * 60; @@ -397,10 +402,10 @@ export default class MemberWrapper { /** * unban this member - * @param {String} reason - * @param {?String} comment + * @param {string} reason + * @param {?string} comment * @param {User|import('discord.js').ClientUser} moderator - * @return {Promise} + * @returns {Promise} */ async unban(reason, comment, moderator){ await this.disableActiveModerations('ban'); @@ -417,11 +422,11 @@ export default class MemberWrapper { /** * softban this user from this guild - * @param {String} reason - * @param {?String} comment + * @param {string} reason + * @param {?string} comment * @param {import('discord.js').User} moderator * @param {?number} [deleteMessageSeconds] - * @return {Promise} + * @returns {Promise} */ async softban(reason, comment, moderator, deleteMessageSeconds){ deleteMessageSeconds ??= 60 * 60; @@ -440,10 +445,10 @@ export default class MemberWrapper { /** * kick this user from this guild - * @param {String} reason - * @param {?String} comment + * @param {string} reason + * @param {?string} comment * @param {User|import('discord.js').ClientUser} moderator - * @return {Promise} + * @returns {Promise} */ async kick(reason, comment, moderator){ await this.dmPunishedUser('kicked', reason, null, 'from'); @@ -454,11 +459,11 @@ export default class MemberWrapper { /** * mute this user in this guild - * @param {String} reason - * @param {?String} comment + * @param {string} reason + * @param {?string} comment * @param {User|import('discord.js').ClientUser} moderator - * @param {Number} [duration] - * @return {Promise} + * @param {number} [duration] + * @returns {Promise} */ async mute(reason, comment, moderator, duration){ const timeout = duration && duration <= TIMEOUT_LIMIT; @@ -485,10 +490,10 @@ export default class MemberWrapper { /** * unmute this user in this guild - * @param {String} reason - * @param {?String} comment + * @param {string} reason + * @param {?string} comment * @param {User|import('discord.js').ClientUser} moderator - * @return {Promise} + * @returns {Promise} */ async unmute(reason, comment, moderator){ if (!this.member) await this.fetchMember(); @@ -506,12 +511,12 @@ export default class MemberWrapper { /** * create a new moderation and save it to the database * @param {string} action moderation type (e.g. 'ban') - * @param {?String} reason reason for the moderation - * @param {?String} comment internal comment for the moderation + * @param {?string} reason reason for the moderation + * @param {?string} comment internal comment for the moderation * @param {?number} duration duration of the moderation * @param {import('discord.js').Snowflake} moderatorId id of the moderator * @param {number} [value] value of the moderation (e.g. strike count) - * @return {Promise} + * @returns {Promise} */ async createModeration(action, reason, comment, duration, moderatorId, value = 0) { await this.disableActiveModerations(action); @@ -547,13 +552,13 @@ export default class MemberWrapper { /** * send the user a dm about this punishment - * @param {String} verb - * @param {String} reason - * @param {Number} [duration] - * @param {String} [preposition] default: from - * @return {Promise} success + * @param {string} verb + * @param {string} reason + * @param {?number} [duration] + * @param {string} [preposition] default: from + * @returns {Promise} success */ - async dmPunishedUser(verb, reason, duration, preposition = 'from') { + async dmPunishedUser(verb, reason, duration = null, preposition = 'from') { return this.guild.sendDM(this.user, `You have been ${verb} ${preposition} ${bold(this.guild.guild.name)}${duration ? ` for ${formatTime(duration)}` : ''}: ${reason}` ); diff --git a/src/discord/RateLimiter.js b/src/discord/RateLimiter.js index a2aa7985b..2203ad30c 100644 --- a/src/discord/RateLimiter.js +++ b/src/discord/RateLimiter.js @@ -2,6 +2,10 @@ import {Collection} from 'discord.js'; import database from '../bot/Database.js'; import logger from '../bot/Logger.js'; +/** + * @import {Guild, User, GuildMember} from 'discord.js'; + */ + export default class RateLimiter { static #modCountCache = new Collection(); static #modCountTimeouts = new Collection(); @@ -10,8 +14,8 @@ export default class RateLimiter { * send a user a direct message * @param {Guild} guild * @param {User|GuildMember} user - * @param {String} message - * @return {Promise} + * @param {string} message + * @returns {Promise} */ static async sendDM(guild, user, message) { let count = this.#modCountCache.get(guild.id); diff --git a/src/discord/UserWrapper.js b/src/discord/UserWrapper.js index afd195d1a..202d6f4d7 100644 --- a/src/discord/UserWrapper.js +++ b/src/discord/UserWrapper.js @@ -23,7 +23,7 @@ export default class UserWrapper { /** * fetch this user - * @return {Promise} + * @returns {Promise} */ async fetchUser() { try { diff --git a/src/discord/permissions/SlashCommandPermissionManager.js b/src/discord/permissions/SlashCommandPermissionManager.js index 6b5245cd0..3ba1a79b2 100644 --- a/src/discord/permissions/SlashCommandPermissionManager.js +++ b/src/discord/permissions/SlashCommandPermissionManager.js @@ -2,6 +2,10 @@ import {RESTJSONErrorCodes} from 'discord.js'; import SlashCommandPermissionOverrides from './SlashCommandPermissionOverrides.js'; import bot from '../../bot/Bot.js'; +/** + * @import {Command} from '../commands/Command.js'; + */ + /** * Emulate Discord Slash Command Permissions * @abstract @@ -13,7 +17,7 @@ export default class SlashCommandPermissionManager { * Uses the older V2 Permission system: https://discord.com/developers/docs/change-log#updated-command-permissions * @param {import('discord.js').Interaction<"cached">} interaction * @param {Command} command - * @return {Promise} + * @returns {Promise} */ async hasPermission(interaction, command) { throw new Error('Not implemented'); @@ -23,7 +27,7 @@ export default class SlashCommandPermissionManager { * fetch the overrides for a command or application * @param {import('discord.js').Interaction<"cached">} interaction * @param {import('discord.js').Snowflake} [commandId] leave empty to fetch global permissions - * @return {Promise} + * @returns {Promise} */ async fetchOverrides(interaction, commandId = bot.client.user.id) { let overrides = []; diff --git a/src/discord/permissions/SlashCommandPermissionManagerV2.js b/src/discord/permissions/SlashCommandPermissionManagerV2.js index 03244f7ad..4f4f1f1e6 100644 --- a/src/discord/permissions/SlashCommandPermissionManagerV2.js +++ b/src/discord/permissions/SlashCommandPermissionManagerV2.js @@ -1,13 +1,18 @@ import {PermissionFlagsBits} from 'discord.js'; import SlashCommandPermissionManager from './SlashCommandPermissionManager.js'; +/** + * @import {Command} from '../commands/Command.js'; + * @import {SlashCommandPermissionOverrides} from './SlashCommandPermissionOverrides.js'; + */ + export default class SlashCommandPermissionManagerV2 extends SlashCommandPermissionManager { /** * Calculates if a member has the permission to execute a command in a guild * Uses the older V2 Permission system: https://discord.com/developers/docs/change-log#updated-command-permissions * @param {import('discord.js').Interaction<"cached">} interaction * @param {Command} command - * @return {Promise} + * @returns {Promise} */ async hasPermission(interaction, command) { if (interaction.memberPermissions.has(PermissionFlagsBits.Administrator)) { @@ -43,7 +48,7 @@ export default class SlashCommandPermissionManagerV2 extends SlashCommandPermiss /** * @param {SlashCommandPermissionOverrides} overrides - * @return {Promise} + * @returns {Promise} */ async hasPermissionInOverrides(overrides) { let permission = null; diff --git a/src/discord/permissions/SlashCommandPermissionManagerV3.js b/src/discord/permissions/SlashCommandPermissionManagerV3.js index 66693bc03..49c3fd7f1 100644 --- a/src/discord/permissions/SlashCommandPermissionManagerV3.js +++ b/src/discord/permissions/SlashCommandPermissionManagerV3.js @@ -1,6 +1,11 @@ import SlashCommandPermissionManager from './SlashCommandPermissionManager.js'; import {PermissionFlagsBits} from 'discord.js'; +/** + * @import {Command} from '../commands/Command.js'; + * @import {SlashCommandPermissionOverrides} from './SlashCommandPermissionOverrides.js'; + */ + export default class SlashCommandPermissionManagerV3 extends SlashCommandPermissionManager { /** * Check if the user has permission to execute the command. @@ -9,7 +14,7 @@ export default class SlashCommandPermissionManagerV3 extends SlashCommandPermiss * Flowchart: ![](https://media.discordapp.net/attachments/697138785317814292/1042878162901672048/flowchart-for-new-permissions.png) * @param {import('discord.js').Interaction<"cached">} interaction * @param {Command} command - * @return {Promise} + * @returns {Promise} */ async hasPermission(interaction, command) { if (interaction.member.permissions.has(PermissionFlagsBits.Administrator)) { @@ -29,7 +34,7 @@ export default class SlashCommandPermissionManagerV3 extends SlashCommandPermiss * @param {SlashCommandPermissionOverrides} appOverrides * @param {import('discord.js').Interaction<"cached">} interaction * @param {Command} command - * @return {Promise} + * @returns {Promise} */ async hasCommandLevelChannelPermission(commandOverrides, appOverrides, interaction, command) { if (commandOverrides.channelOverride) { @@ -59,7 +64,7 @@ export default class SlashCommandPermissionManagerV3 extends SlashCommandPermiss * @param {SlashCommandPermissionOverrides} appOverrides * @param {import('discord.js').Interaction<"cached">} interaction * @param {Command} command - * @return {Promise} + * @returns {Promise} */ async hasAppLevelChannelPermission(commandOverrides, appOverrides, interaction, command) { if (appOverrides.channelOverride) { @@ -84,7 +89,7 @@ export default class SlashCommandPermissionManagerV3 extends SlashCommandPermiss * @param {SlashCommandPermissionOverrides} appOverrides * @param {import('discord.js').Interaction<"cached">} interaction * @param {Command} command - * @return {Promise} + * @returns {Promise} */ async hasCommandLevelUserRolePermission(commandOverrides, appOverrides, interaction, command) { if (commandOverrides.memberOverride) { @@ -110,7 +115,7 @@ export default class SlashCommandPermissionManagerV3 extends SlashCommandPermiss * @param {SlashCommandPermissionOverrides} appOverrides * @param {import('discord.js').Interaction<"cached">} interaction * @param {Command} command - * @return {Promise} + * @returns {Promise} */ async hasAppLevelUserRolePermission(commandOverrides, appOverrides, interaction, command) { if (appOverrides.memberOverride) { @@ -145,7 +150,7 @@ export default class SlashCommandPermissionManagerV3 extends SlashCommandPermiss * @param {SlashCommandPermissionOverrides} appOverrides * @param {import('discord.js').Interaction<"cached">} interaction * @param {Command} command - * @return {Promise} + * @returns {Promise} */ async hasDefaultPermission(commandOverrides, appOverrides, interaction, command) { switch (command.getDefaultMemberPermissions()) { diff --git a/src/discord/permissions/SlashCommandPermissionManagers.js b/src/discord/permissions/SlashCommandPermissionManagers.js index f420907fc..c6c9a6d22 100644 --- a/src/discord/permissions/SlashCommandPermissionManagers.js +++ b/src/discord/permissions/SlashCommandPermissionManagers.js @@ -8,7 +8,7 @@ export default class SlashCommandPermissionManagers { /** * @param {import('discord.js').Interaction<"cached">} interaction - * @return {SlashCommandPermissionManagerV2|SlashCommandPermissionManagerV3} + * @returns {SlashCommandPermissionManagerV2|SlashCommandPermissionManagerV3} */ static getManager(interaction) { if (interaction.guild.features.includes(GuildFeature.ApplicationCommandPermissionsV2)) { diff --git a/src/discord/permissions/SlashCommandPermissionOverrides.js b/src/discord/permissions/SlashCommandPermissionOverrides.js index aedb0b489..d9d748af2 100644 --- a/src/discord/permissions/SlashCommandPermissionOverrides.js +++ b/src/discord/permissions/SlashCommandPermissionOverrides.js @@ -37,7 +37,7 @@ export default class SlashCommandPermissionOverrides { /** * get the raw overrides - * @return {import('discord.js').ApplicationCommandPermissions[]} + * @returns {import('discord.js').ApplicationCommandPermissions[]} */ get rawOverrides() { return this.#overrides; @@ -45,7 +45,7 @@ export default class SlashCommandPermissionOverrides { /** * get all role overrides - * @return {import('discord.js').ApplicationCommandPermissions[]} + * @returns {import('discord.js').ApplicationCommandPermissions[]} */ get roleOverrides() { return this.#overrides.filter(override => override.type === ApplicationCommandPermissionType.Role); @@ -53,7 +53,7 @@ export default class SlashCommandPermissionOverrides { /** * get the overrides for the @everyone role - * @return {?import('discord.js').ApplicationCommandPermissions} + * @returns {?import('discord.js').ApplicationCommandPermissions} */ get everyoneOverride() { return this.roleOverrides.find(override => override.id === this.#guild.id) ?? null; @@ -61,7 +61,7 @@ export default class SlashCommandPermissionOverrides { /** * get the overrides for all roles this member has - * @return {import('discord.js').ApplicationCommandPermissions[]} + * @returns {import('discord.js').ApplicationCommandPermissions[]} */ get memberRoleOverrides() { return this.roleOverrides.filter(override => this.#member.roles.resolve(override.id)); @@ -69,7 +69,7 @@ export default class SlashCommandPermissionOverrides { /** * get the overrides for all members - * @return {import('discord.js').ApplicationCommandPermissions[]} + * @returns {import('discord.js').ApplicationCommandPermissions[]} */ get memberOverrides() { return this.#overrides.filter(override => override.type === ApplicationCommandPermissionType.User); @@ -77,7 +77,7 @@ export default class SlashCommandPermissionOverrides { /** * get the override value for a single member - * @return {?import('discord.js').ApplicationCommandPermissions} + * @returns {?import('discord.js').ApplicationCommandPermissions} */ get memberOverride() { return this.memberOverrides.find(override => override.id === this.#member.id) ?? null; @@ -85,7 +85,7 @@ export default class SlashCommandPermissionOverrides { /** * get the overrides for all channels - * @return {import('discord.js').ApplicationCommandPermissions[]} + * @returns {import('discord.js').ApplicationCommandPermissions[]} */ get channelOverrides() { return this.#overrides.filter(override => override.type === ApplicationCommandPermissionType.Channel); @@ -93,7 +93,7 @@ export default class SlashCommandPermissionOverrides { /** * get the default channel override value - * @return {?import('discord.js').ApplicationCommandPermissions} + * @returns {?import('discord.js').ApplicationCommandPermissions} */ get allChannelsOverride() { // https://discord.com/developers/docs/interactions/application-commands#application-command-permissions-object-application-command-permissions-constants @@ -102,7 +102,7 @@ export default class SlashCommandPermissionOverrides { /** * get the override value for a single channel - * @return {?import('discord.js').ApplicationCommandPermissions} + * @returns {?import('discord.js').ApplicationCommandPermissions} */ get channelOverride() { return this.channelOverrides.find(override => override.id === this.#channel.id) ?? null; diff --git a/src/embeds/BetterButtonBuilder.js b/src/embeds/BetterButtonBuilder.js index 078eaf618..3ccbf1004 100644 --- a/src/embeds/BetterButtonBuilder.js +++ b/src/embeds/BetterButtonBuilder.js @@ -4,9 +4,8 @@ export default class BetterButtonBuilder extends ButtonBuilder { /** * Set the emoji for this button. * If the emoji parameter is null, don't change the emoji. - * * @param {?import('discord.js').ComponentEmojiResolvable} emoji - * @return {ButtonBuilder|BetterButtonBuilder} + * @returns {ButtonBuilder|BetterButtonBuilder} */ setEmojiIfPresent(emoji) { if (!emoji) { diff --git a/src/embeds/EmbedWrapper.js b/src/embeds/EmbedWrapper.js index afe10499e..bd9572177 100644 --- a/src/embeds/EmbedWrapper.js +++ b/src/embeds/EmbedWrapper.js @@ -4,7 +4,7 @@ export default class EmbedWrapper extends EmbedBuilder { /** * convert to discord message * @param {boolean} ephemeral should the message be ephemeral - * @return {{ephemeral: boolean, embeds: this[]}} + * @returns {{ephemeral: boolean, embeds: this[]}} */ toMessage(ephemeral = true) { return {ephemeral, embeds: [this]}; diff --git a/src/embeds/ErrorEmbed.js b/src/embeds/ErrorEmbed.js index c6cfd955d..850622d31 100644 --- a/src/embeds/ErrorEmbed.js +++ b/src/embeds/ErrorEmbed.js @@ -13,7 +13,7 @@ export default class ErrorEmbed extends EmbedWrapper { /** * @param {string} description - * @return {{embeds: EmbedWrapper[]}} + * @returns {{embeds: EmbedWrapper[]}} */ static message(description) { return new this(description).toMessage(); diff --git a/src/embeds/KeyValueEmbed.js b/src/embeds/KeyValueEmbed.js index 349bf17ff..68565c1f4 100644 --- a/src/embeds/KeyValueEmbed.js +++ b/src/embeds/KeyValueEmbed.js @@ -1,12 +1,16 @@ import {bold} from 'discord.js'; import LineEmbed from './LineEmbed.js'; +/** + * @import {Iterable} from '@types/node'; + */ + export default class KeyValueEmbed extends LineEmbed { /** * add a line * @param {string} name * @param {string|number} value - * @return {this} + * @returns {this} */ addPair(name, value) { return this.addLine(bold(name) + ': ' + value); @@ -16,7 +20,7 @@ export default class KeyValueEmbed extends LineEmbed { * add a list of values * @param {string} name * @param {Iterable} list - * @return {KeyValueEmbed} + * @returns {KeyValueEmbed} */ addList(name, list) { this.addLine(bold(name) + ':'); @@ -30,7 +34,7 @@ export default class KeyValueEmbed extends LineEmbed { * add a list of values or a short enumeration for lists with up to 3 items * @param {string} name * @param {Array} list - * @return {KeyValueEmbed} + * @returns {KeyValueEmbed} */ addListOrShortList(name, list) { if (list.length > 3) { @@ -43,7 +47,7 @@ export default class KeyValueEmbed extends LineEmbed { * @param {*} condition * @param {string} name * @param {string|number} value - * @return {this} + * @returns {this} */ addPairIf(condition, name, value) { if (condition) { diff --git a/src/embeds/LineEmbed.js b/src/embeds/LineEmbed.js index 78fb500d6..481dc2d9e 100644 --- a/src/embeds/LineEmbed.js +++ b/src/embeds/LineEmbed.js @@ -24,7 +24,7 @@ export default class LineEmbed extends EmbedWrapper { /** * add a line * @param {string} content - * @return {this} + * @returns {this} */ addLine(content) { this.#lines.push(content); @@ -34,7 +34,7 @@ export default class LineEmbed extends EmbedWrapper { /** * add an empty line - * @return {this} + * @returns {this} */ newLine() { this.#lines.push(''); diff --git a/src/embeds/ModerationEmbed.js b/src/embeds/ModerationEmbed.js index da3a18352..5fb218b5e 100644 --- a/src/embeds/ModerationEmbed.js +++ b/src/embeds/ModerationEmbed.js @@ -3,6 +3,10 @@ import {resolveColor} from '../util/colors.js'; import {formatTime} from '../util/timeutils.js'; import KeyValueEmbed from './KeyValueEmbed.js'; +/** + * @import {Moderation} from '../models/Moderation.js'; + */ + export default class ModerationEmbed extends KeyValueEmbed { /** diff --git a/src/events/EventListener.js b/src/events/EventListener.js index 32531197a..9748a8281 100644 --- a/src/events/EventListener.js +++ b/src/events/EventListener.js @@ -7,7 +7,7 @@ export default class EventListener { /** * get the event name * @abstract - * @return {string} + * @returns {string} */ get name() { return 'message'; diff --git a/src/events/EventManager.js b/src/events/EventManager.js index ae58ebe3d..7523a9b08 100644 --- a/src/events/EventManager.js +++ b/src/events/EventManager.js @@ -1,10 +1,14 @@ import logger from '../bot/Logger.js'; +/** + * @import {EventListener} from '../../events/EventListener.js'; + */ + export default class EventManager { /** * @abstract - * @return {EventListener[]} + * @returns {EventListener[]} */ getEventListeners() { @@ -21,7 +25,7 @@ export default class EventManager { /** * @param {EventListener} eventListener * @param {*} args - * @return {Promise} + * @returns {Promise} */ async notifyEventListener(eventListener, ...args) { try { diff --git a/src/events/discord/BanRemoveEventListener.js b/src/events/discord/BanRemoveEventListener.js index f51e585aa..442c188b6 100644 --- a/src/events/discord/BanRemoveEventListener.js +++ b/src/events/discord/BanRemoveEventListener.js @@ -12,7 +12,7 @@ export default class BanRemoveEventListener extends EventListener { /** * @param {import('discord.js').GuildBan} ban - * @return {Promise} + * @returns {Promise} */ async execute(ban) { const databaseBan = await database.query( diff --git a/src/events/discord/ErrorEventListener.js b/src/events/discord/ErrorEventListener.js index 4b10d5680..937c22de8 100644 --- a/src/events/discord/ErrorEventListener.js +++ b/src/events/discord/ErrorEventListener.js @@ -8,7 +8,7 @@ export default class ErrorEventListener extends EventListener { /** * @param {Error} error - * @return {Promise} + * @returns {Promise} */ async execute(error) { await logger.error('The discord client experienced an error', error); diff --git a/src/events/discord/GuildAuditLogCreateEventListener.js b/src/events/discord/GuildAuditLogCreateEventListener.js index ffa8c1a66..9e5596026 100644 --- a/src/events/discord/GuildAuditLogCreateEventListener.js +++ b/src/events/discord/GuildAuditLogCreateEventListener.js @@ -11,7 +11,7 @@ export default class GuildAuditLogCreateEventListener extends EventListener { /** * @param {import('discord.js').GuildAuditLogsEntry} entry * @param {import('discord.js').Guild} guild - * @return {Promise} + * @returns {Promise} */ async execute(entry, guild) { if (!entry.executorId) { @@ -108,7 +108,7 @@ export default class GuildAuditLogCreateEventListener extends EventListener { * @param {import('discord.js').GuildAuditLogsEntry} entry * @param {import('discord.js').Guild} guild * @param {?number} [duration] - * @return {Promise} + * @returns {Promise} */ async createModeration(action, entry, guild, duration = null) { const member = new MemberWrapper(entry.target, guild); diff --git a/src/events/discord/GuildDeleteEventListener.js b/src/events/discord/GuildDeleteEventListener.js index 6a5bb1fba..734329496 100644 --- a/src/events/discord/GuildDeleteEventListener.js +++ b/src/events/discord/GuildDeleteEventListener.js @@ -8,7 +8,7 @@ export default class GuildDeleteEventListener extends EventListener { /** * @param {import('discord.js').Guild} guild - * @return {Promise[]>} + * @returns {Promise[]>} */ async execute(guild) { const wrapper = new GuildWrapper(guild); diff --git a/src/events/discord/GuildMemberRemoveEventListener.js b/src/events/discord/GuildMemberRemoveEventListener.js index f188f6f41..e9068adf0 100644 --- a/src/events/discord/GuildMemberRemoveEventListener.js +++ b/src/events/discord/GuildMemberRemoveEventListener.js @@ -11,7 +11,7 @@ export default class GuildMemberRemoveEventListener extends EventListener { /** * @param {import('discord.js').GuildMember} member - * @return {Promise} + * @returns {Promise} */ async execute(member) { const embed = new KeyValueEmbed() diff --git a/src/events/discord/MessageDeleteBulkEventListener.js b/src/events/discord/MessageDeleteBulkEventListener.js index ba65291b6..6d6a24dee 100644 --- a/src/events/discord/MessageDeleteBulkEventListener.js +++ b/src/events/discord/MessageDeleteBulkEventListener.js @@ -12,7 +12,7 @@ export default class MessageDeleteBulkEventListener extends EventListener { /** * @param {import('discord.js').Collection} messages * @param {import('discord.js').GuildTextBasedChannel} channel - * @return {Promise} + * @returns {Promise} */ async execute(messages, channel) { const embed = new EmbedBuilder() diff --git a/src/events/discord/MessageDeleteEventListener.js b/src/events/discord/MessageDeleteEventListener.js index 7858fb6b7..a9ef6de81 100644 --- a/src/events/discord/MessageDeleteEventListener.js +++ b/src/events/discord/MessageDeleteEventListener.js @@ -10,7 +10,7 @@ export default class MessageDeleteEventListener extends EventListener { /** * @param {import('discord.js').Message} message - * @return {Promise} + * @returns {Promise} */ async execute(message) { if (!message.guild || message.author.bot) { diff --git a/src/events/discord/WarnEventListener.js b/src/events/discord/WarnEventListener.js index 21c2108ad..a186ae888 100644 --- a/src/events/discord/WarnEventListener.js +++ b/src/events/discord/WarnEventListener.js @@ -8,7 +8,7 @@ export default class WarnEventListener extends EventListener { /** * @param {string} warning - * @return {Promise} + * @returns {Promise} */ async execute(warning) { await logger.warn({ diff --git a/src/events/discord/guildMemberAdd/GuildMemberAddEventListener.js b/src/events/discord/guildMemberAdd/GuildMemberAddEventListener.js index b36c1f2c7..9944a0a50 100644 --- a/src/events/discord/guildMemberAdd/GuildMemberAddEventListener.js +++ b/src/events/discord/guildMemberAdd/GuildMemberAddEventListener.js @@ -10,8 +10,8 @@ export default class GuildMemberAddEventListener extends EventListener { /** * @abstract - * @param {GuildMember} member - * @return {Promise} + * @param {import('discord.js').GuildMember} member + * @returns {Promise} */ async execute(member) { member.id; diff --git a/src/events/discord/interactionCreate/InteractionCreateEventListener.js b/src/events/discord/interactionCreate/InteractionCreateEventListener.js index 3823f69e7..3ab1906f2 100644 --- a/src/events/discord/interactionCreate/InteractionCreateEventListener.js +++ b/src/events/discord/interactionCreate/InteractionCreateEventListener.js @@ -7,7 +7,7 @@ export default class InteractionCreateEventListener extends EventListener { /** * @param {import('discord.js').Interaction} interaction - * @return {Promise} + * @returns {Promise} * @abstract */ async execute(interaction) { diff --git a/src/events/discord/messageCreate/AutoModEventListener.js b/src/events/discord/messageCreate/AutoModEventListener.js index 8830265bd..b65f235a2 100644 --- a/src/events/discord/messageCreate/AutoModEventListener.js +++ b/src/events/discord/messageCreate/AutoModEventListener.js @@ -4,7 +4,7 @@ import autoModManager from '../../../automod/AutoModManager.js'; export default class AutoModEventListener extends MessageCreateEventListener { /** * @param {import('discord.js').Message} message - * @return {Promise} + * @returns {Promise} */ async execute(message) { await autoModManager.checkMessage(message); diff --git a/src/events/discord/messageCreate/AutoResponseEventListener.js b/src/events/discord/messageCreate/AutoResponseEventListener.js index 3c586a9c4..991b5cdaa 100644 --- a/src/events/discord/messageCreate/AutoResponseEventListener.js +++ b/src/events/discord/messageCreate/AutoResponseEventListener.js @@ -24,7 +24,10 @@ export default class AutoResponseEventListener extends MessageCreateEventListene await AutoResponse.get(channel.id, message.guild.id) ).values()); const triggered = /** @type {AutoResponse[]} */ await asyncFilter(responses, - /** @param {AutoResponse} response */ + /** + * @param {AutoResponse} response + * @returns {Promise} + */ async response => { if (response.matches(message.content)) { return true; diff --git a/src/events/discord/messageCreate/MessageCreateEventListener.js b/src/events/discord/messageCreate/MessageCreateEventListener.js index 06629a873..4a61afc52 100644 --- a/src/events/discord/messageCreate/MessageCreateEventListener.js +++ b/src/events/discord/messageCreate/MessageCreateEventListener.js @@ -9,7 +9,7 @@ export default class MessageCreateEventListener extends EventListener { /** * @abstract * @param {import('discord.js').Message} message - * @return {Promise} + * @returns {Promise} */ async execute(message) { message.createdAt; diff --git a/src/events/discord/messageUpdate/MessageUpdateEventListener.js b/src/events/discord/messageUpdate/MessageUpdateEventListener.js index 240cf5a03..9e5ac4a66 100644 --- a/src/events/discord/messageUpdate/MessageUpdateEventListener.js +++ b/src/events/discord/messageUpdate/MessageUpdateEventListener.js @@ -6,7 +6,7 @@ export default class MessageUpdateEventListener extends EventListener { * @abstract * @param {import('discord.js').Message} oldMessage * @param {import('discord.js').Message} message - * @return {Promise} + * @returns {Promise} */ async execute(oldMessage, message) { return Promise.resolve(undefined); diff --git a/src/interval/Interval.js b/src/interval/Interval.js index 2085442a2..6f5d8a412 100644 --- a/src/interval/Interval.js +++ b/src/interval/Interval.js @@ -6,7 +6,7 @@ export default class Interval { /** * @abstract - * @return {number} timeout in ms + * @returns {number} timeout in ms */ getInterval() { return 1000; @@ -15,7 +15,7 @@ export default class Interval { /** * run the task * @abstract - * @return {Promise} + * @returns {Promise} */ async run() { diff --git a/src/interval/IntervalManager.js b/src/interval/IntervalManager.js index fca10d1df..f8bf41d35 100644 --- a/src/interval/IntervalManager.js +++ b/src/interval/IntervalManager.js @@ -6,7 +6,7 @@ import CleanupConfirmationInterval from './CleanupConfirmationInterval.js'; export default class IntervalManager { /** - * @type {Interval[]} + * @type {import('Interval.js')[]} */ #intervals = [ new UnbanInterval(), @@ -22,7 +22,7 @@ export default class IntervalManager { } /** - * @param {Interval} interval + * @param {import('Interval.js')} interval */ async runInterval(interval) { try { diff --git a/src/purge/PurgeFilter.js b/src/purge/PurgeFilter.js index 671112779..35f7424d8 100644 --- a/src/purge/PurgeFilter.js +++ b/src/purge/PurgeFilter.js @@ -9,7 +9,7 @@ export default class PurgeFilter { * Does this message match this filter? * @abstract * @param {import('discord.js').Message} message - * @return {boolean} + * @returns {boolean} */ matches(message) { throw new Error('Not implemented'); diff --git a/src/settings/ChannelSettings.js b/src/settings/ChannelSettings.js index 6f549c5d3..6010c7cb4 100644 --- a/src/settings/ChannelSettings.js +++ b/src/settings/ChannelSettings.js @@ -17,10 +17,10 @@ export default class ChannelSettings extends Settings { /** * @param {import('discord.js').Snowflake} id channel id - * @param {Object} [json] options - * @param {Boolean} [json.invites] allow invites - * @param {Object} [json.lock] permissions before locking (only affected perms) - * @return {ChannelSettings} the settings of the channel + * @param {object} [json] options + * @param {boolean} [json.invites] allow invites + * @param {object} [json.lock] permissions before locking (only affected perms) + * @returns {ChannelSettings} the settings of the channel */ constructor(id, json = {}) { super(id); @@ -31,7 +31,7 @@ export default class ChannelSettings extends Settings { /** * check if the types of this object are a valid guild settings - * @param {Object} json + * @param {object} json * @throws {TypeError} incorrect types */ static checkTypes(json) { @@ -44,7 +44,7 @@ export default class ChannelSettings extends Settings { /** * get all channel configs from this guild * @param {import('discord.js').Snowflake} guildID - * @return {Promise} + * @returns {Promise} */ static async getForGuild(guildID) { const result = []; @@ -56,7 +56,7 @@ export default class ChannelSettings extends Settings { /** * get the guildID of this channel - * @return {Promise} + * @returns {Promise} */ async getGuildID() { try { @@ -79,14 +79,14 @@ export default class ChannelSettings extends Settings { /** * @param {import('discord.js').Snowflake} guildID * @param {Settings} data - * @return {Promise} + * @returns {Promise} */ static async import(guildID, data) { let channel; try { channel = await bot.client.channels.fetch(data.id); } - catch (e) { + catch { return null; } diff --git a/src/settings/GuildSettings.js b/src/settings/GuildSettings.js index ba42b093f..024f916ff 100644 --- a/src/settings/GuildSettings.js +++ b/src/settings/GuildSettings.js @@ -11,29 +11,29 @@ import config from '../bot/Config.js'; import {deepMerge} from '../util/util.js'; /** - * @typedef {Object} SafeSearchSettings + * @typedef {object} SafeSearchSettings * @property {boolean} enabled * @property {number} strikes * @property {number} likelihood likelihood required for a message deletion (-3 to 2) */ /** - * @typedef {Object} GuildSettingsJSON + * @typedef {object} GuildSettingsJSON * @property {import('discord.js').Snowflake} [logChannel] id of the log channel * @property {import('discord.js').Snowflake} [messageLogChannel] id of the message log channel * @property {import('discord.js').Snowflake} [joinLogChannel] id of the join log channel * @property {import('discord.js').Snowflake} [mutedRole] id of the muted role * @property {import('discord.js').Snowflake[]} [modRoles] role ids that can execute commands * @property {import('discord.js').Snowflake[]} [protectedRoles] role ids that can't be targeted by moderations - * @property {Object} [punishments] automatic punishments for strikes - * @property {String} [playlist] id of YouTube playlist for tutorials - * @property {String} [helpcenter] subdomain of the zendesk help center - * @property {Boolean} [invites] allow invites (can be overwritten per channel) - * @property {Number} [linkCooldown] cooldown on links in s (user based) - * @property {Number} [attachmentCooldown] cooldown on attachments in s (user based) - * @property {Boolean} [caps] should caps be automatically deleted - * @property {Number} [antiSpam] should message spam detection be enabled - * @property {Number} [similarMessages] should similar message detection be enabled + * @property {object} [punishments] automatic punishments for strikes + * @property {string} [playlist] id of YouTube playlist for tutorials + * @property {string} [helpcenter] subdomain of the zendesk help center + * @property {boolean} [invites] allow invites (can be overwritten per channel) + * @property {number} [linkCooldown] cooldown on links in s (user based) + * @property {number} [attachmentCooldown] cooldown on attachments in s (user based) + * @property {boolean} [caps] should caps be automatically deleted + * @property {number} [antiSpam] should message spam detection be enabled + * @property {number} [similarMessages] should similar message detection be enabled * @property {?SafeSearchSettings} [safeSearch] safe search configuration */ @@ -78,8 +78,8 @@ export default class GuildSettings extends Settings { /** * @param {import('discord.js').Snowflake} id guild id - * @param {GuildSettingsJSON} [json={}] json object - * @return {GuildSettings} + * @param {GuildSettingsJSON} [json] json object + * @returns {GuildSettings} */ constructor(id, json = {}) { super(id); @@ -117,7 +117,7 @@ export default class GuildSettings extends Settings { /** * check if the types of this object are a valid guild settings - * @param {Object} json + * @param {object} json * @throws {TypeError} incorrect types */ static checkTypes(json) { @@ -154,8 +154,8 @@ export default class GuildSettings extends Settings { } /** - * @param {String} id - * @return {Promise} + * @param {string} id + * @returns {Promise} */ static async get(id) { return super.get(id); @@ -201,7 +201,7 @@ export default class GuildSettings extends Settings { /** * generate an overview of automod settings - * @returns {String} + * @returns {string} */ getAutomodSettings() { const lines = [ @@ -238,7 +238,7 @@ export default class GuildSettings extends Settings { /** * is this guild in the feature whitelist - * @return {boolean} + * @returns {boolean} */ get isFeatureWhitelisted() { return config.data.featureWhitelist.includes(this.id); @@ -248,7 +248,7 @@ export default class GuildSettings extends Settings { * Is this member protected? * @async * @param {import('discord.js').GuildMember} member member object of the user in the specific guild - * @return {Boolean} + * @returns {boolean} */ isProtected(member) { for (let [key] of member.roles.cache) { @@ -260,8 +260,8 @@ export default class GuildSettings extends Settings { /** * get a specific punishment - * @param {Number} strikes - * @return {?Punishment} + * @param {number} strikes + * @returns {?Punishment} */ getPunishment(strikes) { if (!this.#punishments[strikes]) { @@ -273,8 +273,8 @@ export default class GuildSettings extends Settings { /** * find the last punishment - * @param {Number} strikes - * @return {Punishment} + * @param {number} strikes + * @returns {Punishment} */ findPunishment(strikes) { let punishment; @@ -287,9 +287,9 @@ export default class GuildSettings extends Settings { /** * set a punishment - * @param {Number} strikes + * @param {number} strikes * @param {?Punishment} punishment - * @return {Promise<>} + * @returns {Promise} */ setPunishment(strikes, punishment) { if (punishment === null) @@ -301,7 +301,7 @@ export default class GuildSettings extends Settings { /** * get all punishments - * @return {Collection} + * @returns {Collection} */ getPunishments() { const punishments = new Collection(); @@ -315,7 +315,7 @@ export default class GuildSettings extends Settings { /** * get the zendesk instance for this guild - * @return {Zendesk} + * @returns {Zendesk} */ getZendesk() { if (!this.helpcenter) { @@ -327,7 +327,7 @@ export default class GuildSettings extends Settings { /** * get the YouTube playlist for this guild - * @return {YouTubePlaylist} + * @returns {YouTubePlaylist} */ getPlaylist() { if (!this.playlist) { @@ -338,7 +338,7 @@ export default class GuildSettings extends Settings { } /** - * @return {null|import('discord.js').Snowflake} + * @returns {null|import('discord.js').Snowflake} */ getMutedRole() { return this.mutedRole ?? null; diff --git a/src/settings/Settings.js b/src/settings/Settings.js index 5a73002ed..69c0f66ad 100644 --- a/src/settings/Settings.js +++ b/src/settings/Settings.js @@ -3,7 +3,7 @@ import database from '../bot/Database.js'; /** * Config cache time (ms) - * @type {Number} + * @type {number} */ const cacheDuration = 10*60*1000; @@ -20,12 +20,12 @@ export default class Settings { /** * table name - * @type {String} + * @type {string} */ static tableName; /** - * @type {NodeJS.Timer} + * @type {number} */ static clearCache = setInterval(() => { const cache = this.getCache(); @@ -37,17 +37,17 @@ export default class Settings { }, 60 * 1000); /** - * @type {String} + * @type {string} */ id; /** - * @type {Number} + * @type {number} */ createdAt; /** - * @param {String} id ID in the database + * @param {string} id ID in the database */ constructor(id) { this.id = id; @@ -55,7 +55,7 @@ export default class Settings { } /** - * @return {Collection} + * @returns {Collection} */ static getCache() { let cache = this.cache[this.tableName]; @@ -73,7 +73,7 @@ export default class Settings { /** * get the escaped table name - * @return {string} + * @returns {string} */ static get escapedTableName() { return database.escapeId(this.tableName); @@ -81,8 +81,8 @@ export default class Settings { /** * create an empty settings - * @param {String} key - * @return {this} + * @param {string} key + * @returns {this} */ static empty(key) { return new this(key); @@ -90,8 +90,8 @@ export default class Settings { /** * create a settings from a database result - * @param result - * @return {this} + * @param {{id: string, config: string}} result + * @returns {this} */ static create(result) { return new this(result.id, JSON.parse(result.config)); @@ -100,7 +100,7 @@ export default class Settings { /** * Save to db and cache * @async - * @return {Promise<>} + * @returns {Promise} */ async save() { const result = await this._select(); @@ -113,8 +113,9 @@ export default class Settings { } /** - * Get this settings from the DB - * @return {Promise} + * Get these settings from the DB + * @param {string} key + * @returns {Promise} * @private */ static async _select(key) { @@ -122,8 +123,8 @@ export default class Settings { } /** - * Get this settings from the DB - * @return {Promise} + * Get these settings from the DB + * @returns {Promise} * @private */ async _select() { @@ -132,7 +133,7 @@ export default class Settings { /** * Update this settings in the DB - * @return {Promise} + * @returns {Promise} * @private */ async _update() { @@ -142,7 +143,7 @@ export default class Settings { /** * Insert a settings into the DB - * @return {Promise} + * @returns {Promise} * @protected */ async insert() { @@ -152,8 +153,8 @@ export default class Settings { /** * Get settings - * @param {String} id - * @return {Promise} + * @param {string} id + * @returns {Promise} */ static async get(id) { const cache = this.getCache(); @@ -169,7 +170,7 @@ export default class Settings { /** * convert to JSON string - * @return {string} + * @returns {string} */ toJSONString() { return JSON.stringify(this.getDataObject()); @@ -178,7 +179,7 @@ export default class Settings { /** * get a clean data object * @param {this} [original] - * @return {this} + * @returns {this} */ getDataObject(original = this) { //copy to new object diff --git a/src/settings/TypeChecker.js b/src/settings/TypeChecker.js index 0b8ebcbc8..3e65fcd68 100644 --- a/src/settings/TypeChecker.js +++ b/src/settings/TypeChecker.js @@ -1,9 +1,9 @@ export default class TypeChecker { /** * check if value has correct type, otherwise throw a type error - * @param value + * @param {*} value * @param {("undefined"|"object"|"boolean"|"number"|"string"|"function"|"symbol"|"bigint")[]} types - * @param {String} name + * @param {string} name * @param {boolean} [allowNull] * @throws {TypeError} */ @@ -18,42 +18,42 @@ export default class TypeChecker { /** * check if value is a number or undefined - * @param value - * @param {String} name + * @param {*} value + * @param {string} name */ static assertNumberUndefinedOrNull(value, name) { - return this.assertOfTypes(value, ['number', 'undefined'], name, true); + this.assertOfTypes(value, ['number', 'undefined'], name, true); } /** * check if value is a number - * @param value - * @param {String} name + * @param {*} value + * @param {string} name */ static assertNumber(value, name) { - return this.assertOfTypes(value, ['number'], name); + this.assertOfTypes(value, ['number'], name); } /** * check if value is a string or undefined - * @param value - * @param {String} name + * @param {*} value + * @param {string} name */ static assertStringUndefinedOrNull(value, name) { - return this.assertOfTypes(value, ['string', 'undefined'], name, true); + this.assertOfTypes(value, ['string', 'undefined'], name, true); } /** * check if value is a string - * @param value - * @param {String} name + * @param {*} value + * @param {string} name */ static assertString(value, name) { - return this.assertOfTypes(value, ['string'], name); + this.assertOfTypes(value, ['string'], name); } static assertBooleanOrNull(value, name) { - return this.assertOfTypes(value, ['boolean'], name, true); + this.assertOfTypes(value, ['boolean'], name, true); } } \ No newline at end of file diff --git a/src/settings/UserSettings.js b/src/settings/UserSettings.js index 0f45c7d3c..ec27ae624 100644 --- a/src/settings/UserSettings.js +++ b/src/settings/UserSettings.js @@ -6,9 +6,9 @@ export default class UserSettings extends Settings { /** * @param {import('discord.js').Snowflake} id user id - * @param {Object} [json] options + * @param {object} [json] options * @param {boolean} [json.deleteCommands] should commands be deleted automatically - * @return {UserSettings} the settings of the channel + * @returns {UserSettings} the settings of the channel */ constructor(id, json = {}) { super(id); @@ -16,7 +16,7 @@ export default class UserSettings extends Settings { /** * @param {import('discord.js').Snowflake} userid - * @return {Promise} + * @returns {Promise} */ static async get(userid) { return super.get(userid); diff --git a/src/util/channels.js b/src/util/channels.js index ab26cd34d..087792f2f 100644 --- a/src/util/channels.js +++ b/src/util/channels.js @@ -2,9 +2,9 @@ import {StringSelectMenuBuilder} from 'discord.js'; import {SELECT_MENU_OPTIONS_LIMIT} from './apiLimits.js'; /** - * @param {ChannelWrapper[]} channels + * @param {import('../discord/ChannelWrapper.js')[]} channels * @param {import('discord.js').Snowflake[]} defaultChannels - * @return {import('discord.js').StringSelectMenuBuilder} + * @returns {import('discord.js').StringSelectMenuBuilder} */ export function channelSelectMenu(channels, defaultChannels = []) { return new StringSelectMenuBuilder() diff --git a/src/util/colors.js b/src/util/colors.js index 2b55ad8a6..37415ead0 100644 --- a/src/util/colors.js +++ b/src/util/colors.js @@ -5,8 +5,8 @@ export default {RED, ORANGE, GREEN}; /** * Resolves an action to a color - * @param {String} action name of the action to resolve - * @return {Number|null} hex color code or null + * @param {string} action name of the action to resolve + * @returns {number|null} hex color code or null */ export function resolveColor(action) { switch (action.toLowerCase()) { diff --git a/src/util/format.js b/src/util/format.js index 87ac94f51..8bbb7995b 100644 --- a/src/util/format.js +++ b/src/util/format.js @@ -4,7 +4,7 @@ import {formatEmoji} from 'discord.js'; /** * convert a string to title case * @param {string} s - * @return {string} + * @returns {string} */ export function toTitleCase(s) { return s.toLowerCase().replace(/^(\w)|\s(\w)/g, c => c.toUpperCase()); @@ -12,7 +12,7 @@ export function toTitleCase(s) { /** * @param {*} bool - * @return {string} + * @returns {string} */ export function yesNo(bool) { return bool ? 'Yes' : 'No'; @@ -20,7 +20,7 @@ export function yesNo(bool) { /** * @param {string} configKey - * @return {string} + * @returns {string} */ export function inlineEmojiIfExists(configKey) { const emoji = config.data.emoji[configKey]; @@ -37,7 +37,7 @@ export function inlineEmojiIfExists(configKey) { * Add s if number is not 1 * @param {number} number * @param {string} name - * @return {*} + * @returns {*} */ export function formatNumber(number, name) { if (number === 1) { @@ -49,7 +49,7 @@ export function formatNumber(number, name) { /** * @param {string} configKey name of the emoji in the config * @param {?string} fallback emoji character to use if the config key is not set - * @return {?import('discord.js').APIMessageComponentEmoji} + * @returns {?import('discord.js').APIMessageComponentEmoji} */ export function componentEmojiIfExists(configKey, fallback = null) { const emoji = config.data.emoji[configKey]; diff --git a/src/util/fsutils.js b/src/util/fsutils.js index f79887adc..9fa063b22 100644 --- a/src/util/fsutils.js +++ b/src/util/fsutils.js @@ -3,7 +3,7 @@ import {readFile} from 'fs/promises'; /** * @param {string} path - * @return {Promise} + * @returns {Promise} */ export async function exists(path) { try { @@ -21,7 +21,7 @@ export async function exists(path) { /** * read a json file * @param {string} path - * @return {Promise<*>} + * @returns {Promise<*>} */ export async function readJSON(path) { return JSON.parse((await readFile(path)).toString()); diff --git a/src/util/interaction.js b/src/util/interaction.js index 86cb001bf..542b73c7b 100644 --- a/src/util/interaction.js +++ b/src/util/interaction.js @@ -2,7 +2,7 @@ * Reply to an interaction if it wasn't already deferred or replied. Follow up otherwise. * @param {import('discord.js').Interaction} interaction * @param {string | import('discord.js').MessagePayload | import('discord.js').InteractionReplyOptions} options - * @return {Promise} + * @returns {Promise} */ export async function replyOrFollowUp(interaction, options) { if (interaction.deferred || interaction.replied) { @@ -17,7 +17,7 @@ export async function replyOrFollowUp(interaction, options) { * Reply to an interaction if it wasn't already deferred or replied. Edit the response otherwise. * @param {import('discord.js').Interaction} interaction * @param {string | import('discord.js').MessagePayload | import('discord.js').InteractionReplyOptions} options - * @return {Promise} + * @returns {Promise} */ export async function replyOrEdit(interaction, options) { if (interaction.deferred || interaction.replied) { @@ -32,7 +32,7 @@ export async function replyOrEdit(interaction, options) { * Defer a reply to an interaction if it wasn't already deferred or replied. * @param {import('discord.js').Interaction} interaction interaction to defer * @param {boolean} ephemeral should the reply be ephemeral - * @return {Promise} + * @returns {Promise} */ export async function deferReplyOnce(interaction, ephemeral = true) { if (!interaction.deferred && !interaction.replied) { diff --git a/src/util/timeutils.js b/src/util/timeutils.js index 8a4db37b7..767b9c857 100644 --- a/src/util/timeutils.js +++ b/src/util/timeutils.js @@ -1,7 +1,7 @@ /** * parse this time string to a duration in seconds * @param {?string} string - * @return {?number} null if no time was included in the string + * @returns {?number} null if no time was included in the string */ export function parseTime(string) { if (!string) { @@ -52,7 +52,7 @@ export function parseTime(string) { /** * format this duration as a string * @param {number} duration in seconds - * @return {string} + * @returns {string} */ export function formatTime(duration) { let output = ''; @@ -79,7 +79,7 @@ export function formatTime(duration) { /** * current time as a unix timestamp (seconds) - * @return {number} + * @returns {number} */ export function timeNow() { return Math.floor(Date.now() / 1000); @@ -88,7 +88,7 @@ export function timeNow() { /** * return time after duration has expired as unix timestamp (seconds) * @param {string} duration - * @return {number} + * @returns {number} */ export function timeAfter(duration) { return timeNow() + (parseTime(duration) ?? 0); diff --git a/src/util/util.js b/src/util/util.js index a1547db67..793fda0fc 100644 --- a/src/util/util.js +++ b/src/util/util.js @@ -1,12 +1,12 @@ /** * Retries a function if it fails * @async - * @param {function} fn function to retry - * @param {Object} thisArg object that should execute the function - * @param {Array} [args=[]] arguments to pass to the function - * @param {Number} [maxRetries=5] amount of retries before throwing an error - * @param {function} [returnValMatch] function to test the result on - * @return {*} result of fn + * @param {Function} fn function to retry + * @param {object} thisArg object that should execute the function + * @param {Array} [args] arguments to pass to the function + * @param {number} [maxRetries] amount of retries before throwing an error + * @param {Function} [returnValMatch] function to test the result on + * @returns {*} result of fn */ export async function retry(fn, thisArg, args = [], maxRetries = 5, returnValMatch = null) { let err; @@ -27,13 +27,21 @@ export async function retry(fn, thisArg, args = [], maxRetries = 5, returnValMat throw err; } +/** + * @template T + * @callback AsyncFilterCallback + * @param {T} element + * @param {...*} args + * @returns {Promise} + */ + /** * - * @template T, Z + * @template T * @param {T[]} array - * @param {Function} filter - * @param args - * @return {Promise} + * @param {AsyncFilterCallback} filter + * @param {*} args + * @returns {Promise} */ export async function asyncFilter(array, filter, ...args) { const results = []; @@ -53,6 +61,7 @@ export async function asyncFilter(array, filter, ...args) { * @param {number} value * @param {number} min * @param {number} max + * @returns {number} */ export function inLimits(value, min, max) { if (isNaN(value)) { @@ -64,9 +73,9 @@ export function inLimits(value, min, max) { /** * deep merge two objects - * @param {Object} target - * @param {Object} source - * @return {Object} + * @param {object} target + * @param {object} source + * @returns {object} */ export function deepMerge(target, source) { for (const key in source) { @@ -84,8 +93,8 @@ export function deepMerge(target, source) { /** * escape a regular expression - * @param string - * @return {string} + * @param {string} string + * @returns {string} */ export function escapeRegExp(string) { return string.replace(/[.*+?^${}()|[\]\\]/g, '\\$&');