first commit
This commit is contained in:
157
node_modules/discord.js-commando/.eslintrc.json
generated
vendored
Normal file
157
node_modules/discord.js-commando/.eslintrc.json
generated
vendored
Normal file
@@ -0,0 +1,157 @@
|
||||
{
|
||||
"extends": "eslint:recommended",
|
||||
"env": {
|
||||
"node": true,
|
||||
"es6": true
|
||||
},
|
||||
"parserOptions": {
|
||||
"ecmaVersion": 2018
|
||||
},
|
||||
"rules": {
|
||||
"no-await-in-loop": "warn",
|
||||
"no-compare-neg-zero": "error",
|
||||
"no-extra-parens": ["warn", "all", {
|
||||
"nestedBinaryExpressions": false
|
||||
}],
|
||||
"no-template-curly-in-string": "error",
|
||||
"no-unsafe-negation": "error",
|
||||
"valid-jsdoc": ["warn", {
|
||||
"requireReturn": false,
|
||||
"requireReturnDescription": false,
|
||||
"preferType": {
|
||||
"String": "string",
|
||||
"Number": "number",
|
||||
"Boolean": "boolean",
|
||||
"Symbol": "symbol",
|
||||
"function": "Function",
|
||||
"object": "Object",
|
||||
"date": "Date",
|
||||
"error": "Error"
|
||||
}
|
||||
}],
|
||||
|
||||
"accessor-pairs": "warn",
|
||||
"array-callback-return": "error",
|
||||
"complexity": "warn",
|
||||
"consistent-return": "error",
|
||||
"curly": ["error", "multi-line", "consistent"],
|
||||
"dot-location": ["error", "property"],
|
||||
"dot-notation": "error",
|
||||
"eqeqeq": "error",
|
||||
"no-empty-function": "error",
|
||||
"no-floating-decimal": "error",
|
||||
"no-implied-eval": "error",
|
||||
"no-invalid-this": "error",
|
||||
"no-lone-blocks": "error",
|
||||
"no-multi-spaces": "error",
|
||||
"no-new-func": "error",
|
||||
"no-new-wrappers": "error",
|
||||
"no-new": "error",
|
||||
"no-octal-escape": "error",
|
||||
"no-return-assign": "error",
|
||||
"no-return-await": "error",
|
||||
"no-self-compare": "error",
|
||||
"no-sequences": "error",
|
||||
"no-throw-literal": "error",
|
||||
"no-unmodified-loop-condition": "error",
|
||||
"no-unused-expressions": "error",
|
||||
"no-useless-call": "error",
|
||||
"no-useless-concat": "error",
|
||||
"no-useless-escape": "error",
|
||||
"no-useless-return": "error",
|
||||
"no-void": "error",
|
||||
"no-warning-comments": "warn",
|
||||
"prefer-promise-reject-errors": "error",
|
||||
"require-await": "warn",
|
||||
"wrap-iife": "error",
|
||||
"yoda": "error",
|
||||
|
||||
"no-label-var": "error",
|
||||
"no-var": "error",
|
||||
"no-shadow": "error",
|
||||
"no-undef-init": "error",
|
||||
|
||||
"callback-return": "error",
|
||||
"handle-callback-err": "error",
|
||||
"no-mixed-requires": "error",
|
||||
"no-new-require": "error",
|
||||
"no-path-concat": "error",
|
||||
"no-process-env": "error",
|
||||
|
||||
"array-bracket-spacing": "error",
|
||||
"block-spacing": "error",
|
||||
"brace-style": ["error", "1tbs", { "allowSingleLine": true }],
|
||||
"camelcase": "error",
|
||||
"capitalized-comments": ["error", "always", { "ignoreConsecutiveComments": true }],
|
||||
"comma-dangle": "error",
|
||||
"comma-spacing": "error",
|
||||
"comma-style": "error",
|
||||
"computed-property-spacing": "error",
|
||||
"consistent-this": "error",
|
||||
"eol-last": "error",
|
||||
"func-names": "error",
|
||||
"func-style": ["error", "declaration", { "allowArrowFunctions": true }],
|
||||
"id-length": ["error", { "exceptions": ["i", "j", "a", "b"] }],
|
||||
"indent": "off",
|
||||
"indent-legacy": ["error", "tab", { "SwitchCase": 1 }],
|
||||
"key-spacing": "error",
|
||||
"keyword-spacing": ["error", {
|
||||
"overrides": {
|
||||
"if": { "after": false },
|
||||
"for": { "after": false },
|
||||
"while": { "after": false },
|
||||
"catch": { "after": false },
|
||||
"switch": { "after": false }
|
||||
}
|
||||
}],
|
||||
"max-depth": "error",
|
||||
"max-len": ["error", 120, 2],
|
||||
"max-nested-callbacks": ["error", { "max": 4 }],
|
||||
"max-statements-per-line": ["error", { "max": 2 }],
|
||||
"new-cap": "error",
|
||||
"newline-per-chained-call": ["error", { "ignoreChainWithDepth": 3 }],
|
||||
"no-array-constructor": "error",
|
||||
"no-bitwise": "warn",
|
||||
"no-inline-comments": "error",
|
||||
"no-lonely-if": "error",
|
||||
"no-mixed-operators": "error",
|
||||
"no-multiple-empty-lines": ["error", { "max": 2, "maxEOF": 1, "maxBOF": 0 }],
|
||||
"no-new-object": "error",
|
||||
"no-spaced-func": "error",
|
||||
"no-trailing-spaces": "error",
|
||||
"no-unneeded-ternary": "error",
|
||||
"no-whitespace-before-property": "error",
|
||||
"nonblock-statement-body-position": "error",
|
||||
"object-curly-newline": "error",
|
||||
"object-curly-spacing": ["error", "always"],
|
||||
"operator-assignment": "error",
|
||||
"operator-linebreak": ["error", "after"],
|
||||
"padded-blocks": ["error", "never"],
|
||||
"quote-props": ["error", "as-needed"],
|
||||
"quotes": ["error", "single", { "avoidEscape": true, "allowTemplateLiterals": true }],
|
||||
"semi-spacing": "error",
|
||||
"semi": "error",
|
||||
"space-before-blocks": "error",
|
||||
"space-before-function-paren": ["error", "never"],
|
||||
"space-in-parens": "error",
|
||||
"space-infix-ops": "error",
|
||||
"space-unary-ops": "error",
|
||||
"spaced-comment": "error",
|
||||
"template-tag-spacing": "error",
|
||||
"unicode-bom": "error",
|
||||
|
||||
"arrow-body-style": "error",
|
||||
"arrow-parens": ["error", "as-needed"],
|
||||
"arrow-spacing": "error",
|
||||
"no-duplicate-imports": "error",
|
||||
"no-useless-computed-key": "error",
|
||||
"no-useless-constructor": "error",
|
||||
"prefer-arrow-callback": "error",
|
||||
"prefer-rest-params": "error",
|
||||
"prefer-spread": "error",
|
||||
"prefer-template": "error",
|
||||
"rest-spread-spacing": "error",
|
||||
"template-curly-spacing": "error",
|
||||
"yield-star-spacing": "error"
|
||||
}
|
||||
}
|
||||
1
node_modules/discord.js-commando/.gitattributes
generated
vendored
Normal file
1
node_modules/discord.js-commando/.gitattributes
generated
vendored
Normal file
@@ -0,0 +1 @@
|
||||
* text=auto eol=lf
|
||||
29
node_modules/discord.js-commando/.github/workflows/deploy.sh
generated
vendored
Normal file
29
node_modules/discord.js-commando/.github/workflows/deploy.sh
generated
vendored
Normal file
@@ -0,0 +1,29 @@
|
||||
#!/bin/bash
|
||||
set -euxo pipefail
|
||||
|
||||
echo -e "\n# Initialise some useful variables"
|
||||
REPO="https://${GITHUB_ACTOR}:${GITHUB_TOKEN}@github.com/${GITHUB_REPOSITORY}.git"
|
||||
BRANCH_OR_TAG=`awk -F/ '{print $2}' <<< $GITHUB_REF`
|
||||
CURRENT_BRANCH=`awk -F/ '{print $NF}' <<< $GITHUB_REF`
|
||||
|
||||
if [ "$BRANCH_OR_TAG" == "heads" ]; then
|
||||
SOURCE_TYPE="branch"
|
||||
else
|
||||
SOURCE_TYPE="tag"
|
||||
fi
|
||||
|
||||
echo -e "\n# Checkout the repo in the target branch"
|
||||
TARGET_BRANCH="docs"
|
||||
git clone $REPO out -b $TARGET_BRANCH
|
||||
|
||||
echo -e "\n# Move the generated JSON file to the newly-checked-out repo, to be committed and pushed"
|
||||
mv docs/docs.json out/$CURRENT_BRANCH.json
|
||||
|
||||
echo -e "\n# Commit and push"
|
||||
cd out
|
||||
git pull
|
||||
git add .
|
||||
git config user.name "${GITHUB_ACTOR}"
|
||||
git config user.email "${GITHUB_ACTOR}@users.noreply.github.com"
|
||||
git commit -m "Docs build for ${SOURCE_TYPE} ${CURRENT_BRANCH}: ${GITHUB_SHA}" || true
|
||||
git push origin $TARGET_BRANCH
|
||||
30
node_modules/discord.js-commando/.github/workflows/deploy.yml
generated
vendored
Normal file
30
node_modules/discord.js-commando/.github/workflows/deploy.yml
generated
vendored
Normal file
@@ -0,0 +1,30 @@
|
||||
name: Deployment
|
||||
on:
|
||||
push:
|
||||
branches:
|
||||
- '*'
|
||||
- '!gh-action'
|
||||
- '!docs'
|
||||
jobs:
|
||||
docs:
|
||||
name: Documentation
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- name: Checkout repository
|
||||
uses: actions/checkout@v1
|
||||
|
||||
- name: Install Node v12
|
||||
uses: actions/setup-node@v1
|
||||
with:
|
||||
node-version: 12
|
||||
|
||||
- name: Install dependencies
|
||||
run: yarn
|
||||
|
||||
- name: Build documentation
|
||||
run: yarn docs
|
||||
|
||||
- name: Deploy documentation
|
||||
run: bash ./.github/workflows/deploy.sh
|
||||
env:
|
||||
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
||||
42
node_modules/discord.js-commando/.github/workflows/test.yml
generated
vendored
Normal file
42
node_modules/discord.js-commando/.github/workflows/test.yml
generated
vendored
Normal file
@@ -0,0 +1,42 @@
|
||||
name: Testing
|
||||
on: [push, pull_request]
|
||||
jobs:
|
||||
lint:
|
||||
name: ESLint
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- name: Checkout repository
|
||||
uses: actions/checkout@v1
|
||||
|
||||
- name: Install Node v12
|
||||
uses: actions/setup-node@v1
|
||||
with:
|
||||
node-version: 12
|
||||
|
||||
- name: Install dependencies
|
||||
run: yarn
|
||||
|
||||
- name: Run ESLint
|
||||
uses: discordjs/action-eslint@v1
|
||||
env:
|
||||
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
||||
with:
|
||||
job-name: ESLint
|
||||
|
||||
docs:
|
||||
name: Documentation
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- name: Checkout repository
|
||||
uses: actions/checkout@v1
|
||||
|
||||
- name: Install Node v12
|
||||
uses: actions/setup-node@v1
|
||||
with:
|
||||
node-version: 12
|
||||
|
||||
- name: Install dependencies
|
||||
run: yarn
|
||||
|
||||
- name: Test documentation
|
||||
run: yarn docs:test
|
||||
190
node_modules/discord.js-commando/LICENSE
generated
vendored
Normal file
190
node_modules/discord.js-commando/LICENSE
generated
vendored
Normal file
@@ -0,0 +1,190 @@
|
||||
Apache License
|
||||
Version 2.0, January 2004
|
||||
http://www.apache.org/licenses/
|
||||
|
||||
TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
|
||||
|
||||
1. Definitions.
|
||||
|
||||
"License" shall mean the terms and conditions for use, reproduction,
|
||||
and distribution as defined by Sections 1 through 9 of this document.
|
||||
|
||||
"Licensor" shall mean the copyright owner or entity authorized by
|
||||
the copyright owner that is granting the License.
|
||||
|
||||
"Legal Entity" shall mean the union of the acting entity and all
|
||||
other entities that control, are controlled by, or are under common
|
||||
control with that entity. For the purposes of this definition,
|
||||
"control" means (i) the power, direct or indirect, to cause the
|
||||
direction or management of such entity, whether by contract or
|
||||
otherwise, or (ii) ownership of fifty percent (50%) or more of the
|
||||
outstanding shares, or (iii) beneficial ownership of such entity.
|
||||
|
||||
"You" (or "Your") shall mean an individual or Legal Entity
|
||||
exercising permissions granted by this License.
|
||||
|
||||
"Source" form shall mean the preferred form for making modifications,
|
||||
including but not limited to software source code, documentation
|
||||
source, and configuration files.
|
||||
|
||||
"Object" form shall mean any form resulting from mechanical
|
||||
transformation or translation of a Source form, including but
|
||||
not limited to compiled object code, generated documentation,
|
||||
and conversions to other media types.
|
||||
|
||||
"Work" shall mean the work of authorship, whether in Source or
|
||||
Object form, made available under the License, as indicated by a
|
||||
copyright notice that is included in or attached to the work
|
||||
(an example is provided in the Appendix below).
|
||||
|
||||
"Derivative Works" shall mean any work, whether in Source or Object
|
||||
form, that is based on (or derived from) the Work and for which the
|
||||
editorial revisions, annotations, elaborations, or other modifications
|
||||
represent, as a whole, an original work of authorship. For the purposes
|
||||
of this License, Derivative Works shall not include works that remain
|
||||
separable from, or merely link (or bind by name) to the interfaces of,
|
||||
the Work and Derivative Works thereof.
|
||||
|
||||
"Contribution" shall mean any work of authorship, including
|
||||
the original version of the Work and any modifications or additions
|
||||
to that Work or Derivative Works thereof, that is intentionally
|
||||
submitted to Licensor for inclusion in the Work by the copyright owner
|
||||
or by an individual or Legal Entity authorized to submit on behalf of
|
||||
the copyright owner. For the purposes of this definition, "submitted"
|
||||
means any form of electronic, verbal, or written communication sent
|
||||
to the Licensor or its representatives, including but not limited to
|
||||
communication on electronic mailing lists, source code control systems,
|
||||
and issue tracking systems that are managed by, or on behalf of, the
|
||||
Licensor for the purpose of discussing and improving the Work, but
|
||||
excluding communication that is conspicuously marked or otherwise
|
||||
designated in writing by the copyright owner as "Not a Contribution."
|
||||
|
||||
"Contributor" shall mean Licensor and any individual or Legal Entity
|
||||
on behalf of whom a Contribution has been received by Licensor and
|
||||
subsequently incorporated within the Work.
|
||||
|
||||
2. Grant of Copyright License. Subject to the terms and conditions of
|
||||
this License, each Contributor hereby grants to You a perpetual,
|
||||
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
|
||||
copyright license to reproduce, prepare Derivative Works of,
|
||||
publicly display, publicly perform, sublicense, and distribute the
|
||||
Work and such Derivative Works in Source or Object form.
|
||||
|
||||
3. Grant of Patent License. Subject to the terms and conditions of
|
||||
this License, each Contributor hereby grants to You a perpetual,
|
||||
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
|
||||
(except as stated in this section) patent license to make, have made,
|
||||
use, offer to sell, sell, import, and otherwise transfer the Work,
|
||||
where such license applies only to those patent claims licensable
|
||||
by such Contributor that are necessarily infringed by their
|
||||
Contribution(s) alone or by combination of their Contribution(s)
|
||||
with the Work to which such Contribution(s) was submitted. If You
|
||||
institute patent litigation against any entity (including a
|
||||
cross-claim or counterclaim in a lawsuit) alleging that the Work
|
||||
or a Contribution incorporated within the Work constitutes direct
|
||||
or contributory patent infringement, then any patent licenses
|
||||
granted to You under this License for that Work shall terminate
|
||||
as of the date such litigation is filed.
|
||||
|
||||
4. Redistribution. You may reproduce and distribute copies of the
|
||||
Work or Derivative Works thereof in any medium, with or without
|
||||
modifications, and in Source or Object form, provided that You
|
||||
meet the following conditions:
|
||||
|
||||
(a) You must give any other recipients of the Work or
|
||||
Derivative Works a copy of this License; and
|
||||
|
||||
(b) You must cause any modified files to carry prominent notices
|
||||
stating that You changed the files; and
|
||||
|
||||
(c) You must retain, in the Source form of any Derivative Works
|
||||
that You distribute, all copyright, patent, trademark, and
|
||||
attribution notices from the Source form of the Work,
|
||||
excluding those notices that do not pertain to any part of
|
||||
the Derivative Works; and
|
||||
|
||||
(d) If the Work includes a "NOTICE" text file as part of its
|
||||
distribution, then any Derivative Works that You distribute must
|
||||
include a readable copy of the attribution notices contained
|
||||
within such NOTICE file, excluding those notices that do not
|
||||
pertain to any part of the Derivative Works, in at least one
|
||||
of the following places: within a NOTICE text file distributed
|
||||
as part of the Derivative Works; within the Source form or
|
||||
documentation, if provided along with the Derivative Works; or,
|
||||
within a display generated by the Derivative Works, if and
|
||||
wherever such third-party notices normally appear. The contents
|
||||
of the NOTICE file are for informational purposes only and
|
||||
do not modify the License. You may add Your own attribution
|
||||
notices within Derivative Works that You distribute, alongside
|
||||
or as an addendum to the NOTICE text from the Work, provided
|
||||
that such additional attribution notices cannot be construed
|
||||
as modifying the License.
|
||||
|
||||
You may add Your own copyright statement to Your modifications and
|
||||
may provide additional or different license terms and conditions
|
||||
for use, reproduction, or distribution of Your modifications, or
|
||||
for any such Derivative Works as a whole, provided Your use,
|
||||
reproduction, and distribution of the Work otherwise complies with
|
||||
the conditions stated in this License.
|
||||
|
||||
5. Submission of Contributions. Unless You explicitly state otherwise,
|
||||
any Contribution intentionally submitted for inclusion in the Work
|
||||
by You to the Licensor shall be under the terms and conditions of
|
||||
this License, without any additional terms or conditions.
|
||||
Notwithstanding the above, nothing herein shall supersede or modify
|
||||
the terms of any separate license agreement you may have executed
|
||||
with Licensor regarding such Contributions.
|
||||
|
||||
6. Trademarks. This License does not grant permission to use the trade
|
||||
names, trademarks, service marks, or product names of the Licensor,
|
||||
except as required for reasonable and customary use in describing the
|
||||
origin of the Work and reproducing the content of the NOTICE file.
|
||||
|
||||
7. Disclaimer of Warranty. Unless required by applicable law or
|
||||
agreed to in writing, Licensor provides the Work (and each
|
||||
Contributor provides its Contributions) on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
|
||||
implied, including, without limitation, any warranties or conditions
|
||||
of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
|
||||
PARTICULAR PURPOSE. You are solely responsible for determining the
|
||||
appropriateness of using or redistributing the Work and assume any
|
||||
risks associated with Your exercise of permissions under this License.
|
||||
|
||||
8. Limitation of Liability. In no event and under no legal theory,
|
||||
whether in tort (including negligence), contract, or otherwise,
|
||||
unless required by applicable law (such as deliberate and grossly
|
||||
negligent acts) or agreed to in writing, shall any Contributor be
|
||||
liable to You for damages, including any direct, indirect, special,
|
||||
incidental, or consequential damages of any character arising as a
|
||||
result of this License or out of the use or inability to use the
|
||||
Work (including but not limited to damages for loss of goodwill,
|
||||
work stoppage, computer failure or malfunction, or any and all
|
||||
other commercial damages or losses), even if such Contributor
|
||||
has been advised of the possibility of such damages.
|
||||
|
||||
9. Accepting Warranty or Additional Liability. While redistributing
|
||||
the Work or Derivative Works thereof, You may choose to offer,
|
||||
and charge a fee for, acceptance of support, warranty, indemnity,
|
||||
or other liability obligations and/or rights consistent with this
|
||||
License. However, in accepting such obligations, You may act only
|
||||
on Your own behalf and on Your sole responsibility, not on behalf
|
||||
of any other Contributor, and only if You agree to indemnify,
|
||||
defend, and hold each Contributor harmless for any liability
|
||||
incurred by, or claims asserted against, such Contributor by reason
|
||||
of your accepting any such warranty or additional liability.
|
||||
|
||||
END OF TERMS AND CONDITIONS
|
||||
|
||||
Copyright 2017 Schuyler Cebulskie
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
38
node_modules/discord.js-commando/README.md
generated
vendored
Normal file
38
node_modules/discord.js-commando/README.md
generated
vendored
Normal file
@@ -0,0 +1,38 @@
|
||||
# Commando
|
||||
[](https://discord.gg/bRCvFy9)
|
||||
[](https://www.npmjs.com/package/discord.js-commando)
|
||||
[](https://www.npmjs.com/package/discord.js-commando)
|
||||
[](https://david-dm.org/discordjs/Commando)
|
||||
[](https://github.com/discordjs/Commando/actions?query=workflow%3ATesting)
|
||||
|
||||
## About
|
||||
Commando is the official command framework for [discord.js](https://github.com/discordjs/discord.js).
|
||||
It is flexible, fully object-oriented, easy to use, and makes it trivial to create your own powerful commands.
|
||||
Additionally, it makes full use of ES2017's `async`/`await` functionality for clear, concise code that is simple to write and easy to comprehend.
|
||||
|
||||
## Features
|
||||
- Plain command names and aliases
|
||||
- Regular expression triggers
|
||||
- Robust parsing of arguments (with "quoted strings" support)
|
||||
- Sophisticated argument system (optional)
|
||||
* Automatic prompting for arguments that aren't provided
|
||||
* Type system with rules, automatic validation, and parsing to usable values
|
||||
- Basic types (string, integer, float, boolean)
|
||||
- Discord objects (user, member, role, channel, message)
|
||||
- User-defined custom types
|
||||
- Union types
|
||||
* Automatic re-prompting of invalid arguments
|
||||
* Optional arguments with default values
|
||||
* Infinite arguments (arguments that accept as many values as provided)
|
||||
- Multiple responses to commands
|
||||
- Command editing (user edits their message that triggered the command, and the bot's response updates with it)
|
||||
- Command reloading, as well as loading/unloading
|
||||
- Command throttling/cooldowns
|
||||
|
||||
## Installation
|
||||
**Node 12.0.0 or newer is required.**
|
||||
`npm install discord.js@12 discord.js-commando`
|
||||
|
||||
## Documentation
|
||||
[View the docs here.](https://discord.js.org/#/docs/commando)
|
||||
See the [discord.js documentation](https://discord.js.org/#/docs) as well.
|
||||
43
node_modules/discord.js-commando/package.json
generated
vendored
Normal file
43
node_modules/discord.js-commando/package.json
generated
vendored
Normal file
@@ -0,0 +1,43 @@
|
||||
{
|
||||
"name": "discord.js-commando",
|
||||
"version": "0.12.3",
|
||||
"description": "The official command framework for Discord.js",
|
||||
"license": "Apache-2.0",
|
||||
"author": "Schuyler Cebulskie <Gawdl3y@gawdl3y.com> (https://gawdl3y.com/)",
|
||||
"repository": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/discordjs/Commando.git"
|
||||
},
|
||||
"bugs": {
|
||||
"url": "https://github.com/discordjs/Commando/issues"
|
||||
},
|
||||
"keywords": [
|
||||
"discord",
|
||||
"bot",
|
||||
"commands"
|
||||
],
|
||||
"scripts": {
|
||||
"test": "yarn run lint && yarn run docs:test",
|
||||
"lint": "eslint src",
|
||||
"lint:fix": "eslint --fix src",
|
||||
"docs": "docgen --source src --custom docs/index.yml --output docs/docs.json",
|
||||
"docs:test": "docgen --source src --custom docs/index.yml"
|
||||
},
|
||||
"main": "src/index",
|
||||
"types": "./typings/index.d.ts",
|
||||
"dependencies": {
|
||||
"common-tags": "^1.8.0",
|
||||
"emoji-regex": "^9.2.0",
|
||||
"is-promise": "^4.0.0",
|
||||
"require-all": "^3.0.0"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@types/node": "^12.7.3",
|
||||
"discord.js-docgen": "discordjs/docgen",
|
||||
"eslint": "^6.3.0",
|
||||
"typescript": "^3.6.2"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=12.0.0"
|
||||
}
|
||||
}
|
||||
175
node_modules/discord.js-commando/src/client.js
generated
vendored
Normal file
175
node_modules/discord.js-commando/src/client.js
generated
vendored
Normal file
@@ -0,0 +1,175 @@
|
||||
const discord = require('discord.js');
|
||||
const CommandoRegistry = require('./registry');
|
||||
const CommandDispatcher = require('./dispatcher');
|
||||
const GuildSettingsHelper = require('./providers/helper');
|
||||
|
||||
/**
|
||||
* Discord.js Client with a command framework
|
||||
* @extends {Client}
|
||||
*/
|
||||
class CommandoClient extends discord.Client {
|
||||
/**
|
||||
* Options for a CommandoClient
|
||||
* @typedef {ClientOptions} CommandoClientOptions
|
||||
* @property {string} [commandPrefix=!] - Default command prefix
|
||||
* @property {number} [commandEditableDuration=30] - Time in seconds that command messages should be editable
|
||||
* @property {boolean} [nonCommandEditable=true] - Whether messages without commands can be edited to a command
|
||||
* @property {string|string[]|Set<string>} [owner] - ID of the bot owner's Discord user, or multiple IDs
|
||||
* @property {string} [invite] - Invite URL to the bot's support server
|
||||
*/
|
||||
|
||||
/**
|
||||
* @param {CommandoClientOptions} [options] - Options for the client
|
||||
*/
|
||||
constructor(options = {}) {
|
||||
if(typeof options.commandPrefix === 'undefined') options.commandPrefix = '!';
|
||||
if(options.commandPrefix === null) options.commandPrefix = '';
|
||||
if(typeof options.commandEditableDuration === 'undefined') options.commandEditableDuration = 30;
|
||||
if(typeof options.nonCommandEditable === 'undefined') options.nonCommandEditable = true;
|
||||
super(options);
|
||||
|
||||
/**
|
||||
* The client's command registry
|
||||
* @type {CommandoRegistry}
|
||||
*/
|
||||
this.registry = new CommandoRegistry(this);
|
||||
|
||||
/**
|
||||
* The client's command dispatcher
|
||||
* @type {CommandDispatcher}
|
||||
*/
|
||||
this.dispatcher = new CommandDispatcher(this, this.registry);
|
||||
|
||||
/**
|
||||
* The client's setting provider
|
||||
* @type {?SettingProvider}
|
||||
*/
|
||||
this.provider = null;
|
||||
|
||||
/**
|
||||
* Shortcut to use setting provider methods for the global settings
|
||||
* @type {GuildSettingsHelper}
|
||||
*/
|
||||
this.settings = new GuildSettingsHelper(this, null);
|
||||
|
||||
/**
|
||||
* Internal global command prefix, controlled by the {@link CommandoClient#commandPrefix} getter/setter
|
||||
* @type {?string}
|
||||
* @private
|
||||
*/
|
||||
this._commandPrefix = null;
|
||||
|
||||
// Set up command handling
|
||||
const msgErr = err => { this.emit('error', err); };
|
||||
this.on('message', message => { this.dispatcher.handleMessage(message).catch(msgErr); });
|
||||
this.on('messageUpdate', (oldMessage, newMessage) => {
|
||||
this.dispatcher.handleMessage(newMessage, oldMessage).catch(msgErr);
|
||||
});
|
||||
|
||||
// Fetch the owner(s)
|
||||
if(options.owner) {
|
||||
this.once('ready', () => {
|
||||
if(options.owner instanceof Array || options.owner instanceof Set) {
|
||||
for(const owner of options.owner) {
|
||||
this.users.fetch(owner).catch(err => {
|
||||
this.emit('warn', `Unable to fetch owner ${owner}.`);
|
||||
this.emit('error', err);
|
||||
});
|
||||
}
|
||||
} else {
|
||||
this.users.fetch(options.owner).catch(err => {
|
||||
this.emit('warn', `Unable to fetch owner ${options.owner}.`);
|
||||
this.emit('error', err);
|
||||
});
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Global command prefix. An empty string indicates that there is no default prefix, and only mentions will be used.
|
||||
* Setting to `null` means that the default prefix from {@link CommandoClient#options} will be used instead.
|
||||
* @type {string}
|
||||
* @emits {@link CommandoClient#commandPrefixChange}
|
||||
*/
|
||||
get commandPrefix() {
|
||||
if(typeof this._commandPrefix === 'undefined' || this._commandPrefix === null) return this.options.commandPrefix;
|
||||
return this._commandPrefix;
|
||||
}
|
||||
|
||||
set commandPrefix(prefix) {
|
||||
this._commandPrefix = prefix;
|
||||
this.emit('commandPrefixChange', null, this._commandPrefix);
|
||||
}
|
||||
|
||||
/**
|
||||
* Owners of the bot, set by the {@link CommandoClientOptions#owner} option
|
||||
* <info>If you simply need to check if a user is an owner of the bot, please instead use
|
||||
* {@link CommandoClient#isOwner}.</info>
|
||||
* @type {?Array<User>}
|
||||
* @readonly
|
||||
*/
|
||||
get owners() {
|
||||
if(!this.options.owner) return null;
|
||||
if(typeof this.options.owner === 'string') return [this.users.cache.get(this.options.owner)];
|
||||
const owners = [];
|
||||
for(const owner of this.options.owner) owners.push(this.users.cache.get(owner));
|
||||
return owners;
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks whether a user is an owner of the bot (in {@link CommandoClientOptions#owner})
|
||||
* @param {UserResolvable} user - User to check for ownership
|
||||
* @return {boolean}
|
||||
*/
|
||||
isOwner(user) {
|
||||
if(!this.options.owner) return false;
|
||||
user = this.users.resolve(user);
|
||||
if(!user) throw new RangeError('Unable to resolve user.');
|
||||
if(typeof this.options.owner === 'string') return user.id === this.options.owner;
|
||||
if(this.options.owner instanceof Array) return this.options.owner.includes(user.id);
|
||||
if(this.options.owner instanceof Set) return this.options.owner.has(user.id);
|
||||
throw new RangeError('The client\'s "owner" option is an unknown value.');
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the setting provider to use, and initialises it once the client is ready
|
||||
* @param {SettingProvider|Promise<SettingProvider>} provider Provider to use
|
||||
* @return {Promise<void>}
|
||||
*/
|
||||
async setProvider(provider) {
|
||||
const newProvider = await provider;
|
||||
this.provider = newProvider;
|
||||
|
||||
if(this.readyTimestamp) {
|
||||
this.emit('debug', `Provider set to ${newProvider.constructor.name} - initialising...`);
|
||||
await newProvider.init(this);
|
||||
this.emit('debug', 'Provider finished initialisation.');
|
||||
return undefined;
|
||||
}
|
||||
|
||||
this.emit('debug', `Provider set to ${newProvider.constructor.name} - will initialise once ready.`);
|
||||
await new Promise(resolve => {
|
||||
this.once('ready', () => {
|
||||
this.emit('debug', `Initialising provider...`);
|
||||
resolve(newProvider.init(this));
|
||||
});
|
||||
});
|
||||
|
||||
/**
|
||||
* Emitted upon the client's provider finishing initialisation
|
||||
* @event CommandoClient#providerReady
|
||||
* @param {SettingProvider} provider - Provider that was initialised
|
||||
*/
|
||||
this.emit('providerReady', provider);
|
||||
this.emit('debug', 'Provider finished initialisation.');
|
||||
return undefined;
|
||||
}
|
||||
|
||||
async destroy() {
|
||||
await super.destroy();
|
||||
if(this.provider) await this.provider.destroy();
|
||||
}
|
||||
}
|
||||
|
||||
module.exports = CommandoClient;
|
||||
443
node_modules/discord.js-commando/src/commands/argument.js
generated
vendored
Normal file
443
node_modules/discord.js-commando/src/commands/argument.js
generated
vendored
Normal file
@@ -0,0 +1,443 @@
|
||||
const { escapeMarkdown } = require('discord.js');
|
||||
const { oneLine, stripIndents } = require('common-tags');
|
||||
const isPromise = require('is-promise');
|
||||
const ArgumentUnionType = require('../types/union');
|
||||
|
||||
/** A fancy argument */
|
||||
class Argument {
|
||||
/**
|
||||
* @typedef {Object} ArgumentInfo
|
||||
* @property {string} key - Key for the argument
|
||||
* @property {string} [label=key] - Label for the argument
|
||||
* @property {string} prompt - First prompt for the argument when it wasn't specified
|
||||
* @property {string} [error] - Predefined error message to output for the argument when it isn't valid
|
||||
* @property {string} [type] - Type of the argument (must be the ID of one of the registered argument types
|
||||
* or multiple IDs in order of priority separated by `|` for a union type - see
|
||||
* {@link CommandoRegistry#registerDefaultTypes} for the built-in types)
|
||||
* @property {number} [max] - If type is `integer` or `float`, this is the maximum value of the number.
|
||||
* If type is `string`, this is the maximum length of the string.
|
||||
* @property {number} [min] - If type is `integer` or `float`, this is the minimum value of the number.
|
||||
* If type is `string`, this is the minimum length of the string.
|
||||
* @property {ArgumentDefault} [default] - Default value for the argument (makes the arg optional - cannot be `null`)
|
||||
* @property {string[]} [oneOf] - An array of values that are allowed to be used
|
||||
* @property {boolean} [infinite=false] - Whether the argument accepts infinite values
|
||||
* @property {Function} [validate] - Validator function for the argument (see {@link ArgumentType#validate})
|
||||
* @property {Function} [parse] - Parser function for the argument (see {@link ArgumentType#parse})
|
||||
* @property {Function} [isEmpty] - Empty checker for the argument (see {@link ArgumentType#isEmpty})
|
||||
* @property {number} [wait=30] - How long to wait for input (in seconds)
|
||||
*/
|
||||
|
||||
/**
|
||||
* Either a value or a function that returns a value. The function is passed the CommandoMessage and the Argument.
|
||||
* @typedef {*|Function} ArgumentDefault
|
||||
*/
|
||||
|
||||
/**
|
||||
* @param {CommandoClient} client - Client the argument is for
|
||||
* @param {ArgumentInfo} info - Information for the command argument
|
||||
*/
|
||||
constructor(client, info) {
|
||||
this.constructor.validateInfo(client, info);
|
||||
|
||||
/**
|
||||
* Key for the argument
|
||||
* @type {string}
|
||||
*/
|
||||
this.key = info.key;
|
||||
|
||||
/**
|
||||
* Label for the argument
|
||||
* @type {string}
|
||||
*/
|
||||
this.label = info.label || info.key;
|
||||
|
||||
/**
|
||||
* Question prompt for the argument
|
||||
* @type {string}
|
||||
*/
|
||||
this.prompt = info.prompt;
|
||||
|
||||
/**
|
||||
* Error message for when a value is invalid
|
||||
* @type {?string}
|
||||
*/
|
||||
this.error = info.error || null;
|
||||
|
||||
/**
|
||||
* Type of the argument
|
||||
* @type {?ArgumentType}
|
||||
*/
|
||||
this.type = this.constructor.determineType(client, info.type);
|
||||
|
||||
/**
|
||||
* If type is `integer` or `float`, this is the maximum value of the number.
|
||||
* If type is `string`, this is the maximum length of the string.
|
||||
* @type {?number}
|
||||
*/
|
||||
this.max = typeof info.max !== 'undefined' ? info.max : null;
|
||||
|
||||
/**
|
||||
* If type is `integer` or `float`, this is the minimum value of the number.
|
||||
* If type is `string`, this is the minimum length of the string.
|
||||
* @type {?number}
|
||||
*/
|
||||
this.min = typeof info.min !== 'undefined' ? info.min : null;
|
||||
|
||||
/**
|
||||
* The default value for the argument
|
||||
* @type {?ArgumentDefault}
|
||||
*/
|
||||
this.default = typeof info.default !== 'undefined' ? info.default : null;
|
||||
|
||||
/**
|
||||
* Values the user can choose from
|
||||
* If type is `string`, this will be case-insensitive
|
||||
* If type is `channel`, `member`, `role`, or `user`, this will be the IDs.
|
||||
* @type {?string[]}
|
||||
*/
|
||||
this.oneOf = typeof info.oneOf !== 'undefined' ?
|
||||
info.oneOf.map(el => el.toLowerCase ? el.toLowerCase() : el) :
|
||||
null;
|
||||
|
||||
/**
|
||||
* Whether the argument accepts an infinite number of values
|
||||
* @type {boolean}
|
||||
*/
|
||||
this.infinite = Boolean(info.infinite);
|
||||
|
||||
/**
|
||||
* Validator function for validating a value for the argument
|
||||
* @type {?Function}
|
||||
* @see {@link ArgumentType#validate}
|
||||
*/
|
||||
this.validator = info.validate || null;
|
||||
|
||||
/**
|
||||
* Parser function for parsing a value for the argument
|
||||
* @type {?Function}
|
||||
* @see {@link ArgumentType#parse}
|
||||
*/
|
||||
this.parser = info.parse || null;
|
||||
|
||||
/**
|
||||
* Function to check whether a raw value is considered empty
|
||||
* @type {?Function}
|
||||
* @see {@link ArgumentType#isEmpty}
|
||||
*/
|
||||
this.emptyChecker = info.isEmpty || null;
|
||||
|
||||
/**
|
||||
* How long to wait for input (in seconds)
|
||||
* @type {number}
|
||||
*/
|
||||
this.wait = typeof info.wait !== 'undefined' ? info.wait : 30;
|
||||
}
|
||||
|
||||
/**
|
||||
* Result object from obtaining a single {@link Argument}'s value(s)
|
||||
* @typedef {Object} ArgumentResult
|
||||
* @property {?*|?Array<*>} value - Final value(s) for the argument
|
||||
* @property {?string} cancelled - One of:
|
||||
* - `user` (user cancelled)
|
||||
* - `time` (wait time exceeded)
|
||||
* - `promptLimit` (prompt limit exceeded)
|
||||
* @property {Message[]} prompts - All messages that were sent to prompt the user
|
||||
* @property {Message[]} answers - All of the user's messages that answered a prompt
|
||||
*/
|
||||
|
||||
/**
|
||||
* Prompts the user and obtains the value for the argument
|
||||
* @param {CommandoMessage} msg - Message that triggered the command
|
||||
* @param {string} [val] - Pre-provided value for the argument
|
||||
* @param {number} [promptLimit=Infinity] - Maximum number of times to prompt for the argument
|
||||
* @return {Promise<ArgumentResult>}
|
||||
*/
|
||||
async obtain(msg, val, promptLimit = Infinity) {
|
||||
let empty = this.isEmpty(val, msg);
|
||||
if(empty && this.default !== null) {
|
||||
return {
|
||||
value: typeof this.default === 'function' ? await this.default(msg, this) : this.default,
|
||||
cancelled: null,
|
||||
prompts: [],
|
||||
answers: []
|
||||
};
|
||||
}
|
||||
if(this.infinite) return this.obtainInfinite(msg, val, promptLimit);
|
||||
|
||||
const wait = this.wait > 0 && this.wait !== Infinity ? this.wait * 1000 : undefined;
|
||||
const prompts = [];
|
||||
const answers = [];
|
||||
let valid = !empty ? await this.validate(val, msg) : false;
|
||||
|
||||
while(!valid || typeof valid === 'string') {
|
||||
/* eslint-disable no-await-in-loop */
|
||||
if(prompts.length >= promptLimit) {
|
||||
return {
|
||||
value: null,
|
||||
cancelled: 'promptLimit',
|
||||
prompts,
|
||||
answers
|
||||
};
|
||||
}
|
||||
|
||||
// Prompt the user for a new value
|
||||
prompts.push(await msg.reply(stripIndents`
|
||||
${empty ? this.prompt : valid ? valid : `You provided an invalid ${this.label}. Please try again.`}
|
||||
${oneLine`
|
||||
Respond with \`cancel\` to cancel the command.
|
||||
${wait ? `The command will automatically be cancelled in ${this.wait} seconds.` : ''}
|
||||
`}
|
||||
`));
|
||||
|
||||
// Get the user's response
|
||||
const responses = await msg.channel.awaitMessages(msg2 => msg2.author.id === msg.author.id, {
|
||||
max: 1,
|
||||
time: wait
|
||||
});
|
||||
|
||||
// Make sure they actually answered
|
||||
if(responses && responses.size === 1) {
|
||||
answers.push(responses.first());
|
||||
val = answers[answers.length - 1].content;
|
||||
} else {
|
||||
return {
|
||||
value: null,
|
||||
cancelled: 'time',
|
||||
prompts,
|
||||
answers
|
||||
};
|
||||
}
|
||||
|
||||
// See if they want to cancel
|
||||
if(val.toLowerCase() === 'cancel') {
|
||||
return {
|
||||
value: null,
|
||||
cancelled: 'user',
|
||||
prompts,
|
||||
answers
|
||||
};
|
||||
}
|
||||
|
||||
empty = this.isEmpty(val, msg, responses.first());
|
||||
valid = await this.validate(val, msg, responses.first());
|
||||
/* eslint-enable no-await-in-loop */
|
||||
}
|
||||
|
||||
return {
|
||||
value: await this.parse(val, msg, answers.length ? answers[answers.length - 1] : msg),
|
||||
cancelled: null,
|
||||
prompts,
|
||||
answers
|
||||
};
|
||||
}
|
||||
|
||||
/**
|
||||
* Prompts the user and obtains multiple values for the argument
|
||||
* @param {CommandoMessage} msg - Message that triggered the command
|
||||
* @param {string[]} [vals] - Pre-provided values for the argument
|
||||
* @param {number} [promptLimit=Infinity] - Maximum number of times to prompt for the argument
|
||||
* @return {Promise<ArgumentResult>}
|
||||
* @private
|
||||
*/
|
||||
async obtainInfinite(msg, vals, promptLimit = Infinity) { // eslint-disable-line complexity
|
||||
const wait = this.wait > 0 && this.wait !== Infinity ? this.wait * 1000 : undefined;
|
||||
const results = [];
|
||||
const prompts = [];
|
||||
const answers = [];
|
||||
let currentVal = 0;
|
||||
|
||||
while(true) { // eslint-disable-line no-constant-condition
|
||||
/* eslint-disable no-await-in-loop */
|
||||
let val = vals && vals[currentVal] ? vals[currentVal] : null;
|
||||
let valid = val ? await this.validate(val, msg) : false;
|
||||
let attempts = 0;
|
||||
|
||||
while(!valid || typeof valid === 'string') {
|
||||
attempts++;
|
||||
if(attempts > promptLimit) {
|
||||
return {
|
||||
value: null,
|
||||
cancelled: 'promptLimit',
|
||||
prompts,
|
||||
answers
|
||||
};
|
||||
}
|
||||
|
||||
// Prompt the user for a new value
|
||||
if(val) {
|
||||
const escaped = escapeMarkdown(val).replace(/@/g, '@\u200b');
|
||||
prompts.push(await msg.reply(stripIndents`
|
||||
${valid ? valid : oneLine`
|
||||
You provided an invalid ${this.label},
|
||||
"${escaped.length < 1850 ? escaped : '[too long to show]'}".
|
||||
Please try again.
|
||||
`}
|
||||
${oneLine`
|
||||
Respond with \`cancel\` to cancel the command, or \`finish\` to finish entry up to this point.
|
||||
${wait ? `The command will automatically be cancelled in ${this.wait} seconds.` : ''}
|
||||
`}
|
||||
`));
|
||||
} else if(results.length === 0) {
|
||||
prompts.push(await msg.reply(stripIndents`
|
||||
${this.prompt}
|
||||
${oneLine`
|
||||
Respond with \`cancel\` to cancel the command, or \`finish\` to finish entry.
|
||||
${wait ? `The command will automatically be cancelled in ${this.wait} seconds, unless you respond.` : ''}
|
||||
`}
|
||||
`));
|
||||
}
|
||||
|
||||
// Get the user's response
|
||||
const responses = await msg.channel.awaitMessages(msg2 => msg2.author.id === msg.author.id, {
|
||||
max: 1,
|
||||
time: wait
|
||||
});
|
||||
|
||||
// Make sure they actually answered
|
||||
if(responses && responses.size === 1) {
|
||||
answers.push(responses.first());
|
||||
val = answers[answers.length - 1].content;
|
||||
} else {
|
||||
return {
|
||||
value: null,
|
||||
cancelled: 'time',
|
||||
prompts,
|
||||
answers
|
||||
};
|
||||
}
|
||||
|
||||
// See if they want to finish or cancel
|
||||
const lc = val.toLowerCase();
|
||||
if(lc === 'finish') {
|
||||
return {
|
||||
value: results.length > 0 ? results : null,
|
||||
cancelled: this.default ? null : results.length > 0 ? null : 'user',
|
||||
prompts,
|
||||
answers
|
||||
};
|
||||
}
|
||||
if(lc === 'cancel') {
|
||||
return {
|
||||
value: null,
|
||||
cancelled: 'user',
|
||||
prompts,
|
||||
answers
|
||||
};
|
||||
}
|
||||
|
||||
valid = await this.validate(val, msg, responses.first());
|
||||
}
|
||||
|
||||
results.push(await this.parse(val, msg, answers.length ? answers[answers.length - 1] : msg));
|
||||
|
||||
if(vals) {
|
||||
currentVal++;
|
||||
if(currentVal === vals.length) {
|
||||
return {
|
||||
value: results,
|
||||
cancelled: null,
|
||||
prompts,
|
||||
answers
|
||||
};
|
||||
}
|
||||
}
|
||||
/* eslint-enable no-await-in-loop */
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks if a value is valid for the argument
|
||||
* @param {string} val - Value to check
|
||||
* @param {CommandoMessage} originalMsg - Message that triggered the command
|
||||
* @param {?CommandoMessage} [currentMsg=originalMsg] - Current response message
|
||||
* @return {boolean|string|Promise<boolean|string>}
|
||||
*/
|
||||
validate(val, originalMsg, currentMsg = originalMsg) {
|
||||
const valid = this.validator ?
|
||||
this.validator(val, originalMsg, this, currentMsg) :
|
||||
this.type.validate(val, originalMsg, this, currentMsg);
|
||||
if(!valid || typeof valid === 'string') return this.error || valid;
|
||||
if(isPromise(valid)) return valid.then(vld => !vld || typeof vld === 'string' ? this.error || vld : vld);
|
||||
return valid;
|
||||
}
|
||||
|
||||
/**
|
||||
* Parses a value string into a proper value for the argument
|
||||
* @param {string} val - Value to parse
|
||||
* @param {CommandoMessage} originalMsg - Message that triggered the command
|
||||
* @param {?CommandoMessage} [currentMsg=originalMsg] - Current response message
|
||||
* @return {*|Promise<*>}
|
||||
*/
|
||||
parse(val, originalMsg, currentMsg = originalMsg) {
|
||||
if(this.parser) return this.parser(val, originalMsg, this, currentMsg);
|
||||
return this.type.parse(val, originalMsg, this, currentMsg);
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks whether a value for the argument is considered to be empty
|
||||
* @param {string} val - Value to check for emptiness
|
||||
* @param {CommandoMessage} originalMsg - Message that triggered the command
|
||||
* @param {?CommandoMessage} [currentMsg=originalMsg] - Current response message
|
||||
* @return {boolean}
|
||||
*/
|
||||
isEmpty(val, originalMsg, currentMsg = originalMsg) {
|
||||
if(this.emptyChecker) return this.emptyChecker(val, originalMsg, this, currentMsg);
|
||||
if(this.type) return this.type.isEmpty(val, originalMsg, this, currentMsg);
|
||||
if(Array.isArray(val)) return val.length === 0;
|
||||
return !val;
|
||||
}
|
||||
|
||||
/**
|
||||
* Validates the constructor parameters
|
||||
* @param {CommandoClient} client - Client to validate
|
||||
* @param {ArgumentInfo} info - Info to validate
|
||||
* @private
|
||||
*/
|
||||
static validateInfo(client, info) { // eslint-disable-line complexity
|
||||
if(!client) throw new Error('The argument client must be specified.');
|
||||
if(typeof info !== 'object') throw new TypeError('Argument info must be an Object.');
|
||||
if(typeof info.key !== 'string') throw new TypeError('Argument key must be a string.');
|
||||
if(info.label && typeof info.label !== 'string') throw new TypeError('Argument label must be a string.');
|
||||
if(typeof info.prompt !== 'string') throw new TypeError('Argument prompt must be a string.');
|
||||
if(info.error && typeof info.error !== 'string') throw new TypeError('Argument error must be a string.');
|
||||
if(info.type && typeof info.type !== 'string') throw new TypeError('Argument type must be a string.');
|
||||
if(info.type && !info.type.includes('|') && !client.registry.types.has(info.type)) {
|
||||
throw new RangeError(`Argument type "${info.type}" isn't registered.`);
|
||||
}
|
||||
if(!info.type && !info.validate) {
|
||||
throw new Error('Argument must have either "type" or "validate" specified.');
|
||||
}
|
||||
if(info.validate && typeof info.validate !== 'function') {
|
||||
throw new TypeError('Argument validate must be a function.');
|
||||
}
|
||||
if(info.parse && typeof info.parse !== 'function') {
|
||||
throw new TypeError('Argument parse must be a function.');
|
||||
}
|
||||
if(!info.type && (!info.validate || !info.parse)) {
|
||||
throw new Error('Argument must have both validate and parse since it doesn\'t have a type.');
|
||||
}
|
||||
if(typeof info.wait !== 'undefined' && (typeof info.wait !== 'number' || Number.isNaN(info.wait))) {
|
||||
throw new TypeError('Argument wait must be a number.');
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the argument type to use from an ID
|
||||
* @param {CommandoClient} client - Client to use the registry of
|
||||
* @param {string} id - ID of the type to use
|
||||
* @returns {?ArgumentType}
|
||||
* @private
|
||||
*/
|
||||
static determineType(client, id) {
|
||||
if(!id) return null;
|
||||
if(!id.includes('|')) return client.registry.types.get(id);
|
||||
|
||||
let type = client.registry.types.get(id);
|
||||
if(type) return type;
|
||||
type = new ArgumentUnionType(client, id);
|
||||
client.registry.registerType(type);
|
||||
return type;
|
||||
}
|
||||
}
|
||||
|
||||
module.exports = Argument;
|
||||
571
node_modules/discord.js-commando/src/commands/base.js
generated
vendored
Normal file
571
node_modules/discord.js-commando/src/commands/base.js
generated
vendored
Normal file
@@ -0,0 +1,571 @@
|
||||
const path = require('path');
|
||||
const { escapeMarkdown } = require('discord.js');
|
||||
const { oneLine, stripIndents } = require('common-tags');
|
||||
const ArgumentCollector = require('./collector');
|
||||
const { permissions } = require('../util');
|
||||
|
||||
/** A command that can be run in a client */
|
||||
class Command {
|
||||
/**
|
||||
* @typedef {Object} ThrottlingOptions
|
||||
* @property {number} usages - Maximum number of usages of the command allowed in the time frame.
|
||||
* @property {number} duration - Amount of time to count the usages of the command within (in seconds).
|
||||
*/
|
||||
|
||||
/**
|
||||
* @typedef {Object} CommandInfo
|
||||
* @property {string} name - The name of the command (must be lowercase)
|
||||
* @property {string[]} [aliases] - Alternative names for the command (all must be lowercase)
|
||||
* @property {boolean} [autoAliases=true] - Whether automatic aliases should be added
|
||||
* @property {string} group - The ID of the group the command belongs to (must be lowercase)
|
||||
* @property {string} memberName - The member name of the command in the group (must be lowercase)
|
||||
* @property {string} description - A short description of the command
|
||||
* @property {string} [format] - The command usage format string - will be automatically generated if not specified,
|
||||
* and `args` is specified
|
||||
* @property {string} [details] - A detailed description of the command and its functionality
|
||||
* @property {string[]} [examples] - Usage examples of the command
|
||||
* @property {boolean} [guildOnly=false] - Whether or not the command should only function in a guild channel
|
||||
* @property {boolean} [ownerOnly=false] - Whether or not the command is usable only by an owner
|
||||
* @property {PermissionResolvable[]} [clientPermissions] - Permissions required by the client to use the command.
|
||||
* @property {PermissionResolvable[]} [userPermissions] - Permissions required by the user to use the command.
|
||||
* @property {boolean} [nsfw=false] - Whether the command is usable only in NSFW channels.
|
||||
* @property {ThrottlingOptions} [throttling] - Options for throttling usages of the command.
|
||||
* @property {boolean} [defaultHandling=true] - Whether or not the default command handling should be used.
|
||||
* If false, then only patterns will trigger the command.
|
||||
* @property {ArgumentInfo[]} [args] - Arguments for the command.
|
||||
* @property {number} [argsPromptLimit=Infinity] - Maximum number of times to prompt a user for a single argument.
|
||||
* Only applicable if `args` is specified.
|
||||
* @property {string} [argsType=single] - One of 'single' or 'multiple'. Only applicable if `args` is not specified.
|
||||
* When 'single', the entire argument string will be passed to run as one argument.
|
||||
* When 'multiple', it will be passed as multiple arguments.
|
||||
* @property {number} [argsCount=0] - The number of arguments to parse from the command string.
|
||||
* Only applicable when argsType is 'multiple'. If nonzero, it should be at least 2.
|
||||
* When this is 0, the command argument string will be split into as many arguments as it can be.
|
||||
* When nonzero, it will be split into a maximum of this number of arguments.
|
||||
* @property {boolean} [argsSingleQuotes=true] - Whether or not single quotes should be allowed to box-in arguments
|
||||
* in the command string.
|
||||
* @property {RegExp[]} [patterns] - Patterns to use for triggering the command
|
||||
* @property {boolean} [guarded=false] - Whether the command should be protected from disabling
|
||||
* @property {boolean} [hidden=false] - Whether the command should be hidden from the help command
|
||||
* @property {boolean} [unknown=false] - Whether the command should be run when an unknown command is used - there
|
||||
* may only be one command registered with this property as `true`.
|
||||
*/
|
||||
|
||||
/**
|
||||
* @param {CommandoClient} client - The client the command is for
|
||||
* @param {CommandInfo} info - The command information
|
||||
*/
|
||||
// eslint-disable-next-line complexity
|
||||
constructor(client, info) {
|
||||
this.constructor.validateInfo(client, info);
|
||||
|
||||
/**
|
||||
* Client that this command is for
|
||||
* @name Command#client
|
||||
* @type {CommandoClient}
|
||||
* @readonly
|
||||
*/
|
||||
Object.defineProperty(this, 'client', { value: client });
|
||||
|
||||
/**
|
||||
* Name of this command
|
||||
* @type {string}
|
||||
*/
|
||||
this.name = info.name;
|
||||
|
||||
/**
|
||||
* Aliases for this command
|
||||
* @type {string[]}
|
||||
*/
|
||||
this.aliases = info.aliases || [];
|
||||
if(typeof info.autoAliases === 'undefined' || info.autoAliases) {
|
||||
if(this.name.includes('-')) this.aliases.push(this.name.replace(/-/g, ''));
|
||||
for(const alias of this.aliases) {
|
||||
if(alias.includes('-')) this.aliases.push(alias.replace(/-/g, ''));
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* ID of the group the command belongs to
|
||||
* @type {string}
|
||||
*/
|
||||
this.groupID = info.group;
|
||||
|
||||
/**
|
||||
* The group the command belongs to, assigned upon registration
|
||||
* @type {?CommandGroup}
|
||||
*/
|
||||
this.group = null;
|
||||
|
||||
/**
|
||||
* Name of the command within the group
|
||||
* @type {string}
|
||||
*/
|
||||
this.memberName = info.memberName;
|
||||
|
||||
/**
|
||||
* Short description of the command
|
||||
* @type {string}
|
||||
*/
|
||||
this.description = info.description;
|
||||
|
||||
/**
|
||||
* Usage format string of the command
|
||||
* @type {string}
|
||||
*/
|
||||
this.format = info.format || null;
|
||||
|
||||
/**
|
||||
* Long description of the command
|
||||
* @type {?string}
|
||||
*/
|
||||
this.details = info.details || null;
|
||||
|
||||
/**
|
||||
* Example usage strings
|
||||
* @type {?string[]}
|
||||
*/
|
||||
this.examples = info.examples || null;
|
||||
|
||||
/**
|
||||
* Whether the command can only be run in a guild channel
|
||||
* @type {boolean}
|
||||
*/
|
||||
this.guildOnly = Boolean(info.guildOnly);
|
||||
|
||||
/**
|
||||
* Whether the command can only be used by an owner
|
||||
* @type {boolean}
|
||||
*/
|
||||
this.ownerOnly = Boolean(info.ownerOnly);
|
||||
|
||||
/**
|
||||
* Permissions required by the client to use the command.
|
||||
* @type {?PermissionResolvable[]}
|
||||
*/
|
||||
this.clientPermissions = info.clientPermissions || null;
|
||||
|
||||
/**
|
||||
* Permissions required by the user to use the command.
|
||||
* @type {?PermissionResolvable[]}
|
||||
*/
|
||||
this.userPermissions = info.userPermissions || null;
|
||||
|
||||
/**
|
||||
* Whether the command can only be used in NSFW channels
|
||||
* @type {boolean}
|
||||
*/
|
||||
this.nsfw = Boolean(info.nsfw);
|
||||
|
||||
/**
|
||||
* Whether the default command handling is enabled for the command
|
||||
* @type {boolean}
|
||||
*/
|
||||
this.defaultHandling = 'defaultHandling' in info ? info.defaultHandling : true;
|
||||
|
||||
/**
|
||||
* Options for throttling command usages
|
||||
* @type {?ThrottlingOptions}
|
||||
*/
|
||||
this.throttling = info.throttling || null;
|
||||
|
||||
/**
|
||||
* The argument collector for the command
|
||||
* @type {?ArgumentCollector}
|
||||
*/
|
||||
this.argsCollector = info.args && info.args.length ?
|
||||
new ArgumentCollector(client, info.args, info.argsPromptLimit) :
|
||||
null;
|
||||
if(this.argsCollector && typeof info.format === 'undefined') {
|
||||
this.format = this.argsCollector.args.reduce((prev, arg) => {
|
||||
const wrapL = arg.default !== null ? '[' : '<';
|
||||
const wrapR = arg.default !== null ? ']' : '>';
|
||||
return `${prev}${prev ? ' ' : ''}${wrapL}${arg.label}${arg.infinite ? '...' : ''}${wrapR}`;
|
||||
}, '');
|
||||
}
|
||||
|
||||
/**
|
||||
* How the arguments are split when passed to the command's run method
|
||||
* @type {string}
|
||||
*/
|
||||
this.argsType = info.argsType || 'single';
|
||||
|
||||
/**
|
||||
* Maximum number of arguments that will be split
|
||||
* @type {number}
|
||||
*/
|
||||
this.argsCount = info.argsCount || 0;
|
||||
|
||||
/**
|
||||
* Whether single quotes are allowed to encapsulate an argument
|
||||
* @type {boolean}
|
||||
*/
|
||||
this.argsSingleQuotes = 'argsSingleQuotes' in info ? info.argsSingleQuotes : true;
|
||||
|
||||
/**
|
||||
* Regular expression triggers
|
||||
* @type {RegExp[]}
|
||||
*/
|
||||
this.patterns = info.patterns || null;
|
||||
|
||||
/**
|
||||
* Whether the command is protected from being disabled
|
||||
* @type {boolean}
|
||||
*/
|
||||
this.guarded = Boolean(info.guarded);
|
||||
|
||||
/**
|
||||
* Whether the command should be hidden from the help command
|
||||
* @type {boolean}
|
||||
*/
|
||||
this.hidden = Boolean(info.hidden);
|
||||
|
||||
/**
|
||||
* Whether the command will be run when an unknown command is used
|
||||
* @type {boolean}
|
||||
*/
|
||||
this.unknown = Boolean(info.unknown);
|
||||
|
||||
/**
|
||||
* Whether the command is enabled globally
|
||||
* @type {boolean}
|
||||
* @private
|
||||
*/
|
||||
this._globalEnabled = true;
|
||||
|
||||
/**
|
||||
* Current throttle objects for the command, mapped by user ID
|
||||
* @type {Map<string, Object>}
|
||||
* @private
|
||||
*/
|
||||
this._throttles = new Map();
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks whether the user has permission to use the command
|
||||
* @param {CommandoMessage} message - The triggering command message
|
||||
* @param {boolean} [ownerOverride=true] - Whether the bot owner(s) will always have permission
|
||||
* @return {boolean|string} Whether the user has permission, or an error message to respond with if they don't
|
||||
*/
|
||||
hasPermission(message, ownerOverride = true) {
|
||||
if(!this.ownerOnly && !this.userPermissions) return true;
|
||||
if(ownerOverride && this.client.isOwner(message.author)) return true;
|
||||
|
||||
if(this.ownerOnly && (ownerOverride || !this.client.isOwner(message.author))) {
|
||||
return `The \`${this.name}\` command can only be used by the bot owner.`;
|
||||
}
|
||||
|
||||
if(message.channel.type === 'text' && this.userPermissions) {
|
||||
const missing = message.channel.permissionsFor(message.author).missing(this.userPermissions);
|
||||
if(missing.length > 0) {
|
||||
if(missing.length === 1) {
|
||||
return `The \`${this.name}\` command requires you to have the "${permissions[missing[0]]}" permission.`;
|
||||
}
|
||||
return oneLine`
|
||||
The \`${this.name}\` command requires you to have the following permissions:
|
||||
${missing.map(perm => permissions[perm]).join(', ')}
|
||||
`;
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Runs the command
|
||||
* @param {CommandoMessage} message - The message the command is being run for
|
||||
* @param {Object|string|string[]} args - The arguments for the command, or the matches from a pattern.
|
||||
* If args is specified on the command, thise will be the argument values object. If argsType is single, then only
|
||||
* one string will be passed. If multiple, an array of strings will be passed. When fromPattern is true, this is the
|
||||
* matches array from the pattern match
|
||||
* (see [RegExp#exec](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/RegExp/exec)).
|
||||
* @param {boolean} fromPattern - Whether or not the command is being run from a pattern match
|
||||
* @param {?ArgumentCollectorResult} result - Result from obtaining the arguments from the collector (if applicable)
|
||||
* @return {Promise<?Message|?Array<Message>>}
|
||||
* @abstract
|
||||
*/
|
||||
async run(message, args, fromPattern, result) { // eslint-disable-line no-unused-vars, require-await
|
||||
throw new Error(`${this.constructor.name} doesn't have a run() method.`);
|
||||
}
|
||||
|
||||
/**
|
||||
* Called when the command is prevented from running
|
||||
* @param {CommandMessage} message - Command message that the command is running from
|
||||
* @param {string} reason - Reason that the command was blocked
|
||||
* (built-in reasons are `guildOnly`, `nsfw`, `permission`, `throttling`, and `clientPermissions`)
|
||||
* @param {Object} [data] - Additional data associated with the block. Built-in reason data properties:
|
||||
* - guildOnly: none
|
||||
* - nsfw: none
|
||||
* - permission: `response` ({@link string}) to send
|
||||
* - throttling: `throttle` ({@link Object}), `remaining` ({@link number}) time in seconds
|
||||
* - clientPermissions: `missing` ({@link Array}<{@link string}>) permission names
|
||||
* @returns {Promise<?Message|?Array<Message>>}
|
||||
*/
|
||||
onBlock(message, reason, data) {
|
||||
switch(reason) {
|
||||
case 'guildOnly':
|
||||
return message.reply(`The \`${this.name}\` command must be used in a server channel.`);
|
||||
case 'nsfw':
|
||||
return message.reply(`The \`${this.name}\` command can only be used in NSFW channels.`);
|
||||
case 'permission': {
|
||||
if(data.response) return message.reply(data.response);
|
||||
return message.reply(`You do not have permission to use the \`${this.name}\` command.`);
|
||||
}
|
||||
case 'clientPermissions': {
|
||||
if(data.missing.length === 1) {
|
||||
return message.reply(
|
||||
`I need the "${permissions[data.missing[0]]}" permission for the \`${this.name}\` command to work.`
|
||||
);
|
||||
}
|
||||
return message.reply(oneLine`
|
||||
I need the following permissions for the \`${this.name}\` command to work:
|
||||
${data.missing.map(perm => permissions[perm]).join(', ')}
|
||||
`);
|
||||
}
|
||||
case 'throttling': {
|
||||
return message.reply(
|
||||
`You may not use the \`${this.name}\` command again for another ${data.remaining.toFixed(1)} seconds.`
|
||||
);
|
||||
}
|
||||
default:
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Called when the command produces an error while running
|
||||
* @param {Error} err - Error that was thrown
|
||||
* @param {CommandMessage} message - Command message that the command is running from (see {@link Command#run})
|
||||
* @param {Object|string|string[]} args - Arguments for the command (see {@link Command#run})
|
||||
* @param {boolean} fromPattern - Whether the args are pattern matches (see {@link Command#run})
|
||||
* @param {?ArgumentCollectorResult} result - Result from obtaining the arguments from the collector
|
||||
* (if applicable - see {@link Command#run})
|
||||
* @returns {Promise<?Message|?Array<Message>>}
|
||||
*/
|
||||
onError(err, message, args, fromPattern, result) { // eslint-disable-line no-unused-vars
|
||||
const owners = this.client.owners;
|
||||
const ownerList = owners ? owners.map((usr, i) => {
|
||||
const or = i === owners.length - 1 && owners.length > 1 ? 'or ' : '';
|
||||
return `${or}${escapeMarkdown(usr.username)}#${usr.discriminator}`;
|
||||
}).join(owners.length > 2 ? ', ' : ' ') : '';
|
||||
|
||||
const invite = this.client.options.invite;
|
||||
return message.reply(stripIndents`
|
||||
An error occurred while running the command: \`${err.name}: ${err.message}\`
|
||||
You shouldn't ever receive an error like this.
|
||||
Please contact ${ownerList || 'the bot owner'}${invite ? ` in this server: ${invite}` : '.'}
|
||||
`);
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates/obtains the throttle object for a user, if necessary (owners are excluded)
|
||||
* @param {string} userID - ID of the user to throttle for
|
||||
* @return {?Object}
|
||||
* @private
|
||||
*/
|
||||
throttle(userID) {
|
||||
if(!this.throttling || this.client.isOwner(userID)) return null;
|
||||
|
||||
let throttle = this._throttles.get(userID);
|
||||
if(!throttle) {
|
||||
throttle = {
|
||||
start: Date.now(),
|
||||
usages: 0,
|
||||
timeout: this.client.setTimeout(() => {
|
||||
this._throttles.delete(userID);
|
||||
}, this.throttling.duration * 1000)
|
||||
};
|
||||
this._throttles.set(userID, throttle);
|
||||
}
|
||||
|
||||
return throttle;
|
||||
}
|
||||
|
||||
/**
|
||||
* Enables or disables the command in a guild
|
||||
* @param {?GuildResolvable} guild - Guild to enable/disable the command in
|
||||
* @param {boolean} enabled - Whether the command should be enabled or disabled
|
||||
*/
|
||||
setEnabledIn(guild, enabled) {
|
||||
if(typeof guild === 'undefined') throw new TypeError('Guild must not be undefined.');
|
||||
if(typeof enabled === 'undefined') throw new TypeError('Enabled must not be undefined.');
|
||||
if(this.guarded) throw new Error('The command is guarded.');
|
||||
if(!guild) {
|
||||
this._globalEnabled = enabled;
|
||||
this.client.emit('commandStatusChange', null, this, enabled);
|
||||
return;
|
||||
}
|
||||
guild = this.client.guilds.resolve(guild);
|
||||
guild.setCommandEnabled(this, enabled);
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks if the command is enabled in a guild
|
||||
* @param {?GuildResolvable} guild - Guild to check in
|
||||
* @param {boolean} [bypassGroup] - Whether to bypass checking the group's status
|
||||
* @return {boolean}
|
||||
*/
|
||||
isEnabledIn(guild, bypassGroup) {
|
||||
if(this.guarded) return true;
|
||||
if(!guild) return this.group._globalEnabled && this._globalEnabled;
|
||||
guild = this.client.guilds.resolve(guild);
|
||||
return (bypassGroup || guild.isGroupEnabled(this.group)) && guild.isCommandEnabled(this);
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks if the command is usable for a message
|
||||
* @param {?Message} message - The message
|
||||
* @return {boolean}
|
||||
*/
|
||||
isUsable(message = null) {
|
||||
if(!message) return this._globalEnabled;
|
||||
if(this.guildOnly && message && !message.guild) return false;
|
||||
const hasPermission = this.hasPermission(message);
|
||||
return this.isEnabledIn(message.guild) && hasPermission && typeof hasPermission !== 'string';
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a usage string for the command
|
||||
* @param {string} [argString] - A string of arguments for the command
|
||||
* @param {string} [prefix=this.client.commandPrefix] - Prefix to use for the prefixed command format
|
||||
* @param {User} [user=this.client.user] - User to use for the mention command format
|
||||
* @return {string}
|
||||
*/
|
||||
usage(argString, prefix = this.client.commandPrefix, user = this.client.user) {
|
||||
return this.constructor.usage(`${this.name}${argString ? ` ${argString}` : ''}`, prefix, user);
|
||||
}
|
||||
|
||||
/**
|
||||
* Reloads the command
|
||||
*/
|
||||
reload() {
|
||||
let cmdPath, cached, newCmd;
|
||||
try {
|
||||
cmdPath = this.client.registry.resolveCommandPath(this.groupID, this.memberName);
|
||||
cached = require.cache[cmdPath];
|
||||
delete require.cache[cmdPath];
|
||||
newCmd = require(cmdPath);
|
||||
} catch(err) {
|
||||
if(cached) require.cache[cmdPath] = cached;
|
||||
try {
|
||||
cmdPath = path.join(__dirname, this.groupID, `${this.memberName}.js`);
|
||||
cached = require.cache[cmdPath];
|
||||
delete require.cache[cmdPath];
|
||||
newCmd = require(cmdPath);
|
||||
} catch(err2) {
|
||||
if(cached) require.cache[cmdPath] = cached;
|
||||
if(err2.message.includes('Cannot find module')) throw err; else throw err2;
|
||||
}
|
||||
}
|
||||
|
||||
this.client.registry.reregisterCommand(newCmd, this);
|
||||
}
|
||||
|
||||
/**
|
||||
* Unloads the command
|
||||
*/
|
||||
unload() {
|
||||
const cmdPath = this.client.registry.resolveCommandPath(this.groupID, this.memberName);
|
||||
if(!require.cache[cmdPath]) throw new Error('Command cannot be unloaded.');
|
||||
delete require.cache[cmdPath];
|
||||
this.client.registry.unregisterCommand(this);
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a usage string for a command
|
||||
* @param {string} command - A command + arg string
|
||||
* @param {string} [prefix] - Prefix to use for the prefixed command format
|
||||
* @param {User} [user] - User to use for the mention command format
|
||||
* @return {string}
|
||||
*/
|
||||
static usage(command, prefix = null, user = null) {
|
||||
const nbcmd = command.replace(/ /g, '\xa0');
|
||||
if(!prefix && !user) return `\`${nbcmd}\``;
|
||||
|
||||
let prefixPart;
|
||||
if(prefix) {
|
||||
if(prefix.length > 1 && !prefix.endsWith(' ')) prefix += ' ';
|
||||
prefix = prefix.replace(/ /g, '\xa0');
|
||||
prefixPart = `\`${prefix}${nbcmd}\``;
|
||||
}
|
||||
|
||||
let mentionPart;
|
||||
if(user) mentionPart = `\`@${user.username.replace(/ /g, '\xa0')}#${user.discriminator}\xa0${nbcmd}\``;
|
||||
|
||||
return `${prefixPart || ''}${prefix && user ? ' or ' : ''}${mentionPart || ''}`;
|
||||
}
|
||||
|
||||
/**
|
||||
* Validates the constructor parameters
|
||||
* @param {CommandoClient} client - Client to validate
|
||||
* @param {CommandInfo} info - Info to validate
|
||||
* @private
|
||||
*/
|
||||
static validateInfo(client, info) { // eslint-disable-line complexity
|
||||
if(!client) throw new Error('A client must be specified.');
|
||||
if(typeof info !== 'object') throw new TypeError('Command info must be an Object.');
|
||||
if(typeof info.name !== 'string') throw new TypeError('Command name must be a string.');
|
||||
if(info.name !== info.name.toLowerCase()) throw new Error('Command name must be lowercase.');
|
||||
if(info.aliases && (!Array.isArray(info.aliases) || info.aliases.some(ali => typeof ali !== 'string'))) {
|
||||
throw new TypeError('Command aliases must be an Array of strings.');
|
||||
}
|
||||
if(info.aliases && info.aliases.some(ali => ali !== ali.toLowerCase())) {
|
||||
throw new RangeError('Command aliases must be lowercase.');
|
||||
}
|
||||
if(typeof info.group !== 'string') throw new TypeError('Command group must be a string.');
|
||||
if(info.group !== info.group.toLowerCase()) throw new RangeError('Command group must be lowercase.');
|
||||
if(typeof info.memberName !== 'string') throw new TypeError('Command memberName must be a string.');
|
||||
if(info.memberName !== info.memberName.toLowerCase()) throw new Error('Command memberName must be lowercase.');
|
||||
if(typeof info.description !== 'string') throw new TypeError('Command description must be a string.');
|
||||
if('format' in info && typeof info.format !== 'string') throw new TypeError('Command format must be a string.');
|
||||
if('details' in info && typeof info.details !== 'string') throw new TypeError('Command details must be a string.');
|
||||
if(info.examples && (!Array.isArray(info.examples) || info.examples.some(ex => typeof ex !== 'string'))) {
|
||||
throw new TypeError('Command examples must be an Array of strings.');
|
||||
}
|
||||
if(info.clientPermissions) {
|
||||
if(!Array.isArray(info.clientPermissions)) {
|
||||
throw new TypeError('Command clientPermissions must be an Array of permission key strings.');
|
||||
}
|
||||
for(const perm of info.clientPermissions) {
|
||||
if(!permissions[perm]) throw new RangeError(`Invalid command clientPermission: ${perm}`);
|
||||
}
|
||||
}
|
||||
if(info.userPermissions) {
|
||||
if(!Array.isArray(info.userPermissions)) {
|
||||
throw new TypeError('Command userPermissions must be an Array of permission key strings.');
|
||||
}
|
||||
for(const perm of info.userPermissions) {
|
||||
if(!permissions[perm]) throw new RangeError(`Invalid command userPermission: ${perm}`);
|
||||
}
|
||||
}
|
||||
if(info.throttling) {
|
||||
if(typeof info.throttling !== 'object') throw new TypeError('Command throttling must be an Object.');
|
||||
if(typeof info.throttling.usages !== 'number' || isNaN(info.throttling.usages)) {
|
||||
throw new TypeError('Command throttling usages must be a number.');
|
||||
}
|
||||
if(info.throttling.usages < 1) throw new RangeError('Command throttling usages must be at least 1.');
|
||||
if(typeof info.throttling.duration !== 'number' || isNaN(info.throttling.duration)) {
|
||||
throw new TypeError('Command throttling duration must be a number.');
|
||||
}
|
||||
if(info.throttling.duration < 1) throw new RangeError('Command throttling duration must be at least 1.');
|
||||
}
|
||||
if(info.args && !Array.isArray(info.args)) throw new TypeError('Command args must be an Array.');
|
||||
if('argsPromptLimit' in info && typeof info.argsPromptLimit !== 'number') {
|
||||
throw new TypeError('Command argsPromptLimit must be a number.');
|
||||
}
|
||||
if('argsPromptLimit' in info && info.argsPromptLimit < 0) {
|
||||
throw new RangeError('Command argsPromptLimit must be at least 0.');
|
||||
}
|
||||
if(info.argsType && !['single', 'multiple'].includes(info.argsType)) {
|
||||
throw new RangeError('Command argsType must be one of "single" or "multiple".');
|
||||
}
|
||||
if(info.argsType === 'multiple' && info.argsCount && info.argsCount < 2) {
|
||||
throw new RangeError('Command argsCount must be at least 2.');
|
||||
}
|
||||
if(info.patterns && (!Array.isArray(info.patterns) || info.patterns.some(pat => !(pat instanceof RegExp)))) {
|
||||
throw new TypeError('Command patterns must be an Array of regular expressions.');
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
module.exports = Command;
|
||||
105
node_modules/discord.js-commando/src/commands/collector.js
generated
vendored
Normal file
105
node_modules/discord.js-commando/src/commands/collector.js
generated
vendored
Normal file
@@ -0,0 +1,105 @@
|
||||
const Argument = require('./argument');
|
||||
|
||||
/** Obtains, validates, and prompts for argument values */
|
||||
class ArgumentCollector {
|
||||
/**
|
||||
* @param {CommandoClient} client - Client the collector will use
|
||||
* @param {ArgumentInfo[]} args - Arguments for the collector
|
||||
* @param {number} [promptLimit=Infinity] - Maximum number of times to prompt for a single argument
|
||||
*/
|
||||
constructor(client, args, promptLimit = Infinity) {
|
||||
if(!client) throw new TypeError('Collector client must be specified.');
|
||||
if(!args || !Array.isArray(args)) throw new TypeError('Collector args must be an Array.');
|
||||
if(promptLimit === null) promptLimit = Infinity;
|
||||
|
||||
/**
|
||||
* Client this collector is for
|
||||
* @name ArgumentCollector#client
|
||||
* @type {CommandoClient}
|
||||
* @readonly
|
||||
*/
|
||||
Object.defineProperty(this, 'client', { value: client });
|
||||
|
||||
/**
|
||||
* Arguments the collector handles
|
||||
* @type {Argument[]}
|
||||
*/
|
||||
this.args = new Array(args.length);
|
||||
|
||||
let hasInfinite = false;
|
||||
let hasOptional = false;
|
||||
for(let i = 0; i < args.length; i++) {
|
||||
if(hasInfinite) throw new Error('No other argument may come after an infinite argument.');
|
||||
if(args[i].default !== null) hasOptional = true;
|
||||
else if(hasOptional) throw new Error('Required arguments may not come after optional arguments.');
|
||||
this.args[i] = new Argument(this.client, args[i]);
|
||||
if(this.args[i].infinite) hasInfinite = true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Maximum number of times to prompt for a single argument
|
||||
* @type {number}
|
||||
*/
|
||||
this.promptLimit = promptLimit;
|
||||
}
|
||||
|
||||
/**
|
||||
* Result object from obtaining argument values from an {@link ArgumentCollector}
|
||||
* @typedef {Object} ArgumentCollectorResult
|
||||
* @property {?Object} values - Final values for the arguments, mapped by their keys
|
||||
* @property {?string} cancelled - One of:
|
||||
* - `user` (user cancelled)
|
||||
* - `time` (wait time exceeded)
|
||||
* - `promptLimit` (prompt limit exceeded)
|
||||
* @property {Message[]} prompts - All messages that were sent to prompt the user
|
||||
* @property {Message[]} answers - All of the user's messages that answered a prompt
|
||||
*/
|
||||
|
||||
/**
|
||||
* Obtains values for the arguments, prompting if necessary.
|
||||
* @param {CommandoMessage} msg - Message that the collector is being triggered by
|
||||
* @param {Array<*>} [provided=[]] - Values that are already available
|
||||
* @param {number} [promptLimit=this.promptLimit] - Maximum number of times to prompt for a single argument
|
||||
* @return {Promise<ArgumentCollectorResult>}
|
||||
*/
|
||||
async obtain(msg, provided = [], promptLimit = this.promptLimit) {
|
||||
this.client.dispatcher._awaiting.add(msg.author.id + msg.channel.id);
|
||||
const values = {};
|
||||
const results = [];
|
||||
|
||||
try {
|
||||
for(let i = 0; i < this.args.length; i++) {
|
||||
/* eslint-disable no-await-in-loop */
|
||||
const arg = this.args[i];
|
||||
const result = await arg.obtain(msg, arg.infinite ? provided.slice(i) : provided[i], promptLimit);
|
||||
results.push(result);
|
||||
|
||||
if(result.cancelled) {
|
||||
this.client.dispatcher._awaiting.delete(msg.author.id + msg.channel.id);
|
||||
return {
|
||||
values: null,
|
||||
cancelled: result.cancelled,
|
||||
prompts: [].concat(...results.map(res => res.prompts)),
|
||||
answers: [].concat(...results.map(res => res.answers))
|
||||
};
|
||||
}
|
||||
|
||||
values[arg.key] = result.value;
|
||||
/* eslint-enable no-await-in-loop */
|
||||
}
|
||||
} catch(err) {
|
||||
this.client.dispatcher._awaiting.delete(msg.author.id + msg.channel.id);
|
||||
throw err;
|
||||
}
|
||||
|
||||
this.client.dispatcher._awaiting.delete(msg.author.id + msg.channel.id);
|
||||
return {
|
||||
values,
|
||||
cancelled: null,
|
||||
prompts: [].concat(...results.map(res => res.prompts)),
|
||||
answers: [].concat(...results.map(res => res.answers))
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
module.exports = ArgumentCollector;
|
||||
49
node_modules/discord.js-commando/src/commands/commands/disable.js
generated
vendored
Normal file
49
node_modules/discord.js-commando/src/commands/commands/disable.js
generated
vendored
Normal file
@@ -0,0 +1,49 @@
|
||||
const { oneLine } = require('common-tags');
|
||||
const Command = require('../base');
|
||||
|
||||
module.exports = class DisableCommandCommand extends Command {
|
||||
constructor(client) {
|
||||
super(client, {
|
||||
name: 'disable',
|
||||
aliases: ['disable-command', 'cmd-off', 'command-off'],
|
||||
group: 'commands',
|
||||
memberName: 'disable',
|
||||
description: 'Disables a command or command group.',
|
||||
details: oneLine`
|
||||
The argument must be the name/ID (partial or whole) of a command or command group.
|
||||
Only administrators may use this command.
|
||||
`,
|
||||
examples: ['disable util', 'disable Utility', 'disable prefix'],
|
||||
guarded: true,
|
||||
|
||||
args: [
|
||||
{
|
||||
key: 'cmdOrGrp',
|
||||
label: 'command/group',
|
||||
prompt: 'Which command or group would you like to disable?',
|
||||
type: 'group|command'
|
||||
}
|
||||
]
|
||||
});
|
||||
}
|
||||
|
||||
hasPermission(msg) {
|
||||
if(!msg.guild) return this.client.isOwner(msg.author);
|
||||
return msg.member.permissions.has('ADMINISTRATOR') || this.client.isOwner(msg.author);
|
||||
}
|
||||
|
||||
run(msg, args) {
|
||||
if(!args.cmdOrGrp.isEnabledIn(msg.guild, true)) {
|
||||
return msg.reply(
|
||||
`The \`${args.cmdOrGrp.name}\` ${args.cmdOrGrp.group ? 'command' : 'group'} is already disabled.`
|
||||
);
|
||||
}
|
||||
if(args.cmdOrGrp.guarded) {
|
||||
return msg.reply(
|
||||
`You cannot disable the \`${args.cmdOrGrp.name}\` ${args.cmdOrGrp.group ? 'command' : 'group'}.`
|
||||
);
|
||||
}
|
||||
args.cmdOrGrp.setEnabledIn(msg.guild, false);
|
||||
return msg.reply(`Disabled the \`${args.cmdOrGrp.name}\` ${args.cmdOrGrp.group ? 'command' : 'group'}.`);
|
||||
}
|
||||
};
|
||||
55
node_modules/discord.js-commando/src/commands/commands/enable.js
generated
vendored
Normal file
55
node_modules/discord.js-commando/src/commands/commands/enable.js
generated
vendored
Normal file
@@ -0,0 +1,55 @@
|
||||
const { oneLine } = require('common-tags');
|
||||
const Command = require('../base');
|
||||
|
||||
module.exports = class EnableCommandCommand extends Command {
|
||||
constructor(client) {
|
||||
super(client, {
|
||||
name: 'enable',
|
||||
aliases: ['enable-command', 'cmd-on', 'command-on'],
|
||||
group: 'commands',
|
||||
memberName: 'enable',
|
||||
description: 'Enables a command or command group.',
|
||||
details: oneLine`
|
||||
The argument must be the name/ID (partial or whole) of a command or command group.
|
||||
Only administrators may use this command.
|
||||
`,
|
||||
examples: ['enable util', 'enable Utility', 'enable prefix'],
|
||||
guarded: true,
|
||||
|
||||
args: [
|
||||
{
|
||||
key: 'cmdOrGrp',
|
||||
label: 'command/group',
|
||||
prompt: 'Which command or group would you like to enable?',
|
||||
type: 'group|command'
|
||||
}
|
||||
]
|
||||
});
|
||||
}
|
||||
|
||||
hasPermission(msg) {
|
||||
if(!msg.guild) return this.client.isOwner(msg.author);
|
||||
return msg.member.permissions.has('ADMINISTRATOR') || this.client.isOwner(msg.author);
|
||||
}
|
||||
|
||||
run(msg, args) {
|
||||
const group = args.cmdOrGrp.group;
|
||||
if(args.cmdOrGrp.isEnabledIn(msg.guild, true)) {
|
||||
return msg.reply(
|
||||
`The \`${args.cmdOrGrp.name}\` ${args.cmdOrGrp.group ? 'command' : 'group'} is already enabled${
|
||||
group && !group.isEnabledIn(msg.guild) ?
|
||||
`, but the \`${group.name}\` group is disabled, so it still can't be used` :
|
||||
''
|
||||
}.`
|
||||
);
|
||||
}
|
||||
args.cmdOrGrp.setEnabledIn(msg.guild, true);
|
||||
return msg.reply(
|
||||
`Enabled the \`${args.cmdOrGrp.name}\` ${group ? 'command' : 'group'}${
|
||||
group && !group.isEnabledIn(msg.guild) ?
|
||||
`, but the \`${group.name}\` group is disabled, so it still can't be used` :
|
||||
''
|
||||
}.`
|
||||
);
|
||||
}
|
||||
};
|
||||
30
node_modules/discord.js-commando/src/commands/commands/groups.js
generated
vendored
Normal file
30
node_modules/discord.js-commando/src/commands/commands/groups.js
generated
vendored
Normal file
@@ -0,0 +1,30 @@
|
||||
const { stripIndents } = require('common-tags');
|
||||
const Command = require('../base');
|
||||
|
||||
module.exports = class ListGroupsCommand extends Command {
|
||||
constructor(client) {
|
||||
super(client, {
|
||||
name: 'groups',
|
||||
aliases: ['list-groups', 'show-groups'],
|
||||
group: 'commands',
|
||||
memberName: 'groups',
|
||||
description: 'Lists all command groups.',
|
||||
details: 'Only administrators may use this command.',
|
||||
guarded: true
|
||||
});
|
||||
}
|
||||
|
||||
hasPermission(msg) {
|
||||
if(!msg.guild) return this.client.isOwner(msg.author);
|
||||
return msg.member.permissions.has('ADMINISTRATOR') || this.client.isOwner(msg.author);
|
||||
}
|
||||
|
||||
run(msg) {
|
||||
return msg.reply(stripIndents`
|
||||
__**Groups**__
|
||||
${this.client.registry.groups.map(grp =>
|
||||
`**${grp.name}:** ${grp.isEnabledIn(msg.guild) ? 'Enabled' : 'Disabled'}`
|
||||
).join('\n')}
|
||||
`);
|
||||
}
|
||||
};
|
||||
72
node_modules/discord.js-commando/src/commands/commands/load.js
generated
vendored
Normal file
72
node_modules/discord.js-commando/src/commands/commands/load.js
generated
vendored
Normal file
@@ -0,0 +1,72 @@
|
||||
const fs = require('fs');
|
||||
const { oneLine } = require('common-tags');
|
||||
const Command = require('../base');
|
||||
|
||||
module.exports = class LoadCommandCommand extends Command {
|
||||
constructor(client) {
|
||||
super(client, {
|
||||
name: 'load',
|
||||
aliases: ['load-command'],
|
||||
group: 'commands',
|
||||
memberName: 'load',
|
||||
description: 'Loads a new command.',
|
||||
details: oneLine`
|
||||
The argument must be full name of the command in the format of \`group:memberName\`.
|
||||
Only the bot owner(s) may use this command.
|
||||
`,
|
||||
examples: ['load some-command'],
|
||||
ownerOnly: true,
|
||||
guarded: true,
|
||||
|
||||
args: [
|
||||
{
|
||||
key: 'command',
|
||||
prompt: 'Which command would you like to load?',
|
||||
validate: val => new Promise(resolve => {
|
||||
if(!val) return resolve(false);
|
||||
const split = val.split(':');
|
||||
if(split.length !== 2) return resolve(false);
|
||||
if(this.client.registry.findCommands(val).length > 0) {
|
||||
return resolve('That command is already registered.');
|
||||
}
|
||||
const cmdPath = this.client.registry.resolveCommandPath(split[0], split[1]);
|
||||
fs.access(cmdPath, fs.constants.R_OK, err => err ? resolve(false) : resolve(true));
|
||||
return null;
|
||||
}),
|
||||
parse: val => {
|
||||
const split = val.split(':');
|
||||
const cmdPath = this.client.registry.resolveCommandPath(split[0], split[1]);
|
||||
delete require.cache[cmdPath];
|
||||
return require(cmdPath);
|
||||
}
|
||||
}
|
||||
]
|
||||
});
|
||||
}
|
||||
|
||||
async run(msg, args) {
|
||||
this.client.registry.registerCommand(args.command);
|
||||
const command = this.client.registry.commands.last();
|
||||
|
||||
if(this.client.shard) {
|
||||
try {
|
||||
await this.client.shard.broadcastEval(`
|
||||
const ids = [${this.client.shard.ids.join(',')}];
|
||||
if(!this.shard.ids.some(id => ids.includes(id))) {
|
||||
const cmdPath = this.registry.resolveCommandPath('${command.groupID}', '${command.name}');
|
||||
delete require.cache[cmdPath];
|
||||
this.registry.registerCommand(require(cmdPath));
|
||||
}
|
||||
`);
|
||||
} catch(err) {
|
||||
this.client.emit('warn', `Error when broadcasting command load to other shards`);
|
||||
this.client.emit('error', err);
|
||||
await msg.reply(`Loaded \`${command.name}\` command, but failed to load on other shards.`);
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
await msg.reply(`Loaded \`${command.name}\` command${this.client.shard ? ' on all shards' : ''}.`);
|
||||
return null;
|
||||
}
|
||||
};
|
||||
68
node_modules/discord.js-commando/src/commands/commands/reload.js
generated
vendored
Normal file
68
node_modules/discord.js-commando/src/commands/commands/reload.js
generated
vendored
Normal file
@@ -0,0 +1,68 @@
|
||||
const { oneLine } = require('common-tags');
|
||||
const Command = require('../base');
|
||||
|
||||
module.exports = class ReloadCommandCommand extends Command {
|
||||
constructor(client) {
|
||||
super(client, {
|
||||
name: 'reload',
|
||||
aliases: ['reload-command'],
|
||||
group: 'commands',
|
||||
memberName: 'reload',
|
||||
description: 'Reloads a command or command group.',
|
||||
details: oneLine`
|
||||
The argument must be the name/ID (partial or whole) of a command or command group.
|
||||
Providing a command group will reload all of the commands in that group.
|
||||
Only the bot owner(s) may use this command.
|
||||
`,
|
||||
examples: ['reload some-command'],
|
||||
ownerOnly: true,
|
||||
guarded: true,
|
||||
|
||||
args: [
|
||||
{
|
||||
key: 'cmdOrGrp',
|
||||
label: 'command/group',
|
||||
prompt: 'Which command or group would you like to reload?',
|
||||
type: 'group|command'
|
||||
}
|
||||
]
|
||||
});
|
||||
}
|
||||
|
||||
async run(msg, args) {
|
||||
const { cmdOrGrp } = args;
|
||||
const isCmd = Boolean(cmdOrGrp.groupID);
|
||||
cmdOrGrp.reload();
|
||||
|
||||
if(this.client.shard) {
|
||||
try {
|
||||
await this.client.shard.broadcastEval(`
|
||||
const ids = [${this.client.shard.ids.join(',')}];
|
||||
if(!this.shard.ids.some(id => ids.includes(id))) {
|
||||
this.registry.${isCmd ? 'commands' : 'groups'}.get('${isCmd ? cmdOrGrp.name : cmdOrGrp.id}').reload();
|
||||
}
|
||||
`);
|
||||
} catch(err) {
|
||||
this.client.emit('warn', `Error when broadcasting command reload to other shards`);
|
||||
this.client.emit('error', err);
|
||||
if(isCmd) {
|
||||
await msg.reply(`Reloaded \`${cmdOrGrp.name}\` command, but failed to reload on other shards.`);
|
||||
} else {
|
||||
await msg.reply(
|
||||
`Reloaded all of the commands in the \`${cmdOrGrp.name}\` group, but failed to reload on other shards.`
|
||||
);
|
||||
}
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
if(isCmd) {
|
||||
await msg.reply(`Reloaded \`${cmdOrGrp.name}\` command${this.client.shard ? ' on all shards' : ''}.`);
|
||||
} else {
|
||||
await msg.reply(
|
||||
`Reloaded all of the commands in the \`${cmdOrGrp.name}\` group${this.client.shard ? ' on all shards' : ''}.`
|
||||
);
|
||||
}
|
||||
return null;
|
||||
}
|
||||
};
|
||||
52
node_modules/discord.js-commando/src/commands/commands/unload.js
generated
vendored
Normal file
52
node_modules/discord.js-commando/src/commands/commands/unload.js
generated
vendored
Normal file
@@ -0,0 +1,52 @@
|
||||
const { oneLine } = require('common-tags');
|
||||
const Command = require('../base');
|
||||
|
||||
module.exports = class UnloadCommandCommand extends Command {
|
||||
constructor(client) {
|
||||
super(client, {
|
||||
name: 'unload',
|
||||
aliases: ['unload-command'],
|
||||
group: 'commands',
|
||||
memberName: 'unload',
|
||||
description: 'Unloads a command.',
|
||||
details: oneLine`
|
||||
The argument must be the name/ID (partial or whole) of a command.
|
||||
Only the bot owner(s) may use this command.
|
||||
`,
|
||||
examples: ['unload some-command'],
|
||||
ownerOnly: true,
|
||||
guarded: true,
|
||||
|
||||
args: [
|
||||
{
|
||||
key: 'command',
|
||||
prompt: 'Which command would you like to unload?',
|
||||
type: 'command'
|
||||
}
|
||||
]
|
||||
});
|
||||
}
|
||||
|
||||
async run(msg, args) {
|
||||
args.command.unload();
|
||||
|
||||
if(this.client.shard) {
|
||||
try {
|
||||
await this.client.shard.broadcastEval(`
|
||||
const ids = [${this.client.shard.ids.join(',')}];
|
||||
if(!this.shard.ids.some(id => ids.includes(id))) {
|
||||
this.registry.commands.get('${args.command.name}').unload();
|
||||
}
|
||||
`);
|
||||
} catch(err) {
|
||||
this.client.emit('warn', `Error when broadcasting command unload to other shards`);
|
||||
this.client.emit('error', err);
|
||||
await msg.reply(`Unloaded \`${args.command.name}\` command, but failed to unload on other shards.`);
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
await msg.reply(`Unloaded \`${args.command.name}\` command${this.client.shard ? ' on all shards' : ''}.`);
|
||||
return null;
|
||||
}
|
||||
};
|
||||
89
node_modules/discord.js-commando/src/commands/group.js
generated
vendored
Normal file
89
node_modules/discord.js-commando/src/commands/group.js
generated
vendored
Normal file
@@ -0,0 +1,89 @@
|
||||
const discord = require('discord.js');
|
||||
|
||||
/** A group for commands. Whodathunkit? */
|
||||
class CommandGroup {
|
||||
/**
|
||||
* @param {CommandoClient} client - The client the group is for
|
||||
* @param {string} id - The ID for the group
|
||||
* @param {string} [name=id] - The name of the group
|
||||
* @param {boolean} [guarded=false] - Whether the group should be protected from disabling
|
||||
*/
|
||||
constructor(client, id, name, guarded = false) {
|
||||
if(!client) throw new Error('A client must be specified.');
|
||||
if(typeof id !== 'string') throw new TypeError('Group ID must be a string.');
|
||||
if(id !== id.toLowerCase()) throw new Error('Group ID must be lowercase.');
|
||||
|
||||
/**
|
||||
* Client that this group is for
|
||||
* @name CommandGroup#client
|
||||
* @type {CommandoClient}
|
||||
* @readonly
|
||||
*/
|
||||
Object.defineProperty(this, 'client', { value: client });
|
||||
|
||||
/**
|
||||
* ID of this group
|
||||
* @type {string}
|
||||
*/
|
||||
this.id = id;
|
||||
|
||||
/**
|
||||
* Name of this group
|
||||
* @type {string}
|
||||
*/
|
||||
this.name = name || id;
|
||||
|
||||
/**
|
||||
* The commands in this group (added upon their registration)
|
||||
* @type {Collection<string, Command>}
|
||||
*/
|
||||
this.commands = new discord.Collection();
|
||||
|
||||
/**
|
||||
* Whether or not this group is protected from being disabled
|
||||
* @type {boolean}
|
||||
*/
|
||||
this.guarded = guarded;
|
||||
|
||||
this._globalEnabled = true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Enables or disables the group in a guild
|
||||
* @param {?GuildResolvable} guild - Guild to enable/disable the group in
|
||||
* @param {boolean} enabled - Whether the group should be enabled or disabled
|
||||
*/
|
||||
setEnabledIn(guild, enabled) {
|
||||
if(typeof guild === 'undefined') throw new TypeError('Guild must not be undefined.');
|
||||
if(typeof enabled === 'undefined') throw new TypeError('Enabled must not be undefined.');
|
||||
if(this.guarded) throw new Error('The group is guarded.');
|
||||
if(!guild) {
|
||||
this._globalEnabled = enabled;
|
||||
this.client.emit('groupStatusChange', null, this, enabled);
|
||||
return;
|
||||
}
|
||||
guild = this.client.guilds.resolve(guild);
|
||||
guild.setGroupEnabled(this, enabled);
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks if the group is enabled in a guild
|
||||
* @param {?GuildResolvable} guild - Guild to check in
|
||||
* @return {boolean} Whether or not the group is enabled
|
||||
*/
|
||||
isEnabledIn(guild) {
|
||||
if(this.guarded) return true;
|
||||
if(!guild) return this._globalEnabled;
|
||||
guild = this.client.guilds.resolve(guild);
|
||||
return guild.isGroupEnabled(this);
|
||||
}
|
||||
|
||||
/**
|
||||
* Reloads all of the group's commands
|
||||
*/
|
||||
reload() {
|
||||
for(const command of this.commands.values()) command.reload();
|
||||
}
|
||||
}
|
||||
|
||||
module.exports = CommandGroup;
|
||||
116
node_modules/discord.js-commando/src/commands/util/eval.js
generated
vendored
Normal file
116
node_modules/discord.js-commando/src/commands/util/eval.js
generated
vendored
Normal file
@@ -0,0 +1,116 @@
|
||||
const util = require('util');
|
||||
const discord = require('discord.js');
|
||||
const tags = require('common-tags');
|
||||
const { escapeRegex } = require('../../util');
|
||||
const Command = require('../base');
|
||||
|
||||
const nl = '!!NL!!';
|
||||
const nlPattern = new RegExp(nl, 'g');
|
||||
|
||||
module.exports = class EvalCommand extends Command {
|
||||
constructor(client) {
|
||||
super(client, {
|
||||
name: 'eval',
|
||||
group: 'util',
|
||||
memberName: 'eval',
|
||||
description: 'Executes JavaScript code.',
|
||||
details: 'Only the bot owner(s) may use this command.',
|
||||
ownerOnly: true,
|
||||
|
||||
args: [
|
||||
{
|
||||
key: 'script',
|
||||
prompt: 'What code would you like to evaluate?',
|
||||
type: 'string'
|
||||
}
|
||||
]
|
||||
});
|
||||
|
||||
this.lastResult = null;
|
||||
Object.defineProperty(this, '_sensitivePattern', { value: null, configurable: true });
|
||||
}
|
||||
|
||||
run(msg, args) {
|
||||
// Make a bunch of helpers
|
||||
/* eslint-disable no-unused-vars */
|
||||
const message = msg;
|
||||
const client = msg.client;
|
||||
const lastResult = this.lastResult;
|
||||
const doReply = val => {
|
||||
if(val instanceof Error) {
|
||||
msg.reply(`Callback error: \`${val}\``);
|
||||
} else {
|
||||
const result = this.makeResultMessages(val, process.hrtime(this.hrStart));
|
||||
if(Array.isArray(result)) {
|
||||
for(const item of result) msg.reply(item);
|
||||
} else {
|
||||
msg.reply(result);
|
||||
}
|
||||
}
|
||||
};
|
||||
/* eslint-enable no-unused-vars */
|
||||
|
||||
// Remove any surrounding code blocks before evaluation
|
||||
if(args.script.startsWith('```') && args.script.endsWith('```')) {
|
||||
args.script = args.script.replace(/(^.*?\s)|(\n.*$)/g, '');
|
||||
}
|
||||
|
||||
// Run the code and measure its execution time
|
||||
let hrDiff;
|
||||
try {
|
||||
const hrStart = process.hrtime();
|
||||
this.lastResult = eval(args.script);
|
||||
hrDiff = process.hrtime(hrStart);
|
||||
} catch(err) {
|
||||
return msg.reply(`Error while evaluating: \`${err}\``);
|
||||
}
|
||||
|
||||
// Prepare for callback time and respond
|
||||
this.hrStart = process.hrtime();
|
||||
const result = this.makeResultMessages(this.lastResult, hrDiff, args.script);
|
||||
if(Array.isArray(result)) {
|
||||
return result.map(item => msg.reply(item));
|
||||
} else {
|
||||
return msg.reply(result);
|
||||
}
|
||||
}
|
||||
|
||||
makeResultMessages(result, hrDiff, input = null) {
|
||||
const inspected = util.inspect(result, { depth: 0 })
|
||||
.replace(nlPattern, '\n')
|
||||
.replace(this.sensitivePattern, '--snip--');
|
||||
const split = inspected.split('\n');
|
||||
const last = inspected.length - 1;
|
||||
const prependPart = inspected[0] !== '{' && inspected[0] !== '[' && inspected[0] !== "'" ? split[0] : inspected[0];
|
||||
const appendPart = inspected[last] !== '}' && inspected[last] !== ']' && inspected[last] !== "'" ?
|
||||
split[split.length - 1] :
|
||||
inspected[last];
|
||||
const prepend = `\`\`\`javascript\n${prependPart}\n`;
|
||||
const append = `\n${appendPart}\n\`\`\``;
|
||||
if(input) {
|
||||
return discord.splitMessage(tags.stripIndents`
|
||||
*Executed in ${hrDiff[0] > 0 ? `${hrDiff[0]}s ` : ''}${hrDiff[1] / 1000000}ms.*
|
||||
\`\`\`javascript
|
||||
${inspected}
|
||||
\`\`\`
|
||||
`, { maxLength: 1900, prepend, append });
|
||||
} else {
|
||||
return discord.splitMessage(tags.stripIndents`
|
||||
*Callback executed after ${hrDiff[0] > 0 ? `${hrDiff[0]}s ` : ''}${hrDiff[1] / 1000000}ms.*
|
||||
\`\`\`javascript
|
||||
${inspected}
|
||||
\`\`\`
|
||||
`, { maxLength: 1900, prepend, append });
|
||||
}
|
||||
}
|
||||
|
||||
get sensitivePattern() {
|
||||
if(!this._sensitivePattern) {
|
||||
const client = this.client;
|
||||
let pattern = '';
|
||||
if(client.token) pattern += escapeRegex(client.token);
|
||||
Object.defineProperty(this, '_sensitivePattern', { value: new RegExp(pattern, 'gi'), configurable: false });
|
||||
}
|
||||
return this._sensitivePattern;
|
||||
}
|
||||
};
|
||||
105
node_modules/discord.js-commando/src/commands/util/help.js
generated
vendored
Normal file
105
node_modules/discord.js-commando/src/commands/util/help.js
generated
vendored
Normal file
@@ -0,0 +1,105 @@
|
||||
const { stripIndents, oneLine } = require('common-tags');
|
||||
const Command = require('../base');
|
||||
const { disambiguation } = require('../../util');
|
||||
|
||||
module.exports = class HelpCommand extends Command {
|
||||
constructor(client) {
|
||||
super(client, {
|
||||
name: 'help',
|
||||
group: 'util',
|
||||
memberName: 'help',
|
||||
aliases: ['commands'],
|
||||
description: 'Displays a list of available commands, or detailed information for a specified command.',
|
||||
details: oneLine`
|
||||
The command may be part of a command name or a whole command name.
|
||||
If it isn't specified, all available commands will be listed.
|
||||
`,
|
||||
examples: ['help', 'help prefix'],
|
||||
guarded: true,
|
||||
|
||||
args: [
|
||||
{
|
||||
key: 'command',
|
||||
prompt: 'Which command would you like to view the help for?',
|
||||
type: 'string',
|
||||
default: ''
|
||||
}
|
||||
]
|
||||
});
|
||||
}
|
||||
|
||||
async run(msg, args) { // eslint-disable-line complexity
|
||||
const groups = this.client.registry.groups;
|
||||
const commands = this.client.registry.findCommands(args.command, false, msg);
|
||||
const showAll = args.command && args.command.toLowerCase() === 'all';
|
||||
if(args.command && !showAll) {
|
||||
if(commands.length === 1) {
|
||||
let help = stripIndents`
|
||||
${oneLine`
|
||||
__Command **${commands[0].name}**:__ ${commands[0].description}
|
||||
${commands[0].guildOnly ? ' (Usable only in servers)' : ''}
|
||||
${commands[0].nsfw ? ' (NSFW)' : ''}
|
||||
`}
|
||||
|
||||
**Format:** ${msg.anyUsage(`${commands[0].name}${commands[0].format ? ` ${commands[0].format}` : ''}`)}
|
||||
`;
|
||||
if(commands[0].aliases.length > 0) help += `\n**Aliases:** ${commands[0].aliases.join(', ')}`;
|
||||
help += `\n${oneLine`
|
||||
**Group:** ${commands[0].group.name}
|
||||
(\`${commands[0].groupID}:${commands[0].memberName}\`)
|
||||
`}`;
|
||||
if(commands[0].details) help += `\n**Details:** ${commands[0].details}`;
|
||||
if(commands[0].examples) help += `\n**Examples:**\n${commands[0].examples.join('\n')}`;
|
||||
|
||||
const messages = [];
|
||||
try {
|
||||
messages.push(await msg.direct(help));
|
||||
if(msg.channel.type !== 'dm') messages.push(await msg.reply('Sent you a DM with information.'));
|
||||
} catch(err) {
|
||||
messages.push(await msg.reply('Unable to send you the help DM. You probably have DMs disabled.'));
|
||||
}
|
||||
return messages;
|
||||
} else if(commands.length > 15) {
|
||||
return msg.reply('Multiple commands found. Please be more specific.');
|
||||
} else if(commands.length > 1) {
|
||||
return msg.reply(disambiguation(commands, 'commands'));
|
||||
} else {
|
||||
return msg.reply(
|
||||
`Unable to identify command. Use ${msg.usage(
|
||||
null, msg.channel.type === 'dm' ? null : undefined, msg.channel.type === 'dm' ? null : undefined
|
||||
)} to view the list of all commands.`
|
||||
);
|
||||
}
|
||||
} else {
|
||||
const messages = [];
|
||||
try {
|
||||
messages.push(await msg.direct(stripIndents`
|
||||
${oneLine`
|
||||
To run a command in ${msg.guild ? msg.guild.name : 'any server'},
|
||||
use ${Command.usage('command', msg.guild ? msg.guild.commandPrefix : null, this.client.user)}.
|
||||
For example, ${Command.usage('prefix', msg.guild ? msg.guild.commandPrefix : null, this.client.user)}.
|
||||
`}
|
||||
To run a command in this DM, simply use ${Command.usage('command', null, null)} with no prefix.
|
||||
|
||||
Use ${this.usage('<command>', null, null)} to view detailed information about a specific command.
|
||||
Use ${this.usage('all', null, null)} to view a list of *all* commands, not just available ones.
|
||||
|
||||
__**${showAll ? 'All commands' : `Available commands in ${msg.guild || 'this DM'}`}**__
|
||||
|
||||
${groups.filter(grp => grp.commands.some(cmd => !cmd.hidden && (showAll || cmd.isUsable(msg))))
|
||||
.map(grp => stripIndents`
|
||||
__${grp.name}__
|
||||
${grp.commands.filter(cmd => !cmd.hidden && (showAll || cmd.isUsable(msg)))
|
||||
.map(cmd => `**${cmd.name}:** ${cmd.description}${cmd.nsfw ? ' (NSFW)' : ''}`).join('\n')
|
||||
}
|
||||
`).join('\n\n')
|
||||
}
|
||||
`, { split: true }));
|
||||
if(msg.channel.type !== 'dm') messages.push(await msg.reply('Sent you a DM with information.'));
|
||||
} catch(err) {
|
||||
messages.push(await msg.reply('Unable to send you the help DM. You probably have DMs disabled.'));
|
||||
}
|
||||
return messages;
|
||||
}
|
||||
}
|
||||
};
|
||||
28
node_modules/discord.js-commando/src/commands/util/ping.js
generated
vendored
Normal file
28
node_modules/discord.js-commando/src/commands/util/ping.js
generated
vendored
Normal file
@@ -0,0 +1,28 @@
|
||||
const { oneLine } = require('common-tags');
|
||||
const Command = require('../base');
|
||||
|
||||
module.exports = class PingCommand extends Command {
|
||||
constructor(client) {
|
||||
super(client, {
|
||||
name: 'ping',
|
||||
group: 'util',
|
||||
memberName: 'ping',
|
||||
description: 'Checks the bot\'s ping to the Discord server.',
|
||||
throttling: {
|
||||
usages: 5,
|
||||
duration: 10
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
async run(msg) {
|
||||
const pingMsg = await msg.reply('Pinging...');
|
||||
return pingMsg.edit(oneLine`
|
||||
${msg.channel.type !== 'dm' ? `${msg.author},` : ''}
|
||||
Pong! The message round-trip took ${
|
||||
(pingMsg.editedTimestamp || pingMsg.createdTimestamp) - (msg.editedTimestamp || msg.createdTimestamp)
|
||||
}ms.
|
||||
${this.client.ws.ping ? `The heartbeat ping is ${Math.round(this.client.ws.ping)}ms.` : ''}
|
||||
`);
|
||||
}
|
||||
};
|
||||
67
node_modules/discord.js-commando/src/commands/util/prefix.js
generated
vendored
Normal file
67
node_modules/discord.js-commando/src/commands/util/prefix.js
generated
vendored
Normal file
@@ -0,0 +1,67 @@
|
||||
const { stripIndents, oneLine } = require('common-tags');
|
||||
const Command = require('../base');
|
||||
|
||||
module.exports = class PrefixCommand extends Command {
|
||||
constructor(client) {
|
||||
super(client, {
|
||||
name: 'prefix',
|
||||
group: 'util',
|
||||
memberName: 'prefix',
|
||||
description: 'Shows or sets the command prefix.',
|
||||
format: '[prefix/"default"/"none"]',
|
||||
details: oneLine`
|
||||
If no prefix is provided, the current prefix will be shown.
|
||||
If the prefix is "default", the prefix will be reset to the bot's default prefix.
|
||||
If the prefix is "none", the prefix will be removed entirely, only allowing mentions to run commands.
|
||||
Only administrators may change the prefix.
|
||||
`,
|
||||
examples: ['prefix', 'prefix -', 'prefix omg!', 'prefix default', 'prefix none'],
|
||||
|
||||
args: [
|
||||
{
|
||||
key: 'prefix',
|
||||
prompt: 'What would you like to set the bot\'s prefix to?',
|
||||
type: 'string',
|
||||
max: 15,
|
||||
default: ''
|
||||
}
|
||||
]
|
||||
});
|
||||
}
|
||||
|
||||
async run(msg, args) {
|
||||
// Just output the prefix
|
||||
if(!args.prefix) {
|
||||
const prefix = msg.guild ? msg.guild.commandPrefix : this.client.commandPrefix;
|
||||
return msg.reply(stripIndents`
|
||||
${prefix ? `The command prefix is \`${prefix}\`.` : 'There is no command prefix.'}
|
||||
To run commands, use ${msg.anyUsage('command')}.
|
||||
`);
|
||||
}
|
||||
|
||||
// Check the user's permission before changing anything
|
||||
if(msg.guild) {
|
||||
if(!msg.member.permissions.has('ADMINISTRATOR') && !this.client.isOwner(msg.author)) {
|
||||
return msg.reply('Only administrators may change the command prefix.');
|
||||
}
|
||||
} else if(!this.client.isOwner(msg.author)) {
|
||||
return msg.reply('Only the bot owner(s) may change the global command prefix.');
|
||||
}
|
||||
|
||||
// Save the prefix
|
||||
const lowercase = args.prefix.toLowerCase();
|
||||
const prefix = lowercase === 'none' ? '' : args.prefix;
|
||||
let response;
|
||||
if(lowercase === 'default') {
|
||||
if(msg.guild) msg.guild.commandPrefix = null; else this.client.commandPrefix = null;
|
||||
const current = this.client.commandPrefix ? `\`${this.client.commandPrefix}\`` : 'no prefix';
|
||||
response = `Reset the command prefix to the default (currently ${current}).`;
|
||||
} else {
|
||||
if(msg.guild) msg.guild.commandPrefix = prefix; else this.client.commandPrefix = prefix;
|
||||
response = prefix ? `Set the command prefix to \`${args.prefix}\`.` : 'Removed the command prefix entirely.';
|
||||
}
|
||||
|
||||
await msg.reply(`${response} To run commands, use ${msg.anyUsage('command')}.`);
|
||||
return null;
|
||||
}
|
||||
};
|
||||
25
node_modules/discord.js-commando/src/commands/util/unknown-command.js
generated
vendored
Normal file
25
node_modules/discord.js-commando/src/commands/util/unknown-command.js
generated
vendored
Normal file
@@ -0,0 +1,25 @@
|
||||
const Command = require('../base');
|
||||
|
||||
module.exports = class UnknownCommandCommand extends Command {
|
||||
constructor(client) {
|
||||
super(client, {
|
||||
name: 'unknown-command',
|
||||
group: 'util',
|
||||
memberName: 'unknown-command',
|
||||
description: 'Displays help information for when an unknown command is used.',
|
||||
examples: ['unknown-command kickeverybodyever'],
|
||||
unknown: true,
|
||||
hidden: true
|
||||
});
|
||||
}
|
||||
|
||||
run(msg) {
|
||||
return msg.reply(
|
||||
`Unknown command. Use ${msg.anyUsage(
|
||||
'help',
|
||||
msg.guild ? undefined : null,
|
||||
msg.guild ? undefined : null
|
||||
)} to view the command list.`
|
||||
);
|
||||
}
|
||||
};
|
||||
306
node_modules/discord.js-commando/src/dispatcher.js
generated
vendored
Normal file
306
node_modules/discord.js-commando/src/dispatcher.js
generated
vendored
Normal file
@@ -0,0 +1,306 @@
|
||||
const { escapeRegex } = require('./util');
|
||||
const isPromise = require('is-promise');
|
||||
|
||||
/** Handles parsing messages and running commands from them */
|
||||
class CommandDispatcher {
|
||||
/**
|
||||
* @param {CommandoClient} client - Client the dispatcher is for
|
||||
* @param {CommandoRegistry} registry - Registry the dispatcher will use
|
||||
*/
|
||||
constructor(client, registry) {
|
||||
/**
|
||||
* Client this dispatcher handles messages for
|
||||
* @name CommandDispatcher#client
|
||||
* @type {CommandoClient}
|
||||
* @readonly
|
||||
*/
|
||||
Object.defineProperty(this, 'client', { value: client });
|
||||
|
||||
/**
|
||||
* Registry this dispatcher uses
|
||||
* @type {CommandoRegistry}
|
||||
*/
|
||||
this.registry = registry;
|
||||
|
||||
/**
|
||||
* Functions that can block commands from running
|
||||
* @type {Set<Function>}
|
||||
*/
|
||||
this.inhibitors = new Set();
|
||||
|
||||
/**
|
||||
* Map object of {@link RegExp}s that match command messages, mapped by string prefix
|
||||
* @type {Object}
|
||||
* @private
|
||||
*/
|
||||
this._commandPatterns = {};
|
||||
|
||||
/**
|
||||
* Old command message results, mapped by original message ID
|
||||
* @type {Map<string, CommandoMessage>}
|
||||
* @private
|
||||
*/
|
||||
this._results = new Map();
|
||||
|
||||
/**
|
||||
* Tuples in string form of user ID and channel ID that are currently awaiting messages from a user in a channel
|
||||
* @type {Set<string>}
|
||||
* @private
|
||||
*/
|
||||
this._awaiting = new Set();
|
||||
}
|
||||
|
||||
/**
|
||||
* @typedef {Object} Inhibition
|
||||
* @property {string} reason - Identifier for the reason the command is being blocked
|
||||
* @property {?Promise<Message>} response - Response being sent to the user
|
||||
*/
|
||||
|
||||
/**
|
||||
* A function that decides whether the usage of a command should be blocked
|
||||
* @callback Inhibitor
|
||||
* @param {CommandoMessage} msg - Message triggering the command
|
||||
* @return {boolean|string|Inhibition} `false` if the command should *not* be blocked.
|
||||
* If the command *should* be blocked, then one of the following:
|
||||
* - A single string identifying the reason the command is blocked
|
||||
* - An Inhibition object
|
||||
*/
|
||||
|
||||
/**
|
||||
* Adds an inhibitor
|
||||
* @param {Inhibitor} inhibitor - The inhibitor function to add
|
||||
* @return {boolean} Whether the addition was successful
|
||||
* @example
|
||||
* client.dispatcher.addInhibitor(msg => {
|
||||
* if(blacklistedUsers.has(msg.author.id)) return 'blacklisted';
|
||||
* });
|
||||
* @example
|
||||
* client.dispatcher.addInhibitor(msg => {
|
||||
* if(!coolUsers.has(msg.author.id)) return { reason: 'cool', response: msg.reply('You\'re not cool enough!') };
|
||||
* });
|
||||
*/
|
||||
addInhibitor(inhibitor) {
|
||||
if(typeof inhibitor !== 'function') throw new TypeError('The inhibitor must be a function.');
|
||||
if(this.inhibitors.has(inhibitor)) return false;
|
||||
this.inhibitors.add(inhibitor);
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Removes an inhibitor
|
||||
* @param {Inhibitor} inhibitor - The inhibitor function to remove
|
||||
* @return {boolean} Whether the removal was successful
|
||||
*/
|
||||
removeInhibitor(inhibitor) {
|
||||
if(typeof inhibitor !== 'function') throw new TypeError('The inhibitor must be a function.');
|
||||
return this.inhibitors.delete(inhibitor);
|
||||
}
|
||||
|
||||
/**
|
||||
* Handle a new message or a message update
|
||||
* @param {Message} message - The message to handle
|
||||
* @param {Message} [oldMessage] - The old message before the update
|
||||
* @return {Promise<void>}
|
||||
* @private
|
||||
*/
|
||||
async handleMessage(message, oldMessage) {
|
||||
/* eslint-disable max-depth */
|
||||
if(!this.shouldHandleMessage(message, oldMessage)) return;
|
||||
|
||||
// Parse the message, and get the old result if it exists
|
||||
let cmdMsg, oldCmdMsg;
|
||||
if(oldMessage) {
|
||||
oldCmdMsg = this._results.get(oldMessage.id);
|
||||
if(!oldCmdMsg && !this.client.options.nonCommandEditable) return;
|
||||
cmdMsg = this.parseMessage(message);
|
||||
if(cmdMsg && oldCmdMsg) {
|
||||
cmdMsg.responses = oldCmdMsg.responses;
|
||||
cmdMsg.responsePositions = oldCmdMsg.responsePositions;
|
||||
}
|
||||
} else {
|
||||
cmdMsg = this.parseMessage(message);
|
||||
}
|
||||
|
||||
// Run the command, or reply with an error
|
||||
let responses;
|
||||
if(cmdMsg) {
|
||||
const inhibited = this.inhibit(cmdMsg);
|
||||
|
||||
if(!inhibited) {
|
||||
if(cmdMsg.command) {
|
||||
if(!cmdMsg.command.isEnabledIn(message.guild)) {
|
||||
if(!cmdMsg.command.unknown) {
|
||||
responses = await cmdMsg.reply(`The \`${cmdMsg.command.name}\` command is disabled.`);
|
||||
} else {
|
||||
/**
|
||||
* Emitted when an unknown command is triggered
|
||||
* @event CommandoClient#unknownCommand
|
||||
* @param {CommandoMessage} message - Command message that triggered the command
|
||||
*/
|
||||
this.client.emit('unknownCommand', cmdMsg);
|
||||
responses = undefined;
|
||||
}
|
||||
} else if(!oldMessage || typeof oldCmdMsg !== 'undefined') {
|
||||
responses = await cmdMsg.run();
|
||||
if(typeof responses === 'undefined') responses = null;
|
||||
if(Array.isArray(responses)) responses = await Promise.all(responses);
|
||||
}
|
||||
} else {
|
||||
this.client.emit('unknownCommand', cmdMsg);
|
||||
responses = undefined;
|
||||
}
|
||||
} else {
|
||||
responses = await inhibited.response;
|
||||
}
|
||||
|
||||
cmdMsg.finalize(responses);
|
||||
} else if(oldCmdMsg) {
|
||||
oldCmdMsg.finalize(null);
|
||||
if(!this.client.options.nonCommandEditable) this._results.delete(message.id);
|
||||
}
|
||||
|
||||
this.cacheCommandoMessage(message, oldMessage, cmdMsg, responses);
|
||||
/* eslint-enable max-depth */
|
||||
}
|
||||
|
||||
/**
|
||||
* Check whether a message should be handled
|
||||
* @param {Message} message - The message to handle
|
||||
* @param {Message} [oldMessage] - The old message before the update
|
||||
* @return {boolean}
|
||||
* @private
|
||||
*/
|
||||
shouldHandleMessage(message, oldMessage) {
|
||||
// Ignore partial messages
|
||||
if(message.partial) return false;
|
||||
|
||||
if(message.author.bot) return false;
|
||||
else if(message.author.id === this.client.user.id) return false;
|
||||
|
||||
// Ignore messages from users that the bot is already waiting for input from
|
||||
if(this._awaiting.has(message.author.id + message.channel.id)) return false;
|
||||
|
||||
// Make sure the edit actually changed the message content
|
||||
if(oldMessage && message.content === oldMessage.content) return false;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Inhibits a command message
|
||||
* @param {CommandoMessage} cmdMsg - Command message to inhibit
|
||||
* @return {?Inhibition}
|
||||
* @private
|
||||
*/
|
||||
inhibit(cmdMsg) {
|
||||
for(const inhibitor of this.inhibitors) {
|
||||
let inhibit = inhibitor(cmdMsg);
|
||||
if(inhibit) {
|
||||
if(typeof inhibit !== 'object') inhibit = { reason: inhibit, response: undefined };
|
||||
|
||||
const valid = typeof inhibit.reason === 'string' && (
|
||||
typeof inhibit.response === 'undefined' ||
|
||||
inhibit.response === null ||
|
||||
isPromise(inhibit.response)
|
||||
);
|
||||
if(!valid) {
|
||||
throw new TypeError(
|
||||
`Inhibitor "${inhibitor.name}" had an invalid result; must be a string or an Inhibition object.`
|
||||
);
|
||||
}
|
||||
|
||||
this.client.emit('commandBlock', cmdMsg, inhibit.reason, inhibit);
|
||||
return inhibit;
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Caches a command message to be editable
|
||||
* @param {Message} message - Triggering message
|
||||
* @param {Message} oldMessage - Triggering message's old version
|
||||
* @param {CommandoMessage} cmdMsg - Command message to cache
|
||||
* @param {Message|Message[]} responses - Responses to the message
|
||||
* @private
|
||||
*/
|
||||
cacheCommandoMessage(message, oldMessage, cmdMsg, responses) {
|
||||
if(this.client.options.commandEditableDuration <= 0) return;
|
||||
if(!cmdMsg && !this.client.options.nonCommandEditable) return;
|
||||
if(responses !== null) {
|
||||
this._results.set(message.id, cmdMsg);
|
||||
if(!oldMessage) {
|
||||
setTimeout(() => { this._results.delete(message.id); }, this.client.options.commandEditableDuration * 1000);
|
||||
}
|
||||
} else {
|
||||
this._results.delete(message.id);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Parses a message to find details about command usage in it
|
||||
* @param {Message} message - The message
|
||||
* @return {?CommandoMessage}
|
||||
* @private
|
||||
*/
|
||||
parseMessage(message) {
|
||||
// Find the command to run by patterns
|
||||
for(const command of this.registry.commands.values()) {
|
||||
if(!command.patterns) continue;
|
||||
for(const pattern of command.patterns) {
|
||||
const matches = pattern.exec(message.content);
|
||||
if(matches) return message.initCommand(command, null, matches);
|
||||
}
|
||||
}
|
||||
|
||||
// Find the command to run with default command handling
|
||||
const prefix = message.guild ? message.guild.commandPrefix : this.client.commandPrefix;
|
||||
if(!this._commandPatterns[prefix]) this.buildCommandPattern(prefix);
|
||||
let cmdMsg = this.matchDefault(message, this._commandPatterns[prefix], 2);
|
||||
if(!cmdMsg && !message.guild) cmdMsg = this.matchDefault(message, /^([^\s]+)/i, 1, true);
|
||||
return cmdMsg;
|
||||
}
|
||||
|
||||
/**
|
||||
* Matches a message against a guild command pattern
|
||||
* @param {Message} message - The message
|
||||
* @param {RegExp} pattern - The pattern to match against
|
||||
* @param {number} commandNameIndex - The index of the command name in the pattern matches
|
||||
* @param {boolean} prefixless - Whether the match is happening for a prefixless usage
|
||||
* @return {?CommandoMessage}
|
||||
* @private
|
||||
*/
|
||||
matchDefault(message, pattern, commandNameIndex = 1, prefixless = false) {
|
||||
const matches = pattern.exec(message.content);
|
||||
if(!matches) return null;
|
||||
const commands = this.registry.findCommands(matches[commandNameIndex], true);
|
||||
if(commands.length !== 1 || !commands[0].defaultHandling) {
|
||||
return message.initCommand(this.registry.unknownCommand, prefixless ? message.content : matches[1]);
|
||||
}
|
||||
const argString = message.content.substring(matches[1].length + (matches[2] ? matches[2].length : 0));
|
||||
return message.initCommand(commands[0], argString);
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a regular expression to match the command prefix and name in a message
|
||||
* @param {?string} prefix - Prefix to build the pattern for
|
||||
* @return {RegExp}
|
||||
* @private
|
||||
*/
|
||||
buildCommandPattern(prefix) {
|
||||
let pattern;
|
||||
if(prefix) {
|
||||
const escapedPrefix = escapeRegex(prefix);
|
||||
pattern = new RegExp(
|
||||
`^(<@!?${this.client.user.id}>\\s+(?:${escapedPrefix}\\s*)?|${escapedPrefix}\\s*)([^\\s]+)`, 'i'
|
||||
);
|
||||
} else {
|
||||
pattern = new RegExp(`(^<@!?${this.client.user.id}>\\s+)([^\\s]+)`, 'i');
|
||||
}
|
||||
this._commandPatterns[prefix] = pattern;
|
||||
this.client.emit('debug', `Built command pattern for prefix "${prefix}": ${pattern}`);
|
||||
return pattern;
|
||||
}
|
||||
}
|
||||
|
||||
module.exports = CommandDispatcher;
|
||||
27
node_modules/discord.js-commando/src/errors/command-format.js
generated
vendored
Normal file
27
node_modules/discord.js-commando/src/errors/command-format.js
generated
vendored
Normal file
@@ -0,0 +1,27 @@
|
||||
const FriendlyError = require('./friendly');
|
||||
|
||||
/**
|
||||
* Has a descriptive message for a command not having proper format
|
||||
* @extends {FriendlyError}
|
||||
*/
|
||||
class CommandFormatError extends FriendlyError {
|
||||
/**
|
||||
* @param {CommandoMessage} msg - The command message the error is for
|
||||
*/
|
||||
constructor(msg) {
|
||||
super(
|
||||
`Invalid command usage. The \`${msg.command.name}\` command's accepted format is: ${msg.usage(
|
||||
msg.command.format,
|
||||
msg.guild ? undefined : null,
|
||||
msg.guild ? undefined : null
|
||||
)}. Use ${msg.anyUsage(
|
||||
`help ${msg.command.name}`,
|
||||
msg.guild ? undefined : null,
|
||||
msg.guild ? undefined : null
|
||||
)} for more information.`
|
||||
);
|
||||
this.name = 'CommandFormatError';
|
||||
}
|
||||
}
|
||||
|
||||
module.exports = CommandFormatError;
|
||||
13
node_modules/discord.js-commando/src/errors/friendly.js
generated
vendored
Normal file
13
node_modules/discord.js-commando/src/errors/friendly.js
generated
vendored
Normal file
@@ -0,0 +1,13 @@
|
||||
/**
|
||||
* Has a message that can be considered user-friendly
|
||||
* @extends {Error}
|
||||
*/
|
||||
class FriendlyError extends Error {
|
||||
/** @param {string} message - The error message */
|
||||
constructor(message) {
|
||||
super(message);
|
||||
this.name = 'FriendlyError';
|
||||
}
|
||||
}
|
||||
|
||||
module.exports = FriendlyError;
|
||||
148
node_modules/discord.js-commando/src/extensions/guild.js
generated
vendored
Normal file
148
node_modules/discord.js-commando/src/extensions/guild.js
generated
vendored
Normal file
@@ -0,0 +1,148 @@
|
||||
const { Structures } = require('discord.js');
|
||||
const Command = require('../commands/base');
|
||||
const GuildSettingsHelper = require('../providers/helper');
|
||||
|
||||
module.exports = Structures.extend('Guild', Guild => {
|
||||
/**
|
||||
* A fancier Guild for fancier people.
|
||||
* @extends Guild
|
||||
*/
|
||||
class CommandoGuild extends Guild {
|
||||
constructor(...args) {
|
||||
super(...args);
|
||||
|
||||
/**
|
||||
* Shortcut to use setting provider methods for this guild
|
||||
* @type {GuildSettingsHelper}
|
||||
*/
|
||||
this.settings = new GuildSettingsHelper(this.client, this);
|
||||
|
||||
/**
|
||||
* Internal command prefix for the guild, controlled by the {@link CommandoGuild#commandPrefix}
|
||||
* getter/setter
|
||||
* @name CommandoGuild#_commandPrefix
|
||||
* @type {?string}
|
||||
* @private
|
||||
*/
|
||||
this._commandPrefix = null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Command prefix in the guild. An empty string indicates that there is no prefix, and only mentions will be used.
|
||||
* Setting to `null` means that the prefix from {@link CommandoClient#commandPrefix} will be used instead.
|
||||
* @type {string}
|
||||
* @emits {@link CommandoClient#commandPrefixChange}
|
||||
*/
|
||||
get commandPrefix() {
|
||||
if(this._commandPrefix === null) return this.client.commandPrefix;
|
||||
return this._commandPrefix;
|
||||
}
|
||||
|
||||
set commandPrefix(prefix) {
|
||||
this._commandPrefix = prefix;
|
||||
/**
|
||||
* Emitted whenever a guild's command prefix is changed
|
||||
* @event CommandoClient#commandPrefixChange
|
||||
* @param {?CommandoGuild} guild - Guild that the prefix was changed in (null for global)
|
||||
* @param {?string} prefix - New command prefix (null for default)
|
||||
*/
|
||||
this.client.emit('commandPrefixChange', this, this._commandPrefix);
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets whether a command is enabled in the guild
|
||||
* @param {CommandResolvable} command - Command to set status of
|
||||
* @param {boolean} enabled - Whether the command should be enabled
|
||||
*/
|
||||
setCommandEnabled(command, enabled) {
|
||||
command = this.client.registry.resolveCommand(command);
|
||||
if(command.guarded) throw new Error('The command is guarded.');
|
||||
if(typeof enabled === 'undefined') throw new TypeError('Enabled must not be undefined.');
|
||||
enabled = Boolean(enabled);
|
||||
if(!this._commandsEnabled) {
|
||||
/**
|
||||
* Map object of internal command statuses, mapped by command name
|
||||
* @type {Object}
|
||||
* @private
|
||||
*/
|
||||
this._commandsEnabled = {};
|
||||
}
|
||||
this._commandsEnabled[command.name] = enabled;
|
||||
/**
|
||||
* Emitted whenever a command is enabled/disabled in a guild
|
||||
* @event CommandoClient#commandStatusChange
|
||||
* @param {?CommandoGuild} guild - Guild that the command was enabled/disabled in (null for global)
|
||||
* @param {Command} command - Command that was enabled/disabled
|
||||
* @param {boolean} enabled - Whether the command is enabled
|
||||
*/
|
||||
this.client.emit('commandStatusChange', this, command, enabled);
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks whether a command is enabled in the guild (does not take the command's group status into account)
|
||||
* @param {CommandResolvable} command - Command to check status of
|
||||
* @return {boolean}
|
||||
*/
|
||||
isCommandEnabled(command) {
|
||||
command = this.client.registry.resolveCommand(command);
|
||||
if(command.guarded) return true;
|
||||
if(!this._commandsEnabled || typeof this._commandsEnabled[command.name] === 'undefined') {
|
||||
return command._globalEnabled;
|
||||
}
|
||||
return this._commandsEnabled[command.name];
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets whether a command group is enabled in the guild
|
||||
* @param {CommandGroupResolvable} group - Group to set status of
|
||||
* @param {boolean} enabled - Whether the group should be enabled
|
||||
*/
|
||||
setGroupEnabled(group, enabled) {
|
||||
group = this.client.registry.resolveGroup(group);
|
||||
if(group.guarded) throw new Error('The group is guarded.');
|
||||
if(typeof enabled === 'undefined') throw new TypeError('Enabled must not be undefined.');
|
||||
enabled = Boolean(enabled);
|
||||
if(!this._groupsEnabled) {
|
||||
/**
|
||||
* Internal map object of group statuses, mapped by group ID
|
||||
* @type {Object}
|
||||
* @private
|
||||
*/
|
||||
this._groupsEnabled = {};
|
||||
}
|
||||
this._groupsEnabled[group.id] = enabled;
|
||||
/**
|
||||
* Emitted whenever a command group is enabled/disabled in a guild
|
||||
* @event CommandoClient#groupStatusChange
|
||||
* @param {?CommandoGuild} guild - Guild that the group was enabled/disabled in (null for global)
|
||||
* @param {CommandGroup} group - Group that was enabled/disabled
|
||||
* @param {boolean} enabled - Whether the group is enabled
|
||||
*/
|
||||
this.client.emit('groupStatusChange', this, group, enabled);
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks whether a command group is enabled in the guild
|
||||
* @param {CommandGroupResolvable} group - Group to check status of
|
||||
* @return {boolean}
|
||||
*/
|
||||
isGroupEnabled(group) {
|
||||
group = this.client.registry.resolveGroup(group);
|
||||
if(group.guarded) return true;
|
||||
if(!this._groupsEnabled || typeof this._groupsEnabled[group.id] === 'undefined') return group._globalEnabled;
|
||||
return this._groupsEnabled[group.id];
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a command usage string using the guild's prefix
|
||||
* @param {string} [command] - A command + arg string
|
||||
* @param {User} [user=this.client.user] - User to use for the mention command format
|
||||
* @return {string}
|
||||
*/
|
||||
commandUsage(command, user = this.client.user) {
|
||||
return Command.usage(command, this.commandPrefix, user);
|
||||
}
|
||||
}
|
||||
|
||||
return CommandoGuild;
|
||||
});
|
||||
534
node_modules/discord.js-commando/src/extensions/message.js
generated
vendored
Normal file
534
node_modules/discord.js-commando/src/extensions/message.js
generated
vendored
Normal file
@@ -0,0 +1,534 @@
|
||||
const { Structures, escapeMarkdown, splitMessage, resolveString } = require('discord.js');
|
||||
const { oneLine } = require('common-tags');
|
||||
const Command = require('../commands/base');
|
||||
const FriendlyError = require('../errors/friendly');
|
||||
const CommandFormatError = require('../errors/command-format');
|
||||
|
||||
module.exports = Structures.extend('Message', Message => {
|
||||
/**
|
||||
* An extension of the base Discord.js Message class to add command-related functionality.
|
||||
* @extends Message
|
||||
*/
|
||||
class CommandoMessage extends Message {
|
||||
constructor(...args) {
|
||||
super(...args);
|
||||
|
||||
/**
|
||||
* Whether the message contains a command (even an unknown one)
|
||||
* @type {boolean}
|
||||
*/
|
||||
this.isCommand = false;
|
||||
|
||||
/**
|
||||
* Command that the message triggers, if any
|
||||
* @type {?Command}
|
||||
*/
|
||||
this.command = null;
|
||||
|
||||
/**
|
||||
* Argument string for the command
|
||||
* @type {?string}
|
||||
*/
|
||||
this.argString = null;
|
||||
|
||||
/**
|
||||
* Pattern matches (if from a pattern trigger)
|
||||
* @type {?string[]}
|
||||
*/
|
||||
this.patternMatches = null;
|
||||
|
||||
/**
|
||||
* Response messages sent, mapped by channel ID (set by the dispatcher after running the command)
|
||||
* @type {?Object}
|
||||
*/
|
||||
this.responses = null;
|
||||
|
||||
/**
|
||||
* Index of the current response that will be edited, mapped by channel ID
|
||||
* @type {?Object}
|
||||
*/
|
||||
this.responsePositions = null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Initialises the message for a command
|
||||
* @param {Command} [command] - Command the message triggers
|
||||
* @param {string} [argString] - Argument string for the command
|
||||
* @param {?Array<string>} [patternMatches] - Command pattern matches (if from a pattern trigger)
|
||||
* @return {Message} This message
|
||||
* @private
|
||||
*/
|
||||
initCommand(command, argString, patternMatches) {
|
||||
this.isCommand = true;
|
||||
this.command = command;
|
||||
this.argString = argString;
|
||||
this.patternMatches = patternMatches;
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a usage string for the message's command
|
||||
* @param {string} [argString] - A string of arguments for the command
|
||||
* @param {string} [prefix=this.guild.commandPrefix || this.client.commandPrefix] - Prefix to use for the
|
||||
* prefixed command format
|
||||
* @param {User} [user=this.client.user] - User to use for the mention command format
|
||||
* @return {string}
|
||||
*/
|
||||
usage(argString, prefix, user = this.client.user) {
|
||||
if(typeof prefix === 'undefined') {
|
||||
if(this.guild) prefix = this.guild.commandPrefix;
|
||||
else prefix = this.client.commandPrefix;
|
||||
}
|
||||
return this.command.usage(argString, prefix, user);
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a usage string for any command
|
||||
* @param {string} [command] - A command + arg string
|
||||
* @param {string} [prefix=this.guild.commandPrefix || this.client.commandPrefix] - Prefix to use for the
|
||||
* prefixed command format
|
||||
* @param {User} [user=this.client.user] - User to use for the mention command format
|
||||
* @return {string}
|
||||
*/
|
||||
anyUsage(command, prefix, user = this.client.user) {
|
||||
if(typeof prefix === 'undefined') {
|
||||
if(this.guild) prefix = this.guild.commandPrefix;
|
||||
else prefix = this.client.commandPrefix;
|
||||
}
|
||||
return Command.usage(command, prefix, user);
|
||||
}
|
||||
|
||||
/**
|
||||
* Parses the argString into usable arguments, based on the argsType and argsCount of the command
|
||||
* @return {string|string[]}
|
||||
* @see {@link Command#run}
|
||||
*/
|
||||
parseArgs() {
|
||||
switch(this.command.argsType) {
|
||||
case 'single':
|
||||
return this.argString.trim().replace(
|
||||
this.command.argsSingleQuotes ? /^("|')([^]*)\1$/g : /^(")([^]*)"$/g, '$2'
|
||||
);
|
||||
case 'multiple':
|
||||
return this.constructor.parseArgs(this.argString, this.command.argsCount, this.command.argsSingleQuotes);
|
||||
default:
|
||||
throw new RangeError(`Unknown argsType "${this.argsType}".`);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Runs the command
|
||||
* @return {Promise<?Message|?Array<Message>>}
|
||||
*/
|
||||
async run() { // eslint-disable-line complexity
|
||||
// Obtain the member if we don't have it
|
||||
if(this.channel.type === 'text' && !this.guild.members.cache.has(this.author.id) && !this.webhookID) {
|
||||
this.member = await this.guild.members.fetch(this.author);
|
||||
}
|
||||
|
||||
// Obtain the member for the ClientUser if it doesn't already exist
|
||||
if(this.channel.type === 'text' && !this.guild.members.cache.has(this.client.user.id)) {
|
||||
await this.guild.members.fetch(this.client.user.id);
|
||||
}
|
||||
|
||||
// Make sure the command is usable in this context
|
||||
if(this.command.guildOnly && !this.guild) {
|
||||
/**
|
||||
* Emitted when a command is prevented from running
|
||||
* @event CommandoClient#commandBlock
|
||||
* @param {CommandoMessage} message - Command message that the command is running from
|
||||
* @param {string} reason - Reason that the command was blocked
|
||||
* (built-in reasons are `guildOnly`, `nsfw`, `permission`, `throttling`, and `clientPermissions`)
|
||||
* @param {Object} [data] - Additional data associated with the block. Built-in reason data properties:
|
||||
* - guildOnly: none
|
||||
* - nsfw: none
|
||||
* - permission: `response` ({@link string}) to send
|
||||
* - throttling: `throttle` ({@link Object}), `remaining` ({@link number}) time in seconds
|
||||
* - clientPermissions: `missing` ({@link Array}<{@link string}>) permission names
|
||||
*/
|
||||
this.client.emit('commandBlock', this, 'guildOnly');
|
||||
return this.command.onBlock(this, 'guildOnly');
|
||||
}
|
||||
|
||||
// Ensure the channel is a NSFW one if required
|
||||
if(this.command.nsfw && !this.channel.nsfw) {
|
||||
this.client.emit('commandBlock', this, 'nsfw');
|
||||
return this.command.onBlock(this, 'nsfw');
|
||||
}
|
||||
|
||||
// Ensure the user has permission to use the command
|
||||
const hasPermission = this.command.hasPermission(this);
|
||||
if(!hasPermission || typeof hasPermission === 'string') {
|
||||
const data = { response: typeof hasPermission === 'string' ? hasPermission : undefined };
|
||||
this.client.emit('commandBlock', this, 'permission', data);
|
||||
return this.command.onBlock(this, 'permission', data);
|
||||
}
|
||||
|
||||
// Ensure the client user has the required permissions
|
||||
if(this.channel.type === 'text' && this.command.clientPermissions) {
|
||||
const missing = this.channel.permissionsFor(this.client.user).missing(this.command.clientPermissions);
|
||||
if(missing.length > 0) {
|
||||
const data = { missing };
|
||||
this.client.emit('commandBlock', this, 'clientPermissions', data);
|
||||
return this.command.onBlock(this, 'clientPermissions', data);
|
||||
}
|
||||
}
|
||||
|
||||
// Throttle the command
|
||||
const throttle = this.command.throttle(this.author.id);
|
||||
if(throttle && throttle.usages + 1 > this.command.throttling.usages) {
|
||||
const remaining = (throttle.start + (this.command.throttling.duration * 1000) - Date.now()) / 1000;
|
||||
const data = { throttle, remaining };
|
||||
this.client.emit('commandBlock', this, 'throttling', data);
|
||||
return this.command.onBlock(this, 'throttling', data);
|
||||
}
|
||||
|
||||
// Figure out the command arguments
|
||||
let args = this.patternMatches;
|
||||
let collResult = null;
|
||||
if(!args && this.command.argsCollector) {
|
||||
const collArgs = this.command.argsCollector.args;
|
||||
const count = collArgs[collArgs.length - 1].infinite ? Infinity : collArgs.length;
|
||||
const provided = this.constructor.parseArgs(this.argString.trim(), count, this.command.argsSingleQuotes);
|
||||
|
||||
collResult = await this.command.argsCollector.obtain(this, provided);
|
||||
if(collResult.cancelled) {
|
||||
if(collResult.prompts.length === 0 || collResult.cancelled === 'promptLimit') {
|
||||
const err = new CommandFormatError(this);
|
||||
return this.reply(err.message);
|
||||
}
|
||||
/**
|
||||
* Emitted when a command is cancelled (either by typing 'cancel' or not responding in time)
|
||||
* @event CommandoClient#commandCancel
|
||||
* @param {Command} command - Command that was cancelled
|
||||
* @param {string} reason - Reason for the command being cancelled
|
||||
* @param {CommandoMessage} message - Command message that the command ran from (see {@link Command#run})
|
||||
* @param {?ArgumentCollectorResult} result - Result from obtaining the arguments from the collector
|
||||
* (if applicable - see {@link Command#run})
|
||||
*/
|
||||
this.client.emit('commandCancel', this.command, collResult.cancelled, this, collResult);
|
||||
return this.reply('Cancelled command.');
|
||||
}
|
||||
args = collResult.values;
|
||||
}
|
||||
if(!args) args = this.parseArgs();
|
||||
const fromPattern = Boolean(this.patternMatches);
|
||||
|
||||
// Run the command
|
||||
if(throttle) throttle.usages++;
|
||||
const typingCount = this.channel.typingCount;
|
||||
try {
|
||||
this.client.emit('debug', `Running command ${this.command.groupID}:${this.command.memberName}.`);
|
||||
const promise = this.command.run(this, args, fromPattern, collResult);
|
||||
/**
|
||||
* Emitted when running a command
|
||||
* @event CommandoClient#commandRun
|
||||
* @param {Command} command - Command that is being run
|
||||
* @param {Promise} promise - Promise for the command result
|
||||
* @param {CommandoMessage} message - Command message that the command is running from (see {@link Command#run})
|
||||
* @param {Object|string|string[]} args - Arguments for the command (see {@link Command#run})
|
||||
* @param {boolean} fromPattern - Whether the args are pattern matches (see {@link Command#run})
|
||||
* @param {?ArgumentCollectorResult} result - Result from obtaining the arguments from the collector
|
||||
* (if applicable - see {@link Command#run})
|
||||
*/
|
||||
this.client.emit('commandRun', this.command, promise, this, args, fromPattern, collResult);
|
||||
const retVal = await promise;
|
||||
if(!(retVal instanceof Message || retVal instanceof Array || retVal === null || retVal === undefined)) {
|
||||
throw new TypeError(oneLine`
|
||||
Command ${this.command.name}'s run() resolved with an unknown type
|
||||
(${retVal !== null ? retVal && retVal.constructor ? retVal.constructor.name : typeof retVal : null}).
|
||||
Command run methods must return a Promise that resolve with a Message, Array of Messages, or null/undefined.
|
||||
`);
|
||||
}
|
||||
return retVal;
|
||||
} catch(err) {
|
||||
/**
|
||||
* Emitted when a command produces an error while running
|
||||
* @event CommandoClient#commandError
|
||||
* @param {Command} command - Command that produced an error
|
||||
* @param {Error} err - Error that was thrown
|
||||
* @param {CommandoMessage} message - Command message that the command is running from (see {@link Command#run})
|
||||
* @param {Object|string|string[]} args - Arguments for the command (see {@link Command#run})
|
||||
* @param {boolean} fromPattern - Whether the args are pattern matches (see {@link Command#run})
|
||||
* @param {?ArgumentCollectorResult} result - Result from obtaining the arguments from the collector
|
||||
* (if applicable - see {@link Command#run})
|
||||
*/
|
||||
this.client.emit('commandError', this.command, err, this, args, fromPattern, collResult);
|
||||
if(this.channel.typingCount > typingCount) this.channel.stopTyping();
|
||||
if(err instanceof FriendlyError) {
|
||||
return this.reply(err.message);
|
||||
} else {
|
||||
return this.command.onError(err, this, args, fromPattern, collResult);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Responds to the command message
|
||||
* @param {Object} [options] - Options for the response
|
||||
* @return {Message|Message[]}
|
||||
* @private
|
||||
*/
|
||||
respond({ type = 'reply', content, options, lang, fromEdit = false }) {
|
||||
const shouldEdit = this.responses && !fromEdit;
|
||||
if(shouldEdit) {
|
||||
if(options && options.split && typeof options.split !== 'object') options.split = {};
|
||||
}
|
||||
|
||||
if(type === 'reply' && this.channel.type === 'dm') type = 'plain';
|
||||
if(type !== 'direct') {
|
||||
if(this.guild && !this.channel.permissionsFor(this.client.user).has('SEND_MESSAGES')) {
|
||||
type = 'direct';
|
||||
}
|
||||
}
|
||||
|
||||
content = resolveString(content);
|
||||
|
||||
switch(type) {
|
||||
case 'plain':
|
||||
if(!shouldEdit) return this.channel.send(content, options);
|
||||
return this.editCurrentResponse(channelIDOrDM(this.channel), { type, content, options });
|
||||
case 'reply':
|
||||
if(!shouldEdit) return super.reply(content, options);
|
||||
if(options && options.split && !options.split.prepend) options.split.prepend = `${this.author}, `;
|
||||
return this.editCurrentResponse(channelIDOrDM(this.channel), { type, content, options });
|
||||
case 'direct':
|
||||
if(!shouldEdit) return this.author.send(content, options);
|
||||
return this.editCurrentResponse('dm', { type, content, options });
|
||||
case 'code':
|
||||
if(!shouldEdit) return this.channel.send(content, options);
|
||||
if(options && options.split) {
|
||||
if(!options.split.prepend) options.split.prepend = `\`\`\`${lang || ''}\n`;
|
||||
if(!options.split.append) options.split.append = '\n```';
|
||||
}
|
||||
content = `\`\`\`${lang || ''}\n${escapeMarkdown(content, true)}\n\`\`\``;
|
||||
return this.editCurrentResponse(channelIDOrDM(this.channel), { type, content, options });
|
||||
default:
|
||||
throw new RangeError(`Unknown response type "${type}".`);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Edits a response to the command message
|
||||
* @param {Message|Message[]} response - The response message(s) to edit
|
||||
* @param {Object} [options] - Options for the response
|
||||
* @return {Promise<Message|Message[]>}
|
||||
* @private
|
||||
*/
|
||||
editResponse(response, { type, content, options }) {
|
||||
if(!response) return this.respond({ type, content, options, fromEdit: true });
|
||||
if(options && options.split) content = splitMessage(content, options.split);
|
||||
|
||||
let prepend = '';
|
||||
if(type === 'reply') prepend = `${this.author}, `;
|
||||
|
||||
if(content instanceof Array) {
|
||||
const promises = [];
|
||||
if(response instanceof Array) {
|
||||
for(let i = 0; i < content.length; i++) {
|
||||
if(response.length > i) promises.push(response[i].edit(`${prepend}${content[i]}`, options));
|
||||
else promises.push(response[0].channel.send(`${prepend}${content[i]}`));
|
||||
}
|
||||
} else {
|
||||
promises.push(response.edit(`${prepend}${content[0]}`, options));
|
||||
for(let i = 1; i < content.length; i++) {
|
||||
promises.push(response.channel.send(`${prepend}${content[i]}`));
|
||||
}
|
||||
}
|
||||
return Promise.all(promises);
|
||||
} else {
|
||||
if(response instanceof Array) { // eslint-disable-line no-lonely-if
|
||||
for(let i = response.length - 1; i > 0; i--) response[i].delete();
|
||||
return response[0].edit(`${prepend}${content}`, options);
|
||||
} else {
|
||||
return response.edit(`${prepend}${content}`, options);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Edits the current response
|
||||
* @param {string} id - The ID of the channel the response is in ("DM" for direct messages)
|
||||
* @param {Object} [options] - Options for the response
|
||||
* @return {Promise<Message|Message[]>}
|
||||
* @private
|
||||
*/
|
||||
editCurrentResponse(id, options) {
|
||||
if(typeof this.responses[id] === 'undefined') this.responses[id] = [];
|
||||
if(typeof this.responsePositions[id] === 'undefined') this.responsePositions[id] = -1;
|
||||
this.responsePositions[id]++;
|
||||
return this.editResponse(this.responses[id][this.responsePositions[id]], options);
|
||||
}
|
||||
|
||||
/**
|
||||
* Responds with a plain message
|
||||
* @param {StringResolvable} content - Content for the message
|
||||
* @param {MessageOptions} [options] - Options for the message
|
||||
* @return {Promise<Message|Message[]>}
|
||||
*/
|
||||
say(content, options) {
|
||||
if(!options && typeof content === 'object' && !(content instanceof Array)) {
|
||||
options = content;
|
||||
content = '';
|
||||
}
|
||||
return this.respond({ type: 'plain', content, options });
|
||||
}
|
||||
|
||||
/**
|
||||
* Responds with a reply message
|
||||
* @param {StringResolvable} content - Content for the message
|
||||
* @param {MessageOptions} [options] - Options for the message
|
||||
* @return {Promise<Message|Message[]>}
|
||||
*/
|
||||
reply(content, options) {
|
||||
if(!options && typeof content === 'object' && !(content instanceof Array)) {
|
||||
options = content;
|
||||
content = '';
|
||||
}
|
||||
return this.respond({ type: 'reply', content, options });
|
||||
}
|
||||
|
||||
/**
|
||||
* Responds with a direct message
|
||||
* @param {StringResolvable} content - Content for the message
|
||||
* @param {MessageOptions} [options] - Options for the message
|
||||
* @return {Promise<Message|Message[]>}
|
||||
*/
|
||||
direct(content, options) {
|
||||
if(!options && typeof content === 'object' && !(content instanceof Array)) {
|
||||
options = content;
|
||||
content = '';
|
||||
}
|
||||
return this.respond({ type: 'direct', content, options });
|
||||
}
|
||||
|
||||
/**
|
||||
* Responds with a code message
|
||||
* @param {string} lang - Language for the code block
|
||||
* @param {StringResolvable} content - Content for the message
|
||||
* @param {MessageOptions} [options] - Options for the message
|
||||
* @return {Promise<Message|Message[]>}
|
||||
*/
|
||||
code(lang, content, options) {
|
||||
if(!options && typeof content === 'object' && !(content instanceof Array)) {
|
||||
options = content;
|
||||
content = '';
|
||||
}
|
||||
if(typeof options !== 'object') options = {};
|
||||
options.code = lang;
|
||||
return this.respond({ type: 'code', content, options });
|
||||
}
|
||||
|
||||
/**
|
||||
* Responds with an embed
|
||||
* @param {RichEmbed|Object} embed - Embed to send
|
||||
* @param {StringResolvable} [content] - Content for the message
|
||||
* @param {MessageOptions} [options] - Options for the message
|
||||
* @return {Promise<Message|Message[]>}
|
||||
*/
|
||||
embed(embed, content = '', options) {
|
||||
if(typeof options !== 'object') options = {};
|
||||
options.embed = embed;
|
||||
return this.respond({ type: 'plain', content, options });
|
||||
}
|
||||
|
||||
/**
|
||||
* Responds with a mention + embed
|
||||
* @param {RichEmbed|Object} embed - Embed to send
|
||||
* @param {StringResolvable} [content] - Content for the message
|
||||
* @param {MessageOptions} [options] - Options for the message
|
||||
* @return {Promise<Message|Message[]>}
|
||||
*/
|
||||
replyEmbed(embed, content = '', options) {
|
||||
if(typeof options !== 'object') options = {};
|
||||
options.embed = embed;
|
||||
return this.respond({ type: 'reply', content, options });
|
||||
}
|
||||
|
||||
/**
|
||||
* Finalizes the command message by setting the responses and deleting any remaining prior ones
|
||||
* @param {?Array<Message|Message[]>} responses - Responses to the message
|
||||
* @private
|
||||
*/
|
||||
finalize(responses) {
|
||||
if(this.responses) this.deleteRemainingResponses();
|
||||
this.responses = {};
|
||||
this.responsePositions = {};
|
||||
|
||||
if(responses instanceof Array) {
|
||||
for(const response of responses) {
|
||||
const channel = (response instanceof Array ? response[0] : response).channel;
|
||||
const id = channelIDOrDM(channel);
|
||||
if(!this.responses[id]) {
|
||||
this.responses[id] = [];
|
||||
this.responsePositions[id] = -1;
|
||||
}
|
||||
this.responses[id].push(response);
|
||||
}
|
||||
} else if(responses) {
|
||||
const id = channelIDOrDM(responses.channel);
|
||||
this.responses[id] = [responses];
|
||||
this.responsePositions[id] = -1;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Deletes any prior responses that haven't been updated
|
||||
* @private
|
||||
*/
|
||||
deleteRemainingResponses() {
|
||||
for(const id of Object.keys(this.responses)) {
|
||||
const responses = this.responses[id];
|
||||
for(let i = this.responsePositions[id] + 1; i < responses.length; i++) {
|
||||
const response = responses[i];
|
||||
if(response instanceof Array) {
|
||||
for(const resp of response) resp.delete();
|
||||
} else {
|
||||
response.delete();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Parses an argument string into an array of arguments
|
||||
* @param {string} argString - The argument string to parse
|
||||
* @param {number} [argCount] - The number of arguments to extract from the string
|
||||
* @param {boolean} [allowSingleQuote=true] - Whether or not single quotes should be allowed to wrap arguments,
|
||||
* in addition to double quotes
|
||||
* @return {string[]} The array of arguments
|
||||
*/
|
||||
static parseArgs(argString, argCount, allowSingleQuote = true) {
|
||||
const argStringModified = removeSmartQuotes(argString, allowSingleQuote);
|
||||
const re = allowSingleQuote ? /\s*(?:("|')([^]*?)\1|(\S+))\s*/g : /\s*(?:(")([^]*?)"|(\S+))\s*/g;
|
||||
const result = [];
|
||||
let match = [];
|
||||
// Large enough to get all items
|
||||
argCount = argCount || argStringModified.length;
|
||||
// Get match and push the capture group that is not null to the result
|
||||
while(--argCount && (match = re.exec(argStringModified))) result.push(match[2] || match[3]);
|
||||
// If text remains, push it to the array as-is (except for wrapping quotes, which are removed)
|
||||
if(match && re.lastIndex < argStringModified.length) {
|
||||
const re2 = allowSingleQuote ? /^("|')([^]*)\1$/g : /^(")([^]*)"$/g;
|
||||
result.push(argStringModified.substr(re.lastIndex).replace(re2, '$2'));
|
||||
}
|
||||
return result;
|
||||
}
|
||||
}
|
||||
|
||||
return CommandoMessage;
|
||||
});
|
||||
|
||||
function removeSmartQuotes(argString, allowSingleQuote = true) {
|
||||
let replacementArgString = argString;
|
||||
const singleSmartQuote = /[‘’]/g;
|
||||
const doubleSmartQuote = /[“”]/g;
|
||||
if(allowSingleQuote) replacementArgString = argString.replace(singleSmartQuote, '\'');
|
||||
return replacementArgString
|
||||
.replace(doubleSmartQuote, '"');
|
||||
}
|
||||
|
||||
function channelIDOrDM(channel) {
|
||||
if(channel.type !== 'dm') return channel.id;
|
||||
return 'dm';
|
||||
}
|
||||
127
node_modules/discord.js-commando/src/index.js
generated
vendored
Normal file
127
node_modules/discord.js-commando/src/index.js
generated
vendored
Normal file
@@ -0,0 +1,127 @@
|
||||
module.exports = {
|
||||
Client: require('./client'),
|
||||
CommandoClient: require('./client'),
|
||||
CommandoRegistry: require('./registry'),
|
||||
CommandDispatcher: require('./dispatcher'),
|
||||
CommandoGuild: require('./extensions/guild'),
|
||||
CommandoMessage: require('./extensions/message'),
|
||||
Command: require('./commands/base'),
|
||||
CommandGroup: require('./commands/group'),
|
||||
ArgumentCollector: require('./commands/collector'),
|
||||
Argument: require('./commands/argument'),
|
||||
ArgumentType: require('./types/base'),
|
||||
FriendlyError: require('./errors/friendly'),
|
||||
CommandFormatError: require('./errors/command-format'),
|
||||
|
||||
util: require('./util'),
|
||||
version: require('../package').version,
|
||||
|
||||
SettingProvider: require('./providers/base'),
|
||||
get SQLiteProvider() {
|
||||
return require('./providers/sqlite');
|
||||
},
|
||||
get SyncSQLiteProvider() {
|
||||
return require('./providers/sqlite-sync');
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* @external Channel
|
||||
* @see {@link https://discord.js.org/#/docs/main/master/class/Channel}
|
||||
*/
|
||||
/**
|
||||
* @external Client
|
||||
* @see {@link https://discord.js.org/#/docs/main/master/class/Client}
|
||||
*/
|
||||
/**
|
||||
* @external ClientOptions
|
||||
* @see {@link https://discord.js.org/#/docs/main/master/typedef/ClientOptions}
|
||||
*/
|
||||
/**
|
||||
* @external Collection
|
||||
* @see {@link https://discord.js.org/#/docs/main/master/class/Collection}
|
||||
*/
|
||||
/**
|
||||
* @external DMChannel
|
||||
* @see {@link https://discord.js.org/#/docs/main/master/class/DMChannel}
|
||||
*/
|
||||
/**
|
||||
* @external Guild
|
||||
* @see {@link https://discord.js.org/#/docs/main/master/class/Guild}
|
||||
*/
|
||||
/**
|
||||
* @external GuildMember
|
||||
* @see {@link https://discord.js.org/#/docs/main/master/class/GuildMember}
|
||||
*/
|
||||
/**
|
||||
* @external GuildResolvable
|
||||
* @see {@link https://discord.js.org/#/docs/main/master/typedef/GuildResolvable}
|
||||
*/
|
||||
/**
|
||||
* @external Message
|
||||
* @see {@link https://discord.js.org/#/docs/main/master/class/Message}
|
||||
*/
|
||||
/**
|
||||
* @external MessageAttachment
|
||||
* @see {@link https://discord.js.org/#/docs/main/master/class/MessageAttachment}
|
||||
*/
|
||||
/**
|
||||
* @external MessageEmbed
|
||||
* @see {@link https://discord.js.org/#/docs/main/master/class/MessageEmbed}
|
||||
*/
|
||||
/**
|
||||
* @external MessageReaction
|
||||
* @see {@link https://discord.js.org/#/docs/main/master/class/MessageReaction}
|
||||
*/
|
||||
/**
|
||||
* @external MessageOptions
|
||||
* @see {@link https://discord.js.org/#/docs/main/master/typedef/MessageOptions}
|
||||
*/
|
||||
/**
|
||||
* @external PermissionResolvable
|
||||
* @see {@link https://discord.js.org/#/docs/main/master/typedef/PermissionResolvable}
|
||||
*/
|
||||
/**
|
||||
* @external Role
|
||||
* @see {@link https://discord.js.org/#/docs/main/master/class/Role}
|
||||
*/
|
||||
/**
|
||||
* @external StringResolvable
|
||||
* @see {@link https://discord.js.org/#/docs/main/master/typedef/StringResolvable}
|
||||
*/
|
||||
/**
|
||||
* @external TextChannel
|
||||
* @see {@link https://discord.js.org/#/docs/main/master/class/TextChannel}
|
||||
*/
|
||||
/**
|
||||
* @external User
|
||||
* @see {@link https://discord.js.org/#/docs/main/master/class/User}
|
||||
*/
|
||||
/**
|
||||
* @external UserResolvable
|
||||
* @see {@link https://discord.js.org/#/docs/main/master/class/UserResolvable}
|
||||
*/
|
||||
/**
|
||||
* @external Emoji
|
||||
* @see {@link https://discord.js.org/#/docs/main/master/class/Emoji}
|
||||
*/
|
||||
/**
|
||||
* @external ReactionEmoji
|
||||
* @see {@link https://discord.js.org/#/docs/main/master/class/ReactionEmoji}
|
||||
*/
|
||||
/**
|
||||
* @external Webhook
|
||||
* @see {@link https://discord.js.org/#/docs/main/master/class/Webhook}
|
||||
*/
|
||||
/**
|
||||
* @external MessageEmbed
|
||||
* @see {@link https://discord.js.org/#/docs/main/master/class/MessageEmbed}
|
||||
*/
|
||||
/**
|
||||
* @external ShardingManager
|
||||
* @see {@link https://discord.js.org/#/docs/main/master/class/ShardingManager}
|
||||
*/
|
||||
/**
|
||||
* @external RequireAllOptions
|
||||
* @see {@link https://www.npmjs.com/package/require-all}
|
||||
*/
|
||||
79
node_modules/discord.js-commando/src/providers/base.js
generated
vendored
Normal file
79
node_modules/discord.js-commando/src/providers/base.js
generated
vendored
Normal file
@@ -0,0 +1,79 @@
|
||||
/* eslint-disable no-unused-vars */
|
||||
const { Guild } = require('discord.js');
|
||||
|
||||
/**
|
||||
* Loads and stores settings associated with guilds
|
||||
* @abstract
|
||||
*/
|
||||
class SettingProvider {
|
||||
constructor() {
|
||||
if(this.constructor.name === 'SettingProvider') throw new Error('The base SettingProvider cannot be instantiated.');
|
||||
}
|
||||
|
||||
/**
|
||||
* Initialises the provider by connecting to databases and/or caching all data in memory.
|
||||
* {@link CommandoClient#setProvider} will automatically call this once the client is ready.
|
||||
* @param {CommandoClient} client - Client that will be using the provider
|
||||
* @return {Promise<void>}
|
||||
* @abstract
|
||||
*/
|
||||
init(client) { throw new Error(`${this.constructor.name} doesn't have an init method.`); }
|
||||
|
||||
/**
|
||||
* Destroys the provider, removing any event listeners.
|
||||
* @return {Promise<void>}
|
||||
* @abstract
|
||||
*/
|
||||
destroy() { throw new Error(`${this.constructor.name} doesn't have a destroy method.`); }
|
||||
|
||||
/**
|
||||
* Obtains a setting for a guild
|
||||
* @param {Guild|string} guild - Guild the setting is associated with (or 'global')
|
||||
* @param {string} key - Name of the setting
|
||||
* @param {*} [defVal] - Value to default to if the setting isn't set on the guild
|
||||
* @return {*}
|
||||
* @abstract
|
||||
*/
|
||||
get(guild, key, defVal) { throw new Error(`${this.constructor.name} doesn't have a get method.`); }
|
||||
|
||||
/**
|
||||
* Sets a setting for a guild
|
||||
* @param {Guild|string} guild - Guild to associate the setting with (or 'global')
|
||||
* @param {string} key - Name of the setting
|
||||
* @param {*} val - Value of the setting
|
||||
* @return {Promise<*>} New value of the setting
|
||||
* @abstract
|
||||
*/
|
||||
set(guild, key, val) { throw new Error(`${this.constructor.name} doesn't have a set method.`); }
|
||||
|
||||
/**
|
||||
* Removes a setting from a guild
|
||||
* @param {Guild|string} guild - Guild the setting is associated with (or 'global')
|
||||
* @param {string} key - Name of the setting
|
||||
* @return {Promise<*>} Old value of the setting
|
||||
* @abstract
|
||||
*/
|
||||
remove(guild, key) { throw new Error(`${this.constructor.name} doesn't have a remove method.`); }
|
||||
|
||||
/**
|
||||
* Removes all settings in a guild
|
||||
* @param {Guild|string} guild - Guild to clear the settings of
|
||||
* @return {Promise<void>}
|
||||
* @abstract
|
||||
*/
|
||||
clear(guild) { throw new Error(`${this.constructor.name} doesn't have a clear method.`); }
|
||||
|
||||
/**
|
||||
* Obtains the ID of the provided guild, or throws an error if it isn't valid
|
||||
* @param {Guild|string} guild - Guild to get the ID of
|
||||
* @return {string} ID of the guild, or 'global'
|
||||
*/
|
||||
static getGuildID(guild) {
|
||||
if(guild instanceof Guild) return guild.id;
|
||||
if(guild === 'global' || guild === null) return 'global';
|
||||
if(typeof guild === 'string' && !isNaN(guild)) return guild;
|
||||
throw new TypeError('Invalid guild specified. Must be a Guild instance, guild ID, "global", or null.');
|
||||
}
|
||||
}
|
||||
|
||||
module.exports = SettingProvider;
|
||||
70
node_modules/discord.js-commando/src/providers/helper.js
generated
vendored
Normal file
70
node_modules/discord.js-commando/src/providers/helper.js
generated
vendored
Normal file
@@ -0,0 +1,70 @@
|
||||
/** Helper class to use {@link SettingProvider} methods for a specific Guild */
|
||||
class GuildSettingsHelper {
|
||||
/**
|
||||
* @param {CommandoClient} client - Client to use the provider of
|
||||
* @param {?CommandoGuild} guild - Guild the settings are for
|
||||
* @private
|
||||
*/
|
||||
constructor(client, guild) {
|
||||
/**
|
||||
* Client to use the provider of
|
||||
* @name GuildSettingsHelper#client
|
||||
* @type {CommandoClient}
|
||||
* @readonly
|
||||
*/
|
||||
Object.defineProperty(this, 'client', { value: client });
|
||||
|
||||
/**
|
||||
* Guild the settings are for
|
||||
* @type {?CommandoGuild}
|
||||
*/
|
||||
this.guild = guild;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets a setting in the guild
|
||||
* @param {string} key - Name of the setting
|
||||
* @param {*} [defVal] - Value to default to if the setting isn't set
|
||||
* @return {*}
|
||||
* @see {@link SettingProvider#get}
|
||||
*/
|
||||
get(key, defVal) {
|
||||
if(!this.client.provider) throw new Error('No settings provider is available.');
|
||||
return this.client.provider.get(this.guild, key, defVal);
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets a setting for the guild
|
||||
* @param {string} key - Name of the setting
|
||||
* @param {*} val - Value of the setting
|
||||
* @return {Promise<*>} New value of the setting
|
||||
* @see {@link SettingProvider#set}
|
||||
*/
|
||||
set(key, val) {
|
||||
if(!this.client.provider) throw new Error('No settings provider is available.');
|
||||
return this.client.provider.set(this.guild, key, val);
|
||||
}
|
||||
|
||||
/**
|
||||
* Removes a setting from the guild
|
||||
* @param {string} key - Name of the setting
|
||||
* @return {Promise<*>} Old value of the setting
|
||||
* @see {@link SettingProvider#remove}
|
||||
*/
|
||||
remove(key) {
|
||||
if(!this.client.provider) throw new Error('No settings provider is available.');
|
||||
return this.client.provider.remove(this.guild, key);
|
||||
}
|
||||
|
||||
/**
|
||||
* Removes all settings in the guild
|
||||
* @return {Promise<void>}
|
||||
* @see {@link SettingProvider#clear}
|
||||
*/
|
||||
clear() {
|
||||
if(!this.client.provider) throw new Error('No settings provider is available.');
|
||||
return this.client.provider.clear(this.guild);
|
||||
}
|
||||
}
|
||||
|
||||
module.exports = GuildSettingsHelper;
|
||||
240
node_modules/discord.js-commando/src/providers/sqlite-sync.js
generated
vendored
Normal file
240
node_modules/discord.js-commando/src/providers/sqlite-sync.js
generated
vendored
Normal file
@@ -0,0 +1,240 @@
|
||||
const SettingProvider = require('./base');
|
||||
|
||||
/**
|
||||
* Uses an SQLite database to store settings with guilds
|
||||
* @extends {SettingProvider}
|
||||
*/
|
||||
class SyncSQLiteProvider extends SettingProvider {
|
||||
/**
|
||||
* @external SyncSQLiteDatabase
|
||||
* @see {@link https://www.npmjs.com/package/better-sqlite3}
|
||||
*/
|
||||
|
||||
/**
|
||||
* @param {SyncSQLiteDatabase} conn - Database Connection for the provider
|
||||
*/
|
||||
constructor(conn) {
|
||||
super();
|
||||
|
||||
/**
|
||||
* Database that will be used for storing/retrieving settings
|
||||
* @type {SyncSQLiteDatabase}
|
||||
*/
|
||||
this.conn = conn;
|
||||
|
||||
/**
|
||||
* Client that the provider is for (set once the client is ready, after using {@link CommandoClient#setProvider})
|
||||
* @name SyncSQLiteProvider#client
|
||||
* @type {CommandoClient}
|
||||
* @readonly
|
||||
*/
|
||||
Object.defineProperty(this, 'client', { value: null, writable: true });
|
||||
|
||||
/**
|
||||
* Settings cached in memory, mapped by guild ID (or 'global')
|
||||
* @type {Map}
|
||||
* @private
|
||||
*/
|
||||
this.settings = new Map();
|
||||
|
||||
/**
|
||||
* Listeners on the Client, mapped by the event name
|
||||
* @type {Map}
|
||||
* @private
|
||||
*/
|
||||
this.listeners = new Map();
|
||||
|
||||
/**
|
||||
* Prepared statement to insert or replace a settings row
|
||||
* @type {SyncSQLiteStatement}
|
||||
* @private
|
||||
*/
|
||||
this.insertOrReplaceStmt = null;
|
||||
|
||||
/**
|
||||
* Prepared statement to delete an entire settings row
|
||||
* @type {SyncSQLiteStatement}
|
||||
* @private
|
||||
*/
|
||||
this.deleteStmt = null;
|
||||
|
||||
/**
|
||||
* @external SyncSQLiteStatement
|
||||
* @see {@link https://www.npmjs.com/package/better-sqlite3}
|
||||
*/
|
||||
}
|
||||
|
||||
init(client) {
|
||||
this.client = client;
|
||||
this.conn.prepare('CREATE TABLE IF NOT EXISTS settings (guild INTEGER PRIMARY KEY, settings TEXT)').run();
|
||||
|
||||
// Load all settings
|
||||
const rows = this.conn.prepare('SELECT CAST(guild as TEXT) as guild, settings FROM settings').all();
|
||||
for(const row of rows) {
|
||||
let settings;
|
||||
try {
|
||||
settings = JSON.parse(row.settings);
|
||||
} catch(err) {
|
||||
client.emit('warn', `SyncSQLiteProvider couldn't parse the settings stored for guild ${row.guild}.`);
|
||||
continue;
|
||||
}
|
||||
|
||||
const guild = row.guild !== '0' ? row.guild : 'global';
|
||||
this.settings.set(guild, settings);
|
||||
if(guild !== 'global' && !client.guilds.cache.has(row.guild)) continue;
|
||||
this.setupGuild(guild, settings);
|
||||
}
|
||||
|
||||
// Prepare statements
|
||||
this.insertOrReplaceStmt = this.conn.prepare('INSERT OR REPLACE INTO settings VALUES(?, ?)');
|
||||
this.deleteStmt = this.conn.prepare('DELETE FROM settings WHERE guild = ?');
|
||||
|
||||
// Listen for changes
|
||||
this.listeners
|
||||
.set('commandPrefixChange', (guild, prefix) => this.set(guild, 'prefix', prefix))
|
||||
.set('commandStatusChange', (guild, command, enabled) => this.set(guild, `cmd-${command.name}`, enabled))
|
||||
.set('groupStatusChange', (guild, group, enabled) => this.set(guild, `grp-${group.id}`, enabled))
|
||||
.set('guildCreate', guild => {
|
||||
const settings = this.settings.get(guild.id);
|
||||
if(!settings) return;
|
||||
this.setupGuild(guild.id, settings);
|
||||
})
|
||||
.set('commandRegister', command => {
|
||||
for(const [guild, settings] of this.settings) {
|
||||
if(guild !== 'global' && !client.guilds.cache.has(guild)) continue;
|
||||
this.setupGuildCommand(client.guilds.cache.get(guild), command, settings);
|
||||
}
|
||||
})
|
||||
.set('groupRegister', group => {
|
||||
for(const [guild, settings] of this.settings) {
|
||||
if(guild !== 'global' && !client.guilds.cache.has(guild)) continue;
|
||||
this.setupGuildGroup(client.guilds.cache.get(guild), group, settings);
|
||||
}
|
||||
});
|
||||
for(const [event, listener] of this.listeners) client.on(event, listener);
|
||||
}
|
||||
|
||||
destroy() {
|
||||
// Remove all listeners from the client
|
||||
for(const [event, listener] of this.listeners) this.client.removeListener(event, listener);
|
||||
this.listeners.clear();
|
||||
}
|
||||
|
||||
get(guild, key, defVal) {
|
||||
const settings = this.settings.get(this.constructor.getGuildID(guild));
|
||||
return settings ? typeof settings[key] !== 'undefined' ? settings[key] : defVal : defVal;
|
||||
}
|
||||
|
||||
set(guild, key, val) {
|
||||
guild = this.constructor.getGuildID(guild);
|
||||
let settings = this.settings.get(guild);
|
||||
if(!settings) {
|
||||
settings = {};
|
||||
this.settings.set(guild, settings);
|
||||
}
|
||||
|
||||
settings[key] = val;
|
||||
this.insertOrReplaceStmt.run(guild !== 'global' ? guild : 0, JSON.stringify(settings));
|
||||
if(guild === 'global') this.updateOtherShards(key, val);
|
||||
return val;
|
||||
}
|
||||
|
||||
remove(guild, key) {
|
||||
guild = this.constructor.getGuildID(guild);
|
||||
const settings = this.settings.get(guild);
|
||||
if(!settings || typeof settings[key] === 'undefined') return undefined;
|
||||
|
||||
const val = settings[key];
|
||||
settings[key] = undefined;
|
||||
this.insertOrReplaceStmt.run(guild !== 'global' ? guild : 0, JSON.stringify(settings));
|
||||
if(guild === 'global') this.updateOtherShards(key, undefined);
|
||||
return val;
|
||||
}
|
||||
|
||||
clear(guild) {
|
||||
guild = this.constructor.getGuildID(guild);
|
||||
if(!this.settings.has(guild)) return;
|
||||
this.settings.delete(guild);
|
||||
this.deleteStmt.run(guild !== 'global' ? guild : 0);
|
||||
}
|
||||
|
||||
/**
|
||||
* Loads all settings for a guild
|
||||
* @param {string} guild - Guild ID to load the settings of (or 'global')
|
||||
* @param {Object} settings - Settings to load
|
||||
* @private
|
||||
*/
|
||||
setupGuild(guild, settings) {
|
||||
if(typeof guild !== 'string') throw new TypeError('The guild must be a guild ID or "global".');
|
||||
guild = this.client.guilds.cache.get(guild) || null;
|
||||
|
||||
// Load the command prefix
|
||||
if(typeof settings.prefix !== 'undefined') {
|
||||
if(guild) guild._commandPrefix = settings.prefix;
|
||||
else this.client._commandPrefix = settings.prefix;
|
||||
}
|
||||
|
||||
// Load all command/group statuses
|
||||
for(const command of this.client.registry.commands.values()) this.setupGuildCommand(guild, command, settings);
|
||||
for(const group of this.client.registry.groups.values()) this.setupGuildGroup(guild, group, settings);
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets up a command's status in a guild from the guild's settings
|
||||
* @param {?CommandoGuild} guild - Guild to set the status in
|
||||
* @param {Command} command - Command to set the status of
|
||||
* @param {Object} settings - Settings of the guild
|
||||
* @private
|
||||
*/
|
||||
setupGuildCommand(guild, command, settings) {
|
||||
if(typeof settings[`cmd-${command.name}`] === 'undefined') return;
|
||||
if(guild) {
|
||||
if(!guild._commandsEnabled) guild._commandsEnabled = {};
|
||||
guild._commandsEnabled[command.name] = settings[`cmd-${command.name}`];
|
||||
} else {
|
||||
command._globalEnabled = settings[`cmd-${command.name}`];
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets up a command group's status in a guild from the guild's settings
|
||||
* @param {?CommandoGuild} guild - Guild to set the status in
|
||||
* @param {CommandGroup} group - Group to set the status of
|
||||
* @param {Object} settings - Settings of the guild
|
||||
* @private
|
||||
*/
|
||||
setupGuildGroup(guild, group, settings) {
|
||||
if(typeof settings[`grp-${group.id}`] === 'undefined') return;
|
||||
if(guild) {
|
||||
if(!guild._groupsEnabled) guild._groupsEnabled = {};
|
||||
guild._groupsEnabled[group.id] = settings[`grp-${group.id}`];
|
||||
} else {
|
||||
group._globalEnabled = settings[`grp-${group.id}`];
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Updates a global setting on all other shards if using the {@link ShardingManager}.
|
||||
* @param {string} key - Key of the setting to update
|
||||
* @param {*} val - Value of the setting
|
||||
* @private
|
||||
*/
|
||||
updateOtherShards(key, val) {
|
||||
if(!this.client.shard) return;
|
||||
key = JSON.stringify(key);
|
||||
val = typeof val !== 'undefined' ? JSON.stringify(val) : 'undefined';
|
||||
this.client.shard.broadcastEval(`
|
||||
const ids = [${this.client.shard.ids.join(',')}];
|
||||
if(!this.shard.ids.some(id => ids.includes(id)) && this.provider && this.provider.settings) {
|
||||
let global = this.provider.settings.get('global');
|
||||
if(!global) {
|
||||
global = {};
|
||||
this.provider.settings.set('global', global);
|
||||
}
|
||||
global[${key}] = ${val};
|
||||
}
|
||||
`);
|
||||
}
|
||||
}
|
||||
|
||||
module.exports = SyncSQLiteProvider;
|
||||
250
node_modules/discord.js-commando/src/providers/sqlite.js
generated
vendored
Normal file
250
node_modules/discord.js-commando/src/providers/sqlite.js
generated
vendored
Normal file
@@ -0,0 +1,250 @@
|
||||
const SettingProvider = require('./base');
|
||||
|
||||
/**
|
||||
* Uses an SQLite database to store settings with guilds
|
||||
* @extends {SettingProvider}
|
||||
*/
|
||||
class SQLiteProvider extends SettingProvider {
|
||||
/**
|
||||
* @external SQLiteDatabase
|
||||
* @see {@link https://www.npmjs.com/package/sqlite}
|
||||
*/
|
||||
|
||||
/**
|
||||
* @param {SQLiteDatabase} db - Database for the provider
|
||||
*/
|
||||
constructor(db) {
|
||||
super();
|
||||
|
||||
/**
|
||||
* Database that will be used for storing/retrieving settings
|
||||
* @type {SQLiteDatabase}
|
||||
*/
|
||||
this.db = db;
|
||||
|
||||
/**
|
||||
* Client that the provider is for (set once the client is ready, after using {@link CommandoClient#setProvider})
|
||||
* @name SQLiteProvider#client
|
||||
* @type {CommandoClient}
|
||||
* @readonly
|
||||
*/
|
||||
Object.defineProperty(this, 'client', { value: null, writable: true });
|
||||
|
||||
/**
|
||||
* Settings cached in memory, mapped by guild ID (or 'global')
|
||||
* @type {Map}
|
||||
* @private
|
||||
*/
|
||||
this.settings = new Map();
|
||||
|
||||
/**
|
||||
* Listeners on the Client, mapped by the event name
|
||||
* @type {Map}
|
||||
* @private
|
||||
*/
|
||||
this.listeners = new Map();
|
||||
|
||||
/**
|
||||
* Prepared statement to insert or replace a settings row
|
||||
* @type {SQLiteStatement}
|
||||
* @private
|
||||
*/
|
||||
this.insertOrReplaceStmt = null;
|
||||
|
||||
/**
|
||||
* Prepared statement to delete an entire settings row
|
||||
* @type {SQLiteStatement}
|
||||
* @private
|
||||
*/
|
||||
this.deleteStmt = null;
|
||||
|
||||
/**
|
||||
* @external SQLiteStatement
|
||||
* @see {@link https://www.npmjs.com/package/sqlite}
|
||||
*/
|
||||
}
|
||||
|
||||
async init(client) {
|
||||
this.client = client;
|
||||
await this.db.run('CREATE TABLE IF NOT EXISTS settings (guild INTEGER PRIMARY KEY, settings TEXT)');
|
||||
|
||||
// Load all settings
|
||||
const rows = await this.db.all('SELECT CAST(guild as TEXT) as guild, settings FROM settings');
|
||||
for(const row of rows) {
|
||||
let settings;
|
||||
try {
|
||||
settings = JSON.parse(row.settings);
|
||||
} catch(err) {
|
||||
client.emit('warn', `SQLiteProvider couldn't parse the settings stored for guild ${row.guild}.`);
|
||||
continue;
|
||||
}
|
||||
|
||||
const guild = row.guild !== '0' ? row.guild : 'global';
|
||||
this.settings.set(guild, settings);
|
||||
if(guild !== 'global' && !client.guilds.cache.has(row.guild)) continue;
|
||||
this.setupGuild(guild, settings);
|
||||
}
|
||||
|
||||
// Prepare statements
|
||||
const statements = await Promise.all([
|
||||
this.db.prepare('INSERT OR REPLACE INTO settings VALUES(?, ?)'),
|
||||
this.db.prepare('DELETE FROM settings WHERE guild = ?')
|
||||
]);
|
||||
this.insertOrReplaceStmt = statements[0];
|
||||
this.deleteStmt = statements[1];
|
||||
|
||||
// Listen for changes
|
||||
this.listeners
|
||||
.set('commandPrefixChange', (guild, prefix) => this.set(guild, 'prefix', prefix))
|
||||
.set('commandStatusChange', (guild, command, enabled) => this.set(guild, `cmd-${command.name}`, enabled))
|
||||
.set('groupStatusChange', (guild, group, enabled) => this.set(guild, `grp-${group.id}`, enabled))
|
||||
.set('guildCreate', guild => {
|
||||
const settings = this.settings.get(guild.id);
|
||||
if(!settings) return;
|
||||
this.setupGuild(guild.id, settings);
|
||||
})
|
||||
.set('commandRegister', command => {
|
||||
for(const [guild, settings] of this.settings) {
|
||||
if(guild !== 'global' && !client.guilds.cache.has(guild)) continue;
|
||||
this.setupGuildCommand(client.guilds.cache.get(guild), command, settings);
|
||||
}
|
||||
})
|
||||
.set('groupRegister', group => {
|
||||
for(const [guild, settings] of this.settings) {
|
||||
if(guild !== 'global' && !client.guilds.cache.has(guild)) continue;
|
||||
this.setupGuildGroup(client.guilds.cache.get(guild), group, settings);
|
||||
}
|
||||
});
|
||||
for(const [event, listener] of this.listeners) client.on(event, listener);
|
||||
}
|
||||
|
||||
async destroy() {
|
||||
// Finalise prepared statements
|
||||
await Promise.all([
|
||||
this.insertOrReplaceStmt.finalize(),
|
||||
this.deleteStmt.finalize()
|
||||
]);
|
||||
|
||||
// Remove all listeners from the client
|
||||
for(const [event, listener] of this.listeners) this.client.removeListener(event, listener);
|
||||
this.listeners.clear();
|
||||
}
|
||||
|
||||
get(guild, key, defVal) {
|
||||
const settings = this.settings.get(this.constructor.getGuildID(guild));
|
||||
return settings ? typeof settings[key] !== 'undefined' ? settings[key] : defVal : defVal;
|
||||
}
|
||||
|
||||
async set(guild, key, val) {
|
||||
guild = this.constructor.getGuildID(guild);
|
||||
let settings = this.settings.get(guild);
|
||||
if(!settings) {
|
||||
settings = {};
|
||||
this.settings.set(guild, settings);
|
||||
}
|
||||
|
||||
settings[key] = val;
|
||||
await this.insertOrReplaceStmt.run(guild !== 'global' ? guild : 0, JSON.stringify(settings));
|
||||
if(guild === 'global') this.updateOtherShards(key, val);
|
||||
return val;
|
||||
}
|
||||
|
||||
async remove(guild, key) {
|
||||
guild = this.constructor.getGuildID(guild);
|
||||
const settings = this.settings.get(guild);
|
||||
if(!settings || typeof settings[key] === 'undefined') return undefined;
|
||||
|
||||
const val = settings[key];
|
||||
settings[key] = undefined;
|
||||
await this.insertOrReplaceStmt.run(guild !== 'global' ? guild : 0, JSON.stringify(settings));
|
||||
if(guild === 'global') this.updateOtherShards(key, undefined);
|
||||
return val;
|
||||
}
|
||||
|
||||
async clear(guild) {
|
||||
guild = this.constructor.getGuildID(guild);
|
||||
if(!this.settings.has(guild)) return;
|
||||
this.settings.delete(guild);
|
||||
await this.deleteStmt.run(guild !== 'global' ? guild : 0);
|
||||
}
|
||||
|
||||
/**
|
||||
* Loads all settings for a guild
|
||||
* @param {string} guild - Guild ID to load the settings of (or 'global')
|
||||
* @param {Object} settings - Settings to load
|
||||
* @private
|
||||
*/
|
||||
setupGuild(guild, settings) {
|
||||
if(typeof guild !== 'string') throw new TypeError('The guild must be a guild ID or "global".');
|
||||
guild = this.client.guilds.cache.get(guild) || null;
|
||||
|
||||
// Load the command prefix
|
||||
if(typeof settings.prefix !== 'undefined') {
|
||||
if(guild) guild._commandPrefix = settings.prefix;
|
||||
else this.client._commandPrefix = settings.prefix;
|
||||
}
|
||||
|
||||
// Load all command/group statuses
|
||||
for(const command of this.client.registry.commands.values()) this.setupGuildCommand(guild, command, settings);
|
||||
for(const group of this.client.registry.groups.values()) this.setupGuildGroup(guild, group, settings);
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets up a command's status in a guild from the guild's settings
|
||||
* @param {?CommandoGuild} guild - Guild to set the status in
|
||||
* @param {Command} command - Command to set the status of
|
||||
* @param {Object} settings - Settings of the guild
|
||||
* @private
|
||||
*/
|
||||
setupGuildCommand(guild, command, settings) {
|
||||
if(typeof settings[`cmd-${command.name}`] === 'undefined') return;
|
||||
if(guild) {
|
||||
if(!guild._commandsEnabled) guild._commandsEnabled = {};
|
||||
guild._commandsEnabled[command.name] = settings[`cmd-${command.name}`];
|
||||
} else {
|
||||
command._globalEnabled = settings[`cmd-${command.name}`];
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets up a command group's status in a guild from the guild's settings
|
||||
* @param {?CommandoGuild} guild - Guild to set the status in
|
||||
* @param {CommandGroup} group - Group to set the status of
|
||||
* @param {Object} settings - Settings of the guild
|
||||
* @private
|
||||
*/
|
||||
setupGuildGroup(guild, group, settings) {
|
||||
if(typeof settings[`grp-${group.id}`] === 'undefined') return;
|
||||
if(guild) {
|
||||
if(!guild._groupsEnabled) guild._groupsEnabled = {};
|
||||
guild._groupsEnabled[group.id] = settings[`grp-${group.id}`];
|
||||
} else {
|
||||
group._globalEnabled = settings[`grp-${group.id}`];
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Updates a global setting on all other shards if using the {@link ShardingManager}.
|
||||
* @param {string} key - Key of the setting to update
|
||||
* @param {*} val - Value of the setting
|
||||
* @private
|
||||
*/
|
||||
updateOtherShards(key, val) {
|
||||
if(!this.client.shard) return;
|
||||
key = JSON.stringify(key);
|
||||
val = typeof val !== 'undefined' ? JSON.stringify(val) : 'undefined';
|
||||
this.client.shard.broadcastEval(`
|
||||
const ids = [${this.client.shard.ids.join(',')}];
|
||||
if(!this.shard.ids.some(id => ids.includes(id)) && this.provider && this.provider.settings) {
|
||||
let global = this.provider.settings.get('global');
|
||||
if(!global) {
|
||||
global = {};
|
||||
this.provider.settings.set('global', global);
|
||||
}
|
||||
global[${key}] = ${val};
|
||||
}
|
||||
`);
|
||||
}
|
||||
}
|
||||
|
||||
module.exports = SQLiteProvider;
|
||||
561
node_modules/discord.js-commando/src/registry.js
generated
vendored
Normal file
561
node_modules/discord.js-commando/src/registry.js
generated
vendored
Normal file
@@ -0,0 +1,561 @@
|
||||
const path = require('path');
|
||||
const discord = require('discord.js');
|
||||
const Command = require('./commands/base');
|
||||
const CommandGroup = require('./commands/group');
|
||||
const CommandoMessage = require('./extensions/message');
|
||||
const ArgumentType = require('./types/base');
|
||||
const { isConstructor } = require('./util');
|
||||
|
||||
/** Handles registration and searching of commands and groups */
|
||||
class CommandoRegistry {
|
||||
/** @param {CommandoClient} [client] - Client to use */
|
||||
constructor(client) {
|
||||
/**
|
||||
* The client this registry is for
|
||||
* @name CommandoRegistry#client
|
||||
* @type {CommandoClient}
|
||||
* @readonly
|
||||
*/
|
||||
Object.defineProperty(this, 'client', { value: client });
|
||||
|
||||
/**
|
||||
* Registered commands, mapped by their name
|
||||
* @type {Collection<string, Command>}
|
||||
*/
|
||||
this.commands = new discord.Collection();
|
||||
|
||||
/**
|
||||
* Registered command groups, mapped by their ID
|
||||
* @type {Collection<string, CommandGroup>}
|
||||
*/
|
||||
this.groups = new discord.Collection();
|
||||
|
||||
/**
|
||||
* Registered argument types, mapped by their ID
|
||||
* @type {Collection<string, ArgumentType>}
|
||||
*/
|
||||
this.types = new discord.Collection();
|
||||
|
||||
/**
|
||||
* Fully resolved path to the bot's commands directory
|
||||
* @type {?string}
|
||||
*/
|
||||
this.commandsPath = null;
|
||||
|
||||
/**
|
||||
* Command to run when an unknown command is used
|
||||
* @type {?Command}
|
||||
*/
|
||||
this.unknownCommand = null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Registers a single group
|
||||
* @param {CommandGroup|Function|Object|string} group - A CommandGroup instance, a constructor, or the group ID
|
||||
* @param {string} [name] - Name for the group (if the first argument is the group ID)
|
||||
* @param {boolean} [guarded] - Whether the group should be guarded (if the first argument is the group ID)
|
||||
* @return {CommandoRegistry}
|
||||
* @see {@link CommandoRegistry#registerGroups}
|
||||
*/
|
||||
registerGroup(group, name, guarded) {
|
||||
if(typeof group === 'string') {
|
||||
group = new CommandGroup(this.client, group, name, guarded);
|
||||
} else if(isConstructor(group, CommandGroup)) {
|
||||
group = new group(this.client); // eslint-disable-line new-cap
|
||||
} else if(typeof group === 'object' && !(group instanceof CommandGroup)) {
|
||||
group = new CommandGroup(this.client, group.id, group.name, group.guarded);
|
||||
}
|
||||
|
||||
const existing = this.groups.get(group.id);
|
||||
if(existing) {
|
||||
existing.name = group.name;
|
||||
this.client.emit('debug', `Group ${group.id} is already registered; renamed it to "${group.name}".`);
|
||||
} else {
|
||||
this.groups.set(group.id, group);
|
||||
/**
|
||||
* Emitted when a group is registered
|
||||
* @event CommandoClient#groupRegister
|
||||
* @param {CommandGroup} group - Group that was registered
|
||||
* @param {CommandoRegistry} registry - Registry that the group was registered to
|
||||
*/
|
||||
this.client.emit('groupRegister', group, this);
|
||||
this.client.emit('debug', `Registered group ${group.id}.`);
|
||||
}
|
||||
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Registers multiple groups
|
||||
* @param {CommandGroup[]|Function[]|Object[]|Array<string[]>} groups - An array of CommandGroup instances,
|
||||
* constructors, plain objects (with ID, name, and guarded properties),
|
||||
* or arrays of {@link CommandoRegistry#registerGroup} parameters
|
||||
* @return {CommandoRegistry}
|
||||
* @example
|
||||
* registry.registerGroups([
|
||||
* ['fun', 'Fun'],
|
||||
* ['mod', 'Moderation']
|
||||
* ]);
|
||||
* @example
|
||||
* registry.registerGroups([
|
||||
* { id: 'fun', name: 'Fun' },
|
||||
* { id: 'mod', name: 'Moderation' }
|
||||
* ]);
|
||||
*/
|
||||
registerGroups(groups) {
|
||||
if(!Array.isArray(groups)) throw new TypeError('Groups must be an Array.');
|
||||
for(const group of groups) {
|
||||
if(Array.isArray(group)) this.registerGroup(...group);
|
||||
else this.registerGroup(group);
|
||||
}
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Registers a single command
|
||||
* @param {Command|Function} command - Either a Command instance, or a constructor for one
|
||||
* @return {CommandoRegistry}
|
||||
* @see {@link CommandoRegistry#registerCommands}
|
||||
*/
|
||||
registerCommand(command) {
|
||||
/* eslint-disable new-cap */
|
||||
if(isConstructor(command, Command)) command = new command(this.client);
|
||||
else if(isConstructor(command.default, Command)) command = new command.default(this.client);
|
||||
/* eslint-enable new-cap */
|
||||
if(!(command instanceof Command)) throw new Error(`Invalid command object to register: ${command}`);
|
||||
|
||||
// Make sure there aren't any conflicts
|
||||
if(this.commands.some(cmd => cmd.name === command.name || cmd.aliases.includes(command.name))) {
|
||||
throw new Error(`A command with the name/alias "${command.name}" is already registered.`);
|
||||
}
|
||||
for(const alias of command.aliases) {
|
||||
if(this.commands.some(cmd => cmd.name === alias || cmd.aliases.includes(alias))) {
|
||||
throw new Error(`A command with the name/alias "${alias}" is already registered.`);
|
||||
}
|
||||
}
|
||||
const group = this.groups.find(grp => grp.id === command.groupID);
|
||||
if(!group) throw new Error(`Group "${command.groupID}" is not registered.`);
|
||||
if(group.commands.some(cmd => cmd.memberName === command.memberName)) {
|
||||
throw new Error(`A command with the member name "${command.memberName}" is already registered in ${group.id}`);
|
||||
}
|
||||
if(command.unknown && this.unknownCommand) throw new Error('An unknown command is already registered.');
|
||||
|
||||
// Add the command
|
||||
command.group = group;
|
||||
group.commands.set(command.name, command);
|
||||
this.commands.set(command.name, command);
|
||||
if(command.unknown) this.unknownCommand = command;
|
||||
|
||||
/**
|
||||
* Emitted when a command is registered
|
||||
* @event CommandoClient#commandRegister
|
||||
* @param {Command} command - Command that was registered
|
||||
* @param {CommandoRegistry} registry - Registry that the command was registered to
|
||||
*/
|
||||
this.client.emit('commandRegister', command, this);
|
||||
this.client.emit('debug', `Registered command ${group.id}:${command.memberName}.`);
|
||||
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Registers multiple commands
|
||||
* @param {Command[]|Function[]} commands - An array of Command instances or constructors
|
||||
* @param {boolean} [ignoreInvalid=false] - Whether to skip over invalid objects without throwing an error
|
||||
* @return {CommandoRegistry}
|
||||
*/
|
||||
registerCommands(commands, ignoreInvalid = false) {
|
||||
if(!Array.isArray(commands)) throw new TypeError('Commands must be an Array.');
|
||||
for(const command of commands) {
|
||||
const valid = isConstructor(command, Command) || isConstructor(command.default, Command) ||
|
||||
command instanceof Command || command.default instanceof Command;
|
||||
if(ignoreInvalid && !valid) {
|
||||
this.client.emit('warn', `Attempting to register an invalid command object: ${command}; skipping.`);
|
||||
continue;
|
||||
}
|
||||
this.registerCommand(command);
|
||||
}
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Registers all commands in a directory. The files must export a Command class constructor or instance.
|
||||
* @param {string|RequireAllOptions} options - The path to the directory, or a require-all options object
|
||||
* @return {CommandoRegistry}
|
||||
* @example
|
||||
* const path = require('path');
|
||||
* registry.registerCommandsIn(path.join(__dirname, 'commands'));
|
||||
*/
|
||||
registerCommandsIn(options) {
|
||||
const obj = require('require-all')(options);
|
||||
const commands = [];
|
||||
for(const group of Object.values(obj)) {
|
||||
for(let command of Object.values(group)) {
|
||||
if(typeof command.default === 'function') command = command.default;
|
||||
commands.push(command);
|
||||
}
|
||||
}
|
||||
if(typeof options === 'string' && !this.commandsPath) this.commandsPath = options;
|
||||
else if(typeof options === 'object' && !this.commandsPath) this.commandsPath = options.dirname;
|
||||
return this.registerCommands(commands, true);
|
||||
}
|
||||
|
||||
/**
|
||||
* Registers a single argument type
|
||||
* @param {ArgumentType|Function} type - Either an ArgumentType instance, or a constructor for one
|
||||
* @return {CommandoRegistry}
|
||||
* @see {@link CommandoRegistry#registerTypes}
|
||||
*/
|
||||
registerType(type) {
|
||||
/* eslint-disable new-cap */
|
||||
if(isConstructor(type, ArgumentType)) type = new type(this.client);
|
||||
else if(isConstructor(type.default, ArgumentType)) type = new type.default(this.client);
|
||||
/* eslint-enable new-cap */
|
||||
|
||||
if(!(type instanceof ArgumentType)) throw new Error(`Invalid type object to register: ${type}`);
|
||||
|
||||
// Make sure there aren't any conflicts
|
||||
if(this.types.has(type.id)) throw new Error(`An argument type with the ID "${type.id}" is already registered.`);
|
||||
|
||||
// Add the type
|
||||
this.types.set(type.id, type);
|
||||
|
||||
/**
|
||||
* Emitted when an argument type is registered
|
||||
* @event CommandoClient#typeRegister
|
||||
* @param {ArgumentType} type - Argument type that was registered
|
||||
* @param {CommandoRegistry} registry - Registry that the type was registered to
|
||||
*/
|
||||
this.client.emit('typeRegister', type, this);
|
||||
this.client.emit('debug', `Registered argument type ${type.id}.`);
|
||||
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Registers multiple argument types
|
||||
* @param {ArgumentType[]|Function[]} types - An array of ArgumentType instances or constructors
|
||||
* @param {boolean} [ignoreInvalid=false] - Whether to skip over invalid objects without throwing an error
|
||||
* @return {CommandoRegistry}
|
||||
*/
|
||||
registerTypes(types, ignoreInvalid = false) {
|
||||
if(!Array.isArray(types)) throw new TypeError('Types must be an Array.');
|
||||
for(const type of types) {
|
||||
const valid = isConstructor(type, ArgumentType) || isConstructor(type.default, ArgumentType) ||
|
||||
type instanceof ArgumentType || type.default instanceof ArgumentType;
|
||||
if(ignoreInvalid && !valid) {
|
||||
this.client.emit('warn', `Attempting to register an invalid argument type object: ${type}; skipping.`);
|
||||
continue;
|
||||
}
|
||||
this.registerType(type);
|
||||
}
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Registers all argument types in a directory. The files must export an ArgumentType class constructor or instance.
|
||||
* @param {string|RequireAllOptions} options - The path to the directory, or a require-all options object
|
||||
* @return {CommandoRegistry}
|
||||
*/
|
||||
registerTypesIn(options) {
|
||||
const obj = require('require-all')(options);
|
||||
const types = [];
|
||||
for(const type of Object.values(obj)) types.push(type);
|
||||
return this.registerTypes(types, true);
|
||||
}
|
||||
|
||||
/**
|
||||
* Registers the default argument types, groups, and commands. This is equivalent to:
|
||||
* ```js
|
||||
* registry.registerDefaultTypes()
|
||||
* .registerDefaultGroups()
|
||||
* .registerDefaultCommands();
|
||||
* ```
|
||||
* @return {CommandoRegistry}
|
||||
*/
|
||||
registerDefaults() {
|
||||
this.registerDefaultTypes();
|
||||
this.registerDefaultGroups();
|
||||
this.registerDefaultCommands();
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Registers the default groups ("util" and "commands")
|
||||
* @return {CommandoRegistry}
|
||||
*/
|
||||
registerDefaultGroups() {
|
||||
return this.registerGroups([
|
||||
['commands', 'Commands', true],
|
||||
['util', 'Utility']
|
||||
]);
|
||||
}
|
||||
|
||||
/**
|
||||
* Registers the default commands to the registry
|
||||
* @param {Object} [commands] - Object specifying which commands to register
|
||||
* @param {boolean} [commands.help=true] - Whether to register the built-in help command
|
||||
* (requires "util" group and "string" type)
|
||||
* @param {boolean} [commands.prefix=true] - Whether to register the built-in prefix command
|
||||
* (requires "util" group and "string" type)
|
||||
* @param {boolean} [commands.eval=true] - Whether to register the built-in eval command
|
||||
* (requires "util" group and "string" type)
|
||||
* @param {boolean} [commands.ping=true] - Whether to register the built-in ping command (requires "util" group)
|
||||
* @param {boolean} [commands.unknownCommand=true] - Whether to register the built-in unknown command
|
||||
* (requires "util" group)
|
||||
* @param {boolean} [commands.commandState=true] - Whether to register the built-in command state commands
|
||||
* (enable, disable, load, unload, reload, list groups - requires "commands" group, "command" type, and "group" type)
|
||||
* @return {CommandoRegistry}
|
||||
*/
|
||||
registerDefaultCommands(commands = {}) {
|
||||
commands = {
|
||||
help: true, prefix: true, ping: true, eval: true,
|
||||
unknownCommand: true, commandState: true, ...commands
|
||||
};
|
||||
if(commands.help) this.registerCommand(require('./commands/util/help'));
|
||||
if(commands.prefix) this.registerCommand(require('./commands/util/prefix'));
|
||||
if(commands.ping) this.registerCommand(require('./commands/util/ping'));
|
||||
if(commands.eval) this.registerCommand(require('./commands/util/eval'));
|
||||
if(commands.unknownCommand) this.registerCommand(require('./commands/util/unknown-command'));
|
||||
if(commands.commandState) {
|
||||
this.registerCommands([
|
||||
require('./commands/commands/groups'),
|
||||
require('./commands/commands/enable'),
|
||||
require('./commands/commands/disable'),
|
||||
require('./commands/commands/reload'),
|
||||
require('./commands/commands/load'),
|
||||
require('./commands/commands/unload')
|
||||
]);
|
||||
}
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Registers the default argument types to the registry
|
||||
* @param {Object} [types] - Object specifying which types to register
|
||||
* @param {boolean} [types.string=true] - Whether to register the built-in string type
|
||||
* @param {boolean} [types.integer=true] - Whether to register the built-in integer type
|
||||
* @param {boolean} [types.float=true] - Whether to register the built-in float type
|
||||
* @param {boolean} [types.boolean=true] - Whether to register the built-in boolean type
|
||||
* @param {boolean} [types.user=true] - Whether to register the built-in user type
|
||||
* @param {boolean} [types.member=true] - Whether to register the built-in member type
|
||||
* @param {boolean} [types.role=true] - Whether to register the built-in role type
|
||||
* @param {boolean} [types.channel=true] - Whether to register the built-in channel type
|
||||
* @param {boolean} [types.textChannel=true] - Whether to register the built-in text-channel type
|
||||
* @param {boolean} [types.voiceChannel=true] - Whether to register the built-in voice-channel type
|
||||
* @param {boolean} [types.categoryChannel=true] - Whether to register the built-in category-channel type
|
||||
* @param {boolean} [types.message=true] - Whether to register the built-in message type
|
||||
* @param {boolean} [types.customEmoji=true] - Whether to register the built-in custom-emoji type
|
||||
* @param {boolean} [types.defaultEmoji=true] - Whether to register the built-in default-emoji type
|
||||
* @param {boolean} [types.command=true] - Whether to register the built-in command type
|
||||
* @param {boolean} [types.group=true] - Whether to register the built-in group type
|
||||
* @return {CommandoRegistry}
|
||||
*/
|
||||
registerDefaultTypes(types = {}) {
|
||||
types = {
|
||||
string: true, integer: true, float: true, boolean: true,
|
||||
user: true, member: true, role: true, channel: true, textChannel: true,
|
||||
voiceChannel: true, categoryChannel: true, message: true, customEmoji: true,
|
||||
defaultEmoji: true, command: true, group: true, ...types
|
||||
};
|
||||
if(types.string) this.registerType(require('./types/string'));
|
||||
if(types.integer) this.registerType(require('./types/integer'));
|
||||
if(types.float) this.registerType(require('./types/float'));
|
||||
if(types.boolean) this.registerType(require('./types/boolean'));
|
||||
if(types.user) this.registerType(require('./types/user'));
|
||||
if(types.member) this.registerType(require('./types/member'));
|
||||
if(types.role) this.registerType(require('./types/role'));
|
||||
if(types.channel) this.registerType(require('./types/channel'));
|
||||
if(types.textChannel) this.registerType(require('./types/text-channel'));
|
||||
if(types.voiceChannel) this.registerType(require('./types/voice-channel'));
|
||||
if(types.categoryChannel) this.registerType(require('./types/category-channel'));
|
||||
if(types.message) this.registerType(require('./types/message'));
|
||||
if(types.customEmoji) this.registerType(require('./types/custom-emoji'));
|
||||
if(types.defaultEmoji) this.registerType(require('./types/default-emoji'));
|
||||
if(types.command) this.registerType(require('./types/command'));
|
||||
if(types.group) this.registerType(require('./types/group'));
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Reregisters a command (does not support changing name, group, or memberName)
|
||||
* @param {Command|Function} command - New command
|
||||
* @param {Command} oldCommand - Old command
|
||||
*/
|
||||
reregisterCommand(command, oldCommand) {
|
||||
/* eslint-disable new-cap */
|
||||
if(isConstructor(command, Command)) command = new command(this.client);
|
||||
else if(isConstructor(command.default, Command)) command = new command.default(this.client);
|
||||
/* eslint-enable new-cap */
|
||||
|
||||
if(command.name !== oldCommand.name) throw new Error('Command name cannot change.');
|
||||
if(command.groupID !== oldCommand.groupID) throw new Error('Command group cannot change.');
|
||||
if(command.memberName !== oldCommand.memberName) throw new Error('Command memberName cannot change.');
|
||||
if(command.unknown && this.unknownCommand !== oldCommand) {
|
||||
throw new Error('An unknown command is already registered.');
|
||||
}
|
||||
|
||||
command.group = this.resolveGroup(command.groupID);
|
||||
command.group.commands.set(command.name, command);
|
||||
this.commands.set(command.name, command);
|
||||
if(this.unknownCommand === oldCommand) this.unknownCommand = null;
|
||||
if(command.unknown) this.unknownCommand = command;
|
||||
|
||||
/**
|
||||
* Emitted when a command is reregistered
|
||||
* @event CommandoClient#commandReregister
|
||||
* @param {Command} newCommand - New command
|
||||
* @param {Command} oldCommand - Old command
|
||||
*/
|
||||
this.client.emit('commandReregister', command, oldCommand);
|
||||
this.client.emit('debug', `Reregistered command ${command.groupID}:${command.memberName}.`);
|
||||
}
|
||||
|
||||
/**
|
||||
* Unregisters a command
|
||||
* @param {Command} command - Command to unregister
|
||||
*/
|
||||
unregisterCommand(command) {
|
||||
this.commands.delete(command.name);
|
||||
command.group.commands.delete(command.name);
|
||||
if(this.unknownCommand === command) this.unknownCommand = null;
|
||||
|
||||
/**
|
||||
* Emitted when a command is unregistered
|
||||
* @event CommandoClient#commandUnregister
|
||||
* @param {Command} command - Command that was unregistered
|
||||
*/
|
||||
this.client.emit('commandUnregister', command);
|
||||
this.client.emit('debug', `Unregistered command ${command.groupID}:${command.memberName}.`);
|
||||
}
|
||||
|
||||
/**
|
||||
* Finds all groups that match the search string
|
||||
* @param {string} [searchString] - The string to search for
|
||||
* @param {boolean} [exact=false] - Whether the search should be exact
|
||||
* @return {CommandGroup[]} All groups that are found
|
||||
*/
|
||||
findGroups(searchString = null, exact = false) {
|
||||
if(!searchString) return this.groups;
|
||||
|
||||
// Find all matches
|
||||
const lcSearch = searchString.toLowerCase();
|
||||
const matchedGroups = Array.from(this.groups.filter(
|
||||
exact ? groupFilterExact(lcSearch) : groupFilterInexact(lcSearch)
|
||||
).values());
|
||||
if(exact) return matchedGroups;
|
||||
|
||||
// See if there's an exact match
|
||||
for(const group of matchedGroups) {
|
||||
if(group.name.toLowerCase() === lcSearch || group.id === lcSearch) return [group];
|
||||
}
|
||||
return matchedGroups;
|
||||
}
|
||||
|
||||
/**
|
||||
* A CommandGroupResolvable can be:
|
||||
* * A CommandGroup
|
||||
* * A group ID
|
||||
* @typedef {CommandGroup|string} CommandGroupResolvable
|
||||
*/
|
||||
|
||||
/**
|
||||
* Resolves a CommandGroupResolvable to a CommandGroup object
|
||||
* @param {CommandGroupResolvable} group - The group to resolve
|
||||
* @return {CommandGroup} The resolved CommandGroup
|
||||
*/
|
||||
resolveGroup(group) {
|
||||
if(group instanceof CommandGroup) return group;
|
||||
if(typeof group === 'string') {
|
||||
const groups = this.findGroups(group, true);
|
||||
if(groups.length === 1) return groups[0];
|
||||
}
|
||||
throw new Error('Unable to resolve group.');
|
||||
}
|
||||
|
||||
/**
|
||||
* Finds all commands that match the search string
|
||||
* @param {string} [searchString] - The string to search for
|
||||
* @param {boolean} [exact=false] - Whether the search should be exact
|
||||
* @param {Message} [message] - The message to check usability against
|
||||
* @return {Command[]} All commands that are found
|
||||
*/
|
||||
findCommands(searchString = null, exact = false, message = null) {
|
||||
if(!searchString) {
|
||||
return message ?
|
||||
Array.from(this.commands.filter(cmd => cmd.isUsable(message)).values()) :
|
||||
Array.from(this.commands);
|
||||
}
|
||||
|
||||
// Find all matches
|
||||
const lcSearch = searchString.toLowerCase();
|
||||
const matchedCommands = Array.from(this.commands.filter(
|
||||
exact ? commandFilterExact(lcSearch) : commandFilterInexact(lcSearch)
|
||||
).values());
|
||||
if(exact) return matchedCommands;
|
||||
|
||||
// See if there's an exact match
|
||||
for(const command of matchedCommands) {
|
||||
if(command.name === lcSearch || (command.aliases && command.aliases.some(ali => ali === lcSearch))) {
|
||||
return [command];
|
||||
}
|
||||
}
|
||||
|
||||
return matchedCommands;
|
||||
}
|
||||
|
||||
/**
|
||||
* A CommandResolvable can be:
|
||||
* * A Command
|
||||
* * A command name
|
||||
* * A CommandoMessage
|
||||
* @typedef {Command|string} CommandResolvable
|
||||
*/
|
||||
|
||||
/**
|
||||
* Resolves a CommandResolvable to a Command object
|
||||
* @param {CommandResolvable} command - The command to resolve
|
||||
* @return {Command} The resolved Command
|
||||
*/
|
||||
resolveCommand(command) {
|
||||
if(command instanceof Command) return command;
|
||||
if(command instanceof CommandoMessage && command.command) return command.command;
|
||||
if(typeof command === 'string') {
|
||||
const commands = this.findCommands(command, true);
|
||||
if(commands.length === 1) return commands[0];
|
||||
}
|
||||
throw new Error('Unable to resolve command.');
|
||||
}
|
||||
|
||||
/**
|
||||
* Resolves a command file path from a command's group ID and memberName
|
||||
* @param {string} group - ID of the command's group
|
||||
* @param {string} memberName - Member name of the command
|
||||
* @return {string} Fully-resolved path to the corresponding command file
|
||||
*/
|
||||
resolveCommandPath(group, memberName) {
|
||||
return path.join(this.commandsPath, group, `${memberName}.js`);
|
||||
}
|
||||
}
|
||||
|
||||
function groupFilterExact(search) {
|
||||
return grp => grp.id === search || grp.name.toLowerCase() === search;
|
||||
}
|
||||
|
||||
function groupFilterInexact(search) {
|
||||
return grp => grp.id.includes(search) || grp.name.toLowerCase().includes(search);
|
||||
}
|
||||
|
||||
function commandFilterExact(search) {
|
||||
return cmd => cmd.name === search ||
|
||||
(cmd.aliases && cmd.aliases.some(ali => ali === search)) ||
|
||||
`${cmd.groupID}:${cmd.memberName}` === search;
|
||||
}
|
||||
|
||||
function commandFilterInexact(search) {
|
||||
return cmd => cmd.name.includes(search) ||
|
||||
`${cmd.groupID}:${cmd.memberName}` === search ||
|
||||
(cmd.aliases && cmd.aliases.some(ali => ali.includes(search)));
|
||||
}
|
||||
|
||||
module.exports = CommandoRegistry;
|
||||
70
node_modules/discord.js-commando/src/types/base.js
generated
vendored
Normal file
70
node_modules/discord.js-commando/src/types/base.js
generated
vendored
Normal file
@@ -0,0 +1,70 @@
|
||||
/** A type for command arguments */
|
||||
class ArgumentType {
|
||||
/**
|
||||
* @param {CommandoClient} client - The client the argument type is for
|
||||
* @param {string} id - The argument type ID (this is what you specify in {@link ArgumentInfo#type})
|
||||
*/
|
||||
constructor(client, id) {
|
||||
if(!client) throw new Error('A client must be specified.');
|
||||
if(typeof id !== 'string') throw new Error('Argument type ID must be a string.');
|
||||
if(id !== id.toLowerCase()) throw new Error('Argument type ID must be lowercase.');
|
||||
|
||||
/**
|
||||
* Client that this argument type is for
|
||||
* @name ArgumentType#client
|
||||
* @type {CommandoClient}
|
||||
* @readonly
|
||||
*/
|
||||
Object.defineProperty(this, 'client', { value: client });
|
||||
|
||||
/**
|
||||
* ID of this argument type (this is what you specify in {@link ArgumentInfo#type})
|
||||
* @type {string}
|
||||
*/
|
||||
this.id = id;
|
||||
}
|
||||
|
||||
// eslint-disable-next-line valid-jsdoc
|
||||
/**
|
||||
* Validates a value string against the type
|
||||
* @param {string} val - Value to validate
|
||||
* @param {CommandoMessage} originalMsg - Message that triggered the command
|
||||
* @param {Argument} arg - Argument the value was obtained from
|
||||
* @param {?CommandoMessage} [currentMsg=originalMsg] - Current response message
|
||||
* @return {boolean|string|Promise<boolean|string>} Whether the value is valid, or an error message
|
||||
* @abstract
|
||||
*/
|
||||
validate(val, originalMsg, arg, currentMsg = originalMsg) { // eslint-disable-line no-unused-vars
|
||||
throw new Error(`${this.constructor.name} doesn't have a validate() method.`);
|
||||
}
|
||||
|
||||
// eslint-disable-next-line valid-jsdoc
|
||||
/**
|
||||
* Parses the raw value string into a usable value
|
||||
* @param {string} val - Value to parse
|
||||
* @param {CommandoMessage} originalMsg - Message that triggered the command
|
||||
* @param {Argument} arg - Argument the value was obtained from
|
||||
* @param {?CommandoMessage} [currentMsg=originalMsg] - Current response message
|
||||
* @return {*|Promise<*>} Usable value
|
||||
* @abstract
|
||||
*/
|
||||
parse(val, originalMsg, arg, currentMsg = originalMsg) { // eslint-disable-line no-unused-vars
|
||||
throw new Error(`${this.constructor.name} doesn't have a parse() method.`);
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks whether a value is considered to be empty. This determines whether the default value for an argument
|
||||
* should be used and changes the response to the user under certain circumstances.
|
||||
* @param {string} val - Value to check for emptiness
|
||||
* @param {CommandoMessage} originalMsg - Message that triggered the command
|
||||
* @param {Argument} arg - Argument the value was obtained from
|
||||
* @param {?CommandoMessage} [currentMsg=originalMsg] - Current response message
|
||||
* @return {boolean} Whether the value is empty
|
||||
*/
|
||||
isEmpty(val, originalMsg, arg, currentMsg = originalMsg) { // eslint-disable-line no-unused-vars
|
||||
if(Array.isArray(val)) return val.length === 0;
|
||||
return !val;
|
||||
}
|
||||
}
|
||||
|
||||
module.exports = ArgumentType;
|
||||
23
node_modules/discord.js-commando/src/types/boolean.js
generated
vendored
Normal file
23
node_modules/discord.js-commando/src/types/boolean.js
generated
vendored
Normal file
@@ -0,0 +1,23 @@
|
||||
const ArgumentType = require('./base');
|
||||
|
||||
class BooleanArgumentType extends ArgumentType {
|
||||
constructor(client) {
|
||||
super(client, 'boolean');
|
||||
this.truthy = new Set(['true', 't', 'yes', 'y', 'on', 'enable', 'enabled', '1', '+']);
|
||||
this.falsy = new Set(['false', 'f', 'no', 'n', 'off', 'disable', 'disabled', '0', '-']);
|
||||
}
|
||||
|
||||
validate(val) {
|
||||
const lc = val.toLowerCase();
|
||||
return this.truthy.has(lc) || this.falsy.has(lc);
|
||||
}
|
||||
|
||||
parse(val) {
|
||||
const lc = val.toLowerCase();
|
||||
if(this.truthy.has(lc)) return true;
|
||||
if(this.falsy.has(lc)) return false;
|
||||
throw new RangeError('Unknown boolean value.');
|
||||
}
|
||||
}
|
||||
|
||||
module.exports = BooleanArgumentType;
|
||||
65
node_modules/discord.js-commando/src/types/category-channel.js
generated
vendored
Normal file
65
node_modules/discord.js-commando/src/types/category-channel.js
generated
vendored
Normal file
@@ -0,0 +1,65 @@
|
||||
const ArgumentType = require('./base');
|
||||
const { disambiguation } = require('../util');
|
||||
const { escapeMarkdown } = require('discord.js');
|
||||
|
||||
class CategoryChannelArgumentType extends ArgumentType {
|
||||
constructor(client) {
|
||||
super(client, 'category-channel');
|
||||
}
|
||||
|
||||
validate(val, msg, arg) {
|
||||
const matches = val.match(/^([0-9]+)$/);
|
||||
if(matches) {
|
||||
try {
|
||||
const channel = msg.client.channels.resolve(matches[1]);
|
||||
if(!channel || channel.type !== 'category') return false;
|
||||
if(arg.oneOf && !arg.oneOf.includes(channel.id)) return false;
|
||||
return true;
|
||||
} catch(err) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
if(!msg.guild) return false;
|
||||
const search = val.toLowerCase();
|
||||
let channels = msg.guild.channels.cache.filter(channelFilterInexact(search));
|
||||
if(channels.size === 0) return false;
|
||||
if(channels.size === 1) {
|
||||
if(arg.oneOf && !arg.oneOf.includes(channels.first().id)) return false;
|
||||
return true;
|
||||
}
|
||||
const exactChannels = channels.filter(channelFilterExact(search));
|
||||
if(exactChannels.size === 1) {
|
||||
if(arg.oneOf && !arg.oneOf.includes(exactChannels.first().id)) return false;
|
||||
return true;
|
||||
}
|
||||
if(exactChannels.size > 0) channels = exactChannels;
|
||||
return channels.size <= 15 ?
|
||||
`${disambiguation(
|
||||
channels.map(chan => escapeMarkdown(chan.name)), 'categories', null
|
||||
)}\n` :
|
||||
'Multiple categories found. Please be more specific.';
|
||||
}
|
||||
|
||||
parse(val, msg) {
|
||||
const matches = val.match(/^([0-9]+)$/);
|
||||
if(matches) return msg.client.channels.cache.get(matches[1]) || null;
|
||||
if(!msg.guild) return null;
|
||||
const search = val.toLowerCase();
|
||||
const channels = msg.guild.channels.cache.filter(channelFilterInexact(search));
|
||||
if(channels.size === 0) return null;
|
||||
if(channels.size === 1) return channels.first();
|
||||
const exactChannels = channels.filter(channelFilterExact(search));
|
||||
if(exactChannels.size === 1) return exactChannels.first();
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
function channelFilterExact(search) {
|
||||
return chan => chan.type === 'category' && chan.name.toLowerCase() === search;
|
||||
}
|
||||
|
||||
function channelFilterInexact(search) {
|
||||
return chan => chan.type === 'category' && chan.name.toLowerCase().includes(search);
|
||||
}
|
||||
|
||||
module.exports = CategoryChannelArgumentType;
|
||||
52
node_modules/discord.js-commando/src/types/channel.js
generated
vendored
Normal file
52
node_modules/discord.js-commando/src/types/channel.js
generated
vendored
Normal file
@@ -0,0 +1,52 @@
|
||||
const ArgumentType = require('./base');
|
||||
const { disambiguation } = require('../util');
|
||||
const { escapeMarkdown } = require('discord.js');
|
||||
|
||||
class ChannelArgumentType extends ArgumentType {
|
||||
constructor(client) {
|
||||
super(client, 'channel');
|
||||
}
|
||||
|
||||
validate(val, msg, arg) {
|
||||
const matches = val.match(/^(?:<#)?([0-9]+)>?$/);
|
||||
if(matches) return msg.guild.channels.cache.has(matches[1]);
|
||||
const search = val.toLowerCase();
|
||||
let channels = msg.guild.channels.cache.filter(nameFilterInexact(search));
|
||||
if(channels.size === 0) return false;
|
||||
if(channels.size === 1) {
|
||||
if(arg.oneOf && !arg.oneOf.includes(channels.first().id)) return false;
|
||||
return true;
|
||||
}
|
||||
const exactChannels = channels.filter(nameFilterExact(search));
|
||||
if(exactChannels.size === 1) {
|
||||
if(arg.oneOf && !arg.oneOf.includes(exactChannels.first().id)) return false;
|
||||
return true;
|
||||
}
|
||||
if(exactChannels.size > 0) channels = exactChannels;
|
||||
return channels.size <= 15 ?
|
||||
`${disambiguation(channels.map(chan => escapeMarkdown(chan.name)), 'channels', null)}\n` :
|
||||
'Multiple channels found. Please be more specific.';
|
||||
}
|
||||
|
||||
parse(val, msg) {
|
||||
const matches = val.match(/^(?:<#)?([0-9]+)>?$/);
|
||||
if(matches) return msg.guild.channels.cache.get(matches[1]) || null;
|
||||
const search = val.toLowerCase();
|
||||
const channels = msg.guild.channels.cache.filter(nameFilterInexact(search));
|
||||
if(channels.size === 0) return null;
|
||||
if(channels.size === 1) return channels.first();
|
||||
const exactChannels = channels.filter(nameFilterExact(search));
|
||||
if(exactChannels.size === 1) return exactChannels.first();
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
function nameFilterExact(search) {
|
||||
return thing => thing.name.toLowerCase() === search;
|
||||
}
|
||||
|
||||
function nameFilterInexact(search) {
|
||||
return thing => thing.name.toLowerCase().includes(search);
|
||||
}
|
||||
|
||||
module.exports = ChannelArgumentType;
|
||||
24
node_modules/discord.js-commando/src/types/command.js
generated
vendored
Normal file
24
node_modules/discord.js-commando/src/types/command.js
generated
vendored
Normal file
@@ -0,0 +1,24 @@
|
||||
const ArgumentType = require('./base');
|
||||
const { disambiguation } = require('../util');
|
||||
const { escapeMarkdown } = require('discord.js');
|
||||
|
||||
class CommandArgumentType extends ArgumentType {
|
||||
constructor(client) {
|
||||
super(client, 'command');
|
||||
}
|
||||
|
||||
validate(val) {
|
||||
const commands = this.client.registry.findCommands(val);
|
||||
if(commands.length === 1) return true;
|
||||
if(commands.length === 0) return false;
|
||||
return commands.length <= 15 ?
|
||||
`${disambiguation(commands.map(cmd => escapeMarkdown(cmd.name)), 'commands', null)}\n` :
|
||||
'Multiple commands found. Please be more specific.';
|
||||
}
|
||||
|
||||
parse(val) {
|
||||
return this.client.registry.findCommands(val)[0];
|
||||
}
|
||||
}
|
||||
|
||||
module.exports = CommandArgumentType;
|
||||
47
node_modules/discord.js-commando/src/types/custom-emoji.js
generated
vendored
Normal file
47
node_modules/discord.js-commando/src/types/custom-emoji.js
generated
vendored
Normal file
@@ -0,0 +1,47 @@
|
||||
const ArgumentType = require('./base');
|
||||
const { disambiguation } = require('../util');
|
||||
const { escapeMarkdown } = require('discord.js');
|
||||
|
||||
class CustomEmojiArgumentType extends ArgumentType {
|
||||
constructor(client) {
|
||||
super(client, 'custom-emoji');
|
||||
}
|
||||
|
||||
validate(value, msg) {
|
||||
const matches = value.match(/^(?:<a?:([a-zA-Z0-9_]+):)?([0-9]+)>?$/);
|
||||
if(matches && msg.client.emojis.cache.has(matches[2])) return true;
|
||||
if(!msg.guild) return false;
|
||||
const search = value.toLowerCase();
|
||||
let emojis = msg.guild.emojis.cache.filter(nameFilterInexact(search));
|
||||
if(!emojis.size) return false;
|
||||
if(emojis.size === 1) return true;
|
||||
const exactEmojis = emojis.filter(nameFilterExact(search));
|
||||
if(exactEmojis.size === 1) return true;
|
||||
if(exactEmojis.size > 0) emojis = exactEmojis;
|
||||
return emojis.size <= 15 ?
|
||||
`${disambiguation(emojis.map(emoji => escapeMarkdown(emoji.name)), 'emojis', null)}\n` :
|
||||
'Multiple emojis found. Please be more specific.';
|
||||
}
|
||||
|
||||
parse(value, msg) {
|
||||
const matches = value.match(/^(?:<a?:([a-zA-Z0-9_]+):)?([0-9]+)>?$/);
|
||||
if(matches) return msg.client.emojis.cache.get(matches[2]) || null;
|
||||
const search = value.toLowerCase();
|
||||
const emojis = msg.guild.emojis.cache.filter(nameFilterInexact(search));
|
||||
if(!emojis.size) return null;
|
||||
if(emojis.size === 1) return emojis.first();
|
||||
const exactEmojis = emojis.filter(nameFilterExact(search));
|
||||
if(exactEmojis.size === 1) return exactEmojis.first();
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
function nameFilterExact(search) {
|
||||
return emoji => emoji.name.toLowerCase() === search;
|
||||
}
|
||||
|
||||
function nameFilterInexact(search) {
|
||||
return emoji => emoji.name.toLowerCase().includes(search);
|
||||
}
|
||||
|
||||
module.exports = CustomEmojiArgumentType;
|
||||
22
node_modules/discord.js-commando/src/types/default-emoji.js
generated
vendored
Normal file
22
node_modules/discord.js-commando/src/types/default-emoji.js
generated
vendored
Normal file
@@ -0,0 +1,22 @@
|
||||
const ArgumentType = require('./base');
|
||||
const emojiRegex = require('emoji-regex/RGI_Emoji.js');
|
||||
|
||||
class DefaultEmojiArgumentType extends ArgumentType {
|
||||
constructor(client) {
|
||||
super(client, 'default-emoji');
|
||||
}
|
||||
|
||||
validate(value, msg, arg) {
|
||||
if(!new RegExp(`^(?:${emojiRegex().source})$`).test(value)) return false;
|
||||
if(arg.oneOf && !arg.oneOf.includes(value)) {
|
||||
return `Please enter one of the following options: ${arg.oneOf.join(' | ')}`;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
parse(value) {
|
||||
return value;
|
||||
}
|
||||
}
|
||||
|
||||
module.exports = DefaultEmojiArgumentType;
|
||||
28
node_modules/discord.js-commando/src/types/float.js
generated
vendored
Normal file
28
node_modules/discord.js-commando/src/types/float.js
generated
vendored
Normal file
@@ -0,0 +1,28 @@
|
||||
const ArgumentType = require('./base');
|
||||
|
||||
class FloatArgumentType extends ArgumentType {
|
||||
constructor(client) {
|
||||
super(client, 'float');
|
||||
}
|
||||
|
||||
validate(val, msg, arg) {
|
||||
const float = Number.parseFloat(val);
|
||||
if(Number.isNaN(float)) return false;
|
||||
if(arg.oneOf && !arg.oneOf.includes(float)) {
|
||||
return `Please enter one of the following options: ${arg.oneOf.map(opt => `\`${opt}\``).join(', ')}`;
|
||||
}
|
||||
if(arg.min !== null && typeof arg.min !== 'undefined' && float < arg.min) {
|
||||
return `Please enter a number above or exactly ${arg.min}.`;
|
||||
}
|
||||
if(arg.max !== null && typeof arg.max !== 'undefined' && float > arg.max) {
|
||||
return `Please enter a number below or exactly ${arg.max}.`;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
parse(val) {
|
||||
return Number.parseFloat(val);
|
||||
}
|
||||
}
|
||||
|
||||
module.exports = FloatArgumentType;
|
||||
24
node_modules/discord.js-commando/src/types/group.js
generated
vendored
Normal file
24
node_modules/discord.js-commando/src/types/group.js
generated
vendored
Normal file
@@ -0,0 +1,24 @@
|
||||
const ArgumentType = require('./base');
|
||||
const { disambiguation } = require('../util');
|
||||
const { escapeMarkdown } = require('discord.js');
|
||||
|
||||
class GroupArgumentType extends ArgumentType {
|
||||
constructor(client) {
|
||||
super(client, 'group');
|
||||
}
|
||||
|
||||
validate(val) {
|
||||
const groups = this.client.registry.findGroups(val);
|
||||
if(groups.length === 1) return true;
|
||||
if(groups.length === 0) return false;
|
||||
return groups.length <= 15 ?
|
||||
`${disambiguation(groups.map(grp => escapeMarkdown(grp.name)), 'groups', null)}\n` :
|
||||
'Multiple groups found. Please be more specific.';
|
||||
}
|
||||
|
||||
parse(val) {
|
||||
return this.client.registry.findGroups(val)[0];
|
||||
}
|
||||
}
|
||||
|
||||
module.exports = GroupArgumentType;
|
||||
28
node_modules/discord.js-commando/src/types/integer.js
generated
vendored
Normal file
28
node_modules/discord.js-commando/src/types/integer.js
generated
vendored
Normal file
@@ -0,0 +1,28 @@
|
||||
const ArgumentType = require('./base');
|
||||
|
||||
class IntegerArgumentType extends ArgumentType {
|
||||
constructor(client) {
|
||||
super(client, 'integer');
|
||||
}
|
||||
|
||||
validate(val, msg, arg) {
|
||||
const int = Number.parseInt(val);
|
||||
if(Number.isNaN(int)) return false;
|
||||
if(arg.oneOf && !arg.oneOf.includes(int)) {
|
||||
return `Please enter one of the following options: ${arg.oneOf.map(opt => `\`${opt}\``).join(', ')}`;
|
||||
}
|
||||
if(arg.min !== null && typeof arg.min !== 'undefined' && int < arg.min) {
|
||||
return `Please enter a number above or exactly ${arg.min}.`;
|
||||
}
|
||||
if(arg.max !== null && typeof arg.max !== 'undefined' && int > arg.max) {
|
||||
return `Please enter a number below or exactly ${arg.max}.`;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
parse(val) {
|
||||
return Number.parseInt(val);
|
||||
}
|
||||
}
|
||||
|
||||
module.exports = IntegerArgumentType;
|
||||
67
node_modules/discord.js-commando/src/types/member.js
generated
vendored
Normal file
67
node_modules/discord.js-commando/src/types/member.js
generated
vendored
Normal file
@@ -0,0 +1,67 @@
|
||||
const ArgumentType = require('./base');
|
||||
const { disambiguation } = require('../util');
|
||||
const { escapeMarkdown } = require('discord.js');
|
||||
|
||||
class MemberArgumentType extends ArgumentType {
|
||||
constructor(client) {
|
||||
super(client, 'member');
|
||||
}
|
||||
|
||||
async validate(val, msg, arg) {
|
||||
const matches = val.match(/^(?:<@!?)?([0-9]+)>?$/);
|
||||
if(matches) {
|
||||
try {
|
||||
const member = await msg.guild.members.fetch(await msg.client.users.fetch(matches[1]));
|
||||
if(!member) return false;
|
||||
if(arg.oneOf && !arg.oneOf.includes(member.id)) return false;
|
||||
return true;
|
||||
} catch(err) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
const search = val.toLowerCase();
|
||||
let members = msg.guild.members.cache.filter(memberFilterInexact(search));
|
||||
if(members.size === 0) return false;
|
||||
if(members.size === 1) {
|
||||
if(arg.oneOf && !arg.oneOf.includes(members.first().id)) return false;
|
||||
return true;
|
||||
}
|
||||
const exactMembers = members.filter(memberFilterExact(search));
|
||||
if(exactMembers.size === 1) {
|
||||
if(arg.oneOf && !arg.oneOf.includes(exactMembers.first().id)) return false;
|
||||
return true;
|
||||
}
|
||||
if(exactMembers.size > 0) members = exactMembers;
|
||||
return members.size <= 15 ?
|
||||
`${disambiguation(
|
||||
members.map(mem => `${escapeMarkdown(mem.user.username)}#${mem.user.discriminator}`), 'members', null
|
||||
)}\n` :
|
||||
'Multiple members found. Please be more specific.';
|
||||
}
|
||||
|
||||
parse(val, msg) {
|
||||
const matches = val.match(/^(?:<@!?)?([0-9]+)>?$/);
|
||||
if(matches) return msg.guild.member(matches[1]) || null;
|
||||
const search = val.toLowerCase();
|
||||
const members = msg.guild.members.cache.filter(memberFilterInexact(search));
|
||||
if(members.size === 0) return null;
|
||||
if(members.size === 1) return members.first();
|
||||
const exactMembers = members.filter(memberFilterExact(search));
|
||||
if(exactMembers.size === 1) return exactMembers.first();
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
function memberFilterExact(search) {
|
||||
return mem => mem.user.username.toLowerCase() === search ||
|
||||
(mem.nickname && mem.nickname.toLowerCase() === search) ||
|
||||
`${mem.user.username.toLowerCase()}#${mem.user.discriminator}` === search;
|
||||
}
|
||||
|
||||
function memberFilterInexact(search) {
|
||||
return mem => mem.user.username.toLowerCase().includes(search) ||
|
||||
(mem.nickname && mem.nickname.toLowerCase().includes(search)) ||
|
||||
`${mem.user.username.toLowerCase()}#${mem.user.discriminator}`.includes(search);
|
||||
}
|
||||
|
||||
module.exports = MemberArgumentType;
|
||||
18
node_modules/discord.js-commando/src/types/message.js
generated
vendored
Normal file
18
node_modules/discord.js-commando/src/types/message.js
generated
vendored
Normal file
@@ -0,0 +1,18 @@
|
||||
const ArgumentType = require('./base');
|
||||
|
||||
class MessageArgumentType extends ArgumentType {
|
||||
constructor(client) {
|
||||
super(client, 'message');
|
||||
}
|
||||
|
||||
async validate(val, msg) {
|
||||
if(!/^[0-9]+$/.test(val)) return false;
|
||||
return Boolean(await msg.channel.messages.fetch(val).catch(() => null));
|
||||
}
|
||||
|
||||
parse(val, msg) {
|
||||
return msg.channel.messages.cache.get(val);
|
||||
}
|
||||
}
|
||||
|
||||
module.exports = MessageArgumentType;
|
||||
52
node_modules/discord.js-commando/src/types/role.js
generated
vendored
Normal file
52
node_modules/discord.js-commando/src/types/role.js
generated
vendored
Normal file
@@ -0,0 +1,52 @@
|
||||
const ArgumentType = require('./base');
|
||||
const { disambiguation } = require('../util');
|
||||
const { escapeMarkdown } = require('discord.js');
|
||||
|
||||
class RoleArgumentType extends ArgumentType {
|
||||
constructor(client) {
|
||||
super(client, 'role');
|
||||
}
|
||||
|
||||
validate(val, msg, arg) {
|
||||
const matches = val.match(/^(?:<@&)?([0-9]+)>?$/);
|
||||
if(matches) return msg.guild.roles.cache.has(matches[1]);
|
||||
const search = val.toLowerCase();
|
||||
let roles = msg.guild.roles.cache.filter(nameFilterInexact(search));
|
||||
if(roles.size === 0) return false;
|
||||
if(roles.size === 1) {
|
||||
if(arg.oneOf && !arg.oneOf.includes(roles.first().id)) return false;
|
||||
return true;
|
||||
}
|
||||
const exactRoles = roles.filter(nameFilterExact(search));
|
||||
if(exactRoles.size === 1) {
|
||||
if(arg.oneOf && !arg.oneOf.includes(exactRoles.first().id)) return false;
|
||||
return true;
|
||||
}
|
||||
if(exactRoles.size > 0) roles = exactRoles;
|
||||
return roles.size <= 15 ?
|
||||
`${disambiguation(roles.map(role => `${escapeMarkdown(role.name)}`), 'roles', null)}\n` :
|
||||
'Multiple roles found. Please be more specific.';
|
||||
}
|
||||
|
||||
parse(val, msg) {
|
||||
const matches = val.match(/^(?:<@&)?([0-9]+)>?$/);
|
||||
if(matches) return msg.guild.roles.cache.get(matches[1]) || null;
|
||||
const search = val.toLowerCase();
|
||||
const roles = msg.guild.roles.cache.filter(nameFilterInexact(search));
|
||||
if(roles.size === 0) return null;
|
||||
if(roles.size === 1) return roles.first();
|
||||
const exactRoles = roles.filter(nameFilterExact(search));
|
||||
if(exactRoles.size === 1) return exactRoles.first();
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
function nameFilterExact(search) {
|
||||
return thing => thing.name.toLowerCase() === search;
|
||||
}
|
||||
|
||||
function nameFilterInexact(search) {
|
||||
return thing => thing.name.toLowerCase().includes(search);
|
||||
}
|
||||
|
||||
module.exports = RoleArgumentType;
|
||||
26
node_modules/discord.js-commando/src/types/string.js
generated
vendored
Normal file
26
node_modules/discord.js-commando/src/types/string.js
generated
vendored
Normal file
@@ -0,0 +1,26 @@
|
||||
const ArgumentType = require('./base');
|
||||
|
||||
class StringArgumentType extends ArgumentType {
|
||||
constructor(client) {
|
||||
super(client, 'string');
|
||||
}
|
||||
|
||||
validate(val, msg, arg) {
|
||||
if(arg.oneOf && !arg.oneOf.includes(val.toLowerCase())) {
|
||||
return `Please enter one of the following options: ${arg.oneOf.map(opt => `\`${opt}\``).join(', ')}`;
|
||||
}
|
||||
if(arg.min !== null && typeof arg.min !== 'undefined' && val.length < arg.min) {
|
||||
return `Please keep the ${arg.label} above or exactly ${arg.min} characters.`;
|
||||
}
|
||||
if(arg.max !== null && typeof arg.max !== 'undefined' && val.length > arg.max) {
|
||||
return `Please keep the ${arg.label} below or exactly ${arg.max} characters.`;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
parse(val) {
|
||||
return val;
|
||||
}
|
||||
}
|
||||
|
||||
module.exports = StringArgumentType;
|
||||
65
node_modules/discord.js-commando/src/types/text-channel.js
generated
vendored
Normal file
65
node_modules/discord.js-commando/src/types/text-channel.js
generated
vendored
Normal file
@@ -0,0 +1,65 @@
|
||||
const ArgumentType = require('./base');
|
||||
const { disambiguation } = require('../util');
|
||||
const { escapeMarkdown } = require('discord.js');
|
||||
|
||||
class TextChannelArgumentType extends ArgumentType {
|
||||
constructor(client) {
|
||||
super(client, 'text-channel');
|
||||
}
|
||||
|
||||
validate(val, msg, arg) {
|
||||
const matches = val.match(/^(?:<#)?([0-9]+)>?$/);
|
||||
if(matches) {
|
||||
try {
|
||||
const channel = msg.client.channels.resolve(matches[1]);
|
||||
if(!channel || channel.type !== 'text') return false;
|
||||
if(arg.oneOf && !arg.oneOf.includes(channel.id)) return false;
|
||||
return true;
|
||||
} catch(err) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
if(!msg.guild) return false;
|
||||
const search = val.toLowerCase();
|
||||
let channels = msg.guild.channels.cache.filter(channelFilterInexact(search));
|
||||
if(channels.size === 0) return false;
|
||||
if(channels.size === 1) {
|
||||
if(arg.oneOf && !arg.oneOf.includes(channels.first().id)) return false;
|
||||
return true;
|
||||
}
|
||||
const exactChannels = channels.filter(channelFilterExact(search));
|
||||
if(exactChannels.size === 1) {
|
||||
if(arg.oneOf && !arg.oneOf.includes(exactChannels.first().id)) return false;
|
||||
return true;
|
||||
}
|
||||
if(exactChannels.size > 0) channels = exactChannels;
|
||||
return channels.size <= 15 ?
|
||||
`${disambiguation(
|
||||
channels.map(chan => escapeMarkdown(chan.name)), 'text channels', null
|
||||
)}\n` :
|
||||
'Multiple text channels found. Please be more specific.';
|
||||
}
|
||||
|
||||
parse(val, msg) {
|
||||
const matches = val.match(/^(?:<#)?([0-9]+)>?$/);
|
||||
if(matches) return msg.client.channels.resolve(matches[1]) || null;
|
||||
if(!msg.guild) return null;
|
||||
const search = val.toLowerCase();
|
||||
const channels = msg.guild.channels.cache.filter(channelFilterInexact(search));
|
||||
if(channels.size === 0) return null;
|
||||
if(channels.size === 1) return channels.first();
|
||||
const exactChannels = channels.filter(channelFilterExact(search));
|
||||
if(exactChannels.size === 1) return exactChannels.first();
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
function channelFilterExact(search) {
|
||||
return chan => chan.type === 'text' && chan.name.toLowerCase() === search;
|
||||
}
|
||||
|
||||
function channelFilterInexact(search) {
|
||||
return chan => chan.type === 'text' && chan.name.toLowerCase().includes(search);
|
||||
}
|
||||
|
||||
module.exports = TextChannelArgumentType;
|
||||
47
node_modules/discord.js-commando/src/types/union.js
generated
vendored
Normal file
47
node_modules/discord.js-commando/src/types/union.js
generated
vendored
Normal file
@@ -0,0 +1,47 @@
|
||||
const ArgumentType = require('./base');
|
||||
|
||||
/**
|
||||
* A type for command arguments that handles multiple other types
|
||||
* @extends {ArgumentType}
|
||||
*/
|
||||
class ArgumentUnionType extends ArgumentType {
|
||||
constructor(client, id) {
|
||||
super(client, id);
|
||||
|
||||
/**
|
||||
* Types to handle, in order of priority
|
||||
* @type {ArgumentType[]}
|
||||
*/
|
||||
this.types = [];
|
||||
const typeIDs = id.split('|');
|
||||
for(const typeID of typeIDs) {
|
||||
const type = client.registry.types.get(typeID);
|
||||
if(!type) throw new Error(`Argument type "${typeID}" is not registered.`);
|
||||
this.types.push(type);
|
||||
}
|
||||
}
|
||||
|
||||
async validate(val, msg, arg) {
|
||||
let results = this.types.map(type => !type.isEmpty(val, msg, arg) && type.validate(val, msg, arg));
|
||||
results = await Promise.all(results);
|
||||
if(results.some(valid => valid && typeof valid !== 'string')) return true;
|
||||
const errors = results.filter(valid => typeof valid === 'string');
|
||||
if(errors.length > 0) return errors.join('\n');
|
||||
return false;
|
||||
}
|
||||
|
||||
async parse(val, msg, arg) {
|
||||
let results = this.types.map(type => !type.isEmpty(val, msg, arg) && type.validate(val, msg, arg));
|
||||
results = await Promise.all(results);
|
||||
for(let i = 0; i < results.length; i++) {
|
||||
if(results[i] && typeof results[i] !== 'string') return this.types[i].parse(val, msg, arg);
|
||||
}
|
||||
throw new Error(`Couldn't parse value "${val}" with union type ${this.id}.`);
|
||||
}
|
||||
|
||||
isEmpty(val, msg, arg) {
|
||||
return !this.types.some(type => !type.isEmpty(val, msg, arg));
|
||||
}
|
||||
}
|
||||
|
||||
module.exports = ArgumentUnionType;
|
||||
69
node_modules/discord.js-commando/src/types/user.js
generated
vendored
Normal file
69
node_modules/discord.js-commando/src/types/user.js
generated
vendored
Normal file
@@ -0,0 +1,69 @@
|
||||
const ArgumentType = require('./base');
|
||||
const { disambiguation } = require('../util');
|
||||
const { escapeMarkdown } = require('discord.js');
|
||||
|
||||
class UserArgumentType extends ArgumentType {
|
||||
constructor(client) {
|
||||
super(client, 'user');
|
||||
}
|
||||
|
||||
async validate(val, msg, arg) {
|
||||
const matches = val.match(/^(?:<@!?)?([0-9]+)>?$/);
|
||||
if(matches) {
|
||||
try {
|
||||
const user = await msg.client.users.fetch(matches[1]);
|
||||
if(!user) return false;
|
||||
if(arg.oneOf && !arg.oneOf.includes(user.id)) return false;
|
||||
return true;
|
||||
} catch(err) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
if(!msg.guild) return false;
|
||||
const search = val.toLowerCase();
|
||||
let members = msg.guild.members.cache.filter(memberFilterInexact(search));
|
||||
if(members.size === 0) return false;
|
||||
if(members.size === 1) {
|
||||
if(arg.oneOf && !arg.oneOf.includes(members.first().id)) return false;
|
||||
return true;
|
||||
}
|
||||
const exactMembers = members.filter(memberFilterExact(search));
|
||||
if(exactMembers.size === 1) {
|
||||
if(arg.oneOf && !arg.oneOf.includes(exactMembers.first().id)) return false;
|
||||
return true;
|
||||
}
|
||||
if(exactMembers.size > 0) members = exactMembers;
|
||||
return members.size <= 15 ?
|
||||
`${disambiguation(
|
||||
members.map(mem => `${escapeMarkdown(mem.user.username)}#${mem.user.discriminator}`), 'users', null
|
||||
)}\n` :
|
||||
'Multiple users found. Please be more specific.';
|
||||
}
|
||||
|
||||
parse(val, msg) {
|
||||
const matches = val.match(/^(?:<@!?)?([0-9]+)>?$/);
|
||||
if(matches) return msg.client.users.cache.get(matches[1]) || null;
|
||||
if(!msg.guild) return null;
|
||||
const search = val.toLowerCase();
|
||||
const members = msg.guild.members.cache.filter(memberFilterInexact(search));
|
||||
if(members.size === 0) return null;
|
||||
if(members.size === 1) return members.first().user;
|
||||
const exactMembers = members.filter(memberFilterExact(search));
|
||||
if(exactMembers.size === 1) return exactMembers.first().user;
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
function memberFilterExact(search) {
|
||||
return mem => mem.user.username.toLowerCase() === search ||
|
||||
(mem.nickname && mem.nickname.toLowerCase() === search) ||
|
||||
`${mem.user.username.toLowerCase()}#${mem.user.discriminator}` === search;
|
||||
}
|
||||
|
||||
function memberFilterInexact(search) {
|
||||
return mem => mem.user.username.toLowerCase().includes(search) ||
|
||||
(mem.nickname && mem.nickname.toLowerCase().includes(search)) ||
|
||||
`${mem.user.username.toLowerCase()}#${mem.user.discriminator}`.includes(search);
|
||||
}
|
||||
|
||||
module.exports = UserArgumentType;
|
||||
65
node_modules/discord.js-commando/src/types/voice-channel.js
generated
vendored
Normal file
65
node_modules/discord.js-commando/src/types/voice-channel.js
generated
vendored
Normal file
@@ -0,0 +1,65 @@
|
||||
const ArgumentType = require('./base');
|
||||
const { disambiguation } = require('../util');
|
||||
const { escapeMarkdown } = require('discord.js');
|
||||
|
||||
class VoiceChannelArgumentType extends ArgumentType {
|
||||
constructor(client) {
|
||||
super(client, 'voice-channel');
|
||||
}
|
||||
|
||||
validate(val, msg, arg) {
|
||||
const matches = val.match(/^([0-9]+)$/);
|
||||
if(matches) {
|
||||
try {
|
||||
const channel = msg.client.channels.resolve(matches[1]);
|
||||
if(!channel || channel.type !== 'voice') return false;
|
||||
if(arg.oneOf && !arg.oneOf.includes(channel.id)) return false;
|
||||
return true;
|
||||
} catch(err) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
if(!msg.guild) return false;
|
||||
const search = val.toLowerCase();
|
||||
let channels = msg.guild.channels.cache.filter(channelFilterInexact(search));
|
||||
if(channels.size === 0) return false;
|
||||
if(channels.size === 1) {
|
||||
if(arg.oneOf && !arg.oneOf.includes(channels.first().id)) return false;
|
||||
return true;
|
||||
}
|
||||
const exactChannels = channels.filter(channelFilterExact(search));
|
||||
if(exactChannels.size === 1) {
|
||||
if(arg.oneOf && !arg.oneOf.includes(exactChannels.first().id)) return false;
|
||||
return true;
|
||||
}
|
||||
if(exactChannels.size > 0) channels = exactChannels;
|
||||
return channels.size <= 15 ?
|
||||
`${disambiguation(
|
||||
channels.map(chan => escapeMarkdown(chan.name)), 'voice channels', null
|
||||
)}\n` :
|
||||
'Multiple voice channels found. Please be more specific.';
|
||||
}
|
||||
|
||||
parse(val, msg) {
|
||||
const matches = val.match(/^([0-9]+)$/);
|
||||
if(matches) return msg.client.channels.cache.get(matches[1]) || null;
|
||||
if(!msg.guild) return null;
|
||||
const search = val.toLowerCase();
|
||||
const channels = msg.guild.channels.cache.filter(channelFilterInexact(search));
|
||||
if(channels.size === 0) return null;
|
||||
if(channels.size === 1) return channels.first();
|
||||
const exactChannels = channels.filter(channelFilterExact(search));
|
||||
if(exactChannels.size === 1) return exactChannels.first();
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
function channelFilterExact(search) {
|
||||
return chan => chan.type === 'voice' && chan.name.toLowerCase() === search;
|
||||
}
|
||||
|
||||
function channelFilterInexact(search) {
|
||||
return chan => chan.type === 'voice' && chan.name.toLowerCase().includes(search);
|
||||
}
|
||||
|
||||
module.exports = VoiceChannelArgumentType;
|
||||
78
node_modules/discord.js-commando/src/util.js
generated
vendored
Normal file
78
node_modules/discord.js-commando/src/util.js
generated
vendored
Normal file
@@ -0,0 +1,78 @@
|
||||
// This returns Object.prototype in order to return a valid object
|
||||
// without creating a new one each time this is called just to discard it the moment after.
|
||||
const isConstructorProxyHandler = { construct() { return Object.prototype; } };
|
||||
|
||||
function escapeRegex(str) {
|
||||
return str.replace(/[|\\{}()[\]^$+*?.]/g, '\\$&');
|
||||
}
|
||||
|
||||
function disambiguation(items, label, property = 'name') {
|
||||
const itemList = items.map(item => `"${(property ? item[property] : item).replace(/ /g, '\xa0')}"`).join(', ');
|
||||
return `Multiple ${label} found, please be more specific: ${itemList}`;
|
||||
}
|
||||
|
||||
function isConstructor(func, _class) {
|
||||
try {
|
||||
// eslint-disable-next-line no-new
|
||||
new new Proxy(func, isConstructorProxyHandler)();
|
||||
if(!_class) return true;
|
||||
return func.prototype instanceof _class;
|
||||
} catch(err) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
function paginate(items, page = 1, pageLength = 10) {
|
||||
const maxPage = Math.ceil(items.length / pageLength);
|
||||
if(page < 1) page = 1;
|
||||
if(page > maxPage) page = maxPage;
|
||||
const startIndex = (page - 1) * pageLength;
|
||||
return {
|
||||
items: items.length > pageLength ? items.slice(startIndex, startIndex + pageLength) : items,
|
||||
page,
|
||||
maxPage,
|
||||
pageLength
|
||||
};
|
||||
}
|
||||
|
||||
const permissions = {
|
||||
ADMINISTRATOR: 'Administrator',
|
||||
VIEW_AUDIT_LOG: 'View audit log',
|
||||
MANAGE_GUILD: 'Manage server',
|
||||
MANAGE_ROLES: 'Manage roles',
|
||||
MANAGE_CHANNELS: 'Manage channels',
|
||||
KICK_MEMBERS: 'Kick members',
|
||||
BAN_MEMBERS: 'Ban members',
|
||||
CREATE_INSTANT_INVITE: 'Create instant invite',
|
||||
CHANGE_NICKNAME: 'Change nickname',
|
||||
MANAGE_NICKNAMES: 'Manage nicknames',
|
||||
MANAGE_EMOJIS: 'Manage emojis',
|
||||
MANAGE_WEBHOOKS: 'Manage webhooks',
|
||||
VIEW_CHANNEL: 'View channels',
|
||||
SEND_MESSAGES: 'Send messages',
|
||||
SEND_TTS_MESSAGES: 'Send TTS messages',
|
||||
MANAGE_MESSAGES: 'Manage messages',
|
||||
EMBED_LINKS: 'Embed links',
|
||||
ATTACH_FILES: 'Attach files',
|
||||
READ_MESSAGE_HISTORY: 'Read message history',
|
||||
MENTION_EVERYONE: 'Mention everyone',
|
||||
USE_EXTERNAL_EMOJIS: 'Use external emojis',
|
||||
ADD_REACTIONS: 'Add reactions',
|
||||
CONNECT: 'Connect',
|
||||
SPEAK: 'Speak',
|
||||
MUTE_MEMBERS: 'Mute members',
|
||||
DEAFEN_MEMBERS: 'Deafen members',
|
||||
MOVE_MEMBERS: 'Move members',
|
||||
USE_VAD: 'Use voice activity',
|
||||
PRIORITY_SPEAKER: 'Priority speaker',
|
||||
VIEW_GUILD_INSIGHTS: 'View server insights',
|
||||
STREAM: 'Video'
|
||||
};
|
||||
|
||||
module.exports = {
|
||||
escapeRegex,
|
||||
disambiguation,
|
||||
paginate,
|
||||
permissions,
|
||||
isConstructor
|
||||
};
|
||||
19
node_modules/discord.js-commando/tsconfig.json
generated
vendored
Normal file
19
node_modules/discord.js-commando/tsconfig.json
generated
vendored
Normal file
@@ -0,0 +1,19 @@
|
||||
{
|
||||
"compilerOptions": {
|
||||
"module": "commonjs",
|
||||
"target": "es2017",
|
||||
"lib": [
|
||||
"es7"
|
||||
],
|
||||
"noImplicitAny": false,
|
||||
"removeComments": true,
|
||||
"sourceMap": true,
|
||||
"allowJs": true
|
||||
},
|
||||
"include": [
|
||||
"typings/**/*"
|
||||
],
|
||||
"exclude": [
|
||||
"node_modules"
|
||||
]
|
||||
}
|
||||
33
node_modules/discord.js-commando/typings/discord.js-commando-test.ts
generated
vendored
Normal file
33
node_modules/discord.js-commando/typings/discord.js-commando-test.ts
generated
vendored
Normal file
@@ -0,0 +1,33 @@
|
||||
/// <reference path='index.d.ts' />
|
||||
|
||||
import { Message } from 'discord.js';
|
||||
import { Command, CommandoMessage, CommandoClient } from 'discord.js-commando';
|
||||
|
||||
const client = new CommandoClient();
|
||||
|
||||
client.on('message', (message: Message) => {
|
||||
if (message.content === 'hello') {
|
||||
message.channel.send('o/');
|
||||
}
|
||||
});
|
||||
|
||||
class TestCommand extends Command {
|
||||
constructor(client: CommandoClient) {
|
||||
super(client, {
|
||||
name: 'test',
|
||||
group: 'test',
|
||||
memberName: 'test',
|
||||
description: 'test'
|
||||
});
|
||||
}
|
||||
|
||||
public hasPermission(message: CommandoMessage): boolean {
|
||||
return true;
|
||||
}
|
||||
|
||||
public async run(message: CommandoMessage, args: {} | string | string[]): Promise<Message | Message[]> {
|
||||
return message.say('test');
|
||||
}
|
||||
}
|
||||
|
||||
client.login('aefsrgbr6t7u68i6t7ikjtz.sdfdsujhfisudhfsd.dufhsdufh8ehf8hw8ehf83h4thushdg');
|
||||
500
node_modules/discord.js-commando/typings/index.d.ts
generated
vendored
Normal file
500
node_modules/discord.js-commando/typings/index.d.ts
generated
vendored
Normal file
@@ -0,0 +1,500 @@
|
||||
declare module 'discord.js-commando' {
|
||||
import { Client, ClientEvents, ClientOptions, Collection, Guild, GuildResolvable, Message, MessageAttachment, MessageEditOptions, MessageEmbed, MessageOptions, MessageAdditions, MessageReaction, PermissionResolvable, PermissionString, StringResolvable, User, UserResolvable } from 'discord.js';
|
||||
|
||||
export class Argument {
|
||||
private constructor(client: CommandoClient, info: ArgumentInfo);
|
||||
|
||||
private obtainInfinite(msg: CommandoMessage, vals?: string[], promptLimit?: number): Promise<ArgumentResult>;
|
||||
|
||||
private static validateInfo(client: CommandoClient, info: ArgumentInfo): void;
|
||||
|
||||
public default: ArgumentDefault;
|
||||
public emptyChecker: Function;
|
||||
public error: string;
|
||||
public infinite: boolean;
|
||||
public key: string;
|
||||
public label: string;
|
||||
public max: number;
|
||||
public min: number;
|
||||
public oneOf: string[];
|
||||
public parser: Function;
|
||||
public prompt: string;
|
||||
public type: ArgumentType;
|
||||
public validator: Function;
|
||||
public wait: number;
|
||||
|
||||
public isEmpty(val: string, msg: CommandoMessage): boolean;
|
||||
public obtain(msg: CommandoMessage, val?: string, promptLimit?: number): Promise<ArgumentResult>;
|
||||
public parse(val: string, msg: CommandoMessage): any | Promise<any>;
|
||||
public validate(val: string, msg: CommandoMessage): boolean | string | Promise<boolean | string>;
|
||||
}
|
||||
|
||||
export class ArgumentCollector {
|
||||
public constructor(client: CommandoClient, args: ArgumentInfo[], promptLimit?: number);
|
||||
|
||||
public args: Argument[];
|
||||
public readonly client: CommandoClient;
|
||||
public promptLimit: number;
|
||||
|
||||
public obtain(msg: CommandoMessage, provided?: any[], promptLimit?: number): Promise<ArgumentCollectorResult>;
|
||||
}
|
||||
|
||||
export abstract class ArgumentType {
|
||||
public constructor(client: CommandoClient, id: string);
|
||||
|
||||
public readonly client: CommandoClient;
|
||||
public id: string;
|
||||
|
||||
public isEmpty(val: string, msg: CommandoMessage, arg: Argument): boolean;
|
||||
public abstract parse(val: string, msg: CommandoMessage, arg: Argument): any | Promise<any>;
|
||||
public abstract validate(val: string, msg: CommandoMessage, arg: Argument): boolean | string | Promise<boolean | string>;
|
||||
}
|
||||
|
||||
export class ArgumentUnionType extends ArgumentType {
|
||||
public types: ArgumentType[];
|
||||
|
||||
public parse(val: string, msg: CommandoMessage, arg: Argument): any | Promise<any>;
|
||||
public validate(val: string, msg: CommandoMessage, arg: Argument): string | boolean | Promise<string | boolean>;
|
||||
}
|
||||
|
||||
export abstract class Command {
|
||||
public constructor(client: CommandoClient, info: CommandInfo);
|
||||
|
||||
private _globalEnabled: boolean;
|
||||
private _throttles: Map<string, object>;
|
||||
|
||||
private throttle(userID: string): object;
|
||||
|
||||
private static validateInfo(client: CommandoClient, info: CommandInfo);
|
||||
|
||||
public aliases: string[];
|
||||
public argsCollector: ArgumentCollector;
|
||||
public argsCount: number;
|
||||
public argsSingleQuotes: boolean;
|
||||
public argsType: string;
|
||||
public readonly client: CommandoClient;
|
||||
public clientPermissions: PermissionResolvable[];
|
||||
public defaultHandling: boolean;
|
||||
public description: string;
|
||||
public details: string;
|
||||
public examples: string[];
|
||||
public format: string;
|
||||
public group: CommandGroup;
|
||||
public groupID: string;
|
||||
public guarded: boolean;
|
||||
public guildOnly: boolean;
|
||||
public hidden: boolean;
|
||||
public memberName: string;
|
||||
public name: string;
|
||||
public nsfw: boolean;
|
||||
public ownerOnly: boolean;
|
||||
public patterns: RegExp[];
|
||||
public throttling: ThrottlingOptions;
|
||||
public unknown: boolean;
|
||||
public userPermissions: PermissionResolvable[];
|
||||
|
||||
public hasPermission(message: CommandoMessage, ownerOverride?: boolean): boolean | string;
|
||||
public isEnabledIn(guild: GuildResolvable, bypassGroup?: boolean): boolean;
|
||||
public isUsable(message?: Message): boolean;
|
||||
public onBlock(message: CommandoMessage, reason: string, data?: object): Promise<Message | Message[]>;
|
||||
public onBlock(message: CommandoMessage, reason: 'guildOnly' | 'nsfw'): Promise<Message | Message[]>;
|
||||
public onBlock(message: CommandoMessage, reason: 'permission', data: { response?: string }): Promise<Message | Message[]>;
|
||||
public onBlock(message: CommandoMessage, reason: 'clientPermissions', data: { missing: PermissionString[] }): Promise<Message | Message[]>;
|
||||
public onBlock(message: CommandoMessage, reason: 'throttling', data: { throttle: object, remaining: number }): Promise<Message | Message[]>;
|
||||
public onError(err: Error, message: CommandoMessage, args: object | string | string[], fromPattern: false, result?: ArgumentCollectorResult): Promise<Message | Message[]>;
|
||||
public onError(err: Error, message: CommandoMessage, args: string[], fromPattern: true, result?: ArgumentCollectorResult): Promise<Message | Message[]>;
|
||||
public reload(): void;
|
||||
public abstract run(message: CommandoMessage, args: object | string | string[], fromPattern: boolean, result?: ArgumentCollectorResult): Promise<Message | Message[] | null> | null;
|
||||
public setEnabledIn(guild: GuildResolvable, enabled: boolean): void;
|
||||
public unload(): void;
|
||||
public usage(argString?: string, prefix?: string, user?: User): string;
|
||||
|
||||
public static usage(command: string, prefix?: string, user?: User): string;
|
||||
}
|
||||
|
||||
export class CommandDispatcher {
|
||||
public constructor(client: CommandoClient, registry: CommandoRegistry);
|
||||
|
||||
private _awaiting: Set<string>;
|
||||
private _commandPatterns: object;
|
||||
private _results: Map<string, CommandoMessage>;
|
||||
|
||||
private buildCommandPattern(prefix: string): RegExp;
|
||||
private cacheCommandoMessage(message: Message, oldMessage: Message, cmdMsg: CommandoMessage, responses: Message | Message[]): void;
|
||||
private handleMessage(message: Message, oldMessage?: Message): Promise<void>;
|
||||
private inhibit(cmdMsg: CommandoMessage): Inhibition;
|
||||
private matchDefault(message: Message, pattern: RegExp, commandNameIndex?: number, prefixless?: boolean): CommandoMessage;
|
||||
private parseMessage(message: Message): CommandoMessage;
|
||||
private shouldHandleMessage(message: Message, oldMessage?: Message): boolean;
|
||||
|
||||
public readonly client: CommandoClient;
|
||||
public inhibitors: Set<Function>;
|
||||
public registry: CommandoRegistry;
|
||||
|
||||
public addInhibitor(inhibitor: Inhibitor): boolean;
|
||||
public removeInhibitor(inhibitor: Inhibitor): boolean;
|
||||
}
|
||||
|
||||
export class CommandFormatError extends FriendlyError {
|
||||
public constructor(msg: CommandoMessage);
|
||||
}
|
||||
|
||||
export class CommandGroup {
|
||||
public constructor(client: CommandoClient, id: string, name?: string, guarded?: boolean);
|
||||
|
||||
public readonly client: CommandoClient;
|
||||
public commands: Collection<string, Command>
|
||||
public guarded: boolean;
|
||||
public id: string;
|
||||
public name: string;
|
||||
|
||||
public isEnabledIn(guild: GuildResolvable): boolean;
|
||||
public reload(): void;
|
||||
public setEnabledIn(guild: GuildResolvable, enabled: boolean): void;
|
||||
}
|
||||
|
||||
export class CommandoMessage extends Message {
|
||||
public argString: string | null;
|
||||
public command: Command | null;
|
||||
public isCommand: boolean;
|
||||
public patternMatches: string[] | null;
|
||||
public responsePositions: { [key: string]: number } | null;
|
||||
public responses: { [key: string]: CommandoMessage[] } | null;
|
||||
public readonly guild: CommandoGuild;
|
||||
|
||||
private deleteRemainingResponses(): void;
|
||||
private editCurrentResponse(id: string, options: MessageEditOptions | Exclude<MessageAdditions, MessageAttachment>): Promise<CommandoMessage | CommandoMessage[]>;
|
||||
private editResponse(response: CommandoMessage | CommandoMessage[], options: RespondEditOptions): Promise<CommandoMessage | CommandoMessage[]>;
|
||||
private finalize(responses: (CommandoMessage | CommandoMessage[])[]): void;
|
||||
private respond(options: RespondOptions): Promise<CommandoMessage | CommandoMessage[]>;
|
||||
|
||||
public anyUsage(argString?: string, prefix?: string, user?: User): string;
|
||||
public code: CommandoMessage['say'];
|
||||
public direct: CommandoMessage['say'];
|
||||
public embed(embed: MessageEmbed, content?: StringResolvable, options?: (MessageOptions & { split?: false }) | MessageAdditions): Promise<CommandoMessage>;
|
||||
public embed(embed: MessageEmbed, content?: StringResolvable, options?: (MessageOptions & { split: true | Exclude<MessageOptions['split'], boolean> }) | MessageAdditions): Promise<CommandoMessage[]>;
|
||||
public initCommand(command?: Command, argString?: string[], patternMatches?: string[]): this;
|
||||
public parseArgs(): string | string[];
|
||||
public replyEmbed: CommandoMessage['embed'];
|
||||
public run(): Promise<null | CommandoMessage | CommandoMessage[]>;
|
||||
public say(
|
||||
content: StringResolvable | (MessageOptions & { split?: false }) | MessageAdditions,
|
||||
options?: (MessageOptions & { split?: false }) | MessageAdditions
|
||||
): Promise<CommandoMessage>;
|
||||
public say(
|
||||
content: StringResolvable | (MessageOptions & { split: true | Exclude<MessageOptions['split'], boolean> }) | MessageAdditions,
|
||||
options?: (MessageOptions & { split: true | Exclude<MessageOptions['split'], boolean> }) | MessageAdditions
|
||||
): Promise<CommandoMessage[]>;
|
||||
public usage(argString?: string, prefix?: string, user?: User): string;
|
||||
|
||||
public static parseArgs(argString: string, argCount?: number, allowSingleQuote?: boolean): string[];
|
||||
}
|
||||
|
||||
export class CommandoClient extends Client {
|
||||
public constructor(options?: CommandoClientOptions);
|
||||
|
||||
private _commandPrefix: string;
|
||||
|
||||
public commandPrefix: string;
|
||||
public dispatcher: CommandDispatcher;
|
||||
public options: CommandoClientOptions;
|
||||
public readonly owners: User[];
|
||||
public provider: SettingProvider;
|
||||
public registry: CommandoRegistry;
|
||||
public settings: GuildSettingsHelper;
|
||||
|
||||
public isOwner(user: UserResolvable): boolean;
|
||||
public setProvider(provider: SettingProvider | Promise<SettingProvider>): Promise<void>;
|
||||
|
||||
public on<K extends keyof CommandoClientEvents>(event: K, listener: (...args: CommandoClientEvents[K]) => void): this;
|
||||
public once<K extends keyof CommandoClientEvents>(event: K, listener: (...args: CommandoClientEvents[K]) => void): this;
|
||||
public emit<K extends keyof CommandoClientEvents>(event: K, ...args: CommandoClientEvents[K]): boolean;
|
||||
}
|
||||
|
||||
export { CommandoClient as Client };
|
||||
|
||||
export class CommandoGuild extends Guild {
|
||||
private _commandPrefix: string;
|
||||
private _commandsEnabled: object;
|
||||
private _groupsEnabled: object;
|
||||
private _settings: GuildSettingsHelper;
|
||||
|
||||
public commandPrefix: string;
|
||||
public readonly settings: GuildSettingsHelper;
|
||||
|
||||
public commandUsage(command?: string, user?: User): string;
|
||||
public isCommandEnabled(command: CommandResolvable): boolean;
|
||||
public isGroupEnabled(group: CommandGroupResolvable): boolean;
|
||||
public setCommandEnabled(command: CommandResolvable, enabled: boolean): void;
|
||||
public setGroupEnabled(group: CommandGroupResolvable, enabled: boolean): void;
|
||||
}
|
||||
|
||||
export class CommandoRegistry {
|
||||
public constructor(client?: CommandoClient);
|
||||
|
||||
public readonly client: CommandoClient;
|
||||
public commands: Collection<string, Command>;
|
||||
public commandsPath: string;
|
||||
public groups: Collection<string, CommandGroup>;
|
||||
public types: Collection<string, ArgumentType>;
|
||||
public unknownCommand?: Command;
|
||||
|
||||
public findCommands(searchString?: string, exact?: boolean, message?: Message | CommandoMessage): Command[];
|
||||
public findGroups(searchString?: string, exact?: boolean): CommandGroup[];
|
||||
public registerCommand(command: Command | Function): CommandoRegistry;
|
||||
public registerCommands(commands: Command[] | Function[], ignoreInvalid?: boolean): CommandoRegistry;
|
||||
public registerCommandsIn(options: string | {}): CommandoRegistry;
|
||||
public registerDefaultCommands(commands?: DefaultCommandsOptions): CommandoRegistry;
|
||||
public registerDefaultGroups(): CommandoRegistry;
|
||||
public registerDefaults(): CommandoRegistry;
|
||||
public registerDefaultTypes(types?: DefaultTypesOptions): CommandoRegistry;
|
||||
public registerGroup(group: CommandGroup | Function | { id: string, name?: string, guarded?: boolean } | string, name?: string, guarded?: boolean): CommandoRegistry;
|
||||
public registerGroups(groups: CommandGroup[] | Function[] | { id: string, name?: string, guarded?: boolean }[] | string[][]): CommandoRegistry;
|
||||
public registerType(type: ArgumentType | Function): CommandoRegistry;
|
||||
public registerTypes(type: ArgumentType[] | Function[], ignoreInvalid?: boolean): CommandoRegistry;
|
||||
public registerTypesIn(options: string | {}): CommandoRegistry;
|
||||
public reregisterCommand(command: Command | Function, oldCommand: Command): void;
|
||||
public resolveCommand(command: CommandResolvable): Command;
|
||||
public resolveCommandPath(group: string, memberName: string): string;
|
||||
public resolveGroup(group: CommandGroupResolvable): CommandGroup;
|
||||
public unregisterCommand(command: Command): void;
|
||||
}
|
||||
|
||||
export class FriendlyError extends Error {
|
||||
public constructor(message: string);
|
||||
}
|
||||
|
||||
export class GuildSettingsHelper {
|
||||
public constructor(client: CommandoClient, guild: CommandoGuild);
|
||||
|
||||
public readonly client: CommandoClient;
|
||||
public guild: CommandoGuild;
|
||||
|
||||
public clear(): Promise<void>;
|
||||
public get(key: string, defVal?: any): any;
|
||||
public remove(key: string): Promise<any>;
|
||||
public set(key: string, val: any): Promise<any>;
|
||||
}
|
||||
|
||||
export abstract class SettingProvider {
|
||||
public abstract clear(guild: Guild | string): Promise<void>;
|
||||
public abstract destroy(): Promise<void>;
|
||||
public abstract get(guild: Guild | string, key: string, defVal?: any): any;
|
||||
public abstract init(client: CommandoClient): Promise<void>;
|
||||
public abstract remove(guild: Guild | string, key: string): Promise<any>;
|
||||
public abstract set(guild: Guild | string, key: string, val: any): Promise<any>;
|
||||
|
||||
public static getGuildID(guild: Guild | string): string;
|
||||
}
|
||||
|
||||
export class SQLiteProvider extends SettingProvider {
|
||||
public constructor(db: any | Promise<any>);
|
||||
|
||||
public readonly client: CommandoClient;
|
||||
public db: any;
|
||||
private deleteStmt: any;
|
||||
private insertOrReplaceStmt: any;
|
||||
private listeners: Map<any, any>;
|
||||
private settings: Map<any, any>;
|
||||
|
||||
public clear(guild: Guild | string): Promise<void>;
|
||||
public destroy(): Promise<void>;
|
||||
public get(guild: Guild | string, key: string, defVal?: any): any;
|
||||
public init(client: CommandoClient): Promise<void>;
|
||||
public remove(guild: Guild | string, key: string): Promise<any>;
|
||||
public set(guild: Guild | string, key: string, val: any): Promise<any>;
|
||||
private setupGuild(guild: string, settings: {}): void;
|
||||
private setupGuildCommand(guild: CommandoGuild, command: Command, settings: {}): void;
|
||||
private setupGuildGroup(guild: CommandoGuild, group: CommandGroup, settings: {}): void;
|
||||
private updateOtherShards(key: string, val: any): void;
|
||||
}
|
||||
|
||||
export class SyncSQLiteProvider extends SettingProvider {
|
||||
public constructor(db: any | Promise<any>);
|
||||
|
||||
public readonly client: CommandoClient;
|
||||
public db: any;
|
||||
private deleteStmt: any;
|
||||
private insertOrReplaceStmt: any;
|
||||
private listeners: Map<any, any>;
|
||||
private settings: Map<any, any>;
|
||||
|
||||
public clear(guild: Guild | string): Promise<void>;
|
||||
public destroy(): Promise<void>;
|
||||
public get(guild: Guild | string, key: string, defVal?: any): any;
|
||||
public init(client: CommandoClient): Promise<void>;
|
||||
public remove(guild: Guild | string, key: string): Promise<any>;
|
||||
public set(guild: Guild | string, key: string, val: any): Promise<any>;
|
||||
private setupGuild(guild: string, settings: {}): void;
|
||||
private setupGuildCommand(guild: CommandoGuild, command: Command, settings: {}): void;
|
||||
private setupGuildGroup(guild: CommandoGuild, group: CommandGroup, settings: {}): void;
|
||||
private updateOtherShards(key: string, val: any): void;
|
||||
}
|
||||
|
||||
export class util {
|
||||
public static disambiguation(items: any[], label: string, property?: string): string;
|
||||
public static escapeRegex(str: string): string;
|
||||
public static paginate<T>(items: T[], page?: number, pageLength?: number): {
|
||||
items: T[],
|
||||
page: number,
|
||||
maxPage: number,
|
||||
pageLength: number
|
||||
};
|
||||
public static readonly permissions: { [K in PermissionString]: string };
|
||||
}
|
||||
|
||||
export const version: string;
|
||||
|
||||
export interface ArgumentCollectorResult<T = object> {
|
||||
values: T | null;
|
||||
cancelled?: 'user' | 'time' | 'promptLimit';
|
||||
prompts: Message[];
|
||||
answers: Message[];
|
||||
}
|
||||
|
||||
type ArgumentDefault = any | Function;
|
||||
|
||||
export interface ArgumentInfo {
|
||||
key: string;
|
||||
label?: string;
|
||||
prompt: string;
|
||||
error?: string;
|
||||
type?: string;
|
||||
max?: number;
|
||||
min?: number;
|
||||
oneOf?: string[];
|
||||
default?: ArgumentDefault;
|
||||
infinite?: boolean;
|
||||
validate?: Function;
|
||||
parse?: Function;
|
||||
isEmpty?: Function;
|
||||
wait?: number;
|
||||
}
|
||||
|
||||
export interface ArgumentResult {
|
||||
value: any | any[];
|
||||
cancelled?: 'user' | 'time' | 'promptLimit';
|
||||
prompts: Message[];
|
||||
answers: Message[];
|
||||
}
|
||||
|
||||
type CommandGroupResolvable = CommandGroup | string;
|
||||
|
||||
export interface CommandInfo {
|
||||
name: string;
|
||||
aliases?: string[];
|
||||
autoAliases?: boolean;
|
||||
group: string;
|
||||
memberName: string;
|
||||
description: string;
|
||||
format?: string;
|
||||
details?: string;
|
||||
examples?: string[];
|
||||
nsfw?: boolean;
|
||||
guildOnly?: boolean;
|
||||
ownerOnly?: boolean;
|
||||
clientPermissions?: PermissionResolvable[];
|
||||
userPermissions?: PermissionResolvable[];
|
||||
defaultHandling?: boolean;
|
||||
throttling?: ThrottlingOptions;
|
||||
args?: ArgumentInfo[];
|
||||
argsPromptLimit?: number;
|
||||
argsType?: string;
|
||||
argsCount?: number;
|
||||
argsSingleQuotes?: boolean;
|
||||
patterns?: RegExp[];
|
||||
guarded?: boolean;
|
||||
hidden?: boolean;
|
||||
unknown?: boolean;
|
||||
}
|
||||
|
||||
interface CommandoClientEvents extends ClientEvents {
|
||||
commandBlock:
|
||||
| [CommandoMessage, string, object?]
|
||||
| [CommandoMessage, 'guildOnly' | 'nsfw']
|
||||
| [CommandoMessage, 'permission', { response?: string }]
|
||||
| [CommandoMessage, 'throttling', { throttle: object, remaining: number }]
|
||||
| [CommandoMessage, 'clientPermissions', { missing: string }];
|
||||
commandCancel: [Command, string, CommandoMessage];
|
||||
commandError:
|
||||
| [Command, Error, CommandoMessage, object | string | string[], false]
|
||||
| [Command, Error, CommandoMessage, string[], true];
|
||||
commandPrefixChange: [CommandoGuild, string];
|
||||
commandRegister: [Command, CommandoRegistry];
|
||||
commandReregister: [Command, Command];
|
||||
commandRun: [Command, Promise<any>, CommandoMessage, object | string | string[], boolean];
|
||||
commandStatusChange: [CommandoGuild, Command, boolean];
|
||||
commandUnregister: [Command];
|
||||
groupRegister: [CommandGroup, CommandoRegistry];
|
||||
groupStatusChange: [CommandoGuild, CommandGroup, boolean];
|
||||
typeRegister: [ArgumentType, CommandoRegistry];
|
||||
unknownCommand: [CommandoMessage];
|
||||
providerReady: [SettingProvider];
|
||||
}
|
||||
|
||||
export interface CommandoClientOptions extends ClientOptions {
|
||||
commandPrefix?: string;
|
||||
commandEditableDuration?: number;
|
||||
nonCommandEditable?: boolean;
|
||||
owner?: string | string[] | Set<string>;
|
||||
invite?: string;
|
||||
}
|
||||
|
||||
type CommandResolvable = Command | string;
|
||||
|
||||
interface DefaultCommandsOptions {
|
||||
help?: boolean;
|
||||
prefix?: boolean;
|
||||
eval?: boolean;
|
||||
ping?: boolean;
|
||||
unknownCommand?: boolean;
|
||||
commandState?: boolean;
|
||||
}
|
||||
|
||||
interface DefaultTypesOptions {
|
||||
string?: boolean;
|
||||
integer?: boolean;
|
||||
float?: boolean;
|
||||
boolean?: boolean;
|
||||
user?: boolean;
|
||||
member?: boolean;
|
||||
role?: boolean;
|
||||
channel?: boolean;
|
||||
textChannel?: boolean;
|
||||
voiceChannel?: boolean;
|
||||
categoryChannel?: boolean;
|
||||
message?: boolean;
|
||||
customEmoji?: boolean;
|
||||
defaultEmoji?: boolean;
|
||||
command?: boolean;
|
||||
group?: boolean;
|
||||
}
|
||||
|
||||
type Inhibitor = (msg: CommandoMessage) => false | string | Inhibition;
|
||||
|
||||
export interface Inhibition {
|
||||
reason: string;
|
||||
response?: Promise<Message>;
|
||||
}
|
||||
|
||||
export interface ThrottlingOptions {
|
||||
usages: number;
|
||||
duration: number;
|
||||
}
|
||||
|
||||
type ResponseType = 'reply' | 'plain' | 'direct' | 'code';
|
||||
|
||||
interface RespondOptions {
|
||||
content: StringResolvable | MessageOptions;
|
||||
fromEdit?: boolean;
|
||||
options?: MessageOptions;
|
||||
lang?: string;
|
||||
type?: ResponseType;
|
||||
}
|
||||
|
||||
interface RespondEditOptions {
|
||||
content: StringResolvable | MessageEditOptions | Exclude<MessageAdditions, MessageAttachment>;
|
||||
options?: MessageEditOptions | Exclude<MessageAdditions, MessageAttachment>;
|
||||
type?: ResponseType;
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user