From 28341fc1f344f09d2abc806b6c0cae311eac21f9 Mon Sep 17 00:00:00 2001 From: Michael C Date: Sat, 3 Jul 2021 22:49:04 -0400 Subject: [PATCH 1/4] Add eslint based off of SponsorBlock --- .eslintrc.js | 29 + package-lock.json | 2776 ++++++++++++++++++++++++++++++++++++++++++++- package.json | 7 +- 3 files changed, 2799 insertions(+), 13 deletions(-) create mode 100644 .eslintrc.js diff --git a/.eslintrc.js b/.eslintrc.js new file mode 100644 index 0000000..a898b01 --- /dev/null +++ b/.eslintrc.js @@ -0,0 +1,29 @@ +module.exports = { + env: { + browser: false, + es2021: true, + node: true, + }, + extends: [ + "eslint:recommended", + "plugin:@typescript-eslint/recommended", + ], + parser: "@typescript-eslint/parser", + parserOptions: { + ecmaVersion: 12, + sourceType: "module", + }, + plugins: ["@typescript-eslint"], + rules: { + // TODO: Remove warn rules when not needed anymore + "@typescript-eslint/no-this-alias": "warn", + "no-self-assign": "warn", + "@typescript-eslint/no-empty-interface": "warn", + "@typescript-eslint/ban-types": "warn", + }, + settings: { + react: { + version: "detect", + }, + }, +}; \ No newline at end of file diff --git a/package-lock.json b/package-lock.json index 10ab124..ae13a93 100644 --- a/package-lock.json +++ b/package-lock.json @@ -34,6 +34,9 @@ "@types/pg": "^7.14.10", "@types/redis": "^2.8.28", "@types/request": "^2.48.5", + "@typescript-eslint/eslint-plugin": "^4.28.1", + "@typescript-eslint/parser": "^4.28.1", + "eslint": "^7.30.0", "mocha": "^8.4.0", "nodemon": "^2.0.2", "sinon": "^9.2.0", @@ -56,6 +59,231 @@ "tmp": "^0.0.28" } }, + "node_modules/@babel/code-frame": { + "version": "7.12.11", + "resolved": "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.12.11.tgz", + "integrity": "sha512-Zt1yodBx1UcyiePMSkWnU4hPqhwq7hGi2nFL1LeA3EUl+q2LQx16MISgJ0+z7dnmgvP9QtIleuETGOiOH1RcIw==", + "dev": true, + "dependencies": { + "@babel/highlight": "^7.10.4" + } + }, + "node_modules/@babel/helper-validator-identifier": { + "version": "7.14.5", + "resolved": "https://registry.npmjs.org/@babel/helper-validator-identifier/-/helper-validator-identifier-7.14.5.tgz", + "integrity": "sha512-5lsetuxCLilmVGyiLEfoHBRX8UCFD+1m2x3Rj97WrW3V7H3u4RWRXA4evMjImCsin2J2YT0QaVDGf+z8ondbAg==", + "dev": true, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/highlight": { + "version": "7.14.5", + "resolved": "https://registry.npmjs.org/@babel/highlight/-/highlight-7.14.5.tgz", + "integrity": "sha512-qf9u2WFWVV0MppaL877j2dBtQIDgmidgjGk5VIMw3OadXvYaXn66U1BFlH2t4+t3i+8PhedppRv+i40ABzd+gg==", + "dev": true, + "dependencies": { + "@babel/helper-validator-identifier": "^7.14.5", + "chalk": "^2.0.0", + "js-tokens": "^4.0.0" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/highlight/node_modules/ansi-styles": { + "version": "3.2.1", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-3.2.1.tgz", + "integrity": "sha512-VT0ZI6kZRdTh8YyJw3SMbYm/u+NqfsAxEpWO0Pf9sq8/e94WxxOpPKx9FR1FlyCtOVDNOQ+8ntlqFxiRc+r5qA==", + "dev": true, + "dependencies": { + "color-convert": "^1.9.0" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/@babel/highlight/node_modules/chalk": { + "version": "2.4.2", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-2.4.2.tgz", + "integrity": "sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ==", + "dev": true, + "dependencies": { + "ansi-styles": "^3.2.1", + "escape-string-regexp": "^1.0.5", + "supports-color": "^5.3.0" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/@babel/highlight/node_modules/supports-color": { + "version": "5.5.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-5.5.0.tgz", + "integrity": "sha512-QjVjwdXIt408MIiAqCX4oUKsgU2EqAGzs2Ppkm4aQYbjm+ZEWEcW4SfFNTr4uMNZma0ey4f5lgLrkB0aX0QMow==", + "dev": true, + "dependencies": { + "has-flag": "^3.0.0" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/@eslint/eslintrc": { + "version": "0.4.2", + "resolved": "https://registry.npmjs.org/@eslint/eslintrc/-/eslintrc-0.4.2.tgz", + "integrity": "sha512-8nmGq/4ycLpIwzvhI4tNDmQztZ8sp+hI7cyG8i1nQDhkAbRzHpXPidRAHlNvCZQpJTKw5ItIpMw9RSToGF00mg==", + "dev": true, + "dependencies": { + "ajv": "^6.12.4", + "debug": "^4.1.1", + "espree": "^7.3.0", + "globals": "^13.9.0", + "ignore": "^4.0.6", + "import-fresh": "^3.2.1", + "js-yaml": "^3.13.1", + "minimatch": "^3.0.4", + "strip-json-comments": "^3.1.1" + }, + "engines": { + "node": "^10.12.0 || >=12.0.0" + } + }, + "node_modules/@eslint/eslintrc/node_modules/argparse": { + "version": "1.0.10", + "resolved": "https://registry.npmjs.org/argparse/-/argparse-1.0.10.tgz", + "integrity": "sha512-o5Roy6tNG4SL/FOkCAN6RzjiakZS25RLYFrcMttJqbdd8BWrnA+fGz57iN5Pb06pvBGvl5gQ0B48dJlslXvoTg==", + "dev": true, + "dependencies": { + "sprintf-js": "~1.0.2" + } + }, + "node_modules/@eslint/eslintrc/node_modules/debug": { + "version": "4.3.1", + "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.1.tgz", + "integrity": "sha512-doEwdvm4PCeK4K3RQN2ZC2BYUBaxwLARCqZmMjtF8a51J2Rb0xpVloFRnCODwqjpwnAoao4pelN8l3RJdv3gRQ==", + "dev": true, + "dependencies": { + "ms": "2.1.2" + }, + "engines": { + "node": ">=6.0" + }, + "peerDependenciesMeta": { + "supports-color": { + "optional": true + } + } + }, + "node_modules/@eslint/eslintrc/node_modules/js-yaml": { + "version": "3.14.1", + "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-3.14.1.tgz", + "integrity": "sha512-okMH7OXXJ7YrN9Ok3/SXrnu4iX9yOk+25nqX4imS2npuvTYDmo/QEZoqwZkYaIDk3jVvBOTOIEgEhaLOynBS9g==", + "dev": true, + "dependencies": { + "argparse": "^1.0.7", + "esprima": "^4.0.0" + }, + "bin": { + "js-yaml": "bin/js-yaml.js" + } + }, + "node_modules/@eslint/eslintrc/node_modules/ms": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz", + "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==", + "dev": true + }, + "node_modules/@eslint/eslintrc/node_modules/strip-json-comments": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/strip-json-comments/-/strip-json-comments-3.1.1.tgz", + "integrity": "sha512-6fPc+R4ihwqP6N/aIv2f1gMH8lOVtWQHoqC4yK6oSDVVocumAsfCqjkXnqiYMhmMwS/mEHLp7Vehlt3ql6lEig==", + "dev": true, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/@humanwhocodes/config-array": { + "version": "0.5.0", + "resolved": "https://registry.npmjs.org/@humanwhocodes/config-array/-/config-array-0.5.0.tgz", + "integrity": "sha512-FagtKFz74XrTl7y6HCzQpwDfXP0yhxe9lHLD1UZxjvZIcbyRz8zTFF/yYNfSfzU414eDwZ1SrO0Qvtyf+wFMQg==", + "dev": true, + "dependencies": { + "@humanwhocodes/object-schema": "^1.2.0", + "debug": "^4.1.1", + "minimatch": "^3.0.4" + }, + "engines": { + "node": ">=10.10.0" + } + }, + "node_modules/@humanwhocodes/config-array/node_modules/debug": { + "version": "4.3.1", + "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.1.tgz", + "integrity": "sha512-doEwdvm4PCeK4K3RQN2ZC2BYUBaxwLARCqZmMjtF8a51J2Rb0xpVloFRnCODwqjpwnAoao4pelN8l3RJdv3gRQ==", + "dev": true, + "dependencies": { + "ms": "2.1.2" + }, + "engines": { + "node": ">=6.0" + }, + "peerDependenciesMeta": { + "supports-color": { + "optional": true + } + } + }, + "node_modules/@humanwhocodes/config-array/node_modules/ms": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz", + "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==", + "dev": true + }, + "node_modules/@humanwhocodes/object-schema": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/@humanwhocodes/object-schema/-/object-schema-1.2.0.tgz", + "integrity": "sha512-wdppn25U8z/2yiaT6YGquE6X8sSv7hNMWSXYSSU1jGv/yd6XqjXgTDJ8KP4NgjTXfJ3GbRjeeb8RTV7a/VpM+w==", + "dev": true + }, + "node_modules/@nodelib/fs.scandir": { + "version": "2.1.5", + "resolved": "https://registry.npmjs.org/@nodelib/fs.scandir/-/fs.scandir-2.1.5.tgz", + "integrity": "sha512-vq24Bq3ym5HEQm2NKCr3yXDwjc7vTsEThRDnkp2DK9p1uqLR+DHurm/NOTo0KG7HYHU7eppKZj3MyqYuMBf62g==", + "dev": true, + "dependencies": { + "@nodelib/fs.stat": "2.0.5", + "run-parallel": "^1.1.9" + }, + "engines": { + "node": ">= 8" + } + }, + "node_modules/@nodelib/fs.stat": { + "version": "2.0.5", + "resolved": "https://registry.npmjs.org/@nodelib/fs.stat/-/fs.stat-2.0.5.tgz", + "integrity": "sha512-RkhPPp2zrqDAQA/2jNhnztcPAlv64XdhIp7a7454A5ovI7Bukxgt7MX7udwAu3zg1DcpPU0rz3VV1SeaqvY4+A==", + "dev": true, + "engines": { + "node": ">= 8" + } + }, + "node_modules/@nodelib/fs.walk": { + "version": "1.2.7", + "resolved": "https://registry.npmjs.org/@nodelib/fs.walk/-/fs.walk-1.2.7.tgz", + "integrity": "sha512-BTIhocbPBSrRmHxOAJFtR18oLhxTtAFDAvL8hY1S3iU8k+E60W/YFs4jrixGzQjMpF4qPXxIQHcjVD9dz1C2QA==", + "dev": true, + "dependencies": { + "@nodelib/fs.scandir": "2.1.5", + "fastq": "^1.6.0" + }, + "engines": { + "node": ">= 8" + } + }, "node_modules/@sinonjs/commons": { "version": "1.8.1", "resolved": "https://registry.npmjs.org/@sinonjs/commons/-/commons-1.8.1.tgz", @@ -173,6 +401,12 @@ "integrity": "sha512-DmZDpSVnsuBrOhtHwE1oKmUJ3qVjHhhNQ7WnZy9/RhH3A24Ar+9o4SoaCWcTzQhalpRDIAMsfdoZLWNJtdBR7A==", "dev": true }, + "node_modules/@types/json-schema": { + "version": "7.0.7", + "resolved": "https://registry.npmjs.org/@types/json-schema/-/json-schema-7.0.7.tgz", + "integrity": "sha512-cxWFQVseBm6O9Gbw1IWb8r6OS4OhSt3hPZLkFApLjM8TEXROBuQGLAH2i2gZpcXdLBIrpXuTDhH7Vbm1iXmNGA==", + "dev": true + }, "node_modules/@types/mime": { "version": "2.0.3", "resolved": "https://registry.npmjs.org/@types/mime/-/mime-2.0.3.tgz", @@ -275,6 +509,303 @@ "integrity": "sha512-I99sngh224D0M7XgW1s120zxCt3VYQ3IQsuw3P3jbq5GG4yc79+ZjyKznyOGIQrflfylLgcfekeZW/vk0yng6A==", "dev": true }, + "node_modules/@typescript-eslint/eslint-plugin": { + "version": "4.28.1", + "resolved": "https://registry.npmjs.org/@typescript-eslint/eslint-plugin/-/eslint-plugin-4.28.1.tgz", + "integrity": "sha512-9yfcNpDaNGQ6/LQOX/KhUFTR1sCKH+PBr234k6hI9XJ0VP5UqGxap0AnNwBnWFk1MNyWBylJH9ZkzBXC+5akZQ==", + "dev": true, + "dependencies": { + "@typescript-eslint/experimental-utils": "4.28.1", + "@typescript-eslint/scope-manager": "4.28.1", + "debug": "^4.3.1", + "functional-red-black-tree": "^1.0.1", + "regexpp": "^3.1.0", + "semver": "^7.3.5", + "tsutils": "^3.21.0" + }, + "engines": { + "node": "^10.12.0 || >=12.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + }, + "peerDependencies": { + "@typescript-eslint/parser": "^4.0.0", + "eslint": "^5.0.0 || ^6.0.0 || ^7.0.0" + }, + "peerDependenciesMeta": { + "typescript": { + "optional": true + } + } + }, + "node_modules/@typescript-eslint/eslint-plugin/node_modules/debug": { + "version": "4.3.1", + "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.1.tgz", + "integrity": "sha512-doEwdvm4PCeK4K3RQN2ZC2BYUBaxwLARCqZmMjtF8a51J2Rb0xpVloFRnCODwqjpwnAoao4pelN8l3RJdv3gRQ==", + "dev": true, + "dependencies": { + "ms": "2.1.2" + }, + "engines": { + "node": ">=6.0" + }, + "peerDependenciesMeta": { + "supports-color": { + "optional": true + } + } + }, + "node_modules/@typescript-eslint/eslint-plugin/node_modules/lru-cache": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-6.0.0.tgz", + "integrity": "sha512-Jo6dJ04CmSjuznwJSS3pUeWmd/H0ffTlkXXgwZi+eq1UCmqQwCh+eLsYOYCwY991i2Fah4h1BEMCx4qThGbsiA==", + "dev": true, + "dependencies": { + "yallist": "^4.0.0" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/@typescript-eslint/eslint-plugin/node_modules/ms": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz", + "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==", + "dev": true + }, + "node_modules/@typescript-eslint/eslint-plugin/node_modules/semver": { + "version": "7.3.5", + "resolved": "https://registry.npmjs.org/semver/-/semver-7.3.5.tgz", + "integrity": "sha512-PoeGJYh8HK4BTO/a9Tf6ZG3veo/A7ZVsYrSA6J8ny9nb3B1VrpkuN+z9OE5wfE5p6H4LchYZsegiQgbJD94ZFQ==", + "dev": true, + "dependencies": { + "lru-cache": "^6.0.0" + }, + "bin": { + "semver": "bin/semver.js" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/@typescript-eslint/experimental-utils": { + "version": "4.28.1", + "resolved": "https://registry.npmjs.org/@typescript-eslint/experimental-utils/-/experimental-utils-4.28.1.tgz", + "integrity": "sha512-n8/ggadrZ+uyrfrSEchx3jgODdmcx7MzVM2sI3cTpI/YlfSm0+9HEUaWw3aQn2urL2KYlWYMDgn45iLfjDYB+Q==", + "dev": true, + "dependencies": { + "@types/json-schema": "^7.0.7", + "@typescript-eslint/scope-manager": "4.28.1", + "@typescript-eslint/types": "4.28.1", + "@typescript-eslint/typescript-estree": "4.28.1", + "eslint-scope": "^5.1.1", + "eslint-utils": "^3.0.0" + }, + "engines": { + "node": "^10.12.0 || >=12.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + }, + "peerDependencies": { + "eslint": "*" + } + }, + "node_modules/@typescript-eslint/experimental-utils/node_modules/eslint-utils": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/eslint-utils/-/eslint-utils-3.0.0.tgz", + "integrity": "sha512-uuQC43IGctw68pJA1RgbQS8/NP7rch6Cwd4j3ZBtgo4/8Flj4eGE7ZYSZRN3iq5pVUv6GPdW5Z1RFleo84uLDA==", + "dev": true, + "dependencies": { + "eslint-visitor-keys": "^2.0.0" + }, + "engines": { + "node": "^10.0.0 || ^12.0.0 || >= 14.0.0" + }, + "funding": { + "url": "https://github.com/sponsors/mysticatea" + }, + "peerDependencies": { + "eslint": ">=5" + } + }, + "node_modules/@typescript-eslint/parser": { + "version": "4.28.1", + "resolved": "https://registry.npmjs.org/@typescript-eslint/parser/-/parser-4.28.1.tgz", + "integrity": "sha512-UjrMsgnhQIIK82hXGaD+MCN8IfORS1CbMdu7VlZbYa8LCZtbZjJA26De4IPQB7XYZbL8gJ99KWNj0l6WD0guJg==", + "dev": true, + "dependencies": { + "@typescript-eslint/scope-manager": "4.28.1", + "@typescript-eslint/types": "4.28.1", + "@typescript-eslint/typescript-estree": "4.28.1", + "debug": "^4.3.1" + }, + "engines": { + "node": "^10.12.0 || >=12.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + }, + "peerDependencies": { + "eslint": "^5.0.0 || ^6.0.0 || ^7.0.0" + }, + "peerDependenciesMeta": { + "typescript": { + "optional": true + } + } + }, + "node_modules/@typescript-eslint/parser/node_modules/debug": { + "version": "4.3.1", + "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.1.tgz", + "integrity": "sha512-doEwdvm4PCeK4K3RQN2ZC2BYUBaxwLARCqZmMjtF8a51J2Rb0xpVloFRnCODwqjpwnAoao4pelN8l3RJdv3gRQ==", + "dev": true, + "dependencies": { + "ms": "2.1.2" + }, + "engines": { + "node": ">=6.0" + }, + "peerDependenciesMeta": { + "supports-color": { + "optional": true + } + } + }, + "node_modules/@typescript-eslint/parser/node_modules/ms": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz", + "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==", + "dev": true + }, + "node_modules/@typescript-eslint/scope-manager": { + "version": "4.28.1", + "resolved": "https://registry.npmjs.org/@typescript-eslint/scope-manager/-/scope-manager-4.28.1.tgz", + "integrity": "sha512-o95bvGKfss6705x7jFGDyS7trAORTy57lwJ+VsYwil/lOUxKQ9tA7Suuq+ciMhJc/1qPwB3XE2DKh9wubW8YYA==", + "dev": true, + "dependencies": { + "@typescript-eslint/types": "4.28.1", + "@typescript-eslint/visitor-keys": "4.28.1" + }, + "engines": { + "node": "^8.10.0 || ^10.13.0 || >=11.10.1" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + } + }, + "node_modules/@typescript-eslint/types": { + "version": "4.28.1", + "resolved": "https://registry.npmjs.org/@typescript-eslint/types/-/types-4.28.1.tgz", + "integrity": "sha512-4z+knEihcyX7blAGi7O3Fm3O6YRCP+r56NJFMNGsmtdw+NCdpG5SgNz427LS9nQkRVTswZLhz484hakQwB8RRg==", + "dev": true, + "engines": { + "node": "^8.10.0 || ^10.13.0 || >=11.10.1" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + } + }, + "node_modules/@typescript-eslint/typescript-estree": { + "version": "4.28.1", + "resolved": "https://registry.npmjs.org/@typescript-eslint/typescript-estree/-/typescript-estree-4.28.1.tgz", + "integrity": "sha512-GhKxmC4sHXxHGJv8e8egAZeTZ6HI4mLU6S7FUzvFOtsk7ZIDN1ksA9r9DyOgNqowA9yAtZXV0Uiap61bIO81FQ==", + "dev": true, + "dependencies": { + "@typescript-eslint/types": "4.28.1", + "@typescript-eslint/visitor-keys": "4.28.1", + "debug": "^4.3.1", + "globby": "^11.0.3", + "is-glob": "^4.0.1", + "semver": "^7.3.5", + "tsutils": "^3.21.0" + }, + "engines": { + "node": "^10.12.0 || >=12.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + }, + "peerDependenciesMeta": { + "typescript": { + "optional": true + } + } + }, + "node_modules/@typescript-eslint/typescript-estree/node_modules/debug": { + "version": "4.3.1", + "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.1.tgz", + "integrity": "sha512-doEwdvm4PCeK4K3RQN2ZC2BYUBaxwLARCqZmMjtF8a51J2Rb0xpVloFRnCODwqjpwnAoao4pelN8l3RJdv3gRQ==", + "dev": true, + "dependencies": { + "ms": "2.1.2" + }, + "engines": { + "node": ">=6.0" + }, + "peerDependenciesMeta": { + "supports-color": { + "optional": true + } + } + }, + "node_modules/@typescript-eslint/typescript-estree/node_modules/lru-cache": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-6.0.0.tgz", + "integrity": "sha512-Jo6dJ04CmSjuznwJSS3pUeWmd/H0ffTlkXXgwZi+eq1UCmqQwCh+eLsYOYCwY991i2Fah4h1BEMCx4qThGbsiA==", + "dev": true, + "dependencies": { + "yallist": "^4.0.0" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/@typescript-eslint/typescript-estree/node_modules/ms": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz", + "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==", + "dev": true + }, + "node_modules/@typescript-eslint/typescript-estree/node_modules/semver": { + "version": "7.3.5", + "resolved": "https://registry.npmjs.org/semver/-/semver-7.3.5.tgz", + "integrity": "sha512-PoeGJYh8HK4BTO/a9Tf6ZG3veo/A7ZVsYrSA6J8ny9nb3B1VrpkuN+z9OE5wfE5p6H4LchYZsegiQgbJD94ZFQ==", + "dev": true, + "dependencies": { + "lru-cache": "^6.0.0" + }, + "bin": { + "semver": "bin/semver.js" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/@typescript-eslint/visitor-keys": { + "version": "4.28.1", + "resolved": "https://registry.npmjs.org/@typescript-eslint/visitor-keys/-/visitor-keys-4.28.1.tgz", + "integrity": "sha512-K4HMrdFqr9PFquPu178SaSb92CaWe2yErXyPumc8cYWxFmhgJsNY9eSePmO05j0JhBvf2Cdhptd6E6Yv9HVHcg==", + "dev": true, + "dependencies": { + "@typescript-eslint/types": "4.28.1", + "eslint-visitor-keys": "^2.0.0" + }, + "engines": { + "node": "^8.10.0 || ^10.13.0 || >=11.10.1" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + } + }, "node_modules/@ungap/promise-all-settled": { "version": "1.1.2", "resolved": "https://registry.npmjs.org/@ungap/promise-all-settled/-/promise-all-settled-1.1.2.tgz", @@ -310,6 +841,43 @@ "node": ">= 0.6" } }, + "node_modules/acorn": { + "version": "7.4.1", + "resolved": "https://registry.npmjs.org/acorn/-/acorn-7.4.1.tgz", + "integrity": "sha512-nQyp0o1/mNdbTO1PO6kHkwSrmgZ0MT/jCCpNiwbUjGoRN4dlBhqJtoQuCnEOKzgTVwg0ZWiCoQy6SxMebQVh8A==", + "dev": true, + "bin": { + "acorn": "bin/acorn" + }, + "engines": { + "node": ">=0.4.0" + } + }, + "node_modules/acorn-jsx": { + "version": "5.3.1", + "resolved": "https://registry.npmjs.org/acorn-jsx/-/acorn-jsx-5.3.1.tgz", + "integrity": "sha512-K0Ptm/47OKfQRpNQ2J/oIN/3QYiK6FwW+eJbILhsdxh2WTLdl+30o8aGdTbm5JbffpFFAg/g+zi1E+jvJha5ng==", + "dev": true, + "peerDependencies": { + "acorn": "^6.0.0 || ^7.0.0 || ^8.0.0" + } + }, + "node_modules/ajv": { + "version": "6.12.6", + "resolved": "https://registry.npmjs.org/ajv/-/ajv-6.12.6.tgz", + "integrity": "sha512-j3fVLgvTo527anyYyJOGTYJbG+vnnQYvE0m5mmkc1TK+nxAppkCLMIL0aZ4dblVCNoGShhm+kzE4ZUykBoMg4g==", + "dev": true, + "dependencies": { + "fast-deep-equal": "^3.1.1", + "fast-json-stable-stringify": "^2.0.0", + "json-schema-traverse": "^0.4.1", + "uri-js": "^4.2.2" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/epoberezkin" + } + }, "node_modules/ansi-align": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/ansi-align/-/ansi-align-2.0.0.tgz", @@ -445,11 +1013,29 @@ "resolved": "https://registry.npmjs.org/array-flatten/-/array-flatten-1.1.1.tgz", "integrity": "sha1-ml9pkFGx5wczKPKgCJaLZOopVdI=" }, + "node_modules/array-union": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/array-union/-/array-union-2.1.0.tgz", + "integrity": "sha512-HGyxoOTYUyCM6stUe6EJgnd4EoewAI7zMdfqO+kGjnlZmBDz/cR5pf8r/cR4Wq60sL/p0IkcjUEEPwS3GFrIyw==", + "dev": true, + "engines": { + "node": ">=8" + } + }, "node_modules/asap": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/asap/-/asap-1.0.0.tgz", "integrity": "sha1-sqRdpf36ILBJb8N2jMJ8EvqRan0=" }, + "node_modules/astral-regex": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/astral-regex/-/astral-regex-2.0.0.tgz", + "integrity": "sha512-Z7tMw1ytTXt5jqMcOP+OQteU1VuNK9Y02uuJtKQ1Sv69jXQKKg5cibLwGJow8yzZP+eAc18EmLGPal0bp36rvQ==", + "dev": true, + "engines": { + "node": ">=8" + } + }, "node_modules/asynckit": { "version": "0.4.0", "resolved": "https://registry.npmjs.org/asynckit/-/asynckit-0.4.0.tgz", @@ -698,6 +1284,15 @@ "node": ">= 0.8" } }, + "node_modules/callsites": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/callsites/-/callsites-3.1.0.tgz", + "integrity": "sha512-P8BjAsXvZS+VIDUI11hHCQEv74YT67YUi5JJFNWIqL235sBmjX4+qx9Muvls5ivyNENctx46xQLQ3aTuE7ssaQ==", + "dev": true, + "engines": { + "node": ">=6" + } + }, "node_modules/camelcase": { "version": "6.2.0", "resolved": "https://registry.npmjs.org/camelcase/-/camelcase-6.2.0.tgz", @@ -1022,6 +1617,12 @@ "node": ">=4.0.0" } }, + "node_modules/deep-is": { + "version": "0.1.3", + "resolved": "https://registry.npmjs.org/deep-is/-/deep-is-0.1.3.tgz", + "integrity": "sha1-s2nW+128E+7PUk+RsHD+7cNXzzQ=", + "dev": true + }, "node_modules/delayed-stream": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/delayed-stream/-/delayed-stream-1.0.0.tgz", @@ -1077,6 +1678,30 @@ "node": ">=0.3.1" } }, + "node_modules/dir-glob": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/dir-glob/-/dir-glob-3.0.1.tgz", + "integrity": "sha512-WkrWp9GR4KXfKGYzOLmTuGVi1UWFfws377n9cc55/tb6DuqyF6pcQ5AbiHEshaDpY9v6oaSr2XCDidGmMwdzIA==", + "dev": true, + "dependencies": { + "path-type": "^4.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/doctrine": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/doctrine/-/doctrine-3.0.0.tgz", + "integrity": "sha512-yS+Q5i3hBf7GBkd4KG8a7eBNNWNGLTaEwwYWUijIYM7zrlYDM0BFXHjjPWlWZ1Rg7UaddZeIDmi9jF3HmqiQ2w==", + "dev": true, + "dependencies": { + "esutils": "^2.0.2" + }, + "engines": { + "node": ">=6.0.0" + } + }, "node_modules/dot-prop": { "version": "4.2.1", "resolved": "https://registry.npmjs.org/dot-prop/-/dot-prop-4.2.1.tgz", @@ -1130,6 +1755,18 @@ "once": "^1.4.0" } }, + "node_modules/enquirer": { + "version": "2.3.6", + "resolved": "https://registry.npmjs.org/enquirer/-/enquirer-2.3.6.tgz", + "integrity": "sha512-yjNnPr315/FjS4zIsUxYguYUPP2e1NK4d7E7ZOLiyYCcbFBiTMyID+2wvm2w6+pZ/odMA7cRkjhsPbltwBOrLg==", + "dev": true, + "dependencies": { + "ansi-colors": "^4.1.1" + }, + "engines": { + "node": ">=8.6" + } + }, "node_modules/escalade": { "version": "3.1.1", "resolved": "https://registry.npmjs.org/escalade/-/escalade-3.1.1.tgz", @@ -1153,6 +1790,381 @@ "node": ">=0.8.0" } }, + "node_modules/eslint": { + "version": "7.30.0", + "resolved": "https://registry.npmjs.org/eslint/-/eslint-7.30.0.tgz", + "integrity": "sha512-VLqz80i3as3NdloY44BQSJpFw534L9Oh+6zJOUaViV4JPd+DaHwutqP7tcpkW3YiXbK6s05RZl7yl7cQn+lijg==", + "dev": true, + "dependencies": { + "@babel/code-frame": "7.12.11", + "@eslint/eslintrc": "^0.4.2", + "@humanwhocodes/config-array": "^0.5.0", + "ajv": "^6.10.0", + "chalk": "^4.0.0", + "cross-spawn": "^7.0.2", + "debug": "^4.0.1", + "doctrine": "^3.0.0", + "enquirer": "^2.3.5", + "escape-string-regexp": "^4.0.0", + "eslint-scope": "^5.1.1", + "eslint-utils": "^2.1.0", + "eslint-visitor-keys": "^2.0.0", + "espree": "^7.3.1", + "esquery": "^1.4.0", + "esutils": "^2.0.2", + "fast-deep-equal": "^3.1.3", + "file-entry-cache": "^6.0.1", + "functional-red-black-tree": "^1.0.1", + "glob-parent": "^5.1.2", + "globals": "^13.6.0", + "ignore": "^4.0.6", + "import-fresh": "^3.0.0", + "imurmurhash": "^0.1.4", + "is-glob": "^4.0.0", + "js-yaml": "^3.13.1", + "json-stable-stringify-without-jsonify": "^1.0.1", + "levn": "^0.4.1", + "lodash.merge": "^4.6.2", + "minimatch": "^3.0.4", + "natural-compare": "^1.4.0", + "optionator": "^0.9.1", + "progress": "^2.0.0", + "regexpp": "^3.1.0", + "semver": "^7.2.1", + "strip-ansi": "^6.0.0", + "strip-json-comments": "^3.1.0", + "table": "^6.0.9", + "text-table": "^0.2.0", + "v8-compile-cache": "^2.0.3" + }, + "bin": { + "eslint": "bin/eslint.js" + }, + "engines": { + "node": "^10.12.0 || >=12.0.0" + }, + "funding": { + "url": "https://opencollective.com/eslint" + } + }, + "node_modules/eslint-scope": { + "version": "5.1.1", + "resolved": "https://registry.npmjs.org/eslint-scope/-/eslint-scope-5.1.1.tgz", + "integrity": "sha512-2NxwbF/hZ0KpepYN0cNbo+FN6XoK7GaHlQhgx/hIZl6Va0bF45RQOOwhLIy8lQDbuCiadSLCBnH2CFYquit5bw==", + "dev": true, + "dependencies": { + "esrecurse": "^4.3.0", + "estraverse": "^4.1.1" + }, + "engines": { + "node": ">=8.0.0" + } + }, + "node_modules/eslint-utils": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/eslint-utils/-/eslint-utils-2.1.0.tgz", + "integrity": "sha512-w94dQYoauyvlDc43XnGB8lU3Zt713vNChgt4EWwhXAP2XkBvndfxF0AgIqKOOasjPIPzj9JqgwkwbCYD0/V3Zg==", + "dev": true, + "dependencies": { + "eslint-visitor-keys": "^1.1.0" + }, + "engines": { + "node": ">=6" + }, + "funding": { + "url": "https://github.com/sponsors/mysticatea" + } + }, + "node_modules/eslint-utils/node_modules/eslint-visitor-keys": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-1.3.0.tgz", + "integrity": "sha512-6J72N8UNa462wa/KFODt/PJ3IU60SDpC3QXC1Hjc1BXXpfL2C9R5+AU7jhe0F6GREqVMh4Juu+NY7xn+6dipUQ==", + "dev": true, + "engines": { + "node": ">=4" + } + }, + "node_modules/eslint-visitor-keys": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-2.1.0.tgz", + "integrity": "sha512-0rSmRBzXgDzIsD6mGdJgevzgezI534Cer5L/vyMX0kHzT/jiB43jRhd9YUlMGYLQy2zprNmoT8qasCGtY+QaKw==", + "dev": true, + "engines": { + "node": ">=10" + } + }, + "node_modules/eslint/node_modules/ansi-regex": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.0.tgz", + "integrity": "sha512-bY6fj56OUQ0hU1KjFNDQuJFezqKdrAyFdIevADiqrWHwSlbmBNMHp5ak2f40Pm8JTFyM2mqxkG6ngkHO11f/lg==", + "dev": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/eslint/node_modules/argparse": { + "version": "1.0.10", + "resolved": "https://registry.npmjs.org/argparse/-/argparse-1.0.10.tgz", + "integrity": "sha512-o5Roy6tNG4SL/FOkCAN6RzjiakZS25RLYFrcMttJqbdd8BWrnA+fGz57iN5Pb06pvBGvl5gQ0B48dJlslXvoTg==", + "dev": true, + "dependencies": { + "sprintf-js": "~1.0.2" + } + }, + "node_modules/eslint/node_modules/cross-spawn": { + "version": "7.0.3", + "resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-7.0.3.tgz", + "integrity": "sha512-iRDPJKUPVEND7dHPO8rkbOnPpyDygcDFtWjpeWNCgy8WP2rXcxXL8TskReQl6OrB2G7+UJrags1q15Fudc7G6w==", + "dev": true, + "dependencies": { + "path-key": "^3.1.0", + "shebang-command": "^2.0.0", + "which": "^2.0.1" + }, + "engines": { + "node": ">= 8" + } + }, + "node_modules/eslint/node_modules/debug": { + "version": "4.3.1", + "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.1.tgz", + "integrity": "sha512-doEwdvm4PCeK4K3RQN2ZC2BYUBaxwLARCqZmMjtF8a51J2Rb0xpVloFRnCODwqjpwnAoao4pelN8l3RJdv3gRQ==", + "dev": true, + "dependencies": { + "ms": "2.1.2" + }, + "engines": { + "node": ">=6.0" + }, + "peerDependenciesMeta": { + "supports-color": { + "optional": true + } + } + }, + "node_modules/eslint/node_modules/escape-string-regexp": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-4.0.0.tgz", + "integrity": "sha512-TtpcNJ3XAzx3Gq8sWRzJaVajRs0uVxA2YAkdb1jm2YkPz4G6egUFAyA3n5vtEIZefPk5Wa4UXbKuS5fKkJWdgA==", + "dev": true, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/eslint/node_modules/js-yaml": { + "version": "3.14.1", + "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-3.14.1.tgz", + "integrity": "sha512-okMH7OXXJ7YrN9Ok3/SXrnu4iX9yOk+25nqX4imS2npuvTYDmo/QEZoqwZkYaIDk3jVvBOTOIEgEhaLOynBS9g==", + "dev": true, + "dependencies": { + "argparse": "^1.0.7", + "esprima": "^4.0.0" + }, + "bin": { + "js-yaml": "bin/js-yaml.js" + } + }, + "node_modules/eslint/node_modules/lru-cache": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-6.0.0.tgz", + "integrity": "sha512-Jo6dJ04CmSjuznwJSS3pUeWmd/H0ffTlkXXgwZi+eq1UCmqQwCh+eLsYOYCwY991i2Fah4h1BEMCx4qThGbsiA==", + "dev": true, + "dependencies": { + "yallist": "^4.0.0" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/eslint/node_modules/ms": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz", + "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==", + "dev": true + }, + "node_modules/eslint/node_modules/path-key": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/path-key/-/path-key-3.1.1.tgz", + "integrity": "sha512-ojmeN0qd+y0jszEtoY48r0Peq5dwMEkIlCOu6Q5f41lfkswXuKtYrhgoTpLnyIcHm24Uhqx+5Tqm2InSwLhE6Q==", + "dev": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/eslint/node_modules/semver": { + "version": "7.3.5", + "resolved": "https://registry.npmjs.org/semver/-/semver-7.3.5.tgz", + "integrity": "sha512-PoeGJYh8HK4BTO/a9Tf6ZG3veo/A7ZVsYrSA6J8ny9nb3B1VrpkuN+z9OE5wfE5p6H4LchYZsegiQgbJD94ZFQ==", + "dev": true, + "dependencies": { + "lru-cache": "^6.0.0" + }, + "bin": { + "semver": "bin/semver.js" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/eslint/node_modules/shebang-command": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/shebang-command/-/shebang-command-2.0.0.tgz", + "integrity": "sha512-kHxr2zZpYtdmrN1qDjrrX/Z1rR1kG8Dx+gkpK1G4eXmvXswmcE1hTWBWYUzlraYw1/yZp6YuDY77YtvbN0dmDA==", + "dev": true, + "dependencies": { + "shebang-regex": "^3.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/eslint/node_modules/shebang-regex": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/shebang-regex/-/shebang-regex-3.0.0.tgz", + "integrity": "sha512-7++dFhtcx3353uBaq8DDR4NuxBetBzC7ZQOhmTQInHEd6bSrXdiEyzCvG07Z44UYdLShWUyXt5M/yhz8ekcb1A==", + "dev": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/eslint/node_modules/strip-ansi": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.0.tgz", + "integrity": "sha512-AuvKTrTfQNYNIctbR1K/YGTR1756GycPsg7b9bdV9Duqur4gv6aKqHXah67Z8ImS7WEz5QVcOtlfW2rZEugt6w==", + "dev": true, + "dependencies": { + "ansi-regex": "^5.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/eslint/node_modules/strip-json-comments": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/strip-json-comments/-/strip-json-comments-3.1.1.tgz", + "integrity": "sha512-6fPc+R4ihwqP6N/aIv2f1gMH8lOVtWQHoqC4yK6oSDVVocumAsfCqjkXnqiYMhmMwS/mEHLp7Vehlt3ql6lEig==", + "dev": true, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/eslint/node_modules/which": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/which/-/which-2.0.2.tgz", + "integrity": "sha512-BLI3Tl1TW3Pvl70l3yq3Y64i+awpwXqsGBYWkkqMtnbXgrMD+yj7rhW0kuEDxzJaYXGjEW5ogapKNMEKNMjibA==", + "dev": true, + "dependencies": { + "isexe": "^2.0.0" + }, + "bin": { + "node-which": "bin/node-which" + }, + "engines": { + "node": ">= 8" + } + }, + "node_modules/espree": { + "version": "7.3.1", + "resolved": "https://registry.npmjs.org/espree/-/espree-7.3.1.tgz", + "integrity": "sha512-v3JCNCE64umkFpmkFGqzVKsOT0tN1Zr+ueqLZfpV1Ob8e+CEgPWa+OxCoGH3tnhimMKIaBm4m/vaRpJ/krRz2g==", + "dev": true, + "dependencies": { + "acorn": "^7.4.0", + "acorn-jsx": "^5.3.1", + "eslint-visitor-keys": "^1.3.0" + }, + "engines": { + "node": "^10.12.0 || >=12.0.0" + } + }, + "node_modules/espree/node_modules/eslint-visitor-keys": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-1.3.0.tgz", + "integrity": "sha512-6J72N8UNa462wa/KFODt/PJ3IU60SDpC3QXC1Hjc1BXXpfL2C9R5+AU7jhe0F6GREqVMh4Juu+NY7xn+6dipUQ==", + "dev": true, + "engines": { + "node": ">=4" + } + }, + "node_modules/esprima": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/esprima/-/esprima-4.0.1.tgz", + "integrity": "sha512-eGuFFw7Upda+g4p+QHvnW0RyTX/SVeJBDM/gCtMARO0cLuT2HcEKnTPvhjV6aGeqrCB/sbNop0Kszm0jsaWU4A==", + "dev": true, + "bin": { + "esparse": "bin/esparse.js", + "esvalidate": "bin/esvalidate.js" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/esquery": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/esquery/-/esquery-1.4.0.tgz", + "integrity": "sha512-cCDispWt5vHHtwMY2YrAQ4ibFkAL8RbH5YGBnZBc90MolvvfkkQcJro/aZiAQUlQ3qgrYS6D6v8Gc5G5CQsc9w==", + "dev": true, + "dependencies": { + "estraverse": "^5.1.0" + }, + "engines": { + "node": ">=0.10" + } + }, + "node_modules/esquery/node_modules/estraverse": { + "version": "5.2.0", + "resolved": "https://registry.npmjs.org/estraverse/-/estraverse-5.2.0.tgz", + "integrity": "sha512-BxbNGGNm0RyRYvUdHpIwv9IWzeM9XClbOxwoATuFdOE7ZE6wHL+HQ5T8hoPM+zHvmKzzsEqhgy0GrQ5X13afiQ==", + "dev": true, + "engines": { + "node": ">=4.0" + } + }, + "node_modules/esrecurse": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/esrecurse/-/esrecurse-4.3.0.tgz", + "integrity": "sha512-KmfKL3b6G+RXvP8N1vr3Tq1kL/oCFgn2NYXEtqP8/L3pKapUA4G8cFVaoF3SU323CD4XypR/ffioHmkti6/Tag==", + "dev": true, + "dependencies": { + "estraverse": "^5.2.0" + }, + "engines": { + "node": ">=4.0" + } + }, + "node_modules/esrecurse/node_modules/estraverse": { + "version": "5.2.0", + "resolved": "https://registry.npmjs.org/estraverse/-/estraverse-5.2.0.tgz", + "integrity": "sha512-BxbNGGNm0RyRYvUdHpIwv9IWzeM9XClbOxwoATuFdOE7ZE6wHL+HQ5T8hoPM+zHvmKzzsEqhgy0GrQ5X13afiQ==", + "dev": true, + "engines": { + "node": ">=4.0" + } + }, + "node_modules/estraverse": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/estraverse/-/estraverse-4.3.0.tgz", + "integrity": "sha512-39nnKffWz8xN1BU/2c79n9nB9HDzo0niYUqx6xyqUnyoAnQyyWpOTdZEeiCch8BBu515t4wp9ZmgVfVhn9EBpw==", + "dev": true, + "engines": { + "node": ">=4.0" + } + }, + "node_modules/esutils": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/esutils/-/esutils-2.0.3.tgz", + "integrity": "sha512-kVscqXk4OCp68SZ0dkgEKVi6/8ij300KBWTJq32P/dYeWTSwK41WyTxalN1eRmA5Z9UU/LX9D7FWSmV9SAYx6g==", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, "node_modules/etag": { "version": "1.8.1", "resolved": "https://registry.npmjs.org/etag/-/etag-1.8.1.tgz", @@ -1267,6 +2279,61 @@ "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.1.2.tgz", "integrity": "sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g==" }, + "node_modules/fast-deep-equal": { + "version": "3.1.3", + "resolved": "https://registry.npmjs.org/fast-deep-equal/-/fast-deep-equal-3.1.3.tgz", + "integrity": "sha512-f3qQ9oQy9j2AhBe/H9VC91wLmKBCCU/gDOnKNAYG5hswO7BLKj09Hc5HYNz9cGI++xlpDCIgDaitVs03ATR84Q==", + "dev": true + }, + "node_modules/fast-glob": { + "version": "3.2.6", + "resolved": "https://registry.npmjs.org/fast-glob/-/fast-glob-3.2.6.tgz", + "integrity": "sha512-GnLuqj/pvQ7pX8/L4J84nijv6sAnlwvSDpMkJi9i7nPmPxGtRPkBSStfvDW5l6nMdX9VWe+pkKWFTgD+vF2QSQ==", + "dev": true, + "dependencies": { + "@nodelib/fs.stat": "^2.0.2", + "@nodelib/fs.walk": "^1.2.3", + "glob-parent": "^5.1.2", + "merge2": "^1.3.0", + "micromatch": "^4.0.4" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/fast-json-stable-stringify": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/fast-json-stable-stringify/-/fast-json-stable-stringify-2.1.0.tgz", + "integrity": "sha512-lhd/wF+Lk98HZoTCtlVraHtfh5XYijIjalXck7saUtuanSDyLMxnHhSXEDJqHxD7msR8D0uCmqlkwjCV8xvwHw==", + "dev": true + }, + "node_modules/fast-levenshtein": { + "version": "2.0.6", + "resolved": "https://registry.npmjs.org/fast-levenshtein/-/fast-levenshtein-2.0.6.tgz", + "integrity": "sha1-PYpcZog6FqMMqGQ+hR8Zuqd5eRc=", + "dev": true + }, + "node_modules/fastq": { + "version": "1.11.0", + "resolved": "https://registry.npmjs.org/fastq/-/fastq-1.11.0.tgz", + "integrity": "sha512-7Eczs8gIPDrVzT+EksYBcupqMyxSHXXrHOLRRxU2/DicV8789MRBRR8+Hc2uWzUupOs4YS4JzBmBxjjCVBxD/g==", + "dev": true, + "dependencies": { + "reusify": "^1.0.4" + } + }, + "node_modules/file-entry-cache": { + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/file-entry-cache/-/file-entry-cache-6.0.1.tgz", + "integrity": "sha512-7Gps/XWymbLk2QLYK4NzpMOrYjMhdIxXuIvy2QBsLE6ljuodKvdkWs/cpyJJ3CVIVpH0Oi1Hvg1ovbMzLdFBBg==", + "dev": true, + "dependencies": { + "flat-cache": "^3.0.4" + }, + "engines": { + "node": "^10.12.0 || >=12.0.0" + } + }, "node_modules/file-uri-to-path": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/file-uri-to-path/-/file-uri-to-path-1.0.0.tgz", @@ -1326,6 +2393,40 @@ "flat": "cli.js" } }, + "node_modules/flat-cache": { + "version": "3.0.4", + "resolved": "https://registry.npmjs.org/flat-cache/-/flat-cache-3.0.4.tgz", + "integrity": "sha512-dm9s5Pw7Jc0GvMYbshN6zchCA9RgQlzzEZX3vylR9IqFfS8XciblUXOKfW6SiuJ0e13eDYZoZV5wdrev7P3Nwg==", + "dev": true, + "dependencies": { + "flatted": "^3.1.0", + "rimraf": "^3.0.2" + }, + "engines": { + "node": "^10.12.0 || >=12.0.0" + } + }, + "node_modules/flat-cache/node_modules/rimraf": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/rimraf/-/rimraf-3.0.2.tgz", + "integrity": "sha512-JZkJMZkAGFFPP2YqXZXPbMlMBgsxzE8ILs4lMIX/2o0L9UBw9O/Y3o6wFw/i9YLapcUJWwqbi3kdxIPdC62TIA==", + "dev": true, + "dependencies": { + "glob": "^7.1.3" + }, + "bin": { + "rimraf": "bin.js" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, + "node_modules/flatted": { + "version": "3.2.0", + "resolved": "https://registry.npmjs.org/flatted/-/flatted-3.2.0.tgz", + "integrity": "sha512-XprP7lDrVT+kE2c2YlfiV+IfS9zxukiIOvNamPNsImNhXadSsQEbosItdL9bUQlCZXR13SvPk20BjWSWLA7m4A==", + "dev": true + }, "node_modules/form-data": { "version": "3.0.0", "resolved": "https://registry.npmjs.org/form-data/-/form-data-3.0.0.tgz", @@ -1411,6 +2512,12 @@ "length-stream": "^0.1.1" } }, + "node_modules/functional-red-black-tree": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/functional-red-black-tree/-/functional-red-black-tree-1.0.1.tgz", + "integrity": "sha1-GwqzvVU7Kg1jmdKcDj6gslIHgyc=", + "dev": true + }, "node_modules/gauge": { "version": "2.7.4", "resolved": "https://registry.npmjs.org/gauge/-/gauge-2.7.4.tgz", @@ -1501,9 +2608,9 @@ } }, "node_modules/glob-parent": { - "version": "5.1.1", - "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-5.1.1.tgz", - "integrity": "sha512-FnI+VGOpnlGHWZxthPGR+QhR78fuiK0sNLkHQv+bL9fQi57lNNdquIbna/WrfROrolq8GK5Ek6BiMwqL/voRYQ==", + "version": "5.1.2", + "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-5.1.2.tgz", + "integrity": "sha512-AOIgSQCepiJYwP3ARnGx+5VnTu2HBYdzbGP45eLw1vr3zB3vZLeyed1sC9hnbcOc9/SrMyM5RPQrkGz4aS9Zow==", "dev": true, "dependencies": { "is-glob": "^4.0.1" @@ -1524,6 +2631,50 @@ "node": ">=4" } }, + "node_modules/globals": { + "version": "13.9.0", + "resolved": "https://registry.npmjs.org/globals/-/globals-13.9.0.tgz", + "integrity": "sha512-74/FduwI/JaIrr1H8e71UbDE+5x7pIPs1C2rrwC52SszOo043CsWOZEMW7o2Y58xwm9b+0RBKDxY5n2sUpEFxA==", + "dev": true, + "dependencies": { + "type-fest": "^0.20.2" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/globby": { + "version": "11.0.4", + "resolved": "https://registry.npmjs.org/globby/-/globby-11.0.4.tgz", + "integrity": "sha512-9O4MVG9ioZJ08ffbcyVYyLOJLk5JQ688pJ4eMGLpdWLHq/Wr1D9BlriLQyL0E+jbkuePVZXYFj47QM/v093wHg==", + "dev": true, + "dependencies": { + "array-union": "^2.1.0", + "dir-glob": "^3.0.1", + "fast-glob": "^3.1.1", + "ignore": "^5.1.4", + "merge2": "^1.3.0", + "slash": "^3.0.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/globby/node_modules/ignore": { + "version": "5.1.8", + "resolved": "https://registry.npmjs.org/ignore/-/ignore-5.1.8.tgz", + "integrity": "sha512-BMpfD7PpiETpBl/A6S498BaIJ6Y/ABT93ETbby2fP00v4EbvPBXWEoaR1UBPKs3iR53pJY7EtZk5KACI57i1Uw==", + "dev": true, + "engines": { + "node": ">= 4" + } + }, "node_modules/got": { "version": "6.7.1", "resolved": "https://registry.npmjs.org/got/-/got-6.7.1.tgz", @@ -1633,12 +2784,37 @@ } ] }, + "node_modules/ignore": { + "version": "4.0.6", + "resolved": "https://registry.npmjs.org/ignore/-/ignore-4.0.6.tgz", + "integrity": "sha512-cyFDKrqc/YdcWFniJhzI42+AzS+gNwmUzOSFcRCQYwySuBBBy/KjuxWLZ/FHEH6Moq1NizMOBWyTcv8O4OZIMg==", + "dev": true, + "engines": { + "node": ">= 4" + } + }, "node_modules/ignore-by-default": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/ignore-by-default/-/ignore-by-default-1.0.1.tgz", "integrity": "sha1-SMptcvbGo68Aqa1K5odr44ieKwk=", "dev": true }, + "node_modules/import-fresh": { + "version": "3.3.0", + "resolved": "https://registry.npmjs.org/import-fresh/-/import-fresh-3.3.0.tgz", + "integrity": "sha512-veYYhQa+D1QBKznvhUHxb8faxlrwUnxseDAbAp457E0wLNio2bOSKnjYDhMj+YiAq61xrMGhQk9iXVk5FzgQMw==", + "dev": true, + "dependencies": { + "parent-module": "^1.0.0", + "resolve-from": "^4.0.0" + }, + "engines": { + "node": ">=6" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, "node_modules/import-lazy": { "version": "2.1.0", "resolved": "https://registry.npmjs.org/import-lazy/-/import-lazy-2.1.0.tgz", @@ -1847,6 +3023,12 @@ "resolved": "https://registry.npmjs.org/iso8601-duration/-/iso8601-duration-1.2.0.tgz", "integrity": "sha512-ErTBd++b17E8nmWII1K1uZtBgD1E8RjyvwmxlCjPHNqHMD7gmcMHOw0E8Ro/6+QT4PhHRSnnMo7bxa1vFPkwhg==" }, + "node_modules/js-tokens": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/js-tokens/-/js-tokens-4.0.0.tgz", + "integrity": "sha512-RdJUflcE3cUzKiMqQgsCu06FPu9UdIJO0beYbPhHN4k6apgJtifcoCtT9bcxOpYBtpD2kCM6Sbzg4CausW/PKQ==", + "dev": true + }, "node_modules/js-yaml": { "version": "4.0.0", "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-4.0.0.tgz", @@ -1859,6 +3041,18 @@ "js-yaml": "bin/js-yaml.js" } }, + "node_modules/json-schema-traverse": { + "version": "0.4.1", + "resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-0.4.1.tgz", + "integrity": "sha512-xbbCH5dCYU5T8LcEhhuh7HJ88HXuW3qsI3Y0zOZFKfZEHcpWiHU/Jxzk629Brsab/mMiHQti9wMP+845RPe3Vg==", + "dev": true + }, + "node_modules/json-stable-stringify-without-jsonify": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/json-stable-stringify-without-jsonify/-/json-stable-stringify-without-jsonify-1.0.1.tgz", + "integrity": "sha1-nbe1lJatPzz+8wp1FC0tkwrXJlE=", + "dev": true + }, "node_modules/jsonfile": { "version": "2.4.0", "resolved": "https://registry.npmjs.org/jsonfile/-/jsonfile-2.4.0.tgz", @@ -1904,6 +3098,19 @@ "node": ">=0.8" } }, + "node_modules/levn": { + "version": "0.4.1", + "resolved": "https://registry.npmjs.org/levn/-/levn-0.4.1.tgz", + "integrity": "sha512-+bT2uH4E5LGE7h/n3evcS/sQlJXCpIp6ym8OWJ5eV6+67Dsql/LaaT7qJBAt2rzfoa/5QBGBhxDix1dMt2kQKQ==", + "dev": true, + "dependencies": { + "prelude-ls": "^1.2.1", + "type-check": "~0.4.0" + }, + "engines": { + "node": ">= 0.8.0" + } + }, "node_modules/locate-path": { "version": "6.0.0", "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-6.0.0.tgz", @@ -1924,6 +3131,12 @@ "resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.21.tgz", "integrity": "sha512-v2kDEe57lecTulaDIuNTPy3Ry4gLGJ6Z1O3vE1krgXZNrsQ+LFTGHVxVjcXPs17LhbZVGedAJv8XZ1tvj5FvSg==" }, + "node_modules/lodash.clonedeep": { + "version": "4.5.0", + "resolved": "https://registry.npmjs.org/lodash.clonedeep/-/lodash.clonedeep-4.5.0.tgz", + "integrity": "sha1-4j8/nE+Pvd6HJSnBBxhXoIblzO8=", + "dev": true + }, "node_modules/lodash.flattendeep": { "version": "4.4.0", "resolved": "https://registry.npmjs.org/lodash.flattendeep/-/lodash.flattendeep-4.4.0.tgz", @@ -1935,6 +3148,18 @@ "integrity": "sha1-LRd/ZS+jHpObRDjVNBSZ36OCXpk=", "dev": true }, + "node_modules/lodash.merge": { + "version": "4.6.2", + "resolved": "https://registry.npmjs.org/lodash.merge/-/lodash.merge-4.6.2.tgz", + "integrity": "sha512-0KpjqXRVvrYyCsX1swR/XTK0va6VQkQM6MNo7PqW77ByjAhoARA8EfrP1N4+KlKj8YS0ZUCtRT/YUuhyYDujIQ==", + "dev": true + }, + "node_modules/lodash.truncate": { + "version": "4.4.2", + "resolved": "https://registry.npmjs.org/lodash.truncate/-/lodash.truncate-4.4.2.tgz", + "integrity": "sha1-WjUNoLERO4N+z//VgSy+WNbq4ZM=", + "dev": true + }, "node_modules/log-symbols": { "version": "4.0.0", "resolved": "https://registry.npmjs.org/log-symbols/-/log-symbols-4.0.0.tgz", @@ -2001,6 +3226,15 @@ "resolved": "https://registry.npmjs.org/merge-descriptors/-/merge-descriptors-1.0.1.tgz", "integrity": "sha1-sAqqVW3YtEVoFQ7J0blT8/kMu2E=" }, + "node_modules/merge2": { + "version": "1.4.1", + "resolved": "https://registry.npmjs.org/merge2/-/merge2-1.4.1.tgz", + "integrity": "sha512-8q7VEgMJW4J8tcfVPy8g09NcQwZdbwFEqhe/WZkoIzjn/3TGDwtOCYtXGxA3O8tPzpczCCDgv+P2P5y00ZJOOg==", + "dev": true, + "engines": { + "node": ">= 8" + } + }, "node_modules/methods": { "version": "1.1.2", "resolved": "https://registry.npmjs.org/methods/-/methods-1.1.2.tgz", @@ -2009,6 +3243,19 @@ "node": ">= 0.6" } }, + "node_modules/micromatch": { + "version": "4.0.4", + "resolved": "https://registry.npmjs.org/micromatch/-/micromatch-4.0.4.tgz", + "integrity": "sha512-pRmzw/XUcwXGpD9aI9q/0XOwLNygjETJ8y0ao0wdqprrzDa4YnxLcz7fQRZr8voh8V10kGhABbNcHVk5wHgWwg==", + "dev": true, + "dependencies": { + "braces": "^3.0.1", + "picomatch": "^2.2.3" + }, + "engines": { + "node": ">=8.6" + } + }, "node_modules/mime": { "version": "1.6.0", "resolved": "https://registry.npmjs.org/mime/-/mime-1.6.0.tgz", @@ -2310,6 +3557,12 @@ "resolved": "https://registry.npmjs.org/napi-build-utils/-/napi-build-utils-1.0.2.tgz", "integrity": "sha512-ONmRUqK7zj7DWX0D9ADe03wbwOBZxNAfF20PlGfCWQcD3+/MakShIHrMqx9YwPTfxDdF1zLeL+RGZiR9kGMLdg==" }, + "node_modules/natural-compare": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/natural-compare/-/natural-compare-1.4.0.tgz", + "integrity": "sha1-Sr6/7tdUHywnrPspvbvRXI1bpPc=", + "dev": true + }, "node_modules/negotiator": { "version": "0.6.2", "resolved": "https://registry.npmjs.org/negotiator/-/negotiator-0.6.2.tgz", @@ -2491,6 +3744,23 @@ "wrappy": "1" } }, + "node_modules/optionator": { + "version": "0.9.1", + "resolved": "https://registry.npmjs.org/optionator/-/optionator-0.9.1.tgz", + "integrity": "sha512-74RlY5FCnhq4jRxVUPKDaRwrVNXMqsGsiW6AJw4XK8hmtm10wC0ypZBLw5IIp85NZMr91+qd1RvvENwg7jjRFw==", + "dev": true, + "dependencies": { + "deep-is": "^0.1.3", + "fast-levenshtein": "^2.0.6", + "levn": "^0.4.1", + "prelude-ls": "^1.2.1", + "type-check": "^0.4.0", + "word-wrap": "^1.2.3" + }, + "engines": { + "node": ">= 0.8.0" + } + }, "node_modules/os-tmpdir": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/os-tmpdir/-/os-tmpdir-1.0.2.tgz", @@ -2558,6 +3828,18 @@ "resolved": "https://registry.npmjs.org/packet-reader/-/packet-reader-1.0.0.tgz", "integrity": "sha512-HAKu/fG3HpHFO0AA8WE8q2g+gBJaZ9MG7fcKk+IJPLTGAD6Psw4443l+9DGRbOIh3/aXr7Phy0TjilYivJo5XQ==" }, + "node_modules/parent-module": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/parent-module/-/parent-module-1.0.1.tgz", + "integrity": "sha512-GQ2EWRpQV8/o+Aw8YqtfZZPfNRWZYkbidE9k5rpl/hC3vtHHBfGm2Ifi6qWV+coDGkrUKZAxE3Lot5kcsRlh+g==", + "dev": true, + "dependencies": { + "callsites": "^3.0.0" + }, + "engines": { + "node": ">=6" + } + }, "node_modules/parseurl": { "version": "1.3.3", "resolved": "https://registry.npmjs.org/parseurl/-/parseurl-1.3.3.tgz", @@ -2620,6 +3902,15 @@ "resolved": "https://registry.npmjs.org/path-to-regexp/-/path-to-regexp-0.1.7.tgz", "integrity": "sha1-32BBeABfUi8V60SQ5yR6G/qmf4w=" }, + "node_modules/path-type": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/path-type/-/path-type-4.0.0.tgz", + "integrity": "sha512-gDKb8aZMDeD/tZWs9P6+q0J9Mwkdl6xMV8TjnGP3qJVJ06bdMgkbBlLU8IdfOsIsFz2BW1rNVT3XuNEl8zPAvw==", + "dev": true, + "engines": { + "node": ">=8" + } + }, "node_modules/pg": { "version": "8.5.1", "resolved": "https://registry.npmjs.org/pg/-/pg-8.5.1.tgz", @@ -2684,12 +3975,15 @@ } }, "node_modules/picomatch": { - "version": "2.2.2", - "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-2.2.2.tgz", - "integrity": "sha512-q0M/9eZHzmr0AulXyPwNfZjtwZ/RBZlbN3K3CErVrk50T2ASYI7Bye0EvekFY3IP1Nt2DHu0re+V2ZHIpMkuWg==", + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-2.3.0.tgz", + "integrity": "sha512-lY1Q/PiJGC2zOv/z391WOTD+Z02bCgsFfvxoXXf6h7kv9o+WmsmzYqrAwY63sNgOxE4xEdq0WyUnXfKeBrSvYw==", "dev": true, "engines": { "node": ">=8.6" + }, + "funding": { + "url": "https://github.com/sponsors/jonschlinkert" } }, "node_modules/pify": { @@ -2763,6 +4057,15 @@ "node": ">=6" } }, + "node_modules/prelude-ls": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/prelude-ls/-/prelude-ls-1.2.1.tgz", + "integrity": "sha512-vkcDPrRZo1QZLbn5RLGPpg/WmIQ65qoWWhcGKf/b5eplkkarX0m9z8ppCat4mlOqUsWpyNuYgO3VRyrYHSzX5g==", + "dev": true, + "engines": { + "node": ">= 0.8.0" + } + }, "node_modules/prepend-http": { "version": "1.0.4", "resolved": "https://registry.npmjs.org/prepend-http/-/prepend-http-1.0.4.tgz", @@ -2777,6 +4080,15 @@ "resolved": "https://registry.npmjs.org/process-nextick-args/-/process-nextick-args-2.0.1.tgz", "integrity": "sha512-3ouUOpQhtgrbOa17J7+uxOTpITYWaGP7/AhoR3+A+/1e9skrzelGi/dXzEYyvbxubEF6Wn2ypscTKiKJFFn1ag==" }, + "node_modules/progress": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/progress/-/progress-2.0.3.tgz", + "integrity": "sha512-7PiHtLll5LdnKIMw100I+8xJXR5gW2QwWYkT6iJva0bXitZKa/XMrSbdmg3r2Xnaidz9Qumd0VPaMrZlF9V9sA==", + "dev": true, + "engines": { + "node": ">=0.4.0" + } + }, "node_modules/promise": { "version": "7.3.1", "resolved": "https://registry.npmjs.org/promise/-/promise-7.3.1.tgz", @@ -2822,6 +4134,15 @@ "once": "^1.3.1" } }, + "node_modules/punycode": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/punycode/-/punycode-2.1.1.tgz", + "integrity": "sha512-XRsRjdf+j5ml+y/6GKHPZbrF/8p2Yga0JPtdqTIY2Xe5ohJPD9saDJJLPvp9+NSBprVvevdXZybnj2cv8OEd0A==", + "dev": true, + "engines": { + "node": ">=6" + } + }, "node_modules/q": { "version": "1.5.1", "resolved": "https://registry.npmjs.org/q/-/q-1.5.1.tgz", @@ -2839,6 +4160,26 @@ "node": ">=0.6" } }, + "node_modules/queue-microtask": { + "version": "1.2.3", + "resolved": "https://registry.npmjs.org/queue-microtask/-/queue-microtask-1.2.3.tgz", + "integrity": "sha512-NuaNSa6flKT5JaSYQzJok04JzTL1CA6aGhv5rfLW3PgqA+M2ChpZQnAC8h8i4ZFkBS8X5RqkDBHA7r4hej3K9A==", + "dev": true, + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/feross" + }, + { + "type": "patreon", + "url": "https://www.patreon.com/feross" + }, + { + "type": "consulting", + "url": "https://feross.org/support" + } + ] + }, "node_modules/randombytes": { "version": "2.1.0", "resolved": "https://registry.npmjs.org/randombytes/-/randombytes-2.1.0.tgz", @@ -2956,6 +4297,18 @@ "resolved": "https://registry.npmjs.org/regenerator-runtime/-/regenerator-runtime-0.11.1.tgz", "integrity": "sha512-MguG95oij0fC3QV3URf4V2SDYGJhJnJGqvIIgdECeODCT98wSWDAJ94SSuVpYQUoTcGUIL6L4yNB7j1DFFHSBg==" }, + "node_modules/regexpp": { + "version": "3.2.0", + "resolved": "https://registry.npmjs.org/regexpp/-/regexpp-3.2.0.tgz", + "integrity": "sha512-pq2bWo9mVD43nbts2wGv17XLiNLya+GklZ8kaDLV2Z08gDCsGpnKn9BFMepvWuHCbyVvY7J5o5+BVvoQbmlJLg==", + "dev": true, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/sponsors/mysticatea" + } + }, "node_modules/registry-auth-token": { "version": "3.4.0", "resolved": "https://registry.npmjs.org/registry-auth-token/-/registry-auth-token-3.4.0.tgz", @@ -2987,6 +4340,34 @@ "node": ">=0.10.0" } }, + "node_modules/require-from-string": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/require-from-string/-/require-from-string-2.0.2.tgz", + "integrity": "sha512-Xf0nWe6RseziFMu+Ap9biiUbmplq6S9/p+7w7YXP/JBHhrUDDUhwa+vANyubuqfZWTveU//DYVGsDG7RKL/vEw==", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/resolve-from": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/resolve-from/-/resolve-from-4.0.0.tgz", + "integrity": "sha512-pb/MYmXstAkysRFx8piNI1tGFNQIFA3vkE3Gq4EuA1dF6gHp/+vgZqsCGJapvy8N3Q+4o7FwvquPJcnZ7RYy4g==", + "dev": true, + "engines": { + "node": ">=4" + } + }, + "node_modules/reusify": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/reusify/-/reusify-1.0.4.tgz", + "integrity": "sha512-U9nH88a3fc/ekCF1l0/UP1IosiuIjyTh7hBvXVMHYgVcfGvt897Xguj2UOLDeI5BG2m7/uwyaLVT6fbtCwTyzw==", + "dev": true, + "engines": { + "iojs": ">=1.0.0", + "node": ">=0.10.0" + } + }, "node_modules/rimraf": { "version": "2.7.1", "resolved": "https://registry.npmjs.org/rimraf/-/rimraf-2.7.1.tgz", @@ -2998,6 +4379,29 @@ "rimraf": "bin.js" } }, + "node_modules/run-parallel": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/run-parallel/-/run-parallel-1.2.0.tgz", + "integrity": "sha512-5l4VyZR86LZ/lDxZTR6jqL8AFE2S0IFLMP26AbjsLVADxHdhB/c0GUsH+y39UfCi3dzz8OlQuPmnaJOMoDHQBA==", + "dev": true, + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/feross" + }, + { + "type": "patreon", + "url": "https://www.patreon.com/feross" + }, + { + "type": "consulting", + "url": "https://feross.org/support" + } + ], + "dependencies": { + "queue-microtask": "^1.2.2" + } + }, "node_modules/safe-buffer": { "version": "5.2.0", "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.2.0.tgz", @@ -3168,6 +4572,41 @@ "node": ">=0.3.1" } }, + "node_modules/slash": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/slash/-/slash-3.0.0.tgz", + "integrity": "sha512-g9Q1haeby36OSStwb4ntCGGGaKsaVSjQ68fBxoQcutl5fS1vuY18H3wSt3jFyFtrkx+Kz0V1G85A4MyAdDMi2Q==", + "dev": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/slice-ansi": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/slice-ansi/-/slice-ansi-4.0.0.tgz", + "integrity": "sha512-qMCMfhY040cVHT43K9BFygqYbUPFZKHOg7K73mtTWJRb8pyP3fzf4Ixd5SzdEJQ6MRUg/WBnOLxghZtKKurENQ==", + "dev": true, + "dependencies": { + "ansi-styles": "^4.0.0", + "astral-regex": "^2.0.0", + "is-fullwidth-code-point": "^3.0.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/chalk/slice-ansi?sponsor=1" + } + }, + "node_modules/slice-ansi/node_modules/is-fullwidth-code-point": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-3.0.0.tgz", + "integrity": "sha512-zymm5+u+sCsSWyD9qNaejV3DFvhCKclKdizYaJUuHA83RLjb7nSuGnddCHGv0hk+KY7BMAlsWeK4Ueg6EV6XQg==", + "dev": true, + "engines": { + "node": ">=8" + } + }, "node_modules/source-map": { "version": "0.6.1", "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", @@ -3195,6 +4634,12 @@ "readable-stream": "^3.0.0" } }, + "node_modules/sprintf-js": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/sprintf-js/-/sprintf-js-1.0.3.tgz", + "integrity": "sha1-BOaSb2YolTVPPdAVIDYzuFcpfiw=", + "dev": true + }, "node_modules/sqlstring": { "version": "2.3.1", "resolved": "https://registry.npmjs.org/sqlstring/-/sqlstring-2.3.1.tgz", @@ -3364,6 +4809,89 @@ "get-port": "^3.1.0" } }, + "node_modules/table": { + "version": "6.7.1", + "resolved": "https://registry.npmjs.org/table/-/table-6.7.1.tgz", + "integrity": "sha512-ZGum47Yi6KOOFDE8m223td53ath2enHcYLgOCjGr5ngu8bdIARQk6mN/wRMv4yMRcHnCSnHbCEha4sobQx5yWg==", + "dev": true, + "dependencies": { + "ajv": "^8.0.1", + "lodash.clonedeep": "^4.5.0", + "lodash.truncate": "^4.4.2", + "slice-ansi": "^4.0.0", + "string-width": "^4.2.0", + "strip-ansi": "^6.0.0" + }, + "engines": { + "node": ">=10.0.0" + } + }, + "node_modules/table/node_modules/ajv": { + "version": "8.6.0", + "resolved": "https://registry.npmjs.org/ajv/-/ajv-8.6.0.tgz", + "integrity": "sha512-cnUG4NSBiM4YFBxgZIj/In3/6KX+rQ2l2YPRVcvAMQGWEPKuXoPIhxzwqh31jA3IPbI4qEOp/5ILI4ynioXsGQ==", + "dev": true, + "dependencies": { + "fast-deep-equal": "^3.1.1", + "json-schema-traverse": "^1.0.0", + "require-from-string": "^2.0.2", + "uri-js": "^4.2.2" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/epoberezkin" + } + }, + "node_modules/table/node_modules/ansi-regex": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.0.tgz", + "integrity": "sha512-bY6fj56OUQ0hU1KjFNDQuJFezqKdrAyFdIevADiqrWHwSlbmBNMHp5ak2f40Pm8JTFyM2mqxkG6ngkHO11f/lg==", + "dev": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/table/node_modules/is-fullwidth-code-point": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-3.0.0.tgz", + "integrity": "sha512-zymm5+u+sCsSWyD9qNaejV3DFvhCKclKdizYaJUuHA83RLjb7nSuGnddCHGv0hk+KY7BMAlsWeK4Ueg6EV6XQg==", + "dev": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/table/node_modules/json-schema-traverse": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-1.0.0.tgz", + "integrity": "sha512-NM8/P9n3XjXhIZn1lLhkFaACTOURQXjWhV4BA/RnOv8xvgqtqpAX9IO4mRQxSx1Rlo4tqzeqb0sOlruaOy3dug==", + "dev": true + }, + "node_modules/table/node_modules/string-width": { + "version": "4.2.2", + "resolved": "https://registry.npmjs.org/string-width/-/string-width-4.2.2.tgz", + "integrity": "sha512-XBJbT3N4JhVumXE0eoLU9DCjcaF92KLNqTmFCnG1pf8duUxFGwtP6AD6nkjw9a3IdiRtL3E2w3JDiE/xi3vOeA==", + "dev": true, + "dependencies": { + "emoji-regex": "^8.0.0", + "is-fullwidth-code-point": "^3.0.0", + "strip-ansi": "^6.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/table/node_modules/strip-ansi": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.0.tgz", + "integrity": "sha512-AuvKTrTfQNYNIctbR1K/YGTR1756GycPsg7b9bdV9Duqur4gv6aKqHXah67Z8ImS7WEz5QVcOtlfW2rZEugt6w==", + "dev": true, + "dependencies": { + "ansi-regex": "^5.0.0" + }, + "engines": { + "node": ">=8" + } + }, "node_modules/tar": { "version": "6.1.0", "resolved": "https://registry.npmjs.org/tar/-/tar-6.1.0.tgz", @@ -3423,6 +4951,12 @@ "node": ">=4" } }, + "node_modules/text-table": { + "version": "0.2.0", + "resolved": "https://registry.npmjs.org/text-table/-/text-table-0.2.0.tgz", + "integrity": "sha1-f17oI66AUgfACvLfSoTsP8+lcLQ=", + "dev": true + }, "node_modules/then-mysql": { "version": "1.1.1", "resolved": "https://registry.npmjs.org/then-mysql/-/then-mysql-1.1.1.tgz", @@ -3522,6 +5056,27 @@ "node": ">=0.3.1" } }, + "node_modules/tslib": { + "version": "1.14.1", + "resolved": "https://registry.npmjs.org/tslib/-/tslib-1.14.1.tgz", + "integrity": "sha512-Xni35NKzjgMrwevysHTCArtLDpPvye8zV/0E4EyYn43P7/7qvQwPh9BGkHewbMulVntbigmcT7rdX3BNo9wRJg==", + "dev": true + }, + "node_modules/tsutils": { + "version": "3.21.0", + "resolved": "https://registry.npmjs.org/tsutils/-/tsutils-3.21.0.tgz", + "integrity": "sha512-mHKK3iUXL+3UF6xL5k0PEhKRUBKPBCv/+RkEOpjRWxxx27KKRBmmA60A9pgOUvMi8GKhRMPEmjBRPzs2W7O1OA==", + "dev": true, + "dependencies": { + "tslib": "^1.8.1" + }, + "engines": { + "node": ">= 6" + }, + "peerDependencies": { + "typescript": ">=2.8.0 || >= 3.2.0-dev || >= 3.3.0-dev || >= 3.4.0-dev || >= 3.5.0-dev || >= 3.6.0-dev || >= 3.6.0-beta || >= 3.7.0-dev || >= 3.7.0-beta" + } + }, "node_modules/tunnel-agent": { "version": "0.6.0", "resolved": "https://registry.npmjs.org/tunnel-agent/-/tunnel-agent-0.6.0.tgz", @@ -3533,6 +5088,18 @@ "node": "*" } }, + "node_modules/type-check": { + "version": "0.4.0", + "resolved": "https://registry.npmjs.org/type-check/-/type-check-0.4.0.tgz", + "integrity": "sha512-XleUoc9uwGXqjWwXaUTZAmzMcFZ5858QA2vvx1Ur5xIcixXIP+8LnFDgRplU30us6teqdlskFfu+ae4K79Ooew==", + "dev": true, + "dependencies": { + "prelude-ls": "^1.2.1" + }, + "engines": { + "node": ">= 0.8.0" + } + }, "node_modules/type-detect": { "version": "4.0.8", "resolved": "https://registry.npmjs.org/type-detect/-/type-detect-4.0.8.tgz", @@ -3542,6 +5109,18 @@ "node": ">=4" } }, + "node_modules/type-fest": { + "version": "0.20.2", + "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-0.20.2.tgz", + "integrity": "sha512-Ne+eE4r0/iWnpAxD852z3A+N0Bt5RN//NjJwRd2VFHEmrywxf5vsZlh4R6lixl6B+wz/8d+maTSAkN1FIkI3LQ==", + "dev": true, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, "node_modules/type-is": { "version": "1.6.18", "resolved": "https://registry.npmjs.org/type-is/-/type-is-1.6.18.tgz", @@ -3669,6 +5248,15 @@ "node": ">=4" } }, + "node_modules/uri-js": { + "version": "4.4.1", + "resolved": "https://registry.npmjs.org/uri-js/-/uri-js-4.4.1.tgz", + "integrity": "sha512-7rKUyy33Q1yc98pQ1DAmLtwX109F7TIfWlW1Ydo8Wl1ii1SeHieeh0HHfPeL2fMXK6z0s8ecKs9frCuLJvndBg==", + "dev": true, + "dependencies": { + "punycode": "^2.1.0" + } + }, "node_modules/url-parse-lax": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/url-parse-lax/-/url-parse-lax-1.0.0.tgz", @@ -3702,6 +5290,12 @@ "uuid": "bin/uuid" } }, + "node_modules/v8-compile-cache": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/v8-compile-cache/-/v8-compile-cache-2.3.0.tgz", + "integrity": "sha512-l8lCEmLcLYZh4nbunNZvQCJc5pv7+RCwa8q/LdUx8u7lsWvPDKmpodJAJNwkAhJC//dFY48KuIEmjtd4RViDrA==", + "dev": true + }, "node_modules/vary": { "version": "1.1.2", "resolved": "https://registry.npmjs.org/vary/-/vary-1.1.2.tgz", @@ -3742,6 +5336,15 @@ "node": ">=4" } }, + "node_modules/word-wrap": { + "version": "1.2.3", + "resolved": "https://registry.npmjs.org/word-wrap/-/word-wrap-1.2.3.tgz", + "integrity": "sha512-Hz/mrNwitNRh/HUAtM/VT/5VH+ygD6DV7mYKZAtHOrbs8U7lvPS6xf7EJKMF0uW1KJCl0H701g3ZGus+muE5vQ==", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, "node_modules/workerpool": { "version": "6.1.0", "resolved": "https://registry.npmjs.org/workerpool/-/workerpool-6.1.0.tgz", @@ -3979,6 +5582,182 @@ "tmp": "^0.0.28" } }, + "@babel/code-frame": { + "version": "7.12.11", + "resolved": "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.12.11.tgz", + "integrity": "sha512-Zt1yodBx1UcyiePMSkWnU4hPqhwq7hGi2nFL1LeA3EUl+q2LQx16MISgJ0+z7dnmgvP9QtIleuETGOiOH1RcIw==", + "dev": true, + "requires": { + "@babel/highlight": "^7.10.4" + } + }, + "@babel/helper-validator-identifier": { + "version": "7.14.5", + "resolved": "https://registry.npmjs.org/@babel/helper-validator-identifier/-/helper-validator-identifier-7.14.5.tgz", + "integrity": "sha512-5lsetuxCLilmVGyiLEfoHBRX8UCFD+1m2x3Rj97WrW3V7H3u4RWRXA4evMjImCsin2J2YT0QaVDGf+z8ondbAg==", + "dev": true + }, + "@babel/highlight": { + "version": "7.14.5", + "resolved": "https://registry.npmjs.org/@babel/highlight/-/highlight-7.14.5.tgz", + "integrity": "sha512-qf9u2WFWVV0MppaL877j2dBtQIDgmidgjGk5VIMw3OadXvYaXn66U1BFlH2t4+t3i+8PhedppRv+i40ABzd+gg==", + "dev": true, + "requires": { + "@babel/helper-validator-identifier": "^7.14.5", + "chalk": "^2.0.0", + "js-tokens": "^4.0.0" + }, + "dependencies": { + "ansi-styles": { + "version": "3.2.1", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-3.2.1.tgz", + "integrity": "sha512-VT0ZI6kZRdTh8YyJw3SMbYm/u+NqfsAxEpWO0Pf9sq8/e94WxxOpPKx9FR1FlyCtOVDNOQ+8ntlqFxiRc+r5qA==", + "dev": true, + "requires": { + "color-convert": "^1.9.0" + } + }, + "chalk": { + "version": "2.4.2", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-2.4.2.tgz", + "integrity": "sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ==", + "dev": true, + "requires": { + "ansi-styles": "^3.2.1", + "escape-string-regexp": "^1.0.5", + "supports-color": "^5.3.0" + } + }, + "supports-color": { + "version": "5.5.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-5.5.0.tgz", + "integrity": "sha512-QjVjwdXIt408MIiAqCX4oUKsgU2EqAGzs2Ppkm4aQYbjm+ZEWEcW4SfFNTr4uMNZma0ey4f5lgLrkB0aX0QMow==", + "dev": true, + "requires": { + "has-flag": "^3.0.0" + } + } + } + }, + "@eslint/eslintrc": { + "version": "0.4.2", + "resolved": "https://registry.npmjs.org/@eslint/eslintrc/-/eslintrc-0.4.2.tgz", + "integrity": "sha512-8nmGq/4ycLpIwzvhI4tNDmQztZ8sp+hI7cyG8i1nQDhkAbRzHpXPidRAHlNvCZQpJTKw5ItIpMw9RSToGF00mg==", + "dev": true, + "requires": { + "ajv": "^6.12.4", + "debug": "^4.1.1", + "espree": "^7.3.0", + "globals": "^13.9.0", + "ignore": "^4.0.6", + "import-fresh": "^3.2.1", + "js-yaml": "^3.13.1", + "minimatch": "^3.0.4", + "strip-json-comments": "^3.1.1" + }, + "dependencies": { + "argparse": { + "version": "1.0.10", + "resolved": "https://registry.npmjs.org/argparse/-/argparse-1.0.10.tgz", + "integrity": "sha512-o5Roy6tNG4SL/FOkCAN6RzjiakZS25RLYFrcMttJqbdd8BWrnA+fGz57iN5Pb06pvBGvl5gQ0B48dJlslXvoTg==", + "dev": true, + "requires": { + "sprintf-js": "~1.0.2" + } + }, + "debug": { + "version": "4.3.1", + "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.1.tgz", + "integrity": "sha512-doEwdvm4PCeK4K3RQN2ZC2BYUBaxwLARCqZmMjtF8a51J2Rb0xpVloFRnCODwqjpwnAoao4pelN8l3RJdv3gRQ==", + "dev": true, + "requires": { + "ms": "2.1.2" + } + }, + "js-yaml": { + "version": "3.14.1", + "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-3.14.1.tgz", + "integrity": "sha512-okMH7OXXJ7YrN9Ok3/SXrnu4iX9yOk+25nqX4imS2npuvTYDmo/QEZoqwZkYaIDk3jVvBOTOIEgEhaLOynBS9g==", + "dev": true, + "requires": { + "argparse": "^1.0.7", + "esprima": "^4.0.0" + } + }, + "ms": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz", + "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==", + "dev": true + }, + "strip-json-comments": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/strip-json-comments/-/strip-json-comments-3.1.1.tgz", + "integrity": "sha512-6fPc+R4ihwqP6N/aIv2f1gMH8lOVtWQHoqC4yK6oSDVVocumAsfCqjkXnqiYMhmMwS/mEHLp7Vehlt3ql6lEig==", + "dev": true + } + } + }, + "@humanwhocodes/config-array": { + "version": "0.5.0", + "resolved": "https://registry.npmjs.org/@humanwhocodes/config-array/-/config-array-0.5.0.tgz", + "integrity": "sha512-FagtKFz74XrTl7y6HCzQpwDfXP0yhxe9lHLD1UZxjvZIcbyRz8zTFF/yYNfSfzU414eDwZ1SrO0Qvtyf+wFMQg==", + "dev": true, + "requires": { + "@humanwhocodes/object-schema": "^1.2.0", + "debug": "^4.1.1", + "minimatch": "^3.0.4" + }, + "dependencies": { + "debug": { + "version": "4.3.1", + "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.1.tgz", + "integrity": "sha512-doEwdvm4PCeK4K3RQN2ZC2BYUBaxwLARCqZmMjtF8a51J2Rb0xpVloFRnCODwqjpwnAoao4pelN8l3RJdv3gRQ==", + "dev": true, + "requires": { + "ms": "2.1.2" + } + }, + "ms": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz", + "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==", + "dev": true + } + } + }, + "@humanwhocodes/object-schema": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/@humanwhocodes/object-schema/-/object-schema-1.2.0.tgz", + "integrity": "sha512-wdppn25U8z/2yiaT6YGquE6X8sSv7hNMWSXYSSU1jGv/yd6XqjXgTDJ8KP4NgjTXfJ3GbRjeeb8RTV7a/VpM+w==", + "dev": true + }, + "@nodelib/fs.scandir": { + "version": "2.1.5", + "resolved": "https://registry.npmjs.org/@nodelib/fs.scandir/-/fs.scandir-2.1.5.tgz", + "integrity": "sha512-vq24Bq3ym5HEQm2NKCr3yXDwjc7vTsEThRDnkp2DK9p1uqLR+DHurm/NOTo0KG7HYHU7eppKZj3MyqYuMBf62g==", + "dev": true, + "requires": { + "@nodelib/fs.stat": "2.0.5", + "run-parallel": "^1.1.9" + } + }, + "@nodelib/fs.stat": { + "version": "2.0.5", + "resolved": "https://registry.npmjs.org/@nodelib/fs.stat/-/fs.stat-2.0.5.tgz", + "integrity": "sha512-RkhPPp2zrqDAQA/2jNhnztcPAlv64XdhIp7a7454A5ovI7Bukxgt7MX7udwAu3zg1DcpPU0rz3VV1SeaqvY4+A==", + "dev": true + }, + "@nodelib/fs.walk": { + "version": "1.2.7", + "resolved": "https://registry.npmjs.org/@nodelib/fs.walk/-/fs.walk-1.2.7.tgz", + "integrity": "sha512-BTIhocbPBSrRmHxOAJFtR18oLhxTtAFDAvL8hY1S3iU8k+E60W/YFs4jrixGzQjMpF4qPXxIQHcjVD9dz1C2QA==", + "dev": true, + "requires": { + "@nodelib/fs.scandir": "2.1.5", + "fastq": "^1.6.0" + } + }, "@sinonjs/commons": { "version": "1.8.1", "resolved": "https://registry.npmjs.org/@sinonjs/commons/-/commons-1.8.1.tgz", @@ -4096,6 +5875,12 @@ "integrity": "sha512-DmZDpSVnsuBrOhtHwE1oKmUJ3qVjHhhNQ7WnZy9/RhH3A24Ar+9o4SoaCWcTzQhalpRDIAMsfdoZLWNJtdBR7A==", "dev": true }, + "@types/json-schema": { + "version": "7.0.7", + "resolved": "https://registry.npmjs.org/@types/json-schema/-/json-schema-7.0.7.tgz", + "integrity": "sha512-cxWFQVseBm6O9Gbw1IWb8r6OS4OhSt3hPZLkFApLjM8TEXROBuQGLAH2i2gZpcXdLBIrpXuTDhH7Vbm1iXmNGA==", + "dev": true + }, "@types/mime": { "version": "2.0.3", "resolved": "https://registry.npmjs.org/@types/mime/-/mime-2.0.3.tgz", @@ -4197,6 +5982,186 @@ "integrity": "sha512-I99sngh224D0M7XgW1s120zxCt3VYQ3IQsuw3P3jbq5GG4yc79+ZjyKznyOGIQrflfylLgcfekeZW/vk0yng6A==", "dev": true }, + "@typescript-eslint/eslint-plugin": { + "version": "4.28.1", + "resolved": "https://registry.npmjs.org/@typescript-eslint/eslint-plugin/-/eslint-plugin-4.28.1.tgz", + "integrity": "sha512-9yfcNpDaNGQ6/LQOX/KhUFTR1sCKH+PBr234k6hI9XJ0VP5UqGxap0AnNwBnWFk1MNyWBylJH9ZkzBXC+5akZQ==", + "dev": true, + "requires": { + "@typescript-eslint/experimental-utils": "4.28.1", + "@typescript-eslint/scope-manager": "4.28.1", + "debug": "^4.3.1", + "functional-red-black-tree": "^1.0.1", + "regexpp": "^3.1.0", + "semver": "^7.3.5", + "tsutils": "^3.21.0" + }, + "dependencies": { + "debug": { + "version": "4.3.1", + "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.1.tgz", + "integrity": "sha512-doEwdvm4PCeK4K3RQN2ZC2BYUBaxwLARCqZmMjtF8a51J2Rb0xpVloFRnCODwqjpwnAoao4pelN8l3RJdv3gRQ==", + "dev": true, + "requires": { + "ms": "2.1.2" + } + }, + "lru-cache": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-6.0.0.tgz", + "integrity": "sha512-Jo6dJ04CmSjuznwJSS3pUeWmd/H0ffTlkXXgwZi+eq1UCmqQwCh+eLsYOYCwY991i2Fah4h1BEMCx4qThGbsiA==", + "dev": true, + "requires": { + "yallist": "^4.0.0" + } + }, + "ms": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz", + "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==", + "dev": true + }, + "semver": { + "version": "7.3.5", + "resolved": "https://registry.npmjs.org/semver/-/semver-7.3.5.tgz", + "integrity": "sha512-PoeGJYh8HK4BTO/a9Tf6ZG3veo/A7ZVsYrSA6J8ny9nb3B1VrpkuN+z9OE5wfE5p6H4LchYZsegiQgbJD94ZFQ==", + "dev": true, + "requires": { + "lru-cache": "^6.0.0" + } + } + } + }, + "@typescript-eslint/experimental-utils": { + "version": "4.28.1", + "resolved": "https://registry.npmjs.org/@typescript-eslint/experimental-utils/-/experimental-utils-4.28.1.tgz", + "integrity": "sha512-n8/ggadrZ+uyrfrSEchx3jgODdmcx7MzVM2sI3cTpI/YlfSm0+9HEUaWw3aQn2urL2KYlWYMDgn45iLfjDYB+Q==", + "dev": true, + "requires": { + "@types/json-schema": "^7.0.7", + "@typescript-eslint/scope-manager": "4.28.1", + "@typescript-eslint/types": "4.28.1", + "@typescript-eslint/typescript-estree": "4.28.1", + "eslint-scope": "^5.1.1", + "eslint-utils": "^3.0.0" + }, + "dependencies": { + "eslint-utils": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/eslint-utils/-/eslint-utils-3.0.0.tgz", + "integrity": "sha512-uuQC43IGctw68pJA1RgbQS8/NP7rch6Cwd4j3ZBtgo4/8Flj4eGE7ZYSZRN3iq5pVUv6GPdW5Z1RFleo84uLDA==", + "dev": true, + "requires": { + "eslint-visitor-keys": "^2.0.0" + } + } + } + }, + "@typescript-eslint/parser": { + "version": "4.28.1", + "resolved": "https://registry.npmjs.org/@typescript-eslint/parser/-/parser-4.28.1.tgz", + "integrity": "sha512-UjrMsgnhQIIK82hXGaD+MCN8IfORS1CbMdu7VlZbYa8LCZtbZjJA26De4IPQB7XYZbL8gJ99KWNj0l6WD0guJg==", + "dev": true, + "requires": { + "@typescript-eslint/scope-manager": "4.28.1", + "@typescript-eslint/types": "4.28.1", + "@typescript-eslint/typescript-estree": "4.28.1", + "debug": "^4.3.1" + }, + "dependencies": { + "debug": { + "version": "4.3.1", + "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.1.tgz", + "integrity": "sha512-doEwdvm4PCeK4K3RQN2ZC2BYUBaxwLARCqZmMjtF8a51J2Rb0xpVloFRnCODwqjpwnAoao4pelN8l3RJdv3gRQ==", + "dev": true, + "requires": { + "ms": "2.1.2" + } + }, + "ms": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz", + "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==", + "dev": true + } + } + }, + "@typescript-eslint/scope-manager": { + "version": "4.28.1", + "resolved": "https://registry.npmjs.org/@typescript-eslint/scope-manager/-/scope-manager-4.28.1.tgz", + "integrity": "sha512-o95bvGKfss6705x7jFGDyS7trAORTy57lwJ+VsYwil/lOUxKQ9tA7Suuq+ciMhJc/1qPwB3XE2DKh9wubW8YYA==", + "dev": true, + "requires": { + "@typescript-eslint/types": "4.28.1", + "@typescript-eslint/visitor-keys": "4.28.1" + } + }, + "@typescript-eslint/types": { + "version": "4.28.1", + "resolved": "https://registry.npmjs.org/@typescript-eslint/types/-/types-4.28.1.tgz", + "integrity": "sha512-4z+knEihcyX7blAGi7O3Fm3O6YRCP+r56NJFMNGsmtdw+NCdpG5SgNz427LS9nQkRVTswZLhz484hakQwB8RRg==", + "dev": true + }, + "@typescript-eslint/typescript-estree": { + "version": "4.28.1", + "resolved": "https://registry.npmjs.org/@typescript-eslint/typescript-estree/-/typescript-estree-4.28.1.tgz", + "integrity": "sha512-GhKxmC4sHXxHGJv8e8egAZeTZ6HI4mLU6S7FUzvFOtsk7ZIDN1ksA9r9DyOgNqowA9yAtZXV0Uiap61bIO81FQ==", + "dev": true, + "requires": { + "@typescript-eslint/types": "4.28.1", + "@typescript-eslint/visitor-keys": "4.28.1", + "debug": "^4.3.1", + "globby": "^11.0.3", + "is-glob": "^4.0.1", + "semver": "^7.3.5", + "tsutils": "^3.21.0" + }, + "dependencies": { + "debug": { + "version": "4.3.1", + "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.1.tgz", + "integrity": "sha512-doEwdvm4PCeK4K3RQN2ZC2BYUBaxwLARCqZmMjtF8a51J2Rb0xpVloFRnCODwqjpwnAoao4pelN8l3RJdv3gRQ==", + "dev": true, + "requires": { + "ms": "2.1.2" + } + }, + "lru-cache": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-6.0.0.tgz", + "integrity": "sha512-Jo6dJ04CmSjuznwJSS3pUeWmd/H0ffTlkXXgwZi+eq1UCmqQwCh+eLsYOYCwY991i2Fah4h1BEMCx4qThGbsiA==", + "dev": true, + "requires": { + "yallist": "^4.0.0" + } + }, + "ms": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz", + "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==", + "dev": true + }, + "semver": { + "version": "7.3.5", + "resolved": "https://registry.npmjs.org/semver/-/semver-7.3.5.tgz", + "integrity": "sha512-PoeGJYh8HK4BTO/a9Tf6ZG3veo/A7ZVsYrSA6J8ny9nb3B1VrpkuN+z9OE5wfE5p6H4LchYZsegiQgbJD94ZFQ==", + "dev": true, + "requires": { + "lru-cache": "^6.0.0" + } + } + } + }, + "@typescript-eslint/visitor-keys": { + "version": "4.28.1", + "resolved": "https://registry.npmjs.org/@typescript-eslint/visitor-keys/-/visitor-keys-4.28.1.tgz", + "integrity": "sha512-K4HMrdFqr9PFquPu178SaSb92CaWe2yErXyPumc8cYWxFmhgJsNY9eSePmO05j0JhBvf2Cdhptd6E6Yv9HVHcg==", + "dev": true, + "requires": { + "@typescript-eslint/types": "4.28.1", + "eslint-visitor-keys": "^2.0.0" + } + }, "@ungap/promise-all-settled": { "version": "1.1.2", "resolved": "https://registry.npmjs.org/@ungap/promise-all-settled/-/promise-all-settled-1.1.2.tgz", @@ -4226,6 +6191,31 @@ "negotiator": "0.6.2" } }, + "acorn": { + "version": "7.4.1", + "resolved": "https://registry.npmjs.org/acorn/-/acorn-7.4.1.tgz", + "integrity": "sha512-nQyp0o1/mNdbTO1PO6kHkwSrmgZ0MT/jCCpNiwbUjGoRN4dlBhqJtoQuCnEOKzgTVwg0ZWiCoQy6SxMebQVh8A==", + "dev": true + }, + "acorn-jsx": { + "version": "5.3.1", + "resolved": "https://registry.npmjs.org/acorn-jsx/-/acorn-jsx-5.3.1.tgz", + "integrity": "sha512-K0Ptm/47OKfQRpNQ2J/oIN/3QYiK6FwW+eJbILhsdxh2WTLdl+30o8aGdTbm5JbffpFFAg/g+zi1E+jvJha5ng==", + "dev": true, + "requires": {} + }, + "ajv": { + "version": "6.12.6", + "resolved": "https://registry.npmjs.org/ajv/-/ajv-6.12.6.tgz", + "integrity": "sha512-j3fVLgvTo527anyYyJOGTYJbG+vnnQYvE0m5mmkc1TK+nxAppkCLMIL0aZ4dblVCNoGShhm+kzE4ZUykBoMg4g==", + "dev": true, + "requires": { + "fast-deep-equal": "^3.1.1", + "fast-json-stable-stringify": "^2.0.0", + "json-schema-traverse": "^0.4.1", + "uri-js": "^4.2.2" + } + }, "ansi-align": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/ansi-align/-/ansi-align-2.0.0.tgz", @@ -4347,11 +6337,23 @@ "resolved": "https://registry.npmjs.org/array-flatten/-/array-flatten-1.1.1.tgz", "integrity": "sha1-ml9pkFGx5wczKPKgCJaLZOopVdI=" }, + "array-union": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/array-union/-/array-union-2.1.0.tgz", + "integrity": "sha512-HGyxoOTYUyCM6stUe6EJgnd4EoewAI7zMdfqO+kGjnlZmBDz/cR5pf8r/cR4Wq60sL/p0IkcjUEEPwS3GFrIyw==", + "dev": true + }, "asap": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/asap/-/asap-1.0.0.tgz", "integrity": "sha1-sqRdpf36ILBJb8N2jMJ8EvqRan0=" }, + "astral-regex": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/astral-regex/-/astral-regex-2.0.0.tgz", + "integrity": "sha512-Z7tMw1ytTXt5jqMcOP+OQteU1VuNK9Y02uuJtKQ1Sv69jXQKKg5cibLwGJow8yzZP+eAc18EmLGPal0bp36rvQ==", + "dev": true + }, "asynckit": { "version": "0.4.0", "resolved": "https://registry.npmjs.org/asynckit/-/asynckit-0.4.0.tgz", @@ -4558,6 +6560,12 @@ "resolved": "https://registry.npmjs.org/bytes/-/bytes-3.1.0.tgz", "integrity": "sha512-zauLjrfCG+xvoyaqLoV8bLVXXNGC4JqlxFCutSDWA6fJrTo2ZuvLYTqZ7aHBLZSMOopbzwv8f+wZcVzfVTI2Dg==" }, + "callsites": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/callsites/-/callsites-3.1.0.tgz", + "integrity": "sha512-P8BjAsXvZS+VIDUI11hHCQEv74YT67YUi5JJFNWIqL235sBmjX4+qx9Muvls5ivyNENctx46xQLQ3aTuE7ssaQ==", + "dev": true + }, "camelcase": { "version": "6.2.0", "resolved": "https://registry.npmjs.org/camelcase/-/camelcase-6.2.0.tgz", @@ -4812,6 +6820,12 @@ "resolved": "https://registry.npmjs.org/deep-extend/-/deep-extend-0.6.0.tgz", "integrity": "sha512-LOHxIOaPYdHlJRtCQfDIVZtfw/ufM8+rVj649RIHzcm/vGwQRXFt6OPqIFWsm2XEMrNIEtWR64sY1LEKD2vAOA==" }, + "deep-is": { + "version": "0.1.3", + "resolved": "https://registry.npmjs.org/deep-is/-/deep-is-0.1.3.tgz", + "integrity": "sha1-s2nW+128E+7PUk+RsHD+7cNXzzQ=", + "dev": true + }, "delayed-stream": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/delayed-stream/-/delayed-stream-1.0.0.tgz", @@ -4849,6 +6863,24 @@ "integrity": "sha512-/VTCrvm5Z0JGty/BWHljh+BAiw3IK+2j87NGMu8Nwc/f48WoDAC395uomO9ZD117ZOBaHmkX1oyLvkVM/aIT3w==", "dev": true }, + "dir-glob": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/dir-glob/-/dir-glob-3.0.1.tgz", + "integrity": "sha512-WkrWp9GR4KXfKGYzOLmTuGVi1UWFfws377n9cc55/tb6DuqyF6pcQ5AbiHEshaDpY9v6oaSr2XCDidGmMwdzIA==", + "dev": true, + "requires": { + "path-type": "^4.0.0" + } + }, + "doctrine": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/doctrine/-/doctrine-3.0.0.tgz", + "integrity": "sha512-yS+Q5i3hBf7GBkd4KG8a7eBNNWNGLTaEwwYWUijIYM7zrlYDM0BFXHjjPWlWZ1Rg7UaddZeIDmi9jF3HmqiQ2w==", + "dev": true, + "requires": { + "esutils": "^2.0.2" + } + }, "dot-prop": { "version": "4.2.1", "resolved": "https://registry.npmjs.org/dot-prop/-/dot-prop-4.2.1.tgz", @@ -4893,6 +6925,15 @@ "once": "^1.4.0" } }, + "enquirer": { + "version": "2.3.6", + "resolved": "https://registry.npmjs.org/enquirer/-/enquirer-2.3.6.tgz", + "integrity": "sha512-yjNnPr315/FjS4zIsUxYguYUPP2e1NK4d7E7ZOLiyYCcbFBiTMyID+2wvm2w6+pZ/odMA7cRkjhsPbltwBOrLg==", + "dev": true, + "requires": { + "ansi-colors": "^4.1.1" + } + }, "escalade": { "version": "3.1.1", "resolved": "https://registry.npmjs.org/escalade/-/escalade-3.1.1.tgz", @@ -4910,6 +6951,280 @@ "integrity": "sha1-G2HAViGQqN/2rjuyzwIAyhMLhtQ=", "dev": true }, + "eslint": { + "version": "7.30.0", + "resolved": "https://registry.npmjs.org/eslint/-/eslint-7.30.0.tgz", + "integrity": "sha512-VLqz80i3as3NdloY44BQSJpFw534L9Oh+6zJOUaViV4JPd+DaHwutqP7tcpkW3YiXbK6s05RZl7yl7cQn+lijg==", + "dev": true, + "requires": { + "@babel/code-frame": "7.12.11", + "@eslint/eslintrc": "^0.4.2", + "@humanwhocodes/config-array": "^0.5.0", + "ajv": "^6.10.0", + "chalk": "^4.0.0", + "cross-spawn": "^7.0.2", + "debug": "^4.0.1", + "doctrine": "^3.0.0", + "enquirer": "^2.3.5", + "escape-string-regexp": "^4.0.0", + "eslint-scope": "^5.1.1", + "eslint-utils": "^2.1.0", + "eslint-visitor-keys": "^2.0.0", + "espree": "^7.3.1", + "esquery": "^1.4.0", + "esutils": "^2.0.2", + "fast-deep-equal": "^3.1.3", + "file-entry-cache": "^6.0.1", + "functional-red-black-tree": "^1.0.1", + "glob-parent": "^5.1.2", + "globals": "^13.6.0", + "ignore": "^4.0.6", + "import-fresh": "^3.0.0", + "imurmurhash": "^0.1.4", + "is-glob": "^4.0.0", + "js-yaml": "^3.13.1", + "json-stable-stringify-without-jsonify": "^1.0.1", + "levn": "^0.4.1", + "lodash.merge": "^4.6.2", + "minimatch": "^3.0.4", + "natural-compare": "^1.4.0", + "optionator": "^0.9.1", + "progress": "^2.0.0", + "regexpp": "^3.1.0", + "semver": "^7.2.1", + "strip-ansi": "^6.0.0", + "strip-json-comments": "^3.1.0", + "table": "^6.0.9", + "text-table": "^0.2.0", + "v8-compile-cache": "^2.0.3" + }, + "dependencies": { + "ansi-regex": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.0.tgz", + "integrity": "sha512-bY6fj56OUQ0hU1KjFNDQuJFezqKdrAyFdIevADiqrWHwSlbmBNMHp5ak2f40Pm8JTFyM2mqxkG6ngkHO11f/lg==", + "dev": true + }, + "argparse": { + "version": "1.0.10", + "resolved": "https://registry.npmjs.org/argparse/-/argparse-1.0.10.tgz", + "integrity": "sha512-o5Roy6tNG4SL/FOkCAN6RzjiakZS25RLYFrcMttJqbdd8BWrnA+fGz57iN5Pb06pvBGvl5gQ0B48dJlslXvoTg==", + "dev": true, + "requires": { + "sprintf-js": "~1.0.2" + } + }, + "cross-spawn": { + "version": "7.0.3", + "resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-7.0.3.tgz", + "integrity": "sha512-iRDPJKUPVEND7dHPO8rkbOnPpyDygcDFtWjpeWNCgy8WP2rXcxXL8TskReQl6OrB2G7+UJrags1q15Fudc7G6w==", + "dev": true, + "requires": { + "path-key": "^3.1.0", + "shebang-command": "^2.0.0", + "which": "^2.0.1" + } + }, + "debug": { + "version": "4.3.1", + "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.1.tgz", + "integrity": "sha512-doEwdvm4PCeK4K3RQN2ZC2BYUBaxwLARCqZmMjtF8a51J2Rb0xpVloFRnCODwqjpwnAoao4pelN8l3RJdv3gRQ==", + "dev": true, + "requires": { + "ms": "2.1.2" + } + }, + "escape-string-regexp": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-4.0.0.tgz", + "integrity": "sha512-TtpcNJ3XAzx3Gq8sWRzJaVajRs0uVxA2YAkdb1jm2YkPz4G6egUFAyA3n5vtEIZefPk5Wa4UXbKuS5fKkJWdgA==", + "dev": true + }, + "js-yaml": { + "version": "3.14.1", + "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-3.14.1.tgz", + "integrity": "sha512-okMH7OXXJ7YrN9Ok3/SXrnu4iX9yOk+25nqX4imS2npuvTYDmo/QEZoqwZkYaIDk3jVvBOTOIEgEhaLOynBS9g==", + "dev": true, + "requires": { + "argparse": "^1.0.7", + "esprima": "^4.0.0" + } + }, + "lru-cache": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-6.0.0.tgz", + "integrity": "sha512-Jo6dJ04CmSjuznwJSS3pUeWmd/H0ffTlkXXgwZi+eq1UCmqQwCh+eLsYOYCwY991i2Fah4h1BEMCx4qThGbsiA==", + "dev": true, + "requires": { + "yallist": "^4.0.0" + } + }, + "ms": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz", + "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==", + "dev": true + }, + "path-key": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/path-key/-/path-key-3.1.1.tgz", + "integrity": "sha512-ojmeN0qd+y0jszEtoY48r0Peq5dwMEkIlCOu6Q5f41lfkswXuKtYrhgoTpLnyIcHm24Uhqx+5Tqm2InSwLhE6Q==", + "dev": true + }, + "semver": { + "version": "7.3.5", + "resolved": "https://registry.npmjs.org/semver/-/semver-7.3.5.tgz", + "integrity": "sha512-PoeGJYh8HK4BTO/a9Tf6ZG3veo/A7ZVsYrSA6J8ny9nb3B1VrpkuN+z9OE5wfE5p6H4LchYZsegiQgbJD94ZFQ==", + "dev": true, + "requires": { + "lru-cache": "^6.0.0" + } + }, + "shebang-command": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/shebang-command/-/shebang-command-2.0.0.tgz", + "integrity": "sha512-kHxr2zZpYtdmrN1qDjrrX/Z1rR1kG8Dx+gkpK1G4eXmvXswmcE1hTWBWYUzlraYw1/yZp6YuDY77YtvbN0dmDA==", + "dev": true, + "requires": { + "shebang-regex": "^3.0.0" + } + }, + "shebang-regex": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/shebang-regex/-/shebang-regex-3.0.0.tgz", + "integrity": "sha512-7++dFhtcx3353uBaq8DDR4NuxBetBzC7ZQOhmTQInHEd6bSrXdiEyzCvG07Z44UYdLShWUyXt5M/yhz8ekcb1A==", + "dev": true + }, + "strip-ansi": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.0.tgz", + "integrity": "sha512-AuvKTrTfQNYNIctbR1K/YGTR1756GycPsg7b9bdV9Duqur4gv6aKqHXah67Z8ImS7WEz5QVcOtlfW2rZEugt6w==", + "dev": true, + "requires": { + "ansi-regex": "^5.0.0" + } + }, + "strip-json-comments": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/strip-json-comments/-/strip-json-comments-3.1.1.tgz", + "integrity": "sha512-6fPc+R4ihwqP6N/aIv2f1gMH8lOVtWQHoqC4yK6oSDVVocumAsfCqjkXnqiYMhmMwS/mEHLp7Vehlt3ql6lEig==", + "dev": true + }, + "which": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/which/-/which-2.0.2.tgz", + "integrity": "sha512-BLI3Tl1TW3Pvl70l3yq3Y64i+awpwXqsGBYWkkqMtnbXgrMD+yj7rhW0kuEDxzJaYXGjEW5ogapKNMEKNMjibA==", + "dev": true, + "requires": { + "isexe": "^2.0.0" + } + } + } + }, + "eslint-scope": { + "version": "5.1.1", + "resolved": "https://registry.npmjs.org/eslint-scope/-/eslint-scope-5.1.1.tgz", + "integrity": "sha512-2NxwbF/hZ0KpepYN0cNbo+FN6XoK7GaHlQhgx/hIZl6Va0bF45RQOOwhLIy8lQDbuCiadSLCBnH2CFYquit5bw==", + "dev": true, + "requires": { + "esrecurse": "^4.3.0", + "estraverse": "^4.1.1" + } + }, + "eslint-utils": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/eslint-utils/-/eslint-utils-2.1.0.tgz", + "integrity": "sha512-w94dQYoauyvlDc43XnGB8lU3Zt713vNChgt4EWwhXAP2XkBvndfxF0AgIqKOOasjPIPzj9JqgwkwbCYD0/V3Zg==", + "dev": true, + "requires": { + "eslint-visitor-keys": "^1.1.0" + }, + "dependencies": { + "eslint-visitor-keys": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-1.3.0.tgz", + "integrity": "sha512-6J72N8UNa462wa/KFODt/PJ3IU60SDpC3QXC1Hjc1BXXpfL2C9R5+AU7jhe0F6GREqVMh4Juu+NY7xn+6dipUQ==", + "dev": true + } + } + }, + "eslint-visitor-keys": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-2.1.0.tgz", + "integrity": "sha512-0rSmRBzXgDzIsD6mGdJgevzgezI534Cer5L/vyMX0kHzT/jiB43jRhd9YUlMGYLQy2zprNmoT8qasCGtY+QaKw==", + "dev": true + }, + "espree": { + "version": "7.3.1", + "resolved": "https://registry.npmjs.org/espree/-/espree-7.3.1.tgz", + "integrity": "sha512-v3JCNCE64umkFpmkFGqzVKsOT0tN1Zr+ueqLZfpV1Ob8e+CEgPWa+OxCoGH3tnhimMKIaBm4m/vaRpJ/krRz2g==", + "dev": true, + "requires": { + "acorn": "^7.4.0", + "acorn-jsx": "^5.3.1", + "eslint-visitor-keys": "^1.3.0" + }, + "dependencies": { + "eslint-visitor-keys": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-1.3.0.tgz", + "integrity": "sha512-6J72N8UNa462wa/KFODt/PJ3IU60SDpC3QXC1Hjc1BXXpfL2C9R5+AU7jhe0F6GREqVMh4Juu+NY7xn+6dipUQ==", + "dev": true + } + } + }, + "esprima": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/esprima/-/esprima-4.0.1.tgz", + "integrity": "sha512-eGuFFw7Upda+g4p+QHvnW0RyTX/SVeJBDM/gCtMARO0cLuT2HcEKnTPvhjV6aGeqrCB/sbNop0Kszm0jsaWU4A==", + "dev": true + }, + "esquery": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/esquery/-/esquery-1.4.0.tgz", + "integrity": "sha512-cCDispWt5vHHtwMY2YrAQ4ibFkAL8RbH5YGBnZBc90MolvvfkkQcJro/aZiAQUlQ3qgrYS6D6v8Gc5G5CQsc9w==", + "dev": true, + "requires": { + "estraverse": "^5.1.0" + }, + "dependencies": { + "estraverse": { + "version": "5.2.0", + "resolved": "https://registry.npmjs.org/estraverse/-/estraverse-5.2.0.tgz", + "integrity": "sha512-BxbNGGNm0RyRYvUdHpIwv9IWzeM9XClbOxwoATuFdOE7ZE6wHL+HQ5T8hoPM+zHvmKzzsEqhgy0GrQ5X13afiQ==", + "dev": true + } + } + }, + "esrecurse": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/esrecurse/-/esrecurse-4.3.0.tgz", + "integrity": "sha512-KmfKL3b6G+RXvP8N1vr3Tq1kL/oCFgn2NYXEtqP8/L3pKapUA4G8cFVaoF3SU323CD4XypR/ffioHmkti6/Tag==", + "dev": true, + "requires": { + "estraverse": "^5.2.0" + }, + "dependencies": { + "estraverse": { + "version": "5.2.0", + "resolved": "https://registry.npmjs.org/estraverse/-/estraverse-5.2.0.tgz", + "integrity": "sha512-BxbNGGNm0RyRYvUdHpIwv9IWzeM9XClbOxwoATuFdOE7ZE6wHL+HQ5T8hoPM+zHvmKzzsEqhgy0GrQ5X13afiQ==", + "dev": true + } + } + }, + "estraverse": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/estraverse/-/estraverse-4.3.0.tgz", + "integrity": "sha512-39nnKffWz8xN1BU/2c79n9nB9HDzo0niYUqx6xyqUnyoAnQyyWpOTdZEeiCch8BBu515t4wp9ZmgVfVhn9EBpw==", + "dev": true + }, + "esutils": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/esutils/-/esutils-2.0.3.tgz", + "integrity": "sha512-kVscqXk4OCp68SZ0dkgEKVi6/8ij300KBWTJq32P/dYeWTSwK41WyTxalN1eRmA5Z9UU/LX9D7FWSmV9SAYx6g==", + "dev": true + }, "etag": { "version": "1.8.1", "resolved": "https://registry.npmjs.org/etag/-/etag-1.8.1.tgz", @@ -4999,6 +7314,55 @@ "resolved": "https://registry.npmjs.org/express-rate-limit/-/express-rate-limit-5.1.3.tgz", "integrity": "sha512-TINcxve5510pXj4n9/1AMupkj3iWxl3JuZaWhCdYDlZeoCPqweGZrxbrlqTCFb1CT5wli7s8e2SH/Qz2c9GorA==" }, + "fast-deep-equal": { + "version": "3.1.3", + "resolved": "https://registry.npmjs.org/fast-deep-equal/-/fast-deep-equal-3.1.3.tgz", + "integrity": "sha512-f3qQ9oQy9j2AhBe/H9VC91wLmKBCCU/gDOnKNAYG5hswO7BLKj09Hc5HYNz9cGI++xlpDCIgDaitVs03ATR84Q==", + "dev": true + }, + "fast-glob": { + "version": "3.2.6", + "resolved": "https://registry.npmjs.org/fast-glob/-/fast-glob-3.2.6.tgz", + "integrity": "sha512-GnLuqj/pvQ7pX8/L4J84nijv6sAnlwvSDpMkJi9i7nPmPxGtRPkBSStfvDW5l6nMdX9VWe+pkKWFTgD+vF2QSQ==", + "dev": true, + "requires": { + "@nodelib/fs.stat": "^2.0.2", + "@nodelib/fs.walk": "^1.2.3", + "glob-parent": "^5.1.2", + "merge2": "^1.3.0", + "micromatch": "^4.0.4" + } + }, + "fast-json-stable-stringify": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/fast-json-stable-stringify/-/fast-json-stable-stringify-2.1.0.tgz", + "integrity": "sha512-lhd/wF+Lk98HZoTCtlVraHtfh5XYijIjalXck7saUtuanSDyLMxnHhSXEDJqHxD7msR8D0uCmqlkwjCV8xvwHw==", + "dev": true + }, + "fast-levenshtein": { + "version": "2.0.6", + "resolved": "https://registry.npmjs.org/fast-levenshtein/-/fast-levenshtein-2.0.6.tgz", + "integrity": "sha1-PYpcZog6FqMMqGQ+hR8Zuqd5eRc=", + "dev": true + }, + "fastq": { + "version": "1.11.0", + "resolved": "https://registry.npmjs.org/fastq/-/fastq-1.11.0.tgz", + "integrity": "sha512-7Eczs8gIPDrVzT+EksYBcupqMyxSHXXrHOLRRxU2/DicV8789MRBRR8+Hc2uWzUupOs4YS4JzBmBxjjCVBxD/g==", + "dev": true, + "requires": { + "reusify": "^1.0.4" + } + }, + "file-entry-cache": { + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/file-entry-cache/-/file-entry-cache-6.0.1.tgz", + "integrity": "sha512-7Gps/XWymbLk2QLYK4NzpMOrYjMhdIxXuIvy2QBsLE6ljuodKvdkWs/cpyJJ3CVIVpH0Oi1Hvg1ovbMzLdFBBg==", + "dev": true, + "requires": { + "flat-cache": "^3.0.4" + } + }, "file-uri-to-path": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/file-uri-to-path/-/file-uri-to-path-1.0.0.tgz", @@ -5043,6 +7407,33 @@ "integrity": "sha512-b6suED+5/3rTpUBdG1gupIl8MPFCAMA0QXwmljLhvCUKcUvdE4gWky9zpuGCcXHOsz4J9wPGNWq6OKpmIzz3hQ==", "dev": true }, + "flat-cache": { + "version": "3.0.4", + "resolved": "https://registry.npmjs.org/flat-cache/-/flat-cache-3.0.4.tgz", + "integrity": "sha512-dm9s5Pw7Jc0GvMYbshN6zchCA9RgQlzzEZX3vylR9IqFfS8XciblUXOKfW6SiuJ0e13eDYZoZV5wdrev7P3Nwg==", + "dev": true, + "requires": { + "flatted": "^3.1.0", + "rimraf": "^3.0.2" + }, + "dependencies": { + "rimraf": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/rimraf/-/rimraf-3.0.2.tgz", + "integrity": "sha512-JZkJMZkAGFFPP2YqXZXPbMlMBgsxzE8ILs4lMIX/2o0L9UBw9O/Y3o6wFw/i9YLapcUJWwqbi3kdxIPdC62TIA==", + "dev": true, + "requires": { + "glob": "^7.1.3" + } + } + } + }, + "flatted": { + "version": "3.2.0", + "resolved": "https://registry.npmjs.org/flatted/-/flatted-3.2.0.tgz", + "integrity": "sha512-XprP7lDrVT+kE2c2YlfiV+IfS9zxukiIOvNamPNsImNhXadSsQEbosItdL9bUQlCZXR13SvPk20BjWSWLA7m4A==", + "dev": true + }, "form-data": { "version": "3.0.0", "resolved": "https://registry.npmjs.org/form-data/-/form-data-3.0.0.tgz", @@ -5109,6 +7500,12 @@ "length-stream": "^0.1.1" } }, + "functional-red-black-tree": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/functional-red-black-tree/-/functional-red-black-tree-1.0.1.tgz", + "integrity": "sha1-GwqzvVU7Kg1jmdKcDj6gslIHgyc=", + "dev": true + }, "gauge": { "version": "2.7.4", "resolved": "https://registry.npmjs.org/gauge/-/gauge-2.7.4.tgz", @@ -5180,9 +7577,9 @@ } }, "glob-parent": { - "version": "5.1.1", - "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-5.1.1.tgz", - "integrity": "sha512-FnI+VGOpnlGHWZxthPGR+QhR78fuiK0sNLkHQv+bL9fQi57lNNdquIbna/WrfROrolq8GK5Ek6BiMwqL/voRYQ==", + "version": "5.1.2", + "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-5.1.2.tgz", + "integrity": "sha512-AOIgSQCepiJYwP3ARnGx+5VnTu2HBYdzbGP45eLw1vr3zB3vZLeyed1sC9hnbcOc9/SrMyM5RPQrkGz4aS9Zow==", "dev": true, "requires": { "is-glob": "^4.0.1" @@ -5197,6 +7594,37 @@ "ini": "^1.3.4" } }, + "globals": { + "version": "13.9.0", + "resolved": "https://registry.npmjs.org/globals/-/globals-13.9.0.tgz", + "integrity": "sha512-74/FduwI/JaIrr1H8e71UbDE+5x7pIPs1C2rrwC52SszOo043CsWOZEMW7o2Y58xwm9b+0RBKDxY5n2sUpEFxA==", + "dev": true, + "requires": { + "type-fest": "^0.20.2" + } + }, + "globby": { + "version": "11.0.4", + "resolved": "https://registry.npmjs.org/globby/-/globby-11.0.4.tgz", + "integrity": "sha512-9O4MVG9ioZJ08ffbcyVYyLOJLk5JQ688pJ4eMGLpdWLHq/Wr1D9BlriLQyL0E+jbkuePVZXYFj47QM/v093wHg==", + "dev": true, + "requires": { + "array-union": "^2.1.0", + "dir-glob": "^3.0.1", + "fast-glob": "^3.1.1", + "ignore": "^5.1.4", + "merge2": "^1.3.0", + "slash": "^3.0.0" + }, + "dependencies": { + "ignore": { + "version": "5.1.8", + "resolved": "https://registry.npmjs.org/ignore/-/ignore-5.1.8.tgz", + "integrity": "sha512-BMpfD7PpiETpBl/A6S498BaIJ6Y/ABT93ETbby2fP00v4EbvPBXWEoaR1UBPKs3iR53pJY7EtZk5KACI57i1Uw==", + "dev": true + } + } + }, "got": { "version": "6.7.1", "resolved": "https://registry.npmjs.org/got/-/got-6.7.1.tgz", @@ -5274,12 +7702,28 @@ "resolved": "https://registry.npmjs.org/ieee754/-/ieee754-1.2.1.tgz", "integrity": "sha512-dcyqhDvX1C46lXZcVqCpK+FtMRQVdIMN6/Df5js2zouUsqG7I6sFxitIC+7KYK29KdXOLHdu9zL4sFnoVQnqaA==" }, + "ignore": { + "version": "4.0.6", + "resolved": "https://registry.npmjs.org/ignore/-/ignore-4.0.6.tgz", + "integrity": "sha512-cyFDKrqc/YdcWFniJhzI42+AzS+gNwmUzOSFcRCQYwySuBBBy/KjuxWLZ/FHEH6Moq1NizMOBWyTcv8O4OZIMg==", + "dev": true + }, "ignore-by-default": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/ignore-by-default/-/ignore-by-default-1.0.1.tgz", "integrity": "sha1-SMptcvbGo68Aqa1K5odr44ieKwk=", "dev": true }, + "import-fresh": { + "version": "3.3.0", + "resolved": "https://registry.npmjs.org/import-fresh/-/import-fresh-3.3.0.tgz", + "integrity": "sha512-veYYhQa+D1QBKznvhUHxb8faxlrwUnxseDAbAp457E0wLNio2bOSKnjYDhMj+YiAq61xrMGhQk9iXVk5FzgQMw==", + "dev": true, + "requires": { + "parent-module": "^1.0.0", + "resolve-from": "^4.0.0" + } + }, "import-lazy": { "version": "2.1.0", "resolved": "https://registry.npmjs.org/import-lazy/-/import-lazy-2.1.0.tgz", @@ -5437,6 +7881,12 @@ "resolved": "https://registry.npmjs.org/iso8601-duration/-/iso8601-duration-1.2.0.tgz", "integrity": "sha512-ErTBd++b17E8nmWII1K1uZtBgD1E8RjyvwmxlCjPHNqHMD7gmcMHOw0E8Ro/6+QT4PhHRSnnMo7bxa1vFPkwhg==" }, + "js-tokens": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/js-tokens/-/js-tokens-4.0.0.tgz", + "integrity": "sha512-RdJUflcE3cUzKiMqQgsCu06FPu9UdIJO0beYbPhHN4k6apgJtifcoCtT9bcxOpYBtpD2kCM6Sbzg4CausW/PKQ==", + "dev": true + }, "js-yaml": { "version": "4.0.0", "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-4.0.0.tgz", @@ -5446,6 +7896,18 @@ "argparse": "^2.0.1" } }, + "json-schema-traverse": { + "version": "0.4.1", + "resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-0.4.1.tgz", + "integrity": "sha512-xbbCH5dCYU5T8LcEhhuh7HJ88HXuW3qsI3Y0zOZFKfZEHcpWiHU/Jxzk629Brsab/mMiHQti9wMP+845RPe3Vg==", + "dev": true + }, + "json-stable-stringify-without-jsonify": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/json-stable-stringify-without-jsonify/-/json-stable-stringify-without-jsonify-1.0.1.tgz", + "integrity": "sha1-nbe1lJatPzz+8wp1FC0tkwrXJlE=", + "dev": true + }, "jsonfile": { "version": "2.4.0", "resolved": "https://registry.npmjs.org/jsonfile/-/jsonfile-2.4.0.tgz", @@ -5485,6 +7947,16 @@ "pass-stream": "~0.1.0" } }, + "levn": { + "version": "0.4.1", + "resolved": "https://registry.npmjs.org/levn/-/levn-0.4.1.tgz", + "integrity": "sha512-+bT2uH4E5LGE7h/n3evcS/sQlJXCpIp6ym8OWJ5eV6+67Dsql/LaaT7qJBAt2rzfoa/5QBGBhxDix1dMt2kQKQ==", + "dev": true, + "requires": { + "prelude-ls": "^1.2.1", + "type-check": "~0.4.0" + } + }, "locate-path": { "version": "6.0.0", "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-6.0.0.tgz", @@ -5499,6 +7971,12 @@ "resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.21.tgz", "integrity": "sha512-v2kDEe57lecTulaDIuNTPy3Ry4gLGJ6Z1O3vE1krgXZNrsQ+LFTGHVxVjcXPs17LhbZVGedAJv8XZ1tvj5FvSg==" }, + "lodash.clonedeep": { + "version": "4.5.0", + "resolved": "https://registry.npmjs.org/lodash.clonedeep/-/lodash.clonedeep-4.5.0.tgz", + "integrity": "sha1-4j8/nE+Pvd6HJSnBBxhXoIblzO8=", + "dev": true + }, "lodash.flattendeep": { "version": "4.4.0", "resolved": "https://registry.npmjs.org/lodash.flattendeep/-/lodash.flattendeep-4.4.0.tgz", @@ -5510,6 +7988,18 @@ "integrity": "sha1-LRd/ZS+jHpObRDjVNBSZ36OCXpk=", "dev": true }, + "lodash.merge": { + "version": "4.6.2", + "resolved": "https://registry.npmjs.org/lodash.merge/-/lodash.merge-4.6.2.tgz", + "integrity": "sha512-0KpjqXRVvrYyCsX1swR/XTK0va6VQkQM6MNo7PqW77ByjAhoARA8EfrP1N4+KlKj8YS0ZUCtRT/YUuhyYDujIQ==", + "dev": true + }, + "lodash.truncate": { + "version": "4.4.2", + "resolved": "https://registry.npmjs.org/lodash.truncate/-/lodash.truncate-4.4.2.tgz", + "integrity": "sha1-WjUNoLERO4N+z//VgSy+WNbq4ZM=", + "dev": true + }, "log-symbols": { "version": "4.0.0", "resolved": "https://registry.npmjs.org/log-symbols/-/log-symbols-4.0.0.tgz", @@ -5566,11 +8056,27 @@ "resolved": "https://registry.npmjs.org/merge-descriptors/-/merge-descriptors-1.0.1.tgz", "integrity": "sha1-sAqqVW3YtEVoFQ7J0blT8/kMu2E=" }, + "merge2": { + "version": "1.4.1", + "resolved": "https://registry.npmjs.org/merge2/-/merge2-1.4.1.tgz", + "integrity": "sha512-8q7VEgMJW4J8tcfVPy8g09NcQwZdbwFEqhe/WZkoIzjn/3TGDwtOCYtXGxA3O8tPzpczCCDgv+P2P5y00ZJOOg==", + "dev": true + }, "methods": { "version": "1.1.2", "resolved": "https://registry.npmjs.org/methods/-/methods-1.1.2.tgz", "integrity": "sha1-VSmk1nZUE07cxSZmVoNbD4Ua/O4=" }, + "micromatch": { + "version": "4.0.4", + "resolved": "https://registry.npmjs.org/micromatch/-/micromatch-4.0.4.tgz", + "integrity": "sha512-pRmzw/XUcwXGpD9aI9q/0XOwLNygjETJ8y0ao0wdqprrzDa4YnxLcz7fQRZr8voh8V10kGhABbNcHVk5wHgWwg==", + "dev": true, + "requires": { + "braces": "^3.0.1", + "picomatch": "^2.2.3" + } + }, "mime": { "version": "1.6.0", "resolved": "https://registry.npmjs.org/mime/-/mime-1.6.0.tgz", @@ -5789,6 +8295,12 @@ "resolved": "https://registry.npmjs.org/napi-build-utils/-/napi-build-utils-1.0.2.tgz", "integrity": "sha512-ONmRUqK7zj7DWX0D9ADe03wbwOBZxNAfF20PlGfCWQcD3+/MakShIHrMqx9YwPTfxDdF1zLeL+RGZiR9kGMLdg==" }, + "natural-compare": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/natural-compare/-/natural-compare-1.4.0.tgz", + "integrity": "sha1-Sr6/7tdUHywnrPspvbvRXI1bpPc=", + "dev": true + }, "negotiator": { "version": "0.6.2", "resolved": "https://registry.npmjs.org/negotiator/-/negotiator-0.6.2.tgz", @@ -5941,6 +8453,20 @@ "wrappy": "1" } }, + "optionator": { + "version": "0.9.1", + "resolved": "https://registry.npmjs.org/optionator/-/optionator-0.9.1.tgz", + "integrity": "sha512-74RlY5FCnhq4jRxVUPKDaRwrVNXMqsGsiW6AJw4XK8hmtm10wC0ypZBLw5IIp85NZMr91+qd1RvvENwg7jjRFw==", + "dev": true, + "requires": { + "deep-is": "^0.1.3", + "fast-levenshtein": "^2.0.6", + "levn": "^0.4.1", + "prelude-ls": "^1.2.1", + "type-check": "^0.4.0", + "word-wrap": "^1.2.3" + } + }, "os-tmpdir": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/os-tmpdir/-/os-tmpdir-1.0.2.tgz", @@ -5987,6 +8513,15 @@ "resolved": "https://registry.npmjs.org/packet-reader/-/packet-reader-1.0.0.tgz", "integrity": "sha512-HAKu/fG3HpHFO0AA8WE8q2g+gBJaZ9MG7fcKk+IJPLTGAD6Psw4443l+9DGRbOIh3/aXr7Phy0TjilYivJo5XQ==" }, + "parent-module": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/parent-module/-/parent-module-1.0.1.tgz", + "integrity": "sha512-GQ2EWRpQV8/o+Aw8YqtfZZPfNRWZYkbidE9k5rpl/hC3vtHHBfGm2Ifi6qWV+coDGkrUKZAxE3Lot5kcsRlh+g==", + "dev": true, + "requires": { + "callsites": "^3.0.0" + } + }, "parseurl": { "version": "1.3.3", "resolved": "https://registry.npmjs.org/parseurl/-/parseurl-1.3.3.tgz", @@ -6034,6 +8569,12 @@ "resolved": "https://registry.npmjs.org/path-to-regexp/-/path-to-regexp-0.1.7.tgz", "integrity": "sha1-32BBeABfUi8V60SQ5yR6G/qmf4w=" }, + "path-type": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/path-type/-/path-type-4.0.0.tgz", + "integrity": "sha512-gDKb8aZMDeD/tZWs9P6+q0J9Mwkdl6xMV8TjnGP3qJVJ06bdMgkbBlLU8IdfOsIsFz2BW1rNVT3XuNEl8zPAvw==", + "dev": true + }, "pg": { "version": "8.5.1", "resolved": "https://registry.npmjs.org/pg/-/pg-8.5.1.tgz", @@ -6089,9 +8630,9 @@ } }, "picomatch": { - "version": "2.2.2", - "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-2.2.2.tgz", - "integrity": "sha512-q0M/9eZHzmr0AulXyPwNfZjtwZ/RBZlbN3K3CErVrk50T2ASYI7Bye0EvekFY3IP1Nt2DHu0re+V2ZHIpMkuWg==", + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-2.3.0.tgz", + "integrity": "sha512-lY1Q/PiJGC2zOv/z391WOTD+Z02bCgsFfvxoXXf6h7kv9o+WmsmzYqrAwY63sNgOxE4xEdq0WyUnXfKeBrSvYw==", "dev": true }, "pify": { @@ -6144,6 +8685,12 @@ "tunnel-agent": "^0.6.0" } }, + "prelude-ls": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/prelude-ls/-/prelude-ls-1.2.1.tgz", + "integrity": "sha512-vkcDPrRZo1QZLbn5RLGPpg/WmIQ65qoWWhcGKf/b5eplkkarX0m9z8ppCat4mlOqUsWpyNuYgO3VRyrYHSzX5g==", + "dev": true + }, "prepend-http": { "version": "1.0.4", "resolved": "https://registry.npmjs.org/prepend-http/-/prepend-http-1.0.4.tgz", @@ -6155,6 +8702,12 @@ "resolved": "https://registry.npmjs.org/process-nextick-args/-/process-nextick-args-2.0.1.tgz", "integrity": "sha512-3ouUOpQhtgrbOa17J7+uxOTpITYWaGP7/AhoR3+A+/1e9skrzelGi/dXzEYyvbxubEF6Wn2ypscTKiKJFFn1ag==" }, + "progress": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/progress/-/progress-2.0.3.tgz", + "integrity": "sha512-7PiHtLll5LdnKIMw100I+8xJXR5gW2QwWYkT6iJva0bXitZKa/XMrSbdmg3r2Xnaidz9Qumd0VPaMrZlF9V9sA==", + "dev": true + }, "promise": { "version": "7.3.1", "resolved": "https://registry.npmjs.org/promise/-/promise-7.3.1.tgz", @@ -6199,6 +8752,12 @@ "once": "^1.3.1" } }, + "punycode": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/punycode/-/punycode-2.1.1.tgz", + "integrity": "sha512-XRsRjdf+j5ml+y/6GKHPZbrF/8p2Yga0JPtdqTIY2Xe5ohJPD9saDJJLPvp9+NSBprVvevdXZybnj2cv8OEd0A==", + "dev": true + }, "q": { "version": "1.5.1", "resolved": "https://registry.npmjs.org/q/-/q-1.5.1.tgz", @@ -6209,6 +8768,12 @@ "resolved": "https://registry.npmjs.org/qs/-/qs-6.7.0.tgz", "integrity": "sha512-VCdBRNFTX1fyE7Nb6FYoURo/SPe62QCaAyzJvUjwRaIsc+NePBEniHlvxFmmX56+HZphIGtV0XeCirBtpDrTyQ==" }, + "queue-microtask": { + "version": "1.2.3", + "resolved": "https://registry.npmjs.org/queue-microtask/-/queue-microtask-1.2.3.tgz", + "integrity": "sha512-NuaNSa6flKT5JaSYQzJok04JzTL1CA6aGhv5rfLW3PgqA+M2ChpZQnAC8h8i4ZFkBS8X5RqkDBHA7r4hej3K9A==", + "dev": true + }, "randombytes": { "version": "2.1.0", "resolved": "https://registry.npmjs.org/randombytes/-/randombytes-2.1.0.tgz", @@ -6298,6 +8863,12 @@ "resolved": "https://registry.npmjs.org/regenerator-runtime/-/regenerator-runtime-0.11.1.tgz", "integrity": "sha512-MguG95oij0fC3QV3URf4V2SDYGJhJnJGqvIIgdECeODCT98wSWDAJ94SSuVpYQUoTcGUIL6L4yNB7j1DFFHSBg==" }, + "regexpp": { + "version": "3.2.0", + "resolved": "https://registry.npmjs.org/regexpp/-/regexpp-3.2.0.tgz", + "integrity": "sha512-pq2bWo9mVD43nbts2wGv17XLiNLya+GklZ8kaDLV2Z08gDCsGpnKn9BFMepvWuHCbyVvY7J5o5+BVvoQbmlJLg==", + "dev": true + }, "registry-auth-token": { "version": "3.4.0", "resolved": "https://registry.npmjs.org/registry-auth-token/-/registry-auth-token-3.4.0.tgz", @@ -6323,6 +8894,24 @@ "integrity": "sha1-jGStX9MNqxyXbiNE/+f3kqam30I=", "dev": true }, + "require-from-string": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/require-from-string/-/require-from-string-2.0.2.tgz", + "integrity": "sha512-Xf0nWe6RseziFMu+Ap9biiUbmplq6S9/p+7w7YXP/JBHhrUDDUhwa+vANyubuqfZWTveU//DYVGsDG7RKL/vEw==", + "dev": true + }, + "resolve-from": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/resolve-from/-/resolve-from-4.0.0.tgz", + "integrity": "sha512-pb/MYmXstAkysRFx8piNI1tGFNQIFA3vkE3Gq4EuA1dF6gHp/+vgZqsCGJapvy8N3Q+4o7FwvquPJcnZ7RYy4g==", + "dev": true + }, + "reusify": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/reusify/-/reusify-1.0.4.tgz", + "integrity": "sha512-U9nH88a3fc/ekCF1l0/UP1IosiuIjyTh7hBvXVMHYgVcfGvt897Xguj2UOLDeI5BG2m7/uwyaLVT6fbtCwTyzw==", + "dev": true + }, "rimraf": { "version": "2.7.1", "resolved": "https://registry.npmjs.org/rimraf/-/rimraf-2.7.1.tgz", @@ -6331,6 +8920,15 @@ "glob": "^7.1.3" } }, + "run-parallel": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/run-parallel/-/run-parallel-1.2.0.tgz", + "integrity": "sha512-5l4VyZR86LZ/lDxZTR6jqL8AFE2S0IFLMP26AbjsLVADxHdhB/c0GUsH+y39UfCi3dzz8OlQuPmnaJOMoDHQBA==", + "dev": true, + "requires": { + "queue-microtask": "^1.2.2" + } + }, "safe-buffer": { "version": "5.2.0", "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.2.0.tgz", @@ -6470,6 +9068,31 @@ } } }, + "slash": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/slash/-/slash-3.0.0.tgz", + "integrity": "sha512-g9Q1haeby36OSStwb4ntCGGGaKsaVSjQ68fBxoQcutl5fS1vuY18H3wSt3jFyFtrkx+Kz0V1G85A4MyAdDMi2Q==", + "dev": true + }, + "slice-ansi": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/slice-ansi/-/slice-ansi-4.0.0.tgz", + "integrity": "sha512-qMCMfhY040cVHT43K9BFygqYbUPFZKHOg7K73mtTWJRb8pyP3fzf4Ixd5SzdEJQ6MRUg/WBnOLxghZtKKurENQ==", + "dev": true, + "requires": { + "ansi-styles": "^4.0.0", + "astral-regex": "^2.0.0", + "is-fullwidth-code-point": "^3.0.0" + }, + "dependencies": { + "is-fullwidth-code-point": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-3.0.0.tgz", + "integrity": "sha512-zymm5+u+sCsSWyD9qNaejV3DFvhCKclKdizYaJUuHA83RLjb7nSuGnddCHGv0hk+KY7BMAlsWeK4Ueg6EV6XQg==", + "dev": true + } + } + }, "source-map": { "version": "0.6.1", "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", @@ -6494,6 +9117,12 @@ "readable-stream": "^3.0.0" } }, + "sprintf-js": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/sprintf-js/-/sprintf-js-1.0.3.tgz", + "integrity": "sha1-BOaSb2YolTVPPdAVIDYzuFcpfiw=", + "dev": true + }, "sqlstring": { "version": "2.3.1", "resolved": "https://registry.npmjs.org/sqlstring/-/sqlstring-2.3.1.tgz", @@ -6636,6 +9265,72 @@ "get-port": "^3.1.0" } }, + "table": { + "version": "6.7.1", + "resolved": "https://registry.npmjs.org/table/-/table-6.7.1.tgz", + "integrity": "sha512-ZGum47Yi6KOOFDE8m223td53ath2enHcYLgOCjGr5ngu8bdIARQk6mN/wRMv4yMRcHnCSnHbCEha4sobQx5yWg==", + "dev": true, + "requires": { + "ajv": "^8.0.1", + "lodash.clonedeep": "^4.5.0", + "lodash.truncate": "^4.4.2", + "slice-ansi": "^4.0.0", + "string-width": "^4.2.0", + "strip-ansi": "^6.0.0" + }, + "dependencies": { + "ajv": { + "version": "8.6.0", + "resolved": "https://registry.npmjs.org/ajv/-/ajv-8.6.0.tgz", + "integrity": "sha512-cnUG4NSBiM4YFBxgZIj/In3/6KX+rQ2l2YPRVcvAMQGWEPKuXoPIhxzwqh31jA3IPbI4qEOp/5ILI4ynioXsGQ==", + "dev": true, + "requires": { + "fast-deep-equal": "^3.1.1", + "json-schema-traverse": "^1.0.0", + "require-from-string": "^2.0.2", + "uri-js": "^4.2.2" + } + }, + "ansi-regex": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.0.tgz", + "integrity": "sha512-bY6fj56OUQ0hU1KjFNDQuJFezqKdrAyFdIevADiqrWHwSlbmBNMHp5ak2f40Pm8JTFyM2mqxkG6ngkHO11f/lg==", + "dev": true + }, + "is-fullwidth-code-point": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-3.0.0.tgz", + "integrity": "sha512-zymm5+u+sCsSWyD9qNaejV3DFvhCKclKdizYaJUuHA83RLjb7nSuGnddCHGv0hk+KY7BMAlsWeK4Ueg6EV6XQg==", + "dev": true + }, + "json-schema-traverse": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-1.0.0.tgz", + "integrity": "sha512-NM8/P9n3XjXhIZn1lLhkFaACTOURQXjWhV4BA/RnOv8xvgqtqpAX9IO4mRQxSx1Rlo4tqzeqb0sOlruaOy3dug==", + "dev": true + }, + "string-width": { + "version": "4.2.2", + "resolved": "https://registry.npmjs.org/string-width/-/string-width-4.2.2.tgz", + "integrity": "sha512-XBJbT3N4JhVumXE0eoLU9DCjcaF92KLNqTmFCnG1pf8duUxFGwtP6AD6nkjw9a3IdiRtL3E2w3JDiE/xi3vOeA==", + "dev": true, + "requires": { + "emoji-regex": "^8.0.0", + "is-fullwidth-code-point": "^3.0.0", + "strip-ansi": "^6.0.0" + } + }, + "strip-ansi": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.0.tgz", + "integrity": "sha512-AuvKTrTfQNYNIctbR1K/YGTR1756GycPsg7b9bdV9Duqur4gv6aKqHXah67Z8ImS7WEz5QVcOtlfW2rZEugt6w==", + "dev": true, + "requires": { + "ansi-regex": "^5.0.0" + } + } + } + }, "tar": { "version": "6.1.0", "resolved": "https://registry.npmjs.org/tar/-/tar-6.1.0.tgz", @@ -6688,6 +9383,12 @@ "execa": "^0.7.0" } }, + "text-table": { + "version": "0.2.0", + "resolved": "https://registry.npmjs.org/text-table/-/text-table-0.2.0.tgz", + "integrity": "sha1-f17oI66AUgfACvLfSoTsP8+lcLQ=", + "dev": true + }, "then-mysql": { "version": "1.1.1", "resolved": "https://registry.npmjs.org/then-mysql/-/then-mysql-1.1.1.tgz", @@ -6762,6 +9463,21 @@ } } }, + "tslib": { + "version": "1.14.1", + "resolved": "https://registry.npmjs.org/tslib/-/tslib-1.14.1.tgz", + "integrity": "sha512-Xni35NKzjgMrwevysHTCArtLDpPvye8zV/0E4EyYn43P7/7qvQwPh9BGkHewbMulVntbigmcT7rdX3BNo9wRJg==", + "dev": true + }, + "tsutils": { + "version": "3.21.0", + "resolved": "https://registry.npmjs.org/tsutils/-/tsutils-3.21.0.tgz", + "integrity": "sha512-mHKK3iUXL+3UF6xL5k0PEhKRUBKPBCv/+RkEOpjRWxxx27KKRBmmA60A9pgOUvMi8GKhRMPEmjBRPzs2W7O1OA==", + "dev": true, + "requires": { + "tslib": "^1.8.1" + } + }, "tunnel-agent": { "version": "0.6.0", "resolved": "https://registry.npmjs.org/tunnel-agent/-/tunnel-agent-0.6.0.tgz", @@ -6770,12 +9486,27 @@ "safe-buffer": "^5.0.1" } }, + "type-check": { + "version": "0.4.0", + "resolved": "https://registry.npmjs.org/type-check/-/type-check-0.4.0.tgz", + "integrity": "sha512-XleUoc9uwGXqjWwXaUTZAmzMcFZ5858QA2vvx1Ur5xIcixXIP+8LnFDgRplU30us6teqdlskFfu+ae4K79Ooew==", + "dev": true, + "requires": { + "prelude-ls": "^1.2.1" + } + }, "type-detect": { "version": "4.0.8", "resolved": "https://registry.npmjs.org/type-detect/-/type-detect-4.0.8.tgz", "integrity": "sha512-0fr/mIH1dlO+x7TlcMy+bIDqKPsw/70tVyeHW787goQjhmqaZe10uwLujubK9q9Lg6Fiho1KUKDYz0Z7k7g5/g==", "dev": true }, + "type-fest": { + "version": "0.20.2", + "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-0.20.2.tgz", + "integrity": "sha512-Ne+eE4r0/iWnpAxD852z3A+N0Bt5RN//NjJwRd2VFHEmrywxf5vsZlh4R6lixl6B+wz/8d+maTSAkN1FIkI3LQ==", + "dev": true + }, "type-is": { "version": "1.6.18", "resolved": "https://registry.npmjs.org/type-is/-/type-is-1.6.18.tgz", @@ -6874,6 +9605,15 @@ } } }, + "uri-js": { + "version": "4.4.1", + "resolved": "https://registry.npmjs.org/uri-js/-/uri-js-4.4.1.tgz", + "integrity": "sha512-7rKUyy33Q1yc98pQ1DAmLtwX109F7TIfWlW1Ydo8Wl1ii1SeHieeh0HHfPeL2fMXK6z0s8ecKs9frCuLJvndBg==", + "dev": true, + "requires": { + "punycode": "^2.1.0" + } + }, "url-parse-lax": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/url-parse-lax/-/url-parse-lax-1.0.0.tgz", @@ -6898,6 +9638,12 @@ "resolved": "https://registry.npmjs.org/uuid/-/uuid-3.4.0.tgz", "integrity": "sha512-HjSDRw6gZE5JMggctHBcjVak08+KEVhSIiDzFnT9S9aegmp85S/bReBVTb4QTFaRNptJ9kuYaNhnbNEOkbKb/A==" }, + "v8-compile-cache": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/v8-compile-cache/-/v8-compile-cache-2.3.0.tgz", + "integrity": "sha512-l8lCEmLcLYZh4nbunNZvQCJc5pv7+RCwa8q/LdUx8u7lsWvPDKmpodJAJNwkAhJC//dFY48KuIEmjtd4RViDrA==", + "dev": true + }, "vary": { "version": "1.1.2", "resolved": "https://registry.npmjs.org/vary/-/vary-1.1.2.tgz", @@ -6929,6 +9675,12 @@ "string-width": "^2.1.1" } }, + "word-wrap": { + "version": "1.2.3", + "resolved": "https://registry.npmjs.org/word-wrap/-/word-wrap-1.2.3.tgz", + "integrity": "sha512-Hz/mrNwitNRh/HUAtM/VT/5VH+ygD6DV7mYKZAtHOrbs8U7lvPS6xf7EJKMF0uW1KJCl0H701g3ZGus+muE5vQ==", + "dev": true + }, "workerpool": { "version": "6.1.0", "resolved": "https://registry.npmjs.org/workerpool/-/workerpool-6.1.0.tgz", diff --git a/package.json b/package.json index 87a50fa..cc9a2e0 100644 --- a/package.json +++ b/package.json @@ -8,7 +8,9 @@ "dev": "nodemon", "dev:bash": "nodemon -x 'npm test ; npm start'", "start": "ts-node src/index.ts", - "tsc": "tsc -p tsconfig.json" + "tsc": "tsc -p tsconfig.json", + "lint": "eslint src", + "lint:fix": "eslint src --fix" }, "author": "Ajay Ramachandran", "license": "MIT", @@ -38,6 +40,9 @@ "@types/pg": "^7.14.10", "@types/redis": "^2.8.28", "@types/request": "^2.48.5", + "@typescript-eslint/eslint-plugin": "^4.28.1", + "@typescript-eslint/parser": "^4.28.1", + "eslint": "^7.30.0", "mocha": "^8.4.0", "nodemon": "^2.0.2", "sinon": "^9.2.0", From 401be9d9fa45f70368982941c8f9411331ba4f01 Mon Sep 17 00:00:00 2001 From: Michael C Date: Sat, 3 Jul 2021 22:51:26 -0400 Subject: [PATCH 2/4] match sponsorblock warn rules --- .eslintrc.js | 11 ++--------- 1 file changed, 2 insertions(+), 9 deletions(-) diff --git a/.eslintrc.js b/.eslintrc.js index a898b01..ca8daea 100644 --- a/.eslintrc.js +++ b/.eslintrc.js @@ -16,14 +16,7 @@ module.exports = { plugins: ["@typescript-eslint"], rules: { // TODO: Remove warn rules when not needed anymore - "@typescript-eslint/no-this-alias": "warn", - "no-self-assign": "warn", - "@typescript-eslint/no-empty-interface": "warn", - "@typescript-eslint/ban-types": "warn", - }, - settings: { - react: { - version: "detect", - }, + "no-self-assign": "off", + "@typescript-eslint/no-empty-interface": "off", }, }; \ No newline at end of file From d89b26b77dd16b66bc14c35b6b349a0ccbc29a8c Mon Sep 17 00:00:00 2001 From: Michael C Date: Sun, 4 Jul 2021 01:34:31 -0400 Subject: [PATCH 3/4] fix eslint-errors --- .eslintrc.js | 24 ++++++++++ src/app.ts | 9 ++-- src/config.ts | 4 +- src/databases/Mysql.ts | 5 ++- src/databases/Postgres.ts | 6 +-- src/databases/Sqlite.ts | 8 ++-- src/databases/databases.ts | 4 +- src/middleware/apiCsp.ts | 2 +- src/middleware/cors.ts | 4 +- src/middleware/logger.ts | 2 +- src/middleware/userCounter.ts | 2 +- src/routes/addUnlistedVideo.ts | 4 +- src/routes/addUserAsVIP.ts | 2 +- src/routes/deleteLockCategories.ts | 2 +- src/routes/dumpDatabase.ts | 17 ++++--- src/routes/getDaysSavedFormatted.ts | 4 +- src/routes/getIsUserVIP.ts | 2 +- src/routes/getSavedTimeForUser.ts | 4 +- src/routes/getSegmentInfo.ts | 12 ++--- src/routes/getSkipSegments.ts | 12 ++--- src/routes/getSkipSegmentsByHash.ts | 8 ++-- src/routes/getTopUsers.ts | 6 +-- src/routes/getTotalStats.ts | 10 ++--- src/routes/getUserID.ts | 24 +++++----- src/routes/getUserInfo.ts | 18 ++++---- src/routes/getUsername.ts | 5 +-- src/routes/getViewsForUser.ts | 5 +-- src/routes/oldGetVideoSponsorTimes.ts | 6 +-- src/routes/oldSubmitSponsorTimes.ts | 3 +- src/routes/postClearCache.ts | 12 ++--- src/routes/postLockCategories.ts | 10 ++--- src/routes/postPurgeAllSegments.ts | 2 +- src/routes/postSegmentShift.ts | 2 +- src/routes/postSkipSegments.ts | 32 +++++--------- src/routes/postWarning.ts | 4 +- src/routes/setUsername.ts | 4 +- src/routes/shadowBanUser.ts | 6 +-- src/routes/viewedVideoSponsorTime.ts | 2 +- src/routes/voteOnSponsorTime.ts | 15 ++++--- src/utils/diskCache.ts | 16 +++---- src/utils/getFormattedTime.ts | 6 +-- src/utils/getHash.ts | 2 +- src/utils/getSubmissionUUID.ts | 3 +- src/utils/logger.ts | 2 +- src/utils/queryCacher.ts | 4 +- src/utils/redis.ts | 6 +-- src/utils/webhookUtils.ts | 11 +++-- src/utils/youtubeApi.ts | 8 ++-- test/cases/dbUpgrade.ts | 5 +-- test/cases/getIsUserVIP.ts | 8 ++-- test/cases/getSavedTimeForUser.ts | 4 +- test/cases/getSegmentInfo.ts | 46 +++++++++---------- test/cases/getSkipSegments.ts | 30 ++++++------- test/cases/getSkipSegmentsByHash.ts | 32 +++++++------- test/cases/getUserID.ts | 44 +++++++++--------- test/cases/getUserInfo.ts | 24 +++++----- test/cases/lockCategoriesRecords.ts | 47 +++++++++----------- test/cases/oldGetSponsorTime.ts | 10 ++--- test/cases/oldSubmitSponsorTimes.ts | 4 +- test/cases/postClearCache.ts | 2 +- test/cases/postPurgeAllSegments.ts | 2 +- test/cases/postSkipSegments.ts | 28 ++++++------ test/cases/postWarning.ts | 14 +++--- test/cases/reputation.ts | 2 +- test/cases/segmentShift.ts | 2 +- test/cases/setUsername.ts | 36 +++++++-------- test/cases/shadowBanUser.ts | 10 ++--- test/cases/unBan.ts | 6 +-- test/cases/voteOnSponsorTime.ts | 64 +++++++++++++-------------- test/utils.ts | 2 +- test/youtubeMock.ts | 2 +- 71 files changed, 392 insertions(+), 393 deletions(-) create mode 100644 .eslintrc.js diff --git a/.eslintrc.js b/.eslintrc.js new file mode 100644 index 0000000..3dd99ad --- /dev/null +++ b/.eslintrc.js @@ -0,0 +1,24 @@ +module.exports = { + env: { + browser: false, + es2021: true, + node: true, + }, + extends: [ + "eslint:recommended", + "plugin:@typescript-eslint/recommended", + ], + parser: "@typescript-eslint/parser", + parserOptions: { + ecmaVersion: 12, + sourceType: "module", + }, + plugins: ["@typescript-eslint"], + rules: { + // TODO: Remove warn rules when not needed anymore + "no-self-assign": "off", + "semi": "warn", + "@typescript-eslint/no-empty-interface": "off", + "@typescript-eslint/no-explicit-any": "off", + }, +}; \ No newline at end of file diff --git a/src/app.ts b/src/app.ts index a9e4df6..b409136 100644 --- a/src/app.ts +++ b/src/app.ts @@ -34,13 +34,14 @@ import { addUnlistedVideo } from './routes/addUnlistedVideo'; import {postPurgeAllSegments} from './routes/postPurgeAllSegments'; import {getUserID} from './routes/getUserID'; import ExpressPromiseRouter from 'express-promise-router'; +import { Server } from 'http'; -export function createServer(callback: () => void) { +export function createServer(callback: () => void): Server { // Create a service (the app object is just a callback). const app = express(); - const router = ExpressPromiseRouter() - app.use(router) + const router = ExpressPromiseRouter(); + app.use(router); //setup CORS correctly router.use(corsMiddleware); @@ -158,7 +159,7 @@ function setupRoutes(router: Router) { if (config.postgres) { router.get('/database', (req, res) => dumpDatabase(req, res, true)); router.get('/database.json', (req, res) => dumpDatabase(req, res, false)); - router.get('/database/*', redirectLink) + router.get('/database/*', redirectLink); } else { router.get('/database.db', function (req: Request, res: Response) { res.sendFile("./databases/sponsorTimes.db", {root: "./"}); diff --git a/src/config.ts b/src/config.ts index 5a5ad8c..ab60804 100644 --- a/src/config.ts +++ b/src/config.ts @@ -1,6 +1,6 @@ import fs from 'fs'; import {SBSConfig} from "./types/config.model"; -import packageJson from "../package.json" +import packageJson from "../package.json"; const isTestMode = process.env.npm_lifecycle_script === packageJson.scripts.test; const configFile = process.env.TEST_POSTGRES ? 'ci.json' @@ -83,7 +83,7 @@ addDefaults(config, { // Add defaults function addDefaults(config: SBSConfig, defaults: SBSConfig) { for (const key in defaults) { - if (!config.hasOwnProperty(key)) { + if (!Object.prototype.hasOwnProperty.call(config, key)) { // @ts-ignore config[key] = defaults[key]; } diff --git a/src/databases/Mysql.ts b/src/databases/Mysql.ts index 079395d..5a76db6 100644 --- a/src/databases/Mysql.ts +++ b/src/databases/Mysql.ts @@ -1,19 +1,20 @@ import {Logger} from '../utils/logger'; import {IDatabase, QueryType} from './IDatabase'; +// eslint-disable-next-line @typescript-eslint/ban-ts-comment // @ts-ignore import MysqlInterface from 'sync-mysql'; export class Mysql implements IDatabase { private connection: any; - constructor(private config: any) { + constructor(private config: unknown) { } async init(): Promise { this.connection = new MysqlInterface(this.config); } - prepare(type: QueryType, query: string, params?: any[]) { + prepare(type: QueryType, query: string, params?: any[]): Promise { Logger.debug(`prepare (mysql): type: ${type}, query: ${query}, params: ${params}`); const queryResult = this.connection.query(query, params); diff --git a/src/databases/Postgres.ts b/src/databases/Postgres.ts index 65ae5ac..a98afca 100644 --- a/src/databases/Postgres.ts +++ b/src/databases/Postgres.ts @@ -17,7 +17,7 @@ types.setTypeParser(20, function(val) { export class Postgres implements IDatabase { private pool: Pool; - constructor(private config: any) {} + constructor(private config: Record) {} async init(): Promise { this.pool = new Pool(this.config.postgres); @@ -43,7 +43,7 @@ export class Postgres implements IDatabase { } } - async prepare(type: QueryType, query: string, params?: any[]) { + async prepare(type: QueryType, query: string, params?: any[]): Promise { // Convert query to use numbered parameters let count = 1; for (let char = 0; char < query.length; char++) { @@ -64,7 +64,7 @@ export class Postgres implements IDatabase { return value; } case 'all': { - let values = queryResult.rows; + const values = queryResult.rows; Logger.debug(`result (postgres): ${values}`); return values; } diff --git a/src/databases/Sqlite.ts b/src/databases/Sqlite.ts index 98422d3..1f28258 100644 --- a/src/databases/Sqlite.ts +++ b/src/databases/Sqlite.ts @@ -12,7 +12,7 @@ export class Sqlite implements IDatabase { { } - async prepare(type: QueryType, query: string, params: any[] = []) { + async prepare(type: QueryType, query: string, params: any[] = []): Promise { // Logger.debug(`prepare (sqlite): type: ${type}, query: ${query}, params: ${params}`); const preparedQuery = this.db.prepare(query); @@ -30,7 +30,7 @@ export class Sqlite implements IDatabase { } } - async init() { + async init(): Promise { // Make dirs if required if (!fs.existsSync(path.join(this.config.dbPath, "../"))) { fs.mkdirSync(path.join(this.config.dbPath, "../")); @@ -61,7 +61,7 @@ export class Sqlite implements IDatabase { this.db.exec("pragma mmap_size= 500000000;"); } - attachDatabase(database: string, attachAs: string) { + attachDatabase(database: string, attachAs: string): void { this.db.prepare(`ATTACH ? as ${attachAs}`).run(database); } @@ -83,7 +83,7 @@ export class Sqlite implements IDatabase { } private static processUpgradeQuery(query: string): string { - let result = query.replace(/^.*--!sqlite-ignore/gm, ""); + const result = query.replace(/^.*--!sqlite-ignore/gm, ""); return result; } diff --git a/src/databases/databases.ts b/src/databases/databases.ts index 06f53ed..1639cca 100644 --- a/src/databases/databases.ts +++ b/src/databases/databases.ts @@ -60,7 +60,7 @@ if (config.mysql) { enableWalCheckpointNumber: false }); } -async function initDb() { +async function initDb(): Promise { await db.init(); await privateDB.init(); @@ -74,4 +74,4 @@ export { db, privateDB, initDb, -} +}; diff --git a/src/middleware/apiCsp.ts b/src/middleware/apiCsp.ts index 6d5f1ef..093e75b 100644 --- a/src/middleware/apiCsp.ts +++ b/src/middleware/apiCsp.ts @@ -1,6 +1,6 @@ import {NextFunction, Request, Response} from 'express'; -export function apiCspMiddleware(req: Request, res: Response, next: NextFunction) { +export function apiCspMiddleware(req: Request, res: Response, next: NextFunction): void { res.header("Content-Security-Policy", "script-src 'none'; object-src 'none'"); next(); } \ No newline at end of file diff --git a/src/middleware/cors.ts b/src/middleware/cors.ts index 1741319..7d990a1 100644 --- a/src/middleware/cors.ts +++ b/src/middleware/cors.ts @@ -1,8 +1,8 @@ import {NextFunction, Request, Response} from 'express'; -export function corsMiddleware(req: Request, res: Response, next: NextFunction) { +export function corsMiddleware(req: Request, res: Response, next: NextFunction): void { res.header("Access-Control-Allow-Origin", "*"); res.header("Access-Control-Allow-Headers", "X-Requested-With, Content-Type, Accept"); - res.header("Access-Control-Allow-Methods", "GET, POST, OPTIONS, DELETE") + res.header("Access-Control-Allow-Methods", "GET, POST, OPTIONS, DELETE"); next(); } diff --git a/src/middleware/logger.ts b/src/middleware/logger.ts index 942e78e..3c9c6b0 100644 --- a/src/middleware/logger.ts +++ b/src/middleware/logger.ts @@ -1,7 +1,7 @@ import {Logger} from '../utils/logger'; import {NextFunction, Request, Response} from 'express'; -export function loggerMiddleware(req: Request, res: Response, next: NextFunction) { +export function loggerMiddleware(req: Request, res: Response, next: NextFunction): void { Logger.info(`Request received: ${req.method} ${req.url}`); next(); } diff --git a/src/middleware/userCounter.ts b/src/middleware/userCounter.ts index e6a2c71..6b30d83 100644 --- a/src/middleware/userCounter.ts +++ b/src/middleware/userCounter.ts @@ -5,7 +5,7 @@ import {getIP} from '../utils/getIP'; import {getHash} from '../utils/getHash'; import {NextFunction, Request, Response} from 'express'; -export function userCounter(req: Request, res: Response, next: NextFunction) { +export function userCounter(req: Request, res: Response, next: NextFunction): void { fetch(config.userCounterURL + "/api/v1/addIP?hashedIP=" + getHash(getIP(req), 1), {method: "POST"}) .catch(() => Logger.debug("Failing to connect to user counter at: " + config.userCounterURL)); diff --git a/src/routes/addUnlistedVideo.ts b/src/routes/addUnlistedVideo.ts index 1af5146..e7704ba 100644 --- a/src/routes/addUnlistedVideo.ts +++ b/src/routes/addUnlistedVideo.ts @@ -1,4 +1,3 @@ -import { time } from 'console'; import {Request, Response} from 'express'; import { db } from '../databases/databases'; import { Logger } from '../utils/logger'; @@ -10,7 +9,7 @@ import { Logger } from '../utils/logger'; * https://support.google.com/youtube/answer/9230970 */ -export function addUnlistedVideo(req: Request, res: Response) { +export function addUnlistedVideo(req: Request, res: Response): void { const videoID = req.body.videoID; const year = req.body.year || 0; const views = req.body.views || 0; @@ -27,7 +26,6 @@ export function addUnlistedVideo(req: Request, res: Response) { } catch (err) { Logger.error(err); res.sendStatus(500); - return; } diff --git a/src/routes/addUserAsVIP.ts b/src/routes/addUserAsVIP.ts index 71ab186..8eeb97d 100644 --- a/src/routes/addUserAsVIP.ts +++ b/src/routes/addUserAsVIP.ts @@ -3,7 +3,7 @@ import {db} from '../databases/databases'; import {config} from '../config'; import {Request, Response} from 'express'; -export async function addUserAsVIP(req: Request, res: Response) { +export async function addUserAsVIP(req: Request, res: Response): Promise { const userID = req.query.userID as string; let adminUserIDInput = req.query.adminUserID as string; diff --git a/src/routes/deleteLockCategories.ts b/src/routes/deleteLockCategories.ts index 915c411..725a6cf 100644 --- a/src/routes/deleteLockCategories.ts +++ b/src/routes/deleteLockCategories.ts @@ -5,7 +5,7 @@ import {db} from '../databases/databases'; import { Category, VideoID } from '../types/segments.model'; import { UserID } from '../types/user.model'; -export async function deleteLockCategoriesEndpoint(req: Request, res: Response) { +export async function deleteLockCategoriesEndpoint(req: Request, res: Response): Promise { // Collect user input data const videoID = req.body.videoID as VideoID; const userID = req.body.userID as UserID; diff --git a/src/routes/dumpDatabase.ts b/src/routes/dumpDatabase.ts index 5a590b5..ff0b420 100644 --- a/src/routes/dumpDatabase.ts +++ b/src/routes/dumpDatabase.ts @@ -23,7 +23,7 @@ const styleHeader = `` +`; const licenseHeader = `

The API and database follow CC BY-NC-SA 4.0 unless you have explicit permission.

Attribution Template

@@ -38,13 +38,13 @@ const tableNames = tables.map(table => table.name); interface TableDumpList { fileName: string; tableName: string; -}; +} let latestDumpFiles: TableDumpList[] = []; interface TableFile { file: string, timestamp: number -}; +} if (tables.length === 0) { Logger.warn('[dumpDatabase] No tables configured'); @@ -55,7 +55,7 @@ let updateQueued = false; let updateRunning = false; function removeOutdatedDumps(exportPath: string): Promise { - return new Promise((resolve, reject) => { + return new Promise((resolve) => { // Get list of table names // Create array for each table const tableFiles: Record = tableNames.reduce((obj: any, tableName) => { @@ -81,7 +81,7 @@ function removeOutdatedDumps(exportPath: string): Promise { }); }); - for (let tableName in tableFiles) { + for (const tableName in tableFiles) { const files = tableFiles[tableName].sort((a, b) => b.timestamp - a.timestamp); for (let i = 2; i < files.length; i++) { // remove old file @@ -90,13 +90,12 @@ function removeOutdatedDumps(exportPath: string): Promise { }); } } - resolve(); }); }); } -export default async function dumpDatabase(req: Request, res: Response, showPage: boolean) { +export default async function dumpDatabase(req: Request, res: Response, showPage: boolean): Promise { if (!config?.dumpDatabase?.enabled) { res.status(404).send("Database dump is disabled"); return; @@ -108,7 +107,7 @@ export default async function dumpDatabase(req: Request, res: Response, showPage updateQueueTime(); - res.status(200) + res.status(200); if (showPage) { res.send(`${styleHeader} @@ -153,7 +152,7 @@ export default async function dumpDatabase(req: Request, res: Response, showPage size: item.fileSize, }; }), - }) + }); } await queueDump(); diff --git a/src/routes/getDaysSavedFormatted.ts b/src/routes/getDaysSavedFormatted.ts index 22872b4..cdb6eaf 100644 --- a/src/routes/getDaysSavedFormatted.ts +++ b/src/routes/getDaysSavedFormatted.ts @@ -1,8 +1,8 @@ import {db} from '../databases/databases'; import {Request, Response} from 'express'; -export async function getDaysSavedFormatted(req: Request, res: Response) { - let row = await db.prepare('get', 'SELECT SUM(("endTime" - "startTime") / 60 / 60 / 24 * "views") as "daysSaved" from "sponsorTimes" where "shadowHidden" != 1', []); +export async function getDaysSavedFormatted(req: Request, res: Response): Promise { + const row = await db.prepare('get', 'SELECT SUM(("endTime" - "startTime") / 60 / 60 / 24 * "views") as "daysSaved" from "sponsorTimes" where "shadowHidden" != 1', []); if (row !== undefined) { //send this result diff --git a/src/routes/getIsUserVIP.ts b/src/routes/getIsUserVIP.ts index 927ca1f..75b19f3 100644 --- a/src/routes/getIsUserVIP.ts +++ b/src/routes/getIsUserVIP.ts @@ -17,7 +17,7 @@ export async function getIsUserVIP(req: Request, res: Response): Promise { const hashedUserID: HashedUserID = getHash(userID); try { - let vipState = await isUserVIP(hashedUserID); + const vipState = await isUserVIP(hashedUserID); res.status(200).json({ hashedUserID: hashedUserID, vip: vipState, diff --git a/src/routes/getSavedTimeForUser.ts b/src/routes/getSavedTimeForUser.ts index 9a72ee2..d557050 100644 --- a/src/routes/getSavedTimeForUser.ts +++ b/src/routes/getSavedTimeForUser.ts @@ -6,7 +6,7 @@ import { Logger } from '../utils/logger'; const maxRewardTimePerSegmentInSeconds = config.maxRewardTimePerSegmentInSeconds ?? 86400; -export async function getSavedTimeForUser(req: Request, res: Response) { +export async function getSavedTimeForUser(req: Request, res: Response): Promise { let userID = req.query.userID as string; if (userID == undefined) { @@ -19,7 +19,7 @@ export async function getSavedTimeForUser(req: Request, res: Response) { userID = getHash(userID); try { - let row = await db.prepare("get", 'SELECT SUM(((CASE WHEN "endTime" - "startTime" > ? THEN ? ELSE "endTime" - "startTime" END) / 60) * "views") as "minutesSaved" FROM "sponsorTimes" WHERE "userID" = ? AND "votes" > -1 AND "shadowHidden" != 1 ', [maxRewardTimePerSegmentInSeconds, maxRewardTimePerSegmentInSeconds, userID]); + const row = await db.prepare("get", 'SELECT SUM(((CASE WHEN "endTime" - "startTime" > ? THEN ? ELSE "endTime" - "startTime" END) / 60) * "views") as "minutesSaved" FROM "sponsorTimes" WHERE "userID" = ? AND "votes" > -1 AND "shadowHidden" != 1 ', [maxRewardTimePerSegmentInSeconds, maxRewardTimePerSegmentInSeconds, userID]); if (row.minutesSaved != null) { res.send({ diff --git a/src/routes/getSegmentInfo.ts b/src/routes/getSegmentInfo.ts index b9e03ea..77b23e7 100644 --- a/src/routes/getSegmentInfo.ts +++ b/src/routes/getSegmentInfo.ts @@ -2,7 +2,7 @@ import { Request, Response } from 'express'; import { db } from '../databases/databases'; import { DBSegment, SegmentUUID } from "../types/segments.model"; -const isValidSegmentUUID = (str: string): Boolean => /^([a-f0-9]{64}|[a-f0-9]{8}\-[a-f0-9]{4}\-[a-f0-9]{4}\-[a-f0-9]{4}\-[a-f0-9]{12})/.test(str) +const isValidSegmentUUID = (str: string): boolean => /^([a-f0-9]{64}|[a-f0-9]{8}-[a-f0-9]{4}-[a-f0-9]{4}-[a-f0-9]{4}-[a-f0-9]{12})/.test(str); async function getSegmentFromDBByUUID(UUID: SegmentUUID): Promise { try { @@ -18,7 +18,7 @@ async function getSegmentFromDBByUUID(UUID: SegmentUUID): Promise { async function getSegmentsByUUID(UUIDs: SegmentUUID[]): Promise { const DBSegments: DBSegment[] = []; - for (let UUID of UUIDs) { + for (const UUID of UUIDs) { // if UUID is invalid, skip if (!isValidSegmentUUID(UUID)) continue; DBSegments.push(await getSegmentFromDBByUUID(UUID as SegmentUUID)); @@ -26,7 +26,7 @@ async function getSegmentsByUUID(UUIDs: SegmentUUID[]): Promise { return DBSegments; } -async function handleGetSegmentInfo(req: Request, res: Response) { +async function handleGetSegmentInfo(req: Request, res: Response): Promise { // If using params instead of JSON, only one UUID can be pulled let UUIDs = req.query.UUIDs ? JSON.parse(req.query.UUIDs as string) @@ -41,18 +41,18 @@ async function handleGetSegmentInfo(req: Request, res: Response) { if (UUIDs.length > 10) UUIDs = UUIDs.slice(0, 10); if (!Array.isArray(UUIDs) || !UUIDs) { res.status(400).send("UUIDs parameter does not match format requirements."); - return false; + return; } const DBSegments = await getSegmentsByUUID(UUIDs); // all uuids failed lookup if (!DBSegments?.length) { res.sendStatus(400); - return false; + return; } // uuids valid but not found if (DBSegments[0] === null || DBSegments[0] === undefined) { res.sendStatus(400); - return false; + return; } return DBSegments; } diff --git a/src/routes/getSkipSegments.ts b/src/routes/getSkipSegments.ts index 368781d..49d6478 100644 --- a/src/routes/getSkipSegments.ts +++ b/src/routes/getSkipSegments.ts @@ -8,7 +8,7 @@ import { getCategoryActionType } from '../utils/categoryInfo'; import { getHash } from '../utils/getHash'; import { getIP } from '../utils/getIP'; import { Logger } from '../utils/logger'; -import { QueryCacher } from '../utils/queryCacher' +import { QueryCacher } from '../utils/queryCacher'; import { getReputation } from '../utils/reputation'; @@ -41,7 +41,7 @@ async function prepareCategorySegments(req: Request, videoID: VideoID, category: const filteredSegments = segments.filter((_, index) => shouldFilter[index]); - const maxSegments = getCategoryActionType(category) === CategoryActionType.Skippable ? 32 : 1 + const maxSegments = getCategoryActionType(category) === CategoryActionType.Skippable ? 32 : 1; return (await chooseSegments(filteredSegments, maxSegments)).map((chosenSegment) => ({ category, segment: [chosenSegment.startTime, chosenSegment.endTime], @@ -135,7 +135,7 @@ async function getSegmentsFromDBByHash(hashedVideoIDPrefix: VideoIDHash, service ) as Promise; if (hashedVideoIDPrefix.length === 4) { - return await QueryCacher.get(fetchFromDB, skipSegmentsHashKey(hashedVideoIDPrefix, service)) + return await QueryCacher.get(fetchFromDB, skipSegmentsHashKey(hashedVideoIDPrefix, service)); } return await fetchFromDB(); @@ -150,7 +150,7 @@ async function getSegmentsFromDBByVideoID(videoID: VideoID, service: Service): P [videoID, service] ) as Promise; - return await QueryCacher.get(fetchFromDB, skipSegmentsKey(videoID, service)) + return await QueryCacher.get(fetchFromDB, skipSegmentsKey(videoID, service)); } //gets a weighted random choice from the choices array based on their `votes` property. @@ -168,7 +168,7 @@ function getWeightedRandomChoice(choices: T[], amountOf //assign a weight to each choice let totalWeight = 0; - let choicesWithWeights: TWithWeight[] = choices.map(choice => { + const choicesWithWeights: TWithWeight[] = choices.map(choice => { const boost = Math.min(choice.reputation, 4); //The 3 makes -2 the minimum votes before being ignored completely @@ -234,7 +234,7 @@ async function chooseSegments(segments: DBSegment[], max: number): Promise { if (group.locked) { diff --git a/src/routes/getSkipSegmentsByHash.ts b/src/routes/getSkipSegmentsByHash.ts index 29194d4..33bda9a 100644 --- a/src/routes/getSkipSegmentsByHash.ts +++ b/src/routes/getSkipSegmentsByHash.ts @@ -3,11 +3,10 @@ import {getSegmentsByHash} from './getSkipSegments'; import {Request, Response} from 'express'; import { Category, Service, VideoIDHash } from '../types/segments.model'; -export async function getSkipSegmentsByHash(req: Request, res: Response) { +export async function getSkipSegmentsByHash(req: Request, res: Response): Promise { let hashPrefix = req.params.prefix as VideoIDHash; if (!hashPrefixTester(req.params.prefix)) { - res.status(400).send("Hash prefix does not match format requirements."); // Exit early on faulty prefix - return; + return res.status(400).send("Hash prefix does not match format requirements."); // Exit early on faulty prefix } hashPrefix = hashPrefix.toLowerCase() as VideoIDHash; @@ -44,6 +43,5 @@ export async function getSkipSegmentsByHash(req: Request, res: Response) { hash: data.hash, segments: data.segments, })); - - res.status(output.length === 0 ? 404 : 200).json(output); + return res.status(output.length === 0 ? 404 : 200).json(output); } diff --git a/src/routes/getTopUsers.ts b/src/routes/getTopUsers.ts index bd65108..c358eb1 100644 --- a/src/routes/getTopUsers.ts +++ b/src/routes/getTopUsers.ts @@ -7,7 +7,7 @@ const MILLISECONDS_IN_MINUTE = 60000; const getTopUsersWithCache = createMemoryCache(generateTopUsersStats, config.getTopUsersCacheTimeMinutes * MILLISECONDS_IN_MINUTE); const maxRewardTimePerSegmentInSeconds = config.maxRewardTimePerSegmentInSeconds ?? 86400; -async function generateTopUsersStats(sortBy: string, categoryStatsEnabled: boolean = false) { +async function generateTopUsersStats(sortBy: string, categoryStatsEnabled = false) { const userNames = []; const viewCounts = []; const totalSubmissions = []; @@ -63,7 +63,7 @@ async function generateTopUsersStats(sortBy: string, categoryStatsEnabled: boole }; } -export async function getTopUsers(req: Request, res: Response) { +export async function getTopUsers(req: Request, res: Response): Promise { const sortType = parseInt(req.query.sortType as string); const categoryStatsEnabled = req.query.categoryStats; @@ -89,5 +89,5 @@ export async function getTopUsers(req: Request, res: Response) { const stats = await getTopUsersWithCache(sortBy, categoryStatsEnabled); //send this result - res.send(stats); + return res.send(stats); } diff --git a/src/routes/getTotalStats.ts b/src/routes/getTotalStats.ts index 0809a40..b5afb10 100644 --- a/src/routes/getTotalStats.ts +++ b/src/routes/getTotalStats.ts @@ -13,14 +13,14 @@ let apiUsersCache = 0; let lastUserCountCheck = 0; -export async function getTotalStats(req: Request, res: Response) { +export async function getTotalStats(req: Request, res: Response): Promise { const userCountQuery = `(SELECT COUNT(*) FROM (SELECT DISTINCT "userID" from "sponsorTimes") t) "userCount",`; - let row = await db.prepare('get', `SELECT ${req.query.countContributingUsers ? userCountQuery : ""} COUNT(*) as "totalSubmissions", + const row = await db.prepare('get', `SELECT ${req.query.countContributingUsers ? userCountQuery : ""} COUNT(*) as "totalSubmissions", SUM("views") as "viewCount", SUM(("endTime" - "startTime") / 60 * "views") as "minutesSaved" FROM "sponsorTimes" WHERE "shadowHidden" != 1 AND "votes" >= 0`, []); if (row !== undefined) { - let extensionUsers = chromeUsersCache + firefoxUsersCache; + const extensionUsers = chromeUsersCache + firefoxUsersCache; //send this result res.send({ @@ -33,7 +33,7 @@ export async function getTotalStats(req: Request, res: Response) { }); // Check if the cache should be updated (every ~14 hours) - let now = Date.now(); + const now = Date.now(); if (now - lastUserCountCheck > 5000000) { lastUserCountCheck = now; @@ -79,7 +79,7 @@ function updateExtensionUsers() { }) .catch(() => Logger.debug("Failing to connect to " + chromeExtensionUrl)); }) - .catch(err => { + .catch(() => { Logger.debug("Failing to connect to " + mozillaAddonsUrl); }); } diff --git a/src/routes/getUserID.ts b/src/routes/getUserID.ts index 6ecc1b7..0b42588 100644 --- a/src/routes/getUserID.ts +++ b/src/routes/getUserID.ts @@ -2,7 +2,7 @@ import {db} from '../databases/databases'; import {Request, Response} from 'express'; import {UserID} from '../types/user.model'; -function getFuzzyUserID(userName: String): Promise<{userName: String, userID: UserID }[]> { +function getFuzzyUserID(userName: string): Promise<{userName: string, userID: UserID }[]> { // escape [_ % \] to avoid ReDOS userName = userName.replace(/\\/g, '\\\\') .replace(/_/g, '\\_') @@ -11,13 +11,13 @@ function getFuzzyUserID(userName: String): Promise<{userName: String, userID: Us // LIMIT to reduce overhead | ESCAPE to escape LIKE wildcards try { return db.prepare('all', `SELECT "userName", "userID" FROM "userNames" WHERE "userName" - LIKE ? ESCAPE '\\' LIMIT 10`, [userName]) + LIKE ? ESCAPE '\\' LIMIT 10`, [userName]); } catch (err) { return null; } } -function getExactUserID(userName: String): Promise<{userName: String, userID: UserID }[]> { +function getExactUserID(userName: string): Promise<{userName: string, userID: UserID }[]> { try { return db.prepare('all', `SELECT "userName", "userID" from "userNames" WHERE "userName" = ? LIMIT 10`, [userName]); } catch (err) { @@ -25,31 +25,27 @@ function getExactUserID(userName: String): Promise<{userName: String, userID: Us } } -export async function getUserID(req: Request, res: Response) { - let userName = req.query.username as string; +export async function getUserID(req: Request, res: Response): Promise { + const userName = req.query.username as string; const exactSearch = req.query.exact ? req.query.exact == "true" - : false as Boolean; + : false as boolean; // if not exact and length is 1, also skip if (userName == undefined || userName.length > 64 || (!exactSearch && userName.length < 3)) { // invalid request - res.sendStatus(400); - return false; + return res.sendStatus(400); } const results = exactSearch ? await getExactUserID(userName) : await getFuzzyUserID(userName); if (results === undefined || results === null) { - res.sendStatus(500); - return false; + return res.sendStatus(500); } else if (results.length === 0) { - res.sendStatus(404); - return false; + return res.sendStatus(404); } else { - res.send(results); - return false; + return res.send(results); } } diff --git a/src/routes/getUserInfo.ts b/src/routes/getUserInfo.ts index 44db5d5..46e8a48 100644 --- a/src/routes/getUserInfo.ts +++ b/src/routes/getUserInfo.ts @@ -9,7 +9,7 @@ import { SegmentUUID } from "../types/segments.model"; async function dbGetSubmittedSegmentSummary(userID: HashedUserID): Promise<{ minutesSaved: number, segmentCount: number }> { try { - let row = await db.prepare("get", `SELECT SUM((("endTime" - "startTime") / 60) * "views") as "minutesSaved", + const row = await db.prepare("get", `SELECT SUM((("endTime" - "startTime") / 60) * "views") as "minutesSaved", count(*) as "segmentCount" FROM "sponsorTimes" WHERE "userID" = ? AND "votes" > -2 AND "shadowHidden" != 1`, [userID]); if (row.minutesSaved != null) { @@ -30,8 +30,8 @@ async function dbGetSubmittedSegmentSummary(userID: HashedUserID): Promise<{ min async function dbGetIgnoredSegmentCount(userID: HashedUserID): Promise { try { - let row = await db.prepare("get", `SELECT COUNT(*) as "ignoredSegmentCount" FROM "sponsorTimes" WHERE "userID" = ? AND ( "votes" <= -2 OR "shadowHidden" = 1 )`, [userID]); - return row?.ignoredSegmentCount ?? 0 + const row = await db.prepare("get", `SELECT COUNT(*) as "ignoredSegmentCount" FROM "sponsorTimes" WHERE "userID" = ? AND ( "votes" <= -2 OR "shadowHidden" = 1 )`, [userID]); + return row?.ignoredSegmentCount ?? 0; } catch (err) { return null; } @@ -39,7 +39,7 @@ async function dbGetIgnoredSegmentCount(userID: HashedUserID): Promise { async function dbGetUsername(userID: HashedUserID) { try { - let row = await db.prepare('get', `SELECT "userName" FROM "userNames" WHERE "userID" = ?`, [userID]); + const row = await db.prepare('get', `SELECT "userName" FROM "userNames" WHERE "userID" = ?`, [userID]); if (row !== undefined) { return row.userName; } else { @@ -53,7 +53,7 @@ async function dbGetUsername(userID: HashedUserID) { async function dbGetViewsForUser(userID: HashedUserID) { try { - let row = await db.prepare('get', `SELECT SUM("views") as "viewCount" FROM "sponsorTimes" WHERE "userID" = ? AND "votes" > -2 AND "shadowHidden" != 1`, [userID]); + const row = await db.prepare('get', `SELECT SUM("views") as "viewCount" FROM "sponsorTimes" WHERE "userID" = ? AND "votes" > -2 AND "shadowHidden" != 1`, [userID]); return row?.viewCount ?? 0; } catch (err) { return false; @@ -62,7 +62,7 @@ async function dbGetViewsForUser(userID: HashedUserID) { async function dbGetIgnoredViewsForUser(userID: HashedUserID) { try { - let row = await db.prepare('get', `SELECT SUM("views") as "ignoredViewCount" FROM "sponsorTimes" WHERE "userID" = ? AND ( "votes" <= -2 OR "shadowHidden" = 1 )`, [userID]); + const row = await db.prepare('get', `SELECT SUM("views") as "ignoredViewCount" FROM "sponsorTimes" WHERE "userID" = ? AND ( "votes" <= -2 OR "shadowHidden" = 1 )`, [userID]); return row?.ignoredViewCount ?? 0; } catch (err) { return false; @@ -71,7 +71,7 @@ async function dbGetIgnoredViewsForUser(userID: HashedUserID) { async function dbGetWarningsForUser(userID: HashedUserID): Promise { try { - let row = await db.prepare('get', `SELECT COUNT(*) as total FROM "warnings" WHERE "userID" = ? AND "enabled" = 1`, [userID]); + const row = await db.prepare('get', `SELECT COUNT(*) as total FROM "warnings" WHERE "userID" = ? AND "enabled" = 1`, [userID]); return row?.total ?? 0; } catch (err) { Logger.error('Couldn\'t get warnings for user ' + userID + '. returning 0'); @@ -81,14 +81,14 @@ async function dbGetWarningsForUser(userID: HashedUserID): Promise { async function dbGetLastSegmentForUser(userID: HashedUserID): Promise { try { - let row = await db.prepare('get', `SELECT "UUID" FROM "sponsorTimes" WHERE "userID" = ? ORDER BY "timeSubmitted" DESC LIMIT 1`, [userID]); + const row = await db.prepare('get', `SELECT "UUID" FROM "sponsorTimes" WHERE "userID" = ? ORDER BY "timeSubmitted" DESC LIMIT 1`, [userID]); return row?.UUID ?? null; } catch (err) { return null; } } -export async function getUserInfo(req: Request, res: Response) { +export async function getUserInfo(req: Request, res: Response): Promise { const userID = req.query.userID as UserID; const hashedUserID: HashedUserID = userID ? getHash(userID) : req.query.publicUserID as HashedUserID; diff --git a/src/routes/getUsername.ts b/src/routes/getUsername.ts index f8f7e1a..7b9bacd 100644 --- a/src/routes/getUsername.ts +++ b/src/routes/getUsername.ts @@ -3,7 +3,7 @@ import {getHash} from '../utils/getHash'; import {Logger} from '../utils/logger'; import {Request, Response} from 'express'; -export async function getUsername(req: Request, res: Response) { +export async function getUsername(req: Request, res: Response): Promise { let userID = req.query.userID as string; if (userID == undefined) { @@ -16,7 +16,7 @@ export async function getUsername(req: Request, res: Response) { userID = getHash(userID); try { - let row = await db.prepare('get', `SELECT "userName" FROM "userNames" WHERE "userID" = ?`, [userID]); + const row = await db.prepare('get', `SELECT "userName" FROM "userNames" WHERE "userID" = ?`, [userID]); if (row !== undefined) { res.send({ @@ -31,7 +31,6 @@ export async function getUsername(req: Request, res: Response) { } catch (err) { Logger.error(err); res.sendStatus(500); - return; } } diff --git a/src/routes/getViewsForUser.ts b/src/routes/getViewsForUser.ts index ccc0344..6fa2710 100644 --- a/src/routes/getViewsForUser.ts +++ b/src/routes/getViewsForUser.ts @@ -3,7 +3,7 @@ import {Request, Response} from 'express'; import {getHash} from '../utils/getHash'; import {Logger} from '../utils/logger'; -export async function getViewsForUser(req: Request, res: Response) { +export async function getViewsForUser(req: Request, res: Response): Promise { let userID = req.query.userID as string; if (userID == undefined) { @@ -16,7 +16,7 @@ export async function getViewsForUser(req: Request, res: Response) { userID = getHash(userID); try { - let row = await db.prepare('get', `SELECT SUM("views") as "viewCount" FROM "sponsorTimes" WHERE "userID" = ?`, [userID]); + const row = await db.prepare('get', `SELECT SUM("views") as "viewCount" FROM "sponsorTimes" WHERE "userID" = ?`, [userID]); //increase the view count by one if (row.viewCount != null) { @@ -29,7 +29,6 @@ export async function getViewsForUser(req: Request, res: Response) { } catch (err) { Logger.error(err); res.sendStatus(500); - return; } } diff --git a/src/routes/oldGetVideoSponsorTimes.ts b/src/routes/oldGetVideoSponsorTimes.ts index 1a98314..f4a20fb 100644 --- a/src/routes/oldGetVideoSponsorTimes.ts +++ b/src/routes/oldGetVideoSponsorTimes.ts @@ -2,12 +2,12 @@ import {handleGetSegments} from './getSkipSegments'; import {Request, Response} from 'express'; export async function oldGetVideoSponsorTimes(req: Request, res: Response): Promise { - let segments = await handleGetSegments(req, res); + const segments = await handleGetSegments(req, res); if (segments) { // Convert to old outputs - let sponsorTimes = []; - let UUIDs = []; + const sponsorTimes = []; + const UUIDs = []; for (const segment of segments) { sponsorTimes.push(segment.segment); diff --git a/src/routes/oldSubmitSponsorTimes.ts b/src/routes/oldSubmitSponsorTimes.ts index bcf7934..9500220 100644 --- a/src/routes/oldSubmitSponsorTimes.ts +++ b/src/routes/oldSubmitSponsorTimes.ts @@ -1,8 +1,7 @@ import {postSkipSegments} from './postSkipSegments'; import {Request, Response} from 'express'; -export async function oldSubmitSponsorTimes(req: Request, res: Response) { +export async function oldSubmitSponsorTimes(req: Request, res: Response): Promise { req.query.category = "sponsor"; - return postSkipSegments(req, res); } diff --git a/src/routes/postClearCache.ts b/src/routes/postClearCache.ts index c3bc1ca..07e2d92 100644 --- a/src/routes/postClearCache.ts +++ b/src/routes/postClearCache.ts @@ -7,9 +7,9 @@ import { QueryCacher } from '../utils/queryCacher'; import { isUserVIP } from '../utils/isUserVIP'; import { VideoIDHash } from "../types/segments.model"; -export async function postClearCache(req: Request, res: Response) { +export async function postClearCache(req: Request, res: Response): Promise { const videoID = req.query.videoID as VideoID; - let userID = req.query.userID as UserID; + const userID = req.query.userID as UserID; const service = req.query.service as Service ?? Service.YouTube; const invalidFields = []; @@ -24,7 +24,7 @@ export async function postClearCache(req: Request, res: Response) { // invalid request const fields = invalidFields.reduce((p, c, i) => p + (i !== 0 ? ', ' : '') + c, ''); res.status(400).send(`No valid ${fields} field(s) provided`); - return false; + return; } // hash the userID as early as possible @@ -36,7 +36,7 @@ export async function postClearCache(req: Request, res: Response) { if (!(await isUserVIP(hashedUserID))){ Logger.warn("Permission violation: User " + hashedUserID + " attempted to clear cache for video " + videoID + "."); res.status(403).json({"message": "Not a VIP"}); - return false; + return; } try { @@ -49,7 +49,7 @@ export async function postClearCache(req: Request, res: Response) { message: "Cache cleared on video " + videoID }); } catch(err) { - res.status(500).send() - return false; + res.status(500).send(); + return; } } diff --git a/src/routes/postLockCategories.ts b/src/routes/postLockCategories.ts index 55282be..a328367 100644 --- a/src/routes/postLockCategories.ts +++ b/src/routes/postLockCategories.ts @@ -4,11 +4,11 @@ import {isUserVIP} from '../utils/isUserVIP'; import {db} from '../databases/databases'; import {Request, Response} from 'express'; -export async function postLockCategories(req: Request, res: Response) { +export async function postLockCategories(req: Request, res: Response): Promise { // Collect user input data - let videoID = req.body.videoID; + const videoID = req.body.videoID; let userID = req.body.userID; - let categories = req.body.categories; + const categories = req.body.categories; // Check input data is valid if (!videoID @@ -25,7 +25,7 @@ export async function postLockCategories(req: Request, res: Response) { // Check if user is VIP userID = getHash(userID); - let userIsVIP = await isUserVIP(userID); + const userIsVIP = await isUserVIP(userID); if (!userIsVIP) { res.status(403).json({ @@ -67,7 +67,7 @@ export async function postLockCategories(req: Request, res: Response) { message: "Internal Server Error: Could not write marker to the database.", }); } - }; + } res.status(200).json({ submitted: categoriesToMark, diff --git a/src/routes/postPurgeAllSegments.ts b/src/routes/postPurgeAllSegments.ts index 9a05f4b..5e1e484 100644 --- a/src/routes/postPurgeAllSegments.ts +++ b/src/routes/postPurgeAllSegments.ts @@ -20,7 +20,7 @@ export async function postPurgeAllSegments(req: Request, res: Response): Promise const hashedUserID: HashedUserID = getHash(userID); try { - let vipState = await isUserVIP(hashedUserID); + const vipState = await isUserVIP(hashedUserID); if (!vipState) { res.status(403).json({ message: 'Must be a VIP to perform this action.', diff --git a/src/routes/postSegmentShift.ts b/src/routes/postSegmentShift.ts index 0b7f9ab..6c92b5b 100644 --- a/src/routes/postSegmentShift.ts +++ b/src/routes/postSegmentShift.ts @@ -92,7 +92,7 @@ export async function postSegmentShift(req: Request, res: Response): Promise { Logger.debug('Proxy Submission: ' + res.status + ' (' + (await res.text()) + ')'); }) - .catch(err => { + .catch(() => { Logger.error("Proxy Submission: Failed to make call"); }); } -export async function postSkipSegments(req: Request, res: Response) { +export async function postSkipSegments(req: Request, res: Response): Promise { if (config.proxySubmission) { proxySubmission(req); } @@ -338,7 +332,8 @@ export async function postSkipSegments(req: Request, res: Response) { )).count; if (warningsCount >= config.maxNumberOfActiveWarnings) { - return res.status(403).send('Submission rejected due to a warning from a moderator. This means that we noticed you were making some common mistakes that are not malicious, and we just want to clarify the rules. Could you please send a message in Discord or Matrix so we can further help you?'); + res.status(403).send('Submission rejected due to a warning from a moderator. This means that we noticed you were making some common mistakes that are not malicious, and we just want to clarify the rules. Could you please send a message in Discord or Matrix so we can further help you?'); + return; } let lockedCategoryList = (await db.prepare('all', 'SELECT category from "lockCategories" where "videoID" = ?', [videoID])).map((list: any) => { @@ -406,8 +401,8 @@ export async function postSkipSegments(req: Request, res: Response) { } - let startTime = parseFloat(segments[i].segment[0]); - let endTime = parseFloat(segments[i].segment[1]); + const startTime = parseFloat(segments[i].segment[0]); + const endTime = parseFloat(segments[i].segment[1]); if (isNaN(startTime) || isNaN(endTime) || startTime === Infinity || endTime === Infinity || startTime < 0 || startTime > endTime @@ -459,6 +454,7 @@ export async function postSkipSegments(req: Request, res: Response) { const yesterday = timeSubmitted - 86400000; // Disable IP ratelimiting for now + // eslint-disable-next-line no-constant-condition if (false) { //check to see if this ip has submitted too many sponsors today const rateLimitCheckRow = await privateDB.prepare('get', `SELECT COUNT(*) as count FROM "sponsorTimes" WHERE "hashedIP" = ? AND "videoID" = ? AND "timeSubmitted" > ?`, [hashedIP, videoID, yesterday]); @@ -466,12 +462,12 @@ export async function postSkipSegments(req: Request, res: Response) { if (rateLimitCheckRow.count >= 10) { //too many sponsors for the same video from the same ip address res.sendStatus(429); - return; } } // Disable max submissions for now + // eslint-disable-next-line no-constant-condition if (false) { //check to see if the user has already submitted sponsors for this video const duplicateCheckRow = await db.prepare('get', `SELECT COUNT(*) as count FROM "sponsorTimes" WHERE "userID" = ? and "videoID" = ?`, [userID, videoID]); @@ -479,7 +475,6 @@ export async function postSkipSegments(req: Request, res: Response) { if (duplicateCheckRow.count >= 16) { //too many sponsors for the same video from the same user res.sendStatus(429); - return; } } @@ -494,7 +489,7 @@ export async function postSkipSegments(req: Request, res: Response) { shadowBanned = 1; } - let startingVotes = 0 + decreaseVotes; + const startingVotes = 0 + decreaseVotes; const reputation = await getReputation(userID); for (const segmentInfo of segments) { @@ -528,7 +523,6 @@ export async function postSkipSegments(req: Request, res: Response) { res.sendStatus(500); Logger.error("Error when putting sponsorTime in the DB: " + videoID + ", " + segmentInfo.segment[0] + ", " + segmentInfo.segment[1] + ", " + userID + ", " + segmentInfo.category + ". " + err); - return; } @@ -541,9 +535,7 @@ export async function postSkipSegments(req: Request, res: Response) { } } catch (err) { Logger.error(err); - res.sendStatus(500); - return; } diff --git a/src/routes/postWarning.ts b/src/routes/postWarning.ts index 8805b2b..9c12db6 100644 --- a/src/routes/postWarning.ts +++ b/src/routes/postWarning.ts @@ -5,7 +5,7 @@ import {isUserVIP} from '../utils/isUserVIP'; import {getHash} from '../utils/getHash'; import { HashedUserID, UserID } from '../types/user.model'; -export async function postWarning(req: Request, res: Response) { +export async function postWarning(req: Request, res: Response): Promise { // Collect user input data const issuerUserID: HashedUserID = getHash( req.body.issuerUserID); const userID: UserID = req.body.userID; @@ -23,7 +23,7 @@ export async function postWarning(req: Request, res: Response) { let resultStatus = ""; if (enabled) { - let previousWarning = await db.prepare('get', 'SELECT * FROM "warnings" WHERE "userID" = ? AND "issuerUserID" = ?', [userID, issuerUserID]); + const previousWarning = await db.prepare('get', 'SELECT * FROM "warnings" WHERE "userID" = ? AND "issuerUserID" = ?', [userID, issuerUserID]); if (!previousWarning) { await db.prepare( diff --git a/src/routes/setUsername.ts b/src/routes/setUsername.ts index 1dde40d..bd0de35 100644 --- a/src/routes/setUsername.ts +++ b/src/routes/setUsername.ts @@ -11,7 +11,7 @@ async function logUserNameChange(userID: string, newUserName: string, oldUserNam ); } -export async function setUsername(req: Request, res: Response) { +export async function setUsername(req: Request, res: Response): Promise { let userID = req.query.userID as string; let userName = req.query.username as string; @@ -31,6 +31,7 @@ export async function setUsername(req: Request, res: Response) { // remove unicode control characters from username (example: \n, \r, \t etc.) // source: https://en.wikipedia.org/wiki/Control_character#In_Unicode + // eslint-disable-next-line no-control-regex userName = userName.replace(/[\u0000-\u001F\u007F-\u009F]/g, ''); if (adminUserIDInput != undefined) { @@ -81,7 +82,6 @@ export async function setUsername(req: Request, res: Response) { } catch (err) { Logger.error(err); res.sendStatus(500); - return; } } diff --git a/src/routes/shadowBanUser.ts b/src/routes/shadowBanUser.ts index f02c9a0..50f8095 100644 --- a/src/routes/shadowBanUser.ts +++ b/src/routes/shadowBanUser.ts @@ -6,7 +6,7 @@ import { Category, Service, VideoID, VideoIDHash } from '../types/segments.model import { UserID } from '../types/user.model'; import { QueryCacher } from '../utils/queryCacher'; -export async function shadowBanUser(req: Request, res: Response) { +export async function shadowBanUser(req: Request, res: Response): Promise { const userID = req.query.userID as string; const hashedIP = req.query.hashedIP as string; let adminUserIDInput = req.query.adminUserID as string; @@ -66,10 +66,10 @@ export async function shadowBanUser(req: Request, res: Response) { //find all previous submissions and unhide them if (unHideOldSubmissions) { - let segmentsToIgnore = (await db.prepare('all', `SELECT "UUID" FROM "sponsorTimes" st + const segmentsToIgnore = (await db.prepare('all', `SELECT "UUID" FROM "sponsorTimes" st JOIN "lockCategories" ns on "st"."videoID" = "ns"."videoID" AND st.category = ns.category WHERE "st"."userID" = ?` , [userID])).map((item: {UUID: string}) => item.UUID); - let allSegments = (await db.prepare('all', `SELECT "UUID" FROM "sponsorTimes" st WHERE "st"."userID" = ?`, [userID])) + const allSegments = (await db.prepare('all', `SELECT "UUID" FROM "sponsorTimes" st WHERE "st"."userID" = ?`, [userID])) .map((item: {UUID: string}) => item.UUID); await Promise.all(allSegments.filter((item: {uuid: string}) => { diff --git a/src/routes/viewedVideoSponsorTime.ts b/src/routes/viewedVideoSponsorTime.ts index 59ae2ae..95bc5c4 100644 --- a/src/routes/viewedVideoSponsorTime.ts +++ b/src/routes/viewedVideoSponsorTime.ts @@ -2,7 +2,7 @@ import {db} from '../databases/databases'; import {Request, Response} from 'express'; export async function viewedVideoSponsorTime(req: Request, res: Response): Promise { - let UUID = req.query.UUID; + const UUID = req.query.UUID; if (UUID == undefined) { //invalid request diff --git a/src/routes/voteOnSponsorTime.ts b/src/routes/voteOnSponsorTime.ts index 76feae3..3d1f7a0 100644 --- a/src/routes/voteOnSponsorTime.ts +++ b/src/routes/voteOnSponsorTime.ts @@ -252,7 +252,7 @@ export function getUserID(req: Request): UserID { return req.query.userID as UserID; } -export async function voteOnSponsorTime(req: Request, res: Response) { +export async function voteOnSponsorTime(req: Request, res: Response): Promise { const UUID = req.query.UUID as SegmentUUID; const paramUserID = getUserID(req); let type = req.query.type !== undefined ? parseInt(req.query.type as string) : undefined; @@ -269,13 +269,13 @@ export async function voteOnSponsorTime(req: Request, res: Response) { const userID = getHash(paramUserID + UUID); // To force a non 200, change this early - let finalResponse: FinalResponse = { + const finalResponse: FinalResponse = { blockVote: false, finalStatus: 200, finalMessage: null, webhookType: VoteWebhookType.Normal, webhookMessage: null - } + }; //x-forwarded-for if this server is behind a proxy const ip = getIP(req); @@ -292,7 +292,7 @@ export async function voteOnSponsorTime(req: Request, res: Response) { // disallow vote types 10/11 if (type === 10 || type === 11) { // no longer allow type 10/11 alternative votes - res.sendStatus(400) + res.sendStatus(400); return; } @@ -305,8 +305,8 @@ export async function voteOnSponsorTime(req: Request, res: Response) { if (await isSegmentLocked() || await isVideoLocked()) { finalResponse.blockVote = true; - finalResponse.webhookType = VoteWebhookType.Rejected - finalResponse.webhookMessage = "Vote rejected: A moderator has decided that this segment is correct" + finalResponse.webhookType = VoteWebhookType.Rejected; + finalResponse.webhookMessage = "Vote rejected: A moderator has decided that this segment is correct"; } } @@ -337,7 +337,8 @@ export async function voteOnSponsorTime(req: Request, res: Response) { )).count; if (warningsCount >= config.maxNumberOfActiveWarnings) { - return res.status(403).send('Vote rejected due to a warning from a moderator. This means that we noticed you were making some common mistakes that are not malicious, and we just want to clarify the rules. Could you please send a message in Discord or Matrix so we can further help you?'); + res.status(403).send('Vote rejected due to a warning from a moderator. This means that we noticed you were making some common mistakes that are not malicious, and we just want to clarify the rules. Could you please send a message in Discord or Matrix so we can further help you?'); + return; } const voteTypeEnum = (type == 0 || type == 1 || type == 20) ? voteTypes.normal : voteTypes.incorrect; diff --git a/src/utils/diskCache.ts b/src/utils/diskCache.ts index f98d961..5e08603 100644 --- a/src/utils/diskCache.ts +++ b/src/utils/diskCache.ts @@ -10,22 +10,22 @@ if (config.diskCache) { DiskCache = { // constructor(rootPath, options): {}; - init() {}, + init(): void { return; }, - reset() {}, + reset(): void { return; }, - has(key) { return false; }, + has(key: string): boolean { return false; }, - get(key, opts) { return null; }, + get(key: string, opts): string { return null; }, // Returns size - set(key, dataOrSteam) { return new Promise((resolve) => 0); }, + set(key: string, dataOrSteam): Promise { return new Promise(() => 0); }, - del(key) {}, + del(key: string): void { return; }, - size() { return 0; }, + size(): number { return 0; }, - prune() {}, + prune(): void {return; }, }; } diff --git a/src/utils/getFormattedTime.ts b/src/utils/getFormattedTime.ts index afdc020..6a0b40f 100644 --- a/src/utils/getFormattedTime.ts +++ b/src/utils/getFormattedTime.ts @@ -1,9 +1,9 @@ /** * Converts time in seconds to minutes:seconds */ -export function getFormattedTime(totalSeconds: number) { - let minutes = Math.floor(totalSeconds / 60); - let seconds = totalSeconds - minutes * 60; +export function getFormattedTime(totalSeconds: number): string { + const minutes = Math.floor(totalSeconds / 60); + const seconds = totalSeconds - minutes * 60; let secondsDisplay = seconds.toFixed(3); if (seconds < 10) { //add a zero diff --git a/src/utils/getHash.ts b/src/utils/getHash.ts index 950a134..2e07e9e 100644 --- a/src/utils/getHash.ts +++ b/src/utils/getHash.ts @@ -5,7 +5,7 @@ export function getHash(value: T, times = 5000): T & HashedVal if (times <= 0) return "" as T & HashedValue; for (let i = 0; i < times; i++) { - let hashCreator = crypto.createHash('sha256'); + const hashCreator = crypto.createHash('sha256'); value = hashCreator.update(value).digest('hex') as T; } diff --git a/src/utils/getSubmissionUUID.ts b/src/utils/getSubmissionUUID.ts index ff72011..7d0f353 100644 --- a/src/utils/getSubmissionUUID.ts +++ b/src/utils/getSubmissionUUID.ts @@ -1,5 +1,6 @@ import {getHash} from './getHash'; +import { HashedValue } from '../types/hash.model'; -export function getSubmissionUUID(videoID: string, category: string, userID: string, startTime: number, endTime: number) { +export function getSubmissionUUID(videoID: string, category: string, userID: string, startTime: number, endTime: number): HashedValue{ return getHash('v2-categories' + videoID + startTime + endTime + category + userID, 1); } diff --git a/src/utils/logger.ts b/src/utils/logger.ts index bc29588..5871d3b 100644 --- a/src/utils/logger.ts +++ b/src/utils/logger.ts @@ -86,4 +86,4 @@ class Logger { const loggerInstance = new Logger(); export { loggerInstance as Logger -} +}; diff --git a/src/utils/queryCacher.ts b/src/utils/queryCacher.ts index 0c4d880..ae0f5d2 100644 --- a/src/utils/queryCacher.ts +++ b/src/utils/queryCacher.ts @@ -22,7 +22,7 @@ async function get(fetchFromDB: () => Promise, key: string): Promise { return data; } -function clearVideoCache(videoInfo: { videoID: VideoID; hashedVideoID: VideoIDHash; service: Service; userID?: UserID; }) { +function clearVideoCache(videoInfo: { videoID: VideoID; hashedVideoID: VideoIDHash; service: Service; userID?: UserID; }): void { if (videoInfo) { redis.delAsync(skipSegmentsKey(videoInfo.videoID, videoInfo.service)); redis.delAsync(skipSegmentsHashKey(videoInfo.hashedVideoID, videoInfo.service)); @@ -33,4 +33,4 @@ function clearVideoCache(videoInfo: { videoID: VideoID; hashedVideoID: VideoIDHa export const QueryCacher = { get, clearVideoCache -} \ No newline at end of file +}; \ No newline at end of file diff --git a/src/utils/redis.ts b/src/utils/redis.ts index 554e40a..ce41ee5 100644 --- a/src/utils/redis.ts +++ b/src/utils/redis.ts @@ -12,12 +12,12 @@ interface RedisSB { let exportObject: RedisSB = { get: (key, callback?) => callback(null, undefined), - getAsync: (key) => + getAsync: () => new Promise((resolve) => resolve({err: null, reply: undefined})), set: (key, value, callback) => callback(null, undefined), - setAsync: (key, value) => + setAsync: () => new Promise((resolve) => resolve({err: null, reply: undefined})), - delAsync: (...keys) => + delAsync: () => new Promise((resolve) => resolve(null)), }; diff --git a/src/utils/webhookUtils.ts b/src/utils/webhookUtils.ts index 591785f..ca270da 100644 --- a/src/utils/webhookUtils.ts +++ b/src/utils/webhookUtils.ts @@ -1,7 +1,6 @@ import {config} from '../config'; import {Logger} from '../utils/logger'; import fetch from 'node-fetch'; -import AbortController from "abort-controller"; function getVoteAuthorRaw(submissionCount: number, isVIP: boolean, isOwnSubmission: boolean): string { if (isOwnSubmission) { @@ -27,15 +26,15 @@ function getVoteAuthor(submissionCount: number, isVIP: boolean, isOwnSubmission: return ""; } -function dispatchEvent(scope: string, data: any): void { - let webhooks = config.webhooks; +function dispatchEvent(scope: string, data: Record): void { + const webhooks = config.webhooks; if (webhooks === undefined || webhooks.length === 0) return; Logger.debug("Dispatching webhooks"); for (const webhook of webhooks) { - let webhookURL = webhook.url; - let authKey = webhook.key; - let scopes = webhook.scopes || []; + const webhookURL = webhook.url; + const authKey = webhook.key; + const scopes = webhook.scopes || []; if (!scopes.includes(scope.toLowerCase())) return; fetch(webhookURL, { diff --git a/src/utils/youtubeApi.ts b/src/utils/youtubeApi.ts index 94a3829..25129ba 100644 --- a/src/utils/youtubeApi.ts +++ b/src/utils/youtubeApi.ts @@ -17,10 +17,10 @@ export class YouTubeAPI { if (data) { Logger.debug("YouTube API: cache used for video information: " + videoID); - return { err: null, data: JSON.parse(data) } + return { err: null, data: JSON.parse(data) }; } } catch (err) { - return { err } + return { err }; } } @@ -32,7 +32,7 @@ export class YouTubeAPI { if (result.ok) { const data = await result.json(); if (data.error) { - Logger.warn("NewLeaf API Error for " + videoID + ": " + data.error) + Logger.warn("NewLeaf API Error for " + videoID + ": " + data.error); return { err: data.error, data: null }; } @@ -45,7 +45,7 @@ export class YouTubeAPI { return { err: result.statusText, data: null }; } } catch (err) { - return {err, data: null} + return {err, data: null}; } } } diff --git a/test/cases/dbUpgrade.ts b/test/cases/dbUpgrade.ts index 12bfe92..1b863ee 100644 --- a/test/cases/dbUpgrade.ts +++ b/test/cases/dbUpgrade.ts @@ -1,10 +1,9 @@ import {db, privateDB} from '../../src/databases/databases'; -import {Done} from '../utils'; describe('dbUpgrade', () => { it('Should update the database version when starting the application', async () => { - let dbVersion = (await db.prepare('get', 'SELECT key, value FROM config where key = ?', ['version'])).value; - let privateVersion = (await privateDB.prepare('get', 'SELECT key, value FROM config where key = ?', ['version'])).value; + const dbVersion = (await db.prepare('get', 'SELECT key, value FROM config where key = ?', ['version'])).value; + const privateVersion = (await privateDB.prepare('get', 'SELECT key, value FROM config where key = ?', ['version'])).value; if (dbVersion >= 1 && privateVersion >= 1) return; else return 'Versions are not at least 1. db is ' + dbVersion + ', private is ' + privateVersion; }); diff --git a/test/cases/getIsUserVIP.ts b/test/cases/getIsUserVIP.ts index db79ba1..7f491c3 100644 --- a/test/cases/getIsUserVIP.ts +++ b/test/cases/getIsUserVIP.ts @@ -14,7 +14,7 @@ describe('getIsUserVIP', () => { if (res.status !== 200) done("non 200: " + res.status); else done(); // pass }) - .catch(err => done("couldn't call endpoint")); + .catch(() => done("couldn't call endpoint")); }); @@ -24,7 +24,7 @@ describe('getIsUserVIP', () => { if (res.status !== 400) done("non 400: " + res.status); else done(); // pass }) - .catch(err => done("couldn't call endpoint")); + .catch(() => done("couldn't call endpoint")); }); it('Should say a VIP is a VIP', (done: Done) => { @@ -37,7 +37,7 @@ describe('getIsUserVIP', () => { else done("Result was non-vip when should have been vip"); } }) - .catch(err => done("couldn't call endpoint")); + .catch(() => done("couldn't call endpoint")); }); it('Should say a normal user is not a VIP', (done: Done) => { @@ -50,6 +50,6 @@ describe('getIsUserVIP', () => { else done("Result was vip when should have been non-vip"); } }) - .catch(err => done("couldn't call endpoint")); + .catch(() => done("couldn't call endpoint")); }); }); diff --git a/test/cases/getSavedTimeForUser.ts b/test/cases/getSavedTimeForUser.ts index 2df3a83..94405f5 100644 --- a/test/cases/getSavedTimeForUser.ts +++ b/test/cases/getSavedTimeForUser.ts @@ -5,7 +5,7 @@ import {getHash} from '../../src/utils/getHash'; describe('getSavedTimeForUser', () => { before(async () => { - let startOfQuery = 'INSERT INTO "sponsorTimes" ("videoID", "startTime", "endTime", "votes", "UUID", "userID", "timeSubmitted", views, category, "shadowHidden", "hashedVideoID") VALUES'; + const startOfQuery = 'INSERT INTO "sponsorTimes" ("videoID", "startTime", "endTime", "votes", "UUID", "userID", "timeSubmitted", views, category, "shadowHidden", "hashedVideoID") VALUES'; await db.prepare("run", startOfQuery + "(?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)", ['getSavedTimeForUser', 1, 11, 2, 'abc1239999', getHash("testman"), 0, 50, 'sponsor', 0, getHash('getSavedTimeForUser', 0)]); return; @@ -17,6 +17,6 @@ describe('getSavedTimeForUser', () => { if (res.status !== 200) done("non 200"); else done(); // pass }) - .catch(err => done("couldn't call endpoint")); + .catch(() => done("couldn't call endpoint")); }); }); diff --git a/test/cases/getSegmentInfo.ts b/test/cases/getSegmentInfo.ts index a6c2f0d..912619c 100644 --- a/test/cases/getSegmentInfo.ts +++ b/test/cases/getSegmentInfo.ts @@ -20,7 +20,7 @@ const oldID = `${'0'.repeat(8)}-${'0000-'.repeat(3)}${'0'.repeat(12)}` describe('getSegmentInfo', () => { before(async () => { - let insertQuery = `INSERT INTO + const insertQuery = `INSERT INTO "sponsorTimes"("videoID", "startTime", "endTime", "votes", "locked", "UUID", "userID", "timeSubmitted", "views", "category", "service", "videoDuration", "hidden", "shadowHidden", "hashedVideoID") @@ -53,7 +53,7 @@ describe('getSegmentInfo', () => { } } }) - .catch(err => "Couldn't call endpoint"); + .catch(() => "Couldn't call endpoint"); }); it('Should be able to retreive downvoted segment', (done: Done) => { @@ -69,7 +69,7 @@ describe('getSegmentInfo', () => { } } }) - .catch(err => "Couldn't call endpoint"); + .catch(() => "Couldn't call endpoint"); }); it('Should be able to retreive locked up segment', (done: Done) => { @@ -85,7 +85,7 @@ describe('getSegmentInfo', () => { } } }) - .catch(err => "Couldn't call endpoint"); + .catch(() => "Couldn't call endpoint"); }); it('Should be able to retreive infinite vote segment', (done: Done) => { @@ -101,7 +101,7 @@ describe('getSegmentInfo', () => { } } }) - .catch(err => "Couldn't call endpoint"); + .catch(() => "Couldn't call endpoint"); }); it('Should be able to retreive shadowhidden segment', (done: Done) => { @@ -117,7 +117,7 @@ describe('getSegmentInfo', () => { } } }) - .catch(err => "Couldn't call endpoint"); + .catch(() => "Couldn't call endpoint"); }); it('Should be able to retreive locked down segment', (done: Done) => { @@ -133,7 +133,7 @@ describe('getSegmentInfo', () => { } } }) - .catch(err => "Couldn't call endpoint"); + .catch(() => "Couldn't call endpoint"); }); it('Should be able to retreive hidden segment', (done: Done) => { @@ -149,7 +149,7 @@ describe('getSegmentInfo', () => { } } }) - .catch(err => "Couldn't call endpoint"); + .catch(() => "Couldn't call endpoint"); }); it('Should be able to retreive segment with old ID', (done: Done) => { @@ -165,7 +165,7 @@ describe('getSegmentInfo', () => { } } }) - .catch(err => "Couldn't call endpoint"); + .catch(() => "Couldn't call endpoint"); }); it('Should be able to retreive single segment in array', (done: Done) => { @@ -181,7 +181,7 @@ describe('getSegmentInfo', () => { } } }) - .catch(err => "Couldn't call endpoint"); + .catch(() => "Couldn't call endpoint"); }); it('Should be able to retreive multiple segments in array', (done: Done) => { @@ -199,7 +199,7 @@ describe('getSegmentInfo', () => { } } }) - .catch(err => "Couldn't call endpoint"); + .catch(() => "Couldn't call endpoint"); }); it('Should be possible to send unexpected query parameters', (done: Done) => { @@ -215,7 +215,7 @@ describe('getSegmentInfo', () => { } } }) - .catch(err => "Couldn't call endpoint"); + .catch(() => "Couldn't call endpoint"); }); it('Should return 400 if array passed to UUID', (done: Done) => { @@ -224,7 +224,7 @@ describe('getSegmentInfo', () => { if (res.status !== 400) done("non 400 respone code: " + res.status); else done(); // pass }) - .catch(err => ("couldn't call endpoint")); + .catch(() => ("couldn't call endpoint")); }); it('Should return 400 if bad array passed to UUIDs', (done: Done) => { @@ -233,7 +233,7 @@ describe('getSegmentInfo', () => { if (res.status !== 400) done("non 404 respone code: " + res.status); else done(); // pass }) - .catch(err => ("couldn't call endpoint")); + .catch(() => ("couldn't call endpoint")); }); it('Should return 400 if bad UUID passed', (done: Done) => { @@ -242,7 +242,7 @@ describe('getSegmentInfo', () => { if (res.status !== 400) done("non 400 respone code: " + res.status); else done(); // pass }) - .catch(err => ("couldn't call endpoint")); + .catch(() => ("couldn't call endpoint")); }); it('Should return 400 if bad UUIDs passed in array', (done: Done) => { @@ -251,7 +251,7 @@ describe('getSegmentInfo', () => { if (res.status !== 400) done("non 400 respone code: " + res.status); else done(); // pass }) - .catch(err => ("couldn't call endpoint")); + .catch(() => ("couldn't call endpoint")); }); it('Should return good UUID when mixed with bad UUIDs', (done: Done) => { @@ -267,7 +267,7 @@ describe('getSegmentInfo', () => { } } }) - .catch(err => ("couldn't call endpoint")); + .catch(() => ("couldn't call endpoint")); }); it('Should cut off array at 10', function(done: Done) { @@ -286,7 +286,7 @@ describe('getSegmentInfo', () => { } } }) - .catch(err => ("couldn't call endpoint")); + .catch(() => ("couldn't call endpoint")); }); it('Should not duplicate reponses', (done: Done) => { @@ -302,7 +302,7 @@ describe('getSegmentInfo', () => { } } }) - .catch(err => ("couldn't call endpoint")); + .catch(() => ("couldn't call endpoint")); }); it('Should return 400 if UUID not found', (done: Done) => { @@ -311,7 +311,7 @@ describe('getSegmentInfo', () => { if (res.status !== 400) done("non 400 respone code: " + res.status); else done(); // pass }) - .catch(err => ("couldn't call endpoint")); + .catch(() => ("couldn't call endpoint")); }); it('Should be able to retreive multiple segments with multiple parameters', (done: Done) => { @@ -329,11 +329,11 @@ describe('getSegmentInfo', () => { } } }) - .catch(err => "Couldn't call endpoint"); + .catch(() => "Couldn't call endpoint"); }); it('Should not parse repeated UUID if UUIDs present', (done: Done) => { - fetch(getbaseURL() + `/api/segmentInfo?UUID=${downvotedID}&UUID=${lockedupID}&UUIDs=[\"${upvotedID}\"]`) + fetch(getbaseURL() + `/api/segmentInfo?UUID=${downvotedID}&UUID=${lockedupID}&UUIDs=["${upvotedID}"]`) .then(async res => { if (res.status !== 200) done("Status code was: " + res.status); else { @@ -346,6 +346,6 @@ describe('getSegmentInfo', () => { } } }) - .catch(err => "Couldn't call endpoint"); + .catch(() => "Couldn't call endpoint"); }); }); diff --git a/test/cases/getSkipSegments.ts b/test/cases/getSkipSegments.ts index 7ec0798..5a26e10 100644 --- a/test/cases/getSkipSegments.ts +++ b/test/cases/getSkipSegments.ts @@ -35,7 +35,7 @@ describe('getSkipSegments', () => { } } }) - .catch(err => "Couldn't call endpoint"); + .catch(() => "Couldn't call endpoint"); }); it('Should be able to get a time by category for a different service 1', (done: Done) => { @@ -52,7 +52,7 @@ describe('getSkipSegments', () => { } } }) - .catch(err => "Couldn't call endpoint"); + .catch(() => "Couldn't call endpoint"); }); it('Should be able to get a time by category 2', (done: Done) => { @@ -69,7 +69,7 @@ describe('getSkipSegments', () => { } } }) - .catch(err => ("Couldn't call endpoint")); + .catch(() => ("Couldn't call endpoint")); }); it('Should be able to get a time by categories array', (done: Done) => { @@ -86,7 +86,7 @@ describe('getSkipSegments', () => { } } }) - .catch(err => ("Couldn't call endpoint")); + .catch(() => ("Couldn't call endpoint")); }); it('Should be able to get a time by categories array 2', (done: Done) => { @@ -103,7 +103,7 @@ describe('getSkipSegments', () => { } } }) - .catch(err => ("Couldn't call endpoint")); + .catch(() => ("Couldn't call endpoint")); }); it('Should return 404 if all submissions are hidden', (done: Done) => { @@ -112,7 +112,7 @@ describe('getSkipSegments', () => { if (res.status !== 404) done("non 404 respone code: " + res.status); else done(); // pass }) - .catch(err => ("Couldn't call endpoint")); + .catch(() => ("Couldn't call endpoint")); }); it('Should be able to get multiple times by category', (done: Done) => { @@ -171,7 +171,7 @@ describe('getSkipSegments', () => { } } }) - .catch(err => ("Couldn't call endpoint")); + .catch(() => ("Couldn't call endpoint")); }); it('Should be possible to send unexpected query parameters', (done: Done) => { @@ -189,7 +189,7 @@ describe('getSkipSegments', () => { } } }) - .catch(err => done("Couldn't call endpoint")); + .catch(() => done("Couldn't call endpoint")); }); it('Low voted submissions should be hidden', (done: Done) => { @@ -207,7 +207,7 @@ describe('getSkipSegments', () => { } } }) - .catch(err => ("Couldn't call endpoint")); + .catch(() => ("Couldn't call endpoint")); }); it('Should return 404 if no segment found', (done: Done) => { @@ -216,7 +216,7 @@ describe('getSkipSegments', () => { if (res.status !== 404) done("non 404 respone code: " + res.status); else done(); // pass }) - .catch(err => ("couldn't call endpoint")); + .catch(() => ("couldn't call endpoint")); }); it('Should return 400 if bad categories argument', (done: Done) => { @@ -225,7 +225,7 @@ describe('getSkipSegments', () => { if (res.status !== 400) done("non 400 respone code: " + res.status); else done(); // pass }) - .catch(err => ("couldn't call endpoint")); + .catch(() => ("couldn't call endpoint")); }); it('Should be able send a comma in a query param', (done: Done) => { @@ -243,7 +243,7 @@ describe('getSkipSegments', () => { } } }) - .catch(err => ("Couldn't call endpoint")); + .catch(() => ("Couldn't call endpoint")); }); it('Should always get locked segment', (done: Done) => { @@ -260,7 +260,7 @@ describe('getSkipSegments', () => { } } }) - .catch(err => ("Couldn't call endpoint")); + .catch(() => ("Couldn't call endpoint")); }); it('Should be able to get multiple categories with repeating parameters', (done: Done) => { @@ -290,7 +290,7 @@ describe('getSkipSegments', () => { } } }) - .catch(err => ("Couldn't call endpoint")); + .catch(() => ("Couldn't call endpoint")); }); it('Should be able to get, categories param overriding repeating category', (done: Done) => { @@ -307,6 +307,6 @@ describe('getSkipSegments', () => { } } }) - .catch(err => ("Couldn't call endpoint")); + .catch(() => ("Couldn't call endpoint")); }); }); diff --git a/test/cases/getSkipSegmentsByHash.ts b/test/cases/getSkipSegmentsByHash.ts index 92cce4d..18f19b4 100644 --- a/test/cases/getSkipSegmentsByHash.ts +++ b/test/cases/getSkipSegmentsByHash.ts @@ -29,7 +29,7 @@ describe('getSegmentsByHash', () => { if (res.status !== 200) done("non 200 status code, was " + res.status); else done(); // pass }) - .catch(err => done("Couldn't call endpoint")); + .catch(() => done("Couldn't call endpoint")); }); it('Should return 404 if no segments are found even if a video for the given hash is known', (done: Done) => { @@ -42,7 +42,7 @@ describe('getSegmentsByHash', () => { else done("Response had videos"); } }) - .catch(err => done("Couldn't call endpoint")); + .catch(() => done("Couldn't call endpoint")); }); it('Should be able to get an empty array if no videos', (done: Done) => { @@ -55,7 +55,7 @@ describe('getSegmentsByHash', () => { else done("non empty array returned"); } }) - .catch(err => done("Couldn't call endpoint")); + .catch(() => done("Couldn't call endpoint")); }); it('Should be able to get an empty array if only hidden videos', (done: Done) => { @@ -68,7 +68,7 @@ describe('getSegmentsByHash', () => { else done("non empty array returned"); } }) - .catch(err => done("Couldn't call endpoint")); + .catch(() => done("Couldn't call endpoint")); }); it('Should return 400 prefix too short', (done: Done) => { @@ -77,11 +77,11 @@ describe('getSegmentsByHash', () => { if (res.status !== 400) done("non 400 status code, was " + res.status); else done(); // pass }) - .catch(err => done("Couldn't call endpoint")); + .catch(() => done("Couldn't call endpoint")); }); it('Should return 400 prefix too long', (done: Done) => { - let prefix = new Array(50).join('1'); + const prefix = new Array(50).join('1'); if (prefix.length <= 32) { // default value, config can change this done('failed to generate a long enough string for the test ' + prefix.length); return; @@ -91,7 +91,7 @@ describe('getSegmentsByHash', () => { if (res.status !== 400) done("non 400 status code, was " + res.status); else done(); // pass }) - .catch(err => done("Couldn't call endpoint")); + .catch(() => done("Couldn't call endpoint")); }); it('Should not return 400 prefix in range', (done: Done) => { @@ -100,7 +100,7 @@ describe('getSegmentsByHash', () => { if (res.status === 400) done("prefix length 5 gave 400 " + res.status); else done(); // pass }) - .catch(err => done("Couldn't call endpoint")); + .catch(() => done("Couldn't call endpoint")); }); it('Should return 404 for no hash', (done: Done) => { @@ -109,7 +109,7 @@ describe('getSegmentsByHash', () => { if (res.status !== 404) done("expected 404, got " + res.status); else done(); // pass }) - .catch(err => done("Couldn't call endpoint")); + .catch(() => done("Couldn't call endpoint")); }); it('Should return 400 for bad format categories', (done: Done) => { @@ -118,7 +118,7 @@ describe('getSegmentsByHash', () => { if (res.status !== 400) done("expected 400 got " + res.status); else done(); // pass }) - .catch(err => done("Couldn't call endpoint")); + .catch(() => done("Couldn't call endpoint")); }); it('Should be able to get multiple videos', (done: Done) => { @@ -133,7 +133,7 @@ describe('getSegmentsByHash', () => { else done(); } }) - .catch(err => done("Couldn't call endpoint")); + .catch(() => done("Couldn't call endpoint")); }); it('Should be able to get 200 for no categories (default sponsor)', (done: Done) => { @@ -151,7 +151,7 @@ describe('getSegmentsByHash', () => { else done(); } }) - .catch(err => done("Couldn't call endpoint")); + .catch(() => done("Couldn't call endpoint")); }); it('Should be able to get 200 for no categories (default sponsor) for a non YouTube service', (done: Done) => { @@ -166,7 +166,7 @@ describe('getSegmentsByHash', () => { else done(); } }) - .catch(err => done("Couldn't call endpoint")); + .catch(() => done("Couldn't call endpoint")); }); it('Should only return one segment when fetching highlight segments', (done: Done) => { @@ -180,11 +180,11 @@ describe('getSegmentsByHash', () => { else done(); } }) - .catch(err => done("Couldn't call endpoint")); + .catch(() => done("Couldn't call endpoint")); }); it('Should be able to post a segment and get it using endpoint', (done: Done) => { - let testID = 'abc123goodVideo'; + const testID = 'abc123goodVideo'; fetch(getbaseURL() + "/api/postVideoSponsorTimes", { method: 'POST', headers: { @@ -212,7 +212,7 @@ describe('getSegmentsByHash', () => { else done(); } }) - .catch(err => done("(get) Couldn't call endpoint")); + .catch(() => done("(get) Couldn't call endpoint")); } else { done("(post) non 200 status code, was " + res.status); } diff --git a/test/cases/getUserID.ts b/test/cases/getUserID.ts index 7fe5d70..e0c7c5a 100644 --- a/test/cases/getUserID.ts +++ b/test/cases/getUserID.ts @@ -23,11 +23,10 @@ describe('getUserID', () => { it('Should be able to get a 200', (done: Done) => { fetch(getbaseURL() + '/api/userID?username=fuzzy+user+01') .then(async res => { - const text = await res.text() if (res.status !== 200) done('non 200 (' + res.status + ')'); else done(); // pass }) - .catch(err => done('couldn\'t call endpoint')); + .catch(() => done('couldn\'t call endpoint')); }); it('Should be able to get a 400 (No username parameter)', (done: Done) => { @@ -36,17 +35,16 @@ describe('getUserID', () => { if (res.status !== 400) done('non 400 (' + res.status + ')'); else done(); // pass }) - .catch(err => done('couldn\'t call endpoint')); + .catch(() => done('couldn\'t call endpoint')); }); it('Should be able to get a 200 (username is public id)', (done: Done) => { fetch(getbaseURL() + '/api/userID?username='+getHash("getuserid_user_06")) .then(async res => { - const text = await res.text() if (res.status !== 200) done('non 200 (' + res.status + ')'); else done(); // pass }) - .catch(err => done('couldn\'t call endpoint')); + .catch(() => done('couldn\'t call endpoint')); }); it('Should be able to get a 400 (username longer than 64 chars)', (done: Done) => { @@ -55,7 +53,7 @@ describe('getUserID', () => { if (res.status !== 400) done('non 400 (' + res.status + ')'); else done(); // pass }) - .catch(err => done('couldn\'t call endpoint')); + .catch(() => done('couldn\'t call endpoint')); }); it('Should be able to get single username', (done: Done) => { @@ -76,7 +74,7 @@ describe('getUserID', () => { } } }) - .catch(err => ("couldn't call endpoint")); + .catch(() => ("couldn't call endpoint")); }); it('Should be able to get multiple fuzzy user info from start', (done: Done) => { @@ -101,7 +99,7 @@ describe('getUserID', () => { } } }) - .catch(err => ("couldn't call endpoint")); + .catch(() => ("couldn't call endpoint")); }); it('Should be able to get multiple fuzzy user info from middle', (done: Done) => { @@ -130,7 +128,7 @@ describe('getUserID', () => { } } }) - .catch(err => ("couldn't call endpoint")); + .catch(() => ("couldn't call endpoint")); }); it('Should be able to get with public ID', (done: Done) => { @@ -152,7 +150,7 @@ describe('getUserID', () => { } } }) - .catch(err => ("couldn't call endpoint")); + .catch(() => ("couldn't call endpoint")); }); it('Should be able to get with fuzzy public ID', (done: Done) => { @@ -174,7 +172,7 @@ describe('getUserID', () => { } } }) - .catch(err => ("couldn't call endpoint")); + .catch(() => ("couldn't call endpoint")); }); it('Should be able to get repeating username', (done: Done) => { @@ -199,7 +197,7 @@ describe('getUserID', () => { } } }) - .catch(err => ("couldn't call endpoint")); + .catch(() => ("couldn't call endpoint")); }); it('Should be able to get repeating fuzzy username', (done: Done) => { @@ -224,7 +222,7 @@ describe('getUserID', () => { } } }) - .catch(err => ("couldn't call endpoint")); + .catch(() => ("couldn't call endpoint")); }); it('should avoid ReDOS with _', (done: Done) => { @@ -245,7 +243,7 @@ describe('getUserID', () => { } } }) - .catch(err => ("couldn't call endpoint")); + .catch(() => ("couldn't call endpoint")); }); it('should avoid ReDOS with %', (done: Done) => { @@ -266,7 +264,7 @@ describe('getUserID', () => { } } }) - .catch(err => ("couldn't call endpoint")); + .catch(() => ("couldn't call endpoint")); }); it('should return 404 if escaped backslashes present', (done: Done) => { @@ -275,7 +273,7 @@ describe('getUserID', () => { if (res.status !== 404) done('non 404 (' + res.status + ')'); else done(); // pass }) - .catch(err => ("couldn't call endpoint")); + .catch(() => ("couldn't call endpoint")); }); it('should return 404 if backslashes present', (done: Done) => { @@ -284,7 +282,7 @@ describe('getUserID', () => { if (res.status !== 404) done('non 404 (' + res.status + ')'); else done(); // pass }) - .catch(err => ("couldn't call endpoint")); + .catch(() => ("couldn't call endpoint")); }); it('should return user if just backslashes', (done: Done) => { @@ -305,7 +303,7 @@ describe('getUserID', () => { } } }) - .catch(err => ("couldn't call endpoint")); + .catch(() => ("couldn't call endpoint")); }); it('should not allow usernames more than 64 characters', (done: Done) => { @@ -314,7 +312,7 @@ describe('getUserID', () => { if (res.status !== 400) done('non 400 (' + res.status + ')'); else done(); // pass }) - .catch(err => ("couldn't call endpoint")); + .catch(() => ("couldn't call endpoint")); }); it('should not allow usernames less than 3 characters', (done: Done) => { @@ -323,7 +321,7 @@ describe('getUserID', () => { if (res.status !== 400) done('non 400 (' + res.status + ')'); else done(); // pass }) - .catch(err => ("couldn't call endpoint")); + .catch(() => ("couldn't call endpoint")); }); it('should allow exact match', (done: Done) => { @@ -344,7 +342,7 @@ describe('getUserID', () => { } } }) - .catch(err => ("couldn't call endpoint")); + .catch(() => ("couldn't call endpoint")); }); it('Should be able to get repeating username with exact username', (done: Done) => { @@ -369,7 +367,7 @@ describe('getUserID', () => { } } }) - .catch(err => ("couldn't call endpoint")); + .catch(() => ("couldn't call endpoint")); }); it('Should not get exact unless explicitly set to true', (done: Done) => { @@ -398,6 +396,6 @@ describe('getUserID', () => { } } }) - .catch(err => ("couldn't call endpoint")); + .catch(() => ("couldn't call endpoint")); }); }); diff --git a/test/cases/getUserInfo.ts b/test/cases/getUserInfo.ts index 89bb319..f641e1b 100644 --- a/test/cases/getUserInfo.ts +++ b/test/cases/getUserInfo.ts @@ -30,7 +30,7 @@ describe('getUserInfo', () => { if (res.status !== 200) done('non 200 (' + res.status + ')'); else done(); // pass }) - .catch(err => done('couldn\'t call endpoint')); + .catch(() => done('couldn\'t call endpoint')); }); it('Should be able to get a 400 (No userID parameter)', (done: Done) => { @@ -39,7 +39,7 @@ describe('getUserInfo', () => { if (res.status !== 400) done('non 400 (' + res.status + ')'); else done(); // pass }) - .catch(err => done('couldn\'t call endpoint')); + .catch(() => done('couldn\'t call endpoint')); }); it('Should be able to get user info', (done: Done) => { @@ -70,7 +70,7 @@ describe('getUserInfo', () => { } } }) - .catch(err => ("couldn't call endpoint")); + .catch(() => ("couldn't call endpoint")); }); it('Should get warning data', (done: Done) => { @@ -79,12 +79,12 @@ describe('getUserInfo', () => { if (res.status !== 200) { done('non 200 (' + res.status + ')'); } else { - const data = await res.json();; + const data = await res.json(); if (data.warnings !== 1) done('wrong number of warnings: ' + data.warnings + ', not ' + 1); else done(); // pass } }) - .catch(err => ("couldn't call endpoint")); + .catch(() => ("couldn't call endpoint")); }); it('Should get warning data with public ID', (done: Done) => { @@ -98,7 +98,7 @@ describe('getUserInfo', () => { else done(); } }) - .catch(err => ("couldn't call endpoint")); + .catch(() => ("couldn't call endpoint")); }); it('Should get multiple warnings', (done: Done) => { @@ -112,7 +112,7 @@ describe('getUserInfo', () => { else done(); // pass } }) - .catch(err => ("couldn't call endpoint")); + .catch(() => ("couldn't call endpoint")); }); it('Should not get warnings if none', (done: Done) => { @@ -126,7 +126,7 @@ describe('getUserInfo', () => { else done(); // pass } }) - .catch(err => ("couldn't call endpoint")); + .catch(() => ("couldn't call endpoint")); }); it('Should done(userID for userName (No userName set)', (done: Done) => { @@ -142,7 +142,7 @@ describe('getUserInfo', () => { done(); // pass } }) - .catch(err => ('couldn\'t call endpoint')); + .catch(() => ('couldn\'t call endpoint')); }); it('Should return null segment if none', (done: Done) => { @@ -156,20 +156,20 @@ describe('getUserInfo', () => { else done(); // pass } }) - .catch(err => ("couldn't call endpoint")); + .catch(() => ("couldn't call endpoint")); }); it('Should return zeroes if userid does not exist', (done: Done) => { fetch(getbaseURL() + '/api/userInfo?userID=getuserinfo_null') .then(async res => { const data = await res.json(); - for (var value in data) { + for (const value in data) { if (data[value] === null && value !== "lastSegmentID") { done(`returned null for ${value}`) } } done(); // pass }) - .catch(err => ("couldn't call endpoint")); + .catch(() => ("couldn't call endpoint")); }); }); diff --git a/test/cases/lockCategoriesRecords.ts b/test/cases/lockCategoriesRecords.ts index 9779f71..e462c9e 100644 --- a/test/cases/lockCategoriesRecords.ts +++ b/test/cases/lockCategoriesRecords.ts @@ -24,13 +24,13 @@ describe('lockCategoriesRecords', () => { }); it('Should update the database version when starting the application', async () => { - let version = (await db.prepare('get', 'SELECT key, value FROM config where key = ?', ['version'])).value; + const version = (await db.prepare('get', 'SELECT key, value FROM config where key = ?', ['version'])).value; if (version > 1) return; else return 'Version isn\'t greater than 1. Version is ' + version; }); it('Should be able to submit categories not in video (http response)', (done: Done) => { - let json = { + const json = { videoID: 'no-segments-video-id', userID: 'VIPUser-lockCategories', categories: [ @@ -43,7 +43,7 @@ describe('lockCategoriesRecords', () => { ], }; - let expected = { + const expected = { submitted: [ 'outro', 'shilling', @@ -66,7 +66,6 @@ describe('lockCategoriesRecords', () => { done("Incorrect response: expected " + JSON.stringify(expected) + " got " + JSON.stringify(data)); } } else { - const body = await res.text(); done("Status code was " + res.status); } }) @@ -74,7 +73,7 @@ describe('lockCategoriesRecords', () => { }); it('Should be able to submit categories not in video (sql check)', (done: Done) => { - let json = { + const json = { videoID: 'no-segments-video-id-1', userID: 'VIPUser-lockCategories', categories: [ @@ -96,14 +95,13 @@ describe('lockCategoriesRecords', () => { }) .then(async res => { if (res.status === 200) { - let result = await db.prepare('all', 'SELECT * FROM "lockCategories" WHERE "videoID" = ?', ['no-segments-video-id-1']); + const result = await db.prepare('all', 'SELECT * FROM "lockCategories" WHERE "videoID" = ?', ['no-segments-video-id-1']); if (result.length !== 4) { done("Expected 4 entrys in db, got " + result.length); } else { done(); } } else { - const body = await res.text(); done("Status code was " + res.status); } }) @@ -111,7 +109,7 @@ describe('lockCategoriesRecords', () => { }); it('Should be able to submit categories with _ in the category', (done: Done) => { - let json = { + const json = { videoID: 'underscore', userID: 'VIPUser-lockCategories', categories: [ @@ -128,14 +126,13 @@ describe('lockCategoriesRecords', () => { }) .then(async res => { if (res.status === 200) { - let result = await db.prepare('all', 'SELECT * FROM "lockCategories" WHERE "videoID" = ?', ['underscore']); + const result = await db.prepare('all', 'SELECT * FROM "lockCategories" WHERE "videoID" = ?', ['underscore']); if (result.length !== 1) { done("Expected 1 entrys in db, got " + result.length); } else { done(); } } else { - const body = await res.text(); done("Status code was " + res.status); } }) @@ -143,7 +140,7 @@ describe('lockCategoriesRecords', () => { }); it('Should be able to submit categories with upper and lower case in the category', (done: Done) => { - let json = { + const json = { videoID: 'bothCases', userID: 'VIPUser-lockCategories', categories: [ @@ -160,14 +157,13 @@ describe('lockCategoriesRecords', () => { }) .then(async res => { if (res.status === 200) { - let result = await db.prepare('all', 'SELECT * FROM "lockCategories" WHERE "videoID" = ?', ['bothCases']); + const result = await db.prepare('all', 'SELECT * FROM "lockCategories" WHERE "videoID" = ?', ['bothCases']); if (result.length !== 1) { done("Expected 1 entrys in db, got " + result.length); } else { done(); } } else { - const body = await res.text(); done("Status code was " + res.status); } }) @@ -175,7 +171,7 @@ describe('lockCategoriesRecords', () => { }); it('Should not be able to submit categories with $ in the category', (done: Done) => { - let json = { + const json = { videoID: 'specialChar', userID: 'VIPUser-lockCategories', categories: [ @@ -192,14 +188,13 @@ describe('lockCategoriesRecords', () => { }) .then(async res => { if (res.status === 200) { - let result = await db.prepare('all', 'SELECT * FROM "lockCategories" WHERE "videoID" = ?', ['specialChar']); + const result = await db.prepare('all', 'SELECT * FROM "lockCategories" WHERE "videoID" = ?', ['specialChar']); if (result.length !== 0) { done("Expected 0 entrys in db, got " + result.length); } else { done(); } } else { - const body = await res.text(); done("Status code was " + res.status); } }) @@ -225,7 +220,7 @@ describe('lockCategoriesRecords', () => { }); it('Should return 400 for no categories', (done: Done) => { - let json: any = { + const json: any = { videoID: 'test', userID: 'test', categories: [], @@ -249,7 +244,7 @@ describe('lockCategoriesRecords', () => { }); it('Should return 400 for no userID', (done: Done) => { - let json: any = { + const json: any = { videoID: 'test', userID: null, categories: ['sponsor'], @@ -273,7 +268,7 @@ describe('lockCategoriesRecords', () => { }); it('Should return 400 for no videoID', (done: Done) => { - let json: any = { + const json: any = { videoID: null, userID: 'test', categories: ['sponsor'], @@ -297,7 +292,7 @@ describe('lockCategoriesRecords', () => { }); it('Should return 400 object categories', (done: Done) => { - let json = { + const json = { videoID: 'test', userID: 'test', categories: {}, @@ -321,7 +316,7 @@ describe('lockCategoriesRecords', () => { }); it('Should return 400 bad format categories', (done: Done) => { - let json = { + const json = { videoID: 'test', userID: 'test', categories: 'sponsor', @@ -345,7 +340,7 @@ describe('lockCategoriesRecords', () => { }); it('Should return 403 if user is not VIP', (done: Done) => { - let json = { + const json = { videoID: 'test', userID: 'test', categories: [ @@ -371,7 +366,7 @@ describe('lockCategoriesRecords', () => { }); it('Should be able to delete a lockCategories record', (done: Done) => { - let json = { + const json = { videoID: 'delete-record', userID: 'VIPUser-lockCategories', categories: [ @@ -388,7 +383,7 @@ describe('lockCategoriesRecords', () => { }) .then(async res => { if (res.status === 200) { - let result = await db.prepare('all', 'SELECT * FROM "lockCategories" WHERE "videoID" = ?', ['delete-record']); + const result = await db.prepare('all', 'SELECT * FROM "lockCategories" WHERE "videoID" = ?', ['delete-record']); if (result.length === 0) { done(); } else { @@ -402,7 +397,7 @@ describe('lockCategoriesRecords', () => { }); it('Should be able to delete one lockCategories record without removing another', (done: Done) => { - let json = { + const json = { videoID: 'delete-record-1', userID: 'VIPUser-lockCategories', categories: [ @@ -419,7 +414,7 @@ describe('lockCategoriesRecords', () => { }) .then(async res => { if (res.status === 200) { - let result = await db.prepare('all', 'SELECT * FROM "lockCategories" WHERE "videoID" = ?', ['delete-record-1']); + const result = await db.prepare('all', 'SELECT * FROM "lockCategories" WHERE "videoID" = ?', ['delete-record-1']); if (result.length === 1) { done(); } else { diff --git a/test/cases/oldGetSponsorTime.ts b/test/cases/oldGetSponsorTime.ts index 43714e9..9a19fa2 100644 --- a/test/cases/oldGetSponsorTime.ts +++ b/test/cases/oldGetSponsorTime.ts @@ -16,7 +16,7 @@ describe('getVideoSponsorTime (Old get method)', () => { if (res.status !== 200) done("non 200 (" + res.status + ")"); else done(); // pass }) - .catch(err => done("Couldn't call endpoint")); + .catch(() => done("Couldn't call endpoint")); }); it('Should return 404 if no segment found', (done: Done) => { @@ -25,7 +25,7 @@ describe('getVideoSponsorTime (Old get method)', () => { if (res.status !== 404) done("non 404 respone code: " + res.status); else done(); // pass }) - .catch(err => done("couldn't call endpoint")); + .catch(() => done("couldn't call endpoint")); }); @@ -35,7 +35,7 @@ describe('getVideoSponsorTime (Old get method)', () => { if (res.status !== 200) done("non 200"); else done(); // pass }) - .catch(err => done("couldn't callendpoint")); + .catch(() => done("couldn't callendpoint")); }); it('Should be able send a comma in a query param', (done: Done) => { @@ -46,7 +46,7 @@ describe('getVideoSponsorTime (Old get method)', () => { else if (JSON.parse(body).UUIDs[0] === 'uuid-1') done(); // pass else done("couldn't parse response"); }) - .catch(err => done("couln't call endpoint")); + .catch(() => done("couln't call endpoint")); }); it('Should be able to get the correct time', (done: Done) => { @@ -65,6 +65,6 @@ describe('getVideoSponsorTime (Old get method)', () => { } }) - .catch(err => done("couldn't call endpoint")); + .catch(() => done("couldn't call endpoint")); }); }); diff --git a/test/cases/oldSubmitSponsorTimes.ts b/test/cases/oldSubmitSponsorTimes.ts index 90e0449..25475e5 100644 --- a/test/cases/oldSubmitSponsorTimes.ts +++ b/test/cases/oldSubmitSponsorTimes.ts @@ -9,7 +9,7 @@ describe('postVideoSponsorTime (Old submission method)', () => { + "/api/postVideoSponsorTimes?videoID=dQw4w9WgXcQ&startTime=1&endTime=10&userID=test") .then(async res => { if (res.status === 200) { - let row = await db.prepare('get', `SELECT "startTime", "endTime", "category" FROM "sponsorTimes" WHERE "videoID" = ?`, ["dQw4w9WgXcQ"]); + const row = await db.prepare('get', `SELECT "startTime", "endTime", "category" FROM "sponsorTimes" WHERE "videoID" = ?`, ["dQw4w9WgXcQ"]); if (row.startTime === 1 && row.endTime === 10 && row.category === "sponsor") { done(); } else { @@ -32,7 +32,7 @@ describe('postVideoSponsorTime (Old submission method)', () => { }) .then(async res => { if (res.status === 200) { - let row = await db.prepare('get', `SELECT "startTime", "endTime", "category" FROM "sponsorTimes" WHERE "videoID" = ?`, ["dQw4w9WgXcE"]); + const row = await db.prepare('get', `SELECT "startTime", "endTime", "category" FROM "sponsorTimes" WHERE "videoID" = ?`, ["dQw4w9WgXcE"]); if (row.startTime === 1 && row.endTime === 11 && row.category === "sponsor") { done(); } else { diff --git a/test/cases/postClearCache.ts b/test/cases/postClearCache.ts index ffedaae..9a21a4e 100644 --- a/test/cases/postClearCache.ts +++ b/test/cases/postClearCache.ts @@ -6,7 +6,7 @@ import {getHash} from '../../src/utils/getHash'; describe('postClearCache', () => { before(async () => { await db.prepare("run", `INSERT INTO "vipUsers" ("userID") VALUES ('` + getHash("clearing-vip") + "')"); - let startOfQuery = 'INSERT INTO "sponsorTimes" ("videoID", "startTime", "endTime", "votes", "UUID", "userID", "timeSubmitted", views, category, "shadowHidden", "hashedVideoID") VALUES'; + const startOfQuery = 'INSERT INTO "sponsorTimes" ("videoID", "startTime", "endTime", "votes", "UUID", "userID", "timeSubmitted", views, category, "shadowHidden", "hashedVideoID") VALUES'; await db.prepare("run", startOfQuery + "('clear-test', 0, 1, 2, 'clear-uuid', 'testman', 0, 50, 'sponsor', 0, '" + getHash('clear-test', 1) + "')"); }); diff --git a/test/cases/postPurgeAllSegments.ts b/test/cases/postPurgeAllSegments.ts index b9eef50..a907ddc 100644 --- a/test/cases/postPurgeAllSegments.ts +++ b/test/cases/postPurgeAllSegments.ts @@ -20,7 +20,7 @@ async function dbSponsorTimesAdd(db: IDatabase, videoID: string, startTime: numb } async function dbSponsorTimesCompareExpect(db: IDatabase, videoId: string, expectdHidden: number) { - let seg = await db.prepare('get', `SELECT "hidden", "UUID" FROM "sponsorTimes" WHERE "videoID" = ?`, [videoId]); + const seg = await db.prepare('get', `SELECT "hidden", "UUID" FROM "sponsorTimes" WHERE "videoID" = ?`, [videoId]); for (let i = 0, len = seg.length; i < len; i++) { if (seg.hidden !== expectdHidden) { return `${seg.UUID} hidden expected to be ${expectdHidden} but found ${seg.hidden}`; diff --git a/test/cases/postSkipSegments.ts b/test/cases/postSkipSegments.ts index 2c9a3d8..32d13bc 100644 --- a/test/cases/postSkipSegments.ts +++ b/test/cases/postSkipSegments.ts @@ -249,7 +249,7 @@ describe('postSkipSegments', () => { done("non 403 status code: " + res.status + " (" + body + ")"); } }) - .catch(err => done("Couldn't call endpoint")); + .catch(() => done("Couldn't call endpoint")); }); it('Should be able to submit a single time under a different service (JSON method)', (done: Done) => { @@ -512,7 +512,7 @@ describe('postSkipSegments', () => { done("non 200 status code: " + res.status + " (" + body + ")"); } }) - .catch(err => done("Couldn't call endpoint")); + .catch(() => done("Couldn't call endpoint")); }); it('Should be rejected if segment starts and ends at the same time', (done: Done) => { @@ -527,7 +527,7 @@ describe('postSkipSegments', () => { done("non 400 status code: " + res.status + " (" + body + ")"); } }) - .catch(err => done("Couldn't call endpoint")); + .catch(() => done("Couldn't call endpoint")); }); it('Should be accepted if highlight segment starts and ends at the same time', (done: Done) => { @@ -542,7 +542,7 @@ describe('postSkipSegments', () => { done("non 200 status code: " + res.status + " (" + body + ")"); } }) - .catch(err => done("Couldn't call endpoint")); + .catch(() => done("Couldn't call endpoint")); }); it('Should be rejected if highlight segment doesn\'t start and end at the same time', (done: Done) => { @@ -557,7 +557,7 @@ describe('postSkipSegments', () => { done("non 400 status code: " + res.status + " (" + body + ")"); } }) - .catch(err => done("Couldn't call endpoint")); + .catch(() => done("Couldn't call endpoint")); }); it('Should be rejected if a sponsor is less than 1 second', (done: Done) => { @@ -572,7 +572,7 @@ describe('postSkipSegments', () => { done("non 403 status code: " + res.status + " (" + body + ")"); } }) - .catch(err => done("Couldn't call endpoint")); + .catch(() => done("Couldn't call endpoint")); }); it('Should be rejected if over 80% of the video', (done: Done) => { @@ -585,7 +585,7 @@ describe('postSkipSegments', () => { done("non 403 status code: " + res.status + " (" + body + ")"); } }) - .catch(err => done("Couldn't call endpoint")); + .catch(() => done("Couldn't call endpoint")); }); it("Should be rejected if NB's predicted probability is <70%.", (done: Done) => { @@ -598,7 +598,7 @@ describe('postSkipSegments', () => { done("non 200 status code: " + res.status + " (" + body + ")"); } }) - .catch(err => done("Couldn't call endpoint")); + .catch(() => done("Couldn't call endpoint")); }); it('Should be rejected if user has to many active warnings', (done: Done) => { @@ -690,7 +690,7 @@ describe('postSkipSegments', () => { if (res.status === 400) done(); else done(true); }) - .catch(err => done(true)); + .catch(() => done(true)); }); it('Should return 400 for missing params (JSON method) 1', (done: Done) => { @@ -715,7 +715,7 @@ describe('postSkipSegments', () => { if (res.status === 400) done(); else done(true); }) - .catch(err => done(true)); + .catch(() => done(true)); }); it('Should return 400 for missing params (JSON method) 2', (done: Done) => { fetch(getbaseURL() @@ -733,7 +733,7 @@ describe('postSkipSegments', () => { if (res.status === 400) done(); else done(true); }) - .catch(err => done(true)); + .catch(() => done(true)); }); it('Should return 400 for missing params (JSON method) 3', (done: Done) => { fetch(getbaseURL() @@ -758,7 +758,7 @@ describe('postSkipSegments', () => { if (res.status === 400) done(); else done(true); }) - .catch(err => done(true)); + .catch(() => done(true)); }); it('Should return 400 for missing params (JSON method) 4', (done: Done) => { fetch(getbaseURL() @@ -782,7 +782,7 @@ describe('postSkipSegments', () => { if (res.status === 400) done(); else done(true); }) - .catch(err => done(true)); + .catch(() => done(true)); }); it('Should return 400 for missing params (JSON method) 5', (done: Done) => { fetch(getbaseURL() @@ -800,6 +800,6 @@ describe('postSkipSegments', () => { if (res.status === 400) done(); else done(true); }) - .catch(err => done(true)); + .catch(() => done(true)); }); }); diff --git a/test/cases/postWarning.ts b/test/cases/postWarning.ts index de15ef1..8231148 100644 --- a/test/cases/postWarning.ts +++ b/test/cases/postWarning.ts @@ -9,7 +9,7 @@ describe('postWarning', () => { }); it('Should be able to create warning if vip (exp 200)', (done: Done) => { - let json = { + const json = { issuerUserID: 'warning-vip', userID: 'warning-0', reason: 'warning-reason-0' @@ -24,7 +24,7 @@ describe('postWarning', () => { }) .then(async res => { if (res.status === 200) { - let row = await db.prepare('get', `SELECT "userID", "issueTime", "issuerUserID", enabled, "reason" FROM warnings WHERE "userID" = ?`, [json.userID]); + const row = await db.prepare('get', `SELECT "userID", "issueTime", "issuerUserID", enabled, "reason" FROM warnings WHERE "userID" = ?`, [json.userID]); if (row?.enabled == 1 && row?.issuerUserID == getHash(json.issuerUserID) && row?.reason === json.reason) { done(); } else { @@ -40,7 +40,7 @@ describe('postWarning', () => { }); it('Should be not be able to create a duplicate warning if vip', (done: Done) => { - let json = { + const json = { issuerUserID: 'warning-vip', userID: 'warning-0', }; @@ -55,7 +55,7 @@ describe('postWarning', () => { }) .then(async res => { if (res.status === 409) { - let row = await db.prepare('get', `SELECT "userID", "issueTime", "issuerUserID", enabled FROM warnings WHERE "userID" = ?`, [json.userID]); + const row = await db.prepare('get', `SELECT "userID", "issueTime", "issuerUserID", enabled FROM warnings WHERE "userID" = ?`, [json.userID]); if (row?.enabled == 1 && row?.issuerUserID == getHash(json.issuerUserID)) { done(); } else { @@ -71,7 +71,7 @@ describe('postWarning', () => { }); it('Should be able to remove warning if vip', (done: Done) => { - let json = { + const json = { issuerUserID: 'warning-vip', userID: 'warning-0', enabled: false @@ -87,7 +87,7 @@ describe('postWarning', () => { }) .then(async res => { if (res.status === 200) { - let row = await db.prepare('get', `SELECT "userID", "issueTime", "issuerUserID", enabled FROM warnings WHERE "userID" = ?`, [json.userID]); + const row = await db.prepare('get', `SELECT "userID", "issueTime", "issuerUserID", enabled FROM warnings WHERE "userID" = ?`, [json.userID]); if (row?.enabled == 0) { done(); } else { @@ -103,7 +103,7 @@ describe('postWarning', () => { }); it('Should not be able to create warning if not vip (exp 403)', (done: Done) => { - let json = { + const json = { issuerUserID: 'warning-not-vip', userID: 'warning-1', }; diff --git a/test/cases/reputation.ts b/test/cases/reputation.ts index d640a12..e6029e2 100644 --- a/test/cases/reputation.ts +++ b/test/cases/reputation.ts @@ -18,7 +18,7 @@ describe('reputation', () => { this.timeout(5000); // this preparation takes longer then usual const videoID = "reputation-videoID"; - let sponsorTimesInsertQuery = 'INSERT INTO "sponsorTimes" ("videoID", "startTime", "endTime", "votes", "locked", "UUID", "userID", "timeSubmitted", "views", "category", "service", "videoDuration", "hidden", "shadowHidden", "hashedVideoID") VALUES(?,?,?,?,?,?,?,?,?,?,?,?,?,?,?)'; + const sponsorTimesInsertQuery = 'INSERT INTO "sponsorTimes" ("videoID", "startTime", "endTime", "votes", "locked", "UUID", "userID", "timeSubmitted", "views", "category", "service", "videoDuration", "hidden", "shadowHidden", "hashedVideoID") VALUES(?,?,?,?,?,?,?,?,?,?,?,?,?,?,?)'; await db.prepare("run", sponsorTimesInsertQuery, [videoID, 1, 11, 2, 0, 'reputation-0-uuid-0', getHash(userIDLowSubmissions), 1606240000000, 50, 'sponsor', 'YouTube', 100, 0, 0, getHash(videoID, 1)]); await db.prepare("run", sponsorTimesInsertQuery, [videoID, 1, 11, 2, 0, 'reputation-0-uuid-1', getHash(userIDLowSubmissions), 1606240000000, 50, 'sponsor', 'YouTube', 100, 0, 0, getHash(videoID, 1)]); await db.prepare("run", sponsorTimesInsertQuery, [videoID, 1, 11, 100, 0, 'reputation-0-uuid-2', getHash(userIDLowSubmissions), 1606240000000, 50, 'sponsor', 'YouTube', 100, 0, 0, getHash(videoID, 1)]); diff --git a/test/cases/segmentShift.ts b/test/cases/segmentShift.ts index 0e9eced..4a0cae6 100644 --- a/test/cases/segmentShift.ts +++ b/test/cases/segmentShift.ts @@ -25,7 +25,7 @@ async function dbSponsorTimesSetByUUID(db: IDatabase, UUID: string, startTime: n async function dbSponsorTimesCompareExpect(db: IDatabase, expect: any) { for (let i = 0, len = expect.length; i < len; i++) { const expectSeg = expect[i]; - let seg = await db.prepare('get', `SELECT "startTime", "endTime" FROM "sponsorTimes" WHERE "UUID" = ?`, [expectSeg.UUID]); + const seg = await db.prepare('get', `SELECT "startTime", "endTime" FROM "sponsorTimes" WHERE "UUID" = ?`, [expectSeg.UUID]); if ('removed' in expect) { if (expect.removed === true && seg.votes === -2) { return; diff --git a/test/cases/setUsername.ts b/test/cases/setUsername.ts index d48cce1..5216dd0 100644 --- a/test/cases/setUsername.ts +++ b/test/cases/setUsername.ts @@ -34,7 +34,7 @@ async function getUsernameInfo(userID: string): Promise<{ userName: string, lock return row; } -async function addLogUserNameChange(userID: string, newUserName: string, oldUserName: string = '') { +async function addLogUserNameChange(userID: string, newUserName: string, oldUserName = '') { privateDB.prepare('run', `INSERT INTO "userNameLogs"("userID", "newUserName", "oldUserName", "updatedAt", "updatedByAdmin") VALUES(?, ?, ?, ?, ?)`, [getHash(userID), newUserName, oldUserName, new Date().getTime(), + true] @@ -90,7 +90,7 @@ describe('setUsername', () => { if (usernameInfo.locked == "1") done(`Username was locked when it shouldn't have been`); done(); }) - .catch(err => done(`couldn't call endpoint`)); + .catch(() => done(`couldn't call endpoint`)); }); it('Should return 200', (done: Done) => { @@ -103,7 +103,7 @@ describe('setUsername', () => { testUserNameChangelog(user01PrivateUserID, decodeURIComponent('Changed%20Username'), username01, false, done); } }) - .catch(err => done(`couldn't call endpoint`)); + .catch(() => done(`couldn't call endpoint`)); }); it('Should return 400 for missing param "userID"', (done: Done) => { @@ -114,7 +114,7 @@ describe('setUsername', () => { if (res.status !== 400) done(`Status code was ${res.status}`); else done(); // pass }) - .catch(err => done(`couldn't call endpoint`)); + .catch(() => done(`couldn't call endpoint`)); }); it('Should return 400 for missing param "username"', (done: Done) => { @@ -125,7 +125,7 @@ describe('setUsername', () => { if (res.status !== 400) done(`Status code was ${res.status}`); else done(); // pass }) - .catch(err => done(`couldn't call endpoint`)); + .catch(() => done(`couldn't call endpoint`)); }); it('Should return 400 for "username" longer then 64 characters', (done: Done) => { @@ -137,7 +137,7 @@ describe('setUsername', () => { if (res.status !== 400) done(`Status code was ${res.status}`); else done(); // pass }) - .catch(err => done(`couldn't call endpoint`)); + .catch(() => done(`couldn't call endpoint`)); }); it('Should not change username if it contains "discord"', (done: Done) => { @@ -155,7 +155,7 @@ describe('setUsername', () => { else done(); } }) - .catch(err => done(`couldn't call endpoint`)); + .catch(() => done(`couldn't call endpoint`)); }); it('Should be able to change username', (done: Done) => { @@ -163,13 +163,13 @@ describe('setUsername', () => { fetch(`${getbaseURL()}/api/setUsername?userID=${user03PrivateUserID}&username=${encodeURIComponent(newUsername)}`, { method: 'POST', }) - .then(async res => { + .then(async () => { const usernameInfo = await getUsernameInfo(getHash(user03PrivateUserID)); if (usernameInfo.userName !== newUsername) done(`Username did not change`); if (usernameInfo.locked == "1") done(`Username was locked when it shouldn't have been`); testUserNameChangelog(user03PrivateUserID, newUsername, username03, false, done); }) - .catch(err => done(`couldn't call endpoint`)); + .catch(() => done(`couldn't call endpoint`)); }); it('Should not be able to change locked username', (done: Done) => { @@ -177,13 +177,13 @@ describe('setUsername', () => { fetch(`${getbaseURL()}/api/setUsername?userID=${user04PrivateUserID}&username=${encodeURIComponent(newUsername)}`, { method: 'POST', }) - .then(async res => { + .then(async () => { const usernameInfo = await getUsernameInfo(getHash(user04PrivateUserID)); if (usernameInfo.userName === newUsername) done(`Username '${username04}' got changed to '${usernameInfo}'`); if (usernameInfo.locked == "0") done(`Username was unlocked when it shouldn't have been`); else done(); }) - .catch(err => done(`couldn't call endpoint`)); + .catch(() => done(`couldn't call endpoint`)); }); it('Should filter out unicode control characters', (done: Done) => { @@ -191,12 +191,12 @@ describe('setUsername', () => { fetch(`${getbaseURL()}/api/setUsername?userID=${user05PrivateUserID}&username=${encodeURIComponent(newUsername)}`, { method: 'POST', }) - .then(async res => { + .then(async () => { const usernameInfo = await getUsernameInfo(getHash(user05PrivateUserID)); if (usernameInfo.userName === newUsername) done(`Username contains unicode control characters`); testUserNameChangelog(user05PrivateUserID, wellFormatUserName(newUsername), username05, false, done); }) - .catch(err => done(`couldn't call endpoint`)); + .catch(() => done(`couldn't call endpoint`)); }); it('Incorrect adminUserID should return 403', (done: Done) => { @@ -208,7 +208,7 @@ describe('setUsername', () => { if (res.status !== 403) done(`Status code was ${res.status}`); else done(); }) - .catch(err => done(`couldn't call endpoint`)); + .catch(() => done(`couldn't call endpoint`)); }); it('Admin should be able to change username', (done: Done) => { @@ -216,13 +216,13 @@ describe('setUsername', () => { fetch(`${getbaseURL()}/api/setUsername?adminUserID=${adminPrivateUserID}&userID=${getHash(user06PrivateUserID)}&username=${encodeURIComponent(newUsername)}`, { method: 'POST', }) - .then(async res => { + .then(async () => { const usernameInfo = await getUsernameInfo(getHash(user06PrivateUserID)); if (usernameInfo.userName !== newUsername) done(`Failed to change username from '${username06}' to '${newUsername}'`); if (usernameInfo.locked == "0") done(`Username was not locked`); else testUserNameChangelog(user06PrivateUserID, newUsername, username06, true, done); }) - .catch(err => done(`couldn't call endpoint`)); + .catch(() => done(`couldn't call endpoint`)); }); it('Admin should be able to change locked username', (done: Done) => { @@ -230,12 +230,12 @@ describe('setUsername', () => { fetch(`${getbaseURL()}/api/setUsername?adminUserID=${adminPrivateUserID}&userID=${getHash(user07PrivateUserID)}&username=${encodeURIComponent(newUsername)}`, { method: 'POST', }) - .then(async res => { + .then(async () => { const usernameInfo = await getUsernameInfo(getHash(user06PrivateUserID)); if (usernameInfo.userName !== newUsername) done(`Failed to change username from '${username06}' to '${newUsername}'`); if (usernameInfo.locked == "0") done(`Username was unlocked when it shouldn't have been`); else testUserNameChangelog(user07PrivateUserID, newUsername, username07, true, done); }) - .catch(err => done(`couldn't call endpoint`)); + .catch(() => done(`couldn't call endpoint`)); }); }); diff --git a/test/cases/shadowBanUser.ts b/test/cases/shadowBanUser.ts index a064d37..49e05a4 100644 --- a/test/cases/shadowBanUser.ts +++ b/test/cases/shadowBanUser.ts @@ -40,7 +40,7 @@ describe('shadowBanUser', () => { } } }) - .catch(err => done("Couldn't call endpoint")); + .catch(() => done("Couldn't call endpoint")); }); it('Should be able to unban user without unhiding submissions', (done: Done) => { @@ -60,7 +60,7 @@ describe('shadowBanUser', () => { } } }) - .catch(err => done("Couldn't call endpoint")); + .catch(() => done("Couldn't call endpoint")); }); it('Should be able to ban user and hide submissions from only some categories', (done: Done) => { @@ -80,7 +80,7 @@ describe('shadowBanUser', () => { } } }) - .catch(err => done("Couldn't call endpoint")); + .catch(() => done("Couldn't call endpoint")); }); it('Should be able to unban user and unhide submissions', (done: Done) => { @@ -100,7 +100,7 @@ describe('shadowBanUser', () => { } } }) - .catch(err => done("Couldn't call endpoint")); + .catch(() => done("Couldn't call endpoint")); }); it('Should be able to unban user and unhide some submissions', (done: Done) => { @@ -120,7 +120,7 @@ describe('shadowBanUser', () => { } } }) - .catch(err => done("Couldn't call endpoint")); + .catch(() => done("Couldn't call endpoint")); }); }); diff --git a/test/cases/unBan.ts b/test/cases/unBan.ts index 5b84976..19a6a16 100644 --- a/test/cases/unBan.ts +++ b/test/cases/unBan.ts @@ -32,7 +32,7 @@ describe('unBan', () => { }) .then(async res => { if (res.status === 200) { - let result = await db.prepare('all', 'SELECT * FROM "sponsorTimes" WHERE "videoID" = ? AND "userID" = ? AND "shadowHidden" = ?', ['unBan-videoID-0', 'testMan-unBan', 1]); + const result = await db.prepare('all', 'SELECT * FROM "sponsorTimes" WHERE "videoID" = ? AND "userID" = ? AND "shadowHidden" = ?', ['unBan-videoID-0', 'testMan-unBan', 1]); if (result.length !== 0) { console.log(result); done("Expected 0 banned entrys in db, got " + result.length); @@ -57,7 +57,7 @@ describe('unBan', () => { }) .then(async res => { if (res.status === 200) { - let result = await db.prepare('all', 'SELECT * FROM "sponsorTimes" WHERE "videoID" = ? AND "userID" = ? AND "shadowHidden" = ?', ['unBan-videoID-1', 'testWoman-unBan', 1]); + const result = await db.prepare('all', 'SELECT * FROM "sponsorTimes" WHERE "videoID" = ? AND "userID" = ? AND "shadowHidden" = ?', ['unBan-videoID-1', 'testWoman-unBan', 1]); if (result.length !== 1) { console.log(result); done("Expected 1 banned entry1 in db, got " + result.length); @@ -82,7 +82,7 @@ describe('unBan', () => { }) .then(async res => { if (res.status === 200) { - let result = await db.prepare('all', 'SELECT * FROM "sponsorTimes" WHERE "userID" = ? AND "shadowHidden" = ?', ['testEntity-unBan', 1]); + const result = await db.prepare('all', 'SELECT * FROM "sponsorTimes" WHERE "userID" = ? AND "shadowHidden" = ?', ['testEntity-unBan', 1]); if (result.length !== 1) { console.log(result); done("Expected 1 banned entry1 in db, got " + result.length); diff --git a/test/cases/voteOnSponsorTime.ts b/test/cases/voteOnSponsorTime.ts index 82cc2aa..8e0cc1e 100644 --- a/test/cases/voteOnSponsorTime.ts +++ b/test/cases/voteOnSponsorTime.ts @@ -67,7 +67,7 @@ describe('voteOnSponsorTime', () => { + "/api/voteOnSponsorTime?userID=randomID&UUID=vote-uuid-0&type=1") .then(async res => { if (res.status === 200) { - let row = await db.prepare('get', `SELECT "votes" FROM "sponsorTimes" WHERE "UUID" = ?`, ["vote-uuid-0"]); + const row = await db.prepare('get', `SELECT "votes" FROM "sponsorTimes" WHERE "UUID" = ?`, ["vote-uuid-0"]); if (row.votes === 3) { done(); } else { @@ -85,7 +85,7 @@ describe('voteOnSponsorTime', () => { + "/api/voteOnSponsorTime?userID=randomID2&UUID=vote-uuid-2&type=0") .then(async res => { if (res.status === 200) { - let row = await db.prepare('get', `SELECT "votes" FROM "sponsorTimes" WHERE "UUID" = ?`, ["vote-uuid-2"]); + const row = await db.prepare('get', `SELECT "votes" FROM "sponsorTimes" WHERE "UUID" = ?`, ["vote-uuid-2"]); if (row.votes < 10) { done(); } else { @@ -103,7 +103,7 @@ describe('voteOnSponsorTime', () => { + "/api/voteOnSponsorTime?userID=randomID3&UUID=vote-uuid-2&type=0") .then(async res => { if (res.status === 200) { - let row = await db.prepare('get', `SELECT "votes" FROM "sponsorTimes" WHERE "UUID" = ?`, ["vote-uuid-2"]); + const row = await db.prepare('get', `SELECT "votes" FROM "sponsorTimes" WHERE "UUID" = ?`, ["vote-uuid-2"]); if (row.votes === 9) { done(); } else { @@ -121,7 +121,7 @@ describe('voteOnSponsorTime', () => { + "/api/voteOnSponsorTime?userID=randomID4&UUID=vote-uuid-1.6&type=0") .then(async res => { if (res.status === 200) { - let row = await db.prepare('get', `SELECT "votes" FROM "sponsorTimes" WHERE "UUID" = ?`, ["vote-uuid-1.6"]); + const row = await db.prepare('get', `SELECT "votes" FROM "sponsorTimes" WHERE "UUID" = ?`, ["vote-uuid-1.6"]); if (row.votes === 10) { done(); } else { @@ -139,7 +139,7 @@ describe('voteOnSponsorTime', () => { + "/api/voteOnSponsorTime?userID=hasNotSubmittedID&UUID=vote-uuid-1&type=1") .then(async res => { if (res.status === 200) { - let row = await db.prepare('get', `SELECT "votes" FROM "sponsorTimes" WHERE "UUID" = ?`, ["vote-uuid-1"]); + const row = await db.prepare('get', `SELECT "votes" FROM "sponsorTimes" WHERE "UUID" = ?`, ["vote-uuid-1"]); if (row.votes === 2) { done(); } else { @@ -157,7 +157,7 @@ describe('voteOnSponsorTime', () => { + "/api/voteOnSponsorTime?userID=hasNotSubmittedID&UUID=vote-uuid-1.5&type=0") .then(async res => { if (res.status === 200) { - let row = await db.prepare('get', `SELECT "votes" FROM "sponsorTimes" WHERE "UUID" = ?`, ["vote-uuid-1.5"]); + const row = await db.prepare('get', `SELECT "votes" FROM "sponsorTimes" WHERE "UUID" = ?`, ["vote-uuid-1.5"]); if (row.votes === 10) { done(); } else { @@ -175,7 +175,7 @@ describe('voteOnSponsorTime', () => { + "/api/voteOnSponsorTime?userID=VIPUser&UUID=vote-uuid-3&type=0") .then(async res => { if (res.status === 200) { - let row = await db.prepare('get', `SELECT "votes" FROM "sponsorTimes" WHERE "UUID" = ?`, ["vote-uuid-3"]); + const row = await db.prepare('get', `SELECT "votes" FROM "sponsorTimes" WHERE "UUID" = ?`, ["vote-uuid-3"]); if (row.votes <= -2) { done(); } else { @@ -193,7 +193,7 @@ describe('voteOnSponsorTime', () => { + "/api/voteOnSponsorTime?userID=own-submission-id&UUID=own-submission-uuid&type=0") .then(async res => { if (res.status === 200) { - let row = await db.prepare('get', `SELECT "votes" FROM "sponsorTimes" WHERE "UUID" = ?`, ["own-submission-uuid"]); + const row = await db.prepare('get', `SELECT "votes" FROM "sponsorTimes" WHERE "UUID" = ?`, ["own-submission-uuid"]); if (row.votes <= -2) { done(); } else { @@ -211,7 +211,7 @@ describe('voteOnSponsorTime', () => { + "/api/voteOnSponsorTime?userID=randomID2&UUID=not-own-submission-uuid&type=0") .then(async res => { if (res.status === 200) { - let row = await db.prepare('get', `SELECT "votes" FROM "sponsorTimes" WHERE "UUID" = ?`, ["not-own-submission-uuid"]); + const row = await db.prepare('get', `SELECT "votes" FROM "sponsorTimes" WHERE "UUID" = ?`, ["not-own-submission-uuid"]); if (row.votes === 499) { done(); } else { @@ -229,8 +229,8 @@ describe('voteOnSponsorTime', () => { + "/api/voteOnSponsorTime?userID=randomID2&UUID=vote-uuid-4&category=intro") .then(async res => { if (res.status === 200) { - let row = await db.prepare('get', `SELECT "category" FROM "sponsorTimes" WHERE "UUID" = ?`, ["vote-uuid-4"]); - let categoryRows = await db.prepare('all', `SELECT votes, category FROM "categoryVotes" WHERE "UUID" = ?`, ["vote-uuid-4"]); + const row = await db.prepare('get', `SELECT "category" FROM "sponsorTimes" WHERE "UUID" = ?`, ["vote-uuid-4"]); + const categoryRows = await db.prepare('all', `SELECT votes, category FROM "categoryVotes" WHERE "UUID" = ?`, ["vote-uuid-4"]); if (row.category === "sponsor" && categoryRows.length === 2 && categoryRows[0]?.votes === 1 && categoryRows[0]?.category === "intro" && categoryRows[1]?.votes === 1 && categoryRows[1]?.category === "sponsor") { @@ -250,7 +250,7 @@ describe('voteOnSponsorTime', () => { + "/api/voteOnSponsorTime?userID=randomID2&UUID=incorrect-category&category=fakecategory") .then(async res => { if (res.status === 400) { - let row = await db.prepare('get', `SELECT "category" FROM "sponsorTimes" WHERE "UUID" = ?`, ["incorrect-category"]); + const row = await db.prepare('get', `SELECT "category" FROM "sponsorTimes" WHERE "UUID" = ?`, ["incorrect-category"]); if (row.category === "sponsor") { done(); } else { @@ -268,7 +268,7 @@ describe('voteOnSponsorTime', () => { + "/api/voteOnSponsorTime?userID=randomID2&UUID=incorrect-category&category=highlight") .then(async res => { if (res.status === 400) { - let row = await db.prepare('get', `SELECT "category" FROM "sponsorTimes" WHERE "UUID" = ?`, ["incorrect-category"]); + const row = await db.prepare('get', `SELECT "category" FROM "sponsorTimes" WHERE "UUID" = ?`, ["incorrect-category"]); if (row.category === "sponsor") { done(); } else { @@ -286,8 +286,8 @@ describe('voteOnSponsorTime', () => { + "/api/voteOnSponsorTime?userID=randomID2&UUID=vote-uuid-4&category=outro") .then(async res => { if (res.status === 200) { - let submissionRow = await db.prepare('get', `SELECT "category" FROM "sponsorTimes" WHERE "UUID" = ?`, ["vote-uuid-4"]); - let categoryRows = await db.prepare('all', `SELECT votes, category FROM "categoryVotes" WHERE "UUID" = ?`, ["vote-uuid-4"]); + const submissionRow = await db.prepare('get', `SELECT "category" FROM "sponsorTimes" WHERE "UUID" = ?`, ["vote-uuid-4"]); + const categoryRows = await db.prepare('all', `SELECT votes, category FROM "categoryVotes" WHERE "UUID" = ?`, ["vote-uuid-4"]); let introVotes = 0; let outroVotes = 0; let sponsorVotes = 0; @@ -315,8 +315,8 @@ describe('voteOnSponsorTime', () => { const vote = (inputCat: string, assertCat: string, callback: Done) => { fetch(getbaseURL() + "/api/voteOnSponsorTime?userID=randomID2&UUID=incorrect-category-change&category=" + inputCat) - .then(async res => { - let row = await db.prepare('get', `SELECT "category" FROM "sponsorTimes" WHERE "UUID" = ?`, ["incorrect-category-change"]); + .then(async () => { + const row = await db.prepare('get', `SELECT "category" FROM "sponsorTimes" WHERE "UUID" = ?`, ["incorrect-category-change"]); if (row.category === assertCat) { callback(); } else { @@ -336,8 +336,8 @@ describe('voteOnSponsorTime', () => { + "/api/voteOnSponsorTime?userID=VIPUser&UUID=vote-uuid-5&category=outro") .then(async res => { if (res.status === 200) { - let row = await db.prepare('get', `SELECT "category" FROM "sponsorTimes" WHERE "UUID" = ?`, ["vote-uuid-5"]); - let row2 = await db.prepare('get', `SELECT votes FROM "categoryVotes" WHERE "UUID" = ? and category = ?`, ["vote-uuid-5", "outro"]); + const row = await db.prepare('get', `SELECT "category" FROM "sponsorTimes" WHERE "UUID" = ?`, ["vote-uuid-5"]); + const row2 = await db.prepare('get', `SELECT votes FROM "categoryVotes" WHERE "UUID" = ? and category = ?`, ["vote-uuid-5", "outro"]); if (row.category === "outro" && row2.votes === 500) { done(); } else { @@ -355,7 +355,7 @@ describe('voteOnSponsorTime', () => { + "/api/voteOnSponsorTime?userID=testman&UUID=vote-uuid-5_1&category=outro") .then(async res => { if (res.status === 200) { - let row = await db.prepare('get', `SELECT "category" FROM "sponsorTimes" WHERE "UUID" = ?`, ["vote-uuid-5"]); + const row = await db.prepare('get', `SELECT "category" FROM "sponsorTimes" WHERE "UUID" = ?`, ["vote-uuid-5"]); if (row.category === "outro") { done(); } else { @@ -385,7 +385,7 @@ describe('voteOnSponsorTime', () => { fetch(getbaseURL() + "/api/voteOnSponsorTime?userID=randomID2&UUID=vote-uuid-5&type=1") .then(async res => { - let row = await db.prepare('get', `SELECT "votes" FROM "sponsorTimes" WHERE "UUID" = ?`, ["vote-uuid-5"]); + const row = await db.prepare('get', `SELECT "votes" FROM "sponsorTimes" WHERE "UUID" = ?`, ["vote-uuid-5"]); if (res.status === 403 && row.votes === -3) { done(); } else { @@ -399,7 +399,7 @@ describe('voteOnSponsorTime', () => { fetch(getbaseURL() + "/api/voteOnSponsorTime?userID=randomID2&UUID=vote-uuid-5&type=0") .then(async res => { - let row = await db.prepare('get', `SELECT "votes" FROM "sponsorTimes" WHERE "UUID" = ?`, ["vote-uuid-5"]); + const row = await db.prepare('get', `SELECT "votes" FROM "sponsorTimes" WHERE "UUID" = ?`, ["vote-uuid-5"]); if (res.status === 200 && row.votes === -3) { done(); } else { @@ -414,7 +414,7 @@ describe('voteOnSponsorTime', () => { + "/api/voteOnSponsorTime?userID=VIPUser&UUID=vote-uuid-5&type=1") .then(async res => { if (res.status === 200) { - let row = await db.prepare('get', `SELECT "votes" FROM "sponsorTimes" WHERE "UUID" = ?`, ["vote-uuid-5"]); + const row = await db.prepare('get', `SELECT "votes" FROM "sponsorTimes" WHERE "UUID" = ?`, ["vote-uuid-5"]); if (row.votes > -3) { done(); } else { @@ -444,7 +444,7 @@ describe('voteOnSponsorTime', () => { fetch(getbaseURL() + "/api/voteOnSponsorTime?userID=randomID&UUID=no-sponsor-segments-uuid-0&type=0") .then(async res => { - let row = await db.prepare('get', `SELECT "votes" FROM "sponsorTimes" WHERE "UUID" = ?`, ["no-sponsor-segments-uuid-0"]); + const row = await db.prepare('get', `SELECT "votes" FROM "sponsorTimes" WHERE "UUID" = ?`, ["no-sponsor-segments-uuid-0"]); if (res.status === 200 && row.votes === 2) { done(); } else { @@ -458,7 +458,7 @@ describe('voteOnSponsorTime', () => { fetch(getbaseURL() + "/api/voteOnSponsorTime?userID=randomID&UUID=no-sponsor-segments-uuid-0&type=1") .then(async res => { - let row = await db.prepare('get', `SELECT "votes" FROM "sponsorTimes" WHERE "UUID" = ?`, ["no-sponsor-segments-uuid-0"]); + const row = await db.prepare('get', `SELECT "votes" FROM "sponsorTimes" WHERE "UUID" = ?`, ["no-sponsor-segments-uuid-0"]); if (res.status === 200 && row.votes === 3) { done(); } else { @@ -472,7 +472,7 @@ describe('voteOnSponsorTime', () => { fetch(getbaseURL() + "/api/voteOnSponsorTime?userID=randomID&UUID=no-sponsor-segments-uuid-0&category=outro") .then(async res => { - let row = await db.prepare('get', `SELECT "category" FROM "sponsorTimes" WHERE "UUID" = ?`, ["no-sponsor-segments-uuid-0"]); + const row = await db.prepare('get', `SELECT "category" FROM "sponsorTimes" WHERE "UUID" = ?`, ["no-sponsor-segments-uuid-0"]); if (res.status === 200 && row.category === "sponsor") { done(); } else { @@ -487,7 +487,7 @@ describe('voteOnSponsorTime', () => { + "/api/voteOnSponsorTime?userID=VIPUser&UUID=segment-locking-uuid-1&type=1") .then(async res => { if (res.status === 200) { - let row = await db.prepare('get', `SELECT "locked" FROM "sponsorTimes" WHERE "UUID" = ?`, ["segment-locking-uuid-1"]); + const row = await db.prepare('get', `SELECT "locked" FROM "sponsorTimes" WHERE "UUID" = ?`, ["segment-locking-uuid-1"]); if (row?.locked) { done(); } else { @@ -505,7 +505,7 @@ describe('voteOnSponsorTime', () => { + "/api/voteOnSponsorTime?userID=VIPUser&UUID=segment-locking-uuid-1&type=0") .then(async res => { if (res.status === 200) { - let row = await db.prepare('get', `SELECT "locked" FROM "sponsorTimes" WHERE "UUID" = ?`, ["segment-locking-uuid-1"]); + const row = await db.prepare('get', `SELECT "locked" FROM "sponsorTimes" WHERE "UUID" = ?`, ["segment-locking-uuid-1"]); if (!row?.locked) { done(); } else { @@ -523,7 +523,7 @@ describe('voteOnSponsorTime', () => { + "/api/voteOnSponsorTime?userID=VIPUser&UUID=segment-hidden-uuid-1&type=1") .then(async res => { if (res.status === 200) { - let row = await db.prepare('get', `SELECT "hidden" FROM "sponsorTimes" WHERE "UUID" = ?`, ["segment-hidden-uuid-1"]); + const row = await db.prepare('get', `SELECT "hidden" FROM "sponsorTimes" WHERE "UUID" = ?`, ["segment-hidden-uuid-1"]); if (!row?.hidden) { done(); } else { @@ -541,7 +541,7 @@ describe('voteOnSponsorTime', () => { + "/api/voteOnSponsorTime?userID=randomID2&UUID=vote-uuid-2&type=20") .then(async res => { if (res.status === 200) { - let row = await db.prepare('get', `SELECT "votes" FROM "sponsorTimes" WHERE "UUID" = ?`, ["vote-uuid-2"]); + const row = await db.prepare('get', `SELECT "votes" FROM "sponsorTimes" WHERE "UUID" = ?`, ["vote-uuid-2"]); if (row.votes === 10) { done(); } else { @@ -560,7 +560,7 @@ describe('voteOnSponsorTime', () => { if (res.status !== 400) done('non 400 (' + res.status + ')'); else done(); // pass }) - .catch(err => done('couldn\'t call endpoint')); + .catch(() => done('couldn\'t call endpoint')); }); it('Should not be able to vote with type 11', (done: Done) => { @@ -569,7 +569,7 @@ describe('voteOnSponsorTime', () => { if (res.status !== 400) done('non 400 (' + res.status + ')'); else done(); // pass }) - .catch(err => done('couldn\'t call endpoint')); + .catch(() => done('couldn\'t call endpoint')); }); }); diff --git a/test/utils.ts b/test/utils.ts index 2ff13ae..ed67509 100644 --- a/test/utils.ts +++ b/test/utils.ts @@ -1,6 +1,6 @@ import {config} from '../src/config'; -export function getbaseURL() { +export function getbaseURL(): string { return "http://localhost:" + config.port; } diff --git a/test/youtubeMock.ts b/test/youtubeMock.ts index 3e68369..78ea161 100644 --- a/test/youtubeMock.ts +++ b/test/youtubeMock.ts @@ -1,7 +1,7 @@ import { APIVideoData, APIVideoInfo } from "../src/types/youtubeApi.model"; export class YouTubeApiMock { - static async listVideos(videoID: string, ignoreCache = false): Promise { + static async listVideos(videoID: string): Promise { const obj = { id: videoID }; From 8df0c31d35553d0472dad20e09f458866791c3e3 Mon Sep 17 00:00:00 2001 From: Michael C Date: Sun, 4 Jul 2021 02:04:39 -0400 Subject: [PATCH 4/4] consistent return and sendStatus --- src/routes/addUnlistedVideo.ts | 10 +++--- src/routes/addUserAsVIP.ts | 10 +++--- src/routes/deleteLockCategories.ts | 10 +++--- src/routes/dumpDatabase.ts | 2 +- src/routes/getDaysSavedFormatted.ts | 4 +-- src/routes/getIsUserVIP.ts | 11 +++--- src/routes/getSavedTimeForUser.ts | 13 +++----- src/routes/getSegmentInfo.ts | 8 ++--- src/routes/getSkipSegments.ts | 9 +++-- src/routes/getTopUsers.ts | 3 +- src/routes/getUserInfo.ts | 9 +++-- src/routes/getUsername.ts | 12 +++---- src/routes/getViewsForUser.ts | 12 +++---- src/routes/oldGetVideoSponsorTimes.ts | 4 +-- src/routes/oldSubmitSponsorTimes.ts | 2 +- src/routes/postClearCache.ts | 13 +++----- src/routes/postPurgeAllSegments.ts | 15 +++------ src/routes/postSegmentShift.ts | 10 +++--- src/routes/postSkipSegments.ts | 48 +++++++++------------------ src/routes/postWarning.ts | 10 +++--- src/routes/setUsername.ts | 24 +++++--------- src/routes/shadowBanUser.ts | 11 +++--- src/routes/voteOnSponsorTime.ts | 43 +++++++++--------------- 23 files changed, 112 insertions(+), 181 deletions(-) diff --git a/src/routes/addUnlistedVideo.ts b/src/routes/addUnlistedVideo.ts index e7704ba..92d6772 100644 --- a/src/routes/addUnlistedVideo.ts +++ b/src/routes/addUnlistedVideo.ts @@ -9,15 +9,14 @@ import { Logger } from '../utils/logger'; * https://support.google.com/youtube/answer/9230970 */ -export function addUnlistedVideo(req: Request, res: Response): void { +export function addUnlistedVideo(req: Request, res: Response): Response { const videoID = req.body.videoID; const year = req.body.year || 0; const views = req.body.views || 0; const channelID = req.body.channelID || "Unknown"; if (videoID === undefined || typeof(videoID) !== "string" || videoID.length !== 11) { - res.status(400).send("Invalid parameters"); - return; + return res.status(400).send("Invalid parameters"); } try { @@ -25,9 +24,8 @@ export function addUnlistedVideo(req: Request, res: Response): void { db.prepare('run', `INSERT INTO "unlistedVideos" ("videoID", "year", "views", "channelID", "timeSubmitted") values (?, ?, ?, ?, ?)`, [videoID, year, views, channelID, timeSubmitted]); } catch (err) { Logger.error(err); - res.sendStatus(500); - return; + return res.sendStatus(500); } - res.sendStatus(200); + return res.sendStatus(200); } \ No newline at end of file diff --git a/src/routes/addUserAsVIP.ts b/src/routes/addUserAsVIP.ts index 8eeb97d..46a6b56 100644 --- a/src/routes/addUserAsVIP.ts +++ b/src/routes/addUserAsVIP.ts @@ -3,7 +3,7 @@ import {db} from '../databases/databases'; import {config} from '../config'; import {Request, Response} from 'express'; -export async function addUserAsVIP(req: Request, res: Response): Promise { +export async function addUserAsVIP(req: Request, res: Response): Promise { const userID = req.query.userID as string; let adminUserIDInput = req.query.adminUserID as string; @@ -13,8 +13,7 @@ export async function addUserAsVIP(req: Request, res: Response): Promise { if (userID == undefined || adminUserIDInput == undefined) { //invalid request - res.sendStatus(400); - return; + return res.sendStatus(400); } //hash the userID @@ -22,8 +21,7 @@ export async function addUserAsVIP(req: Request, res: Response): Promise { if (adminUserIDInput !== config.adminUserID) { //not authorized - res.sendStatus(403); - return; + return res.sendStatus(403); } //check to see if this user is already a vip @@ -37,5 +35,5 @@ export async function addUserAsVIP(req: Request, res: Response): Promise { await db.prepare('run', 'DELETE FROM "vipUsers" WHERE "userID" = ?', [userID]); } - res.sendStatus(200); + return res.sendStatus(200); } diff --git a/src/routes/deleteLockCategories.ts b/src/routes/deleteLockCategories.ts index 725a6cf..f06c373 100644 --- a/src/routes/deleteLockCategories.ts +++ b/src/routes/deleteLockCategories.ts @@ -5,7 +5,7 @@ import {db} from '../databases/databases'; import { Category, VideoID } from '../types/segments.model'; import { UserID } from '../types/user.model'; -export async function deleteLockCategoriesEndpoint(req: Request, res: Response): Promise { +export async function deleteLockCategoriesEndpoint(req: Request, res: Response): Promise { // Collect user input data const videoID = req.body.videoID as VideoID; const userID = req.body.userID as UserID; @@ -18,10 +18,9 @@ export async function deleteLockCategoriesEndpoint(req: Request, res: Response): || !Array.isArray(categories) || categories.length === 0 ) { - res.status(400).json({ + return res.status(400).json({ message: 'Bad Format', }); - return; } // Check if user is VIP @@ -29,15 +28,14 @@ export async function deleteLockCategoriesEndpoint(req: Request, res: Response): const userIsVIP = await isUserVIP(hashedUserID); if (!userIsVIP) { - res.status(403).json({ + return res.status(403).json({ message: 'Must be a VIP to mark videos.', }); - return; } await deleteLockCategories(videoID, categories); - res.status(200).json({message: 'Removed lock categories entrys for video ' + videoID}); + return res.status(200).json({message: 'Removed lock categories entrys for video ' + videoID}); } /** diff --git a/src/routes/dumpDatabase.ts b/src/routes/dumpDatabase.ts index ff0b420..9dc7cd9 100644 --- a/src/routes/dumpDatabase.ts +++ b/src/routes/dumpDatabase.ts @@ -181,7 +181,7 @@ export async function redirectLink(req: Request, res: Response): Promise { if (file) { res.redirect("/download/" + file.fileName); } else { - res.status(404).send(); + res.sendStatus(404); } await queueDump(); diff --git a/src/routes/getDaysSavedFormatted.ts b/src/routes/getDaysSavedFormatted.ts index cdb6eaf..184fba4 100644 --- a/src/routes/getDaysSavedFormatted.ts +++ b/src/routes/getDaysSavedFormatted.ts @@ -1,12 +1,12 @@ import {db} from '../databases/databases'; import {Request, Response} from 'express'; -export async function getDaysSavedFormatted(req: Request, res: Response): Promise { +export async function getDaysSavedFormatted(req: Request, res: Response): Promise { const row = await db.prepare('get', 'SELECT SUM(("endTime" - "startTime") / 60 / 60 / 24 * "views") as "daysSaved" from "sponsorTimes" where "shadowHidden" != 1', []); if (row !== undefined) { //send this result - res.send({ + return res.send({ daysSaved: row.daysSaved.toFixed(2), }); } diff --git a/src/routes/getIsUserVIP.ts b/src/routes/getIsUserVIP.ts index 75b19f3..81d6eee 100644 --- a/src/routes/getIsUserVIP.ts +++ b/src/routes/getIsUserVIP.ts @@ -4,13 +4,12 @@ import {isUserVIP} from '../utils/isUserVIP'; import {Request, Response} from 'express'; import { HashedUserID, UserID } from '../types/user.model'; -export async function getIsUserVIP(req: Request, res: Response): Promise { +export async function getIsUserVIP(req: Request, res: Response): Promise { const userID = req.query.userID as UserID; if (userID == undefined) { //invalid request - res.sendStatus(400); - return; + return res.sendStatus(400); } //hash the userID @@ -18,14 +17,12 @@ export async function getIsUserVIP(req: Request, res: Response): Promise { try { const vipState = await isUserVIP(hashedUserID); - res.status(200).json({ + return res.status(200).json({ hashedUserID: hashedUserID, vip: vipState, }); } catch (err) { Logger.error(err); - res.sendStatus(500); - - return; + return res.sendStatus(500); } } diff --git a/src/routes/getSavedTimeForUser.ts b/src/routes/getSavedTimeForUser.ts index d557050..b5511d1 100644 --- a/src/routes/getSavedTimeForUser.ts +++ b/src/routes/getSavedTimeForUser.ts @@ -6,13 +6,12 @@ import { Logger } from '../utils/logger'; const maxRewardTimePerSegmentInSeconds = config.maxRewardTimePerSegmentInSeconds ?? 86400; -export async function getSavedTimeForUser(req: Request, res: Response): Promise { +export async function getSavedTimeForUser(req: Request, res: Response): Promise { let userID = req.query.userID as string; if (userID == undefined) { //invalid request - res.sendStatus(400); - return; + return res.sendStatus(400); } //hash the userID @@ -22,16 +21,14 @@ export async function getSavedTimeForUser(req: Request, res: Response): Promise< const row = await db.prepare("get", 'SELECT SUM(((CASE WHEN "endTime" - "startTime" > ? THEN ? ELSE "endTime" - "startTime" END) / 60) * "views") as "minutesSaved" FROM "sponsorTimes" WHERE "userID" = ? AND "votes" > -1 AND "shadowHidden" != 1 ', [maxRewardTimePerSegmentInSeconds, maxRewardTimePerSegmentInSeconds, userID]); if (row.minutesSaved != null) { - res.send({ + return res.send({ timeSaved: row.minutesSaved, }); } else { - res.sendStatus(404); + return res.sendStatus(404); } } catch (err) { Logger.error("getSavedTimeForUser " + err); - res.sendStatus(500); - - return; + return res.sendStatus(500); } } diff --git a/src/routes/getSegmentInfo.ts b/src/routes/getSegmentInfo.ts index 77b23e7..254a6d6 100644 --- a/src/routes/getSegmentInfo.ts +++ b/src/routes/getSegmentInfo.ts @@ -57,19 +57,19 @@ async function handleGetSegmentInfo(req: Request, res: Response): Promise { +async function endpoint(req: Request, res: Response): Promise { try { const DBSegments = await handleGetSegmentInfo(req, res); // If false, res.send has already been called if (DBSegments) { //send result - res.send(DBSegments); + return res.send(DBSegments); } } catch (err) { if (err instanceof SyntaxError) { // catch JSON.parse error - res.status(400).send("UUIDs parameter does not match format requirements."); - } else res.status(500).send(); + return res.status(400).send("UUIDs parameter does not match format requirements."); + } else return res.sendStatus(500); } } diff --git a/src/routes/getSkipSegments.ts b/src/routes/getSkipSegments.ts index 49d6478..704cb13 100644 --- a/src/routes/getSkipSegments.ts +++ b/src/routes/getSkipSegments.ts @@ -291,26 +291,25 @@ async function handleGetSegments(req: Request, res: Response): Promise { +async function endpoint(req: Request, res: Response): Promise { try { const segments = await handleGetSegments(req, res); // If false, res.send has already been called if (segments) { //send result - res.send(segments); + return res.send(segments); } } catch (err) { if (err instanceof SyntaxError) { - res.status(400).send("Categories parameter does not match format requirements."); - } else res.status(500).send(); + return res.status(400).send("Categories parameter does not match format requirements."); + } else return res.sendStatus(500); } } diff --git a/src/routes/getTopUsers.ts b/src/routes/getTopUsers.ts index c358eb1..2885ec1 100644 --- a/src/routes/getTopUsers.ts +++ b/src/routes/getTopUsers.ts @@ -69,8 +69,7 @@ export async function getTopUsers(req: Request, res: Response): Promise { +export async function getUserInfo(req: Request, res: Response): Promise { const userID = req.query.userID as UserID; const hashedUserID: HashedUserID = userID ? getHash(userID) : req.query.publicUserID as HashedUserID; if (hashedUserID == undefined) { //invalid request - res.status(400).send('Parameters are not valid'); - return; + return res.status(400).send('Parameters are not valid'); } const segmentsSummary = await dbGetSubmittedSegmentSummary(hashedUserID); if (segmentsSummary) { - res.send({ + return res.send({ userID: hashedUserID, userName: await dbGetUsername(hashedUserID), minutesSaved: segmentsSummary.minutesSaved, @@ -114,6 +113,6 @@ export async function getUserInfo(req: Request, res: Response): Promise { lastSegmentID: await dbGetLastSegmentForUser(hashedUserID), }); } else { - res.status(400).send(); + return res.sendStatus(400); } } diff --git a/src/routes/getUsername.ts b/src/routes/getUsername.ts index 7b9bacd..a9bcc53 100644 --- a/src/routes/getUsername.ts +++ b/src/routes/getUsername.ts @@ -3,13 +3,12 @@ import {getHash} from '../utils/getHash'; import {Logger} from '../utils/logger'; import {Request, Response} from 'express'; -export async function getUsername(req: Request, res: Response): Promise { +export async function getUsername(req: Request, res: Response): Promise { let userID = req.query.userID as string; if (userID == undefined) { //invalid request - res.sendStatus(400); - return; + return res.sendStatus(400); } //hash the userID @@ -19,18 +18,17 @@ export async function getUsername(req: Request, res: Response): Promise { const row = await db.prepare('get', `SELECT "userName" FROM "userNames" WHERE "userID" = ?`, [userID]); if (row !== undefined) { - res.send({ + return res.send({ userName: row.userName, }); } else { //no username yet, just send back the userID - res.send({ + return res.send({ userName: userID, }); } } catch (err) { Logger.error(err); - res.sendStatus(500); - return; + return res.sendStatus(500); } } diff --git a/src/routes/getViewsForUser.ts b/src/routes/getViewsForUser.ts index 6fa2710..3ccbb8a 100644 --- a/src/routes/getViewsForUser.ts +++ b/src/routes/getViewsForUser.ts @@ -3,13 +3,12 @@ import {Request, Response} from 'express'; import {getHash} from '../utils/getHash'; import {Logger} from '../utils/logger'; -export async function getViewsForUser(req: Request, res: Response): Promise { +export async function getViewsForUser(req: Request, res: Response): Promise { let userID = req.query.userID as string; if (userID == undefined) { //invalid request - res.sendStatus(400); - return; + return res.sendStatus(400); } //hash the userID @@ -20,15 +19,14 @@ export async function getViewsForUser(req: Request, res: Response): Promise { +export async function oldGetVideoSponsorTimes(req: Request, res: Response): Promise { const segments = await handleGetSegments(req, res); if (segments) { @@ -14,7 +14,7 @@ export async function oldGetVideoSponsorTimes(req: Request, res: Response): Prom UUIDs.push(segment.UUID); } - res.send({ + return res.send({ sponsorTimes, UUIDs, }); diff --git a/src/routes/oldSubmitSponsorTimes.ts b/src/routes/oldSubmitSponsorTimes.ts index 9500220..2f04142 100644 --- a/src/routes/oldSubmitSponsorTimes.ts +++ b/src/routes/oldSubmitSponsorTimes.ts @@ -1,7 +1,7 @@ import {postSkipSegments} from './postSkipSegments'; import {Request, Response} from 'express'; -export async function oldSubmitSponsorTimes(req: Request, res: Response): Promise { +export async function oldSubmitSponsorTimes(req: Request, res: Response): Promise { req.query.category = "sponsor"; return postSkipSegments(req, res); } diff --git a/src/routes/postClearCache.ts b/src/routes/postClearCache.ts index 07e2d92..75040fe 100644 --- a/src/routes/postClearCache.ts +++ b/src/routes/postClearCache.ts @@ -7,7 +7,7 @@ import { QueryCacher } from '../utils/queryCacher'; import { isUserVIP } from '../utils/isUserVIP'; import { VideoIDHash } from "../types/segments.model"; -export async function postClearCache(req: Request, res: Response): Promise { +export async function postClearCache(req: Request, res: Response): Promise { const videoID = req.query.videoID as VideoID; const userID = req.query.userID as UserID; const service = req.query.service as Service ?? Service.YouTube; @@ -23,8 +23,7 @@ export async function postClearCache(req: Request, res: Response): Promise if (invalidFields.length !== 0) { // invalid request const fields = invalidFields.reduce((p, c, i) => p + (i !== 0 ? ', ' : '') + c, ''); - res.status(400).send(`No valid ${fields} field(s) provided`); - return; + return res.status(400).send(`No valid ${fields} field(s) provided`); } // hash the userID as early as possible @@ -35,8 +34,7 @@ export async function postClearCache(req: Request, res: Response): Promise // Ensure user is a VIP if (!(await isUserVIP(hashedUserID))){ Logger.warn("Permission violation: User " + hashedUserID + " attempted to clear cache for video " + videoID + "."); - res.status(403).json({"message": "Not a VIP"}); - return; + return res.status(403).json({"message": "Not a VIP"}); } try { @@ -45,11 +43,10 @@ export async function postClearCache(req: Request, res: Response): Promise hashedVideoID, service }); - res.status(200).json({ + return res.status(200).json({ message: "Cache cleared on video " + videoID }); } catch(err) { - res.status(500).send(); - return; + return res.sendStatus(500); } } diff --git a/src/routes/postPurgeAllSegments.ts b/src/routes/postPurgeAllSegments.ts index 5e1e484..80c5df6 100644 --- a/src/routes/postPurgeAllSegments.ts +++ b/src/routes/postPurgeAllSegments.ts @@ -6,14 +6,13 @@ import {HashedUserID, UserID} from '../types/user.model'; import {VideoID} from "../types/segments.model"; import {db} from '../databases/databases'; -export async function postPurgeAllSegments(req: Request, res: Response): Promise { +export async function postPurgeAllSegments(req: Request, res: Response): Promise { const userID = req.body.userID as UserID; const videoID = req.body.videoID as VideoID; if (userID == undefined) { //invalid request - res.sendStatus(400); - return; + return res.sendStatus(400); } //hash the userID @@ -22,20 +21,16 @@ export async function postPurgeAllSegments(req: Request, res: Response): Promise try { const vipState = await isUserVIP(hashedUserID); if (!vipState) { - res.status(403).json({ + return res.status(403).json({ message: 'Must be a VIP to perform this action.', }); - return; } await db.prepare('run', `UPDATE "sponsorTimes" SET "hidden" = 1 WHERE "videoID" = ?`, [videoID]); } catch (err) { Logger.error(err); - res.sendStatus(500); - - return; + return res.sendStatus(500); } - - res.sendStatus(200); + return res.sendStatus(200); } diff --git a/src/routes/postSegmentShift.ts b/src/routes/postSegmentShift.ts index 6c92b5b..50730ad 100644 --- a/src/routes/postSegmentShift.ts +++ b/src/routes/postSegmentShift.ts @@ -58,10 +58,9 @@ export async function postSegmentShift(req: Request, res: Response): Promise { +export async function postSkipSegments(req: Request, res: Response): Promise { if (config.proxySubmission) { proxySubmission(req); } @@ -315,8 +315,7 @@ export async function postSkipSegments(req: Request, res: Response): Promise p + (i !== 0 ? ', ' : '') + c, ''); - res.status(400).send(`No valid ${fields} field(s) provided`); - return; + return res.status(400).send(`No valid ${fields} field(s) provided`); } //hash the userID @@ -332,13 +331,10 @@ export async function postSkipSegments(req: Request, res: Response): Promise= config.maxNumberOfActiveWarnings) { - res.status(403).send('Submission rejected due to a warning from a moderator. This means that we noticed you were making some common mistakes that are not malicious, and we just want to clarify the rules. Could you please send a message in Discord or Matrix so we can further help you?'); - return; + return res.status(403).send('Submission rejected due to a warning from a moderator. This means that we noticed you were making some common mistakes that are not malicious, and we just want to clarify the rules. Could you please send a message in Discord or Matrix so we can further help you?'); } - let lockedCategoryList = (await db.prepare('all', 'SELECT category from "lockCategories" where "videoID" = ?', [videoID])).map((list: any) => { - return list.category; - }); + let lockedCategoryList = (await db.prepare('all', 'SELECT category from "lockCategories" where "videoID" = ?', [videoID])).map((list: any) => list.category ); //check if this user is on the vip list const isVIP = (await db.prepare("get", `SELECT count(*) as "userCount" FROM "vipUsers" WHERE "userID" = ?`, [userID])).userCount > 0; @@ -377,27 +373,24 @@ export async function postSkipSegments(req: Request, res: Response): Promise 0) { - res.sendStatus(409); - return; + return res.sendStatus(409); } } @@ -439,8 +429,7 @@ export async function postSkipSegments(req: Request, res: Response): Promise= 10) { //too many sponsors for the same video from the same ip address - res.sendStatus(429); - return; + return res.sendStatus(429); } } @@ -474,8 +462,7 @@ export async function postSkipSegments(req: Request, res: Response): Promise= 16) { //too many sponsors for the same video from the same user - res.sendStatus(429); - return; + return res.sendStatus(429); } } @@ -520,10 +507,9 @@ export async function postSkipSegments(req: Request, res: Response): Promise { +export async function postWarning(req: Request, res: Response): Promise { // Collect user input data const issuerUserID: HashedUserID = getHash( req.body.issuerUserID); const userID: UserID = req.body.userID; @@ -16,8 +16,7 @@ export async function postWarning(req: Request, res: Response): Promise { // Ensure user is a VIP if (!await isUserVIP(issuerUserID)) { Logger.warn("Permission violation: User " + issuerUserID + " attempted to warn user " + userID + "."); - res.status(403).json({"message": "Not a VIP"}); - return; + return res.status(403).json({"message": "Not a VIP"}); } let resultStatus = ""; @@ -33,15 +32,14 @@ export async function postWarning(req: Request, res: Response): Promise { ); resultStatus = "issued to"; } else { - res.status(409).send(); - return; + return res.sendStatus(409); } } else { await db.prepare('run', 'UPDATE "warnings" SET "enabled" = 0 WHERE "userID" = ?', [userID]); resultStatus = "removed from"; } - res.status(200).json({ + return res.status(200).json({ message: "Warning " + resultStatus + " user '" + userID + "'.", }); } diff --git a/src/routes/setUsername.ts b/src/routes/setUsername.ts index bd0de35..cbf2ad3 100644 --- a/src/routes/setUsername.ts +++ b/src/routes/setUsername.ts @@ -4,14 +4,14 @@ import {db, privateDB} from '../databases/databases'; import {getHash} from '../utils/getHash'; import {Request, Response} from 'express'; -async function logUserNameChange(userID: string, newUserName: string, oldUserName: string, updatedByAdmin: boolean): Promise { +async function logUserNameChange(userID: string, newUserName: string, oldUserName: string, updatedByAdmin: boolean): Promise { return privateDB.prepare('run', `INSERT INTO "userNameLogs"("userID", "newUserName", "oldUserName", "updatedByAdmin", "updatedAt") VALUES(?, ?, ?, ?, ?)`, [userID, newUserName, oldUserName, + updatedByAdmin, new Date().getTime()] ); } -export async function setUsername(req: Request, res: Response): Promise { +export async function setUsername(req: Request, res: Response): Promise { let userID = req.query.userID as string; let userName = req.query.username as string; @@ -19,14 +19,12 @@ export async function setUsername(req: Request, res: Response): Promise { if (userID == undefined || userName == undefined || userID === "undefined" || userName.length > 64) { //invalid request - res.sendStatus(400); - return; + return res.sendStatus(400); } if (userName.includes("discord")) { // Don't allow - res.sendStatus(200); - return; + return res.sendStatus(200); } // remove unicode control characters from username (example: \n, \r, \t etc.) @@ -40,8 +38,7 @@ export async function setUsername(req: Request, res: Response): Promise { if (adminUserIDInput != config.adminUserID) { //they aren't the admin - res.sendStatus(403); - return; + return res.sendStatus(403); } } else { //hash the userID @@ -51,14 +48,12 @@ export async function setUsername(req: Request, res: Response): Promise { try { const row = await db.prepare('get', `SELECT count(*) as count FROM "userNames" WHERE "userID" = ? AND "locked" = '1'`, [userID]); if (adminUserIDInput === undefined && row.count > 0) { - res.sendStatus(200); - return; + return res.sendStatus(200); } } catch (error) { Logger.error(error); - res.sendStatus(500); - return; + return res.sendStatus(500); } try { @@ -78,10 +73,9 @@ export async function setUsername(req: Request, res: Response): Promise { await logUserNameChange(userID, userName, oldUserName, adminUserIDInput !== undefined); - res.sendStatus(200); + return res.sendStatus(200); } catch (err) { Logger.error(err); - res.sendStatus(500); - return; + return res.sendStatus(500); } } diff --git a/src/routes/shadowBanUser.ts b/src/routes/shadowBanUser.ts index 50f8095..71806be 100644 --- a/src/routes/shadowBanUser.ts +++ b/src/routes/shadowBanUser.ts @@ -6,7 +6,7 @@ import { Category, Service, VideoID, VideoIDHash } from '../types/segments.model import { UserID } from '../types/user.model'; import { QueryCacher } from '../utils/queryCacher'; -export async function shadowBanUser(req: Request, res: Response): Promise { +export async function shadowBanUser(req: Request, res: Response): Promise { const userID = req.query.userID as string; const hashedIP = req.query.hashedIP as string; let adminUserIDInput = req.query.adminUserID as string; @@ -23,8 +23,7 @@ export async function shadowBanUser(req: Request, res: Response): Promise if (adminUserIDInput == undefined || (userID == undefined && hashedIP == undefined)) { //invalid request - res.sendStatus(400); - return; + return res.sendStatus(400); } //hash the userID @@ -33,8 +32,7 @@ export async function shadowBanUser(req: Request, res: Response): Promise const isVIP = (await db.prepare("get", `SELECT count(*) as "userCount" FROM "vipUsers" WHERE "userID" = ?`, [adminUserIDInput])).userCount > 0; if (!isVIP) { //not authorized - res.sendStatus(403); - return; + return res.sendStatus(403); } if (userID) { @@ -114,6 +112,5 @@ export async function shadowBanUser(req: Request, res: Response): Promise // } }*/ } - - res.sendStatus(200); + return res.sendStatus(200); } diff --git a/src/routes/voteOnSponsorTime.ts b/src/routes/voteOnSponsorTime.ts index 3d1f7a0..7c9251e 100644 --- a/src/routes/voteOnSponsorTime.ts +++ b/src/routes/voteOnSponsorTime.ts @@ -161,31 +161,27 @@ async function sendWebhooks(voteData: VoteData) { } async function categoryVote(UUID: SegmentUUID, userID: UserID, isVIP: boolean, isOwnSubmission: boolean, category: Category - , hashedIP: HashedIP, finalResponse: FinalResponse, res: Response) { + , hashedIP: HashedIP, finalResponse: FinalResponse, res: Response): Promise { // Check if they've already made a vote const usersLastVoteInfo = await privateDB.prepare('get', `select count(*) as votes, category from "categoryVotes" where "UUID" = ? and "userID" = ? group by category`, [UUID, userID]); if (usersLastVoteInfo?.category === category) { // Double vote, ignore - res.sendStatus(finalResponse.finalStatus); - return; + return res.sendStatus(finalResponse.finalStatus); } const videoInfo = (await db.prepare('get', `SELECT "category", "videoID", "hashedVideoID", "service", "userID" FROM "sponsorTimes" WHERE "UUID" = ?`, [UUID])) as {category: Category, videoID: VideoID, hashedVideoID: VideoIDHash, service: Service, userID: UserID}; if (!videoInfo) { // Submission doesn't exist - res.status(400).send("Submission doesn't exist."); - return; + return res.status(400).send("Submission doesn't exist."); } if (!config.categoryList.includes(category)) { - res.status(400).send("Category doesn't exist."); - return; + return res.status(400).send("Category doesn't exist."); } if (getCategoryActionType(category) !== CategoryActionType.Skippable) { - res.status(400).send("Cannot vote for this category"); - return; + return res.status(400).send("Cannot vote for this category"); } const nextCategoryInfo = await db.prepare("get", `select votes from "categoryVotes" where "UUID" = ? and category = ?`, [UUID, category]); @@ -245,14 +241,14 @@ async function categoryVote(UUID: SegmentUUID, userID: UserID, isVIP: boolean, i QueryCacher.clearVideoCache(videoInfo); - res.sendStatus(finalResponse.finalStatus); + return res.sendStatus(finalResponse.finalStatus); } export function getUserID(req: Request): UserID { return req.query.userID as UserID; } -export async function voteOnSponsorTime(req: Request, res: Response): Promise { +export async function voteOnSponsorTime(req: Request, res: Response): Promise { const UUID = req.query.UUID as SegmentUUID; const paramUserID = getUserID(req); let type = req.query.type !== undefined ? parseInt(req.query.type as string) : undefined; @@ -260,8 +256,7 @@ export async function voteOnSponsorTime(req: Request, res: Response): Promise= config.maxNumberOfActiveWarnings) { - res.status(403).send('Vote rejected due to a warning from a moderator. This means that we noticed you were making some common mistakes that are not malicious, and we just want to clarify the rules. Could you please send a message in Discord or Matrix so we can further help you?'); - return; + return res.status(403).send('Vote rejected due to a warning from a moderator. This means that we noticed you were making some common mistakes that are not malicious, and we just want to clarify the rules. Could you please send a message in Discord or Matrix so we can further help you?'); } const voteTypeEnum = (type == 0 || type == 1 || type == 20) ? voteTypes.normal : voteTypes.incorrect; @@ -362,8 +353,7 @@ export async function voteOnSponsorTime(req: Request, res: Response): Promise