diff --git a/.eslintrc.js b/.eslintrc.js new file mode 100644 index 0000000..64d1185 --- /dev/null +++ b/.eslintrc.js @@ -0,0 +1,25 @@ +module.exports = { + parser: '@typescript-eslint/parser', + parserOptions: { + project: 'tsconfig.json', + sourceType: 'module', + }, + plugins: ['@typescript-eslint/eslint-plugin'], + extends: [ + 'plugin:@typescript-eslint/recommended', + 'prettier/@typescript-eslint', + 'plugin:prettier/recommended', + ], + root: true, + env: { + node: true, + jest: true, + }, + ignorePatterns: ['.eslintrc.js'], + rules: { + '@typescript-eslint/interface-name-prefix': 'off', + '@typescript-eslint/explicit-function-return-type': 'off', + '@typescript-eslint/explicit-module-boundary-types': 'off', + '@typescript-eslint/no-explicit-any': 'off', + }, +}; diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..a13915f --- /dev/null +++ b/.gitignore @@ -0,0 +1,36 @@ +# compiled output +/dist +/node_modules + +# Logs +logs +*.log +npm-debug.log* +yarn-debug.log* +yarn-error.log* +lerna-debug.log* + +# OS +.DS_Store + +# Tests +/coverage +/.nyc_output + +# IDEs and editors +/.idea +.project +.classpath +.c9/ +*.launch +.settings/ +*.sublime-workspace + +# IDE - VSCode +.vscode/* +!.vscode/settings.json +!.vscode/tasks.json +!.vscode/launch.json +!.vscode/extensions.json + +/config.yml \ No newline at end of file diff --git a/.prettierrc b/.prettierrc new file mode 100644 index 0000000..dcb7279 --- /dev/null +++ b/.prettierrc @@ -0,0 +1,4 @@ +{ + "singleQuote": true, + "trailingComma": "all" +} \ No newline at end of file diff --git a/.vscode/settings.json b/.vscode/settings.json new file mode 100644 index 0000000..4c6ad29 --- /dev/null +++ b/.vscode/settings.json @@ -0,0 +1,14 @@ +{ + "cSpell.words": [ + "Repos", + "boardcat", + "gitea", + "lpush", + "lrange", + "metatype", + "pmessage", + "psubscribe", + "rpop", + "rpush" + ] +} \ No newline at end of file diff --git a/package-lock.json b/package-lock.json index 8ce1e96..3dfd5a9 100644 --- a/package-lock.json +++ b/package-lock.json @@ -15,6 +15,23 @@ "magic-string": "0.25.7", "rxjs": "6.6.3", "source-map": "0.7.3" + }, + "dependencies": { + "rxjs": { + "version": "6.6.3", + "resolved": "https://registry.npmjs.org/rxjs/-/rxjs-6.6.3.tgz", + "integrity": "sha512-trsQc+xYYXZ3urjOiJOuCOa5N3jAZ3eiSpQB5hIT8zGlL2QfnHLJ2r7GMkBGuIausdJN1OneaI6gQlsqNHHmZQ==", + "dev": true, + "requires": { + "tslib": "^1.9.0" + } + }, + "tslib": { + "version": "1.14.1", + "resolved": "https://registry.npmjs.org/tslib/-/tslib-1.14.1.tgz", + "integrity": "sha512-Xni35NKzjgMrwevysHTCArtLDpPvye8zV/0E4EyYn43P7/7qvQwPh9BGkHewbMulVntbigmcT7rdX3BNo9wRJg==", + "dev": true + } } }, "@angular-devkit/schematics": { @@ -43,6 +60,21 @@ "strip-ansi": "^6.0.0", "wcwidth": "^1.0.1" } + }, + "rxjs": { + "version": "6.6.3", + "resolved": "https://registry.npmjs.org/rxjs/-/rxjs-6.6.3.tgz", + "integrity": "sha512-trsQc+xYYXZ3urjOiJOuCOa5N3jAZ3eiSpQB5hIT8zGlL2QfnHLJ2r7GMkBGuIausdJN1OneaI6gQlsqNHHmZQ==", + "dev": true, + "requires": { + "tslib": "^1.9.0" + } + }, + "tslib": { + "version": "1.14.1", + "resolved": "https://registry.npmjs.org/tslib/-/tslib-1.14.1.tgz", + "integrity": "sha512-Xni35NKzjgMrwevysHTCArtLDpPvye8zV/0E4EyYn43P7/7qvQwPh9BGkHewbMulVntbigmcT7rdX3BNo9wRJg==", + "dev": true } } }, @@ -2039,9 +2071,9 @@ } }, "@eslint/eslintrc": { - "version": "0.3.0", - "resolved": "https://registry.npmjs.org/@eslint/eslintrc/-/eslintrc-0.3.0.tgz", - "integrity": "sha512-1JTKgrOKAHVivSvOYw+sJOunkBjUOvjqWk1DPja7ZFhIS2mX/4EgTT8M7eTK9jrKhL/FvXXEbQwIs3pg1xp3dg==", + "version": "0.4.0", + "resolved": "https://registry.npmjs.org/@eslint/eslintrc/-/eslintrc-0.4.0.tgz", + "integrity": "sha512-2ZPCc+uNbjV5ERJr+aKSPRwZgKd2z11x0EgLvb1PURmUrn9QNRXFqje0Ldq454PfAVyaJYyrDvvIKSFP4NnBog==", "dev": true, "requires": { "ajv": "^6.12.4", @@ -2051,7 +2083,6 @@ "ignore": "^4.0.6", "import-fresh": "^3.2.1", "js-yaml": "^3.13.1", - "lodash": "^4.17.20", "minimatch": "^3.0.4", "strip-json-comments": "^3.1.1" }, @@ -2065,13 +2096,13 @@ "sprintf-js": "~1.0.2" } }, - "debug": { - "version": "4.3.1", - "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.1.tgz", - "integrity": "sha512-doEwdvm4PCeK4K3RQN2ZC2BYUBaxwLARCqZmMjtF8a51J2Rb0xpVloFRnCODwqjpwnAoao4pelN8l3RJdv3gRQ==", + "globals": { + "version": "12.4.0", + "resolved": "https://registry.npmjs.org/globals/-/globals-12.4.0.tgz", + "integrity": "sha512-BWICuzzDvDoH54NHKCseDanAhE3CeDorgDL5MT6LMXXj2WCnd9UC2szdk4AWLfjdgNBCXLUanXYcpBBKOSWGwg==", "dev": true, "requires": { - "ms": "2.1.2" + "type-fest": "^0.8.1" } }, "ignore": { @@ -2090,10 +2121,10 @@ "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==", + "type-fest": { + "version": "0.8.1", + "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-0.8.1.tgz", + "integrity": "sha512-4dbzIzqvjtgiM5rw1k5rEHtBANKmdudhGyBEajN01fEyhaAIhsoKNy6y7+IN93IfpFtwY9iqi7kD+xwKhQsNJA==", "dev": true } } @@ -3138,6 +3169,17 @@ "magic-string": "0.25.7", "rxjs": "6.6.3", "source-map": "0.7.3" + }, + "dependencies": { + "rxjs": { + "version": "6.6.3", + "resolved": "https://registry.npmjs.org/rxjs/-/rxjs-6.6.3.tgz", + "integrity": "sha512-trsQc+xYYXZ3urjOiJOuCOa5N3jAZ3eiSpQB5hIT8zGlL2QfnHLJ2r7GMkBGuIausdJN1OneaI6gQlsqNHHmZQ==", + "dev": true, + "requires": { + "tslib": "^1.9.0" + } + } } }, "@angular-devkit/schematics": { @@ -3149,6 +3191,17 @@ "@angular-devkit/core": "11.2.4", "ora": "5.3.0", "rxjs": "6.6.3" + }, + "dependencies": { + "rxjs": { + "version": "6.6.3", + "resolved": "https://registry.npmjs.org/rxjs/-/rxjs-6.6.3.tgz", + "integrity": "sha512-trsQc+xYYXZ3urjOiJOuCOa5N3jAZ3eiSpQB5hIT8zGlL2QfnHLJ2r7GMkBGuIausdJN1OneaI6gQlsqNHHmZQ==", + "dev": true, + "requires": { + "tslib": "^1.9.0" + } + } } }, "chalk": { @@ -3189,6 +3242,12 @@ "supports-color": "^7.1.0" } }, + "tslib": { + "version": "1.14.1", + "resolved": "https://registry.npmjs.org/tslib/-/tslib-1.14.1.tgz", + "integrity": "sha512-Xni35NKzjgMrwevysHTCArtLDpPvye8zV/0E4EyYn43P7/7qvQwPh9BGkHewbMulVntbigmcT7rdX3BNo9wRJg==", + "dev": true + }, "typescript": { "version": "4.2.3", "resolved": "https://registry.npmjs.org/typescript/-/typescript-4.2.3.tgz", @@ -3198,9 +3257,9 @@ } }, "@nestjs/common": { - "version": "7.6.7", - "resolved": "https://registry.npmjs.org/@nestjs/common/-/common-7.6.7.tgz", - "integrity": "sha512-aMoqSQQG3UKWyfLl8cYgd/+bgDNUvSobZm4B1Ne+1CvavnS8E3818ksxRjoZ7MPJJOSOSIQJUY0HYXVvbddt0w==", + "version": "7.6.15", + "resolved": "https://registry.npmjs.org/@nestjs/common/-/common-7.6.15.tgz", + "integrity": "sha512-H/3Nk7M02Fc4YN9St05i34gZKVuzE54gd5eXAX6WwisqU5fQ00kss1pYGbltjb2QGu3A/fpO1MdYEwOA18Z/VQ==", "requires": { "axios": "0.21.1", "iterare": "1.2.1", @@ -3222,9 +3281,9 @@ } }, "@nestjs/core": { - "version": "7.6.7", - "resolved": "https://registry.npmjs.org/@nestjs/core/-/core-7.6.7.tgz", - "integrity": "sha512-1n4r0AqoD3Eg+nnqZyNSFEz1MQRf2GabQbxnJj3T6SLj2VwxKNEO1qIZyDABNXLFcj79AfjPq5gqEhCutCuE2Q==", + "version": "7.6.15", + "resolved": "https://registry.npmjs.org/@nestjs/core/-/core-7.6.15.tgz", + "integrity": "sha512-8CrL/iY5Gt4HJfyDg1PgPalhT7tVRT643f2mGMgPum/P/e94uuwEYBNIgsMEVOJUrOAWZkNIN60uEf8JkH6GWw==", "requires": { "@nuxtjs/opencollective": "0.3.2", "fast-safe-stringify": "2.0.7", @@ -3291,9 +3350,9 @@ "integrity": "sha512-TVtd/aTb7EqPhVczdeuvzF9dY0fyE3ivvCstc2eO+AkNqrfzSG1kXYYiUUznKjd0qDa8g2TmPSmHUQ21AXsV1Q==" }, "@nestjs/platform-express": { - "version": "7.6.7", - "resolved": "https://registry.npmjs.org/@nestjs/platform-express/-/platform-express-7.6.7.tgz", - "integrity": "sha512-QNVtsWCtHUmfuoX+JfE+Y5tyiJKMjNFHm0RHvNhTk33zIzkpLo9NsgFfL3T9z1C5Qs37A/xV6wFXTXx4l5r6eg==", + "version": "7.6.15", + "resolved": "https://registry.npmjs.org/@nestjs/platform-express/-/platform-express-7.6.15.tgz", + "integrity": "sha512-XpoHtai7UlUvm6rLo0u2xtkABhC6YbxNuNYqpv/L+mT1xzKJtPV2jWYxJnsE4WNZAddsnKsAcDjj2nCQgiJ52Q==", "requires": { "body-parser": "1.19.0", "cors": "2.8.5", @@ -3303,21 +3362,22 @@ } }, "@nestjs/schematics": { - "version": "7.2.7", - "resolved": "https://registry.npmjs.org/@nestjs/schematics/-/schematics-7.2.7.tgz", - "integrity": "sha512-71XqMPf7s2P1Q6PVMDLbSLphVWgGDK2CgURVYyreuIWXVSoi9pcPIeO5k0Qb5n5jELlKwdrf66g05U2I6TIxzg==", + "version": "7.3.1", + "resolved": "https://registry.npmjs.org/@nestjs/schematics/-/schematics-7.3.1.tgz", + "integrity": "sha512-eyBjJstAjecpdzRuBLiqnwomwXIAEV3+kPkpaphOieRUM6nBhjnXCCl3Qf8Dul2QUQK4NOVPd8FFxWtGP5XNlg==", "dev": true, "requires": { - "@angular-devkit/core": "11.1.0", - "@angular-devkit/schematics": "11.1.0", + "@angular-devkit/core": "11.2.4", + "@angular-devkit/schematics": "11.2.4", "fs-extra": "9.1.0", + "jsonc-parser": "3.0.0", "pluralize": "8.0.0" }, "dependencies": { "@angular-devkit/core": { - "version": "11.1.0", - "resolved": "https://registry.npmjs.org/@angular-devkit/core/-/core-11.1.0.tgz", - "integrity": "sha512-O2oIcqpQKGvYJH88d/NCgLYZGc9laA1eo2d1s0FH1Udu4c2L+bAsviQqtTKNmzyaqODHrlkt+eKx7uakdwWtnQ==", + "version": "11.2.4", + "resolved": "https://registry.npmjs.org/@angular-devkit/core/-/core-11.2.4.tgz", + "integrity": "sha512-98mGDV4XtKWiQ/2D6yzvOHrnJovXchaAN9AjscAHd2an8Fkiq72d9m2wREpk+2J40NWTDB6J5iesTh3qbi8+CA==", "dev": true, "requires": { "ajv": "6.12.6", @@ -3328,20 +3388,20 @@ } }, "@angular-devkit/schematics": { - "version": "11.1.0", - "resolved": "https://registry.npmjs.org/@angular-devkit/schematics/-/schematics-11.1.0.tgz", - "integrity": "sha512-6qfR5w1jyk8MC+5Tfimz+Czsq3WlsVoB57dpxSZfhGGsv1Vxc8Q41y5f3BrAyEqHYjcH7NtaoLQoJjtra5KaAg==", + "version": "11.2.4", + "resolved": "https://registry.npmjs.org/@angular-devkit/schematics/-/schematics-11.2.4.tgz", + "integrity": "sha512-M9Ike1TYawOIHzenlZS1ufQbsS+Z11/doj5w/UrU0q2OEKc6U375t5qVGgKo3PLHHS8osb9aW9xYwBfVlKrryQ==", "dev": true, "requires": { - "@angular-devkit/core": "11.1.0", - "ora": "5.2.0", + "@angular-devkit/core": "11.2.4", + "ora": "5.3.0", "rxjs": "6.6.3" } }, "ora": { - "version": "5.2.0", - "resolved": "https://registry.npmjs.org/ora/-/ora-5.2.0.tgz", - "integrity": "sha512-+wG2v8TUU8EgzPHun1k/n45pXquQ9fHnbXVetl9rRgO6kjZszGGbraF3XPTIdgeA+s1lbRjSEftAnyT0w8ZMvQ==", + "version": "5.3.0", + "resolved": "https://registry.npmjs.org/ora/-/ora-5.3.0.tgz", + "integrity": "sha512-zAKMgGXUim0Jyd6CXK9lraBnD3H5yPGBPPOkC23a2BG6hsm4Zu6OQSjQuEtV0BHDf4aKHcUFvJiGRrFuW3MG8g==", "dev": true, "requires": { "bl": "^4.0.3", @@ -3353,13 +3413,28 @@ "strip-ansi": "^6.0.0", "wcwidth": "^1.0.1" } + }, + "rxjs": { + "version": "6.6.3", + "resolved": "https://registry.npmjs.org/rxjs/-/rxjs-6.6.3.tgz", + "integrity": "sha512-trsQc+xYYXZ3urjOiJOuCOa5N3jAZ3eiSpQB5hIT8zGlL2QfnHLJ2r7GMkBGuIausdJN1OneaI6gQlsqNHHmZQ==", + "dev": true, + "requires": { + "tslib": "^1.9.0" + } + }, + "tslib": { + "version": "1.14.1", + "resolved": "https://registry.npmjs.org/tslib/-/tslib-1.14.1.tgz", + "integrity": "sha512-Xni35NKzjgMrwevysHTCArtLDpPvye8zV/0E4EyYn43P7/7qvQwPh9BGkHewbMulVntbigmcT7rdX3BNo9wRJg==", + "dev": true } } }, "@nestjs/testing": { - "version": "7.6.7", - "resolved": "https://registry.npmjs.org/@nestjs/testing/-/testing-7.6.7.tgz", - "integrity": "sha512-DegNWF8P7m4aPvIDdPmR6dqT6DcEnbjig8c7BTcaNjV2Fc+YUlvss9PABBlOEUvNTU7BzUD7sqXB/HGfEp+KSw==", + "version": "7.6.15", + "resolved": "https://registry.npmjs.org/@nestjs/testing/-/testing-7.6.15.tgz", + "integrity": "sha512-AWr8stnRoS0yCU/EotAJKveYXm1XSB4ZT+ReqFDXhPyqC1ppOfU+zZuCjQlQHorMzidsVHsAstK5/rUsXnrZUQ==", "dev": true, "requires": { "optional": "0.1.4", @@ -3602,14 +3677,6 @@ "@types/node": "*" } }, - "@types/bull": { - "version": "3.15.0", - "resolved": "https://registry.npmjs.org/@types/bull/-/bull-3.15.0.tgz", - "integrity": "sha512-54Y1RYkJt6i+4dH45w4gZOP6fyhksTvOImfgBYAxgq/nt5ZrES4xFWwOzt2bxAgSR7FMH9fwvaiJN/pripPzag==", - "requires": { - "@types/ioredis": "*" - } - }, "@types/connect": { "version": "3.4.34", "resolved": "https://registry.npmjs.org/@types/connect/-/connect-3.4.34.tgz", @@ -3645,12 +3712,6 @@ "resolved": "https://registry.npmjs.org/@types/cors/-/cors-2.8.10.tgz", "integrity": "sha512-C7srjHiVG3Ey1nR6d511dtDkCEjxuN9W1HWAEjGq8kpcwmNM6JJkpC0xvabM7BXTG2wDq8Eu33iH9aQKa7IvLQ==" }, - "@types/debug": { - "version": "4.1.5", - "resolved": "https://registry.npmjs.org/@types/debug/-/debug-4.1.5.tgz", - "integrity": "sha512-Q1y515GcOdTHgagaVFhHnIFQ38ygs/kmxdNpvpou+raI9UO3YZcHDngBSYKQklcKlvA7iuQlmIKbzvmxcOE9CQ==", - "dev": true - }, "@types/eslint": { "version": "7.2.10", "resolved": "https://registry.npmjs.org/@types/eslint/-/eslint-7.2.10.tgz", @@ -3755,9 +3816,9 @@ } }, "@types/jest": { - "version": "26.0.20", - "resolved": "https://registry.npmjs.org/@types/jest/-/jest-26.0.20.tgz", - "integrity": "sha512-9zi2Y+5USJRxd0FsahERhBwlcvFh6D2GLQnY2FH2BzK8J9s9omvNHIbvABwIluXa0fD8XVKMLTO0aOEuUfACAA==", + "version": "26.0.22", + "resolved": "https://registry.npmjs.org/@types/jest/-/jest-26.0.22.tgz", + "integrity": "sha512-eeWwWjlqxvBxc4oQdkueW5OF/gtfSceKk4OnOAGlUSwS/liBRtZppbJuz1YkgbrbfGOoeBHun9fOvXnjNwrSOw==", "dev": true, "requires": { "jest-diff": "^26.0.0", @@ -3815,9 +3876,9 @@ "integrity": "sha512-YATxVxgRqNH6nHEIsvg6k2Boc1JHI9ZbH5iWFFv/MTkchz3b1ieGDa5T0a9RznNdI0KhVbdbWSN+KWWrQZRxTw==" }, "@types/node": { - "version": "14.14.22", - "resolved": "https://registry.npmjs.org/@types/node/-/node-14.14.22.tgz", - "integrity": "sha512-g+f/qj/cNcqKkc3tFqlXOYjrmZA+jNBiDzbP3kH+B+otKFqAdPgVTGP1IeKRdMml/aE69as5S4FqtxAbl+LaMw==" + "version": "14.14.41", + "resolved": "https://registry.npmjs.org/@types/node/-/node-14.14.41.tgz", + "integrity": "sha512-dueRKfaJL4RTtSa7bWeTK1M+VH+Gns73oCgzvYfHZywRCoPSd8EkXBL0mZ9unPTveBn+D9phZBaxuzpwjWkW0g==" }, "@types/node-fetch": { "version": "2.5.8", @@ -3896,9 +3957,9 @@ } }, "@types/supertest": { - "version": "2.0.10", - "resolved": "https://registry.npmjs.org/@types/supertest/-/supertest-2.0.10.tgz", - "integrity": "sha512-Xt8TbEyZTnD5Xulw95GLMOkmjGICrOQyJ2jqgkSjAUR3mm7pAIzSR0NFBaMcwlzVvlpCjNwbATcWWwjNiZiFrQ==", + "version": "2.0.11", + "resolved": "https://registry.npmjs.org/@types/supertest/-/supertest-2.0.11.tgz", + "integrity": "sha512-uci4Esokrw9qGb9bvhhSVEjd6rkny/dk5PK/Qz4yxKiyppEI+dOPlNrZBahE3i+PoKFYyDxChVXZ/ysS/nrm1Q==", "dev": true, "requires": { "@types/superagent": "*" @@ -3949,137 +4010,85 @@ "integrity": "sha512-HrCIVMLjE1MOozVoD86622S7aunluLb2PJdPfb3nYiEtohm8mIB/vyv0Fd37AdeMFrTUQXEunw78YloMA3Qilg==" }, "@typescript-eslint/eslint-plugin": { - "version": "4.14.1", - "resolved": "https://registry.npmjs.org/@typescript-eslint/eslint-plugin/-/eslint-plugin-4.14.1.tgz", - "integrity": "sha512-5JriGbYhtqMS1kRcZTQxndz1lKMwwEXKbwZbkUZNnp6MJX0+OVXnG0kOlBZP4LUAxEyzu3cs+EXd/97MJXsGfw==", + "version": "4.22.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/eslint-plugin/-/eslint-plugin-4.22.0.tgz", + "integrity": "sha512-U8SP9VOs275iDXaL08Ln1Fa/wLXfj5aTr/1c0t0j6CdbOnxh+TruXu1p4I0NAvdPBQgoPjHsgKn28mOi0FzfoA==", "dev": true, "requires": { - "@typescript-eslint/experimental-utils": "4.14.1", - "@typescript-eslint/scope-manager": "4.14.1", + "@typescript-eslint/experimental-utils": "4.22.0", + "@typescript-eslint/scope-manager": "4.22.0", "debug": "^4.1.1", "functional-red-black-tree": "^1.0.1", "lodash": "^4.17.15", "regexpp": "^3.0.0", "semver": "^7.3.2", "tsutils": "^3.17.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/experimental-utils": { - "version": "4.14.1", - "resolved": "https://registry.npmjs.org/@typescript-eslint/experimental-utils/-/experimental-utils-4.14.1.tgz", - "integrity": "sha512-2CuHWOJwvpw0LofbyG5gvYjEyoJeSvVH2PnfUQSn0KQr4v8Dql2pr43ohmx4fdPQ/eVoTSFjTi/bsGEXl/zUUQ==", + "version": "4.22.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/experimental-utils/-/experimental-utils-4.22.0.tgz", + "integrity": "sha512-xJXHHl6TuAxB5AWiVrGhvbGL8/hbiCQ8FiWwObO3r0fnvBdrbWEDy1hlvGQOAWc6qsCWuWMKdVWlLAEMpxnddg==", "dev": true, "requires": { "@types/json-schema": "^7.0.3", - "@typescript-eslint/scope-manager": "4.14.1", - "@typescript-eslint/types": "4.14.1", - "@typescript-eslint/typescript-estree": "4.14.1", + "@typescript-eslint/scope-manager": "4.22.0", + "@typescript-eslint/types": "4.22.0", + "@typescript-eslint/typescript-estree": "4.22.0", "eslint-scope": "^5.0.0", "eslint-utils": "^2.0.0" } }, "@typescript-eslint/parser": { - "version": "4.14.1", - "resolved": "https://registry.npmjs.org/@typescript-eslint/parser/-/parser-4.14.1.tgz", - "integrity": "sha512-mL3+gU18g9JPsHZuKMZ8Z0Ss9YP1S5xYZ7n68Z98GnPq02pYNQuRXL85b9GYhl6jpdvUc45Km7hAl71vybjUmw==", + "version": "4.22.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/parser/-/parser-4.22.0.tgz", + "integrity": "sha512-z/bGdBJJZJN76nvAY9DkJANYgK3nlRstRRi74WHm3jjgf2I8AglrSY+6l7ogxOmn55YJ6oKZCLLy+6PW70z15Q==", "dev": true, "requires": { - "@typescript-eslint/scope-manager": "4.14.1", - "@typescript-eslint/types": "4.14.1", - "@typescript-eslint/typescript-estree": "4.14.1", + "@typescript-eslint/scope-manager": "4.22.0", + "@typescript-eslint/types": "4.22.0", + "@typescript-eslint/typescript-estree": "4.22.0", "debug": "^4.1.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.14.1", - "resolved": "https://registry.npmjs.org/@typescript-eslint/scope-manager/-/scope-manager-4.14.1.tgz", - "integrity": "sha512-F4bjJcSqXqHnC9JGUlnqSa3fC2YH5zTtmACS1Hk+WX/nFB0guuynVK5ev35D4XZbdKjulXBAQMyRr216kmxghw==", + "version": "4.22.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/scope-manager/-/scope-manager-4.22.0.tgz", + "integrity": "sha512-OcCO7LTdk6ukawUM40wo61WdeoA7NM/zaoq1/2cs13M7GyiF+T4rxuA4xM+6LeHWjWbss7hkGXjFDRcKD4O04Q==", "dev": true, "requires": { - "@typescript-eslint/types": "4.14.1", - "@typescript-eslint/visitor-keys": "4.14.1" + "@typescript-eslint/types": "4.22.0", + "@typescript-eslint/visitor-keys": "4.22.0" } }, "@typescript-eslint/types": { - "version": "4.14.1", - "resolved": "https://registry.npmjs.org/@typescript-eslint/types/-/types-4.14.1.tgz", - "integrity": "sha512-SkhzHdI/AllAgQSxXM89XwS1Tkic7csPdndUuTKabEwRcEfR8uQ/iPA3Dgio1rqsV3jtqZhY0QQni8rLswJM2w==", + "version": "4.22.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/types/-/types-4.22.0.tgz", + "integrity": "sha512-sW/BiXmmyMqDPO2kpOhSy2Py5w6KvRRsKZnV0c4+0nr4GIcedJwXAq+RHNK4lLVEZAJYFltnnk1tJSlbeS9lYA==", "dev": true }, "@typescript-eslint/typescript-estree": { - "version": "4.14.1", - "resolved": "https://registry.npmjs.org/@typescript-eslint/typescript-estree/-/typescript-estree-4.14.1.tgz", - "integrity": "sha512-M8+7MbzKC1PvJIA8kR2sSBnex8bsR5auatLCnVlNTJczmJgqRn8M+sAlQfkEq7M4IY3WmaNJ+LJjPVRrREVSHQ==", + "version": "4.22.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/typescript-estree/-/typescript-estree-4.22.0.tgz", + "integrity": "sha512-TkIFeu5JEeSs5ze/4NID+PIcVjgoU3cUQUIZnH3Sb1cEn1lBo7StSV5bwPuJQuoxKXlzAObjYTilOEKRuhR5yg==", "dev": true, "requires": { - "@typescript-eslint/types": "4.14.1", - "@typescript-eslint/visitor-keys": "4.14.1", + "@typescript-eslint/types": "4.22.0", + "@typescript-eslint/visitor-keys": "4.22.0", "debug": "^4.1.1", "globby": "^11.0.1", "is-glob": "^4.0.1", - "lodash": "^4.17.15", "semver": "^7.3.2", "tsutils": "^3.17.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/visitor-keys": { - "version": "4.14.1", - "resolved": "https://registry.npmjs.org/@typescript-eslint/visitor-keys/-/visitor-keys-4.14.1.tgz", - "integrity": "sha512-TAblbDXOI7bd0C/9PE1G+AFo7R5uc+ty1ArDoxmrC1ah61Hn6shURKy7gLdRb1qKJmjHkqu5Oq+e4Kt0jwf1IA==", + "version": "4.22.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/visitor-keys/-/visitor-keys-4.22.0.tgz", + "integrity": "sha512-nnMu4F+s4o0sll6cBSsTeVsT4cwxB7zECK3dFxzEjPBii9xLpq4yqqsy/FU5zMfan6G60DKZSCXAa3sHJZrcYw==", "dev": true, "requires": { - "@typescript-eslint/types": "4.14.1", + "@typescript-eslint/types": "4.22.0", "eslint-visitor-keys": "^2.0.0" } }, @@ -4718,7 +4727,6 @@ "version": "2.23.0", "resolved": "https://registry.npmjs.org/apollo-server-testing/-/apollo-server-testing-2.23.0.tgz", "integrity": "sha512-xDZwB4iAoecWbaMevqmtMb7a7fkBgk4DXEVaytdtvyS5E+piY288/72t1Gpdrn/SuNlHjdyLvPrR6iCS6dJXpg==", - "optional": true, "requires": { "apollo-server-core": "^2.23.0" } @@ -5835,9 +5843,9 @@ } }, "consola": { - "version": "2.15.0", - "resolved": "https://registry.npmjs.org/consola/-/consola-2.15.0.tgz", - "integrity": "sha512-vlcSGgdYS26mPf7qNi+dCisbhiyDnrN1zaRbw3CSuc2wGOMEGGPsp46PdRG5gqXwgtJfjxDkxRNAgRPr1B77vQ==" + "version": "2.15.3", + "resolved": "https://registry.npmjs.org/consola/-/consola-2.15.3.tgz", + "integrity": "sha512-9vAdYbHj6x2fLKC4+oPH0kFzY/orMZyG2Aj+kNylHxKGJ/Ed4dpNyAQYwJOdqO4zdM7XpVHmyejQDcQHrnuXbw==" }, "console-control-strings": { "version": "1.1.0", @@ -6443,13 +6451,13 @@ } }, "eslint": { - "version": "7.18.0", - "resolved": "https://registry.npmjs.org/eslint/-/eslint-7.18.0.tgz", - "integrity": "sha512-fbgTiE8BfUJZuBeq2Yi7J3RB3WGUQ9PNuNbmgi6jt9Iv8qrkxfy19Ds3OpL1Pm7zg3BtTVhvcUZbIRQ0wmSjAQ==", + "version": "7.24.0", + "resolved": "https://registry.npmjs.org/eslint/-/eslint-7.24.0.tgz", + "integrity": "sha512-k9gaHeHiFmGCDQ2rEfvULlSLruz6tgfA8DEn+rY9/oYPFFTlz55mM/Q/Rij1b2Y42jwZiK3lXvNTw6w6TXzcKQ==", "dev": true, "requires": { - "@babel/code-frame": "^7.0.0", - "@eslint/eslintrc": "^0.3.0", + "@babel/code-frame": "7.12.11", + "@eslint/eslintrc": "^0.4.0", "ajv": "^6.10.0", "chalk": "^4.0.0", "cross-spawn": "^7.0.2", @@ -6460,12 +6468,12 @@ "eslint-utils": "^2.1.0", "eslint-visitor-keys": "^2.0.0", "espree": "^7.3.1", - "esquery": "^1.2.0", + "esquery": "^1.4.0", "esutils": "^2.0.2", - "file-entry-cache": "^6.0.0", + "file-entry-cache": "^6.0.1", "functional-red-black-tree": "^1.0.1", "glob-parent": "^5.0.0", - "globals": "^12.1.0", + "globals": "^13.6.0", "ignore": "^4.0.6", "import-fresh": "^3.0.0", "imurmurhash": "^0.1.4", @@ -6473,7 +6481,7 @@ "js-yaml": "^3.13.1", "json-stable-stringify-without-jsonify": "^1.0.1", "levn": "^0.4.1", - "lodash": "^4.17.20", + "lodash": "^4.17.21", "minimatch": "^3.0.4", "natural-compare": "^1.4.0", "optionator": "^0.9.1", @@ -6496,15 +6504,6 @@ "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" - } - }, "ignore": { "version": "4.0.6", "resolved": "https://registry.npmjs.org/ignore/-/ignore-4.0.6.tgz", @@ -6521,10 +6520,10 @@ "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==", + "lodash": { + "version": "4.17.21", + "resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.21.tgz", + "integrity": "sha512-v2kDEe57lecTulaDIuNTPy3Ry4gLGJ6Z1O3vE1krgXZNrsQ+LFTGHVxVjcXPs17LhbZVGedAJv8XZ1tvj5FvSg==", "dev": true } } @@ -6536,9 +6535,9 @@ "dev": true }, "eslint-plugin-prettier": { - "version": "3.3.1", - "resolved": "https://registry.npmjs.org/eslint-plugin-prettier/-/eslint-plugin-prettier-3.3.1.tgz", - "integrity": "sha512-Rq3jkcFY8RYeQLgk2cCwuc0P7SEFwDravPhsJZOQ5N4YI4DSg50NyqJ/9gdZHzQlHf8MvafSesbNJCcP/FF6pQ==", + "version": "3.4.0", + "resolved": "https://registry.npmjs.org/eslint-plugin-prettier/-/eslint-plugin-prettier-3.4.0.tgz", + "integrity": "sha512-UDK6rJT6INSfcOo545jiaOwB701uAIt2/dR7WnFQoGCVl1/EMqdANBmwUaqqQ45aXprsTGzSa39LI1PyuRBxxw==", "dev": true, "requires": { "prettier-linter-helpers": "^1.0.0" @@ -6609,9 +6608,9 @@ "dev": true }, "esquery": { - "version": "1.3.1", - "resolved": "https://registry.npmjs.org/esquery/-/esquery-1.3.1.tgz", - "integrity": "sha512-olpvt9QG0vniUBZspVRN6lwB7hOZoTRtT+jzR+tS4ffYx2mzbw+z0XCOk44aaLYKApNX5nMm+E+P6o25ip/DHQ==", + "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" @@ -7033,9 +7032,9 @@ } }, "file-entry-cache": { - "version": "6.0.0", - "resolved": "https://registry.npmjs.org/file-entry-cache/-/file-entry-cache-6.0.0.tgz", - "integrity": "sha512-fqoO76jZ3ZnYrXLDRxBR1YvOvc0k844kcOg40bgsPrE25LAb/PDqTY+ho64Xh2c8ZXgIKldchCFHczG2UVRcWA==", + "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" @@ -7104,9 +7103,9 @@ "dev": true }, "follow-redirects": { - "version": "1.13.2", - "resolved": "https://registry.npmjs.org/follow-redirects/-/follow-redirects-1.13.2.tgz", - "integrity": "sha512-6mPTgLxYm3r6Bkkg0vNM0HTjfGrOEtsfbhagQvbxDEsEkpNhw582upBaoRZylzen6krEmxXJgt9Ju6HiI4O7BA==" + "version": "1.13.3", + "resolved": "https://registry.npmjs.org/follow-redirects/-/follow-redirects-1.13.3.tgz", + "integrity": "sha512-DUgl6+HDzB0iEptNQEXLx/KhTmDb8tZUHSeLqpnjpknR70H0nC2t9N73BK6fN4hOvJ84pKlIQVQ4k5FFlBedKA==" }, "for-each": { "version": "0.3.3", @@ -7369,26 +7368,26 @@ "dev": true }, "globals": { - "version": "12.4.0", - "resolved": "https://registry.npmjs.org/globals/-/globals-12.4.0.tgz", - "integrity": "sha512-BWICuzzDvDoH54NHKCseDanAhE3CeDorgDL5MT6LMXXj2WCnd9UC2szdk4AWLfjdgNBCXLUanXYcpBBKOSWGwg==", + "version": "13.8.0", + "resolved": "https://registry.npmjs.org/globals/-/globals-13.8.0.tgz", + "integrity": "sha512-rHtdA6+PDBIjeEvA91rpqzEvk/k3/i7EeNQiryiWuJH0Hw9cpyJMAt2jtbAwUaRdhD+573X4vWw6IcjKPasi9Q==", "dev": true, "requires": { - "type-fest": "^0.8.1" + "type-fest": "^0.20.2" }, "dependencies": { "type-fest": { - "version": "0.8.1", - "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-0.8.1.tgz", - "integrity": "sha512-4dbzIzqvjtgiM5rw1k5rEHtBANKmdudhGyBEajN01fEyhaAIhsoKNy6y7+IN93IfpFtwY9iqi7kD+xwKhQsNJA==", + "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 } } }, "globby": { - "version": "11.0.2", - "resolved": "https://registry.npmjs.org/globby/-/globby-11.0.2.tgz", - "integrity": "sha512-2ZThXDvvV8fYFRVIxnrMQBipZQDr7MxKAmQK1vujaj9/7eF0efG7BPUKJ7jP7G5SLF37xKDXvO4S/KKLj/Z0og==", + "version": "11.0.3", + "resolved": "https://registry.npmjs.org/globby/-/globby-11.0.3.tgz", + "integrity": "sha512-ffdmosjA807y7+lA1NM0jELARVmYul/715xiILEjo3hBLPTcirgQNnXECn5g3mtR8TOLCVbkfua1Hpen25/Xcg==", "dev": true, "requires": { "array-union": "^2.1.0", @@ -8959,9 +8958,9 @@ }, "dependencies": { "json5": { - "version": "2.1.3", - "resolved": "https://registry.npmjs.org/json5/-/json5-2.1.3.tgz", - "integrity": "sha512-KXPvOm8K9IJKFM0bmdn8QXh7udDh1g/giieX0NLCaMnb4hEiVFqnop2ImTXCc5e0/oHz3LTqmHGtExn5hfMkOA==", + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/json5/-/json5-2.2.0.tgz", + "integrity": "sha512-f+8cldu7X/y7RAJurMEJmdoKXGB/X550w2Nr3tTbezL6RwEE/iMcm+tZnXeoZtKuOq6ft8+CqzEkrIgx1fPoQA==", "dev": true, "requires": { "minimist": "^1.2.5" @@ -8982,6 +8981,12 @@ "resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.20.tgz", "integrity": "sha512-PlhdFcillOINfeV7Ni6oF1TAEayyZBoZ8bcshTHqOYJYlrqzRK5hagpagky5o4HfCzzd1TRkXPMFq6cKk9rGmA==" }, + "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.defaults": { "version": "4.2.0", "resolved": "https://registry.npmjs.org/lodash.defaults/-/lodash.defaults-4.2.0.tgz", @@ -9018,6 +9023,12 @@ "integrity": "sha1-JMS/zWsvuji/0FlNsRedjptlZWE=", "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 + }, "lodash.xorby": { "version": "4.7.0", "resolved": "https://registry.npmjs.org/lodash.xorby/-/lodash.xorby-4.7.0.tgz", @@ -10669,9 +10680,9 @@ "integrity": "sha512-zb/1OuZ6flOlH6tQyMPUrE3x3Ulxjlo9WIVXR4yVYi4H9UXQaeIsPbLn2R3O3vQCnDKkAl2qHiuocKKX4Tz/Sw==" }, "rxjs": { - "version": "6.6.3", - "resolved": "https://registry.npmjs.org/rxjs/-/rxjs-6.6.3.tgz", - "integrity": "sha512-trsQc+xYYXZ3urjOiJOuCOa5N3jAZ3eiSpQB5hIT8zGlL2QfnHLJ2r7GMkBGuIausdJN1OneaI6gQlsqNHHmZQ==", + "version": "6.6.7", + "resolved": "https://registry.npmjs.org/rxjs/-/rxjs-6.6.7.tgz", + "integrity": "sha512-hTdwr+7yYNIT5n4AMYp85KA6yw2Va0FLa3Rguvbpa4W3I5xynaBZo41cM3XM+4Q6fRMj3sBYIR1VAmZMXYJvRQ==", "requires": { "tslib": "^1.9.0" }, @@ -11764,21 +11775,26 @@ } }, "table": { - "version": "6.0.7", - "resolved": "https://registry.npmjs.org/table/-/table-6.0.7.tgz", - "integrity": "sha512-rxZevLGTUzWna/qBLObOe16kB2RTnnbhciwgPbMMlazz1yZGVEgnZK762xyVdVznhqxrfCeBMmMkgOOaPwjH7g==", + "version": "6.1.0", + "resolved": "https://registry.npmjs.org/table/-/table-6.1.0.tgz", + "integrity": "sha512-T4G5KMmqIk6X87gLKWyU5exPpTjLjY5KyrFWaIjv3SvgaIUGXV7UEzGEnZJdTA38/yUS6f9PlKezQ0bYXG3iIQ==", "dev": true, "requires": { - "ajv": "^7.0.2", - "lodash": "^4.17.20", + "ajv": "^8.0.1", + "is-boolean-object": "^1.1.0", + "is-number-object": "^1.0.4", + "is-string": "^1.0.5", + "lodash.clonedeep": "^4.5.0", + "lodash.flatten": "^4.4.0", + "lodash.truncate": "^4.4.2", "slice-ansi": "^4.0.0", "string-width": "^4.2.0" }, "dependencies": { "ajv": { - "version": "7.0.3", - "resolved": "https://registry.npmjs.org/ajv/-/ajv-7.0.3.tgz", - "integrity": "sha512-R50QRlXSxqXcQP5SvKUrw8VZeypvo12i2IX0EeR5PiZ7bEKeHWgzgo264LDadUsCU42lTJVhFikTqJwNeH34gQ==", + "version": "8.1.0", + "resolved": "https://registry.npmjs.org/ajv/-/ajv-8.1.0.tgz", + "integrity": "sha512-B/Sk2Ix7A36fs/ZkuGLIR86EdjbgR6fsAcbx9lOP/QBSXujDNbVmIS/U4Itz5k8fPFDeVZl/zQ/gJW4Jrq6XjQ==", "dev": true, "requires": { "fast-deep-equal": "^3.1.1", @@ -12044,12 +12060,11 @@ } }, "ts-jest": { - "version": "26.5.0", - "resolved": "https://registry.npmjs.org/ts-jest/-/ts-jest-26.5.0.tgz", - "integrity": "sha512-Ya4IQgvIFNa2Mgq52KaO8yBw2W8tWp61Ecl66VjF0f5JaV8u50nGoptHVILOPGoI7SDnShmEqnYQEmyHdQ+56g==", + "version": "26.5.5", + "resolved": "https://registry.npmjs.org/ts-jest/-/ts-jest-26.5.5.tgz", + "integrity": "sha512-7tP4m+silwt1NHqzNRAPjW1BswnAhopTdc2K3HEkRZjF0ZG2F/e/ypVH0xiZIMfItFtD3CX0XFbwPzp9fIEUVg==", "dev": true, "requires": { - "@types/jest": "26.x", "bs-logger": "0.x", "buffer-from": "1.x", "fast-json-stable-stringify": "2.x", @@ -12063,9 +12078,9 @@ }, "dependencies": { "json5": { - "version": "2.1.3", - "resolved": "https://registry.npmjs.org/json5/-/json5-2.1.3.tgz", - "integrity": "sha512-KXPvOm8K9IJKFM0bmdn8QXh7udDh1g/giieX0NLCaMnb4hEiVFqnop2ImTXCc5e0/oHz3LTqmHGtExn5hfMkOA==", + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/json5/-/json5-2.2.0.tgz", + "integrity": "sha512-f+8cldu7X/y7RAJurMEJmdoKXGB/X550w2Nr3tTbezL6RwEE/iMcm+tZnXeoZtKuOq6ft8+CqzEkrIgx1fPoQA==", "dev": true, "requires": { "minimist": "^1.2.5" @@ -12078,17 +12093,17 @@ "dev": true }, "yargs-parser": { - "version": "20.2.4", - "resolved": "https://registry.npmjs.org/yargs-parser/-/yargs-parser-20.2.4.tgz", - "integrity": "sha512-WOkpgNhPTlE73h4VFAFsOnomJVaovO8VqLDzy5saChRBFQFBoMYirowyW+Q9HB4HFF4Z7VZTiG3iSzJJA29yRA==", + "version": "20.2.7", + "resolved": "https://registry.npmjs.org/yargs-parser/-/yargs-parser-20.2.7.tgz", + "integrity": "sha512-FiNkvbeHzB/syOjIUxFDCnhSfzAL8R5vs40MgLFBorXACCOAEaWu0gRZl14vG8MR9AOJIZbmkjhusqBYZ3HTHw==", "dev": true } } }, "ts-loader": { - "version": "8.0.14", - "resolved": "https://registry.npmjs.org/ts-loader/-/ts-loader-8.0.14.tgz", - "integrity": "sha512-Jt/hHlUnApOZjnSjTmZ+AbD5BGlQFx3f1D0nYuNKwz0JJnuDGHJas6az+FlWKwwRTu+26GXpv249A8UAnYUpqA==", + "version": "8.1.0", + "resolved": "https://registry.npmjs.org/ts-loader/-/ts-loader-8.1.0.tgz", + "integrity": "sha512-YiQipGGAFj2zBfqLhp28yUvPP9jUGqHxRzrGYuc82Z2wM27YIHbElXiaZDc93c3x0mz4zvBmS6q/DgExpdj37A==", "dev": true, "requires": { "chalk": "^4.1.0", @@ -12169,9 +12184,9 @@ "integrity": "sha512-hcVC3wYEziELGGmEEXue7D75zbwIIVUMWAVbHItGPx0ziyXxrOMQx4rQEVEV45Ut/1IotuEvwqPopzIOkDMf0A==" }, "tsutils": { - "version": "3.20.0", - "resolved": "https://registry.npmjs.org/tsutils/-/tsutils-3.20.0.tgz", - "integrity": "sha512-RYbuQuvkhuqVeXweWT3tJLKOEJ/UUw9GjNEZGWdrLLlM+611o1gwLHBpxoFJKKl25fLprp2eVthtKs5JOrNeXg==", + "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" @@ -12338,9 +12353,9 @@ } }, "typescript": { - "version": "4.1.3", - "resolved": "https://registry.npmjs.org/typescript/-/typescript-4.1.3.tgz", - "integrity": "sha512-B3ZIOf1IKeH2ixgHhj6la6xdwR9QrLC5d1VKeCSY4tvkqhF2eqd9O7txNlS0PO3GrBAFIdr3L1ndNwteUbZLYg==", + "version": "4.2.4", + "resolved": "https://registry.npmjs.org/typescript/-/typescript-4.2.4.tgz", + "integrity": "sha512-V+evlYHZnQkaz8TRBuxTA92yZBPotr5H+WhQ7bD3hZUndx5tGOa1fuCgeSjxAzM1RiN5IzvadIXTVefuuwZCRg==", "dev": true }, "ua-parser-js": { @@ -12522,9 +12537,9 @@ "integrity": "sha512-+NYs2QeMWy+GWFOEm9xnn6HCDp0l7QBD7ml8zLUmJ+93Q5NF0NocErnwkTkXVFNiX3/fpC6afS8Dhb/gz7R7eg==" }, "v8-compile-cache": { - "version": "2.2.0", - "resolved": "https://registry.npmjs.org/v8-compile-cache/-/v8-compile-cache-2.2.0.tgz", - "integrity": "sha512-gTpR5XQNKFwOd4clxfnhaqvfqMpqEwr4tOtCyz4MtYZX2JYhfr1JvBFKdS+7K/9rfpZR3VLX+YWBbKoxCgS43Q==", + "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 }, "v8-to-istanbul": { diff --git a/package.json b/package.json index 7628d70..1f90c67 100644 --- a/package.json +++ b/package.json @@ -22,13 +22,12 @@ }, "dependencies": { "@nestjs/bull": "^0.3.1", - "@nestjs/common": "^7.5.1", + "@nestjs/common": "^7.6.15", "@nestjs/config": "^0.6.2", - "@nestjs/core": "^7.5.1", + "@nestjs/core": "^7.6.15", "@nestjs/graphql": "^7.9.8", - "@nestjs/platform-express": "^7.5.1", + "@nestjs/platform-express": "^7.6.15", "@nestjs/typeorm": "^7.1.5", - "@types/bull": "^3.15.0", "apollo-server-express": "^2.19.2", "bcrypt": "^5.0.0", "body-parser": "^1.19.0", @@ -46,34 +45,32 @@ "ramda": "^0.27.1", "reflect-metadata": "^0.1.13", "rimraf": "^3.0.2", - "rxjs": "^6.6.3", + "rxjs": "^6.6.7", "simple-git": "^2.35.0", "typeorm": "^0.2.30" }, "devDependencies": { "@nestjs/cli": "^7.5.7", - "@nestjs/schematics": "^7.1.3", - "@nestjs/testing": "^7.5.1", - "@types/body-parser": "^1.19.0", - "@types/debug": "^4.1.5", + "@nestjs/schematics": "^7.3.1", + "@nestjs/testing": "^7.6.15", "@types/express": "^4.17.8", - "@types/ioredis": "^4.22.3", - "@types/jest": "^26.0.15", - "@types/node": "^14.14.6", - "@types/supertest": "^2.0.10", - "@typescript-eslint/eslint-plugin": "^4.6.1", - "@typescript-eslint/parser": "^4.6.1", - "eslint": "^7.12.1", + "@types/jest": "^26.0.22", + "@types/node": "^14.14.41", + "@types/supertest": "^2.0.11", + "@typescript-eslint/eslint-plugin": "^4.22.0", + "@typescript-eslint/parser": "^4.22.0", + "apollo-server-testing": "^2.23.0", + "eslint": "^7.24.0", "eslint-config-prettier": "7.2.0", - "eslint-plugin-prettier": "^3.1.4", + "eslint-plugin-prettier": "^3.4.0", "jest": "^26.6.3", "prettier": "^2.1.2", "supertest": "^6.0.0", - "ts-jest": "^26.4.3", - "ts-loader": "^8.0.8", + "ts-jest": "^26.5.5", + "ts-loader": "^8.1.0", "ts-node": "^9.0.0", "tsconfig-paths": "^3.9.0", - "typescript": "^4.0.5" + "typescript": "^4.2.4" }, "jest": { "moduleFileExtensions": [ diff --git a/src/app.module.ts b/src/app.module.ts index 9b6d556..f749f74 100644 --- a/src/app.module.ts +++ b/src/app.module.ts @@ -10,6 +10,7 @@ import { RedisModule } from 'nestjs-redis'; import { ParseBodyMiddleware } from './commons/middleware/parse-body.middleware'; import { BullModule } from '@nestjs/bull'; import { PubSubModule } from './commons/pub-sub/pub-sub.module'; +import { ArticlesModule } from './articles/articles.module'; @Module({ imports: [ @@ -72,6 +73,7 @@ import { PubSubModule } from './commons/pub-sub/pub-sub.module'; }), inject: [ConfigService], }), + ArticlesModule, ], controllers: [AppController], providers: [AppService, AppResolver], diff --git a/src/articles/articles.module.ts b/src/articles/articles.module.ts new file mode 100644 index 0000000..7388681 --- /dev/null +++ b/src/articles/articles.module.ts @@ -0,0 +1,11 @@ +import { Module } from '@nestjs/common'; +import { ArticlesService } from './articles.service'; +import { ArticlesResolver } from './articles.resolver'; +import { TypeOrmModule } from '@nestjs/typeorm'; +import { Article } from './entities/article.entity'; + +@Module({ + imports: [TypeOrmModule.forFeature([Article])], + providers: [ArticlesResolver, ArticlesService], +}) +export class ArticlesModule {} diff --git a/src/articles/articles.resolver.spec.ts b/src/articles/articles.resolver.spec.ts new file mode 100644 index 0000000..9d1e7c6 --- /dev/null +++ b/src/articles/articles.resolver.spec.ts @@ -0,0 +1,25 @@ +import { Test, TestingModule } from '@nestjs/testing'; +import { ArticlesResolver } from './articles.resolver'; +import { ArticlesService } from './articles.service'; + +describe('ArticlesResolver', () => { + let resolver: ArticlesResolver; + + beforeEach(async () => { + const module: TestingModule = await Test.createTestingModule({ + providers: [ + ArticlesResolver, + { + provide: ArticlesService, + useValue: {}, + }, + ], + }).compile(); + + resolver = module.get(ArticlesResolver); + }); + + it('should be defined', () => { + expect(resolver).toBeDefined(); + }); +}); diff --git a/src/articles/articles.resolver.ts b/src/articles/articles.resolver.ts new file mode 100644 index 0000000..2076f43 --- /dev/null +++ b/src/articles/articles.resolver.ts @@ -0,0 +1,42 @@ +import { Resolver, Query, Mutation, Args, Int } from '@nestjs/graphql'; +import { ArticlesService } from './articles.service'; +import { Article } from './entities/article.entity'; +import { CreateArticleInput } from './dto/create-article.input'; +import { UpdateArticleInput } from './dto/update-article.input'; + +@Resolver(() => Article) +export class ArticlesResolver { + constructor(private readonly articlesService: ArticlesService) {} + + @Mutation(() => Article) + createArticle( + @Args('createArticleInput') createArticleInput: CreateArticleInput, + ) { + return this.articlesService.create(createArticleInput); + } + + @Query(() => [Article], { name: 'articles' }) + findAll() { + return this.articlesService.findAll(); + } + + @Query(() => Article, { name: 'article' }) + findOne(@Args('id', { type: () => String }) id: string) { + return this.articlesService.findOne(id); + } + + @Mutation(() => Article) + updateArticle( + @Args('updateArticleInput') updateArticleInput: UpdateArticleInput, + ) { + return this.articlesService.update( + updateArticleInput.id, + updateArticleInput, + ); + } + + @Mutation(() => Article) + removeArticle(@Args('id', { type: () => String }) id: string) { + return this.articlesService.remove(id); + } +} diff --git a/src/articles/articles.service.spec.ts b/src/articles/articles.service.spec.ts new file mode 100644 index 0000000..f6c6a23 --- /dev/null +++ b/src/articles/articles.service.spec.ts @@ -0,0 +1,27 @@ +import { Test, TestingModule } from '@nestjs/testing'; +import { getRepositoryToken } from '@nestjs/typeorm'; +import { Repository } from 'typeorm'; +import { ArticlesService } from './articles.service'; +import { Article } from './entities/article.entity'; + +describe('ArticlesService', () => { + let service: ArticlesService; + + beforeEach(async () => { + const module: TestingModule = await Test.createTestingModule({ + providers: [ + ArticlesService, + { + provide: getRepositoryToken(Article), + useValue: new Repository(), + }, + ], + }).compile(); + + service = module.get(ArticlesService); + }); + + it('should be defined', () => { + expect(service).toBeDefined(); + }); +}); diff --git a/src/articles/articles.service.ts b/src/articles/articles.service.ts new file mode 100644 index 0000000..25ae229 --- /dev/null +++ b/src/articles/articles.service.ts @@ -0,0 +1,38 @@ +import { Injectable } from '@nestjs/common'; +import { InjectRepository } from '@nestjs/typeorm'; +import { Repository } from 'typeorm'; +import { BaseDbService } from '../commons/services/base-db.service'; +import { CreateArticleInput } from './dto/create-article.input'; +import { UpdateArticleInput } from './dto/update-article.input'; +import { Article } from './entities/article.entity'; + +@Injectable() +export class ArticlesService extends BaseDbService
{ + readonly uniqueFields: Array = ['title']; + constructor( + @InjectRepository(Article) + readonly repository: Repository
, + ) { + super(repository); + } + async create(createArticleInput: CreateArticleInput) { + await this.isDuplicateEntity(createArticleInput); + return await this.repository.save( + this.repository.create(createArticleInput), + ); + } + + async findAll() { + return await this.repository.find(); + } + + async update(id: string, updateArticleInput: UpdateArticleInput) { + await this.isDuplicateEntityForUpdate(id, updateArticleInput); + return await this.repository.update(id, updateArticleInput); + } + + async remove(id: string) { + await this.canRemove([id]); + return await this.repository.softDelete({ id }); + } +} diff --git a/src/articles/dto/create-article.input.ts b/src/articles/dto/create-article.input.ts new file mode 100644 index 0000000..8e7954c --- /dev/null +++ b/src/articles/dto/create-article.input.ts @@ -0,0 +1,20 @@ +import { InputType } from '@nestjs/graphql'; +import { IsDate, IsOptional, IsString, Length } from 'class-validator'; + +@InputType() +export class CreateArticleInput { + @IsString() + @Length(1, 100) + title: string; + + @IsString() + @Length(2, 100000) + content: string; + + @IsOptional() + @IsDate() + publishedAt?: Date; + + @IsString({ each: true }) + tags: string[]; +} diff --git a/src/articles/dto/update-article.input.ts b/src/articles/dto/update-article.input.ts new file mode 100644 index 0000000..642777f --- /dev/null +++ b/src/articles/dto/update-article.input.ts @@ -0,0 +1,8 @@ +import { CreateArticleInput } from './create-article.input'; +import { InputType, Field, Int, PartialType } from '@nestjs/graphql'; + +@InputType() +export class UpdateArticleInput extends PartialType(CreateArticleInput) { + @Field(() => Int) + id: string; +} diff --git a/src/articles/entities/article.entity.ts b/src/articles/entities/article.entity.ts new file mode 100644 index 0000000..ffcf4c3 --- /dev/null +++ b/src/articles/entities/article.entity.ts @@ -0,0 +1,20 @@ +import { ObjectType } from '@nestjs/graphql'; +import { Column, Entity, Index } from 'typeorm'; +import { AppBaseEntity } from '../../commons/entities/app-base-entity'; + +@Entity() +@ObjectType() +export class Article extends AppBaseEntity { + @Column() + title: string; + + @Column({ type: 'text' }) + content: string; + + @Index() + @Column({ nullable: true }) + publishedAt?: Date; + + @Column({ type: 'varchar', array: true }) + tags: string[]; +} diff --git a/src/commons/services/base-db.service.ts b/src/commons/services/base-db.service.ts index ab52e02..168e215 100644 --- a/src/commons/services/base-db.service.ts +++ b/src/commons/services/base-db.service.ts @@ -112,7 +112,7 @@ export class BaseDbService extends TypeormHelper { } } - async canYouRemoveWithIds(ids: string[]): Promise { + async canRemove(ids: string[]): Promise { return; } diff --git a/test/app.e2e-spec.ts b/test/app.e2e-spec.ts index 50cda62..57526e7 100644 --- a/test/app.e2e-spec.ts +++ b/test/app.e2e-spec.ts @@ -1,24 +1,49 @@ import { Test, TestingModule } from '@nestjs/testing'; import { INestApplication } from '@nestjs/common'; -import * as request from 'supertest'; import { AppModule } from './../src/app.module'; +import { GraphQLModule } from '@nestjs/graphql'; +import { + ApolloServerTestClient, + createTestClient, +} from 'apollo-server-testing'; +import { gql } from 'apollo-server-express'; -describe('AppController (e2e)', () => { +describe('ArticleResolver (e2e)', () => { let app: INestApplication; + let apolloClient: ApolloServerTestClient; - beforeEach(async () => { + beforeAll(async () => { const moduleFixture: TestingModule = await Test.createTestingModule({ imports: [AppModule], }).compile(); app = moduleFixture.createNestApplication(); await app.init(); + const module: GraphQLModule = moduleFixture.get( + GraphQLModule, + ); + // apolloServer is protected, we need to cast module to any to get it + apolloClient = createTestClient((module as any).apolloServer); + }); + it('QUERY hello', async () => { + const res = await apolloClient.query({ + query: gql` + query { + hello { + message + } + } + `, + variables: {}, + }); + expect(res.data).toEqual({ + hello: { + message: 'Hello, World!', + }, + }); }); - it('/ (GET)', () => { - return request(app.getHttpServer()) - .get('/') - .expect(200) - .expect('Hello World!'); + afterAll(async () => { + await app?.close(); }); }); diff --git a/test/article.e2e-spec.ts b/test/article.e2e-spec.ts new file mode 100644 index 0000000..7056be3 --- /dev/null +++ b/test/article.e2e-spec.ts @@ -0,0 +1,33 @@ +import { Test, TestingModule } from '@nestjs/testing'; +import { INestApplication } from '@nestjs/common'; +import * as request from 'supertest'; +import { AppModule } from '../src/app.module'; +import { GraphQLModule } from '@nestjs/graphql'; +import { + ApolloServerTestClient, + createTestClient, +} from 'apollo-server-testing'; +import { gql } from 'apollo-server-express'; + +describe('AppController (e2e)', () => { + let app: INestApplication; + let apolloClient: ApolloServerTestClient; + + beforeAll(async () => { + const moduleFixture: TestingModule = await Test.createTestingModule({ + imports: [AppModule], + }).compile(); + + app = moduleFixture.createNestApplication(); + await app.init(); + const module: GraphQLModule = moduleFixture.get( + GraphQLModule, + ); + // apolloServer is protected, we need to cast module to any to get it + apolloClient = createTestClient((module as any).apolloServer); + }); + + afterAll(async () => { + await app?.close(); + }); +}); diff --git a/test/data/article.e2e-spec.ts b/test/data/article.e2e-spec.ts new file mode 100644 index 0000000..e69de29 diff --git a/test/data/bad-work.js b/test/data/bad-work.js deleted file mode 100644 index caffb9c..0000000 --- a/test/data/bad-work.js +++ /dev/null @@ -1,8 +0,0 @@ -for (let i = 1; i <= 5; i++) { - console.log(i * 10); -} -console.error('Error Message'); -console.error('Error Message 2'); -console.log('Bye-bye'); - -process.exit(1); diff --git a/test/data/gitea-hook-payload.json.bin b/test/data/gitea-hook-payload.json.bin deleted file mode 100644 index 5ee386c..0000000 --- a/test/data/gitea-hook-payload.json.bin +++ /dev/null @@ -1,115 +0,0 @@ -{ - "secret": "boardcat", - "ref": "refs/heads/master", - "before": "429de1eaedf1da83f1e0e3ac3d8b20e771b7051c", - "after": "429de1eaedf1da83f1e0e3ac3d8b20e771b7051c", - "compare_url": "", - "commits": [ - { - "id": "429de1eaedf1da83f1e0e3ac3d8b20e771b7051c", - "message": "test(pipeline-tasks): pass test cases.\n", - "url": "https://git.ivanli.cc/Fennec/fennec-be/commit/429de1eaedf1da83f1e0e3ac3d8b20e771b7051c", - "author": { - "name": "Ivan", - "email": "ivanli@live.cn", - "username": "" - }, - "committer": { - "name": "Ivan", - "email": "ivanli@live.cn", - "username": "" - }, - "verification": null, - "timestamp": "0001-01-01T00:00:00Z", - "added": null, - "removed": null, - "modified": null - } - ], - "head_commit": null, - "repository": { - "id": 3, - "owner": { - "id": 3, - "login": "Fennec", - "full_name": "", - "email": "", - "avatar_url": "https://git.ivanli.cc/user/avatar/Fennec/-1", - "language": "", - "is_admin": false, - "last_login": "1970-01-01T08:00:00+08:00", - "created": "2021-01-30T16:46:11+08:00", - "username": "Fennec" - }, - "name": "fennec-be", - "full_name": "Fennec/fennec-be", - "description": "Fennec CI/CD Back-End", - "empty": false, - "private": false, - "fork": false, - "template": false, - "parent": null, - "mirror": false, - "size": 1897, - "html_url": "https://git.ivanli.cc/Fennec/fennec-be", - "ssh_url": "ssh://gitea@git.ivanli.cc:7018/Fennec/fennec-be.git", - "clone_url": "https://git.ivanli.cc/Fennec/fennec-be.git", - "original_url": "", - "website": "", - "stars_count": 1, - "forks_count": 0, - "watchers_count": 1, - "open_issues_count": 0, - "open_pr_counter": 0, - "release_counter": 0, - "default_branch": "master", - "archived": false, - "created_at": "2021-01-31T09:58:38+08:00", - "updated_at": "2021-03-27T15:57:00+08:00", - "permissions": { - "admin": false, - "push": false, - "pull": false - }, - "has_issues": true, - "internal_tracker": { - "enable_time_tracker": true, - "allow_only_contributors_to_track_time": true, - "enable_issue_dependencies": true - }, - "has_wiki": true, - "has_pull_requests": true, - "has_projects": true, - "ignore_whitespace_conflicts": false, - "allow_merge_commits": true, - "allow_rebase": true, - "allow_rebase_explicit": true, - "allow_squash_merge": true, - "avatar_url": "", - "internal": false - }, - "pusher": { - "id": 1, - "login": "Ivan", - "full_name": "Ivan Li", - "email": "ivan@noreply.%(DOMAIN)s", - "avatar_url": "https://git.ivanli.cc/user/avatar/Ivan/-1", - "language": "zh-CN", - "is_admin": true, - "last_login": "2021-03-26T22:28:05+08:00", - "created": "2021-01-23T18:15:30+08:00", - "username": "Ivan" - }, - "sender": { - "id": 1, - "login": "Ivan", - "full_name": "Ivan Li", - "email": "ivan@noreply.%(DOMAIN)s", - "avatar_url": "https://git.ivanli.cc/user/avatar/Ivan/-1", - "language": "zh-CN", - "is_admin": true, - "last_login": "2021-03-26T22:28:05+08:00", - "created": "2021-01-23T18:15:30+08:00", - "username": "Ivan" - } -} \ No newline at end of file diff --git a/test/data/one-second-work.js b/test/data/one-second-work.js deleted file mode 100644 index be81207..0000000 --- a/test/data/one-second-work.js +++ /dev/null @@ -1,7 +0,0 @@ -let timer; -let count = 0; -setTimeout(() => clearInterval(timer), 1_000); - -timer = setInterval(() => { - console.log(++count * 10); -}, 95); diff --git a/test/graphql-e2e.ts b/test/graphql-e2e.ts new file mode 100644 index 0000000..8d5bd01 --- /dev/null +++ b/test/graphql-e2e.ts @@ -0,0 +1,15 @@ +// eslint-disable-next-line @typescript-eslint/no-var-requires +const transformer = require('@nestjs/graphql/plugin'); + +module.exports.name = 'nestjs-graphql-transformer'; +// you should change the version number anytime you change the configuration below - otherwise, jest will not detect changes +module.exports.version = 1; + +module.exports.factory = (cs) => { + return transformer.before( + { + // @nestjs/graphql/plugin options (can be empty) + }, + cs.tsCompiler.program, + ); +}; diff --git a/test/jest-e2e.json b/test/jest-e2e.json index e9d912f..c7c537a 100644 --- a/test/jest-e2e.json +++ b/test/jest-e2e.json @@ -5,5 +5,12 @@ "testRegex": ".e2e-spec.ts$", "transform": { "^.+\\.(t|j)s$": "ts-jest" + }, + "globals": { + "ts-jest": { + "astTransformers": { + "before": ["/graphql-e2e.ts"] + } + } } }