diff --git a/.github/dependabot.yml b/.github/dependabot.yml index 742679c..ac517fa 100644 --- a/.github/dependabot.yml +++ b/.github/dependabot.yml @@ -24,4 +24,4 @@ updates: commit-message: prefix: "fix" prefix-development: "chore" - + \ No newline at end of file diff --git a/.github/workflows/nodejs.yml b/.github/workflows/nodejs.yml index 6663a0b..dcf4f4d 100644 --- a/.github/workflows/nodejs.yml +++ b/.github/workflows/nodejs.yml @@ -9,11 +9,8 @@ jobs: strategy: matrix: node-version: [12, 14] - os: [macos-latest, windows-latest, ubuntu-latest] + os: [windows-latest, ubuntu-latest] steps: - - name: Disable autocrlf - run: git config --global core.autocrlf false - if: matrix.os == 'windows-latest' - uses: actions/checkout@v2 - name: setup Node.js ${{ matrix.node-version }} uses: actions/setup-node@v1 @@ -31,6 +28,7 @@ jobs: ${{ runner.os }}-yarn- - run: yarn --frozen-lockfile - run: yarn lint + if: matrix.os != 'windows-latest' - run: yarn typecheck - run: yarn test --coverage - run: npx codecov diff --git a/.gitignore b/.gitignore index f06235c..e060b02 100644 --- a/.gitignore +++ b/.gitignore @@ -1,2 +1,4 @@ node_modules dist +benchmark +coverage diff --git a/CHANGELOG.md b/CHANGELOG.md index c3e9d10..34df7e7 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -2,6 +2,64 @@ All notable changes to this project will be documented in this file. See [standard-version](https://github.com/conventional-changelog/standard-version) for commit guidelines. +## [0.12.0](https://github.com/frouriojs/frourio/compare/v0.11.0...v0.12.0) (2020-09-11) + + +### ⚠ BREAKING CHANGES + +* override createController + +### Features + +* add benchmark ([ef5d373](https://github.com/frouriojs/frourio/commit/ef5d373ffcdde0d1452dcb4223e3de52ac8ad754)) +* add createHooks ([da05725](https://github.com/frouriojs/frourio/commit/da05725ee95d0b34c0f8488bbdeb6377cb63f171)) +* add noPublic ([8e2490b](https://github.com/frouriojs/frourio/commit/8e2490b4dd87779d8417cb01add7ffa31df71af2)) +* add noTypedParams ([ed36c1e](https://github.com/frouriojs/frourio/commit/ed36c1e9c0616ae9ba63113a837637cd0e13cfb5)) +* add noTypeorm ([a432380](https://github.com/frouriojs/frourio/commit/a432380e9340eb689ed6367cce8327b80c4b64e0)) +* build for benchmark ([79034f3](https://github.com/frouriojs/frourio/commit/79034f3eaf59a8f8bcc2509add95069e6028e38a)) +* combine index.ts into $app.ts ([2293cd9](https://github.com/frouriojs/frourio/commit/2293cd92d5ff6b3bcedcd9e9ad067cf009ff2e2e)) +* delete cors and helmet ([d17e07d](https://github.com/frouriojs/frourio/commit/d17e07d986226b3f7257e015fb92813aa25b8bc4)) +* generate controllers array ([babecd9](https://github.com/frouriojs/frourio/commit/babecd95eaf7f354f1dd0b6bc9c9029426896f80)) +* ignore empty dirs ([61320be](https://github.com/frouriojs/frourio/commit/61320beaf5f20fab718f23a160cc3381de6eafdb)) +* integrate fastify and express ([8203dbb](https://github.com/frouriojs/frourio/commit/8203dbbca94f12a9a71a8fbd137e0667b3afdb39)) +* override createController ([ac6e61b](https://github.com/frouriojs/frourio/commit/ac6e61b19d48485dfb81cac5ac90b9808e620aa0)) +* parse with tsc ([1880be1](https://github.com/frouriojs/frourio/commit/1880be1fe3b8355e49acf47ebb35aeb4bdd19f18)) +* remove dir option ([25f5844](https://github.com/frouriojs/frourio/commit/25f5844697895b15a98facf98432070d0d0a124b)) +* remove fastify ([6d59a3d](https://github.com/frouriojs/frourio/commit/6d59a3d60875f6ccddcc3688a506baf10cc297fc)) +* remove multer when not in use ([3456679](https://github.com/frouriojs/frourio/commit/34566790bce5ae2501752eec9b988aa7b9623351)) +* remove public dir ([b334555](https://github.com/frouriojs/frourio/commit/b33455528e293d565d9acae319ecd12284130078)) +* remove typeorm from deps ([76ff7ec](https://github.com/frouriojs/frourio/commit/76ff7ecb674dca0565b7c7305e14a2c94e9bc82f)) +* remove typeorm from deps ([5f04bd8](https://github.com/frouriojs/frourio/commit/5f04bd8d2b6817887ece972f60244b722aecf26f)) +* rename createController to defineController ([cb6889b](https://github.com/frouriojs/frourio/commit/cb6889b7eac208e0baa4ad7d5d361ffcd0182db5)) +* rename createHooks to defineHooks ([17a04aa](https://github.com/frouriojs/frourio/commit/17a04aa4cee1c7f090287757999f3999132a75d6)) +* rename types to validators ([ad0adac](https://github.com/frouriojs/frourio/commit/ad0adac86dd639531018ed923f2d42301242c2fc)) +* suport fastify ([efce77e](https://github.com/frouriojs/frourio/commit/efce77e251fe7aeb5f1e3980cb26ebd8518feeec)) +* support crlf ([e8829d8](https://github.com/frouriojs/frourio/commit/e8829d8c728bf6ebec6f2978ef2166b327c670f6)) +* support number type query params ([e859624](https://github.com/frouriojs/frourio/commit/e85962430b0fabc4df4075172942d7975f8a64ab)) +* support paths from tsconfig ([c5c9eac](https://github.com/frouriojs/frourio/commit/c5c9eac62b6e8bbbac7e4815a872a07f59c01da2)) +* support velona ([521edec](https://github.com/frouriojs/frourio/commit/521edec2f0c7c221e02a205cb6f6411782c215be)) +* update aspida@0.20.2 ([0018225](https://github.com/frouriojs/frourio/commit/00182254793792a4960f0e45950d8605d1c8e04c)) + + +### Bug Fixes + +* delete $arrayTypeKeysName ([f21b612](https://github.com/frouriojs/frourio/commit/f21b612bd744fc5f05401a8de690325fa907014f)) +* parse JSON ([6d06947](https://github.com/frouriojs/frourio/commit/6d06947b541e334d4d553e0e8649d9acea1922c7)) + + +### Refactors + +* add createValidateHandler ([997bc0f](https://github.com/frouriojs/frourio/commit/997bc0f68d44dce42c9a5350f86984fe1b8ed808)) +* apply router to app ([d99f5ed](https://github.com/frouriojs/frourio/commit/d99f5ed0f247aab3e3ad978a2ca736bca02572ba)) +* optimize controllers ([0641d38](https://github.com/frouriojs/frourio/commit/0641d38e45bb45568f787a1e4cb0c540c434dd8e)) +* optimize deps ([83b8d4e](https://github.com/frouriojs/frourio/commit/83b8d4e591148a6ee870c9d133b97eee6c31d217)) + + +### Documentation + +* fix broken twitter image link ([9e8ea10](https://github.com/frouriojs/frourio/commit/9e8ea10be447b78d3845b1b6f2c8be08d0da1cfa)) +* update README ([a69a219](https://github.com/frouriojs/frourio/commit/a69a2190e98a811549cc1dcf19939d99f06731b2)) + ## [0.11.0](https://github.com/frouriojs/frourio/compare/v0.10.4...v0.11.0) (2020-07-19) diff --git a/README.md b/README.md index 598c447..968310b 100644 --- a/README.md +++ b/README.md @@ -1,20 +1,30 @@ -# frourio - - - npm version - - - Node.js CI - - - Codecov - - - License - +
+
+ frourio +
-> Perfectly type-checkable REST framework for TypeScript. +
+ + npm version + + + Node.js CI + + + Codecov + + + Language grade: JavaScript + + + License + +
+

Frourio is a perfectly type-checkable REST framework for TypeScript.

+
+
+
## Why frourio ? @@ -49,7 +59,7 @@ The front is checked by the type to see if it is making an API request as define Architecture of create-frourio-app -## Usage +## Install Make sure you have [npx](https://www.npmjs.com/package/npx) installed (`npx` is shipped by default since [npm](https://www.npmjs.com/get-npm) `5.2.0`) @@ -74,25 +84,6 @@ yarn create frourio-app Frourio requires TypeScript 3.9 or higher. If the TypeScript version of VSCode is low, an error is displayed during development. -## Type definition of API endpoints - -aspida: `/apis` --> frourio: `/server/api` - -[See: Create an endpoint type definition file | aspida](https://github.com/aspidajs/aspida#create-an-endpoint-type-definition-file) - -#### Warning ! -examples. - -> GET: /api/test - -x- /server/api/test.ts -o- /server/api/test/index.ts - -> GET: /api/test/{testId} - -x- /server/api/test/_testId.ts -o- /server/api/test/_testId/index.ts - ## Support @@ -101,4 +92,4 @@ o- /server/api/test/_testId/index.ts ## License -frourio is licensed under a [MIT License](https://github.com/frouriojs/frourio/blob/master/packages/frourio/LICENSE). +Frourio is licensed under a [MIT License](https://github.com/frouriojs/frourio/blob/master/packages/frourio/LICENSE). diff --git a/commitlint.config.js b/commitlint.config.js deleted file mode 100644 index a4f4369..0000000 --- a/commitlint.config.js +++ /dev/null @@ -1,3 +0,0 @@ -module.exports = { - extends: ['@commitlint/config-conventional'] -} diff --git a/docs/assets/images/ogp.png b/docs/assets/images/ogp.png new file mode 100644 index 0000000..ae34963 Binary files /dev/null and b/docs/assets/images/ogp.png differ diff --git a/jest.config.js b/jest.config.js index 146e539..a07c06a 100644 --- a/jest.config.js +++ b/jest.config.js @@ -1,7 +1,10 @@ +const { pathsToModuleNameMapper } = require('ts-jest/utils') +const { compilerOptions } = require('./tsconfig') + module.exports = { preset: 'ts-jest', testEnvironment: 'node', globals: { Blob: {} }, - testPathIgnorePatterns: ['apis'], - coveragePathIgnorePatterns: ['apis', 'dist'] + moduleNameMapper: pathsToModuleNameMapper(compilerOptions.paths, { prefix: '/' }), + coveragePathIgnorePatterns: ['\\$api.ts', 'dist'] } diff --git a/package.json b/package.json index 94d5285..6c98cdd 100644 --- a/package.json +++ b/package.json @@ -4,9 +4,10 @@ "packages/*" ], "scripts": { - "dev": "npm run build && cd packages/frourio && cd server && aspida --build && node ../bin/index.js --build", - "build": "npm run rimraf -- frourio && cd packages/frourio && tsc --project tsconfig.json", - "rimraf": "node -e \"require('fs').rmdirSync('packages/' + process.argv[1] + '/dist', { recursive: true })\"", + "dev": "npm run build && cd packages/frourio/servers && aspida && node build.js", + "build": "npm run rimraf -- packages/frourio/dist && tsc -p packages/frourio", + "build:benchmark": "npm run rimraf -- benchmark && tsc -p tsconfig.benchmark.json", + "rimraf": "node -e \"require('fs').rmdirSync(process.argv[1], { recursive: true })\"", "release": "standard-version --skip.tag", "release:major": "npm run release -- --release-as major", "release:minor": "npm run release -- --release-as minor", @@ -14,7 +15,7 @@ "lint": "eslint --ext .js,.ts --ignore-path .gitignore .", "lint:fix": "npm run lint -- --fix", "test": "jest", - "typecheck": "npm run build && tsc --noEmit" + "typecheck": "tsc --noEmit" }, "eslintConfig": { "env": { @@ -64,27 +65,30 @@ ] }, "devDependencies": { - "@aspida/axios": "^0.9.4", - "@commitlint/cli": "^9.1.1", - "@commitlint/config-conventional": "^9.1.1", - "@types/jest": "^26.0.4", - "@types/minimist": "^1.2.0", - "@typescript-eslint/eslint-plugin": "^3.6.1", - "@typescript-eslint/parser": "^3.6.1", - "axios": "^0.19.2", - "eslint": "^7.4.0", + "@aspida/axios": "^0.11.3", + "@types/express": "^4.17.7", + "@types/jest": "^26.0.13", + "@types/multer": "^1.4.4", + "@typescript-eslint/eslint-plugin": "^4.1.0", + "@typescript-eslint/parser": "^4.1.0", + "axios": "^0.20.0", + "class-validator": "^0.12.2", + "eslint": "^7.8.1", "eslint-config-prettier": "^6.11.0", "eslint-config-standard": "^14.1.1", "eslint-plugin-import": "^2.22.0", - "eslint-plugin-jest": "^23.18.0", + "eslint-plugin-jest": "^24.0.0", "eslint-plugin-node": "^11.1.0", "eslint-plugin-prettier": "^3.1.4", "eslint-plugin-promise": "^4.2.1", "eslint-plugin-standard": "^4.0.1", + "express": "^4.17.1", "form-data": "^3.0.0", - "jest": "^26.1.0", - "prettier": "2.0.5", - "standard-version": "^8.0.2", - "ts-jest": "^26.1.3" + "jest": "^26.4.2", + "multer": "^1.4.2", + "prettier": "^2.1.1", + "standard-version": "^9.0.0", + "ts-jest": "^26.3.0", + "typescript": "^4.0.2" } } diff --git a/packages/frourio/__test__/build.spec.ts b/packages/frourio/__test__/build.spec.ts index f3a3a8a..88caeeb 100644 --- a/packages/frourio/__test__/build.spec.ts +++ b/packages/frourio/__test__/build.spec.ts @@ -1,20 +1,37 @@ import fs from 'fs' +import { version } from '../package.json' +import { run } from '../src/cli' import build from '../src/buildServerFile' import aspidaBuild from 'aspida/dist/buildTemplate' const basePath = 'packages/frourio' +test('version command', () => { + const spyLog = jest.spyOn(console, 'log') + const args = ['--version'] + + run(args) + expect(console.log).toHaveBeenCalledWith(`v${version}`) + + spyLog.mockRestore() +}) + test('build', () => { - const inputDir = `${basePath}/server` + const inputDir = `${basePath}/servers` - const result = build(inputDir) - expect(result.text.replace(inputDir, 'server')).toBe(fs.readFileSync(result.filePath, 'utf8')) + fs.readdirSync(inputDir, { withFileTypes: true }) + .filter(d => d.isDirectory()) + .map(d => `${inputDir}/${d.name}`) + .forEach(input => { + const result = build(input) + expect(result.text).toBe(fs.readFileSync(result.filePath, 'utf8').replace(/\r/g, '')) - const [target] = aspidaBuild({ - input: `${inputDir}/api`, - baseURL: '', - trailingSlash: false, - outputEachDir: false - }) - expect(target.text).toBe(fs.readFileSync(target.filePath, 'utf8')) + const [target] = aspidaBuild({ + input: `${input}/api`, + baseURL: '', + trailingSlash: false, + outputEachDir: false + }) + expect(target.text).toBe(fs.readFileSync(target.filePath, 'utf8').replace(/\r/g, '')) + }) }) diff --git a/packages/frourio/__test__/index.spec.ts b/packages/frourio/__test__/index.spec.ts index 3bc1c69..1f7b160 100644 --- a/packages/frourio/__test__/index.spec.ts +++ b/packages/frourio/__test__/index.spec.ts @@ -1,28 +1,31 @@ +/* eslint-disable jest/no-done-callback */ import { Server } from 'http' import fs from 'fs' +import express from 'express' import FormData from 'form-data' import axios from 'axios' -import { $arrayTypeKeysName } from 'aspida' import aspida from '@aspida/axios' -import api from '../server/api/$api' -import { run } from '../server/$app' +import api from '../servers/all/api/$api' +import frourio from '../servers/all/$app' const port = 11111 const baseURL = `http://localhost:${port}` const client = api(aspida(undefined, { baseURL })) let server: Server -beforeEach(async () => { - server = (await run({ port })).server +beforeEach(cb => { + server = frourio(express()).listen(port, cb) }) afterEach(fn => { - fs.rmdirSync('packages/frourio/server/.upload', { recursive: true }) + fs.rmdirSync('packages/frourio/servers/all/.upload', { recursive: true }) server.close(fn) }) test('GET: 200', async () => { - const res = await client.$get({ query: { id: '1', disable: 'false' } }) + const res = await client.$get({ + query: { requiredNum: 1, requiredNumArr: [1, 2], id: '1', disable: 'false' } + }) expect(res?.id).toBe(1) }) @@ -40,17 +43,27 @@ test('GET: params.userId', async () => { test('GET: 400', async () => { await Promise.all([ - expect(client.get({ query: { id: '1', disable: 'no boolean' } })).rejects.toHaveProperty( - 'response.status', - 400 - ), - expect(client.get({ query: { id: 'no number', disable: 'true' } })).rejects.toHaveProperty( - 'response.status', - 400 - ) + expect( + client.get({ query: { requiredNum: 0, requiredNumArr: [], id: '1', disable: 'no boolean' } }) + ).rejects.toHaveProperty('response.status', 400), + expect( + client.get({ + query: { requiredNum: 1, requiredNumArr: [1, 2], id: 'no number', disable: 'true' } + }) + ).rejects.toHaveProperty('response.status', 400) ]) }) +test('GET: 500', async () => { + await expect(client.$500.get()).rejects.toHaveProperty('response.status', 500) +}) + +test('PUT: JSON', async () => { + const id = 'abcd' + const res = await client.texts.sample.$put({ body: { id } }) + expect(res?.id).toBe(id) +}) + test('POST: formdata', async () => { const port = '3000' const fileName = 'tsconfig.json' @@ -59,7 +72,7 @@ test('POST: formdata', async () => { form.append('file', fs.createReadStream(fileName)) const res = await axios.post(baseURL, form, { headers: form.getHeaders(), - params: { id: 1, disable: true } + params: { requiredNum: 0, requiredNumArr: [], id: 1, disable: true } }) expect(res.data.port).toBe(port) expect(res.data.fileName).toBe(fileName) @@ -69,18 +82,19 @@ test('POST: multi file upload', async () => { const fileName = 'tsconfig.json' const form = new FormData() const fileST = fs.createReadStream(fileName) + form.append('optionalArr', 'sample') form.append('name', 'sample') form.append('vals', 'dammy') form.append('icon', fileST) form.append('files', fileST) form.append('files', fileST) - form.append($arrayTypeKeysName, ['empty', 'vals', 'files'].join(',')) const res = await axios.post(`${baseURL}/multiForm`, form, { headers: form.getHeaders() }) + expect(res.data).toEqual({ - [$arrayTypeKeysName]: undefined, - empty: 0, + requiredArr: 0, + optionalArr: 1, name: -1, icon: -1, vals: 1, @@ -95,7 +109,6 @@ test('POST: 400', async () => { form.append('name', 'sample') form.append('vals', 'dammy') form.append('icon', fileST) - form.append($arrayTypeKeysName, ['empty', 'vals', 'files'].join(',')) await expect( axios.post(`${baseURL}/multiForm`, form, { @@ -103,8 +116,3 @@ test('POST: 400', async () => { }) ).rejects.toHaveProperty('response.status', 400) }) - -test('GET: static', async () => { - const res = await axios.get(`http://localhost:${port}/sample.json`) - expect(res.data.sample).toBe(true) -}) diff --git a/packages/frourio/__test__/unit.spec.ts b/packages/frourio/__test__/unit.spec.ts new file mode 100644 index 0000000..026e708 --- /dev/null +++ b/packages/frourio/__test__/unit.spec.ts @@ -0,0 +1,42 @@ +import fs from 'fs' +import createDefaultFilesIfNotExists from '../src/createDefaultFilesIfNotExists' + +test('createDefaultFilesIfNotExists', () => { + const dir = 'tmp' + fs.mkdirSync(dir) + createDefaultFilesIfNotExists(dir) + + expect(fs.readFileSync(`${dir}/index.ts`, 'utf8')).toBe(`export type Methods = { + get: { + resBody: string + } +} +`) + + expect(fs.readFileSync(`${dir}/controller.ts`, 'utf8')) + .toBe(`import { defineController } from './$relay' + +export default defineController(() => ({ + get: () => ({ status: 200, body: 'Hello' }) +})) +`) + + expect(fs.existsSync(`${dir}/hooks.ts`)).toBeFalsy() + + fs.writeFileSync(`${dir}/hooks.ts`, '', 'utf8') + createDefaultFilesIfNotExists(dir) + + expect(fs.readFileSync(`${dir}/hooks.ts`, 'utf8')).toBe( + `import { defineHooks } from './$relay' + +export default defineHooks(() => ({ + onRequest: (req, res, next) => { + console.log('Directory level onRequest hook:', req.path) + next() + } +})) +` + ) + + fs.rmdirSync(dir, { recursive: true }) +}) diff --git a/packages/frourio/package.json b/packages/frourio/package.json index 0bbce91..55804bc 100644 --- a/packages/frourio/package.json +++ b/packages/frourio/package.json @@ -1,12 +1,12 @@ { "name": "frourio", - "version": "0.11.0", + "version": "0.12.0", "description": "Perfectly type-checkable REST framework for TypeScript", "author": "Solufa ", "license": "MIT", "main": "dist/index.js", "bin": "bin/index.js", - "homepage": "https://github.com/frouriojs/frourio/tree/master/packages/frourio#readme", + "homepage": "https://github.com/frouriojs/frourio#readme", "repository": { "type": "git", "url": "git+https://github.com/frouriojs/frourio.git" @@ -23,19 +23,7 @@ "server" ], "dependencies": { - "@types/cors": "^2.8.6", - "@types/express": "^4.17.7", - "@types/express-serve-static-core": "^4.17.8", - "@types/helmet": "^0.0.47", - "@types/multer": "^1.4.3", - "aspida": "^0.19.4", - "class-validator": "^0.12.2", - "cors": "^2.8.5", - "express": "^4.17.1", - "helmet": "^3.23.3", - "multer": "^1.4.2", - "reflect-metadata": "^0.1.13", - "typeorm": "^0.2.25", - "typescript": "^3.9.7" + "aspida": "^0.21.3", + "velona": "^0.5.1" } } diff --git a/packages/frourio/server/$app.ts b/packages/frourio/server/$app.ts deleted file mode 100644 index a44386b..0000000 --- a/packages/frourio/server/$app.ts +++ /dev/null @@ -1,137 +0,0 @@ -/* eslint-disable */ -import 'reflect-metadata' -import { Server } from 'http' -import path from 'path' -import express, { Express } from 'express' -import multer from 'multer' -import helmet from 'helmet' -import cors from 'cors' -import { createConnection, Connection } from 'typeorm' -import { createRouter, Config } from 'frourio' -import { Task as Entity0 } from './entity/Task' -import { TaskSubscriber as Subscriber0 } from './subscriber/TaskSubscriber' -import * as Types from './types' -import controller0, { middleware as ctrlMiddleware0 } from './api/@controller' -import controller1 from './api/multiForm/@controller' -import controller2 from './api/texts/@controller' -import controller3 from './api/texts/sample/@controller' -import controller4, { middleware as ctrlMiddleware1 } from './api/users/@controller' -import controller5 from './api/users/_userId@number/@controller' -import middleware0 from './api/@middleware' -import middleware1 from './api/users/@middleware' - -export const controllers = { - name: '/', - validator: { - get: { - query: { required: false, Class: Types.ValidQuery } - }, - post: { - query: { required: true, Class: Types.ValidQuery }, - body: { required: true, Class: Types.ValidBody } - } - }, - uploader: ['post'], - controller: controller0, - ctrlMiddleware: ctrlMiddleware0, - middleware: middleware0, - children: { - names: [ - { - name: '/multiForm', - validator: { - post: { - body: { required: true, Class: Types.ValidMultiForm } - } - }, - uploader: ['post'], - controller: controller1 - }, - { - name: '/texts', - controller: controller2, - children: { - names: [ - { - name: '/sample', - controller: controller3 - } - ] - } - }, - { - name: '/users', - validator: { - post: { - body: { required: true, Class: Types.ValidUserInfo } - } - }, - controller: controller4, - ctrlMiddleware: ctrlMiddleware1, - middleware: middleware1, - children: { - value: { - name: '/_userId@number', - controller: controller5 - } - } - } - ] - } -} - -export const entities = [Entity0] -export const migrations = [] -export const subscribers = [Subscriber0] -export const run = async (config: Config) => { - const app = express() - const router = createRouter( - controllers, - multer( - config.multer ?? { dest: path.join(__dirname, '.upload'), limits: { fileSize: 1024 ** 3 } } - ).any() - ) - - if (config.helmet) app.use(helmet(config.helmet === true ? {} : config.helmet)) - if (config.cors) app.use(cors(config.cors === true ? {} : config.cors)) - - app.use((req, res, next) => { - express.json()(req, res, err => { - if (err) return res.sendStatus(400) - - next() - }) - }) - - const staticMiddleware = express.static(path.join(__dirname, 'public')) - if (config.basePath && config.basePath !== '/') { - const staticPath = config.basePath.startsWith('/') ? config.basePath : `/${config.basePath}` - app.use(staticPath, router) - app.use(staticPath, staticMiddleware) - } else { - app.use(router) - app.use(staticMiddleware) - } - - let connection: Connection - - if (config.typeorm) { - connection = await createConnection({ - entities, - migrations, - subscribers, - ...config.typeorm - }) - } - - return new Promise<{ - app: Express - server: Server - connection?: Connection - }>(resolve => { - const server = app.listen(config.port, () => { - console.log(`Frourio is running on http://localhost:${config.port}`) - resolve({ app, server, connection }) - }) - }) -} diff --git a/packages/frourio/server/api/$relay.ts b/packages/frourio/server/api/$relay.ts deleted file mode 100644 index 0a7eeff..0000000 --- a/packages/frourio/server/api/$relay.ts +++ /dev/null @@ -1,17 +0,0 @@ -/* eslint-disable */ -import { RequestHandler } from 'express' -import { ServerMethods } from 'frourio' -import { Methods } from './' - -type ControllerMethods = ServerMethods - -export const createMiddleware = < - T extends RequestHandler | [] | [RequestHandler, ...RequestHandler[]] ->(handler: T): T => handler - -export const createController = (methods: ControllerMethods) => methods - -export const createInjectableController = ( - cb: (deps: T) => ControllerMethods, - deps: T -) => ({ ...cb(deps), inject: (d: T) => cb(d) }) diff --git a/packages/frourio/server/api/@controller.ts b/packages/frourio/server/api/@controller.ts deleted file mode 100644 index 58fee96..0000000 --- a/packages/frourio/server/api/@controller.ts +++ /dev/null @@ -1,17 +0,0 @@ -import { createController, createMiddleware } from './$relay' - -export const middleware = createMiddleware((req, res, next) => { - console.log('Controller level middleware:', req.path) - next() -}) - -export default createController({ - get: async v => { - return await { status: 200, body: { id: +(v.query?.id || 0) } } - }, - post: v => ({ - // @ts-expect-error - status: 200, - body: { id: +v.query.id, port: v.body.port, fileName: v.body.file.originalname } - }) -}) diff --git a/packages/frourio/server/api/@middleware.ts b/packages/frourio/server/api/@middleware.ts deleted file mode 100644 index 7357476..0000000 --- a/packages/frourio/server/api/@middleware.ts +++ /dev/null @@ -1,6 +0,0 @@ -import { createMiddleware } from './$relay' - -export default createMiddleware((req, res, next) => { - console.log('Directory level middleware:', req.path) - next() -}) diff --git a/packages/frourio/server/api/multiForm/$relay.ts b/packages/frourio/server/api/multiForm/$relay.ts deleted file mode 100644 index 0a7eeff..0000000 --- a/packages/frourio/server/api/multiForm/$relay.ts +++ /dev/null @@ -1,17 +0,0 @@ -/* eslint-disable */ -import { RequestHandler } from 'express' -import { ServerMethods } from 'frourio' -import { Methods } from './' - -type ControllerMethods = ServerMethods - -export const createMiddleware = < - T extends RequestHandler | [] | [RequestHandler, ...RequestHandler[]] ->(handler: T): T => handler - -export const createController = (methods: ControllerMethods) => methods - -export const createInjectableController = ( - cb: (deps: T) => ControllerMethods, - deps: T -) => ({ ...cb(deps), inject: (d: T) => cb(d) }) diff --git a/packages/frourio/server/api/texts/$relay.ts b/packages/frourio/server/api/texts/$relay.ts deleted file mode 100644 index 0a7eeff..0000000 --- a/packages/frourio/server/api/texts/$relay.ts +++ /dev/null @@ -1,17 +0,0 @@ -/* eslint-disable */ -import { RequestHandler } from 'express' -import { ServerMethods } from 'frourio' -import { Methods } from './' - -type ControllerMethods = ServerMethods - -export const createMiddleware = < - T extends RequestHandler | [] | [RequestHandler, ...RequestHandler[]] ->(handler: T): T => handler - -export const createController = (methods: ControllerMethods) => methods - -export const createInjectableController = ( - cb: (deps: T) => ControllerMethods, - deps: T -) => ({ ...cb(deps), inject: (d: T) => cb(d) }) diff --git a/packages/frourio/server/api/texts/@controller.ts b/packages/frourio/server/api/texts/@controller.ts deleted file mode 100644 index 27dc37e..0000000 --- a/packages/frourio/server/api/texts/@controller.ts +++ /dev/null @@ -1,6 +0,0 @@ -import { createController } from './$relay' - -// @ts-expect-error -export default createController({ - get: ({ query }) => ({ status: 200, body: query.val }) -}) diff --git a/packages/frourio/server/api/texts/sample/$relay.ts b/packages/frourio/server/api/texts/sample/$relay.ts deleted file mode 100644 index 0a7eeff..0000000 --- a/packages/frourio/server/api/texts/sample/$relay.ts +++ /dev/null @@ -1,17 +0,0 @@ -/* eslint-disable */ -import { RequestHandler } from 'express' -import { ServerMethods } from 'frourio' -import { Methods } from './' - -type ControllerMethods = ServerMethods - -export const createMiddleware = < - T extends RequestHandler | [] | [RequestHandler, ...RequestHandler[]] ->(handler: T): T => handler - -export const createController = (methods: ControllerMethods) => methods - -export const createInjectableController = ( - cb: (deps: T) => ControllerMethods, - deps: T -) => ({ ...cb(deps), inject: (d: T) => cb(d) }) diff --git a/packages/frourio/server/api/users/$relay.ts b/packages/frourio/server/api/users/$relay.ts deleted file mode 100644 index ea0d2de..0000000 --- a/packages/frourio/server/api/users/$relay.ts +++ /dev/null @@ -1,20 +0,0 @@ -/* eslint-disable */ -import { RequestHandler } from 'express' -import { ServerMethods } from 'frourio' -import { User } from './@middleware' -import { Methods } from './' - -type ControllerMethods = ServerMethods - -export const createMiddleware = < - T extends RequestHandler | [] | [RequestHandler, ...RequestHandler[]] ->(handler: T): T => handler - -export const createController = (methods: ControllerMethods) => methods - -export const createInjectableController = ( - cb: (deps: T) => ControllerMethods, - deps: T -) => ({ ...cb(deps), inject: (d: T) => cb(d) }) diff --git a/packages/frourio/server/api/users/@controller.ts b/packages/frourio/server/api/users/@controller.ts deleted file mode 100644 index 80380ae..0000000 --- a/packages/frourio/server/api/users/@controller.ts +++ /dev/null @@ -1,15 +0,0 @@ -import { createController, createMiddleware } from './$relay' - -const middleware = createMiddleware([ - (req, res, next) => { - console.log('Controller level middleware:', req.path) - next() - } -]) - -export { middleware } - -export default createController({ - get: async () => ({ status: 200, body: [{ id: 1, name: 'aa' }] }), - post: () => ({ status: 204 }) -}) diff --git a/packages/frourio/server/api/users/@middleware.ts b/packages/frourio/server/api/users/@middleware.ts deleted file mode 100644 index 5986a66..0000000 --- a/packages/frourio/server/api/users/@middleware.ts +++ /dev/null @@ -1,13 +0,0 @@ -import { createMiddleware } from './$relay' - -export type User = { - id: number - name: string - role: 'admin' | 'user' -} - -export default createMiddleware((req, res, next) => { - console.log('Added user') - ;(req as any).user = { id: 1, name: 'user name', role: 'admin' } - next() -}) diff --git a/packages/frourio/server/api/users/_userId@number/$relay.ts b/packages/frourio/server/api/users/_userId@number/$relay.ts deleted file mode 100644 index 72d7a57..0000000 --- a/packages/frourio/server/api/users/_userId@number/$relay.ts +++ /dev/null @@ -1,23 +0,0 @@ -/* eslint-disable */ -import { RequestHandler } from 'express' -import { ServerMethods } from 'frourio' -import { User } from './../@middleware' -import { Methods } from './' - -type ControllerMethods = ServerMethods - -export const createMiddleware = < - T extends RequestHandler | [] | [RequestHandler, ...RequestHandler[]] ->(handler: T): T => handler - -export const createController = (methods: ControllerMethods) => methods - -export const createInjectableController = ( - cb: (deps: T) => ControllerMethods, - deps: T -) => ({ ...cb(deps), inject: (d: T) => cb(d) }) diff --git a/packages/frourio/server/api/users/_userId@number/@controller.ts b/packages/frourio/server/api/users/_userId@number/@controller.ts deleted file mode 100644 index 6472b95..0000000 --- a/packages/frourio/server/api/users/_userId@number/@controller.ts +++ /dev/null @@ -1,5 +0,0 @@ -import { createController } from './$relay' - -export default createController({ - get: ({ params }) => ({ status: 200, body: { id: params.userId, name: 'bbb' } }) -}) diff --git a/packages/frourio/server/api/users/_userId@number/index.ts b/packages/frourio/server/api/users/_userId@number/index.ts deleted file mode 100644 index e686e44..0000000 --- a/packages/frourio/server/api/users/_userId@number/index.ts +++ /dev/null @@ -1,7 +0,0 @@ -import { ValidUserInfo } from '../../../types' - -export type Methods = { - get: { - resBody: ValidUserInfo - } -} diff --git a/packages/frourio/server/api/users/index.ts b/packages/frourio/server/api/users/index.ts deleted file mode 100644 index d54407a..0000000 --- a/packages/frourio/server/api/users/index.ts +++ /dev/null @@ -1,11 +0,0 @@ -import { ValidUserInfo } from '../../types' - -export type Methods = { - get: { - resBody: ValidUserInfo[] - } - - post: { - reqBody: ValidUserInfo - } -} diff --git a/packages/frourio/server/entity/Task.ts b/packages/frourio/server/entity/Task.ts deleted file mode 100644 index d165155..0000000 --- a/packages/frourio/server/entity/Task.ts +++ /dev/null @@ -1,13 +0,0 @@ -import { Entity, PrimaryColumn, Column } from 'typeorm' - -@Entity() -export class Task { - @PrimaryColumn() - id: number - - @Column({ length: 100 }) - label: string - - @Column({ default: false }) - done: boolean -} diff --git a/packages/frourio/server/index.ts b/packages/frourio/server/index.ts deleted file mode 100644 index 12da900..0000000 --- a/packages/frourio/server/index.ts +++ /dev/null @@ -1,7 +0,0 @@ -import { run } from './$app' - -run({ - port: 10000, - basePath: '/api', - cors: true -}) diff --git a/packages/frourio/server/public/sample.json b/packages/frourio/server/public/sample.json deleted file mode 100644 index 09c61a0..0000000 --- a/packages/frourio/server/public/sample.json +++ /dev/null @@ -1 +0,0 @@ -{ "sample": true } diff --git a/packages/frourio/server/subscriber/TaskSubscriber.ts b/packages/frourio/server/subscriber/TaskSubscriber.ts deleted file mode 100644 index c03285b..0000000 --- a/packages/frourio/server/subscriber/TaskSubscriber.ts +++ /dev/null @@ -1,13 +0,0 @@ -import { EntitySubscriberInterface, EventSubscriber, InsertEvent } from 'typeorm' -import { Task } from '../entity/Task' - -@EventSubscriber() -export class TaskSubscriber implements EntitySubscriberInterface { - listenTo() { - return Task - } - - afterInsert(event: InsertEvent) { - console.log(event) - } -} diff --git a/packages/frourio/servers/all/$app.ts b/packages/frourio/servers/all/$app.ts new file mode 100644 index 0000000..95ff0bd --- /dev/null +++ b/packages/frourio/servers/all/$app.ts @@ -0,0 +1,347 @@ +/* eslint-disable */ +import path from 'path' +import { + LowerHttpMethod, + AspidaMethods, + HttpMethod, + HttpStatusOk, + AspidaMethodParams +} from 'aspida' +import { Deps } from 'velona' +import express, { Express, RequestHandler, Request } from 'express' +import multer, { Options } from 'multer' +import { validateOrReject } from 'class-validator' + +type Hooks = { + onRequest?: RequestHandler | RequestHandler[] + preParsing?: RequestHandler | RequestHandler[] + preValidation?: RequestHandler | RequestHandler[] + preHandler?: RequestHandler | RequestHandler[] + onSend?: RequestHandler | RequestHandler[] +} + +export function defineHooks(hooks: () => T): T +export function defineHooks>(deps: U, cb: (deps: Deps) => T): T & { inject: (d: Deps) => T } +export function defineHooks>(hooks: () => T | U, cb?: (deps: Deps) => T) { + return typeof hooks === 'function' ? hooks() : { ...cb!(hooks), inject: (d: Deps) => cb!(d) } +} + +import * as Validators from './validators' +import controller0, { hooks as ctrlHooks0 } from './api/controller' +import controller1 from './api/500/controller' +import controller2 from './api/empty/noEmpty/controller' +import controller3 from './api/multiForm/controller' +import controller4 from './api/texts/controller' +import controller5 from './api/texts/sample/controller' +import controller6, { hooks as ctrlHooks1 } from './api/users/controller' +import controller7 from './api/users/_userId@number/controller' +import hooks0 from './api/hooks' +import hooks1 from './api/users/hooks' + +export type FrourioOptions = { + basePath?: string + multer?: Options +} + +export type MulterFile = Express.Multer.File + +type HttpStatusNoOk = + | 301 + | 302 + | 400 + | 401 + | 402 + | 403 + | 404 + | 405 + | 406 + | 409 + | 500 + | 501 + | 502 + | 503 + | 504 + | 505 + +type PartiallyPartial = Omit & Partial> + +type BaseResponse = { + status: V extends number ? V : HttpStatusOk + body: T + headers: U +} + +type ServerResponse = + | (K['resBody'] extends {} | null + ? K['resHeaders'] extends {} + ? BaseResponse + : PartiallyPartial< + BaseResponse< + K['resBody'], + K['resHeaders'] extends {} | undefined ? K['resHeaders'] : undefined, + K['status'] + >, + 'headers' + > + : K['resHeaders'] extends {} + ? PartiallyPartial< + BaseResponse< + K['resBody'] extends {} | null | undefined ? K['resBody'] : undefined, + K['resHeaders'], + K['status'] + >, + 'body' + > + : PartiallyPartial< + BaseResponse< + K['resBody'] extends {} | null | undefined ? K['resBody'] : undefined, + K['resHeaders'] extends {} | undefined ? K['resHeaders'] : undefined, + K['status'] + >, + 'body' | 'headers' + >) + | PartiallyPartial, 'body' | 'headers'> + +type ServerValues = { + params?: Record + user?: any +} + +type BlobToFile = T['reqFormat'] extends FormData + ? { + [P in keyof T['reqBody']]: Required[P] extends Blob + ? MulterFile + : Required[P] extends Blob[] + ? MulterFile[] + : T['reqBody'][P] + } + : T['reqBody'] + +type RequestParams = { + path: string + method: HttpMethod + query: T['query'] + body: BlobToFile + headers: T['reqHeaders'] +} + +export type ServerMethods = { + [K in keyof T]: ( + req: RequestParams & U + ) => ServerResponse | Promise> +} + +const parseNumberTypeQueryParams = (numberTypeParams: [string, boolean, boolean][]): RequestHandler => ({ query }, res, next) => { + for (const [key, isOptional, isArray] of numberTypeParams) { + const param = query[key] + + if (isArray) { + if (!isOptional && param === undefined) { + query[key] = [] + } else if (!isOptional || param !== undefined) { + if (!Array.isArray(param)) { + res.sendStatus(400) + return + } + + const vals = (param as string[]).map(Number) + + if (vals.some(isNaN)) { + res.sendStatus(400) + return + } + + query[key] = vals as any + } + } else if (!isOptional || param !== undefined) { + const val = Number(param) + + if (isNaN(val)) { + res.sendStatus(400) + return + } + + query[key] = val as any + } + } + + next() +} + +const parseJSONBoby: RequestHandler = (req, res, next) => { + express.json()(req, res, err => { + if (err) return res.sendStatus(400) + + next() + }) +} + +const createTypedParamsHandler = (numberTypeParams: string[]): RequestHandler => ( + req, + res, + next +) => { + const typedParams: Record = { ...req.params } + + for (const key of numberTypeParams) { + const val = Number(typedParams[key]) + if (isNaN(val)) { + res.sendStatus(400) + return + } + + typedParams[key] = val + } + + ;(req as any).typedParams = typedParams + next() +} + +const createValidateHandler = (validators: (req: Request) => (Promise | null)[]): RequestHandler => + (req, res, next) => Promise.all(validators(req)).then(() => next()).catch(() => res.sendStatus(400)) + +const methodsToHandler = ( + methodCallback: ServerMethods[LowerHttpMethod] +): RequestHandler => async (req, res) => { + try { + const result = methodCallback({ + query: req.query, + path: req.path, + method: req.method as HttpMethod, + body: req.body, + headers: req.headers, + params: (req as any).typedParams, + user: (req as any).user + }) + + const { status, body, headers } = result instanceof Promise ? await result : result + + for (const key in headers) { + res.setHeader(key, headers[key]) + } + + res.status(status).send(body) + } catch (e) { + res.sendStatus(500) + } +} + +const formatMulterData = (arrayTypeKeys: [string, boolean][]): RequestHandler => ({ body, files }, _res, next) => { + for (const [key] of arrayTypeKeys) { + if (body[key] === undefined) body[key] = [] + else if (!Array.isArray(body[key])) { + body[key] = [body[key]] + } + } + + for (const file of files as MulterFile[]) { + if (Array.isArray(body[file.fieldname])) { + body[file.fieldname].push(file) + } else { + body[file.fieldname] = file + } + } + + for (const [key, isOptional] of arrayTypeKeys) { + if (!body[key].length && isOptional) delete body[key] + } + + next() +} + +export default (app: Express, options: FrourioOptions = {}) => { + const basePath = options.basePath ?? '' + const uploader = multer( + options.multer ?? { dest: path.join(__dirname, '.upload'), limits: { fileSize: 1024 ** 3 } } + ).any() + + app.get(`${basePath}/`, [ + ...hooks0.onRequest, + ctrlHooks0.onRequest, + parseNumberTypeQueryParams([['requiredNum', false, false], ['optionalNum', true, false], ['optionalNumArr', true, true], ['emptyNum', true, false], ['requiredNumArr', false, true]]), + createValidateHandler(req => [ + Object.keys(req.query).length ? validateOrReject(Object.assign(new Validators.Query(), req.query)) : null + ]), + methodsToHandler(controller0.get) + ]) + + app.post(`${basePath}/`, [ + ...hooks0.onRequest, + ctrlHooks0.onRequest, + hooks0.preParsing, + parseNumberTypeQueryParams([['requiredNum', false, false], ['optionalNum', true, false], ['optionalNumArr', true, true], ['emptyNum', true, false], ['requiredNumArr', false, true]]), + uploader, + formatMulterData([]), + createValidateHandler(req => [ + validateOrReject(Object.assign(new Validators.Query(), req.query)), + validateOrReject(Object.assign(new Validators.Body(), req.body)) + ]), + methodsToHandler(controller0.post) + ]) + + app.get(`${basePath}/500`, [ + ...hooks0.onRequest, + methodsToHandler(controller1.get) + ]) + + app.get(`${basePath}/empty/noEmpty`, [ + ...hooks0.onRequest, + methodsToHandler(controller2.get) + ]) + + app.post(`${basePath}/multiForm`, [ + ...hooks0.onRequest, + hooks0.preParsing, + uploader, + formatMulterData([['requiredArr', false], ['optionalArr', true], ['empty', true], ['vals', false], ['files', false]]), + createValidateHandler(req => [ + validateOrReject(Object.assign(new Validators.MultiForm(), req.body)) + ]), + methodsToHandler(controller3.post) + ]) + + app.get(`${basePath}/texts`, [ + ...hooks0.onRequest, + methodsToHandler(controller4.get) + ]) + + app.put(`${basePath}/texts`, [ + ...hooks0.onRequest, + methodsToHandler(controller4.put) + ]) + + app.put(`${basePath}/texts/sample`, [ + ...hooks0.onRequest, + hooks0.preParsing, + parseJSONBoby, + methodsToHandler(controller5.put) + ]) + + app.get(`${basePath}/users`, [ + ...hooks0.onRequest, + hooks1.onRequest, + ...ctrlHooks1.preHandler, + methodsToHandler(controller6.get) + ]) + + app.post(`${basePath}/users`, [ + ...hooks0.onRequest, + hooks1.onRequest, + hooks0.preParsing, + parseJSONBoby, + createValidateHandler(req => [ + validateOrReject(Object.assign(new Validators.UserInfo(), req.body)) + ]), + ...ctrlHooks1.preHandler, + methodsToHandler(controller6.post) + ]) + + app.get(`${basePath}/users/:userId`, [ + ...hooks0.onRequest, + hooks1.onRequest, + createTypedParamsHandler(['userId']), + methodsToHandler(controller7.get) + ]) + + return app +} diff --git a/packages/frourio/servers/all/api/$api.ts b/packages/frourio/servers/all/api/$api.ts new file mode 100644 index 0000000..b3d59b5 --- /dev/null +++ b/packages/frourio/servers/all/api/$api.ts @@ -0,0 +1,103 @@ +/* eslint-disable */ +import { AspidaClient, BasicHeaders, dataToURLString } from 'aspida' +import { Methods as Methods0 } from '.' +import { Methods as Methods1 } from './500' +import { Methods as Methods2 } from './empty/noEmpty' +import { Methods as Methods3 } from './multiForm' +import { Methods as Methods4 } from './texts' +import { Methods as Methods5 } from './texts/sample' +import { Methods as Methods6 } from './users' +import { Methods as Methods7 } from './users/_userId@number' + +const api = ({ baseURL, fetch }: AspidaClient) => { + const prefix = (baseURL === undefined ? '' : baseURL).replace(/\/$/, '') + const PATH0 = '/500' + const PATH1 = '/empty/noEmpty' + const PATH2 = '/multiForm' + const PATH3 = '/texts' + const PATH4 = '/texts/sample' + const PATH5 = '/users' + const GET = 'GET' + const POST = 'POST' + const PUT = 'PUT' + + return { + $500: { + get: (option?: { config?: T }) => + fetch(prefix, PATH0, GET, option).text(), + $get: (option?: { config?: T }) => + fetch(prefix, PATH0, GET, option).text().then(r => r.body), + $path: () => `${prefix}${PATH0}` + }, + empty: { + noEmpty: { + get: (option?: { config?: T }) => + fetch(prefix, PATH1, GET, option).text(), + $get: (option?: { config?: T }) => + fetch(prefix, PATH1, GET, option).text().then(r => r.body), + $path: () => `${prefix}${PATH1}` + } + }, + multiForm: { + post: (option: { body: Methods3['post']['reqBody'], config?: T }) => + fetch(prefix, PATH2, POST, option, 'FormData').json(), + $post: (option: { body: Methods3['post']['reqBody'], config?: T }) => + fetch(prefix, PATH2, POST, option, 'FormData').json().then(r => r.body), + $path: () => `${prefix}${PATH2}` + }, + texts: { + sample: { + put: (option: { body: Methods5['put']['reqBody'], config?: T }) => + fetch(prefix, PATH4, PUT, option).json(), + $put: (option: { body: Methods5['put']['reqBody'], config?: T }) => + fetch(prefix, PATH4, PUT, option).json().then(r => r.body), + $path: () => `${prefix}${PATH4}` + }, + get: (option: { query: Methods4['get']['query'], config?: T }) => + fetch(prefix, PATH3, GET, option).text(), + $get: (option: { query: Methods4['get']['query'], config?: T }) => + fetch(prefix, PATH3, GET, option).text().then(r => r.body), + put: (option?: { config?: T }) => + fetch(prefix, PATH3, PUT, option).send(), + $put: (option?: { config?: T }) => + fetch(prefix, PATH3, PUT, option).send().then(r => r.body), + $path: (option?: { method?: 'get'; query: Methods4['get']['query'] }) => + `${prefix}${PATH3}${option && option.query ? `?${dataToURLString(option.query)}` : ''}` + }, + users: { + _userId: (val0: number) => { + const prefix0 = `${PATH5}/${val0}` + + return { + get: (option?: { config?: T }) => + fetch(prefix, prefix0, GET, option).json(), + $get: (option?: { config?: T }) => + fetch(prefix, prefix0, GET, option).json().then(r => r.body), + $path: () => `${prefix}${prefix0}` + } + }, + get: (option?: { config?: T }) => + fetch(prefix, PATH5, GET, option).json(), + $get: (option?: { config?: T }) => + fetch(prefix, PATH5, GET, option).json().then(r => r.body), + post: (option: { body: Methods6['post']['reqBody'], config?: T }) => + fetch(prefix, PATH5, POST, option).send(), + $post: (option: { body: Methods6['post']['reqBody'], config?: T }) => + fetch(prefix, PATH5, POST, option).send().then(r => r.body), + $path: () => `${prefix}${PATH5}` + }, + get: (option?: { query?: Methods0['get']['query'], config?: T }) => + fetch(prefix, '', GET, option).json(), + $get: (option?: { query?: Methods0['get']['query'], config?: T }) => + fetch(prefix, '', GET, option).json().then(r => r.body), + post: (option: { body: Methods0['post']['reqBody'], query: Methods0['post']['query'], config?: T }) => + fetch(prefix, '', POST, option, 'FormData').json(), + $post: (option: { body: Methods0['post']['reqBody'], query: Methods0['post']['query'], config?: T }) => + fetch(prefix, '', POST, option, 'FormData').json().then(r => r.body), + $path: (option?: { method?: 'get'; query: Methods0['get']['query'] } | { method: 'post'; query: Methods0['post']['query'] }) => + `${prefix}${''}${option && option.query ? `?${dataToURLString(option.query)}` : ''}` + } +} + +export type ApiInstance = ReturnType +export default api diff --git a/packages/frourio/servers/all/api/$relay.ts b/packages/frourio/servers/all/api/$relay.ts new file mode 100644 index 0000000..f064967 --- /dev/null +++ b/packages/frourio/servers/all/api/$relay.ts @@ -0,0 +1,14 @@ +/* eslint-disable */ +import { Deps } from 'velona' +import { ServerMethods, defineHooks } from '../$app' +import { Methods } from './' + +type ControllerMethods = ServerMethods + +export { defineHooks } + +export function defineController(methods: () => ControllerMethods): ControllerMethods +export function defineController>(deps: T, cb: (deps: Deps) => ControllerMethods): ControllerMethods & { inject: (d: Deps) => ControllerMethods } +export function defineController>(methods: () => ControllerMethods | T, cb?: (deps: Deps) => ControllerMethods) { + return typeof methods === 'function' ? methods() : { ...cb!(methods), inject: (d: Deps) => cb!(d) } +} diff --git a/packages/frourio/servers/all/api/500/$relay.ts b/packages/frourio/servers/all/api/500/$relay.ts new file mode 100644 index 0000000..8b7c89b --- /dev/null +++ b/packages/frourio/servers/all/api/500/$relay.ts @@ -0,0 +1,14 @@ +/* eslint-disable */ +import { Deps } from 'velona' +import { ServerMethods, defineHooks } from '../../$app' +import { Methods } from './' + +type ControllerMethods = ServerMethods + +export { defineHooks } + +export function defineController(methods: () => ControllerMethods): ControllerMethods +export function defineController>(deps: T, cb: (deps: Deps) => ControllerMethods): ControllerMethods & { inject: (d: Deps) => ControllerMethods } +export function defineController>(methods: () => ControllerMethods | T, cb?: (deps: Deps) => ControllerMethods) { + return typeof methods === 'function' ? methods() : { ...cb!(methods), inject: (d: Deps) => cb!(d) } +} diff --git a/packages/frourio/servers/all/api/500/controller.ts b/packages/frourio/servers/all/api/500/controller.ts new file mode 100644 index 0000000..a583290 --- /dev/null +++ b/packages/frourio/servers/all/api/500/controller.ts @@ -0,0 +1,7 @@ +import { defineController } from './$relay' + +export default defineController(() => ({ + get: () => { + throw new Error('500 error test') + } +})) diff --git a/packages/frourio/servers/all/api/500/index.ts b/packages/frourio/servers/all/api/500/index.ts new file mode 100644 index 0000000..0556ee1 --- /dev/null +++ b/packages/frourio/servers/all/api/500/index.ts @@ -0,0 +1,5 @@ +export type Methods = { + get: { + resBody: string + } +} diff --git a/packages/frourio/servers/all/api/controller.ts b/packages/frourio/servers/all/api/controller.ts new file mode 100644 index 0000000..869a03f --- /dev/null +++ b/packages/frourio/servers/all/api/controller.ts @@ -0,0 +1,22 @@ +import { defineController, defineHooks } from '~/$relay' +import { depend } from 'velona' + +const hooks = defineHooks({ print: (...args: string[]) => console.log(...args) }, ({ print }) => ({ + onRequest: depend({}, (deps, req, res, next) => { + print('Controller level onRequest hook:', req.path) + next() + }) +})) + +export default defineController(() => ({ + get: async v => { + return await { status: 200, body: { id: +(v.query?.id || 0) } } + }, + post: v => ({ + // @ts-expect-error + status: 200, + body: { id: +v.query.id, port: v.body.port, fileName: v.body.file.originalname } + }) +})) + +export { hooks } diff --git a/packages/frourio/servers/all/api/empty/$relay.ts b/packages/frourio/servers/all/api/empty/$relay.ts new file mode 100644 index 0000000..8b7c89b --- /dev/null +++ b/packages/frourio/servers/all/api/empty/$relay.ts @@ -0,0 +1,14 @@ +/* eslint-disable */ +import { Deps } from 'velona' +import { ServerMethods, defineHooks } from '../../$app' +import { Methods } from './' + +type ControllerMethods = ServerMethods + +export { defineHooks } + +export function defineController(methods: () => ControllerMethods): ControllerMethods +export function defineController>(deps: T, cb: (deps: Deps) => ControllerMethods): ControllerMethods & { inject: (d: Deps) => ControllerMethods } +export function defineController>(methods: () => ControllerMethods | T, cb?: (deps: Deps) => ControllerMethods) { + return typeof methods === 'function' ? methods() : { ...cb!(methods), inject: (d: Deps) => cb!(d) } +} diff --git a/packages/frourio/servers/all/api/empty/controller.ts b/packages/frourio/servers/all/api/empty/controller.ts new file mode 100644 index 0000000..edbfd03 --- /dev/null +++ b/packages/frourio/servers/all/api/empty/controller.ts @@ -0,0 +1,3 @@ +import { defineController } from './$relay' + +export default defineController(() => ({})) diff --git a/packages/frourio/servers/all/api/empty/index.ts b/packages/frourio/servers/all/api/empty/index.ts new file mode 100644 index 0000000..4dcad57 --- /dev/null +++ b/packages/frourio/servers/all/api/empty/index.ts @@ -0,0 +1 @@ +export type Methods = {} diff --git a/packages/frourio/servers/all/api/empty/noEmpty/$relay.ts b/packages/frourio/servers/all/api/empty/noEmpty/$relay.ts new file mode 100644 index 0000000..26ca223 --- /dev/null +++ b/packages/frourio/servers/all/api/empty/noEmpty/$relay.ts @@ -0,0 +1,14 @@ +/* eslint-disable */ +import { Deps } from 'velona' +import { ServerMethods, defineHooks } from '../../../$app' +import { Methods } from './' + +type ControllerMethods = ServerMethods + +export { defineHooks } + +export function defineController(methods: () => ControllerMethods): ControllerMethods +export function defineController>(deps: T, cb: (deps: Deps) => ControllerMethods): ControllerMethods & { inject: (d: Deps) => ControllerMethods } +export function defineController>(methods: () => ControllerMethods | T, cb?: (deps: Deps) => ControllerMethods) { + return typeof methods === 'function' ? methods() : { ...cb!(methods), inject: (d: Deps) => cb!(d) } +} diff --git a/packages/frourio/servers/all/api/empty/noEmpty/controller.ts b/packages/frourio/servers/all/api/empty/noEmpty/controller.ts new file mode 100644 index 0000000..eb73909 --- /dev/null +++ b/packages/frourio/servers/all/api/empty/noEmpty/controller.ts @@ -0,0 +1,5 @@ +import { defineController } from './$relay' + +export default defineController(() => ({ + get: () => ({ status: 200, body: 'sample' }) +})) diff --git a/packages/frourio/servers/all/api/empty/noEmpty/index.ts b/packages/frourio/servers/all/api/empty/noEmpty/index.ts new file mode 100644 index 0000000..0556ee1 --- /dev/null +++ b/packages/frourio/servers/all/api/empty/noEmpty/index.ts @@ -0,0 +1,5 @@ +export type Methods = { + get: { + resBody: string + } +} diff --git a/packages/frourio/servers/all/api/hooks.ts b/packages/frourio/servers/all/api/hooks.ts new file mode 100644 index 0000000..cc590f1 --- /dev/null +++ b/packages/frourio/servers/all/api/hooks.ts @@ -0,0 +1,14 @@ +import { defineHooks } from './$relay' + +export default defineHooks(() => ({ + onRequest: [ + (req, res, next) => { + console.log('Directory level middleware:', req.path) + next() + } + ], + preParsing: (req, res, next) => { + console.log('Directory level middleware:', req.path) + next() + } +})) diff --git a/packages/frourio/server/api/index.ts b/packages/frourio/servers/all/api/index.ts similarity index 65% rename from packages/frourio/server/api/index.ts rename to packages/frourio/servers/all/api/index.ts index db0549a..a9d6441 100644 --- a/packages/frourio/server/api/index.ts +++ b/packages/frourio/servers/all/api/index.ts @@ -1,16 +1,16 @@ -import { ValidQuery, ValidBody } from '../types' +import { Query, Body } from 'validators' export type Methods = { get: { - query?: ValidQuery + query?: Query status: 200 resBody?: { id: number } } post: { - query: ValidQuery + query: Query reqFormat: FormData - reqBody: ValidBody + reqBody: Body status: 201 resBody: { id: number diff --git a/packages/frourio/servers/all/api/multiForm/$relay.ts b/packages/frourio/servers/all/api/multiForm/$relay.ts new file mode 100644 index 0000000..8b7c89b --- /dev/null +++ b/packages/frourio/servers/all/api/multiForm/$relay.ts @@ -0,0 +1,14 @@ +/* eslint-disable */ +import { Deps } from 'velona' +import { ServerMethods, defineHooks } from '../../$app' +import { Methods } from './' + +type ControllerMethods = ServerMethods + +export { defineHooks } + +export function defineController(methods: () => ControllerMethods): ControllerMethods +export function defineController>(deps: T, cb: (deps: Deps) => ControllerMethods): ControllerMethods & { inject: (d: Deps) => ControllerMethods } +export function defineController>(methods: () => ControllerMethods | T, cb?: (deps: Deps) => ControllerMethods) { + return typeof methods === 'function' ? methods() : { ...cb!(methods), inject: (d: Deps) => cb!(d) } +} diff --git a/packages/frourio/server/api/multiForm/@controller.ts b/packages/frourio/servers/all/api/multiForm/controller.ts similarity index 73% rename from packages/frourio/server/api/multiForm/@controller.ts rename to packages/frourio/servers/all/api/multiForm/controller.ts index 8c46a3f..dd166bc 100644 --- a/packages/frourio/server/api/multiForm/@controller.ts +++ b/packages/frourio/servers/all/api/multiForm/controller.ts @@ -1,7 +1,7 @@ -import { createController } from './$relay' +import { defineController } from './$relay' import { Methods } from './' -export default createController({ +export default defineController(() => ({ post: ({ body }) => ({ status: 201, body: Object.entries(body).reduce( @@ -9,4 +9,4 @@ export default createController({ {} as Methods['post']['resBody'] ) }) -}) +})) diff --git a/packages/frourio/server/api/multiForm/index.ts b/packages/frourio/servers/all/api/multiForm/index.ts similarity index 71% rename from packages/frourio/server/api/multiForm/index.ts rename to packages/frourio/servers/all/api/multiForm/index.ts index 2e8e234..f307b9c 100644 --- a/packages/frourio/server/api/multiForm/index.ts +++ b/packages/frourio/servers/all/api/multiForm/index.ts @@ -1,9 +1,9 @@ -import { ValidMultiForm } from '../../types' +import { MultiForm } from 'validators' export type Methods = { post: { reqFormat: FormData - reqBody: ValidMultiForm + reqBody: MultiForm resBody: { empty: number name: number diff --git a/packages/frourio/servers/all/api/texts/$relay.ts b/packages/frourio/servers/all/api/texts/$relay.ts new file mode 100644 index 0000000..8b7c89b --- /dev/null +++ b/packages/frourio/servers/all/api/texts/$relay.ts @@ -0,0 +1,14 @@ +/* eslint-disable */ +import { Deps } from 'velona' +import { ServerMethods, defineHooks } from '../../$app' +import { Methods } from './' + +type ControllerMethods = ServerMethods + +export { defineHooks } + +export function defineController(methods: () => ControllerMethods): ControllerMethods +export function defineController>(deps: T, cb: (deps: Deps) => ControllerMethods): ControllerMethods & { inject: (d: Deps) => ControllerMethods } +export function defineController>(methods: () => ControllerMethods | T, cb?: (deps: Deps) => ControllerMethods) { + return typeof methods === 'function' ? methods() : { ...cb!(methods), inject: (d: Deps) => cb!(d) } +} diff --git a/packages/frourio/servers/all/api/texts/controller.ts b/packages/frourio/servers/all/api/texts/controller.ts new file mode 100644 index 0000000..edca134 --- /dev/null +++ b/packages/frourio/servers/all/api/texts/controller.ts @@ -0,0 +1,6 @@ +import { defineController } from './$relay' + +// @ts-expect-error +export default defineController(() => ({ + get: ({ query }) => ({ status: 200, body: query.val }) +})) diff --git a/packages/frourio/server/api/texts/index.ts b/packages/frourio/servers/all/api/texts/index.ts similarity index 100% rename from packages/frourio/server/api/texts/index.ts rename to packages/frourio/servers/all/api/texts/index.ts diff --git a/packages/frourio/servers/all/api/texts/sample/$relay.ts b/packages/frourio/servers/all/api/texts/sample/$relay.ts new file mode 100644 index 0000000..26ca223 --- /dev/null +++ b/packages/frourio/servers/all/api/texts/sample/$relay.ts @@ -0,0 +1,14 @@ +/* eslint-disable */ +import { Deps } from 'velona' +import { ServerMethods, defineHooks } from '../../../$app' +import { Methods } from './' + +type ControllerMethods = ServerMethods + +export { defineHooks } + +export function defineController(methods: () => ControllerMethods): ControllerMethods +export function defineController>(deps: T, cb: (deps: Deps) => ControllerMethods): ControllerMethods & { inject: (d: Deps) => ControllerMethods } +export function defineController>(methods: () => ControllerMethods | T, cb?: (deps: Deps) => ControllerMethods) { + return typeof methods === 'function' ? methods() : { ...cb!(methods), inject: (d: Deps) => cb!(d) } +} diff --git a/packages/frourio/server/api/texts/sample/@controller.ts b/packages/frourio/servers/all/api/texts/sample/controller.ts similarity index 58% rename from packages/frourio/server/api/texts/sample/@controller.ts rename to packages/frourio/servers/all/api/texts/sample/controller.ts index 69a4b45..8aa3058 100644 --- a/packages/frourio/server/api/texts/sample/@controller.ts +++ b/packages/frourio/servers/all/api/texts/sample/controller.ts @@ -1,7 +1,7 @@ -import { createController } from './$relay' +import { defineController } from './$relay' -export default createController({ +export default defineController(() => ({ // @ts-expect-error get: ({ query }) => ({ status: 200, body: query.val }), put: ({ body }) => ({ status: 200, body }) -}) +})) diff --git a/packages/frourio/server/api/texts/sample/index.ts b/packages/frourio/servers/all/api/texts/sample/index.ts similarity index 100% rename from packages/frourio/server/api/texts/sample/index.ts rename to packages/frourio/servers/all/api/texts/sample/index.ts diff --git a/packages/frourio/servers/all/api/users/$relay.ts b/packages/frourio/servers/all/api/users/$relay.ts new file mode 100644 index 0000000..2f2292e --- /dev/null +++ b/packages/frourio/servers/all/api/users/$relay.ts @@ -0,0 +1,17 @@ +/* eslint-disable */ +import { Deps } from 'velona' +import { ServerMethods, defineHooks } from '../../$app' +import { User } from './hooks' +import { Methods } from './' + +type ControllerMethods = ServerMethods + +export { defineHooks } + +export function defineController(methods: () => ControllerMethods): ControllerMethods +export function defineController>(deps: T, cb: (deps: Deps) => ControllerMethods): ControllerMethods & { inject: (d: Deps) => ControllerMethods } +export function defineController>(methods: () => ControllerMethods | T, cb?: (deps: Deps) => ControllerMethods) { + return typeof methods === 'function' ? methods() : { ...cb!(methods), inject: (d: Deps) => cb!(d) } +} diff --git a/packages/frourio/servers/all/api/users/_userId@number/$relay.ts b/packages/frourio/servers/all/api/users/_userId@number/$relay.ts new file mode 100644 index 0000000..b3fd1d5 --- /dev/null +++ b/packages/frourio/servers/all/api/users/_userId@number/$relay.ts @@ -0,0 +1,20 @@ +/* eslint-disable */ +import { Deps } from 'velona' +import { ServerMethods, defineHooks } from '../../../$app' +import { User } from './../hooks' +import { Methods } from './' + +type ControllerMethods = ServerMethods + +export { defineHooks } + +export function defineController(methods: () => ControllerMethods): ControllerMethods +export function defineController>(deps: T, cb: (deps: Deps) => ControllerMethods): ControllerMethods & { inject: (d: Deps) => ControllerMethods } +export function defineController>(methods: () => ControllerMethods | T, cb?: (deps: Deps) => ControllerMethods) { + return typeof methods === 'function' ? methods() : { ...cb!(methods), inject: (d: Deps) => cb!(d) } +} diff --git a/packages/frourio/servers/all/api/users/_userId@number/controller.ts b/packages/frourio/servers/all/api/users/_userId@number/controller.ts new file mode 100644 index 0000000..047e709 --- /dev/null +++ b/packages/frourio/servers/all/api/users/_userId@number/controller.ts @@ -0,0 +1,5 @@ +import { defineController } from './$relay' + +export default defineController(() => ({ + get: ({ params }) => ({ status: 200, body: { id: params.userId, name: 'bbb' } }) +})) diff --git a/packages/frourio/servers/all/api/users/_userId@number/index.ts b/packages/frourio/servers/all/api/users/_userId@number/index.ts new file mode 100644 index 0000000..6cebe6d --- /dev/null +++ b/packages/frourio/servers/all/api/users/_userId@number/index.ts @@ -0,0 +1,7 @@ +import { UserInfo } from 'validators' + +export type Methods = { + get: { + resBody: UserInfo + } +} diff --git a/packages/frourio/servers/all/api/users/controller.ts b/packages/frourio/servers/all/api/users/controller.ts new file mode 100644 index 0000000..7c9ed22 --- /dev/null +++ b/packages/frourio/servers/all/api/users/controller.ts @@ -0,0 +1,17 @@ +import { defineController, defineHooks } from './$relay' + +const hooks = defineHooks(() => ({ + preHandler: [ + (req, res, next) => { + console.log('Controller level preHandler hook:', req.path) + next() + } + ] +})) + +export { hooks } + +export default defineController(() => ({ + get: async () => ({ status: 200, body: [{ id: 1, name: 'aa' }] }), + post: () => ({ status: 204 }) +})) diff --git a/packages/frourio/servers/all/api/users/hooks.ts b/packages/frourio/servers/all/api/users/hooks.ts new file mode 100644 index 0000000..036c246 --- /dev/null +++ b/packages/frourio/servers/all/api/users/hooks.ts @@ -0,0 +1,15 @@ +import { defineHooks } from './$relay' + +export type User = { + id: number + name: string + role: 'admin' | 'user' +} + +export default defineHooks(() => ({ + onRequest: (req, res, next) => { + console.log('Added user') + ;(req as any).user = { id: 1, name: 'user name', role: 'admin' } + next() + } +})) diff --git a/packages/frourio/servers/all/api/users/index.ts b/packages/frourio/servers/all/api/users/index.ts new file mode 100644 index 0000000..bc9fdab --- /dev/null +++ b/packages/frourio/servers/all/api/users/index.ts @@ -0,0 +1,11 @@ +import { UserInfo } from 'validators' + +export type Methods = { + get: { + resBody: UserInfo[] + } + + post: { + reqBody: UserInfo + } +} diff --git a/packages/frourio/servers/all/tsconfig.json b/packages/frourio/servers/all/tsconfig.json new file mode 100644 index 0000000..991c48a --- /dev/null +++ b/packages/frourio/servers/all/tsconfig.json @@ -0,0 +1,10 @@ +{ + "extends": "../../../../tsconfig.json", + "compilerOptions": { + "baseUrl": ".", + "paths": { + "~/*": ["api/*"], + "validators": ["validators"] + } + } +} diff --git a/packages/frourio/servers/all/validators/index.ts b/packages/frourio/servers/all/validators/index.ts new file mode 100644 index 0000000..5966e93 --- /dev/null +++ b/packages/frourio/servers/all/validators/index.ts @@ -0,0 +1,65 @@ +import { + IsNumberString, + IsBooleanString, + IsPort, + IsInt, + MaxLength, + IsString, + Allow, + IsOptional, + ArrayNotEmpty +} from 'class-validator' + +export class Query { + requiredNum: number + optionalNum?: number + optionalNumArr?: Array + + @IsOptional() + emptyNum?: number + + @IsInt({ each: true }) + requiredNumArr: number[] + + @IsNumberString() + id: string + + @IsBooleanString() + disable: string +} + +export class Body { + @IsPort() + port: string + + file: File +} + +export class UserInfo { + @IsInt() + id: number + + @MaxLength(20) + name: string +} + +export class MultiForm { + requiredArr: string[] + optionalArr?: string[] + + @IsOptional() + @IsInt({ each: true }) + empty?: number[] + + @IsString() + name: string + + @Allow() + icon: Blob + + @IsString({ each: true }) + vals: string[] + + @ArrayNotEmpty() + files: Blob[] +} diff --git a/packages/frourio/servers/aspida.config.js b/packages/frourio/servers/aspida.config.js new file mode 100644 index 0000000..a2f2c33 --- /dev/null +++ b/packages/frourio/servers/aspida.config.js @@ -0,0 +1,6 @@ +const fs = require('fs') + +module.exports = fs + .readdirSync('.', { withFileTypes: true }) + .filter(d => d.isDirectory()) + .map(d => ({ input: `${d.name}/api` })) diff --git a/packages/frourio/servers/build.js b/packages/frourio/servers/build.js new file mode 100644 index 0000000..603a907 --- /dev/null +++ b/packages/frourio/servers/build.js @@ -0,0 +1,7 @@ +const fs = require('fs') +const write = require('aspida/dist/writeRouteFile').default +const build = require('../dist/buildServerFile').default + +fs.readdirSync(__dirname, { withFileTypes: true }).forEach(dir => { + if (dir.isDirectory()) write(build(`${__dirname}/${dir.name}`)) +}) diff --git a/packages/frourio/servers/frourio.ts b/packages/frourio/servers/frourio.ts new file mode 100644 index 0000000..25b7b6c --- /dev/null +++ b/packages/frourio/servers/frourio.ts @@ -0,0 +1,4 @@ +import express from 'express' +import frourio from './frourio/$app' + +frourio(express()).listen(3000) diff --git a/packages/frourio/servers/frourio/$app.ts b/packages/frourio/servers/frourio/$app.ts new file mode 100644 index 0000000..315772d --- /dev/null +++ b/packages/frourio/servers/frourio/$app.ts @@ -0,0 +1,140 @@ +/* eslint-disable */ +import { + LowerHttpMethod, + AspidaMethods, + HttpMethod, + HttpStatusOk, + AspidaMethodParams +} from 'aspida' +import { Deps } from 'velona' +import { Express, RequestHandler } from 'express' + +type Hooks = { + onRequest?: RequestHandler | RequestHandler[] + preParsing?: RequestHandler | RequestHandler[] + preValidation?: RequestHandler | RequestHandler[] + preHandler?: RequestHandler | RequestHandler[] + onSend?: RequestHandler | RequestHandler[] +} + +export function defineHooks(hooks: () => T): T +export function defineHooks>(deps: U, cb: (deps: Deps) => T): T & { inject: (d: Deps) => T } +export function defineHooks>(hooks: () => T | U, cb?: (deps: Deps) => T) { + return typeof hooks === 'function' ? hooks() : { ...cb!(hooks), inject: (d: Deps) => cb!(d) } +} + +import controller0 from './api/controller' + +export type FrourioOptions = { + basePath?: string +} + +type HttpStatusNoOk = + | 301 + | 302 + | 400 + | 401 + | 402 + | 403 + | 404 + | 405 + | 406 + | 409 + | 500 + | 501 + | 502 + | 503 + | 504 + | 505 + +type PartiallyPartial = Omit & Partial> + +type BaseResponse = { + status: V extends number ? V : HttpStatusOk + body: T + headers: U +} + +type ServerResponse = + | (K['resBody'] extends {} | null + ? K['resHeaders'] extends {} + ? BaseResponse + : PartiallyPartial< + BaseResponse< + K['resBody'], + K['resHeaders'] extends {} | undefined ? K['resHeaders'] : undefined, + K['status'] + >, + 'headers' + > + : K['resHeaders'] extends {} + ? PartiallyPartial< + BaseResponse< + K['resBody'] extends {} | null | undefined ? K['resBody'] : undefined, + K['resHeaders'], + K['status'] + >, + 'body' + > + : PartiallyPartial< + BaseResponse< + K['resBody'] extends {} | null | undefined ? K['resBody'] : undefined, + K['resHeaders'] extends {} | undefined ? K['resHeaders'] : undefined, + K['status'] + >, + 'body' | 'headers' + >) + | PartiallyPartial, 'body' | 'headers'> + +type ServerValues = { + params?: Record + user?: any +} + +type RequestParams = { + path: string + method: HttpMethod + query: T['query'] + body: T['reqBody'] + headers: T['reqHeaders'] +} + +export type ServerMethods = { + [K in keyof T]: ( + req: RequestParams & U + ) => ServerResponse | Promise> +} + +const methodsToHandler = ( + methodCallback: ServerMethods[LowerHttpMethod] +): RequestHandler => async (req, res) => { + try { + const result = methodCallback({ + query: req.query, + path: req.path, + method: req.method as HttpMethod, + body: req.body, + headers: req.headers, + params: (req as any).typedParams, + user: (req as any).user + }) + + const { status, body, headers } = result instanceof Promise ? await result : result + + for (const key in headers) { + res.setHeader(key, headers[key]) + } + + res.status(status).send(body) + } catch (e) { + res.sendStatus(500) + } +} + +export default (app: Express, options: FrourioOptions = {}) => { + const basePath = options.basePath ?? '' + + app.get(`${basePath}/`, methodsToHandler(controller0.get)) + + return app +} diff --git a/packages/frourio/servers/frourio/api/$api.ts b/packages/frourio/servers/frourio/api/$api.ts new file mode 100644 index 0000000..bf69e8f --- /dev/null +++ b/packages/frourio/servers/frourio/api/$api.ts @@ -0,0 +1,20 @@ +/* eslint-disable */ +import { AspidaClient } from 'aspida' +import { Methods as Methods0 } from '.' + +const api = ({ baseURL, fetch }: AspidaClient) => { + const prefix = (baseURL === undefined ? '' : baseURL).replace(/\/$/, '') + + const GET = 'GET' + + return { + get: (option?: { config?: T }) => + fetch(prefix, '', GET, option).text(), + $get: (option?: { config?: T }) => + fetch(prefix, '', GET, option).text().then(r => r.body), + $path: () => `${prefix}${''}` + } +} + +export type ApiInstance = ReturnType +export default api diff --git a/packages/frourio/servers/frourio/api/$relay.ts b/packages/frourio/servers/frourio/api/$relay.ts new file mode 100644 index 0000000..f064967 --- /dev/null +++ b/packages/frourio/servers/frourio/api/$relay.ts @@ -0,0 +1,14 @@ +/* eslint-disable */ +import { Deps } from 'velona' +import { ServerMethods, defineHooks } from '../$app' +import { Methods } from './' + +type ControllerMethods = ServerMethods + +export { defineHooks } + +export function defineController(methods: () => ControllerMethods): ControllerMethods +export function defineController>(deps: T, cb: (deps: Deps) => ControllerMethods): ControllerMethods & { inject: (d: Deps) => ControllerMethods } +export function defineController>(methods: () => ControllerMethods | T, cb?: (deps: Deps) => ControllerMethods) { + return typeof methods === 'function' ? methods() : { ...cb!(methods), inject: (d: Deps) => cb!(d) } +} diff --git a/packages/frourio/servers/frourio/api/controller.ts b/packages/frourio/servers/frourio/api/controller.ts new file mode 100644 index 0000000..9de8c56 --- /dev/null +++ b/packages/frourio/servers/frourio/api/controller.ts @@ -0,0 +1,5 @@ +import { defineController } from './$relay' + +export default defineController(() => ({ + get: () => ({ status: 200, body: 'Hello world' }) +})) diff --git a/packages/frourio/servers/frourio/api/index.ts b/packages/frourio/servers/frourio/api/index.ts new file mode 100644 index 0000000..0556ee1 --- /dev/null +++ b/packages/frourio/servers/frourio/api/index.ts @@ -0,0 +1,5 @@ +export type Methods = { + get: { + resBody: string + } +} diff --git a/packages/frourio/servers/noMulter/$app.ts b/packages/frourio/servers/noMulter/$app.ts new file mode 100644 index 0000000..4fbaf1b --- /dev/null +++ b/packages/frourio/servers/noMulter/$app.ts @@ -0,0 +1,245 @@ +/* eslint-disable */ +import { + LowerHttpMethod, + AspidaMethods, + HttpMethod, + HttpStatusOk, + AspidaMethodParams +} from 'aspida' +import { Deps } from 'velona' +import express, { Express, RequestHandler, Request } from 'express' +import { validateOrReject } from 'class-validator' + +type Hooks = { + onRequest?: RequestHandler | RequestHandler[] + preParsing?: RequestHandler | RequestHandler[] + preValidation?: RequestHandler | RequestHandler[] + preHandler?: RequestHandler | RequestHandler[] + onSend?: RequestHandler | RequestHandler[] +} + +export function defineHooks(hooks: () => T): T +export function defineHooks>(deps: U, cb: (deps: Deps) => T): T & { inject: (d: Deps) => T } +export function defineHooks>(hooks: () => T | U, cb?: (deps: Deps) => T) { + return typeof hooks === 'function' ? hooks() : { ...cb!(hooks), inject: (d: Deps) => cb!(d) } +} + +import * as Validators from './validators' +import controller0, { hooks as ctrlHooks0 } from './api/controller' +import controller1 from './api/empty/noEmpty/controller' +import controller2 from './api/texts/controller' +import controller3 from './api/texts/sample/controller' +import controller4, { hooks as ctrlHooks1 } from './api/users/controller' +import controller5 from './api/users/_userId@number/controller' +import hooks0 from './api/hooks' +import hooks1 from './api/users/hooks' + +export type FrourioOptions = { + basePath?: string +} + +type HttpStatusNoOk = + | 301 + | 302 + | 400 + | 401 + | 402 + | 403 + | 404 + | 405 + | 406 + | 409 + | 500 + | 501 + | 502 + | 503 + | 504 + | 505 + +type PartiallyPartial = Omit & Partial> + +type BaseResponse = { + status: V extends number ? V : HttpStatusOk + body: T + headers: U +} + +type ServerResponse = + | (K['resBody'] extends {} | null + ? K['resHeaders'] extends {} + ? BaseResponse + : PartiallyPartial< + BaseResponse< + K['resBody'], + K['resHeaders'] extends {} | undefined ? K['resHeaders'] : undefined, + K['status'] + >, + 'headers' + > + : K['resHeaders'] extends {} + ? PartiallyPartial< + BaseResponse< + K['resBody'] extends {} | null | undefined ? K['resBody'] : undefined, + K['resHeaders'], + K['status'] + >, + 'body' + > + : PartiallyPartial< + BaseResponse< + K['resBody'] extends {} | null | undefined ? K['resBody'] : undefined, + K['resHeaders'] extends {} | undefined ? K['resHeaders'] : undefined, + K['status'] + >, + 'body' | 'headers' + >) + | PartiallyPartial, 'body' | 'headers'> + +type ServerValues = { + params?: Record + user?: any +} + +type RequestParams = { + path: string + method: HttpMethod + query: T['query'] + body: T['reqBody'] + headers: T['reqHeaders'] +} + +export type ServerMethods = { + [K in keyof T]: ( + req: RequestParams & U + ) => ServerResponse | Promise> +} + +const parseJSONBoby: RequestHandler = (req, res, next) => { + express.json()(req, res, err => { + if (err) return res.sendStatus(400) + + next() + }) +} + +const createTypedParamsHandler = (numberTypeParams: string[]): RequestHandler => ( + req, + res, + next +) => { + const typedParams: Record = { ...req.params } + + for (const key of numberTypeParams) { + const val = Number(typedParams[key]) + if (isNaN(val)) { + res.sendStatus(400) + return + } + + typedParams[key] = val + } + + ;(req as any).typedParams = typedParams + next() +} + +const createValidateHandler = (validators: (req: Request) => (Promise | null)[]): RequestHandler => + (req, res, next) => Promise.all(validators(req)).then(() => next()).catch(() => res.sendStatus(400)) + +const methodsToHandler = ( + methodCallback: ServerMethods[LowerHttpMethod] +): RequestHandler => async (req, res) => { + try { + const result = methodCallback({ + query: req.query, + path: req.path, + method: req.method as HttpMethod, + body: req.body, + headers: req.headers, + params: (req as any).typedParams, + user: (req as any).user + }) + + const { status, body, headers } = result instanceof Promise ? await result : result + + for (const key in headers) { + res.setHeader(key, headers[key]) + } + + res.status(status).send(body) + } catch (e) { + res.sendStatus(500) + } +} + +export default (app: Express, options: FrourioOptions = {}) => { + const basePath = options.basePath ?? '' + + app.get(`${basePath}/`, [ + hooks0.onRequest, + ctrlHooks0.onRequest, + createValidateHandler(req => [ + Object.keys(req.query).length ? validateOrReject(Object.assign(new Validators.Query(), req.query)) : null + ]), + methodsToHandler(controller0.get) + ]) + + app.post(`${basePath}/`, [ + hooks0.onRequest, + ctrlHooks0.onRequest, + parseJSONBoby, + createValidateHandler(req => [ + validateOrReject(Object.assign(new Validators.Query(), req.query)), + validateOrReject(Object.assign(new Validators.Body(), req.body)) + ]), + methodsToHandler(controller0.post) + ]) + + app.get(`${basePath}/empty/noEmpty`, [ + hooks0.onRequest, + methodsToHandler(controller1.get) + ]) + + app.get(`${basePath}/texts`, [ + hooks0.onRequest, + methodsToHandler(controller2.get) + ]) + + app.put(`${basePath}/texts`, [ + hooks0.onRequest, + methodsToHandler(controller2.put) + ]) + + app.put(`${basePath}/texts/sample`, [ + hooks0.onRequest, + parseJSONBoby, + methodsToHandler(controller3.put) + ]) + + app.get(`${basePath}/users`, [ + hooks0.onRequest, + hooks1.onRequest, + ...ctrlHooks1.preHandler, + methodsToHandler(controller4.get) + ]) + + app.post(`${basePath}/users`, [ + hooks0.onRequest, + hooks1.onRequest, + parseJSONBoby, + createValidateHandler(req => [ + validateOrReject(Object.assign(new Validators.UserInfo(), req.body)) + ]), + ...ctrlHooks1.preHandler, + methodsToHandler(controller4.post) + ]) + + app.get(`${basePath}/users/:userId`, [ + hooks0.onRequest, + hooks1.onRequest, + createTypedParamsHandler(['userId']), + methodsToHandler(controller5.get) + ]) + + return app +} diff --git a/packages/frourio/server/api/$api.ts b/packages/frourio/servers/noMulter/api/$api.ts similarity index 68% rename from packages/frourio/server/api/$api.ts rename to packages/frourio/servers/noMulter/api/$api.ts index 379c426..82ecc29 100644 --- a/packages/frourio/server/api/$api.ts +++ b/packages/frourio/servers/noMulter/api/$api.ts @@ -1,35 +1,39 @@ /* eslint-disable */ -import { AspidaClient, BasicHeaders } from 'aspida' +import { AspidaClient, BasicHeaders, dataToURLString } from 'aspida' import { Methods as Methods0 } from '.' -import { Methods as Methods1 } from './multiForm' +import { Methods as Methods1 } from './empty/noEmpty' import { Methods as Methods2 } from './texts' import { Methods as Methods3 } from './texts/sample' import { Methods as Methods4 } from './users' import { Methods as Methods5 } from './users/_userId@number' -const GET = 'GET' -const POST = 'POST' -const PUT = 'PUT' -const PATH0 = '/multiForm' -const PATH1 = '/texts' -const PATH2 = '/texts/sample' -const PATH3 = '/users' const api = ({ baseURL, fetch }: AspidaClient) => { const prefix = (baseURL === undefined ? '' : baseURL).replace(/\/$/, '') + const PATH0 = '/empty/noEmpty' + const PATH1 = '/texts' + const PATH2 = '/texts/sample' + const PATH3 = '/users' + const GET = 'GET' + const POST = 'POST' + const PUT = 'PUT' return { - multiForm: { - post: (option: { body: Methods1['post']['reqBody'], config?: T }) => - fetch(prefix, PATH0, POST, option, 'FormData').json(), - $post: (option: { body: Methods1['post']['reqBody'], config?: T }) => - fetch(prefix, PATH0, POST, option, 'FormData').json().then(r => r.body) + empty: { + noEmpty: { + get: (option?: { config?: T }) => + fetch(prefix, PATH0, GET, option).text(), + $get: (option?: { config?: T }) => + fetch(prefix, PATH0, GET, option).text().then(r => r.body), + $path: () => `${prefix}${PATH0}` + } }, texts: { sample: { put: (option: { body: Methods3['put']['reqBody'], config?: T }) => fetch(prefix, PATH2, PUT, option).json(), $put: (option: { body: Methods3['put']['reqBody'], config?: T }) => - fetch(prefix, PATH2, PUT, option).json().then(r => r.body) + fetch(prefix, PATH2, PUT, option).json().then(r => r.body), + $path: () => `${prefix}${PATH2}` }, get: (option: { query: Methods2['get']['query'], config?: T }) => fetch(prefix, PATH1, GET, option).text(), @@ -38,7 +42,9 @@ const api = ({ baseURL, fetch }: AspidaClient) => { put: (option?: { config?: T }) => fetch(prefix, PATH1, PUT, option).send(), $put: (option?: { config?: T }) => - fetch(prefix, PATH1, PUT, option).send().then(r => r.body) + fetch(prefix, PATH1, PUT, option).send().then(r => r.body), + $path: (option?: { method?: 'get'; query: Methods2['get']['query'] }) => + `${prefix}${PATH1}${option && option.query ? `?${dataToURLString(option.query)}` : ''}` }, users: { _userId: (val0: number) => { @@ -48,7 +54,8 @@ const api = ({ baseURL, fetch }: AspidaClient) => { get: (option?: { config?: T }) => fetch(prefix, prefix0, GET, option).json(), $get: (option?: { config?: T }) => - fetch(prefix, prefix0, GET, option).json().then(r => r.body) + fetch(prefix, prefix0, GET, option).json().then(r => r.body), + $path: () => `${prefix}${prefix0}` } }, get: (option?: { config?: T }) => @@ -58,16 +65,19 @@ const api = ({ baseURL, fetch }: AspidaClient) => { post: (option: { body: Methods4['post']['reqBody'], config?: T }) => fetch(prefix, PATH3, POST, option).send(), $post: (option: { body: Methods4['post']['reqBody'], config?: T }) => - fetch(prefix, PATH3, POST, option).send().then(r => r.body) + fetch(prefix, PATH3, POST, option).send().then(r => r.body), + $path: () => `${prefix}${PATH3}` }, get: (option?: { query?: Methods0['get']['query'], config?: T }) => fetch(prefix, '', GET, option).json(), $get: (option?: { query?: Methods0['get']['query'], config?: T }) => fetch(prefix, '', GET, option).json().then(r => r.body), post: (option: { body: Methods0['post']['reqBody'], query: Methods0['post']['query'], config?: T }) => - fetch(prefix, '', POST, option, 'FormData').json(), + fetch(prefix, '', POST, option).json(), $post: (option: { body: Methods0['post']['reqBody'], query: Methods0['post']['query'], config?: T }) => - fetch(prefix, '', POST, option, 'FormData').json().then(r => r.body) + fetch(prefix, '', POST, option).json().then(r => r.body), + $path: (option?: { method?: 'get'; query: Methods0['get']['query'] } | { method: 'post'; query: Methods0['post']['query'] }) => + `${prefix}${''}${option && option.query ? `?${dataToURLString(option.query)}` : ''}` } } diff --git a/packages/frourio/servers/noMulter/api/$relay.ts b/packages/frourio/servers/noMulter/api/$relay.ts new file mode 100644 index 0000000..f064967 --- /dev/null +++ b/packages/frourio/servers/noMulter/api/$relay.ts @@ -0,0 +1,14 @@ +/* eslint-disable */ +import { Deps } from 'velona' +import { ServerMethods, defineHooks } from '../$app' +import { Methods } from './' + +type ControllerMethods = ServerMethods + +export { defineHooks } + +export function defineController(methods: () => ControllerMethods): ControllerMethods +export function defineController>(deps: T, cb: (deps: Deps) => ControllerMethods): ControllerMethods & { inject: (d: Deps) => ControllerMethods } +export function defineController>(methods: () => ControllerMethods | T, cb?: (deps: Deps) => ControllerMethods) { + return typeof methods === 'function' ? methods() : { ...cb!(methods), inject: (d: Deps) => cb!(d) } +} diff --git a/packages/frourio/servers/noMulter/api/controller.ts b/packages/frourio/servers/noMulter/api/controller.ts new file mode 100644 index 0000000..7bac341 --- /dev/null +++ b/packages/frourio/servers/noMulter/api/controller.ts @@ -0,0 +1,19 @@ +import { defineController, defineHooks } from './$relay' + +export const hooks = defineHooks(() => ({ + onRequest: (req, res, next) => { + console.log('Controller level onRequest hook:', req.path) + next() + } +})) + +export default defineController(() => ({ + get: async v => { + return await { status: 200, body: { id: +(v.query?.id || 0) } } + }, + post: v => ({ + // @ts-expect-error + status: 200, + body: { id: +v.query.id, port: v.body.port } + }) +})) diff --git a/packages/frourio/servers/noMulter/api/empty/$relay.ts b/packages/frourio/servers/noMulter/api/empty/$relay.ts new file mode 100644 index 0000000..8b7c89b --- /dev/null +++ b/packages/frourio/servers/noMulter/api/empty/$relay.ts @@ -0,0 +1,14 @@ +/* eslint-disable */ +import { Deps } from 'velona' +import { ServerMethods, defineHooks } from '../../$app' +import { Methods } from './' + +type ControllerMethods = ServerMethods + +export { defineHooks } + +export function defineController(methods: () => ControllerMethods): ControllerMethods +export function defineController>(deps: T, cb: (deps: Deps) => ControllerMethods): ControllerMethods & { inject: (d: Deps) => ControllerMethods } +export function defineController>(methods: () => ControllerMethods | T, cb?: (deps: Deps) => ControllerMethods) { + return typeof methods === 'function' ? methods() : { ...cb!(methods), inject: (d: Deps) => cb!(d) } +} diff --git a/packages/frourio/servers/noMulter/api/empty/controller.ts b/packages/frourio/servers/noMulter/api/empty/controller.ts new file mode 100644 index 0000000..edbfd03 --- /dev/null +++ b/packages/frourio/servers/noMulter/api/empty/controller.ts @@ -0,0 +1,3 @@ +import { defineController } from './$relay' + +export default defineController(() => ({})) diff --git a/packages/frourio/servers/noMulter/api/empty/index.ts b/packages/frourio/servers/noMulter/api/empty/index.ts new file mode 100644 index 0000000..4dcad57 --- /dev/null +++ b/packages/frourio/servers/noMulter/api/empty/index.ts @@ -0,0 +1 @@ +export type Methods = {} diff --git a/packages/frourio/servers/noMulter/api/empty/noEmpty/$relay.ts b/packages/frourio/servers/noMulter/api/empty/noEmpty/$relay.ts new file mode 100644 index 0000000..26ca223 --- /dev/null +++ b/packages/frourio/servers/noMulter/api/empty/noEmpty/$relay.ts @@ -0,0 +1,14 @@ +/* eslint-disable */ +import { Deps } from 'velona' +import { ServerMethods, defineHooks } from '../../../$app' +import { Methods } from './' + +type ControllerMethods = ServerMethods + +export { defineHooks } + +export function defineController(methods: () => ControllerMethods): ControllerMethods +export function defineController>(deps: T, cb: (deps: Deps) => ControllerMethods): ControllerMethods & { inject: (d: Deps) => ControllerMethods } +export function defineController>(methods: () => ControllerMethods | T, cb?: (deps: Deps) => ControllerMethods) { + return typeof methods === 'function' ? methods() : { ...cb!(methods), inject: (d: Deps) => cb!(d) } +} diff --git a/packages/frourio/servers/noMulter/api/empty/noEmpty/controller.ts b/packages/frourio/servers/noMulter/api/empty/noEmpty/controller.ts new file mode 100644 index 0000000..eb73909 --- /dev/null +++ b/packages/frourio/servers/noMulter/api/empty/noEmpty/controller.ts @@ -0,0 +1,5 @@ +import { defineController } from './$relay' + +export default defineController(() => ({ + get: () => ({ status: 200, body: 'sample' }) +})) diff --git a/packages/frourio/servers/noMulter/api/empty/noEmpty/index.ts b/packages/frourio/servers/noMulter/api/empty/noEmpty/index.ts new file mode 100644 index 0000000..0556ee1 --- /dev/null +++ b/packages/frourio/servers/noMulter/api/empty/noEmpty/index.ts @@ -0,0 +1,5 @@ +export type Methods = { + get: { + resBody: string + } +} diff --git a/packages/frourio/servers/noMulter/api/hooks.ts b/packages/frourio/servers/noMulter/api/hooks.ts new file mode 100644 index 0000000..c0c0ad6 --- /dev/null +++ b/packages/frourio/servers/noMulter/api/hooks.ts @@ -0,0 +1,8 @@ +import { defineHooks } from './$relay' + +export default defineHooks(() => ({ + onRequest: (req, res, next) => { + console.log('Directory level middleware:', req.path) + next() + } +})) diff --git a/packages/frourio/servers/noMulter/api/index.ts b/packages/frourio/servers/noMulter/api/index.ts new file mode 100644 index 0000000..7909803 --- /dev/null +++ b/packages/frourio/servers/noMulter/api/index.ts @@ -0,0 +1,19 @@ +import { Query, Body } from '../validators' + +export type Methods = { + get: { + query?: Query + status: 200 + resBody?: { id: number } + } + + post: { + query: Query + reqBody: Body + status: 201 + resBody: { + id: number + port: string + } + } +} diff --git a/packages/frourio/servers/noMulter/api/texts/$relay.ts b/packages/frourio/servers/noMulter/api/texts/$relay.ts new file mode 100644 index 0000000..8b7c89b --- /dev/null +++ b/packages/frourio/servers/noMulter/api/texts/$relay.ts @@ -0,0 +1,14 @@ +/* eslint-disable */ +import { Deps } from 'velona' +import { ServerMethods, defineHooks } from '../../$app' +import { Methods } from './' + +type ControllerMethods = ServerMethods + +export { defineHooks } + +export function defineController(methods: () => ControllerMethods): ControllerMethods +export function defineController>(deps: T, cb: (deps: Deps) => ControllerMethods): ControllerMethods & { inject: (d: Deps) => ControllerMethods } +export function defineController>(methods: () => ControllerMethods | T, cb?: (deps: Deps) => ControllerMethods) { + return typeof methods === 'function' ? methods() : { ...cb!(methods), inject: (d: Deps) => cb!(d) } +} diff --git a/packages/frourio/servers/noMulter/api/texts/controller.ts b/packages/frourio/servers/noMulter/api/texts/controller.ts new file mode 100644 index 0000000..edca134 --- /dev/null +++ b/packages/frourio/servers/noMulter/api/texts/controller.ts @@ -0,0 +1,6 @@ +import { defineController } from './$relay' + +// @ts-expect-error +export default defineController(() => ({ + get: ({ query }) => ({ status: 200, body: query.val }) +})) diff --git a/packages/frourio/servers/noMulter/api/texts/index.ts b/packages/frourio/servers/noMulter/api/texts/index.ts new file mode 100644 index 0000000..5ff9a66 --- /dev/null +++ b/packages/frourio/servers/noMulter/api/texts/index.ts @@ -0,0 +1,10 @@ +export type Methods = { + get: { + query: { + val: string + } + resBody: string + } + + put: {} +} diff --git a/packages/frourio/servers/noMulter/api/texts/sample/$relay.ts b/packages/frourio/servers/noMulter/api/texts/sample/$relay.ts new file mode 100644 index 0000000..26ca223 --- /dev/null +++ b/packages/frourio/servers/noMulter/api/texts/sample/$relay.ts @@ -0,0 +1,14 @@ +/* eslint-disable */ +import { Deps } from 'velona' +import { ServerMethods, defineHooks } from '../../../$app' +import { Methods } from './' + +type ControllerMethods = ServerMethods + +export { defineHooks } + +export function defineController(methods: () => ControllerMethods): ControllerMethods +export function defineController>(deps: T, cb: (deps: Deps) => ControllerMethods): ControllerMethods & { inject: (d: Deps) => ControllerMethods } +export function defineController>(methods: () => ControllerMethods | T, cb?: (deps: Deps) => ControllerMethods) { + return typeof methods === 'function' ? methods() : { ...cb!(methods), inject: (d: Deps) => cb!(d) } +} diff --git a/packages/frourio/servers/noMulter/api/texts/sample/controller.ts b/packages/frourio/servers/noMulter/api/texts/sample/controller.ts new file mode 100644 index 0000000..8aa3058 --- /dev/null +++ b/packages/frourio/servers/noMulter/api/texts/sample/controller.ts @@ -0,0 +1,7 @@ +import { defineController } from './$relay' + +export default defineController(() => ({ + // @ts-expect-error + get: ({ query }) => ({ status: 200, body: query.val }), + put: ({ body }) => ({ status: 200, body }) +})) diff --git a/packages/frourio/servers/noMulter/api/texts/sample/index.ts b/packages/frourio/servers/noMulter/api/texts/sample/index.ts new file mode 100644 index 0000000..8fb901b --- /dev/null +++ b/packages/frourio/servers/noMulter/api/texts/sample/index.ts @@ -0,0 +1,10 @@ +export type Methods = { + put: { + reqBody: { + id: string + } | null + resBody: { + id: string + } | null + } +} diff --git a/packages/frourio/servers/noMulter/api/users/$relay.ts b/packages/frourio/servers/noMulter/api/users/$relay.ts new file mode 100644 index 0000000..2f2292e --- /dev/null +++ b/packages/frourio/servers/noMulter/api/users/$relay.ts @@ -0,0 +1,17 @@ +/* eslint-disable */ +import { Deps } from 'velona' +import { ServerMethods, defineHooks } from '../../$app' +import { User } from './hooks' +import { Methods } from './' + +type ControllerMethods = ServerMethods + +export { defineHooks } + +export function defineController(methods: () => ControllerMethods): ControllerMethods +export function defineController>(deps: T, cb: (deps: Deps) => ControllerMethods): ControllerMethods & { inject: (d: Deps) => ControllerMethods } +export function defineController>(methods: () => ControllerMethods | T, cb?: (deps: Deps) => ControllerMethods) { + return typeof methods === 'function' ? methods() : { ...cb!(methods), inject: (d: Deps) => cb!(d) } +} diff --git a/packages/frourio/servers/noMulter/api/users/_userId@number/$relay.ts b/packages/frourio/servers/noMulter/api/users/_userId@number/$relay.ts new file mode 100644 index 0000000..b3fd1d5 --- /dev/null +++ b/packages/frourio/servers/noMulter/api/users/_userId@number/$relay.ts @@ -0,0 +1,20 @@ +/* eslint-disable */ +import { Deps } from 'velona' +import { ServerMethods, defineHooks } from '../../../$app' +import { User } from './../hooks' +import { Methods } from './' + +type ControllerMethods = ServerMethods + +export { defineHooks } + +export function defineController(methods: () => ControllerMethods): ControllerMethods +export function defineController>(deps: T, cb: (deps: Deps) => ControllerMethods): ControllerMethods & { inject: (d: Deps) => ControllerMethods } +export function defineController>(methods: () => ControllerMethods | T, cb?: (deps: Deps) => ControllerMethods) { + return typeof methods === 'function' ? methods() : { ...cb!(methods), inject: (d: Deps) => cb!(d) } +} diff --git a/packages/frourio/servers/noMulter/api/users/_userId@number/controller.ts b/packages/frourio/servers/noMulter/api/users/_userId@number/controller.ts new file mode 100644 index 0000000..047e709 --- /dev/null +++ b/packages/frourio/servers/noMulter/api/users/_userId@number/controller.ts @@ -0,0 +1,5 @@ +import { defineController } from './$relay' + +export default defineController(() => ({ + get: ({ params }) => ({ status: 200, body: { id: params.userId, name: 'bbb' } }) +})) diff --git a/packages/frourio/servers/noMulter/api/users/_userId@number/index.ts b/packages/frourio/servers/noMulter/api/users/_userId@number/index.ts new file mode 100644 index 0000000..ad9940f --- /dev/null +++ b/packages/frourio/servers/noMulter/api/users/_userId@number/index.ts @@ -0,0 +1,7 @@ +import { UserInfo } from '../../../validators' + +export type Methods = { + get: { + resBody: UserInfo + } +} diff --git a/packages/frourio/servers/noMulter/api/users/controller.ts b/packages/frourio/servers/noMulter/api/users/controller.ts new file mode 100644 index 0000000..7c9ed22 --- /dev/null +++ b/packages/frourio/servers/noMulter/api/users/controller.ts @@ -0,0 +1,17 @@ +import { defineController, defineHooks } from './$relay' + +const hooks = defineHooks(() => ({ + preHandler: [ + (req, res, next) => { + console.log('Controller level preHandler hook:', req.path) + next() + } + ] +})) + +export { hooks } + +export default defineController(() => ({ + get: async () => ({ status: 200, body: [{ id: 1, name: 'aa' }] }), + post: () => ({ status: 204 }) +})) diff --git a/packages/frourio/servers/noMulter/api/users/hooks.ts b/packages/frourio/servers/noMulter/api/users/hooks.ts new file mode 100644 index 0000000..036c246 --- /dev/null +++ b/packages/frourio/servers/noMulter/api/users/hooks.ts @@ -0,0 +1,15 @@ +import { defineHooks } from './$relay' + +export type User = { + id: number + name: string + role: 'admin' | 'user' +} + +export default defineHooks(() => ({ + onRequest: (req, res, next) => { + console.log('Added user') + ;(req as any).user = { id: 1, name: 'user name', role: 'admin' } + next() + } +})) diff --git a/packages/frourio/servers/noMulter/api/users/index.ts b/packages/frourio/servers/noMulter/api/users/index.ts new file mode 100644 index 0000000..4e7791b --- /dev/null +++ b/packages/frourio/servers/noMulter/api/users/index.ts @@ -0,0 +1,11 @@ +import { UserInfo } from '../../validators' + +export type Methods = { + get: { + resBody: UserInfo[] + } + + post: { + reqBody: UserInfo + } +} diff --git a/packages/frourio/servers/noMulter/validators/index.ts b/packages/frourio/servers/noMulter/validators/index.ts new file mode 100644 index 0000000..dee69ee --- /dev/null +++ b/packages/frourio/servers/noMulter/validators/index.ts @@ -0,0 +1,22 @@ +import { IsNumberString, IsBooleanString, IsPort, IsInt, MaxLength } from 'class-validator' + +export class Query { + @IsNumberString() + id: string + + @IsBooleanString() + disable: string +} + +export class Body { + @IsPort() + port: string +} + +export class UserInfo { + @IsInt() + id: number + + @MaxLength(20) + name: string +} diff --git a/packages/frourio/servers/noTypedParams/$app.ts b/packages/frourio/servers/noTypedParams/$app.ts new file mode 100644 index 0000000..b907f60 --- /dev/null +++ b/packages/frourio/servers/noTypedParams/$app.ts @@ -0,0 +1,269 @@ +/* eslint-disable */ +import path from 'path' +import { + LowerHttpMethod, + AspidaMethods, + HttpMethod, + HttpStatusOk, + AspidaMethodParams +} from 'aspida' +import { Deps } from 'velona' +import express, { Express, RequestHandler, Request } from 'express' +import multer, { Options } from 'multer' +import { validateOrReject } from 'class-validator' + +type Hooks = { + onRequest?: RequestHandler | RequestHandler[] + preParsing?: RequestHandler | RequestHandler[] + preValidation?: RequestHandler | RequestHandler[] + preHandler?: RequestHandler | RequestHandler[] + onSend?: RequestHandler | RequestHandler[] +} + +export function defineHooks(hooks: () => T): T +export function defineHooks>(deps: U, cb: (deps: Deps) => T): T & { inject: (d: Deps) => T } +export function defineHooks>(hooks: () => T | U, cb?: (deps: Deps) => T) { + return typeof hooks === 'function' ? hooks() : { ...cb!(hooks), inject: (d: Deps) => cb!(d) } +} + +import * as Validators from './validators' +import controller0, { hooks as ctrlHooks0 } from './api/controller' +import controller1 from './api/empty/noEmpty/controller' +import controller2 from './api/multiForm/controller' +import controller3 from './api/texts/controller' +import controller4 from './api/texts/sample/controller' +import controller5, { hooks as ctrlHooks1 } from './api/users/controller' +import hooks0 from './api/hooks' +import hooks1 from './api/users/hooks' + +export type FrourioOptions = { + basePath?: string + multer?: Options +} + +export type MulterFile = Express.Multer.File + +type HttpStatusNoOk = + | 301 + | 302 + | 400 + | 401 + | 402 + | 403 + | 404 + | 405 + | 406 + | 409 + | 500 + | 501 + | 502 + | 503 + | 504 + | 505 + +type PartiallyPartial = Omit & Partial> + +type BaseResponse = { + status: V extends number ? V : HttpStatusOk + body: T + headers: U +} + +type ServerResponse = + | (K['resBody'] extends {} | null + ? K['resHeaders'] extends {} + ? BaseResponse + : PartiallyPartial< + BaseResponse< + K['resBody'], + K['resHeaders'] extends {} | undefined ? K['resHeaders'] : undefined, + K['status'] + >, + 'headers' + > + : K['resHeaders'] extends {} + ? PartiallyPartial< + BaseResponse< + K['resBody'] extends {} | null | undefined ? K['resBody'] : undefined, + K['resHeaders'], + K['status'] + >, + 'body' + > + : PartiallyPartial< + BaseResponse< + K['resBody'] extends {} | null | undefined ? K['resBody'] : undefined, + K['resHeaders'] extends {} | undefined ? K['resHeaders'] : undefined, + K['status'] + >, + 'body' | 'headers' + >) + | PartiallyPartial, 'body' | 'headers'> + +type ServerValues = { + params?: Record + user?: any +} + +type BlobToFile = T['reqFormat'] extends FormData + ? { + [P in keyof T['reqBody']]: Required[P] extends Blob + ? MulterFile + : Required[P] extends Blob[] + ? MulterFile[] + : T['reqBody'][P] + } + : T['reqBody'] + +type RequestParams = { + path: string + method: HttpMethod + query: T['query'] + body: BlobToFile + headers: T['reqHeaders'] +} + +export type ServerMethods = { + [K in keyof T]: ( + req: RequestParams & U + ) => ServerResponse | Promise> +} + +const parseJSONBoby: RequestHandler = (req, res, next) => { + express.json()(req, res, err => { + if (err) return res.sendStatus(400) + + next() + }) +} + +const createValidateHandler = (validators: (req: Request) => (Promise | null)[]): RequestHandler => + (req, res, next) => Promise.all(validators(req)).then(() => next()).catch(() => res.sendStatus(400)) + +const methodsToHandler = ( + methodCallback: ServerMethods[LowerHttpMethod] +): RequestHandler => async (req, res) => { + try { + const result = methodCallback({ + query: req.query, + path: req.path, + method: req.method as HttpMethod, + body: req.body, + headers: req.headers, + params: (req as any).typedParams, + user: (req as any).user + }) + + const { status, body, headers } = result instanceof Promise ? await result : result + + for (const key in headers) { + res.setHeader(key, headers[key]) + } + + res.status(status).send(body) + } catch (e) { + res.sendStatus(500) + } +} + +const formatMulterData = (arrayTypeKeys: [string, boolean][]): RequestHandler => ({ body, files }, _res, next) => { + for (const [key] of arrayTypeKeys) { + if (body[key] === undefined) body[key] = [] + else if (!Array.isArray(body[key])) { + body[key] = [body[key]] + } + } + + for (const file of files as MulterFile[]) { + if (Array.isArray(body[file.fieldname])) { + body[file.fieldname].push(file) + } else { + body[file.fieldname] = file + } + } + + for (const [key, isOptional] of arrayTypeKeys) { + if (!body[key].length && isOptional) delete body[key] + } + + next() +} + +export default (app: Express, options: FrourioOptions = {}) => { + const basePath = options.basePath ?? '' + const uploader = multer( + options.multer ?? { dest: path.join(__dirname, '.upload'), limits: { fileSize: 1024 ** 3 } } + ).any() + + app.get(`${basePath}/`, [ + hooks0.onRequest, + ctrlHooks0.onRequest, + createValidateHandler(req => [ + Object.keys(req.query).length ? validateOrReject(Object.assign(new Validators.Query(), req.query)) : null + ]), + methodsToHandler(controller0.get) + ]) + + app.post(`${basePath}/`, [ + hooks0.onRequest, + ctrlHooks0.onRequest, + uploader, + formatMulterData([]), + createValidateHandler(req => [ + validateOrReject(Object.assign(new Validators.Query(), req.query)), + validateOrReject(Object.assign(new Validators.Body(), req.body)) + ]), + methodsToHandler(controller0.post) + ]) + + app.get(`${basePath}/empty/noEmpty`, [ + hooks0.onRequest, + methodsToHandler(controller1.get) + ]) + + app.post(`${basePath}/multiForm`, [ + hooks0.onRequest, + uploader, + formatMulterData([['empty', false], ['vals', false], ['files', false]]), + createValidateHandler(req => [ + validateOrReject(Object.assign(new Validators.MultiForm(), req.body)) + ]), + methodsToHandler(controller2.post) + ]) + + app.get(`${basePath}/texts`, [ + hooks0.onRequest, + methodsToHandler(controller3.get) + ]) + + app.put(`${basePath}/texts`, [ + hooks0.onRequest, + methodsToHandler(controller3.put) + ]) + + app.put(`${basePath}/texts/sample`, [ + hooks0.onRequest, + parseJSONBoby, + methodsToHandler(controller4.put) + ]) + + app.get(`${basePath}/users`, [ + hooks0.onRequest, + hooks1.onRequest, + ...ctrlHooks1.preHandler, + methodsToHandler(controller5.get) + ]) + + app.post(`${basePath}/users`, [ + hooks0.onRequest, + hooks1.onRequest, + parseJSONBoby, + createValidateHandler(req => [ + validateOrReject(Object.assign(new Validators.UserInfo(), req.body)) + ]), + ...ctrlHooks1.preHandler, + methodsToHandler(controller5.post) + ]) + + return app +} diff --git a/packages/frourio/servers/noTypedParams/api/$api.ts b/packages/frourio/servers/noTypedParams/api/$api.ts new file mode 100644 index 0000000..4b5ee7c --- /dev/null +++ b/packages/frourio/servers/noTypedParams/api/$api.ts @@ -0,0 +1,82 @@ +/* eslint-disable */ +import { AspidaClient, BasicHeaders, dataToURLString } from 'aspida' +import { Methods as Methods0 } from '.' +import { Methods as Methods1 } from './empty/noEmpty' +import { Methods as Methods2 } from './multiForm' +import { Methods as Methods3 } from './texts' +import { Methods as Methods4 } from './texts/sample' +import { Methods as Methods5 } from './users' + +const api = ({ baseURL, fetch }: AspidaClient) => { + const prefix = (baseURL === undefined ? '' : baseURL).replace(/\/$/, '') + const PATH0 = '/empty/noEmpty' + const PATH1 = '/multiForm' + const PATH2 = '/texts' + const PATH3 = '/texts/sample' + const PATH4 = '/users' + const GET = 'GET' + const POST = 'POST' + const PUT = 'PUT' + + return { + empty: { + noEmpty: { + get: (option?: { config?: T }) => + fetch(prefix, PATH0, GET, option).text(), + $get: (option?: { config?: T }) => + fetch(prefix, PATH0, GET, option).text().then(r => r.body), + $path: () => `${prefix}${PATH0}` + } + }, + multiForm: { + post: (option: { body: Methods2['post']['reqBody'], config?: T }) => + fetch(prefix, PATH1, POST, option, 'FormData').json(), + $post: (option: { body: Methods2['post']['reqBody'], config?: T }) => + fetch(prefix, PATH1, POST, option, 'FormData').json().then(r => r.body), + $path: () => `${prefix}${PATH1}` + }, + texts: { + sample: { + put: (option: { body: Methods4['put']['reqBody'], config?: T }) => + fetch(prefix, PATH3, PUT, option).json(), + $put: (option: { body: Methods4['put']['reqBody'], config?: T }) => + fetch(prefix, PATH3, PUT, option).json().then(r => r.body), + $path: () => `${prefix}${PATH3}` + }, + get: (option: { query: Methods3['get']['query'], config?: T }) => + fetch(prefix, PATH2, GET, option).text(), + $get: (option: { query: Methods3['get']['query'], config?: T }) => + fetch(prefix, PATH2, GET, option).text().then(r => r.body), + put: (option?: { config?: T }) => + fetch(prefix, PATH2, PUT, option).send(), + $put: (option?: { config?: T }) => + fetch(prefix, PATH2, PUT, option).send().then(r => r.body), + $path: (option?: { method?: 'get'; query: Methods3['get']['query'] }) => + `${prefix}${PATH2}${option && option.query ? `?${dataToURLString(option.query)}` : ''}` + }, + users: { + get: (option?: { config?: T }) => + fetch(prefix, PATH4, GET, option).json(), + $get: (option?: { config?: T }) => + fetch(prefix, PATH4, GET, option).json().then(r => r.body), + post: (option: { body: Methods5['post']['reqBody'], config?: T }) => + fetch(prefix, PATH4, POST, option).send(), + $post: (option: { body: Methods5['post']['reqBody'], config?: T }) => + fetch(prefix, PATH4, POST, option).send().then(r => r.body), + $path: () => `${prefix}${PATH4}` + }, + get: (option?: { query?: Methods0['get']['query'], config?: T }) => + fetch(prefix, '', GET, option).json(), + $get: (option?: { query?: Methods0['get']['query'], config?: T }) => + fetch(prefix, '', GET, option).json().then(r => r.body), + post: (option: { body: Methods0['post']['reqBody'], query: Methods0['post']['query'], config?: T }) => + fetch(prefix, '', POST, option, 'FormData').json(), + $post: (option: { body: Methods0['post']['reqBody'], query: Methods0['post']['query'], config?: T }) => + fetch(prefix, '', POST, option, 'FormData').json().then(r => r.body), + $path: (option?: { method?: 'get'; query: Methods0['get']['query'] } | { method: 'post'; query: Methods0['post']['query'] }) => + `${prefix}${''}${option && option.query ? `?${dataToURLString(option.query)}` : ''}` + } +} + +export type ApiInstance = ReturnType +export default api diff --git a/packages/frourio/servers/noTypedParams/api/$relay.ts b/packages/frourio/servers/noTypedParams/api/$relay.ts new file mode 100644 index 0000000..f064967 --- /dev/null +++ b/packages/frourio/servers/noTypedParams/api/$relay.ts @@ -0,0 +1,14 @@ +/* eslint-disable */ +import { Deps } from 'velona' +import { ServerMethods, defineHooks } from '../$app' +import { Methods } from './' + +type ControllerMethods = ServerMethods + +export { defineHooks } + +export function defineController(methods: () => ControllerMethods): ControllerMethods +export function defineController>(deps: T, cb: (deps: Deps) => ControllerMethods): ControllerMethods & { inject: (d: Deps) => ControllerMethods } +export function defineController>(methods: () => ControllerMethods | T, cb?: (deps: Deps) => ControllerMethods) { + return typeof methods === 'function' ? methods() : { ...cb!(methods), inject: (d: Deps) => cb!(d) } +} diff --git a/packages/frourio/servers/noTypedParams/api/controller.ts b/packages/frourio/servers/noTypedParams/api/controller.ts new file mode 100644 index 0000000..67f3e09 --- /dev/null +++ b/packages/frourio/servers/noTypedParams/api/controller.ts @@ -0,0 +1,19 @@ +import { defineController, defineHooks } from './$relay' + +export const hooks = defineHooks(() => ({ + onRequest: (req, res, next) => { + console.log('Controller level onRequest hook:', req.path) + next() + } +})) + +export default defineController(() => ({ + get: async v => { + return await { status: 200, body: { id: +(v.query?.id || 0) } } + }, + post: v => ({ + // @ts-expect-error + status: 200, + body: { id: +v.query.id, port: v.body.port, fileName: v.body.file.originalname } + }) +})) diff --git a/packages/frourio/servers/noTypedParams/api/empty/$relay.ts b/packages/frourio/servers/noTypedParams/api/empty/$relay.ts new file mode 100644 index 0000000..8b7c89b --- /dev/null +++ b/packages/frourio/servers/noTypedParams/api/empty/$relay.ts @@ -0,0 +1,14 @@ +/* eslint-disable */ +import { Deps } from 'velona' +import { ServerMethods, defineHooks } from '../../$app' +import { Methods } from './' + +type ControllerMethods = ServerMethods + +export { defineHooks } + +export function defineController(methods: () => ControllerMethods): ControllerMethods +export function defineController>(deps: T, cb: (deps: Deps) => ControllerMethods): ControllerMethods & { inject: (d: Deps) => ControllerMethods } +export function defineController>(methods: () => ControllerMethods | T, cb?: (deps: Deps) => ControllerMethods) { + return typeof methods === 'function' ? methods() : { ...cb!(methods), inject: (d: Deps) => cb!(d) } +} diff --git a/packages/frourio/servers/noTypedParams/api/empty/controller.ts b/packages/frourio/servers/noTypedParams/api/empty/controller.ts new file mode 100644 index 0000000..edbfd03 --- /dev/null +++ b/packages/frourio/servers/noTypedParams/api/empty/controller.ts @@ -0,0 +1,3 @@ +import { defineController } from './$relay' + +export default defineController(() => ({})) diff --git a/packages/frourio/servers/noTypedParams/api/empty/index.ts b/packages/frourio/servers/noTypedParams/api/empty/index.ts new file mode 100644 index 0000000..4dcad57 --- /dev/null +++ b/packages/frourio/servers/noTypedParams/api/empty/index.ts @@ -0,0 +1 @@ +export type Methods = {} diff --git a/packages/frourio/servers/noTypedParams/api/empty/noEmpty/$relay.ts b/packages/frourio/servers/noTypedParams/api/empty/noEmpty/$relay.ts new file mode 100644 index 0000000..26ca223 --- /dev/null +++ b/packages/frourio/servers/noTypedParams/api/empty/noEmpty/$relay.ts @@ -0,0 +1,14 @@ +/* eslint-disable */ +import { Deps } from 'velona' +import { ServerMethods, defineHooks } from '../../../$app' +import { Methods } from './' + +type ControllerMethods = ServerMethods + +export { defineHooks } + +export function defineController(methods: () => ControllerMethods): ControllerMethods +export function defineController>(deps: T, cb: (deps: Deps) => ControllerMethods): ControllerMethods & { inject: (d: Deps) => ControllerMethods } +export function defineController>(methods: () => ControllerMethods | T, cb?: (deps: Deps) => ControllerMethods) { + return typeof methods === 'function' ? methods() : { ...cb!(methods), inject: (d: Deps) => cb!(d) } +} diff --git a/packages/frourio/servers/noTypedParams/api/empty/noEmpty/controller.ts b/packages/frourio/servers/noTypedParams/api/empty/noEmpty/controller.ts new file mode 100644 index 0000000..eb73909 --- /dev/null +++ b/packages/frourio/servers/noTypedParams/api/empty/noEmpty/controller.ts @@ -0,0 +1,5 @@ +import { defineController } from './$relay' + +export default defineController(() => ({ + get: () => ({ status: 200, body: 'sample' }) +})) diff --git a/packages/frourio/servers/noTypedParams/api/empty/noEmpty/index.ts b/packages/frourio/servers/noTypedParams/api/empty/noEmpty/index.ts new file mode 100644 index 0000000..0556ee1 --- /dev/null +++ b/packages/frourio/servers/noTypedParams/api/empty/noEmpty/index.ts @@ -0,0 +1,5 @@ +export type Methods = { + get: { + resBody: string + } +} diff --git a/packages/frourio/servers/noTypedParams/api/hooks.ts b/packages/frourio/servers/noTypedParams/api/hooks.ts new file mode 100644 index 0000000..c0c0ad6 --- /dev/null +++ b/packages/frourio/servers/noTypedParams/api/hooks.ts @@ -0,0 +1,8 @@ +import { defineHooks } from './$relay' + +export default defineHooks(() => ({ + onRequest: (req, res, next) => { + console.log('Directory level middleware:', req.path) + next() + } +})) diff --git a/packages/frourio/servers/noTypedParams/api/index.ts b/packages/frourio/servers/noTypedParams/api/index.ts new file mode 100644 index 0000000..a76d795 --- /dev/null +++ b/packages/frourio/servers/noTypedParams/api/index.ts @@ -0,0 +1,21 @@ +import { Query, Body } from '../validators' + +export type Methods = { + get: { + query?: Query + status: 200 + resBody?: { id: number } + } + + post: { + query: Query + reqFormat: FormData + reqBody: Body + status: 201 + resBody: { + id: number + port: string + fileName: string + } + } +} diff --git a/packages/frourio/servers/noTypedParams/api/multiForm/$relay.ts b/packages/frourio/servers/noTypedParams/api/multiForm/$relay.ts new file mode 100644 index 0000000..8b7c89b --- /dev/null +++ b/packages/frourio/servers/noTypedParams/api/multiForm/$relay.ts @@ -0,0 +1,14 @@ +/* eslint-disable */ +import { Deps } from 'velona' +import { ServerMethods, defineHooks } from '../../$app' +import { Methods } from './' + +type ControllerMethods = ServerMethods + +export { defineHooks } + +export function defineController(methods: () => ControllerMethods): ControllerMethods +export function defineController>(deps: T, cb: (deps: Deps) => ControllerMethods): ControllerMethods & { inject: (d: Deps) => ControllerMethods } +export function defineController>(methods: () => ControllerMethods | T, cb?: (deps: Deps) => ControllerMethods) { + return typeof methods === 'function' ? methods() : { ...cb!(methods), inject: (d: Deps) => cb!(d) } +} diff --git a/packages/frourio/servers/noTypedParams/api/multiForm/controller.ts b/packages/frourio/servers/noTypedParams/api/multiForm/controller.ts new file mode 100644 index 0000000..dd166bc --- /dev/null +++ b/packages/frourio/servers/noTypedParams/api/multiForm/controller.ts @@ -0,0 +1,12 @@ +import { defineController } from './$relay' +import { Methods } from './' + +export default defineController(() => ({ + post: ({ body }) => ({ + status: 201, + body: Object.entries(body).reduce( + (p, [key, val]) => ({ ...p, [key]: Array.isArray(val) ? val.length : -1 }), + {} as Methods['post']['resBody'] + ) + }) +})) diff --git a/packages/frourio/servers/noTypedParams/api/multiForm/index.ts b/packages/frourio/servers/noTypedParams/api/multiForm/index.ts new file mode 100644 index 0000000..27bcc4a --- /dev/null +++ b/packages/frourio/servers/noTypedParams/api/multiForm/index.ts @@ -0,0 +1,15 @@ +import { MultiForm } from '../../validators' + +export type Methods = { + post: { + reqFormat: FormData + reqBody: MultiForm + resBody: { + empty: number + name: number + icon: number + vals: number + files: number + } + } +} diff --git a/packages/frourio/servers/noTypedParams/api/texts/$relay.ts b/packages/frourio/servers/noTypedParams/api/texts/$relay.ts new file mode 100644 index 0000000..8b7c89b --- /dev/null +++ b/packages/frourio/servers/noTypedParams/api/texts/$relay.ts @@ -0,0 +1,14 @@ +/* eslint-disable */ +import { Deps } from 'velona' +import { ServerMethods, defineHooks } from '../../$app' +import { Methods } from './' + +type ControllerMethods = ServerMethods + +export { defineHooks } + +export function defineController(methods: () => ControllerMethods): ControllerMethods +export function defineController>(deps: T, cb: (deps: Deps) => ControllerMethods): ControllerMethods & { inject: (d: Deps) => ControllerMethods } +export function defineController>(methods: () => ControllerMethods | T, cb?: (deps: Deps) => ControllerMethods) { + return typeof methods === 'function' ? methods() : { ...cb!(methods), inject: (d: Deps) => cb!(d) } +} diff --git a/packages/frourio/servers/noTypedParams/api/texts/controller.ts b/packages/frourio/servers/noTypedParams/api/texts/controller.ts new file mode 100644 index 0000000..edca134 --- /dev/null +++ b/packages/frourio/servers/noTypedParams/api/texts/controller.ts @@ -0,0 +1,6 @@ +import { defineController } from './$relay' + +// @ts-expect-error +export default defineController(() => ({ + get: ({ query }) => ({ status: 200, body: query.val }) +})) diff --git a/packages/frourio/servers/noTypedParams/api/texts/index.ts b/packages/frourio/servers/noTypedParams/api/texts/index.ts new file mode 100644 index 0000000..5ff9a66 --- /dev/null +++ b/packages/frourio/servers/noTypedParams/api/texts/index.ts @@ -0,0 +1,10 @@ +export type Methods = { + get: { + query: { + val: string + } + resBody: string + } + + put: {} +} diff --git a/packages/frourio/servers/noTypedParams/api/texts/sample/$relay.ts b/packages/frourio/servers/noTypedParams/api/texts/sample/$relay.ts new file mode 100644 index 0000000..26ca223 --- /dev/null +++ b/packages/frourio/servers/noTypedParams/api/texts/sample/$relay.ts @@ -0,0 +1,14 @@ +/* eslint-disable */ +import { Deps } from 'velona' +import { ServerMethods, defineHooks } from '../../../$app' +import { Methods } from './' + +type ControllerMethods = ServerMethods + +export { defineHooks } + +export function defineController(methods: () => ControllerMethods): ControllerMethods +export function defineController>(deps: T, cb: (deps: Deps) => ControllerMethods): ControllerMethods & { inject: (d: Deps) => ControllerMethods } +export function defineController>(methods: () => ControllerMethods | T, cb?: (deps: Deps) => ControllerMethods) { + return typeof methods === 'function' ? methods() : { ...cb!(methods), inject: (d: Deps) => cb!(d) } +} diff --git a/packages/frourio/servers/noTypedParams/api/texts/sample/controller.ts b/packages/frourio/servers/noTypedParams/api/texts/sample/controller.ts new file mode 100644 index 0000000..8aa3058 --- /dev/null +++ b/packages/frourio/servers/noTypedParams/api/texts/sample/controller.ts @@ -0,0 +1,7 @@ +import { defineController } from './$relay' + +export default defineController(() => ({ + // @ts-expect-error + get: ({ query }) => ({ status: 200, body: query.val }), + put: ({ body }) => ({ status: 200, body }) +})) diff --git a/packages/frourio/servers/noTypedParams/api/texts/sample/index.ts b/packages/frourio/servers/noTypedParams/api/texts/sample/index.ts new file mode 100644 index 0000000..8fb901b --- /dev/null +++ b/packages/frourio/servers/noTypedParams/api/texts/sample/index.ts @@ -0,0 +1,10 @@ +export type Methods = { + put: { + reqBody: { + id: string + } | null + resBody: { + id: string + } | null + } +} diff --git a/packages/frourio/servers/noTypedParams/api/users/$relay.ts b/packages/frourio/servers/noTypedParams/api/users/$relay.ts new file mode 100644 index 0000000..2f2292e --- /dev/null +++ b/packages/frourio/servers/noTypedParams/api/users/$relay.ts @@ -0,0 +1,17 @@ +/* eslint-disable */ +import { Deps } from 'velona' +import { ServerMethods, defineHooks } from '../../$app' +import { User } from './hooks' +import { Methods } from './' + +type ControllerMethods = ServerMethods + +export { defineHooks } + +export function defineController(methods: () => ControllerMethods): ControllerMethods +export function defineController>(deps: T, cb: (deps: Deps) => ControllerMethods): ControllerMethods & { inject: (d: Deps) => ControllerMethods } +export function defineController>(methods: () => ControllerMethods | T, cb?: (deps: Deps) => ControllerMethods) { + return typeof methods === 'function' ? methods() : { ...cb!(methods), inject: (d: Deps) => cb!(d) } +} diff --git a/packages/frourio/servers/noTypedParams/api/users/controller.ts b/packages/frourio/servers/noTypedParams/api/users/controller.ts new file mode 100644 index 0000000..7c9ed22 --- /dev/null +++ b/packages/frourio/servers/noTypedParams/api/users/controller.ts @@ -0,0 +1,17 @@ +import { defineController, defineHooks } from './$relay' + +const hooks = defineHooks(() => ({ + preHandler: [ + (req, res, next) => { + console.log('Controller level preHandler hook:', req.path) + next() + } + ] +})) + +export { hooks } + +export default defineController(() => ({ + get: async () => ({ status: 200, body: [{ id: 1, name: 'aa' }] }), + post: () => ({ status: 204 }) +})) diff --git a/packages/frourio/servers/noTypedParams/api/users/hooks.ts b/packages/frourio/servers/noTypedParams/api/users/hooks.ts new file mode 100644 index 0000000..036c246 --- /dev/null +++ b/packages/frourio/servers/noTypedParams/api/users/hooks.ts @@ -0,0 +1,15 @@ +import { defineHooks } from './$relay' + +export type User = { + id: number + name: string + role: 'admin' | 'user' +} + +export default defineHooks(() => ({ + onRequest: (req, res, next) => { + console.log('Added user') + ;(req as any).user = { id: 1, name: 'user name', role: 'admin' } + next() + } +})) diff --git a/packages/frourio/servers/noTypedParams/api/users/index.ts b/packages/frourio/servers/noTypedParams/api/users/index.ts new file mode 100644 index 0000000..4e7791b --- /dev/null +++ b/packages/frourio/servers/noTypedParams/api/users/index.ts @@ -0,0 +1,11 @@ +import { UserInfo } from '../../validators' + +export type Methods = { + get: { + resBody: UserInfo[] + } + + post: { + reqBody: UserInfo + } +} diff --git a/packages/frourio/server/types.ts b/packages/frourio/servers/noTypedParams/validators.ts similarity index 82% rename from packages/frourio/server/types.ts rename to packages/frourio/servers/noTypedParams/validators.ts index 00b2dae..bf0eb13 100644 --- a/packages/frourio/server/types.ts +++ b/packages/frourio/servers/noTypedParams/validators.ts @@ -9,7 +9,7 @@ import { ArrayNotEmpty } from 'class-validator' -export class ValidQuery { +export class Query { @IsNumberString() id: string @@ -17,14 +17,14 @@ export class ValidQuery { disable: string } -export class ValidBody { +export class Body { @IsPort() port: string file: File } -export class ValidUserInfo { +export class UserInfo { @IsInt() id: number @@ -32,7 +32,7 @@ export class ValidUserInfo { name: string } -export class ValidMultiForm { +export class MultiForm { @IsInt({ each: true }) empty: number[] diff --git a/packages/frourio/servers/noValidator/$app.ts b/packages/frourio/servers/noValidator/$app.ts new file mode 100644 index 0000000..78216e2 --- /dev/null +++ b/packages/frourio/servers/noValidator/$app.ts @@ -0,0 +1,280 @@ +/* eslint-disable */ +import path from 'path' +import { + LowerHttpMethod, + AspidaMethods, + HttpMethod, + HttpStatusOk, + AspidaMethodParams +} from 'aspida' +import { Deps } from 'velona' +import express, { Express, RequestHandler } from 'express' +import multer, { Options } from 'multer' + +type Hooks = { + onRequest?: RequestHandler | RequestHandler[] + preParsing?: RequestHandler | RequestHandler[] + preValidation?: RequestHandler | RequestHandler[] + preHandler?: RequestHandler | RequestHandler[] + onSend?: RequestHandler | RequestHandler[] +} + +export function defineHooks(hooks: () => T): T +export function defineHooks>(deps: U, cb: (deps: Deps) => T): T & { inject: (d: Deps) => T } +export function defineHooks>(hooks: () => T | U, cb?: (deps: Deps) => T) { + return typeof hooks === 'function' ? hooks() : { ...cb!(hooks), inject: (d: Deps) => cb!(d) } +} + +import controller0, { hooks as ctrlHooks0 } from './api/controller' +import controller1 from './api/empty/noEmpty/controller' +import controller2 from './api/multiForm/controller' +import controller3 from './api/texts/controller' +import controller4 from './api/texts/sample/controller' +import controller5, { hooks as ctrlHooks1 } from './api/users/controller' +import controller6 from './api/users/_userId@number/controller' +import hooks0 from './api/hooks' +import hooks1 from './api/users/hooks' + +export type FrourioOptions = { + basePath?: string + multer?: Options +} + +export type MulterFile = Express.Multer.File + +type HttpStatusNoOk = + | 301 + | 302 + | 400 + | 401 + | 402 + | 403 + | 404 + | 405 + | 406 + | 409 + | 500 + | 501 + | 502 + | 503 + | 504 + | 505 + +type PartiallyPartial = Omit & Partial> + +type BaseResponse = { + status: V extends number ? V : HttpStatusOk + body: T + headers: U +} + +type ServerResponse = + | (K['resBody'] extends {} | null + ? K['resHeaders'] extends {} + ? BaseResponse + : PartiallyPartial< + BaseResponse< + K['resBody'], + K['resHeaders'] extends {} | undefined ? K['resHeaders'] : undefined, + K['status'] + >, + 'headers' + > + : K['resHeaders'] extends {} + ? PartiallyPartial< + BaseResponse< + K['resBody'] extends {} | null | undefined ? K['resBody'] : undefined, + K['resHeaders'], + K['status'] + >, + 'body' + > + : PartiallyPartial< + BaseResponse< + K['resBody'] extends {} | null | undefined ? K['resBody'] : undefined, + K['resHeaders'] extends {} | undefined ? K['resHeaders'] : undefined, + K['status'] + >, + 'body' | 'headers' + >) + | PartiallyPartial, 'body' | 'headers'> + +type ServerValues = { + params?: Record + user?: any +} + +type BlobToFile = T['reqFormat'] extends FormData + ? { + [P in keyof T['reqBody']]: Required[P] extends Blob + ? MulterFile + : Required[P] extends Blob[] + ? MulterFile[] + : T['reqBody'][P] + } + : T['reqBody'] + +type RequestParams = { + path: string + method: HttpMethod + query: T['query'] + body: BlobToFile + headers: T['reqHeaders'] +} + +export type ServerMethods = { + [K in keyof T]: ( + req: RequestParams & U + ) => ServerResponse | Promise> +} + +const parseJSONBoby: RequestHandler = (req, res, next) => { + express.json()(req, res, err => { + if (err) return res.sendStatus(400) + + next() + }) +} + +const createTypedParamsHandler = (numberTypeParams: string[]): RequestHandler => ( + req, + res, + next +) => { + const typedParams: Record = { ...req.params } + + for (const key of numberTypeParams) { + const val = Number(typedParams[key]) + if (isNaN(val)) { + res.sendStatus(400) + return + } + + typedParams[key] = val + } + + ;(req as any).typedParams = typedParams + next() +} + +const methodsToHandler = ( + methodCallback: ServerMethods[LowerHttpMethod] +): RequestHandler => async (req, res) => { + try { + const result = methodCallback({ + query: req.query, + path: req.path, + method: req.method as HttpMethod, + body: req.body, + headers: req.headers, + params: (req as any).typedParams, + user: (req as any).user + }) + + const { status, body, headers } = result instanceof Promise ? await result : result + + for (const key in headers) { + res.setHeader(key, headers[key]) + } + + res.status(status).send(body) + } catch (e) { + res.sendStatus(500) + } +} + +const formatMulterData = (arrayTypeKeys: [string, boolean][]): RequestHandler => ({ body, files }, _res, next) => { + for (const [key] of arrayTypeKeys) { + if (body[key] === undefined) body[key] = [] + else if (!Array.isArray(body[key])) { + body[key] = [body[key]] + } + } + + for (const file of files as MulterFile[]) { + if (Array.isArray(body[file.fieldname])) { + body[file.fieldname].push(file) + } else { + body[file.fieldname] = file + } + } + + for (const [key, isOptional] of arrayTypeKeys) { + if (!body[key].length && isOptional) delete body[key] + } + + next() +} + +export default (app: Express, options: FrourioOptions = {}) => { + const basePath = options.basePath ?? '' + const uploader = multer( + options.multer ?? { dest: path.join(__dirname, '.upload'), limits: { fileSize: 1024 ** 3 } } + ).any() + + app.get(`${basePath}/`, [ + hooks0.onRequest, + ctrlHooks0.onRequest, + methodsToHandler(controller0.get) + ]) + + app.post(`${basePath}/`, [ + hooks0.onRequest, + ctrlHooks0.onRequest, + uploader, + formatMulterData([]), + methodsToHandler(controller0.post) + ]) + + app.get(`${basePath}/empty/noEmpty`, [ + hooks0.onRequest, + methodsToHandler(controller1.get) + ]) + + app.post(`${basePath}/multiForm`, [ + hooks0.onRequest, + uploader, + formatMulterData([['empty', false], ['vals', false], ['files', false]]), + methodsToHandler(controller2.post) + ]) + + app.get(`${basePath}/texts`, [ + hooks0.onRequest, + methodsToHandler(controller3.get) + ]) + + app.put(`${basePath}/texts`, [ + hooks0.onRequest, + methodsToHandler(controller3.put) + ]) + + app.put(`${basePath}/texts/sample`, [ + hooks0.onRequest, + parseJSONBoby, + methodsToHandler(controller4.put) + ]) + + app.get(`${basePath}/users`, [ + hooks0.onRequest, + hooks1.onRequest, + ...ctrlHooks1.preHandler, + methodsToHandler(controller5.get) + ]) + + app.post(`${basePath}/users`, [ + hooks0.onRequest, + hooks1.onRequest, + parseJSONBoby, + ...ctrlHooks1.preHandler, + methodsToHandler(controller5.post) + ]) + + app.get(`${basePath}/users/:userId`, [ + hooks0.onRequest, + hooks1.onRequest, + createTypedParamsHandler(['userId']), + methodsToHandler(controller6.get) + ]) + + return app +} diff --git a/packages/frourio/servers/noValidator/api/$api.ts b/packages/frourio/servers/noValidator/api/$api.ts new file mode 100644 index 0000000..62a3db2 --- /dev/null +++ b/packages/frourio/servers/noValidator/api/$api.ts @@ -0,0 +1,94 @@ +/* eslint-disable */ +import { AspidaClient, BasicHeaders, dataToURLString } from 'aspida' +import { Methods as Methods0 } from '.' +import { Methods as Methods1 } from './empty/noEmpty' +import { Methods as Methods2 } from './multiForm' +import { Methods as Methods3 } from './texts' +import { Methods as Methods4 } from './texts/sample' +import { Methods as Methods5 } from './users' +import { Methods as Methods6 } from './users/_userId@number' + +const api = ({ baseURL, fetch }: AspidaClient) => { + const prefix = (baseURL === undefined ? '' : baseURL).replace(/\/$/, '') + const PATH0 = '/empty/noEmpty' + const PATH1 = '/multiForm' + const PATH2 = '/texts' + const PATH3 = '/texts/sample' + const PATH4 = '/users' + const GET = 'GET' + const POST = 'POST' + const PUT = 'PUT' + + return { + empty: { + noEmpty: { + get: (option?: { config?: T }) => + fetch(prefix, PATH0, GET, option).text(), + $get: (option?: { config?: T }) => + fetch(prefix, PATH0, GET, option).text().then(r => r.body), + $path: () => `${prefix}${PATH0}` + } + }, + multiForm: { + post: (option: { body: Methods2['post']['reqBody'], config?: T }) => + fetch(prefix, PATH1, POST, option, 'FormData').json(), + $post: (option: { body: Methods2['post']['reqBody'], config?: T }) => + fetch(prefix, PATH1, POST, option, 'FormData').json().then(r => r.body), + $path: () => `${prefix}${PATH1}` + }, + texts: { + sample: { + put: (option: { body: Methods4['put']['reqBody'], config?: T }) => + fetch(prefix, PATH3, PUT, option).json(), + $put: (option: { body: Methods4['put']['reqBody'], config?: T }) => + fetch(prefix, PATH3, PUT, option).json().then(r => r.body), + $path: () => `${prefix}${PATH3}` + }, + get: (option: { query: Methods3['get']['query'], config?: T }) => + fetch(prefix, PATH2, GET, option).text(), + $get: (option: { query: Methods3['get']['query'], config?: T }) => + fetch(prefix, PATH2, GET, option).text().then(r => r.body), + put: (option?: { config?: T }) => + fetch(prefix, PATH2, PUT, option).send(), + $put: (option?: { config?: T }) => + fetch(prefix, PATH2, PUT, option).send().then(r => r.body), + $path: (option?: { method?: 'get'; query: Methods3['get']['query'] }) => + `${prefix}${PATH2}${option && option.query ? `?${dataToURLString(option.query)}` : ''}` + }, + users: { + _userId: (val0: number) => { + const prefix0 = `${PATH4}/${val0}` + + return { + get: (option?: { config?: T }) => + fetch(prefix, prefix0, GET, option).json(), + $get: (option?: { config?: T }) => + fetch(prefix, prefix0, GET, option).json().then(r => r.body), + $path: () => `${prefix}${prefix0}` + } + }, + get: (option?: { config?: T }) => + fetch(prefix, PATH4, GET, option).json(), + $get: (option?: { config?: T }) => + fetch(prefix, PATH4, GET, option).json().then(r => r.body), + post: (option: { body: Methods5['post']['reqBody'], config?: T }) => + fetch(prefix, PATH4, POST, option).send(), + $post: (option: { body: Methods5['post']['reqBody'], config?: T }) => + fetch(prefix, PATH4, POST, option).send().then(r => r.body), + $path: () => `${prefix}${PATH4}` + }, + get: (option?: { query?: Methods0['get']['query'], config?: T }) => + fetch(prefix, '', GET, option).json(), + $get: (option?: { query?: Methods0['get']['query'], config?: T }) => + fetch(prefix, '', GET, option).json().then(r => r.body), + post: (option: { body: Methods0['post']['reqBody'], query: Methods0['post']['query'], config?: T }) => + fetch(prefix, '', POST, option, 'FormData').json(), + $post: (option: { body: Methods0['post']['reqBody'], query: Methods0['post']['query'], config?: T }) => + fetch(prefix, '', POST, option, 'FormData').json().then(r => r.body), + $path: (option?: { method?: 'get'; query: Methods0['get']['query'] } | { method: 'post'; query: Methods0['post']['query'] }) => + `${prefix}${''}${option && option.query ? `?${dataToURLString(option.query)}` : ''}` + } +} + +export type ApiInstance = ReturnType +export default api diff --git a/packages/frourio/servers/noValidator/api/$relay.ts b/packages/frourio/servers/noValidator/api/$relay.ts new file mode 100644 index 0000000..f064967 --- /dev/null +++ b/packages/frourio/servers/noValidator/api/$relay.ts @@ -0,0 +1,14 @@ +/* eslint-disable */ +import { Deps } from 'velona' +import { ServerMethods, defineHooks } from '../$app' +import { Methods } from './' + +type ControllerMethods = ServerMethods + +export { defineHooks } + +export function defineController(methods: () => ControllerMethods): ControllerMethods +export function defineController>(deps: T, cb: (deps: Deps) => ControllerMethods): ControllerMethods & { inject: (d: Deps) => ControllerMethods } +export function defineController>(methods: () => ControllerMethods | T, cb?: (deps: Deps) => ControllerMethods) { + return typeof methods === 'function' ? methods() : { ...cb!(methods), inject: (d: Deps) => cb!(d) } +} diff --git a/packages/frourio/servers/noValidator/api/controller.ts b/packages/frourio/servers/noValidator/api/controller.ts new file mode 100644 index 0000000..67f3e09 --- /dev/null +++ b/packages/frourio/servers/noValidator/api/controller.ts @@ -0,0 +1,19 @@ +import { defineController, defineHooks } from './$relay' + +export const hooks = defineHooks(() => ({ + onRequest: (req, res, next) => { + console.log('Controller level onRequest hook:', req.path) + next() + } +})) + +export default defineController(() => ({ + get: async v => { + return await { status: 200, body: { id: +(v.query?.id || 0) } } + }, + post: v => ({ + // @ts-expect-error + status: 200, + body: { id: +v.query.id, port: v.body.port, fileName: v.body.file.originalname } + }) +})) diff --git a/packages/frourio/servers/noValidator/api/empty/$relay.ts b/packages/frourio/servers/noValidator/api/empty/$relay.ts new file mode 100644 index 0000000..8b7c89b --- /dev/null +++ b/packages/frourio/servers/noValidator/api/empty/$relay.ts @@ -0,0 +1,14 @@ +/* eslint-disable */ +import { Deps } from 'velona' +import { ServerMethods, defineHooks } from '../../$app' +import { Methods } from './' + +type ControllerMethods = ServerMethods + +export { defineHooks } + +export function defineController(methods: () => ControllerMethods): ControllerMethods +export function defineController>(deps: T, cb: (deps: Deps) => ControllerMethods): ControllerMethods & { inject: (d: Deps) => ControllerMethods } +export function defineController>(methods: () => ControllerMethods | T, cb?: (deps: Deps) => ControllerMethods) { + return typeof methods === 'function' ? methods() : { ...cb!(methods), inject: (d: Deps) => cb!(d) } +} diff --git a/packages/frourio/servers/noValidator/api/empty/controller.ts b/packages/frourio/servers/noValidator/api/empty/controller.ts new file mode 100644 index 0000000..edbfd03 --- /dev/null +++ b/packages/frourio/servers/noValidator/api/empty/controller.ts @@ -0,0 +1,3 @@ +import { defineController } from './$relay' + +export default defineController(() => ({})) diff --git a/packages/frourio/servers/noValidator/api/empty/index.ts b/packages/frourio/servers/noValidator/api/empty/index.ts new file mode 100644 index 0000000..4dcad57 --- /dev/null +++ b/packages/frourio/servers/noValidator/api/empty/index.ts @@ -0,0 +1 @@ +export type Methods = {} diff --git a/packages/frourio/servers/noValidator/api/empty/noEmpty/$relay.ts b/packages/frourio/servers/noValidator/api/empty/noEmpty/$relay.ts new file mode 100644 index 0000000..26ca223 --- /dev/null +++ b/packages/frourio/servers/noValidator/api/empty/noEmpty/$relay.ts @@ -0,0 +1,14 @@ +/* eslint-disable */ +import { Deps } from 'velona' +import { ServerMethods, defineHooks } from '../../../$app' +import { Methods } from './' + +type ControllerMethods = ServerMethods + +export { defineHooks } + +export function defineController(methods: () => ControllerMethods): ControllerMethods +export function defineController>(deps: T, cb: (deps: Deps) => ControllerMethods): ControllerMethods & { inject: (d: Deps) => ControllerMethods } +export function defineController>(methods: () => ControllerMethods | T, cb?: (deps: Deps) => ControllerMethods) { + return typeof methods === 'function' ? methods() : { ...cb!(methods), inject: (d: Deps) => cb!(d) } +} diff --git a/packages/frourio/servers/noValidator/api/empty/noEmpty/controller.ts b/packages/frourio/servers/noValidator/api/empty/noEmpty/controller.ts new file mode 100644 index 0000000..eb73909 --- /dev/null +++ b/packages/frourio/servers/noValidator/api/empty/noEmpty/controller.ts @@ -0,0 +1,5 @@ +import { defineController } from './$relay' + +export default defineController(() => ({ + get: () => ({ status: 200, body: 'sample' }) +})) diff --git a/packages/frourio/servers/noValidator/api/empty/noEmpty/index.ts b/packages/frourio/servers/noValidator/api/empty/noEmpty/index.ts new file mode 100644 index 0000000..0556ee1 --- /dev/null +++ b/packages/frourio/servers/noValidator/api/empty/noEmpty/index.ts @@ -0,0 +1,5 @@ +export type Methods = { + get: { + resBody: string + } +} diff --git a/packages/frourio/servers/noValidator/api/hooks.ts b/packages/frourio/servers/noValidator/api/hooks.ts new file mode 100644 index 0000000..c0c0ad6 --- /dev/null +++ b/packages/frourio/servers/noValidator/api/hooks.ts @@ -0,0 +1,8 @@ +import { defineHooks } from './$relay' + +export default defineHooks(() => ({ + onRequest: (req, res, next) => { + console.log('Directory level middleware:', req.path) + next() + } +})) diff --git a/packages/frourio/servers/noValidator/api/index.ts b/packages/frourio/servers/noValidator/api/index.ts new file mode 100644 index 0000000..a76d795 --- /dev/null +++ b/packages/frourio/servers/noValidator/api/index.ts @@ -0,0 +1,21 @@ +import { Query, Body } from '../validators' + +export type Methods = { + get: { + query?: Query + status: 200 + resBody?: { id: number } + } + + post: { + query: Query + reqFormat: FormData + reqBody: Body + status: 201 + resBody: { + id: number + port: string + fileName: string + } + } +} diff --git a/packages/frourio/servers/noValidator/api/multiForm/$relay.ts b/packages/frourio/servers/noValidator/api/multiForm/$relay.ts new file mode 100644 index 0000000..8b7c89b --- /dev/null +++ b/packages/frourio/servers/noValidator/api/multiForm/$relay.ts @@ -0,0 +1,14 @@ +/* eslint-disable */ +import { Deps } from 'velona' +import { ServerMethods, defineHooks } from '../../$app' +import { Methods } from './' + +type ControllerMethods = ServerMethods + +export { defineHooks } + +export function defineController(methods: () => ControllerMethods): ControllerMethods +export function defineController>(deps: T, cb: (deps: Deps) => ControllerMethods): ControllerMethods & { inject: (d: Deps) => ControllerMethods } +export function defineController>(methods: () => ControllerMethods | T, cb?: (deps: Deps) => ControllerMethods) { + return typeof methods === 'function' ? methods() : { ...cb!(methods), inject: (d: Deps) => cb!(d) } +} diff --git a/packages/frourio/servers/noValidator/api/multiForm/controller.ts b/packages/frourio/servers/noValidator/api/multiForm/controller.ts new file mode 100644 index 0000000..dd166bc --- /dev/null +++ b/packages/frourio/servers/noValidator/api/multiForm/controller.ts @@ -0,0 +1,12 @@ +import { defineController } from './$relay' +import { Methods } from './' + +export default defineController(() => ({ + post: ({ body }) => ({ + status: 201, + body: Object.entries(body).reduce( + (p, [key, val]) => ({ ...p, [key]: Array.isArray(val) ? val.length : -1 }), + {} as Methods['post']['resBody'] + ) + }) +})) diff --git a/packages/frourio/servers/noValidator/api/multiForm/index.ts b/packages/frourio/servers/noValidator/api/multiForm/index.ts new file mode 100644 index 0000000..27bcc4a --- /dev/null +++ b/packages/frourio/servers/noValidator/api/multiForm/index.ts @@ -0,0 +1,15 @@ +import { MultiForm } from '../../validators' + +export type Methods = { + post: { + reqFormat: FormData + reqBody: MultiForm + resBody: { + empty: number + name: number + icon: number + vals: number + files: number + } + } +} diff --git a/packages/frourio/servers/noValidator/api/texts/$relay.ts b/packages/frourio/servers/noValidator/api/texts/$relay.ts new file mode 100644 index 0000000..8b7c89b --- /dev/null +++ b/packages/frourio/servers/noValidator/api/texts/$relay.ts @@ -0,0 +1,14 @@ +/* eslint-disable */ +import { Deps } from 'velona' +import { ServerMethods, defineHooks } from '../../$app' +import { Methods } from './' + +type ControllerMethods = ServerMethods + +export { defineHooks } + +export function defineController(methods: () => ControllerMethods): ControllerMethods +export function defineController>(deps: T, cb: (deps: Deps) => ControllerMethods): ControllerMethods & { inject: (d: Deps) => ControllerMethods } +export function defineController>(methods: () => ControllerMethods | T, cb?: (deps: Deps) => ControllerMethods) { + return typeof methods === 'function' ? methods() : { ...cb!(methods), inject: (d: Deps) => cb!(d) } +} diff --git a/packages/frourio/servers/noValidator/api/texts/controller.ts b/packages/frourio/servers/noValidator/api/texts/controller.ts new file mode 100644 index 0000000..edca134 --- /dev/null +++ b/packages/frourio/servers/noValidator/api/texts/controller.ts @@ -0,0 +1,6 @@ +import { defineController } from './$relay' + +// @ts-expect-error +export default defineController(() => ({ + get: ({ query }) => ({ status: 200, body: query.val }) +})) diff --git a/packages/frourio/servers/noValidator/api/texts/index.ts b/packages/frourio/servers/noValidator/api/texts/index.ts new file mode 100644 index 0000000..5ff9a66 --- /dev/null +++ b/packages/frourio/servers/noValidator/api/texts/index.ts @@ -0,0 +1,10 @@ +export type Methods = { + get: { + query: { + val: string + } + resBody: string + } + + put: {} +} diff --git a/packages/frourio/servers/noValidator/api/texts/sample/$relay.ts b/packages/frourio/servers/noValidator/api/texts/sample/$relay.ts new file mode 100644 index 0000000..26ca223 --- /dev/null +++ b/packages/frourio/servers/noValidator/api/texts/sample/$relay.ts @@ -0,0 +1,14 @@ +/* eslint-disable */ +import { Deps } from 'velona' +import { ServerMethods, defineHooks } from '../../../$app' +import { Methods } from './' + +type ControllerMethods = ServerMethods + +export { defineHooks } + +export function defineController(methods: () => ControllerMethods): ControllerMethods +export function defineController>(deps: T, cb: (deps: Deps) => ControllerMethods): ControllerMethods & { inject: (d: Deps) => ControllerMethods } +export function defineController>(methods: () => ControllerMethods | T, cb?: (deps: Deps) => ControllerMethods) { + return typeof methods === 'function' ? methods() : { ...cb!(methods), inject: (d: Deps) => cb!(d) } +} diff --git a/packages/frourio/servers/noValidator/api/texts/sample/controller.ts b/packages/frourio/servers/noValidator/api/texts/sample/controller.ts new file mode 100644 index 0000000..8aa3058 --- /dev/null +++ b/packages/frourio/servers/noValidator/api/texts/sample/controller.ts @@ -0,0 +1,7 @@ +import { defineController } from './$relay' + +export default defineController(() => ({ + // @ts-expect-error + get: ({ query }) => ({ status: 200, body: query.val }), + put: ({ body }) => ({ status: 200, body }) +})) diff --git a/packages/frourio/servers/noValidator/api/texts/sample/index.ts b/packages/frourio/servers/noValidator/api/texts/sample/index.ts new file mode 100644 index 0000000..8fb901b --- /dev/null +++ b/packages/frourio/servers/noValidator/api/texts/sample/index.ts @@ -0,0 +1,10 @@ +export type Methods = { + put: { + reqBody: { + id: string + } | null + resBody: { + id: string + } | null + } +} diff --git a/packages/frourio/servers/noValidator/api/users/$relay.ts b/packages/frourio/servers/noValidator/api/users/$relay.ts new file mode 100644 index 0000000..2f2292e --- /dev/null +++ b/packages/frourio/servers/noValidator/api/users/$relay.ts @@ -0,0 +1,17 @@ +/* eslint-disable */ +import { Deps } from 'velona' +import { ServerMethods, defineHooks } from '../../$app' +import { User } from './hooks' +import { Methods } from './' + +type ControllerMethods = ServerMethods + +export { defineHooks } + +export function defineController(methods: () => ControllerMethods): ControllerMethods +export function defineController>(deps: T, cb: (deps: Deps) => ControllerMethods): ControllerMethods & { inject: (d: Deps) => ControllerMethods } +export function defineController>(methods: () => ControllerMethods | T, cb?: (deps: Deps) => ControllerMethods) { + return typeof methods === 'function' ? methods() : { ...cb!(methods), inject: (d: Deps) => cb!(d) } +} diff --git a/packages/frourio/servers/noValidator/api/users/_userId@number/$relay.ts b/packages/frourio/servers/noValidator/api/users/_userId@number/$relay.ts new file mode 100644 index 0000000..b3fd1d5 --- /dev/null +++ b/packages/frourio/servers/noValidator/api/users/_userId@number/$relay.ts @@ -0,0 +1,20 @@ +/* eslint-disable */ +import { Deps } from 'velona' +import { ServerMethods, defineHooks } from '../../../$app' +import { User } from './../hooks' +import { Methods } from './' + +type ControllerMethods = ServerMethods + +export { defineHooks } + +export function defineController(methods: () => ControllerMethods): ControllerMethods +export function defineController>(deps: T, cb: (deps: Deps) => ControllerMethods): ControllerMethods & { inject: (d: Deps) => ControllerMethods } +export function defineController>(methods: () => ControllerMethods | T, cb?: (deps: Deps) => ControllerMethods) { + return typeof methods === 'function' ? methods() : { ...cb!(methods), inject: (d: Deps) => cb!(d) } +} diff --git a/packages/frourio/servers/noValidator/api/users/_userId@number/controller.ts b/packages/frourio/servers/noValidator/api/users/_userId@number/controller.ts new file mode 100644 index 0000000..047e709 --- /dev/null +++ b/packages/frourio/servers/noValidator/api/users/_userId@number/controller.ts @@ -0,0 +1,5 @@ +import { defineController } from './$relay' + +export default defineController(() => ({ + get: ({ params }) => ({ status: 200, body: { id: params.userId, name: 'bbb' } }) +})) diff --git a/packages/frourio/servers/noValidator/api/users/_userId@number/index.ts b/packages/frourio/servers/noValidator/api/users/_userId@number/index.ts new file mode 100644 index 0000000..ad9940f --- /dev/null +++ b/packages/frourio/servers/noValidator/api/users/_userId@number/index.ts @@ -0,0 +1,7 @@ +import { UserInfo } from '../../../validators' + +export type Methods = { + get: { + resBody: UserInfo + } +} diff --git a/packages/frourio/servers/noValidator/api/users/controller.ts b/packages/frourio/servers/noValidator/api/users/controller.ts new file mode 100644 index 0000000..7c9ed22 --- /dev/null +++ b/packages/frourio/servers/noValidator/api/users/controller.ts @@ -0,0 +1,17 @@ +import { defineController, defineHooks } from './$relay' + +const hooks = defineHooks(() => ({ + preHandler: [ + (req, res, next) => { + console.log('Controller level preHandler hook:', req.path) + next() + } + ] +})) + +export { hooks } + +export default defineController(() => ({ + get: async () => ({ status: 200, body: [{ id: 1, name: 'aa' }] }), + post: () => ({ status: 204 }) +})) diff --git a/packages/frourio/servers/noValidator/api/users/hooks.ts b/packages/frourio/servers/noValidator/api/users/hooks.ts new file mode 100644 index 0000000..036c246 --- /dev/null +++ b/packages/frourio/servers/noValidator/api/users/hooks.ts @@ -0,0 +1,15 @@ +import { defineHooks } from './$relay' + +export type User = { + id: number + name: string + role: 'admin' | 'user' +} + +export default defineHooks(() => ({ + onRequest: (req, res, next) => { + console.log('Added user') + ;(req as any).user = { id: 1, name: 'user name', role: 'admin' } + next() + } +})) diff --git a/packages/frourio/servers/noValidator/api/users/index.ts b/packages/frourio/servers/noValidator/api/users/index.ts new file mode 100644 index 0000000..4e7791b --- /dev/null +++ b/packages/frourio/servers/noValidator/api/users/index.ts @@ -0,0 +1,11 @@ +import { UserInfo } from '../../validators' + +export type Methods = { + get: { + resBody: UserInfo[] + } + + post: { + reqBody: UserInfo + } +} diff --git a/packages/frourio/servers/noValidator/validators.ts b/packages/frourio/servers/noValidator/validators.ts new file mode 100644 index 0000000..91cb25a --- /dev/null +++ b/packages/frourio/servers/noValidator/validators.ts @@ -0,0 +1,22 @@ +export type Query = { + id: string + disable: string +} + +export type Body = { + port: string + file: File +} + +export type UserInfo = { + id: number + name: string +} + +export type MultiForm = { + empty: number[] + name: string + icon: Blob + vals: string[] + files: Blob[] +} diff --git a/packages/frourio/src/buildServerFile.ts b/packages/frourio/src/buildServerFile.ts index 6c3c6e0..3d342fb 100644 --- a/packages/frourio/src/buildServerFile.ts +++ b/packages/frourio/src/buildServerFile.ts @@ -1,78 +1,297 @@ import path from 'path' -import { Template } from 'aspida/dist/buildTemplate' import createControllersText from './createControllersText' -import createTypeormText from './createTypeormText' -export default (input: string): Template => { - const typeormText = createTypeormText(input) +export default (input: string, project?: string) => { + const { imports, controllers } = createControllersText(`${input}/api`, project ?? input) + const hasNumberTypeQuery = controllers.includes(' parseNumberTypeQueryParams(') + const hasJSONBody = controllers.includes(' parseJSONBoby,') + const hasTypedParams = controllers.includes(' createTypedParamsHandler(') + const hasValidator = controllers.includes(' validateOrReject(') + const hasMulter = controllers.includes(' uploader,') return { - text: `/* eslint-disable */ -import 'reflect-metadata' -import { Server } from 'http' -import path from 'path' -import express, { Express } from 'express' -import multer from 'multer' -import helmet from 'helmet' -import cors from 'cors' -import { createConnection, Connection } from 'typeorm' -import { createRouter, Config } from 'frourio'${typeormText.imports} -${createControllersText(`${input}/api`)} - -export const entities = [${typeormText.entities}] -export const migrations = [${typeormText.migrations}] -export const subscribers = [${typeormText.subscribers}] -export const run = async (config: Config) => { - const app = express() - const router = createRouter( - controllers, - multer( - config.multer ?? { dest: path.join(__dirname, '.upload'), limits: { fileSize: 1024 ** 3 } } - ).any() - ) - - if (config.helmet) app.use(helmet(config.helmet === true ? {} : config.helmet)) - if (config.cors) app.use(cors(config.cors === true ? {} : config.cors)) - - app.use((req, res, next) => { - express.json()(req, res, err => { - if (err) return res.sendStatus(400) - - next() - }) - }) + text: `/* eslint-disable */${hasMulter ? "\nimport path from 'path'" : ''} +import { + LowerHttpMethod, + AspidaMethods, + HttpMethod, + HttpStatusOk, + AspidaMethodParams +} from 'aspida' +import { Deps } from 'velona' +import ${hasJSONBody ? 'express, ' : ''}{ Express, RequestHandler${ + hasValidator ? ', Request' : '' + } } from 'express'${hasMulter ? "\nimport multer, { Options } from 'multer'" : ''}${ + hasValidator ? "\nimport { validateOrReject } from 'class-validator'" : '' + } + +type Hooks = { + onRequest?: RequestHandler | RequestHandler[] + preParsing?: RequestHandler | RequestHandler[] + preValidation?: RequestHandler | RequestHandler[] + preHandler?: RequestHandler | RequestHandler[] + onSend?: RequestHandler | RequestHandler[] +} + +export function defineHooks(hooks: () => T): T +export function defineHooks>(deps: U, cb: (deps: Deps) => T): T & { inject: (d: Deps) => T } +export function defineHooks>(hooks: () => T | U, cb?: (deps: Deps) => T) { + return typeof hooks === 'function' ? hooks() : { ...cb!(hooks), inject: (d: Deps) => cb!(d) } +} + +${hasValidator ? `import * as Validators from './validators'${imports ? '\n' : ''}` : ''}${imports} + +export type FrourioOptions = { + basePath?: string +${ + hasMulter + ? ` multer?: Options +} + +export type MulterFile = Express.Multer.File` + : '}' +} + +type HttpStatusNoOk = + | 301 + | 302 + | 400 + | 401 + | 402 + | 403 + | 404 + | 405 + | 406 + | 409 + | 500 + | 501 + | 502 + | 503 + | 504 + | 505 + +type PartiallyPartial = Omit & Partial> + +type BaseResponse = { + status: V extends number ? V : HttpStatusOk + body: T + headers: U +} + +type ServerResponse = + | (K['resBody'] extends {} | null + ? K['resHeaders'] extends {} + ? BaseResponse + : PartiallyPartial< + BaseResponse< + K['resBody'], + K['resHeaders'] extends {} | undefined ? K['resHeaders'] : undefined, + K['status'] + >, + 'headers' + > + : K['resHeaders'] extends {} + ? PartiallyPartial< + BaseResponse< + K['resBody'] extends {} | null | undefined ? K['resBody'] : undefined, + K['resHeaders'], + K['status'] + >, + 'body' + > + : PartiallyPartial< + BaseResponse< + K['resBody'] extends {} | null | undefined ? K['resBody'] : undefined, + K['resHeaders'] extends {} | undefined ? K['resHeaders'] : undefined, + K['status'] + >, + 'body' | 'headers' + >) + | PartiallyPartial, 'body' | 'headers'> + +type ServerValues = { + params?: Record + user?: any +} +${ + hasMulter + ? ` +type BlobToFile = T['reqFormat'] extends FormData + ? { + [P in keyof T['reqBody']]: Required[P] extends Blob + ? MulterFile + : Required[P] extends Blob[] + ? MulterFile[] + : T['reqBody'][P] + } + : T['reqBody'] +` + : '' +} +type RequestParams = { + path: string + method: HttpMethod + query: T['query'] + body: ${hasMulter ? 'BlobToFile' : "T['reqBody']"} + headers: T['reqHeaders'] +} + +export type ServerMethods = { + [K in keyof T]: ( + req: RequestParams & U + ) => ServerResponse | Promise> +} +${ + hasNumberTypeQuery + ? ` +const parseNumberTypeQueryParams = (numberTypeParams: [string, boolean, boolean][]): RequestHandler => ({ query }, res, next) => { + for (const [key, isOptional, isArray] of numberTypeParams) { + const param = query[key] + + if (isArray) { + if (!isOptional && param === undefined) { + query[key] = [] + } else if (!isOptional || param !== undefined) { + if (!Array.isArray(param)) { + res.sendStatus(400) + return + } + + const vals = (param as string[]).map(Number) - const staticMiddleware = express.static(path.join(__dirname, 'public')) - if (config.basePath && config.basePath !== '/') { - const staticPath = config.basePath.startsWith('/') ? config.basePath : \`/\${config.basePath}\` - app.use(staticPath, router) - app.use(staticPath, staticMiddleware) - } else { - app.use(router) - app.use(staticMiddleware) + if (vals.some(isNaN)) { + res.sendStatus(400) + return + } + + query[key] = vals as any + } + } else if (!isOptional || param !== undefined) { + const val = Number(param) + + if (isNaN(val)) { + res.sendStatus(400) + return + } + + query[key] = val as any + } } - let connection: Connection + next() +} +` + : '' +}${ + hasJSONBody + ? ` +const parseJSONBoby: RequestHandler = (req, res, next) => { + express.json()(req, res, err => { + if (err) return res.sendStatus(400) - if (config.typeorm) { - connection = await createConnection({ - entities, - migrations, - subscribers, - ...config.typeorm - }) + next() + }) +} +` + : '' + }${ + hasTypedParams + ? ` +const createTypedParamsHandler = (numberTypeParams: string[]): RequestHandler => ( + req, + res, + next +) => { + const typedParams: Record = { ...req.params } + + for (const key of numberTypeParams) { + const val = Number(typedParams[key]) + if (isNaN(val)) { + res.sendStatus(400) + return + } + + typedParams[key] = val } - return new Promise<{ - app: Express - server: Server - connection?: Connection - }>(resolve => { - const server = app.listen(config.port, () => { - console.log(\`Frourio is running on http://localhost:\${config.port}\`) - resolve({ app, server, connection }) + ;(req as any).typedParams = typedParams + next() +} +` + : '' + }${ + hasValidator + ? ` +const createValidateHandler = (validators: (req: Request) => (Promise | null)[]): RequestHandler => + (req, res, next) => Promise.all(validators(req)).then(() => next()).catch(() => res.sendStatus(400)) +` + : '' + } +const methodsToHandler = ( + methodCallback: ServerMethods[LowerHttpMethod] +): RequestHandler => async (req, res) => { + try { + const result = methodCallback({ + query: req.query, + path: req.path, + method: req.method as HttpMethod, + body: req.body, + headers: req.headers, + params: (req as any).typedParams, + user: (req as any).user }) - }) + + const { status, body, headers } = result instanceof Promise ? await result : result + + for (const key in headers) { + res.setHeader(key, headers[key]) + } + + res.status(status).send(body) + } catch (e) { + res.sendStatus(500) + } +} +${ + hasMulter + ? ` +const formatMulterData = (arrayTypeKeys: [string, boolean][]): RequestHandler => ({ body, files }, _res, next) => { + for (const [key] of arrayTypeKeys) { + if (body[key] === undefined) body[key] = [] + else if (!Array.isArray(body[key])) { + body[key] = [body[key]] + } + } + + for (const file of files as MulterFile[]) { + if (Array.isArray(body[file.fieldname])) { + body[file.fieldname].push(file) + } else { + body[file.fieldname] = file + } + } + + for (const [key, isOptional] of arrayTypeKeys) { + if (!body[key].length && isOptional) delete body[key] + } + + next() +} +` + : '' +} +export default (app: Express, options: FrourioOptions = {}) => { + const basePath = options.basePath ?? '' +${ + hasMulter + ? ` const uploader = multer( + options.multer ?? { dest: path.join(__dirname, '.upload'), limits: { fileSize: 1024 ** 3 } } + ).any() +` + : '' +} +${controllers} + return app } `, filePath: path.posix.join(input, '$app.ts') diff --git a/packages/frourio/src/cli.ts b/packages/frourio/src/cli.ts index c6ded7b..5738dc4 100644 --- a/packages/frourio/src/cli.ts +++ b/packages/frourio/src/cli.ts @@ -1,31 +1,19 @@ import minimist from 'minimist' import write from 'aspida/dist/writeRouteFile' -import watch from 'aspida/dist/cli/watchInputDir' -import { Command, nullCommand } from 'aspida/dist/cli/command' -import { version as versionCommand } from 'aspida/dist/cli/version' +import watch from 'aspida/dist/watchInputDir' import build from './buildServerFile' -const options: minimist.Opts = { - string: ['version', 'dir', 'build', 'watch'], - alias: { v: 'version', d: 'dir', b: 'build', w: 'watch' } -} - export const run = (args: string[]) => { - const argv = minimist(args, options) - const dirs = ((argv.dir as string) ?? '.').split(',') - const commands: Command[] = [ - argv.version !== undefined ? versionCommand : nullCommand, - argv.build !== undefined ? { exec: () => dirs.forEach(dir => write(build(dir))) } : nullCommand, - argv.watch !== undefined - ? { - exec: () => - dirs.forEach(dir => { - write(build(dir)) - watch(dir, () => write(build(dir))) - }) - } - : nullCommand - ] + const argv = minimist(args, { + string: ['version', 'watch', 'project'], + alias: { v: 'version', w: 'watch', p: 'project' } + }) + const dir = '.' - commands.forEach(c => c.exec()) + // eslint-disable-next-line no-unused-expressions + argv.version !== undefined + ? console.log(`v${require('../package.json').version}`) + : argv.watch !== undefined + ? (write(build(dir, argv.project)), watch(dir, () => write(build(dir, argv.project)))) + : write(build(dir, argv.project)) } diff --git a/packages/frourio/src/createControllersText.ts b/packages/frourio/src/createControllersText.ts index a95ef64..32ca5d6 100644 --- a/packages/frourio/src/createControllersText.ts +++ b/packages/frourio/src/createControllersText.ts @@ -1,25 +1,48 @@ import path from 'path' import fs from 'fs' -import parseInterface from 'aspida/dist/parseInterface' +import ts from 'typescript' import createDefaultFiles from './createDefaultFilesIfNotExists' -export default (inputDir: string) => { - const middlewares: string[] = [] +const hooksEvents = ['onRequest', 'preParsing', 'preValidation', 'preHandler', 'onSend'] as const +type HooksEvent = typeof hooksEvents[number] + +export default (appDir: string, project: string) => { + const hooksList: string[] = [] const controllers: [string, boolean][] = [] - let hasValidators = false + const configDir = project.replace(/\/[^/]+\.json$/, '') + const configFileName = ts.findConfigFile( + configDir, + ts.sys.fileExists, + project.endsWith('.json') ? project.split('/').pop() : undefined + ) + + const compilerOptions = configFileName + ? ts.parseJsonConfigFileContent( + ts.readConfigFile(configFileName, ts.sys.readFile).config, + ts.sys, + configDir + ) + : undefined - const createText = (input: string, indent: string, params: [string, string][], user = '') => { - let result = '' + const createText = ( + dirPath: string, + hooks: { name: string; events: { type: HooksEvent; isArray: boolean }[] }[], + params: [string, string][], + appPath = '$app', + user = '' + ) => { + const input = path.posix.join(appDir, dirPath) + const appText = `../${appPath}` const userPath = - fs.existsSync(path.join(input, '@middleware.ts')) && - parseInterface(fs.readFileSync(path.join(input, '@middleware.ts'), 'utf8'), 'User') - ? './@middleware' + fs.existsSync(path.join(input, 'hooks.ts')) && + /(^|\n)export .+ User(,| )/.test(fs.readFileSync(path.join(input, 'hooks.ts'), 'utf8')) + ? './hooks' : user ? `./.${user}` : '' const relayPath = path.join(input, '$relay.ts') - const text = `/* eslint-disable */\nimport { RequestHandler } from 'express'\nimport { ServerMethods } from 'frourio'\n${ + const text = `/* eslint-disable */\nimport { Deps } from 'velona'\nimport { ServerMethods, defineHooks } from '${appText}'\n${ userPath ? `import { User } from '${userPath}'\n` : '' }import { Methods } from './'\n\ntype ControllerMethods = ServerMethods { : '' }}> -export const createMiddleware = < - T extends RequestHandler | [] | [RequestHandler, ...RequestHandler[]] ->(handler: T): T => handler +export { defineHooks } -export const createController = (methods: ControllerMethods) => methods - -export const createInjectableController = ( - cb: (deps: T) => ControllerMethods, - deps: T -) => ({ ...cb(deps), inject: (d: T) => cb(d) }) +export function defineController(methods: () => ControllerMethods): ControllerMethods +export function defineController>(deps: T, cb: (deps: Deps) => ControllerMethods): ControllerMethods & { inject: (d: Deps) => ControllerMethods } +export function defineController>(methods: () => ControllerMethods | T, cb?: (deps: Deps) => ControllerMethods) { + return typeof methods === 'function' ? methods() : { ...cb!(methods), inject: (d: Deps) => cb!(d) } +} ` if (!fs.existsSync(relayPath) || fs.readFileSync(relayPath, 'utf8') !== text) { @@ -47,122 +67,277 @@ export const createInjectableController = ( createDefaultFiles(input) - const validatorPrefix = 'Valid' - const methods = parseInterface(fs.readFileSync(path.join(input, 'index.ts'), 'utf8'), 'Methods') - if (methods) { - const validateInfo = methods - .map(m => { - const props: [string, { value: string; hasQuestion: boolean }][] = [] - if (m.props.query?.value.startsWith(validatorPrefix)) { - props.push(['query', m.props.query]) - } - if (m.props.reqBody?.value.startsWith(validatorPrefix)) { - props.push(['body', m.props.reqBody]) - } - if (m.props.reqHeaders?.value.startsWith(validatorPrefix)) { - props.push(['headers', m.props.reqHeaders]) + const indexFile = path.join(input, 'index.ts') + const hooksFile = path.join(input, 'hooks.ts') + const controllerFile = path.join(input, 'controller.ts') + const program = ts.createProgram( + [indexFile, hooksFile, controllerFile], + compilerOptions?.options + ? { baseUrl: compilerOptions?.options.baseUrl, paths: compilerOptions?.options.paths } + : {} + ) + const source = program.getSourceFile(indexFile) + const results: string[] = [] + + if (source) { + const checker = program.getTypeChecker() + const methods = ts.forEachChild(source, node => + (ts.isTypeAliasDeclaration(node) || ts.isInterfaceDeclaration(node)) && + node.name.escapedText === 'Methods' && + node.modifiers?.some(m => m.kind === ts.SyntaxKind.ExportKeyword) + ? checker.getTypeAtLocation(node).getProperties() + : undefined + ) + + if (methods?.length) { + const hooksSource = program.getSourceFile(hooksFile) + + if (hooksSource) { + const events = ts.forEachChild(hooksSource, node => { + if (ts.isExportAssignment(node)) { + return checker + .getTypeAtLocation(node.expression) + .getProperties() + .map(p => { + const typeNode = checker.typeToTypeNode( + checker.getTypeOfSymbolAtLocation(p, p.valueDeclaration), + undefined, + undefined + ) + + return { + type: p.name as HooksEvent, + isArray: typeNode + ? ts.isArrayTypeNode(typeNode) || ts.isTupleTypeNode(typeNode) + : false + } + }) + } + }) + + if (events) { + hooks.push({ name: `hooks${hooksList.length}`, events }) + hooksList.push(`${input}/hooks`) } - return { method: m.name, props } - }) - .filter(v => v.props.length) - - if (validateInfo.length) { - hasValidators = true - result += `,\n${indent}validator: {\n${validateInfo - .map( - v => - ` ${indent}${v.method}: {\n${v.props - .map( - p => - ` ${indent}${p[0]}: { required: ${!p[1].hasQuestion}, Class: Types.${ - p[1].value - } }` - ) - .join(',\n')}\n ${indent}}` - ) - .join(',\n')}\n${indent}}` - } + } - const uploaders = methods - .filter(m => m.props.reqFormat?.value === 'FormData') - .map(m => m.name) - if (uploaders.length) { - result += `,\n${indent}uploader: ['${uploaders.join("', '")}']` - } - } + const controllerSource = program.getSourceFile(controllerFile) + let ctrlHooksNode: ts.Node | undefined - result += `,\n${indent}controller: controller${controllers.length}` - const ctrlText = fs.readFileSync(path.join(input, '@controller.ts'), 'utf8') - const hasMiddleware = /export (const|{)(.*[ ,])?middleware[, }=]/.test(ctrlText) + if (controllerSource) { + ctrlHooksNode = ts.forEachChild(controllerSource, node => { + if ( + ts.isVariableStatement(node) && + node.modifiers?.some(m => m.kind === ts.SyntaxKind.ExportKeyword) + ) { + return node.declarationList.declarations.find(d => d.name.getText() === 'hooks') + } else if (ts.isExportDeclaration(node)) { + const { exportClause } = node + if (exportClause && ts.isNamedExports(exportClause)) { + return exportClause.elements.find(el => el.name.text === 'hooks') + } + } + }) + } - if (hasMiddleware) { - result += `,\n${indent}ctrlMiddleware: ctrlMiddleware${controllers.filter(c => c[1]).length}` - } + const ctrlHooksEvents = + ctrlHooksNode && + checker + .getTypeAtLocation(ctrlHooksNode) + .getProperties() + .map(p => { + const typeNode = checker.typeToTypeNode( + checker.getTypeOfSymbolAtLocation(p, p.valueDeclaration), + undefined, + undefined + ) + + return { + type: p.name as HooksEvent, + isArray: typeNode + ? ts.isArrayTypeNode(typeNode) || ts.isTupleTypeNode(typeNode) + : false + } + }) + + const genHookTexts = (event: HooksEvent) => [ + ...hooks.flatMap(h => { + const ev = h.events.find(e => e.type === event) + return ev ? [`${ev.isArray ? '...' : ''}${h.name}.${event}`] : [] + }), + ...(ctrlHooksEvents?.map(e => + e.type === event + ? `${e.isArray ? '...' : ''}ctrlHooks${controllers.filter(c => c[1]).length}.${event}` + : '' + ) ?? []) + ] + + results.push( + methods + .map(m => { + const props = checker.getTypeOfSymbolAtLocation(m, m.valueDeclaration).getProperties() + const query = props.find(p => p.name === 'query') + const numberTypeQueryParams = + query && + checker + .getTypeOfSymbolAtLocation(query, query.valueDeclaration) + .getProperties() + .map(p => { + const typeString = checker.typeToString( + checker.getTypeOfSymbolAtLocation(p, p.valueDeclaration) + ) + return typeString === 'number' + ? `['${p.name}', ${p.declarations.some(d => + d.getChildren().some(c => c.kind === ts.SyntaxKind.QuestionToken) + )}, false]` + : typeString === 'number[]' + ? `['${p.name}', ${p.declarations.some(d => + d.getChildren().some(c => c.kind === ts.SyntaxKind.QuestionToken) + )}, true]` + : null + }) + .filter(Boolean) + const validateInfo = [ + { name: 'query', val: query }, + { name: 'body', val: props.find(p => p.name === 'reqBody') }, + { name: 'headers', val: props.find(p => p.name === 'reqHeaders') } + ] + .filter((prop): prop is { name: string; val: ts.Symbol } => !!prop.val) + .map(({ name, val }) => ({ + name, + type: checker.getTypeOfSymbolAtLocation(val, val.valueDeclaration), + hasQuestion: val.declarations.some( + d => d.getChildAt(1).kind === ts.SyntaxKind.QuestionToken + ) + })) + .filter(({ type }) => type.isClass()) + + const reqFormat = props.find(p => p.name === 'reqFormat') + const isFormData = + (reqFormat && + checker.typeToString( + checker.getTypeOfSymbolAtLocation(reqFormat, reqFormat.valueDeclaration) + )) === 'FormData' + const reqBody = props.find(p => p.name === 'reqBody') + + const handlers = [ + ...genHookTexts('onRequest'), + ...(isFormData || (!reqFormat && reqBody) ? genHookTexts('preParsing') : []), + numberTypeQueryParams && numberTypeQueryParams.length + ? `parseNumberTypeQueryParams([${numberTypeQueryParams.join(', ')}])` + : '', + ...(isFormData && reqBody + ? [ + 'uploader', + `formatMulterData([${checker + .getTypeOfSymbolAtLocation(reqBody, reqBody.valueDeclaration) + .getProperties() + .map(p => { + const node = checker.typeToTypeNode( + checker.getTypeOfSymbolAtLocation(p, p.valueDeclaration), + undefined, + undefined + ) + + return node && (ts.isArrayTypeNode(node) || ts.isTupleTypeNode(node)) + ? `['${p.name}', ${p.declarations.some(d => + d.getChildren().some(c => c.kind === ts.SyntaxKind.QuestionToken) + )}]` + : undefined + }) + .filter(Boolean) + .join(', ')}])` + ] + : []), + !reqFormat && reqBody ? 'parseJSONBoby' : '', + ...(validateInfo.length || dirPath.includes('@number') + ? genHookTexts('preValidation') + : []), + validateInfo.length + ? `createValidateHandler(req => [ +${validateInfo + .map( + v => + ` ${ + v.hasQuestion ? `Object.keys(req.${v.name}).length ? ` : '' + }validateOrReject(Object.assign(new Validators.${checker.typeToString(v.type)}(), req.${ + v.name + }))${v.hasQuestion ? ' : null' : ''}` + ) + .join(',\n')}\n ])` + : '', + dirPath.includes('@number') + ? `createTypedParamsHandler(['${dirPath + .split('/') + .filter(p => p.includes('@number')) + .map(p => p.split('@')[0].slice(1)) + .join("', '")}'])` + : '', + ...genHookTexts('preHandler'), + `methodsToHandler(controller${controllers.length}.${m.name})`, + ...genHookTexts('onSend') + ].filter(Boolean) - controllers.push([`${input}/@controller`, hasMiddleware]) + return ` app.${m.name}(\`\${basePath}${`/${dirPath}` + .replace(/\/_/g, '/:') + .replace(/@.+?($|\/)/g, '')}\`, ${ + handlers.length === 1 ? handlers[0] : `[\n ${handlers.join(',\n ')}\n ]` + })\n` + }) + .join('\n') + ) - if (fs.existsSync(path.join(input, '@middleware.ts'))) { - result += `,\n${indent}middleware: middleware${middlewares.length}` - middlewares.push(`${input}/@middleware`) + controllers.push([`${input}/controller`, !!ctrlHooksEvents]) + } } const childrenDirs = fs - .readdirSync(input) - .filter(d => fs.statSync(path.join(input, d)).isDirectory() && !d.startsWith('@')) + .readdirSync(input, { withFileTypes: true }) + .filter(d => d.isDirectory() && !d.name.startsWith('@')) if (childrenDirs.length) { - result += `,\n${indent}children: {\n` - const names = childrenDirs.filter(d => !d.startsWith('_')) - if (names.length) { - result += ` ${indent}names: [\n` - result += names - .map( - n => - ` ${indent}{\n ${indent}name: '/${n}'${createText( - path.posix.join(input, n), - ` ${indent}`, - params, - userPath - )}\n ${indent}}` + results.push( + ...childrenDirs + .filter(d => !d.name.startsWith('_')) + .flatMap(d => + createText(path.posix.join(dirPath, d.name), hooks, params, appText, userPath) ) - .join(',\n') - result += `\n ${indent}]` - } + ) - const value = childrenDirs.find(d => d.startsWith('_')) + const value = childrenDirs.find(d => d.name.startsWith('_')) if (value) { - result += `${ - names.length ? ',\n' : '' - } ${indent}value: {\n ${indent}name: '/${value}'${createText( - path.posix.join(input, value), - ` ${indent}`, - [...params, [value.slice(1).split('@')[0], value.split('@')[1] ?? 'string']], - userPath - )}\n ${indent}}` + results.push( + ...createText( + path.posix.join(dirPath, value.name), + hooks, + [...params, [value.name.slice(1).split('@')[0], value.name.split('@')[1] ?? 'string']], + appText, + userPath + ) + ) } - result += `\n${indent}}` } - return result + return results } - const text = createText(inputDir, ' ', []) - const ctrlMiddleware = controllers.filter(c => c[1]) - - return `${hasValidators ? "import * as Types from './types'" : ''}${ - controllers.length ? '\n' : '' - }${controllers - .map( - (ctrl, i) => - `import controller${i}${ - ctrl[1] ? `, { middleware as ctrlMiddleware${ctrlMiddleware.indexOf(ctrl)} }` : '' - } from '${ctrl[0].replace(/^api/, './api').replace(inputDir, './api')}'` - ) - .join('\n')}${middlewares.length ? '\n' : ''}${middlewares - .map( - (m, i) => - `import middleware${i} from '${m.replace(/^api/, './api').replace(inputDir, './api')}'` - ) - .join('\n')}\n\nexport const controllers = {\n name: '/'${text}\n}` + const text = createText('', [], []).join('\n') + const ctrlHooks = controllers.filter(c => c[1]) + + return { + imports: `${controllers + .map( + (ctrl, i) => + `import controller${i}${ + ctrl[1] ? `, { hooks as ctrlHooks${ctrlHooks.indexOf(ctrl)} }` : '' + } from '${ctrl[0].replace(/^api/, './api').replace(appDir, './api')}'` + ) + .join('\n')}${hooksList.length ? '\n' : ''}${hooksList + .map( + (m, i) => `import hooks${i} from '${m.replace(/^api/, './api').replace(appDir, './api')}'` + ) + .join('\n')}`, + controllers: text + } } diff --git a/packages/frourio/src/createDefaultFilesIfNotExists.ts b/packages/frourio/src/createDefaultFilesIfNotExists.ts index 5a7ad00..b9468dd 100644 --- a/packages/frourio/src/createDefaultFilesIfNotExists.ts +++ b/packages/frourio/src/createDefaultFilesIfNotExists.ts @@ -1,29 +1,51 @@ import fs from 'fs' import path from 'path' -export default async (dir: string) => { +export default (dir: string) => { const indexFilePath = path.join(dir, 'index.ts') + if (!fs.existsSync(indexFilePath)) { - fs.promises.writeFile(indexFilePath, 'export type Methods = {}\n', 'utf8') + fs.writeFileSync( + indexFilePath, + `export type Methods = { + get: { + resBody: string + } +} +`, + 'utf8' + ) } - const controllerFilePath = path.join(dir, '@controller.ts') + const controllerFilePath = path.join(dir, 'controller.ts') + if (!fs.existsSync(controllerFilePath)) { - fs.promises.writeFile( + fs.writeFileSync( controllerFilePath, - "import { createController } from './$relay'\n\nexport default createController({})\n", + `import { defineController } from './$relay' + +export default defineController(() => ({ + get: () => ({ status: 200, body: 'Hello' }) +})) +`, 'utf8' ) } - const middlewareFilePath = path.join(dir, '@middleware.ts') - if ( - fs.existsSync(middlewareFilePath) && - !(await fs.promises.readFile(middlewareFilePath, 'utf8')) - ) { - fs.promises.writeFile( - middlewareFilePath, - "import { createMiddleware } from './$relay'\n\nexport default createMiddleware([])\n", + const hooksFilePath = path.join(dir, 'hooks.ts') + + if (fs.existsSync(hooksFilePath) && !fs.readFileSync(hooksFilePath, 'utf8')) { + fs.writeFileSync( + hooksFilePath, + `import { defineHooks } from './$relay' + +export default defineHooks(() => ({ + onRequest: (req, res, next) => { + console.log('Directory level onRequest hook:', req.path) + next() + } +})) +`, 'utf8' ) } diff --git a/packages/frourio/src/createTypeormText.ts b/packages/frourio/src/createTypeormText.ts deleted file mode 100644 index 6182a1c..0000000 --- a/packages/frourio/src/createTypeormText.ts +++ /dev/null @@ -1,65 +0,0 @@ -import fs from 'fs' -import path from 'path' -import { listFiles } from './listFiles' - -const getFileName = (name: string) => path.basename(name, path.extname(name)) - -export default (inputDir: string) => { - const entities = fs.existsSync(`${inputDir}/entity`) ? listFiles(`${inputDir}/entity`) : [] - const migrations = fs.existsSync(`${inputDir}/migration`) - ? listFiles(`${inputDir}/migration`) - : [] - const subscribers = fs.existsSync(`${inputDir}/subscriber`) - ? listFiles(`${inputDir}/subscriber`) - : [] - - entities.forEach(async e => { - if (await fs.promises.readFile(e, 'utf8')) return - - await fs.promises.writeFile( - e, - `import { Entity, PrimaryGeneratedColumn, Column } from 'typeorm' - -@Entity() -export class ${getFileName(e)} { - @PrimaryGeneratedColumn() - id: number - - @Column({ length: 100 }) - name: string -} -`, - 'utf8' - ) - }) - - const imports = `${entities - .map( - (e, i) => - `\nimport { ${getFileName(e)} as Entity${i} } from '${e - .replace(inputDir, '.') - .replace('.ts', '')}'` - ) - .join('')}${migrations - .map((m, i) => { - const names = getFileName(m).split('-') - return `\nimport { ${names[1]}${names[0]} as Migration${i} } from '${m - .replace(inputDir, '.') - .replace('.ts', '')}'` - }) - .join('')}${subscribers - .map( - (s, i) => - `\nimport { ${getFileName(s)} as Subscriber${i} } from '${s - .replace(inputDir, '.') - .replace('.ts', '')}'` - ) - .join('')}` - - return { - imports, - entities: entities.map((_, i) => `Entity${i}`).join(', '), - migrations: migrations.map((_, i) => `Migration${i}`).join(', '), - subscribers: subscribers.map((_, i) => `Subscriber${i}`).join(', ') - } -} diff --git a/packages/frourio/src/index.ts b/packages/frourio/src/index.ts deleted file mode 100644 index f8da45e..0000000 --- a/packages/frourio/src/index.ts +++ /dev/null @@ -1,306 +0,0 @@ -import { - LowerHttpMethod, - AspidaMethods, - HttpMethod, - HttpStatusOk, - AspidaMethodParams, - $arrayTypeKeysName -} from 'aspida' -import express, { RequestHandler, Router } from 'express' -import { validateOrReject } from 'class-validator' -import { ConnectionOptions } from 'typeorm' -import { IHelmetConfiguration } from 'helmet' -import { CorsOptions } from 'cors' -import { Options } from 'multer' - -export type File = Express.Multer.File - -export type Config = { - port: number | string - basePath?: string - helmet?: boolean | IHelmetConfiguration - cors?: boolean | CorsOptions - typeorm?: ConnectionOptions - multer?: Options -} - -type HttpStatusNoOk = - | 301 - | 302 - | 400 - | 401 - | 402 - | 403 - | 404 - | 405 - | 406 - | 409 - | 500 - | 501 - | 502 - | 503 - | 504 - | 505 - -type PartiallyPartial = Omit & Partial> - -type BaseResponse = { - status: V extends number ? V : HttpStatusOk - body: T - headers: U -} - -type ServerResponse = - | (K['resBody'] extends {} | null - ? K['resHeaders'] extends {} - ? BaseResponse - : PartiallyPartial< - BaseResponse< - K['resBody'], - K['resHeaders'] extends {} | undefined ? K['resHeaders'] : undefined, - K['status'] - >, - 'headers' - > - : K['resHeaders'] extends {} - ? PartiallyPartial< - BaseResponse< - K['resBody'] extends {} | null | undefined ? K['resBody'] : undefined, - K['resHeaders'], - K['status'] - >, - 'body' - > - : PartiallyPartial< - BaseResponse< - K['resBody'] extends {} | null | undefined ? K['resBody'] : undefined, - K['resHeaders'] extends {} | undefined ? K['resHeaders'] : undefined, - K['status'] - >, - 'body' | 'headers' - >) - | PartiallyPartial, 'body' | 'headers'> - -type ServerValues = { - params?: Record - user?: any -} - -type BlobToFile = T['reqFormat'] extends FormData - ? { - [P in keyof T['reqBody']]: Required[P] extends Blob - ? File - : Required[P] extends Blob[] - ? File[] - : T['reqBody'][P] - } - : T['reqBody'] - -type RequestParams = { - path: string - method: HttpMethod - query: T['query'] - body: BlobToFile - headers: T['reqHeaders'] -} - -export type ServerMethods = { - [K in keyof T]: ( - req: RequestParams & U - ) => ServerResponse | Promise> -} - -type Validator = { - required: boolean - Class: any -} - -type Validators = { - query?: Validator - body?: Validator - headers?: Validator -} - -type ControllerTree = { - name: string - controller?: ServerMethods - ctrlMiddleware?: RequestHandler | RequestHandler[] - uploader?: string[] - validator?: { [K in LowerHttpMethod]?: Validators } - middleware?: RequestHandler | RequestHandler[] - children?: { - names?: ControllerTree[] - value?: ControllerTree - } -} - -const createValidateHandler = (validator: Validators | undefined): RequestHandler => ( - req, - res, - next -) => - Promise.all([ - validator?.query && - (Object.keys(req.query).length || validator.query.required ? true : undefined) && - validateOrReject(Object.assign(new validator.query.Class(), req.query)), - validator?.headers && - (Object.keys(req.headers).length || validator.headers.required ? true : undefined) && - validateOrReject(Object.assign(new validator.headers.Class(), req.headers)), - validator?.body && - (Object.keys(req.body).length || validator.body.required ? true : undefined) && - validateOrReject(Object.assign(new validator.body.Class(), req.body)) - ]) - .then(() => next()) - .catch(() => res.sendStatus(400)) - -const createTypedParamsHandler = (numberTypeParams: string[]): RequestHandler => async ( - req, - res, - next -) => { - const typedParams: Record = { ...req.params } - - for (const key of numberTypeParams) { - const val = Number(typedParams[key]) - if (isNaN(val)) { - res.sendStatus(400) - return - } - - typedParams[key] = val - } - - ;(req as any).typedParams = typedParams - next() -} - -const methodsToHandler = ( - methodCallback: ServerMethods[LowerHttpMethod] -): RequestHandler => async (req, res) => { - try { - const result = methodCallback({ - query: req.query, - path: req.path, - method: req.method as HttpMethod, - body: req.body, - headers: req.headers, - params: (req as any).typedParams, - user: (req as any).user - }) - - const { status, body, headers } = result instanceof Promise ? await result : result - - for (const key in headers) { - res.setHeader(key, headers[key]) - } - - res.status(status).send(body) - } catch (e) { - res.sendStatus(500) - } -} - -const formatMulterData: RequestHandler = ({ body, files }, _res, next) => { - if (body[$arrayTypeKeysName]) { - const arrayTypeKeys: string[] = body[$arrayTypeKeysName].split(',') - - for (const key of arrayTypeKeys) { - if (body[key] === undefined) body[key] = [] - else if (!Array.isArray(body[key])) { - body[key] = [body[key]] - } - } - - for (const file of files) { - if (Array.isArray(body[file.fieldname])) { - body[file.fieldname].push(file) - } else { - body[file.fieldname] = file - } - } - - delete body[$arrayTypeKeysName] - } else { - for (const file of files) { - if (Array.isArray(body[file.fieldname])) { - body[file.fieldname].push(file) - } else { - body[file.fieldname] = - body[file.fieldname] === undefined ? file : [body[file.fieldname], file] - } - } - } - - next() -} - -export const createRouter = ( - ctrl: ControllerTree, - uploader: RequestHandler, - numberTypeParams: string[] = [] -): Router => { - const router = express.Router({ mergeParams: true }) - - if (ctrl.middleware) { - ;(Array.isArray(ctrl.middleware) ? ctrl.middleware : [ctrl.middleware]).forEach(handler => { - router.use(handler) - }) - } - - if (ctrl.controller) { - const typedParamsHandler = createTypedParamsHandler(numberTypeParams) - const ctrlMiddlewareList = Array.isArray(ctrl.ctrlMiddleware) - ? ctrl.ctrlMiddleware - : ctrl.ctrlMiddleware - ? [ctrl.ctrlMiddleware] - : [] - - for (const method in ctrl.controller) { - const validateHandler = createValidateHandler(ctrl.validator?.[method as LowerHttpMethod]) - const handler = methodsToHandler(ctrl.controller[method]) - - ;(router.route('/') as any)[method]( - ctrl.uploader?.includes(method) - ? [ - uploader, - formatMulterData, - validateHandler, - typedParamsHandler, - ...ctrlMiddlewareList, - handler - ] - : [validateHandler, typedParamsHandler, ...ctrlMiddlewareList, handler] - ) - } - } - - if (ctrl.children) { - // eslint-disable-next-line no-unused-expressions - ctrl.children.names?.forEach(n => { - router.use(n.name, createRouter(n, uploader, numberTypeParams)) - }) - - if (ctrl.children.value) { - const pathName = ctrl.children.value.name.replace('_', ':').split('@') - router.use( - pathName[0], - createRouter( - ctrl.children.value, - uploader, - pathName[1] === 'number' ? [...numberTypeParams, pathName[0].slice(2)] : numberTypeParams - ) - ) - } - } - - return router -} - -export const createInjectableFunction = ( - cb: (deps: V, ...params: T) => U, - deps: V -) => { - const fn = (...args: T) => cb(deps, ...args) - fn.inject = (d: V) => (...args: T) => cb(d, ...args) - return fn -} diff --git a/packages/frourio/src/listFiles.ts b/packages/frourio/src/listFiles.ts deleted file mode 100644 index 120af28..0000000 --- a/packages/frourio/src/listFiles.ts +++ /dev/null @@ -1,10 +0,0 @@ -import fs from 'fs' -import path from 'path' - -export const listFiles = (targetDir: string): string[] => - fs.readdirSync(targetDir, { withFileTypes: true }).flatMap(dirent => { - const target = path.posix.join(targetDir, dirent.name) - return dirent.isFile() - ? [targetDir.startsWith('.') ? `./${target}` : target] - : listFiles(target) - }) diff --git a/packages/frourio/tsconfig.json b/packages/frourio/tsconfig.json index a7efd23..e0d6637 100644 --- a/packages/frourio/tsconfig.json +++ b/packages/frourio/tsconfig.json @@ -1,5 +1,7 @@ { "extends": "../../tsconfig.json", - "compilerOptions": { "outDir": "dist" }, + "compilerOptions": { + "outDir": "dist" + }, "include": ["src/**/*"] } diff --git a/tsconfig.benchmark.json b/tsconfig.benchmark.json new file mode 100644 index 0000000..2270394 --- /dev/null +++ b/tsconfig.benchmark.json @@ -0,0 +1,14 @@ +{ + "extends": "./tsconfig.json", + "compilerOptions": { + "declaration": false, + "declarationMap": false, + "sourceMap": false, + "outDir": "benchmark", + "target": "es2018" + }, + "include": [ + "packages/frourio/servers/frourio/**/*", + "packages/frourio/servers/frourio.ts", + ] +} diff --git a/tsconfig.json b/tsconfig.json index 4deebb6..24e2a1a 100644 --- a/tsconfig.json +++ b/tsconfig.json @@ -6,9 +6,15 @@ "experimentalDecorators": true, "emitDecoratorMetadata": true, "esModuleInterop": true, + "resolveJsonModule": true, "lib": ["esnext", "dom"], "module": "commonjs", "moduleResolution": "node", + "baseUrl": ".", + "paths": { + "~/*": ["packages/frourio/servers/all/api/*"], + "validators": ["packages/frourio/servers/all/validators"] + }, "sourceMap": true, "strict": true, "strictPropertyInitialization": false, diff --git a/yarn.lock b/yarn.lock index 6f4e189..cf01cd5 100644 --- a/yarn.lock +++ b/yarn.lock @@ -2,12 +2,12 @@ # yarn lockfile v1 -"@aspida/axios@^0.9.4": - version "0.9.4" - resolved "https://registry.yarnpkg.com/@aspida/axios/-/axios-0.9.4.tgz#9a51a2c6ced10d3d8f00d8e33b02ed01534e6e83" - integrity sha512-lK9DHj+wvuv2y7JWzHAiyWdOLPrWKf4EjmeFmVhc7SpmwhNJ81XeZMLzl+wgjMPCP2UrT9cSxgTyjgp7MOtdGQ== +"@aspida/axios@^0.11.3": + version "0.11.3" + resolved "https://registry.yarnpkg.com/@aspida/axios/-/axios-0.11.3.tgz#f24e3fb3ac08c367ce4704b9603f897589407fc0" + integrity sha512-AGZvqQWdIzwvnizRSfN673/Nn5ivZZPoLBlS6mzAAWYwx2cFy1YrExb+v7n3owHAb/g1HMagT2mwMV/GooWPGA== dependencies: - aspida "^0.19.4" + aspida "^0.21.3" "@babel/code-frame@^7.0.0", "@babel/code-frame@^7.10.1": version "7.10.1" @@ -103,6 +103,11 @@ resolved "https://registry.yarnpkg.com/@babel/helper-plugin-utils/-/helper-plugin-utils-7.10.1.tgz#ec5a5cf0eec925b66c60580328b122c01230a127" integrity sha512-fvoGeXt0bJc7VMWZGCAEBEMo/HAjW2mP8apF5eXK0wSqwLAVHAISCWRoLMBMUs2kqeaG77jltVqu4Hn8Egl3nA== +"@babel/helper-plugin-utils@^7.10.4": + version "7.10.4" + resolved "https://registry.yarnpkg.com/@babel/helper-plugin-utils/-/helper-plugin-utils-7.10.4.tgz#2f75a831269d4f677de49986dff59927533cf375" + integrity sha512-O4KCvQA6lLiMU9l2eawBPMf1xPP8xPfB3iEQw150hOVTqj/rfXz0ThTb4HEzqQfs2Bmo5Ay8BzxfzVtBrr9dVg== + "@babel/helper-replace-supers@^7.10.1": version "7.10.1" resolved "https://registry.yarnpkg.com/@babel/helper-replace-supers/-/helper-replace-supers-7.10.1.tgz#ec6859d20c5d8087f6a2dc4e014db7228975f13d" @@ -177,6 +182,13 @@ dependencies: "@babel/helper-plugin-utils" "^7.10.1" +"@babel/plugin-syntax-import-meta@^7.8.3": + version "7.10.4" + resolved "https://registry.yarnpkg.com/@babel/plugin-syntax-import-meta/-/plugin-syntax-import-meta-7.10.4.tgz#ee601348c370fa334d2207be158777496521fd51" + integrity sha512-Yqfm+XDx0+Prh3VSeEQCPU81yC+JWZ2pDPFSS4ZdpfZhp4MkFMaDC1UqseovEKwSUpnIL7+vK+Clp7bfh0iD7g== + dependencies: + "@babel/helper-plugin-utils" "^7.10.4" + "@babel/plugin-syntax-json-strings@^7.8.3": version "7.8.3" resolved "https://registry.yarnpkg.com/@babel/plugin-syntax-json-strings/-/plugin-syntax-json-strings-7.8.3.tgz#01ca21b668cd8218c9e640cb6dd88c5412b2c96a" @@ -226,13 +238,6 @@ dependencies: "@babel/helper-plugin-utils" "^7.8.0" -"@babel/runtime@^7.9.6": - version "7.10.3" - resolved "https://registry.yarnpkg.com/@babel/runtime/-/runtime-7.10.3.tgz#670d002655a7c366540c67f6fd3342cd09500364" - integrity sha512-RzGO0RLSdokm9Ipe/YD+7ww8X2Ro79qiXZF3HU9ljrM+qnJmH1Vqth+hbiQZy761LnMJTMitHDuKVYTk3k4dLw== - dependencies: - regenerator-runtime "^0.13.4" - "@babel/template@^7.10.1", "@babel/template@^7.3.3": version "7.10.1" resolved "https://registry.yarnpkg.com/@babel/template/-/template-7.10.1.tgz#e167154a94cb5f14b28dc58f5356d2162f539811" @@ -279,141 +284,21 @@ exec-sh "^0.3.2" minimist "^1.2.0" -"@commitlint/cli@^9.1.1": - version "9.1.1" - resolved "https://registry.yarnpkg.com/@commitlint/cli/-/cli-9.1.1.tgz#24277e6c1e616191a34a7182a1d3e73369a34f98" - integrity sha512-ye9vUZz8Niv77e5ecBWnA2PnuPF+vYy/3BfSZx8sEaNjozJWUolTk/fuqTsoij3bseZBVObd+cVqZgGk8lfEdw== - dependencies: - "@babel/runtime" "^7.9.6" - "@commitlint/format" "^9.1.1" - "@commitlint/lint" "^9.1.1" - "@commitlint/load" "^9.1.1" - "@commitlint/read" "^9.1.1" - chalk "4.1.0" - core-js "^3.6.1" - get-stdin "7.0.0" - lodash "^4.17.15" - meow "5.0.0" - regenerator-runtime "0.13.5" - resolve-from "5.0.0" - resolve-global "1.0.0" - -"@commitlint/config-conventional@^9.1.1": - version "9.1.1" - resolved "https://registry.yarnpkg.com/@commitlint/config-conventional/-/config-conventional-9.1.1.tgz#c10e6ff8e56bd462fa33e17522b0f98da97daa39" - integrity sha512-t/bvv8ofjj7V4W99eVDyuACaC7Ch4SYaukglBYt/K1Y9Ixg8mCBuFDMGRMhyZn4upUe1ls8l4SO3rjaVbYIjlg== - dependencies: - conventional-changelog-conventionalcommits "4.3.0" - -"@commitlint/ensure@^9.1.1": - version "9.1.1" - resolved "https://registry.yarnpkg.com/@commitlint/ensure/-/ensure-9.1.1.tgz#0143f2c34a27fcd7fb91b7a5029de84a0f416b93" - integrity sha512-dCvev16s7pTqM3Qka8WkWkjZ0lKu3cZ8q+EK34gXR90v7rkssVbPvbyttTfTWTvmQTqZY1zNkvMqbOc8V7pXwA== - dependencies: - "@commitlint/types" "^9.1.1" - lodash "^4.17.15" - -"@commitlint/execute-rule@^9.1.1": - version "9.1.1" - resolved "https://registry.yarnpkg.com/@commitlint/execute-rule/-/execute-rule-9.1.1.tgz#59bfe018d85545881e4bd1a47f9cd155b2df4c2c" - integrity sha512-kCncHMXfVDfmUx1NExl7T+s7udAWEOh039DFGR9R5MWoy+zm2cJsCdsbWFFuNbcPWCKor57ywdIUN2t048P6Yg== - -"@commitlint/format@^9.1.1": - version "9.1.1" - resolved "https://registry.yarnpkg.com/@commitlint/format/-/format-9.1.1.tgz#a1a48bcdcaca304ff33d40bbf2b787600e47082e" - integrity sha512-CLVXltSA8U7Sr+8ad1hBCFFL5GSdVWZsFgttt1hNT6CiOtPHV9e3AeWK0TACFcXWIl+iFKdRNfNrYM77RBJN0A== - dependencies: - chalk "^4.0.0" - -"@commitlint/is-ignored@^9.1.1": - version "9.1.1" - resolved "https://registry.yarnpkg.com/@commitlint/is-ignored/-/is-ignored-9.1.1.tgz#1f2683897dab03ec00d363486b4b439791a86927" - integrity sha512-A2ernvkAIfkGh53cNSuuMlTVZyJ58BYbkUw8h34pG0uS/GDteUyh7K3hgRqMmrwoL/DNBEp5earRM6nBYgLX1Q== - dependencies: - "@commitlint/types" "^9.1.1" - semver "7.3.2" - -"@commitlint/lint@^9.1.1": - version "9.1.1" - resolved "https://registry.yarnpkg.com/@commitlint/lint/-/lint-9.1.1.tgz#c947a1b1a68213488450a4c4ce047e46a45c4699" - integrity sha512-2g2OL8J5dfzH3VY004i506DmRbCJR1W49JbYsTGuTAv1y9f0s8ocV2Wbfh7WJ8YZQabSHXTMZFQJjsvMQ+b0Hw== - dependencies: - "@commitlint/is-ignored" "^9.1.1" - "@commitlint/parse" "^9.1.1" - "@commitlint/rules" "^9.1.1" - "@commitlint/types" "^9.1.1" - -"@commitlint/load@^9.1.1": - version "9.1.1" - resolved "https://registry.yarnpkg.com/@commitlint/load/-/load-9.1.1.tgz#8b1580ab821729bbe197e95f960e7cee966402ae" - integrity sha512-RCIX44M8nq3bW98vuxA6C2rM0wAnZlneFls2OVi5l2BvD/rsQ2R9CZYwPt/MYU6RbwMmlGhkuHdScwK6pJeUqA== - dependencies: - "@commitlint/execute-rule" "^9.1.1" - "@commitlint/resolve-extends" "^9.1.1" - "@commitlint/types" "^9.1.1" - chalk "4.1.0" - cosmiconfig "^6.0.0" - lodash "^4.17.15" - resolve-from "^5.0.0" - -"@commitlint/message@^9.1.1": - version "9.1.1" - resolved "https://registry.yarnpkg.com/@commitlint/message/-/message-9.1.1.tgz#7621e8f194d676d7d747bfdda49c00ca4d1572df" - integrity sha512-52Li4BNSY55I0fAq1s8cnxIK9Jneozdh4oonLlDzqWvgFq8znsHb9LWmi46K0bsCQT3CRUnMU+GPnikghIMRKQ== - -"@commitlint/parse@^9.1.1": - version "9.1.1" - resolved "https://registry.yarnpkg.com/@commitlint/parse/-/parse-9.1.1.tgz#ec2b9527eb42725591976bedbed5bccfcde529bd" - integrity sha512-WxvsEi7sMBh8vynamTiHvUOsPOUZ5308pi0gJ5q+DnLY+JPx0Bbxdho9pjyVc3S0bymPCbOrk2gTIbmaTokIRQ== - dependencies: - conventional-changelog-angular "^5.0.0" - conventional-commits-parser "^3.0.0" - -"@commitlint/read@^9.1.1": - version "9.1.1" - resolved "https://registry.yarnpkg.com/@commitlint/read/-/read-9.1.1.tgz#de20c32e9f7020ecaf1601c5e06a83c74464b161" - integrity sha512-cg75klW1WNBAJZABxacf2FhxAlP0di7xs/wuTqPNq0OTpblhY5s2BoS7eO0UlQi1K14Unx7b9+Sb7sjuE9Viyw== - dependencies: - "@commitlint/top-level" "^9.1.1" - fs-extra "^8.1.0" - git-raw-commits "^2.0.0" - -"@commitlint/resolve-extends@^9.1.1": - version "9.1.1" - resolved "https://registry.yarnpkg.com/@commitlint/resolve-extends/-/resolve-extends-9.1.1.tgz#8ce703fcd2426ab1f5449906442267e18c995430" - integrity sha512-IxxNaSUT+dPhSCQPAMpQyHQlcSVikDxQWJFP6uwGJUU5rQff+0yQTuC3taWI2NWaATukjNWboAbH2vgBDnrDrg== - dependencies: - import-fresh "^3.0.0" - lodash "^4.17.15" - resolve-from "^5.0.0" - resolve-global "^1.0.0" - -"@commitlint/rules@^9.1.1": - version "9.1.1" - resolved "https://registry.yarnpkg.com/@commitlint/rules/-/rules-9.1.1.tgz#21165c9dc8621a52fa57eec9a66e01c83ec58f90" - integrity sha512-QicTJ9v4g8WbJ71gu2ypvbdEP6Q+cJYlLPrb6ilNhtOMCyn6ndXSlCMpcQNw84d9ORyd28okzhDZZBSqX5hslg== - dependencies: - "@commitlint/ensure" "^9.1.1" - "@commitlint/message" "^9.1.1" - "@commitlint/to-lines" "^9.1.1" - "@commitlint/types" "^9.1.1" - -"@commitlint/to-lines@^9.1.1": - version "9.1.1" - resolved "https://registry.yarnpkg.com/@commitlint/to-lines/-/to-lines-9.1.1.tgz#882631657ea4e14aea8600e7d48c4fbfb3e63c2d" - integrity sha512-JFKfpehPL3Qrlo6DpIsuJvdtR1wSjdbXD3liphvFTAFWo64yYC/jmnTdy0UqWIhrV1jcxP1LzNejIuRt6hsCXQ== - -"@commitlint/top-level@^9.1.1": - version "9.1.1" - resolved "https://registry.yarnpkg.com/@commitlint/top-level/-/top-level-9.1.1.tgz#5b825515381d70972189e549b0a9d57542afe996" - integrity sha512-pIgAbGqHbOunTGiUzBPhIKfXrTWdCrVwsimECXy/If5XaZ3GHhxiiA7BxsWFlAN1UZ6PgVMPgymKU0kx2D5A/w== +"@eslint/eslintrc@^0.1.3": + version "0.1.3" + resolved "https://registry.yarnpkg.com/@eslint/eslintrc/-/eslintrc-0.1.3.tgz#7d1a2b2358552cc04834c0979bd4275362e37085" + integrity sha512-4YVwPkANLeNtRjMekzux1ci8hIaH5eGKktGqR0d3LWsKNn5B2X/1Z6Trxy7jQXl9EBGE6Yj02O+t09FMeRllaA== dependencies: - find-up "^4.0.0" - -"@commitlint/types@^9.1.1": - version "9.1.1" - resolved "https://registry.yarnpkg.com/@commitlint/types/-/types-9.1.1.tgz#d97ebc35d20eed6d8458361cbca5c7cb85d45184" - integrity sha512-SXY8bCQ1qacJ8AUTUxjabY8G6OjSmMPLN9MBCzGaKOjpPNX6z8zbXTbk9oU3GHZLtcxweWLCi2n49IRS4iQlwg== + ajv "^6.12.4" + debug "^4.1.1" + espree "^7.3.0" + globals "^12.1.0" + ignore "^4.0.6" + import-fresh "^3.2.1" + js-yaml "^3.13.1" + lodash "^4.17.19" + minimatch "^3.0.4" + strip-json-comments "^3.1.1" "@istanbuljs/load-nyc-config@^1.0.0": version "1.1.0" @@ -431,89 +316,93 @@ resolved "https://registry.yarnpkg.com/@istanbuljs/schema/-/schema-0.1.2.tgz#26520bf09abe4a5644cd5414e37125a8954241dd" integrity sha512-tsAQNx32a8CoFhjhijUIhI4kccIAgmGhy8LZMZgGfmXcpMbPRUqn5LWmgRttILi6yeGmBJd2xsPkFMs0PzgPCw== -"@jest/console@^26.1.0": - version "26.1.0" - resolved "https://registry.yarnpkg.com/@jest/console/-/console-26.1.0.tgz#f67c89e4f4d04dbcf7b052aed5ab9c74f915b954" - integrity sha512-+0lpTHMd/8pJp+Nd4lyip+/Iyf2dZJvcCqrlkeZQoQid+JlThA4M9vxHtheyrQ99jJTMQam+es4BcvZ5W5cC3A== +"@jest/console@^26.3.0": + version "26.3.0" + resolved "https://registry.yarnpkg.com/@jest/console/-/console-26.3.0.tgz#ed04063efb280c88ba87388b6f16427c0a85c856" + integrity sha512-/5Pn6sJev0nPUcAdpJHMVIsA8sKizL2ZkcKPE5+dJrCccks7tcM7c9wbgHudBJbxXLoTbqsHkG1Dofoem4F09w== dependencies: - "@jest/types" "^26.1.0" + "@jest/types" "^26.3.0" + "@types/node" "*" chalk "^4.0.0" - jest-message-util "^26.1.0" - jest-util "^26.1.0" + jest-message-util "^26.3.0" + jest-util "^26.3.0" slash "^3.0.0" -"@jest/core@^26.1.0": - version "26.1.0" - resolved "https://registry.yarnpkg.com/@jest/core/-/core-26.1.0.tgz#4580555b522de412a7998b3938c851e4f9da1c18" - integrity sha512-zyizYmDJOOVke4OO/De//aiv8b07OwZzL2cfsvWF3q9YssfpcKfcnZAwDY8f+A76xXSMMYe8i/f/LPocLlByfw== +"@jest/core@^26.4.2": + version "26.4.2" + resolved "https://registry.yarnpkg.com/@jest/core/-/core-26.4.2.tgz#85d0894f31ac29b5bab07aa86806d03dd3d33edc" + integrity sha512-sDva7YkeNprxJfepOctzS8cAk9TOekldh+5FhVuXS40+94SHbiicRO1VV2tSoRtgIo+POs/Cdyf8p76vPTd6dg== dependencies: - "@jest/console" "^26.1.0" - "@jest/reporters" "^26.1.0" - "@jest/test-result" "^26.1.0" - "@jest/transform" "^26.1.0" - "@jest/types" "^26.1.0" + "@jest/console" "^26.3.0" + "@jest/reporters" "^26.4.1" + "@jest/test-result" "^26.3.0" + "@jest/transform" "^26.3.0" + "@jest/types" "^26.3.0" + "@types/node" "*" ansi-escapes "^4.2.1" chalk "^4.0.0" exit "^0.1.2" graceful-fs "^4.2.4" - jest-changed-files "^26.1.0" - jest-config "^26.1.0" - jest-haste-map "^26.1.0" - jest-message-util "^26.1.0" + jest-changed-files "^26.3.0" + jest-config "^26.4.2" + jest-haste-map "^26.3.0" + jest-message-util "^26.3.0" jest-regex-util "^26.0.0" - jest-resolve "^26.1.0" - jest-resolve-dependencies "^26.1.0" - jest-runner "^26.1.0" - jest-runtime "^26.1.0" - jest-snapshot "^26.1.0" - jest-util "^26.1.0" - jest-validate "^26.1.0" - jest-watcher "^26.1.0" + jest-resolve "^26.4.0" + jest-resolve-dependencies "^26.4.2" + jest-runner "^26.4.2" + jest-runtime "^26.4.2" + jest-snapshot "^26.4.2" + jest-util "^26.3.0" + jest-validate "^26.4.2" + jest-watcher "^26.3.0" micromatch "^4.0.2" p-each-series "^2.1.0" rimraf "^3.0.0" slash "^3.0.0" strip-ansi "^6.0.0" -"@jest/environment@^26.1.0": - version "26.1.0" - resolved "https://registry.yarnpkg.com/@jest/environment/-/environment-26.1.0.tgz#378853bcdd1c2443b4555ab908cfbabb851e96da" - integrity sha512-86+DNcGongbX7ai/KE/S3/NcUVZfrwvFzOOWX/W+OOTvTds7j07LtC+MgGydH5c8Ri3uIrvdmVgd1xFD5zt/xA== +"@jest/environment@^26.3.0": + version "26.3.0" + resolved "https://registry.yarnpkg.com/@jest/environment/-/environment-26.3.0.tgz#e6953ab711ae3e44754a025f838bde1a7fd236a0" + integrity sha512-EW+MFEo0DGHahf83RAaiqQx688qpXgl99wdb8Fy67ybyzHwR1a58LHcO376xQJHfmoXTu89M09dH3J509cx2AA== dependencies: - "@jest/fake-timers" "^26.1.0" - "@jest/types" "^26.1.0" - jest-mock "^26.1.0" + "@jest/fake-timers" "^26.3.0" + "@jest/types" "^26.3.0" + "@types/node" "*" + jest-mock "^26.3.0" -"@jest/fake-timers@^26.1.0": - version "26.1.0" - resolved "https://registry.yarnpkg.com/@jest/fake-timers/-/fake-timers-26.1.0.tgz#9a76b7a94c351cdbc0ad53e5a748789f819a65fe" - integrity sha512-Y5F3kBVWxhau3TJ825iuWy++BAuQzK/xEa+wD9vDH3RytW9f2DbMVodfUQC54rZDX3POqdxCgcKdgcOL0rYUpA== +"@jest/fake-timers@^26.3.0": + version "26.3.0" + resolved "https://registry.yarnpkg.com/@jest/fake-timers/-/fake-timers-26.3.0.tgz#f515d4667a6770f60ae06ae050f4e001126c666a" + integrity sha512-ZL9ytUiRwVP8ujfRepffokBvD2KbxbqMhrXSBhSdAhISCw3gOkuntisiSFv+A6HN0n0fF4cxzICEKZENLmW+1A== dependencies: - "@jest/types" "^26.1.0" + "@jest/types" "^26.3.0" "@sinonjs/fake-timers" "^6.0.1" - jest-message-util "^26.1.0" - jest-mock "^26.1.0" - jest-util "^26.1.0" + "@types/node" "*" + jest-message-util "^26.3.0" + jest-mock "^26.3.0" + jest-util "^26.3.0" -"@jest/globals@^26.1.0": - version "26.1.0" - resolved "https://registry.yarnpkg.com/@jest/globals/-/globals-26.1.0.tgz#6cc5d7cbb79b76b120f2403d7d755693cf063ab1" - integrity sha512-MKiHPNaT+ZoG85oMaYUmGHEqu98y3WO2yeIDJrs2sJqHhYOy3Z6F7F/luzFomRQ8SQ1wEkmahFAz2291Iv8EAw== +"@jest/globals@^26.4.2": + version "26.4.2" + resolved "https://registry.yarnpkg.com/@jest/globals/-/globals-26.4.2.tgz#73c2a862ac691d998889a241beb3dc9cada40d4a" + integrity sha512-Ot5ouAlehhHLRhc+sDz2/9bmNv9p5ZWZ9LE1pXGGTCXBasmi5jnYjlgYcYt03FBwLmZXCZ7GrL29c33/XRQiow== dependencies: - "@jest/environment" "^26.1.0" - "@jest/types" "^26.1.0" - expect "^26.1.0" + "@jest/environment" "^26.3.0" + "@jest/types" "^26.3.0" + expect "^26.4.2" -"@jest/reporters@^26.1.0": - version "26.1.0" - resolved "https://registry.yarnpkg.com/@jest/reporters/-/reporters-26.1.0.tgz#08952e90c90282e14ff49e927bdf1873617dae78" - integrity sha512-SVAysur9FOIojJbF4wLP0TybmqwDkdnFxHSPzHMMIYyBtldCW9gG+Q5xWjpMFyErDiwlRuPyMSJSU64A67Pazg== +"@jest/reporters@^26.4.1": + version "26.4.1" + resolved "https://registry.yarnpkg.com/@jest/reporters/-/reporters-26.4.1.tgz#3b4d6faf28650f3965f8b97bc3d114077fb71795" + integrity sha512-aROTkCLU8++yiRGVxLsuDmZsQEKO6LprlrxtAuzvtpbIFl3eIjgIf3EUxDKgomkS25R9ZzwGEdB5weCcBZlrpQ== dependencies: "@bcoe/v8-coverage" "^0.2.3" - "@jest/console" "^26.1.0" - "@jest/test-result" "^26.1.0" - "@jest/transform" "^26.1.0" - "@jest/types" "^26.1.0" + "@jest/console" "^26.3.0" + "@jest/test-result" "^26.3.0" + "@jest/transform" "^26.3.0" + "@jest/types" "^26.3.0" chalk "^4.0.0" collect-v8-coverage "^1.0.0" exit "^0.1.2" @@ -524,63 +413,63 @@ istanbul-lib-report "^3.0.0" istanbul-lib-source-maps "^4.0.0" istanbul-reports "^3.0.2" - jest-haste-map "^26.1.0" - jest-resolve "^26.1.0" - jest-util "^26.1.0" - jest-worker "^26.1.0" + jest-haste-map "^26.3.0" + jest-resolve "^26.4.0" + jest-util "^26.3.0" + jest-worker "^26.3.0" slash "^3.0.0" source-map "^0.6.0" string-length "^4.0.1" terminal-link "^2.0.0" - v8-to-istanbul "^4.1.3" + v8-to-istanbul "^5.0.1" optionalDependencies: - node-notifier "^7.0.0" + node-notifier "^8.0.0" -"@jest/source-map@^26.1.0": - version "26.1.0" - resolved "https://registry.yarnpkg.com/@jest/source-map/-/source-map-26.1.0.tgz#a6a020d00e7d9478f4b690167c5e8b77e63adb26" - integrity sha512-XYRPYx4eEVX15cMT9mstnO7hkHP3krNtKfxUYd8L7gbtia8JvZZ6bMzSwa6IQJENbudTwKMw5R1BePRD+bkEmA== +"@jest/source-map@^26.3.0": + version "26.3.0" + resolved "https://registry.yarnpkg.com/@jest/source-map/-/source-map-26.3.0.tgz#0e646e519883c14c551f7b5ae4ff5f1bfe4fc3d9" + integrity sha512-hWX5IHmMDWe1kyrKl7IhFwqOuAreIwHhbe44+XH2ZRHjrKIh0LO5eLQ/vxHFeAfRwJapmxuqlGAEYLadDq6ZGQ== dependencies: callsites "^3.0.0" graceful-fs "^4.2.4" source-map "^0.6.0" -"@jest/test-result@^26.1.0": - version "26.1.0" - resolved "https://registry.yarnpkg.com/@jest/test-result/-/test-result-26.1.0.tgz#a93fa15b21ad3c7ceb21c2b4c35be2e407d8e971" - integrity sha512-Xz44mhXph93EYMA8aYDz+75mFbarTV/d/x0yMdI3tfSRs/vh4CqSxgzVmCps1fPkHDCtn0tU8IH9iCKgGeGpfw== +"@jest/test-result@^26.3.0": + version "26.3.0" + resolved "https://registry.yarnpkg.com/@jest/test-result/-/test-result-26.3.0.tgz#46cde01fa10c0aaeb7431bf71e4a20d885bc7fdb" + integrity sha512-a8rbLqzW/q7HWheFVMtghXV79Xk+GWwOK1FrtimpI5n1la2SY0qHri3/b0/1F0Ve0/yJmV8pEhxDfVwiUBGtgg== dependencies: - "@jest/console" "^26.1.0" - "@jest/types" "^26.1.0" + "@jest/console" "^26.3.0" + "@jest/types" "^26.3.0" "@types/istanbul-lib-coverage" "^2.0.0" collect-v8-coverage "^1.0.0" -"@jest/test-sequencer@^26.1.0": - version "26.1.0" - resolved "https://registry.yarnpkg.com/@jest/test-sequencer/-/test-sequencer-26.1.0.tgz#41a6fc8b850c3f33f48288ea9ea517c047e7f14e" - integrity sha512-Z/hcK+rTq56E6sBwMoQhSRDVjqrGtj1y14e2bIgcowARaIE1SgOanwx6gvY4Q9gTKMoZQXbXvptji+q5GYxa6Q== +"@jest/test-sequencer@^26.4.2": + version "26.4.2" + resolved "https://registry.yarnpkg.com/@jest/test-sequencer/-/test-sequencer-26.4.2.tgz#58a3760a61eec758a2ce6080201424580d97cbba" + integrity sha512-83DRD8N3M0tOhz9h0bn6Kl6dSp+US6DazuVF8J9m21WAp5x7CqSMaNycMP0aemC/SH/pDQQddbsfHRTBXVUgog== dependencies: - "@jest/test-result" "^26.1.0" + "@jest/test-result" "^26.3.0" graceful-fs "^4.2.4" - jest-haste-map "^26.1.0" - jest-runner "^26.1.0" - jest-runtime "^26.1.0" + jest-haste-map "^26.3.0" + jest-runner "^26.4.2" + jest-runtime "^26.4.2" -"@jest/transform@^26.1.0": - version "26.1.0" - resolved "https://registry.yarnpkg.com/@jest/transform/-/transform-26.1.0.tgz#697f48898c2a2787c9b4cb71d09d7e617464e509" - integrity sha512-ICPm6sUXmZJieq45ix28k0s+d/z2E8CHDsq+WwtWI6kW8m7I8kPqarSEcUN86entHQ570ZBRci5OWaKL0wlAWw== +"@jest/transform@^26.3.0": + version "26.3.0" + resolved "https://registry.yarnpkg.com/@jest/transform/-/transform-26.3.0.tgz#c393e0e01459da8a8bfc6d2a7c2ece1a13e8ba55" + integrity sha512-Isj6NB68QorGoFWvcOjlUhpkT56PqNIsXKR7XfvoDlCANn/IANlh8DrKAA2l2JKC3yWSMH5wS0GwuQM20w3b2A== dependencies: "@babel/core" "^7.1.0" - "@jest/types" "^26.1.0" + "@jest/types" "^26.3.0" babel-plugin-istanbul "^6.0.0" chalk "^4.0.0" convert-source-map "^1.4.0" fast-json-stable-stringify "^2.0.0" graceful-fs "^4.2.4" - jest-haste-map "^26.1.0" + jest-haste-map "^26.3.0" jest-regex-util "^26.0.0" - jest-util "^26.1.0" + jest-util "^26.3.0" micromatch "^4.0.2" pirates "^4.0.1" slash "^3.0.0" @@ -607,6 +496,38 @@ "@types/yargs" "^15.0.0" chalk "^4.0.0" +"@jest/types@^26.3.0": + version "26.3.0" + resolved "https://registry.yarnpkg.com/@jest/types/-/types-26.3.0.tgz#97627bf4bdb72c55346eef98e3b3f7ddc4941f71" + integrity sha512-BDPG23U0qDeAvU4f99haztXwdAg3hz4El95LkAM+tHAqqhiVzRpEGHHU8EDxT/AnxOrA65YjLBwDahdJ9pTLJQ== + dependencies: + "@types/istanbul-lib-coverage" "^2.0.0" + "@types/istanbul-reports" "^3.0.0" + "@types/node" "*" + "@types/yargs" "^15.0.0" + chalk "^4.0.0" + +"@nodelib/fs.scandir@2.1.3": + version "2.1.3" + resolved "https://registry.yarnpkg.com/@nodelib/fs.scandir/-/fs.scandir-2.1.3.tgz#3a582bdb53804c6ba6d146579c46e52130cf4a3b" + integrity sha512-eGmwYQn3gxo4r7jdQnkrrN6bY478C3P+a/y72IJukF8LjB6ZHeB3c+Ehacj3sYeSmUXGlnA67/PmbM9CVwL7Dw== + dependencies: + "@nodelib/fs.stat" "2.0.3" + run-parallel "^1.1.9" + +"@nodelib/fs.stat@2.0.3", "@nodelib/fs.stat@^2.0.2": + version "2.0.3" + resolved "https://registry.yarnpkg.com/@nodelib/fs.stat/-/fs.stat-2.0.3.tgz#34dc5f4cabbc720f4e60f75a747e7ecd6c175bd3" + integrity sha512-bQBFruR2TAwoevBEd/NWMoAAtNGzTRgdrqnYCc7dhzfoNvqPzLyqlEQnzZ3kVnNrSp25iyxE00/3h2fqGAGArA== + +"@nodelib/fs.walk@^1.2.3": + version "1.2.4" + resolved "https://registry.yarnpkg.com/@nodelib/fs.walk/-/fs.walk-1.2.4.tgz#011b9202a70a6366e436ca5c065844528ab04976" + integrity sha512-1V9XOY4rDW0rehzbrcqAmHnz8e7SKvX27gh8Gt2WgB0+pdzdiLV83p72kZPU+jvMbS1qU5mauP2iOvO8rhmurQ== + dependencies: + "@nodelib/fs.scandir" "2.1.3" + fastq "^1.6.0" + "@sinonjs/commons@^1.7.0": version "1.8.0" resolved "https://registry.yarnpkg.com/@sinonjs/commons/-/commons-1.8.0.tgz#c8d68821a854c555bba172f3b06959a0039b236d" @@ -685,47 +606,16 @@ dependencies: "@types/node" "*" -"@types/cors@^2.8.6": - version "2.8.6" - resolved "https://registry.yarnpkg.com/@types/cors/-/cors-2.8.6.tgz#cfaab33c49c15b1ded32f235111ce9123009bd02" - integrity sha512-invOmosX0DqbpA+cE2yoHGUlF/blyf7nB0OGYBBiH27crcVm5NmFaZkLP4Ta1hGaesckCi5lVLlydNJCxkTOSg== - dependencies: - "@types/express" "*" - -"@types/eslint-visitor-keys@^1.0.0": - version "1.0.0" - resolved "https://registry.yarnpkg.com/@types/eslint-visitor-keys/-/eslint-visitor-keys-1.0.0.tgz#1ee30d79544ca84d68d4b3cdb0af4f205663dd2d" - integrity sha512-OCutwjDZ4aFS6PB1UZ988C4YgwlBHJd6wCeQqaLdmadZ/7e+w79+hbMUFC1QXDNCmdyoRfAFdm0RypzwR+Qpag== - "@types/express-serve-static-core@*": - version "4.17.7" - resolved "https://registry.yarnpkg.com/@types/express-serve-static-core/-/express-serve-static-core-4.17.7.tgz#dfe61f870eb549dc6d7e12050901847c7d7e915b" - integrity sha512-EMgTj/DF9qpgLXyc+Btimg+XoH7A2liE8uKul8qSmMTHCeNYzydDKFdsJskDvw42UsesCnhO63dO0Grbj8J4Dw== - dependencies: - "@types/node" "*" - "@types/qs" "*" - "@types/range-parser" "*" - -"@types/express-serve-static-core@^4.17.8": - version "4.17.8" - resolved "https://registry.yarnpkg.com/@types/express-serve-static-core/-/express-serve-static-core-4.17.8.tgz#b8f7b714138536742da222839892e203df569d1c" - integrity sha512-1SJZ+R3Q/7mLkOD9ewCBDYD2k0WyZQtWYqF/2VvoNN2/uhI49J9CDN4OAm+wGMA0DbArA4ef27xl4+JwMtGggw== + version "4.17.9" + resolved "https://registry.yarnpkg.com/@types/express-serve-static-core/-/express-serve-static-core-4.17.9.tgz#2d7b34dcfd25ec663c25c85d76608f8b249667f1" + integrity sha512-DG0BYg6yO+ePW+XoDENYz8zhNGC3jDDEpComMYn7WJc4mY1Us8Rw9ax2YhJXxpyk2SF47PQAoQ0YyVT1a0bEkA== dependencies: "@types/node" "*" "@types/qs" "*" "@types/range-parser" "*" -"@types/express@*": - version "4.17.6" - resolved "https://registry.yarnpkg.com/@types/express/-/express-4.17.6.tgz#6bce49e49570507b86ea1b07b806f04697fac45e" - integrity sha512-n/mr9tZI83kd4azlPG5y997C/M4DNABK9yErhFM6hKdym4kkmd9j0vtsJyjFIwfRBxtrxZtAfGZCNRIBMFLK5w== - dependencies: - "@types/body-parser" "*" - "@types/express-serve-static-core" "*" - "@types/qs" "*" - "@types/serve-static" "*" - -"@types/express@^4.17.7": +"@types/express@*", "@types/express@^4.17.7": version "4.17.7" resolved "https://registry.yarnpkg.com/@types/express/-/express-4.17.7.tgz#42045be6475636d9801369cd4418ef65cdb0dd59" integrity sha512-dCOT5lcmV/uC2J9k0rPafATeeyz+99xTt54ReX11/LObZgfzJqZNcW27zGhYyX+9iSEGXGt5qLPwRSvBZcLvtQ== @@ -742,13 +632,6 @@ dependencies: "@types/node" "*" -"@types/helmet@^0.0.47": - version "0.0.47" - resolved "https://registry.yarnpkg.com/@types/helmet/-/helmet-0.0.47.tgz#ec5161541b649142205b7c558bca14801c5ce129" - integrity sha512-TcHA/djjdUtrMtq/QAayVLrsgjNNZ1Uhtz0KhfH01mrmjH44E54DA1A0HNbwW0H/NBFqV+tGMo85ACuEhMXcdg== - dependencies: - "@types/express" "*" - "@types/istanbul-lib-coverage@*", "@types/istanbul-lib-coverage@^2.0.0", "@types/istanbul-lib-coverage@^2.0.1": version "2.0.2" resolved "https://registry.yarnpkg.com/@types/istanbul-lib-coverage/-/istanbul-lib-coverage-2.0.2.tgz#79d7a78bad4219f4c03d6557a1c72d9ca6ba62d5" @@ -769,10 +652,25 @@ "@types/istanbul-lib-coverage" "*" "@types/istanbul-lib-report" "*" -"@types/jest@^26.0.4": - version "26.0.4" - resolved "https://registry.yarnpkg.com/@types/jest/-/jest-26.0.4.tgz#d2e513e85aca16992816f192582b5e67b0b15efb" - integrity sha512-4fQNItvelbNA9+sFgU+fhJo8ZFF+AS4Egk3GWwCW2jFtViukXbnztccafAdLhzE/0EiCogljtQQXP8aQ9J7sFg== +"@types/istanbul-reports@^3.0.0": + version "3.0.0" + resolved "https://registry.yarnpkg.com/@types/istanbul-reports/-/istanbul-reports-3.0.0.tgz#508b13aa344fa4976234e75dddcc34925737d821" + integrity sha512-nwKNbvnwJ2/mndE9ItP/zc2TCzw6uuodnF4EHYWD+gCQDVBuRQL5UzbZD0/ezy1iKsFU2ZQiDqg4M9dN4+wZgA== + dependencies: + "@types/istanbul-lib-report" "*" + +"@types/jest@26.x": + version "26.0.10" + resolved "https://registry.yarnpkg.com/@types/jest/-/jest-26.0.10.tgz#8faf7e9756c033c39014ae76a7329efea00ea607" + integrity sha512-i2m0oyh8w/Lum7wWK/YOZJakYF8Mx08UaKA1CtbmFeDquVhAEdA7znacsVSf2hJ1OQ/OfVMGN90pw/AtzF8s/Q== + dependencies: + jest-diff "^25.2.1" + pretty-format "^25.2.1" + +"@types/jest@^26.0.13": + version "26.0.13" + resolved "https://registry.yarnpkg.com/@types/jest/-/jest-26.0.13.tgz#5a7b9d5312f5dd521a38329c38ee9d3802a0b85e" + integrity sha512-sCzjKow4z9LILc6DhBvn5AkIfmQzDZkgtVVKmGwVrs5tuid38ws281D4l+7x1kP487+FlKDh5kfMZ8WSPAdmdA== dependencies: jest-diff "^25.2.1" pretty-format "^25.2.1" @@ -788,19 +686,19 @@ integrity sha1-7ihweulOEdK4J7y+UnC86n8+ce4= "@types/mime@*": - version "2.0.2" - resolved "https://registry.yarnpkg.com/@types/mime/-/mime-2.0.2.tgz#857a118d8634c84bba7ae14088e4508490cd5da5" - integrity sha512-4kPlzbljFcsttWEq6aBW0OZe6BDajAmyvr2xknBG92tejQnvdGtT9+kXSZ580DqpxY9qG2xeQVF9Dq0ymUTo5Q== + version "2.0.3" + resolved "https://registry.yarnpkg.com/@types/mime/-/mime-2.0.3.tgz#c893b73721db73699943bfc3653b1deb7faa4a3a" + integrity sha512-Jus9s4CDbqwocc5pOAnh8ShfrnMcPHuJYzVcSUU7lrh8Ni5HuIqX3oilL86p3dlTrk0LzHRCgA/GQ7uNCw6l2Q== "@types/minimist@^1.2.0": version "1.2.0" resolved "https://registry.yarnpkg.com/@types/minimist/-/minimist-1.2.0.tgz#69a23a3ad29caf0097f06eda59b361ee2f0639f6" integrity sha1-aaI6OtKcrwCX8G7aWbNh7i8GOfY= -"@types/multer@^1.4.3": - version "1.4.3" - resolved "https://registry.yarnpkg.com/@types/multer/-/multer-1.4.3.tgz#bdff74b334c38a8ee1de9fbedb5d1d3dbc377422" - integrity sha512-tWsKbF5LYtXrJ7eOfI0aLBgEv9B7fnJe1JRXTj5+Z6EMfX0yHVsRFsNGnKyN8Bs0gtDv+JR37xAqsPnALyVTqg== +"@types/multer@^1.4.4": + version "1.4.4" + resolved "https://registry.yarnpkg.com/@types/multer/-/multer-1.4.4.tgz#bb5d9abc410da82726ceca74008bb81813349a88" + integrity sha512-wdfkiKBBEMTODNbuF3J+qDDSqJxt50yB9pgDiTcFew7f97Gcc7/sM4HR66ofGgpJPOALWOqKAch4gPyqEXSkeQ== dependencies: "@types/express" "*" @@ -814,20 +712,15 @@ resolved "https://registry.yarnpkg.com/@types/normalize-package-data/-/normalize-package-data-2.4.0.tgz#e486d0d97396d79beedd0a6e33f4534ff6b4973e" integrity sha512-f5j5b/Gf71L+dbqxIpQ4Z2WlmI/mPJ0fOkGGmFgtb6sAu97EPczzbS3/tJKxmcYDj55OX6ssqwDAWOHIYDRDGA== -"@types/parse-json@^4.0.0": - version "4.0.0" - resolved "https://registry.yarnpkg.com/@types/parse-json/-/parse-json-4.0.0.tgz#2f8bb441434d163b35fb8ffdccd7138927ffb8c0" - integrity sha512-//oorEZjL6sbPcKUaCdIGlIUeH26mgzimjBB77G6XRgnDl/L5wOnpyBGRe/Mmf5CVW3PwEBE1NjiMZ/ssFh4wA== - "@types/prettier@^2.0.0": version "2.0.1" resolved "https://registry.yarnpkg.com/@types/prettier/-/prettier-2.0.1.tgz#b6e98083f13faa1e5231bfa3bdb1b0feff536b6d" integrity sha512-boy4xPNEtiw6N3abRhBi/e7hNvy3Tt8E9ZRAQrwAGzoCGZS/1wjo9KY7JHhnfnEsG5wSjDbymCozUM9a3ea7OQ== "@types/qs@*": - version "6.9.3" - resolved "https://registry.yarnpkg.com/@types/qs/-/qs-6.9.3.tgz#b755a0934564a200d3efdf88546ec93c369abd03" - integrity sha512-7s9EQWupR1fTc2pSMtXRQ9w9gLOcrJn+h7HOXw4evxyvVqMi4f+q7d2tnFe3ng3SNHjtK+0EzGMGFUQX4/AQRA== + version "6.9.4" + resolved "https://registry.yarnpkg.com/@types/qs/-/qs-6.9.4.tgz#a59e851c1ba16c0513ea123830dd639a0a15cb6a" + integrity sha512-+wYo+L6ZF6BMoEjtf8zB2esQsqdV6WsjRK/GP9WOgLPrq87PbNWgIxS76dS5uvl/QXtHGakZmwTznIfcPXcKlQ== "@types/range-parser@*": version "1.2.3" @@ -835,9 +728,9 @@ integrity sha512-ewFXqrQHlFsgc09MK5jP5iR7vumV/BYayNC6PgJO2LPe8vrnNFyjQjSppfEngITi0qvfKtzFvgKymGheFM9UOA== "@types/serve-static@*": - version "1.13.4" - resolved "https://registry.yarnpkg.com/@types/serve-static/-/serve-static-1.13.4.tgz#6662a93583e5a6cabca1b23592eb91e12fa80e7c" - integrity sha512-jTDt0o/YbpNwZbQmE/+2e+lfjJEJJR0I3OFaKQKPWkASkCoW3i6fsUnqudSMcNAfbtmADGu8f4MV4q+GqULmug== + version "1.13.5" + resolved "https://registry.yarnpkg.com/@types/serve-static/-/serve-static-1.13.5.tgz#3d25d941a18415d3ab092def846e135a08bbcf53" + integrity sha512-6M64P58N+OXjU432WoLLBQxbA0LRGBCRm7aAGQJ+SMC1IMl0dgRVi9EFfoDcS2a7Xogygk/eGN94CfwU9UF7UQ== dependencies: "@types/express-serve-static-core" "*" "@types/mime" "*" @@ -864,88 +757,122 @@ dependencies: "@types/yargs-parser" "*" -"@typescript-eslint/eslint-plugin@^3.6.1": - version "3.6.1" - resolved "https://registry.yarnpkg.com/@typescript-eslint/eslint-plugin/-/eslint-plugin-3.6.1.tgz#5ced8fd2087fbb83a76973dea4a0d39d9cb4a642" - integrity sha512-06lfjo76naNeOMDl+mWG9Fh/a0UHKLGhin+mGaIw72FUMbMGBkdi/FEJmgEDzh4eE73KIYzHWvOCYJ0ak7nrJQ== +"@typescript-eslint/eslint-plugin@^4.1.0": + version "4.1.0" + resolved "https://registry.yarnpkg.com/@typescript-eslint/eslint-plugin/-/eslint-plugin-4.1.0.tgz#7d309f60815ff35e9627ad85e41928d7b7fd443f" + integrity sha512-U+nRJx8XDUqJxYF0FCXbpmD9nWt/xHDDG0zsw1vrVYAmEAuD/r49iowfurjSL2uTA2JsgtpsyG7mjO7PHf2dYw== dependencies: - "@typescript-eslint/experimental-utils" "3.6.1" + "@typescript-eslint/experimental-utils" "4.1.0" + "@typescript-eslint/scope-manager" "4.1.0" debug "^4.1.1" functional-red-black-tree "^1.0.1" regexpp "^3.0.0" semver "^7.3.2" tsutils "^3.17.1" -"@typescript-eslint/experimental-utils@3.6.1": - version "3.6.1" - resolved "https://registry.yarnpkg.com/@typescript-eslint/experimental-utils/-/experimental-utils-3.6.1.tgz#b5a2738ebbceb3fa90c5b07d50bb1225403c4a54" - integrity sha512-oS+hihzQE5M84ewXrTlVx7eTgc52eu+sVmG7ayLfOhyZmJ8Unvf3osyFQNADHP26yoThFfbxcibbO0d2FjnYhg== +"@typescript-eslint/experimental-utils@4.1.0": + version "4.1.0" + resolved "https://registry.yarnpkg.com/@typescript-eslint/experimental-utils/-/experimental-utils-4.1.0.tgz#263d7225645c09a411c8735eeffd417f50f49026" + integrity sha512-paEYLA37iqRIDPeQwAmoYSiZ3PiHsaAc3igFeBTeqRHgPnHjHLJ9OGdmP6nwAkF65p2QzEsEBtpjNUBWByNWzA== dependencies: "@types/json-schema" "^7.0.3" - "@typescript-eslint/types" "3.6.1" - "@typescript-eslint/typescript-estree" "3.6.1" + "@typescript-eslint/scope-manager" "4.1.0" + "@typescript-eslint/types" "4.1.0" + "@typescript-eslint/typescript-estree" "4.1.0" eslint-scope "^5.0.0" eslint-utils "^2.0.0" -"@typescript-eslint/experimental-utils@^2.5.0": - version "2.34.0" - resolved "https://registry.yarnpkg.com/@typescript-eslint/experimental-utils/-/experimental-utils-2.34.0.tgz#d3524b644cdb40eebceca67f8cf3e4cc9c8f980f" - integrity sha512-eS6FTkq+wuMJ+sgtuNTtcqavWXqsflWcfBnlYhg/nS4aZ1leewkXGbvBhaapn1q6qf4M71bsR1tez5JTRMuqwA== +"@typescript-eslint/experimental-utils@^4.0.1": + version "4.0.1" + resolved "https://registry.yarnpkg.com/@typescript-eslint/experimental-utils/-/experimental-utils-4.0.1.tgz#7d9a3ab6821ad5274dad2186c1aa0d93afd696eb" + integrity sha512-gAqOjLiHoED79iYTt3F4uSHrYmg/GPz/zGezdB0jAdr6S6gwNiR/j7cTZ8nREKVzMVKLd9G3xbg1sV9GClW3sw== dependencies: "@types/json-schema" "^7.0.3" - "@typescript-eslint/typescript-estree" "2.34.0" + "@typescript-eslint/scope-manager" "4.0.1" + "@typescript-eslint/types" "4.0.1" + "@typescript-eslint/typescript-estree" "4.0.1" eslint-scope "^5.0.0" eslint-utils "^2.0.0" -"@typescript-eslint/parser@^3.6.1": - version "3.6.1" - resolved "https://registry.yarnpkg.com/@typescript-eslint/parser/-/parser-3.6.1.tgz#216e8adf4ee9c629f77c985476a2ea07fb80e1dc" - integrity sha512-SLihQU8RMe77YJ/jGTqOt0lMq7k3hlPVfp7v/cxMnXA9T0bQYoMDfTsNgHXpwSJM1Iq2aAJ8WqekxUwGv5F67Q== +"@typescript-eslint/parser@^4.1.0": + version "4.1.0" + resolved "https://registry.yarnpkg.com/@typescript-eslint/parser/-/parser-4.1.0.tgz#9b0409411725f14cd7faa81a664e5051225961db" + integrity sha512-hM/WNCQTzDHgS0Ke3cR9zPndL3OTKr9OoN9CL3UqulsAjYDrglSwIIgswSmHBcSbOzLmgaMARwrQEbIumIglvQ== dependencies: - "@types/eslint-visitor-keys" "^1.0.0" - "@typescript-eslint/experimental-utils" "3.6.1" - "@typescript-eslint/types" "3.6.1" - "@typescript-eslint/typescript-estree" "3.6.1" - eslint-visitor-keys "^1.1.0" + "@typescript-eslint/scope-manager" "4.1.0" + "@typescript-eslint/types" "4.1.0" + "@typescript-eslint/typescript-estree" "4.1.0" + debug "^4.1.1" -"@typescript-eslint/types@3.6.1": - version "3.6.1" - resolved "https://registry.yarnpkg.com/@typescript-eslint/types/-/types-3.6.1.tgz#87600fe79a1874235d3cc1cf5c7e1a12eea69eee" - integrity sha512-NPxd5yXG63gx57WDTW1rp0cF3XlNuuFFB5G+Kc48zZ+51ZnQn9yjDEsjTPQ+aWM+V+Z0I4kuTFKjKvgcT1F7xQ== +"@typescript-eslint/scope-manager@4.0.1": + version "4.0.1" + resolved "https://registry.yarnpkg.com/@typescript-eslint/scope-manager/-/scope-manager-4.0.1.tgz#24d93c3000bdfcc5a157dc4d32b742405a8631b5" + integrity sha512-u3YEXVJ8jsj7QCJk3om0Y457fy2euEOkkzxIB/LKU3MdyI+FJ2gI0M4aKEaXzwCSfNDiZ13a3lDo5DVozc+XLQ== + dependencies: + "@typescript-eslint/types" "4.0.1" + "@typescript-eslint/visitor-keys" "4.0.1" -"@typescript-eslint/typescript-estree@2.34.0": - version "2.34.0" - resolved "https://registry.yarnpkg.com/@typescript-eslint/typescript-estree/-/typescript-estree-2.34.0.tgz#14aeb6353b39ef0732cc7f1b8285294937cf37d5" - integrity sha512-OMAr+nJWKdlVM9LOqCqh3pQQPwxHAN7Du8DR6dmwCrAmxtiXQnhHJ6tBNtf+cggqfo51SG/FCwnKhXCIM7hnVg== +"@typescript-eslint/scope-manager@4.1.0": + version "4.1.0" + resolved "https://registry.yarnpkg.com/@typescript-eslint/scope-manager/-/scope-manager-4.1.0.tgz#9e389745ee9cfe12252ed1e9958808abd6b3a683" + integrity sha512-HD1/u8vFNnxwiHqlWKC/Pigdn0Mvxi84Y6GzbZ5f5sbLrFKu0al02573Er+D63Sw67IffVUXR0uR8rpdfdk+vA== dependencies: + "@typescript-eslint/types" "4.1.0" + "@typescript-eslint/visitor-keys" "4.1.0" + +"@typescript-eslint/types@4.0.1": + version "4.0.1" + resolved "https://registry.yarnpkg.com/@typescript-eslint/types/-/types-4.0.1.tgz#1cf72582f764931f085cb8230ff215980fe467b2" + integrity sha512-S+gD3fgbkZYW2rnbjugNMqibm9HpEjqZBZkTiI3PwbbNGWmAcxolWIUwZ0SKeG4Dy2ktpKKaI/6+HGYVH8Qrlg== + +"@typescript-eslint/types@4.1.0": + version "4.1.0" + resolved "https://registry.yarnpkg.com/@typescript-eslint/types/-/types-4.1.0.tgz#edbd3fec346f34e13ce7aa176b03b497a32c496a" + integrity sha512-rkBqWsO7m01XckP9R2YHVN8mySOKKY2cophGM8K5uDK89ArCgahItQYdbg/3n8xMxzu2elss+an1TphlUpDuJw== + +"@typescript-eslint/typescript-estree@4.0.1": + version "4.0.1" + resolved "https://registry.yarnpkg.com/@typescript-eslint/typescript-estree/-/typescript-estree-4.0.1.tgz#29a43c7060641ec51c902d9f50ac7c5866ec479f" + integrity sha512-zGzleORFXrRWRJAMLTB2iJD1IZbCPkg4hsI8mGdpYlKaqzvKYSEWVAYh14eauaR+qIoZVWrXgYSXqLtTlxotiw== + dependencies: + "@typescript-eslint/types" "4.0.1" + "@typescript-eslint/visitor-keys" "4.0.1" debug "^4.1.1" - eslint-visitor-keys "^1.1.0" - glob "^7.1.6" + globby "^11.0.1" is-glob "^4.0.1" lodash "^4.17.15" semver "^7.3.2" tsutils "^3.17.1" -"@typescript-eslint/typescript-estree@3.6.1": - version "3.6.1" - resolved "https://registry.yarnpkg.com/@typescript-eslint/typescript-estree/-/typescript-estree-3.6.1.tgz#a5c91fcc5497cce7922ff86bc37d5e5891dcdefa" - integrity sha512-G4XRe/ZbCZkL1fy09DPN3U0mR6SayIv1zSeBNquRFRk7CnVLgkC2ZPj8llEMJg5Y8dJ3T76SvTGtceytniaztQ== +"@typescript-eslint/typescript-estree@4.1.0": + version "4.1.0" + resolved "https://registry.yarnpkg.com/@typescript-eslint/typescript-estree/-/typescript-estree-4.1.0.tgz#394046ead25164494218c0e3d6b960695ea967f6" + integrity sha512-r6et57qqKAWU173nWyw31x7OfgmKfMEcjJl9vlJEzS+kf9uKNRr4AVTRXfTCwebr7bdiVEkfRY5xGnpPaNPe4Q== dependencies: - "@typescript-eslint/types" "3.6.1" - "@typescript-eslint/visitor-keys" "3.6.1" + "@typescript-eslint/types" "4.1.0" + "@typescript-eslint/visitor-keys" "4.1.0" debug "^4.1.1" - glob "^7.1.6" + globby "^11.0.1" is-glob "^4.0.1" lodash "^4.17.15" semver "^7.3.2" tsutils "^3.17.1" -"@typescript-eslint/visitor-keys@3.6.1": - version "3.6.1" - resolved "https://registry.yarnpkg.com/@typescript-eslint/visitor-keys/-/visitor-keys-3.6.1.tgz#5c57a7772f4dd623cfeacc219303e7d46f963b37" - integrity sha512-qC8Olwz5ZyMTZrh4Wl3K4U6tfms0R/mzU4/5W3XeUZptVraGVmbptJbn6h2Ey6Rb3hOs3zWoAUebZk8t47KGiQ== +"@typescript-eslint/visitor-keys@4.0.1": + version "4.0.1" + resolved "https://registry.yarnpkg.com/@typescript-eslint/visitor-keys/-/visitor-keys-4.0.1.tgz#d4e8de62775f2a6db71c7e8539633680039fdd6c" + integrity sha512-yBSqd6FjnTzbg5RUy9J+9kJEyQjTI34JdGMJz+9ttlJzLCnGkBikxw+N5n2VDcc3CesbIEJ0MnZc5uRYnrEnCw== dependencies: - eslint-visitor-keys "^1.1.0" + "@typescript-eslint/types" "4.0.1" + eslint-visitor-keys "^2.0.0" + +"@typescript-eslint/visitor-keys@4.1.0": + version "4.1.0" + resolved "https://registry.yarnpkg.com/@typescript-eslint/visitor-keys/-/visitor-keys-4.1.0.tgz#b2d528c9484e7eda1aa4f86ccf0432fb16e4d545" + integrity sha512-+taO0IZGCtCEsuNTTF2Q/5o8+fHrlml8i9YsZt2AiDCdYEJzYlsmRY991l/6f3jNXFyAWepdQj7n8Na6URiDRQ== + dependencies: + "@typescript-eslint/types" "4.1.0" + eslint-visitor-keys "^2.0.0" JSONStream@^1.0.4: version "1.3.5" @@ -991,10 +918,10 @@ acorn@^7.1.1: resolved "https://registry.yarnpkg.com/acorn/-/acorn-7.2.0.tgz#17ea7e40d7c8640ff54a694c889c26f31704effe" integrity sha512-apwXVmYVpQ34m/i71vrApRrRKCWQnZZF1+npOD0WV5xZFfwWOmKGQ2RWlfdy9vWITsenisM8M0Qeq8agcFHNiQ== -acorn@^7.2.0: - version "7.3.1" - resolved "https://registry.yarnpkg.com/acorn/-/acorn-7.3.1.tgz#85010754db53c3fbaf3b9ea3e083aa5c5d147ffd" - integrity sha512-tLc0wSnatxAQHVHUapaHdz72pi9KUyHjq5KyHjGg9Y8Ifdc79pTh2XvI6I1/chZbnM7QtNKzh66ooDogPZSleA== +acorn@^7.4.0: + version "7.4.0" + resolved "https://registry.yarnpkg.com/acorn/-/acorn-7.4.0.tgz#e1ad486e6c54501634c6c397c5c121daa383607c" + integrity sha512-+G7P8jJmCHr+S+cLfQxygbWhXy+8YTVGzAkpEbcLo2mLoL7tij/VG41QSHACSf5QgYRhMZYHuNc6drJaO0Da+w== add-stream@^1.0.0: version "1.0.0" @@ -1011,6 +938,16 @@ ajv@^6.10.0, ajv@^6.10.2, ajv@^6.5.5: json-schema-traverse "^0.4.1" uri-js "^4.2.2" +ajv@^6.12.4: + version "6.12.4" + resolved "https://registry.yarnpkg.com/ajv/-/ajv-6.12.4.tgz#0614facc4522127fa713445c6bfd3ebd376e2234" + integrity sha512-eienB2c9qVQs2KWexhkrdMLVDoIQCz5KSeLxwg9Lzk4DOfBtIK9PQwwufcsn1jjGuf9WZmqPMbGxOzfcuphJCQ== + 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" + ansi-colors@^3.2.1: version "3.2.4" resolved "https://registry.yarnpkg.com/ansi-colors/-/ansi-colors-3.2.4.tgz#e3a3da4bfbae6c86a9c285625de124a234026fbf" @@ -1023,11 +960,6 @@ ansi-escapes@^4.2.1: dependencies: type-fest "^0.11.0" -ansi-regex@^2.0.0: - version "2.1.1" - resolved "https://registry.yarnpkg.com/ansi-regex/-/ansi-regex-2.1.1.tgz#c3b33ab5ee360d86e0e628f0468ae7ef27d654df" - integrity sha1-w7M6te42DYbg5ijwRorn7yfWVN8= - ansi-regex@^4.1.0: version "4.1.0" resolved "https://registry.yarnpkg.com/ansi-regex/-/ansi-regex-4.1.0.tgz#8b9f8f08cf1acb843756a839ca8c7e3168c51997" @@ -1038,11 +970,6 @@ ansi-regex@^5.0.0: resolved "https://registry.yarnpkg.com/ansi-regex/-/ansi-regex-5.0.0.tgz#388539f55179bf39339c81af30a654d69f87cb75" integrity sha512-bY6fj56OUQ0hU1KjFNDQuJFezqKdrAyFdIevADiqrWHwSlbmBNMHp5ak2f40Pm8JTFyM2mqxkG6ngkHO11f/lg== -ansi-styles@^2.2.1: - version "2.2.1" - resolved "https://registry.yarnpkg.com/ansi-styles/-/ansi-styles-2.2.1.tgz#b432dd3358b634cf75e1e4664368240533c1ddbe" - integrity sha1-tDLdM1i2NM914eRmQ2gkBTPB3b4= - ansi-styles@^3.2.0, ansi-styles@^3.2.1: version "3.2.1" resolved "https://registry.yarnpkg.com/ansi-styles/-/ansi-styles-3.2.1.tgz#41fbb20243e50b12be0f04b8dedbf07520ce841d" @@ -1058,11 +985,6 @@ ansi-styles@^4.0.0, ansi-styles@^4.1.0: "@types/color-name" "^1.1.1" color-convert "^2.0.1" -any-promise@^1.0.0: - version "1.3.0" - resolved "https://registry.yarnpkg.com/any-promise/-/any-promise-1.3.0.tgz#abc6afeedcea52e809cdc0376aed3ce39635d17f" - integrity sha1-q8av7tzqUugJzcA3au0845Y10X8= - anymatch@^2.0.0: version "2.0.0" resolved "https://registry.yarnpkg.com/anymatch/-/anymatch-2.0.0.tgz#bcb24b4f37934d9aa7ac17b4adaf89e7c76ef2eb" @@ -1079,11 +1001,6 @@ anymatch@^3.0.3, anymatch@~3.1.1: normalize-path "^3.0.0" picomatch "^2.0.4" -app-root-path@^3.0.0: - version "3.0.0" - resolved "https://registry.yarnpkg.com/app-root-path/-/app-root-path-3.0.0.tgz#210b6f43873227e18a4b810a032283311555d5ad" - integrity sha512-qMcx+Gy2UZynHjOHOIXPNvpf+9cjvk3cWrBBK7zg4gH9+clobJRb9NGzcT7mQTcV/6Gm/1WelUtqxVXnNlrwcw== - append-field@^1.0.0: version "1.0.0" resolved "https://registry.yarnpkg.com/append-field/-/append-field-1.0.0.tgz#1e3440e915f0b1203d23748e78edd7b9b5b43e56" @@ -1135,6 +1052,11 @@ array-includes@^3.1.1: es-abstract "^1.17.0" is-string "^1.0.5" +array-union@^2.1.0: + version "2.1.0" + resolved "https://registry.yarnpkg.com/array-union/-/array-union-2.1.0.tgz#b798420adbeb1de828d84acd8a2e23d3efe85e8d" + integrity sha512-HGyxoOTYUyCM6stUe6EJgnd4EoewAI7zMdfqO+kGjnlZmBDz/cR5pf8r/cR4Wq60sL/p0IkcjUEEPwS3GFrIyw== + array-unique@^0.3.2: version "0.3.2" resolved "https://registry.yarnpkg.com/array-unique/-/array-unique-0.3.2.tgz#a894b75d4bc4f6cd679ef3244a9fd8f46ae2d428" @@ -1165,12 +1087,13 @@ asn1@~0.2.3: dependencies: safer-buffer "~2.1.0" -aspida@^0.19.4: - version "0.19.4" - resolved "https://registry.yarnpkg.com/aspida/-/aspida-0.19.4.tgz#d4547021d289481121f4fe2584f8cf9af3aeba93" - integrity sha512-L6SGCk0YYGxPLRCBlFiJIUVOqoUgwVGLxvMqpj7V9w5YW4M0xHXCkcHS6QR0l2RZLUavU4rHXKBIs7DVJAFEGg== +aspida@^0.21.3: + version "0.21.3" + resolved "https://registry.yarnpkg.com/aspida/-/aspida-0.21.3.tgz#78a8ad1fe84bff3797768f3760466e9e5f0dbca4" + integrity sha512-1syaJea+IddYaxvAAnNfXDdeNGVeu40AKzPQRKSnqMcStIR17Nz656e2z/NndwNhWuzA3z/Io9GCmMiVujBy7A== dependencies: - chokidar "^3.4.0" + "@types/minimist" "^1.2.0" + chokidar "^3.4.2" minimist "^1.2.5" assert-plus@1.0.0, assert-plus@^1.0.0: @@ -1208,23 +1131,23 @@ aws4@^1.8.0: resolved "https://registry.yarnpkg.com/aws4/-/aws4-1.10.0.tgz#a17b3a8ea811060e74d47d306122400ad4497ae2" integrity sha512-3YDiu347mtVtjpyV3u5kVqQLP242c06zwDOgpeRnybmXlYYsLbtTrUBUm8i8srONt+FWobl5aibnU1030PeeuA== -axios@^0.19.2: - version "0.19.2" - resolved "https://registry.yarnpkg.com/axios/-/axios-0.19.2.tgz#3ea36c5d8818d0d5f8a8a97a6d36b86cdc00cb27" - integrity sha512-fjgm5MvRHLhx+osE2xoekY70AhARk3a6hkN+3Io1jc00jtquGvxYlKlsFUhmUET0V5te6CcZI7lcv2Ym61mjHA== +axios@^0.20.0: + version "0.20.0" + resolved "https://registry.yarnpkg.com/axios/-/axios-0.20.0.tgz#057ba30f04884694993a8cd07fa394cff11c50bd" + integrity sha512-ANA4rr2BDcmmAQLOKft2fufrtuvlqR+cXNNinUmvfeSNCOF98PZL+7M/v1zIdGo7OLjEA9J2gXJL+j4zGsl0bA== dependencies: - follow-redirects "1.5.10" + follow-redirects "^1.10.0" -babel-jest@^26.1.0: - version "26.1.0" - resolved "https://registry.yarnpkg.com/babel-jest/-/babel-jest-26.1.0.tgz#b20751185fc7569a0f135730584044d1cb934328" - integrity sha512-Nkqgtfe7j6PxLO6TnCQQlkMm8wdTdnIF8xrdpooHCuD5hXRzVEPbPneTJKknH5Dsv3L8ip9unHDAp48YQ54Dkg== +babel-jest@^26.3.0: + version "26.3.0" + resolved "https://registry.yarnpkg.com/babel-jest/-/babel-jest-26.3.0.tgz#10d0ca4b529ca3e7d1417855ef7d7bd6fc0c3463" + integrity sha512-sxPnQGEyHAOPF8NcUsD0g7hDCnvLL2XyblRBcgrzTWBB/mAIpWow3n1bEL+VghnnZfreLhFSBsFluRoK2tRK4g== dependencies: - "@jest/transform" "^26.1.0" - "@jest/types" "^26.1.0" + "@jest/transform" "^26.3.0" + "@jest/types" "^26.3.0" "@types/babel__core" "^7.1.7" babel-plugin-istanbul "^6.0.0" - babel-preset-jest "^26.1.0" + babel-preset-jest "^26.3.0" chalk "^4.0.0" graceful-fs "^4.2.4" slash "^3.0.0" @@ -1240,24 +1163,25 @@ babel-plugin-istanbul@^6.0.0: istanbul-lib-instrument "^4.0.0" test-exclude "^6.0.0" -babel-plugin-jest-hoist@^26.1.0: - version "26.1.0" - resolved "https://registry.yarnpkg.com/babel-plugin-jest-hoist/-/babel-plugin-jest-hoist-26.1.0.tgz#c6a774da08247a28285620a64dfadbd05dd5233a" - integrity sha512-qhqLVkkSlqmC83bdMhM8WW4Z9tB+JkjqAqlbbohS9sJLT5Ha2vfzuKqg5yenXrAjOPG2YC0WiXdH3a9PvB+YYw== +babel-plugin-jest-hoist@^26.2.0: + version "26.2.0" + resolved "https://registry.yarnpkg.com/babel-plugin-jest-hoist/-/babel-plugin-jest-hoist-26.2.0.tgz#bdd0011df0d3d513e5e95f76bd53b51147aca2dd" + integrity sha512-B/hVMRv8Nh1sQ1a3EY8I0n4Y1Wty3NrR5ebOyVT302op+DOAau+xNEImGMsUWOC3++ZlMooCytKz+NgN8aKGbA== dependencies: "@babel/template" "^7.3.3" "@babel/types" "^7.3.3" "@types/babel__core" "^7.0.0" "@types/babel__traverse" "^7.0.6" -babel-preset-current-node-syntax@^0.1.2: - version "0.1.2" - resolved "https://registry.yarnpkg.com/babel-preset-current-node-syntax/-/babel-preset-current-node-syntax-0.1.2.tgz#fb4a4c51fe38ca60fede1dc74ab35eb843cb41d6" - integrity sha512-u/8cS+dEiK1SFILbOC8/rUI3ml9lboKuuMvZ/4aQnQmhecQAgPw5ew066C1ObnEAUmlx7dv/s2z52psWEtLNiw== +babel-preset-current-node-syntax@^0.1.3: + version "0.1.3" + resolved "https://registry.yarnpkg.com/babel-preset-current-node-syntax/-/babel-preset-current-node-syntax-0.1.3.tgz#b4b547acddbf963cba555ba9f9cbbb70bfd044da" + integrity sha512-uyexu1sVwcdFnyq9o8UQYsXwXflIh8LvrF5+cKrYam93ned1CStffB3+BEcsxGSgagoA3GEyjDqO4a/58hyPYQ== dependencies: "@babel/plugin-syntax-async-generators" "^7.8.4" "@babel/plugin-syntax-bigint" "^7.8.3" "@babel/plugin-syntax-class-properties" "^7.8.3" + "@babel/plugin-syntax-import-meta" "^7.8.3" "@babel/plugin-syntax-json-strings" "^7.8.3" "@babel/plugin-syntax-logical-assignment-operators" "^7.8.3" "@babel/plugin-syntax-nullish-coalescing-operator" "^7.8.3" @@ -1266,24 +1190,19 @@ babel-preset-current-node-syntax@^0.1.2: "@babel/plugin-syntax-optional-catch-binding" "^7.8.3" "@babel/plugin-syntax-optional-chaining" "^7.8.3" -babel-preset-jest@^26.1.0: - version "26.1.0" - resolved "https://registry.yarnpkg.com/babel-preset-jest/-/babel-preset-jest-26.1.0.tgz#612f714e5b457394acfd863793c564cbcdb7d1c1" - integrity sha512-na9qCqFksknlEj5iSdw1ehMVR06LCCTkZLGKeEtxDDdhg8xpUF09m29Kvh1pRbZ07h7AQ5ttLYUwpXL4tO6w7w== +babel-preset-jest@^26.3.0: + version "26.3.0" + resolved "https://registry.yarnpkg.com/babel-preset-jest/-/babel-preset-jest-26.3.0.tgz#ed6344506225c065fd8a0b53e191986f74890776" + integrity sha512-5WPdf7nyYi2/eRxCbVrE1kKCWxgWY4RsPEbdJWFm7QsesFGqjdkyLeu1zRkwM1cxK6EPIlNd6d2AxLk7J+t4pw== dependencies: - babel-plugin-jest-hoist "^26.1.0" - babel-preset-current-node-syntax "^0.1.2" + babel-plugin-jest-hoist "^26.2.0" + babel-preset-current-node-syntax "^0.1.3" balanced-match@^1.0.0: version "1.0.0" resolved "https://registry.yarnpkg.com/balanced-match/-/balanced-match-1.0.0.tgz#89b4d199ab2bee49de164ea02b89ce462d71b767" integrity sha1-ibTRmasr7kneFk6gK4nORi1xt2c= -base64-js@^1.0.2: - version "1.3.1" - resolved "https://registry.yarnpkg.com/base64-js/-/base64-js-1.3.1.tgz#58ece8cb75dd07e71ed08c736abc5fac4dbf8df1" - integrity sha512-mLQ4i2QO1ytvGWFWmcngKO//JXAQueZvwEKtjgQFM4jIK0kU+ytMfplL8j+n5mspOfjHwoAg+9yhb7BwAHm36g== - base@^0.11.1: version "0.11.2" resolved "https://registry.yarnpkg.com/base/-/base-0.11.2.tgz#7bde5ced145b6d551a90db87f83c558b4eb48a8f" @@ -1325,11 +1244,6 @@ body-parser@1.19.0: raw-body "2.4.0" type-is "~1.6.17" -bowser@2.9.0: - version "2.9.0" - resolved "https://registry.yarnpkg.com/bowser/-/bowser-2.9.0.tgz#3bed854233b419b9a7422d9ee3e85504373821c9" - integrity sha512-2ld76tuLBNFekRgmJfT2+3j5MIrP6bFict8WAIT3beq+srz1gcKNAdNKMqHqauQt63NmAa88HfP1/Ypa9Er3HA== - brace-expansion@^1.1.7: version "1.1.11" resolved "https://registry.yarnpkg.com/brace-expansion/-/brace-expansion-1.1.11.tgz#3c7fcbf529d87226f3d2f52b966ff5271eb441dd" @@ -1385,14 +1299,6 @@ buffer-from@1.x, buffer-from@^1.0.0: resolved "https://registry.yarnpkg.com/buffer-from/-/buffer-from-1.1.1.tgz#32713bc028f75c02fdb710d7c7bcec1f2c6070ef" integrity sha512-MQcXEUbCKtEo7bhqEs6560Hyd4XaovZlO/k9V3hjVUF/zwW7KBVdSK4gIt/bzwS9MbR5qob+F5jusZsb0YQK2A== -buffer@^5.1.0: - version "5.6.0" - resolved "https://registry.yarnpkg.com/buffer/-/buffer-5.6.0.tgz#a31749dc7d81d84db08abf937b6b8c4033f62786" - integrity sha512-/gDYp/UtU0eA1ys8bOs9J6a+E/KWIY+DZ+Q2WESNUA0jFRsJOc0SNUO6xJ5SGA1xueg3NL65W6s+NY5l9cunuw== - dependencies: - base64-js "^1.0.2" - ieee754 "^1.1.4" - busboy@^0.2.11: version "0.2.14" resolved "https://registry.yarnpkg.com/busboy/-/busboy-0.2.14.tgz#6c2a622efcf47c57bbbe1e2a9c37ad36c7925453" @@ -1472,11 +1378,6 @@ camelcase@^6.0.0: resolved "https://registry.yarnpkg.com/camelcase/-/camelcase-6.0.0.tgz#5259f7c30e35e278f1bdc2a4d91230b37cad981e" integrity sha512-8KMDF1Vz2gzOq54ONPJS65IvTUaB1cHJ2DMM7MbPmLZljDH1qpzzLsWdiN9pHh6qvkRVDTi/07+eNGch/oLU4w== -camelize@1.0.0: - version "1.0.0" - resolved "https://registry.yarnpkg.com/camelize/-/camelize-1.0.0.tgz#164a5483e630fa4321e5af07020e531831b2609b" - integrity sha1-FkpUg+Yw+kMh5a8HAg5TGDGyYJs= - capture-exit@^2.0.0: version "2.0.0" resolved "https://registry.yarnpkg.com/capture-exit/-/capture-exit-2.0.0.tgz#fb953bfaebeb781f62898239dabb426d08a509a4" @@ -1489,25 +1390,6 @@ caseless@~0.12.0: resolved "https://registry.yarnpkg.com/caseless/-/caseless-0.12.0.tgz#1b681c21ff84033c826543090689420d187151dc" integrity sha1-G2gcIf+EAzyCZUMJBolCDRhxUdw= -chalk@4.1.0: - version "4.1.0" - resolved "https://registry.yarnpkg.com/chalk/-/chalk-4.1.0.tgz#4e14870a618d9e2edd97dd8345fd9d9dc315646a" - integrity sha512-qwx12AxXe2Q5xQ43Ac//I6v5aXTipYrSESdOgzrN+9XjgEpyjpKuvSGaN4qE93f7TQTlerQQ8S+EQ0EyDoVL1A== - dependencies: - ansi-styles "^4.1.0" - supports-color "^7.1.0" - -chalk@^1.1.1: - version "1.1.3" - resolved "https://registry.yarnpkg.com/chalk/-/chalk-1.1.3.tgz#a8115c55e4a702fe4d150abd3872822a7e09fc98" - integrity sha1-qBFcVeSnAv5NFQq9OHKCKn4J/Jg= - dependencies: - ansi-styles "^2.2.1" - escape-string-regexp "^1.0.2" - has-ansi "^2.0.0" - strip-ansi "^3.0.0" - supports-color "^2.0.0" - chalk@^2.0.0, chalk@^2.4.2: version "2.4.2" resolved "https://registry.yarnpkg.com/chalk/-/chalk-2.4.2.tgz#cd42541677a54333cf541a49108c1432b44c9424" @@ -1538,10 +1420,10 @@ char-regex@^1.0.2: resolved "https://registry.yarnpkg.com/char-regex/-/char-regex-1.0.2.tgz#d744358226217f981ed58f479b1d6bcc29545dcf" integrity sha512-kWWXztvZ5SBQV+eRgKFeh8q5sLuZY2+8WUIzlxWVTg+oGwY14qylx1KbKzHd8P6ZYkAg0xyIDU9JMHhyJMZ1jw== -chokidar@^3.4.0: - version "3.4.0" - resolved "https://registry.yarnpkg.com/chokidar/-/chokidar-3.4.0.tgz#b30611423ce376357c765b9b8f904b9fba3c0be8" - integrity sha512-aXAaho2VJtisB/1fg1+3nlLJqGOuewTzQpd/Tz0yTg2R0e4IGtshYvtjowyEumcBv2z+y4+kc75Mz7j5xJskcQ== +chokidar@^3.4.2: + version "3.4.2" + resolved "https://registry.yarnpkg.com/chokidar/-/chokidar-3.4.2.tgz#38dc8e658dec3809741eb3ef7bb0a47fe424232d" + integrity sha512-IZHaDeBeI+sZJRX7lGcXsdzgvZqKv6sECqsbErJA4mHWfpRrD8B97kSFN4cQz6nGBGiuFia1MKR4d6c1o8Cv7A== dependencies: anymatch "~3.1.1" braces "~3.0.2" @@ -1578,27 +1460,6 @@ class-validator@^0.12.2: tslib ">=1.9.0" validator "13.0.0" -cli-highlight@^2.0.0: - version "2.1.4" - resolved "https://registry.yarnpkg.com/cli-highlight/-/cli-highlight-2.1.4.tgz#098cb642cf17f42adc1c1145e07f960ec4d7522b" - integrity sha512-s7Zofobm20qriqDoU9sXptQx0t2R9PEgac92mENNm7xaEe1hn71IIMsXMK+6encA6WRCWWxIGQbipr3q998tlQ== - dependencies: - chalk "^3.0.0" - highlight.js "^9.6.0" - mz "^2.4.0" - parse5 "^5.1.1" - parse5-htmlparser2-tree-adapter "^5.1.1" - yargs "^15.0.0" - -cliui@^5.0.0: - version "5.0.0" - resolved "https://registry.yarnpkg.com/cliui/-/cliui-5.0.0.tgz#deefcfdb2e800784aa34f46fa08e06851c7bbbc5" - integrity sha512-PYeGSEmmHM6zvoef2w8TPzlrnNpXIjTipYK780YswmIP9vjxmd6Y2a3CB2Ks6/AU8NHjZugXvo8w3oWM2qnwXA== - dependencies: - string-width "^3.1.0" - strip-ansi "^5.2.0" - wrap-ansi "^5.1.0" - cliui@^6.0.0: version "6.0.0" resolved "https://registry.yarnpkg.com/cliui/-/cliui-6.0.0.tgz#511d702c0c4e41ca156d7d0e96021f23e13225b1" @@ -1662,13 +1523,13 @@ commander@~2.20.3: resolved "https://registry.yarnpkg.com/commander/-/commander-2.20.3.tgz#fd485e84c03eb4881c20722ba48035e8531aeb33" integrity sha512-GpVkmM8vF2vQUkj2LvZmD35JxeJOLCwJ9cUkugyk2nuhbv3+mJvpLYYt+0+USMxE+oj+ey/lJEnhZw75x/OMcQ== -compare-func@^1.3.1: - version "1.3.4" - resolved "https://registry.yarnpkg.com/compare-func/-/compare-func-1.3.4.tgz#6b07c4c5e8341119baf44578085bda0f4a823516" - integrity sha512-sq2sWtrqKPkEXAC8tEJA1+BqAH9GbFkGBtUOqrUX57VSfwp8xyktctk+uLoRy5eccTdxzDcVIztlYDpKs3Jv1Q== +compare-func@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/compare-func/-/compare-func-2.0.0.tgz#fb65e75edbddfd2e568554e8b5b05fff7a51fcb3" + integrity sha512-zHig5N+tPWARooBnb0Zx1MFcdfpyJrfTJ3Y5L+IFvUm8rM74hHz66z0gw0x4tijh5CorKkKUCnW82R2vmpeCRA== dependencies: array-ify "^1.0.0" - dot-prop "^3.0.0" + dot-prop "^5.1.0" component-emitter@^1.2.1: version "1.3.0" @@ -1712,22 +1573,17 @@ content-disposition@0.5.3: dependencies: safe-buffer "5.1.2" -content-security-policy-builder@2.1.0: - version "2.1.0" - resolved "https://registry.yarnpkg.com/content-security-policy-builder/-/content-security-policy-builder-2.1.0.tgz#0a2364d769a3d7014eec79ff7699804deb8cfcbb" - integrity sha512-/MtLWhJVvJNkA9dVLAp6fg9LxD2gfI6R2Fi1hPmfjYXSahJJzcfvoeDOxSyp4NvxMuwWv3WMssE9o31DoULHrQ== - content-type@~1.0.4: version "1.0.4" resolved "https://registry.yarnpkg.com/content-type/-/content-type-1.0.4.tgz#e138cc75e040c727b1966fe5e5f8c9aee256fe3b" integrity sha512-hIP3EEPs8tB9AT1L+NUqtwOAps4mk2Zob89MWXMHjHWg9milF/j4osnnQLXBCBFBk/tvIG/tUc9mOUJiPBhPXA== -conventional-changelog-angular@^5.0.0, conventional-changelog-angular@^5.0.10: - version "5.0.10" - resolved "https://registry.yarnpkg.com/conventional-changelog-angular/-/conventional-changelog-angular-5.0.10.tgz#5cf7b00dd315b6a6a558223c80d5ef24ddb34205" - integrity sha512-k7RPPRs0vp8+BtPsM9uDxRl6KcgqtCJmzRD1wRtgqmhQ96g8ifBGo9O/TZBG23jqlXS/rg8BKRDELxfnQQGiaA== +conventional-changelog-angular@^5.0.11: + version "5.0.11" + resolved "https://registry.yarnpkg.com/conventional-changelog-angular/-/conventional-changelog-angular-5.0.11.tgz#99a3ca16e4a5305e0c2c2fae3ef74fd7631fc3fb" + integrity sha512-nSLypht/1yEflhuTogC03i7DX7sOrXGsRn14g131Potqi6cbGbGEE9PSDEHKldabB6N76HiSyw9Ph+kLmC04Qw== dependencies: - compare-func "^1.3.1" + compare-func "^2.0.0" q "^1.5.1" conventional-changelog-atom@^2.0.7: @@ -1749,28 +1605,28 @@ conventional-changelog-config-spec@2.1.0: resolved "https://registry.yarnpkg.com/conventional-changelog-config-spec/-/conventional-changelog-config-spec-2.1.0.tgz#874a635287ef8b581fd8558532bf655d4fb59f2d" integrity sha512-IpVePh16EbbB02V+UA+HQnnPIohgXvJRxHcS5+Uwk4AT5LjzCZJm5sp/yqs5C6KZJ1jMsV4paEV13BN1pvDuxQ== -conventional-changelog-conventionalcommits@4.3.0, conventional-changelog-conventionalcommits@^4.3.0: - version "4.3.0" - resolved "https://registry.yarnpkg.com/conventional-changelog-conventionalcommits/-/conventional-changelog-conventionalcommits-4.3.0.tgz#c4205a659f7ca9d7881f29ee78a4e7d6aeb8b3c2" - integrity sha512-oYHydvZKU+bS8LnGqTMlNrrd7769EsuEHKy4fh1oMdvvDi7fem8U+nvfresJ1IDB8K00Mn4LpiA/lR+7Gs6rgg== +conventional-changelog-conventionalcommits@4.4.0, conventional-changelog-conventionalcommits@^4.4.0: + version "4.4.0" + resolved "https://registry.yarnpkg.com/conventional-changelog-conventionalcommits/-/conventional-changelog-conventionalcommits-4.4.0.tgz#8d96687141c9bbd725a89b95c04966d364194cd4" + integrity sha512-ybvx76jTh08tpaYrYn/yd0uJNLt5yMrb1BphDe4WBredMlvPisvMghfpnJb6RmRNcqXeuhR6LfGZGewbkRm9yA== dependencies: - compare-func "^1.3.1" + compare-func "^2.0.0" lodash "^4.17.15" q "^1.5.1" -conventional-changelog-core@^4.1.7: - version "4.1.7" - resolved "https://registry.yarnpkg.com/conventional-changelog-core/-/conventional-changelog-core-4.1.7.tgz#6b5cdadda4430895cc4a75a73dd8b36e322ab346" - integrity sha512-UBvSrQR2RdKbSQKh7RhueiiY4ZAIOW3+CSWdtKOwRv+KxIMNFKm1rOcGBFx0eA8AKhGkkmmacoTWJTqyz7Q0VA== +conventional-changelog-core@^4.2.0: + version "4.2.0" + resolved "https://registry.yarnpkg.com/conventional-changelog-core/-/conventional-changelog-core-4.2.0.tgz#d8befd1e1f5126bf35a17668276cc8c244650469" + integrity sha512-8+xMvN6JvdDtPbGBqA7oRNyZD4od1h/SIzrWqHcKZjitbVXrFpozEeyn4iI4af1UwdrabQpiZMaV07fPUTGd4w== dependencies: add-stream "^1.0.0" - conventional-changelog-writer "^4.0.16" + conventional-changelog-writer "^4.0.17" conventional-commits-parser "^3.1.0" dateformat "^3.0.0" get-pkg-repo "^1.0.0" git-raw-commits "2.0.0" git-remote-origin-url "^2.0.0" - git-semver-tags "^4.0.0" + git-semver-tags "^4.1.0" lodash "^4.17.15" normalize-package-data "^2.3.5" q "^1.5.1" @@ -1807,12 +1663,12 @@ conventional-changelog-jquery@^3.0.10: dependencies: q "^1.5.1" -conventional-changelog-jshint@^2.0.7: - version "2.0.7" - resolved "https://registry.yarnpkg.com/conventional-changelog-jshint/-/conventional-changelog-jshint-2.0.7.tgz#955a69266951cd31e8afeb3f1c55e0517fdca943" - integrity sha512-qHA8rmwUnLiIxANJbz650+NVzqDIwNtc0TcpIa0+uekbmKHttidvQ1dGximU3vEDdoJVKFgR3TXFqYuZmYy9ZQ== +conventional-changelog-jshint@^2.0.8: + version "2.0.8" + resolved "https://registry.yarnpkg.com/conventional-changelog-jshint/-/conventional-changelog-jshint-2.0.8.tgz#3fff4df8cb46037f77b9dc3f8e354c7f99332f13" + integrity sha512-hB/iI0IiZwnZ+seYI+qEQ4b+EMQSEC8jGIvhO2Vpz1E5p8FgLz75OX8oB1xJWl+s4xBMB6f8zJr0tC/BL7YOjw== dependencies: - compare-func "^1.3.1" + compare-func "^2.0.0" q "^1.5.1" conventional-changelog-preset-loader@^2.3.4: @@ -1820,12 +1676,12 @@ conventional-changelog-preset-loader@^2.3.4: resolved "https://registry.yarnpkg.com/conventional-changelog-preset-loader/-/conventional-changelog-preset-loader-2.3.4.tgz#14a855abbffd59027fd602581f1f34d9862ea44c" integrity sha512-GEKRWkrSAZeTq5+YjUZOYxdHq+ci4dNwHvpaBC3+ENalzFWuCWa9EZXSuZBpkr72sMdKB+1fyDV4takK1Lf58g== -conventional-changelog-writer@^4.0.16: - version "4.0.16" - resolved "https://registry.yarnpkg.com/conventional-changelog-writer/-/conventional-changelog-writer-4.0.16.tgz#ca10f2691a8ea6d3c2eb74bd35bcf40aa052dda5" - integrity sha512-jmU1sDJDZpm/dkuFxBeRXvyNcJQeKhGtVcFFkwTphUAzyYWcwz2j36Wcv+Mv2hU3tpvLMkysOPXJTLO55AUrYQ== +conventional-changelog-writer@^4.0.17: + version "4.0.17" + resolved "https://registry.yarnpkg.com/conventional-changelog-writer/-/conventional-changelog-writer-4.0.17.tgz#4753aaa138bf5aa59c0b274cb5937efcd2722e21" + integrity sha512-IKQuK3bib/n032KWaSb8YlBFds+aLmzENtnKtxJy3+HqDq5kohu3g/UdNbIHeJWygfnEbZjnCKFxAW0y7ArZAw== dependencies: - compare-func "^1.3.1" + compare-func "^2.0.0" conventional-commits-filter "^2.0.6" dateformat "^3.0.0" handlebars "^4.7.6" @@ -1836,21 +1692,21 @@ conventional-changelog-writer@^4.0.16: split "^1.0.0" through2 "^3.0.0" -conventional-changelog@3.1.21: - version "3.1.21" - resolved "https://registry.yarnpkg.com/conventional-changelog/-/conventional-changelog-3.1.21.tgz#4a774e6bf503acfd7e4685bb750da8c0eccf1e0d" - integrity sha512-ZGecVZPEo3aC75VVE4nu85589dDhpMyqfqgUM5Myq6wfKWiNqhDJLSDMsc8qKXshZoY7dqs1hR0H/15kI/G2jQ== +conventional-changelog@3.1.23: + version "3.1.23" + resolved "https://registry.yarnpkg.com/conventional-changelog/-/conventional-changelog-3.1.23.tgz#d696408021b579a3814aba79b38729ed86478aea" + integrity sha512-sScUu2NHusjRC1dPc5p8/b3kT78OYr95/Bx7Vl8CPB8tF2mG1xei5iylDTRjONV5hTlzt+Cn/tBWrKdd299b7A== dependencies: - conventional-changelog-angular "^5.0.10" + conventional-changelog-angular "^5.0.11" conventional-changelog-atom "^2.0.7" conventional-changelog-codemirror "^2.0.7" - conventional-changelog-conventionalcommits "^4.3.0" - conventional-changelog-core "^4.1.7" + conventional-changelog-conventionalcommits "^4.4.0" + conventional-changelog-core "^4.2.0" conventional-changelog-ember "^2.0.8" conventional-changelog-eslint "^3.0.8" conventional-changelog-express "^2.0.5" conventional-changelog-jquery "^3.0.10" - conventional-changelog-jshint "^2.0.7" + conventional-changelog-jshint "^2.0.8" conventional-changelog-preset-loader "^2.3.4" conventional-commits-filter@^2.0.6: @@ -1861,7 +1717,7 @@ conventional-commits-filter@^2.0.6: lodash.ismatch "^4.4.0" modify-values "^1.0.0" -conventional-commits-parser@^3.0.0, conventional-commits-parser@^3.1.0: +conventional-commits-parser@^3.1.0: version "3.1.0" resolved "https://registry.yarnpkg.com/conventional-commits-parser/-/conventional-commits-parser-3.1.0.tgz#10140673d5e7ef5572633791456c5d03b69e8be4" integrity sha512-RSo5S0WIwXZiRxUGTPuYFbqvrR4vpJ1BDdTlthFgvHt5kEdnd1+pdvwWphWn57/oIl4V72NMmOocFqqJ8mFFhA== @@ -1874,17 +1730,17 @@ conventional-commits-parser@^3.0.0, conventional-commits-parser@^3.1.0: through2 "^3.0.0" trim-off-newlines "^1.0.0" -conventional-recommended-bump@6.0.9: - version "6.0.9" - resolved "https://registry.yarnpkg.com/conventional-recommended-bump/-/conventional-recommended-bump-6.0.9.tgz#49ee74f52fbafcc63e89e2297d020279fea318f0" - integrity sha512-DpRmW1k8CpRrcsXHOPGgHgOd4BMGiq2gtXAveGM8B9pSd9b4r4WKnqp1Fd0vkDtk8l973mIk8KKKUYnKRr9SFw== +conventional-recommended-bump@6.0.10: + version "6.0.10" + resolved "https://registry.yarnpkg.com/conventional-recommended-bump/-/conventional-recommended-bump-6.0.10.tgz#ac2fb3e31bad2aeda80086b345bf0c52edd1d1b3" + integrity sha512-2ibrqAFMN3ZA369JgVoSbajdD/BHN6zjY7DZFKTHzyzuQejDUCjQ85S5KHxCRxNwsbDJhTPD5hOKcis/jQhRgg== dependencies: concat-stream "^2.0.0" conventional-changelog-preset-loader "^2.3.4" conventional-commits-filter "^2.0.6" conventional-commits-parser "^3.1.0" git-raw-commits "2.0.0" - git-semver-tags "^4.0.0" + git-semver-tags "^4.1.0" meow "^7.0.0" q "^1.5.1" @@ -1910,35 +1766,11 @@ copy-descriptor@^0.1.0: resolved "https://registry.yarnpkg.com/copy-descriptor/-/copy-descriptor-0.1.1.tgz#676f6eb3c39997c2ee1ac3a924fd6124748f578d" integrity sha1-Z29us8OZl8LuGsOpJP1hJHSPV40= -core-js@^3.6.1: - version "3.6.5" - resolved "https://registry.yarnpkg.com/core-js/-/core-js-3.6.5.tgz#7395dc273af37fb2e50e9bd3d9fe841285231d1a" - integrity sha512-vZVEEwZoIsI+vPEuoF9Iqf5H7/M3eeQqWlQnYa8FSKKePuYTf5MWnxb5SDAzCa60b3JBRS5g9b+Dq7b1y/RCrA== - core-util-is@1.0.2, core-util-is@~1.0.0: version "1.0.2" resolved "https://registry.yarnpkg.com/core-util-is/-/core-util-is-1.0.2.tgz#b5fd54220aa2bc5ab57aab7140c940754503c1a7" integrity sha1-tf1UIgqivFq1eqtxQMlAdUUDwac= -cors@^2.8.5: - version "2.8.5" - resolved "https://registry.yarnpkg.com/cors/-/cors-2.8.5.tgz#eac11da51592dd86b9f06f6e7ac293b3df875d29" - integrity sha512-KIHbLJqu73RGr/hnbrO9uBeixNGuvSQjul/jdFvS/KFSIH1hWVd1ng7zOHx+YrEfInLG7q4n6GHQ9cDtxv/P6g== - dependencies: - object-assign "^4" - vary "^1" - -cosmiconfig@^6.0.0: - version "6.0.0" - resolved "https://registry.yarnpkg.com/cosmiconfig/-/cosmiconfig-6.0.0.tgz#da4fee853c52f6b1e6935f41c1a2fc50bd4a9982" - integrity sha512-xb3ZL6+L8b9JLLCx3ZdoZy4+2ECphCMo2PwqgP1tlfVq6M6YReyzBJtvWWtbDSpNr9hn96pkCiZqUcFEc+54Qg== - dependencies: - "@types/parse-json" "^4.0.0" - import-fresh "^3.1.0" - parse-json "^5.0.0" - path-type "^4.0.0" - yaml "^1.7.2" - cross-spawn@^6.0.0: version "6.0.5" resolved "https://registry.yarnpkg.com/cross-spawn/-/cross-spawn-6.0.5.tgz#4a5ec7c64dfae22c3a14124dbacdee846d80cbc4" @@ -1990,11 +1822,6 @@ dargs@^4.0.1: dependencies: number-is-nan "^1.0.0" -dargs@^7.0.0: - version "7.0.0" - resolved "https://registry.yarnpkg.com/dargs/-/dargs-7.0.0.tgz#04015c41de0bcb69ec84050f3d9be0caf8d6d5cc" - integrity sha512-2iy1EkLdlBzQGvbweYRFxmFath8+K7+AKB0TlhHWkNuH+TmovaMH/Wp7V7R4u7f4SnX3OgLsU9t1NI9ioDnUpg== - dashdash@^1.12.0: version "1.14.1" resolved "https://registry.yarnpkg.com/dashdash/-/dashdash-1.14.1.tgz#853cfa0f7cbe2fed5de20326b8dd581035f6e2f0" @@ -2002,11 +1829,6 @@ dashdash@^1.12.0: dependencies: assert-plus "^1.0.0" -dasherize@2.0.0: - version "2.0.0" - resolved "https://registry.yarnpkg.com/dasherize/-/dasherize-2.0.0.tgz#6d809c9cd0cf7bb8952d80fc84fa13d47ddb1308" - integrity sha1-bYCcnNDPe7iVLYD8hPoT1H3bEwg= - data-urls@^2.0.0: version "2.0.0" resolved "https://registry.yarnpkg.com/data-urls/-/data-urls-2.0.0.tgz#156485a72963a970f5d5821aaf642bef2bf2db9b" @@ -2028,13 +1850,6 @@ debug@2.6.9, debug@^2.2.0, debug@^2.3.3, debug@^2.6.9: dependencies: ms "2.0.0" -debug@=3.1.0: - version "3.1.0" - resolved "https://registry.yarnpkg.com/debug/-/debug-3.1.0.tgz#5bb5a0672628b64149566ba16819e61518c67261" - integrity sha512-OX8XqP7/1a9cqkxYw2yXss15f26NKWBpDXQd0/uK/KPqdQhxbPa994hnzjcE2VqQpDslf55723cKPUOGSmMY3g== - dependencies: - ms "2.0.0" - debug@^4.0.1, debug@^4.1.0, debug@^4.1.1: version "4.1.1" resolved "https://registry.yarnpkg.com/debug/-/debug-4.1.1.tgz#3b72260255109c6b589cee050f1d516139664791" @@ -2109,11 +1924,6 @@ delayed-stream@~1.0.0: resolved "https://registry.yarnpkg.com/delayed-stream/-/delayed-stream-1.0.0.tgz#df3ae199acadfb7d440aaae0b29e2272b24ec619" integrity sha1-3zrhmayt+31ECqrgsp4icrJOxhk= -depd@2.0.0: - version "2.0.0" - resolved "https://registry.yarnpkg.com/depd/-/depd-2.0.0.tgz#b696163cc757560d09cf22cc8fad1571b79e76df" - integrity sha512-g7nH6P6dyDioJogAAGprGpCtVImJhpPk/roCzdb3fIh61/s/nPsfR6onyMwkCAR/OlC3yBC0lESvUoQEAssIrw== - depd@~1.1.2: version "1.1.2" resolved "https://registry.yarnpkg.com/depd/-/depd-1.1.2.tgz#9bcd52e14c097763e749b274c4346ed2e560b5a9" @@ -2147,10 +1957,17 @@ diff-sequences@^25.2.6: resolved "https://registry.yarnpkg.com/diff-sequences/-/diff-sequences-25.2.6.tgz#5f467c00edd35352b7bca46d7927d60e687a76dd" integrity sha512-Hq8o7+6GaZeoFjtpgvRBUknSXNeJiCx7V9Fr94ZMljNiCr9n9L8H8aJqgWOQiDDGdyn29fRNcDdRVJ5fdyihfg== -diff-sequences@^26.0.0: - version "26.0.0" - resolved "https://registry.yarnpkg.com/diff-sequences/-/diff-sequences-26.0.0.tgz#0760059a5c287637b842bd7085311db7060e88a6" - integrity sha512-JC/eHYEC3aSS0vZGjuoc4vHA0yAQTzhQQldXMeMF+JlxLGJlCO38Gma82NV9gk1jGFz8mDzUMeaKXvjRRdJ2dg== +diff-sequences@^26.3.0: + version "26.3.0" + resolved "https://registry.yarnpkg.com/diff-sequences/-/diff-sequences-26.3.0.tgz#62a59b1b29ab7fd27cef2a33ae52abe73042d0a2" + integrity sha512-5j5vdRcw3CNctePNYN0Wy2e/JbWT6cAYnXv5OuqPhDpyCGc0uLu2TK0zOCJWNB9kOIfYMSpIulRaDgIi4HJ6Ig== + +dir-glob@^3.0.1: + version "3.0.1" + resolved "https://registry.yarnpkg.com/dir-glob/-/dir-glob-3.0.1.tgz#56dbf73d992a4a93ba1584f4534063fd2e41717f" + integrity sha512-WkrWp9GR4KXfKGYzOLmTuGVi1UWFfws377n9cc55/tb6DuqyF6pcQ5AbiHEshaDpY9v6oaSr2XCDidGmMwdzIA== + dependencies: + path-type "^4.0.0" doctrine@1.5.0: version "1.5.0" @@ -2174,22 +1991,12 @@ domexception@^2.0.1: dependencies: webidl-conversions "^5.0.0" -dont-sniff-mimetype@1.1.0: - version "1.1.0" - resolved "https://registry.yarnpkg.com/dont-sniff-mimetype/-/dont-sniff-mimetype-1.1.0.tgz#c7d0427f8bcb095762751252af59d148b0a623b2" - integrity sha512-ZjI4zqTaxveH2/tTlzS1wFp+7ncxNZaIEWYg3lzZRHkKf5zPT/MnEG6WL0BhHMJUabkh8GeU5NL5j+rEUCb7Ug== - -dot-prop@^3.0.0: - version "3.0.0" - resolved "https://registry.yarnpkg.com/dot-prop/-/dot-prop-3.0.0.tgz#1b708af094a49c9a0e7dbcad790aba539dac1177" - integrity sha1-G3CK8JSknJoOfbyteQq6U52sEXc= +dot-prop@^5.1.0: + version "5.2.0" + resolved "https://registry.yarnpkg.com/dot-prop/-/dot-prop-5.2.0.tgz#c34ecc29556dc45f1f4c22697b6f4904e0cc4fcb" + integrity sha512-uEUyaDKoSQ1M4Oq8l45hSE26SnTxL6snNnqvK/VWx5wJhmff5z0FUVJDKDanor/6w3kzE3i7XZOk+7wC0EXr1A== dependencies: - is-obj "^1.0.0" - -dotenv@^6.2.0: - version "6.2.0" - resolved "https://registry.yarnpkg.com/dotenv/-/dotenv-6.2.0.tgz#941c0410535d942c8becf28d3f357dbd9d476064" - integrity sha512-HygQCKUBSFl8wKQZBSemMywRWcEDNidvNbjGVyZu3nbZ8qq9ubiPoGLMdRDpfSrpkkm9BXYFkpKxxFX38o/76w== + is-obj "^2.0.0" dotgitignore@^2.1.0: version "2.1.0" @@ -2212,6 +2019,11 @@ ee-first@1.1.1: resolved "https://registry.yarnpkg.com/ee-first/-/ee-first-1.1.1.tgz#590c61156b0ae2f4f0255732a158b266bc56b21d" integrity sha1-WQxhFWsK4vTwJVcyoViyZrxWsh0= +emittery@^0.7.1: + version "0.7.1" + resolved "https://registry.yarnpkg.com/emittery/-/emittery-0.7.1.tgz#c02375a927a40948c0345cc903072597f5270451" + integrity sha512-d34LN4L6h18Bzz9xpoku2nPwKxCPlPMr3EEKTkoEBi+1/+b0lcRkRJ1UVyyZaKNeqGR3swcGl6s390DNO4YVgQ== + emoji-regex@^7.0.1: version "7.0.3" resolved "https://registry.yarnpkg.com/emoji-regex/-/emoji-regex-7.0.3.tgz#933a04052860c85e83c122479c4748a8e4c72156" @@ -2279,7 +2091,7 @@ escape-html@~1.0.3: resolved "https://registry.yarnpkg.com/escape-html/-/escape-html-1.0.3.tgz#0258eae4d3d0c0974de1c169188ef0051d1d1988" integrity sha1-Aljq5NPQwJdN4cFpGI7wBR0dGYg= -escape-string-regexp@^1.0.2, escape-string-regexp@^1.0.5: +escape-string-regexp@^1.0.5: version "1.0.5" resolved "https://registry.yarnpkg.com/escape-string-regexp/-/escape-string-regexp-1.0.5.tgz#1b61c0562190a8dff6ae3bb2cf0200ca130b86d4" integrity sha1-G2HAViGQqN/2rjuyzwIAyhMLhtQ= @@ -2356,12 +2168,12 @@ eslint-plugin-import@^2.22.0: resolve "^1.17.0" tsconfig-paths "^3.9.0" -eslint-plugin-jest@^23.18.0: - version "23.18.0" - resolved "https://registry.yarnpkg.com/eslint-plugin-jest/-/eslint-plugin-jest-23.18.0.tgz#4813eacb181820ed13c5505f400956d176b25af8" - integrity sha512-wLPM/Rm1SGhxrFQ2TKM/BYsYPhn7ch6ZEK92S2o/vGkAAnDXM0I4nTIo745RIX+VlCRMFgBuJEax6XfTHMdeKg== +eslint-plugin-jest@^24.0.0: + version "24.0.0" + resolved "https://registry.yarnpkg.com/eslint-plugin-jest/-/eslint-plugin-jest-24.0.0.tgz#6b1c460c529104c7d16d889e76fe708b281c4d14" + integrity sha512-a0G7hSDbuBCW4PNT6MVpAyfnGbUDOqxzOyhR6wT2BIBnR7MhvfAqd6KKfsTjX+Z3gxzIHiEsihzdClU4cSc6qQ== dependencies: - "@typescript-eslint/experimental-utils" "^2.5.0" + "@typescript-eslint/experimental-utils" "^4.0.1" eslint-plugin-node@^11.1.0: version "11.1.0" @@ -2415,22 +2227,35 @@ eslint-utils@^2.0.0: dependencies: eslint-visitor-keys "^1.1.0" +eslint-utils@^2.1.0: + version "2.1.0" + resolved "https://registry.yarnpkg.com/eslint-utils/-/eslint-utils-2.1.0.tgz#d2de5e03424e707dc10c74068ddedae708741b27" + integrity sha512-w94dQYoauyvlDc43XnGB8lU3Zt713vNChgt4EWwhXAP2XkBvndfxF0AgIqKOOasjPIPzj9JqgwkwbCYD0/V3Zg== + dependencies: + eslint-visitor-keys "^1.1.0" + eslint-visitor-keys@^1.1.0: version "1.1.0" resolved "https://registry.yarnpkg.com/eslint-visitor-keys/-/eslint-visitor-keys-1.1.0.tgz#e2a82cea84ff246ad6fb57f9bde5b46621459ec2" integrity sha512-8y9YjtM1JBJU/A9Kc+SbaOV4y29sSWckBwMHa+FGtVj5gN/sbnKDf6xJUl+8g7FAij9LVaP8C24DUiH/f/2Z9A== -eslint-visitor-keys@^1.2.0: +eslint-visitor-keys@^1.3.0: version "1.3.0" resolved "https://registry.yarnpkg.com/eslint-visitor-keys/-/eslint-visitor-keys-1.3.0.tgz#30ebd1ef7c2fdff01c3a4f151044af25fab0523e" integrity sha512-6J72N8UNa462wa/KFODt/PJ3IU60SDpC3QXC1Hjc1BXXpfL2C9R5+AU7jhe0F6GREqVMh4Juu+NY7xn+6dipUQ== -eslint@^7.4.0: - version "7.4.0" - resolved "https://registry.yarnpkg.com/eslint/-/eslint-7.4.0.tgz#4e35a2697e6c1972f9d6ef2b690ad319f80f206f" - integrity sha512-gU+lxhlPHu45H3JkEGgYhWhkR9wLHHEXC9FbWFnTlEkbKyZKWgWRLgf61E8zWmBuI6g5xKBph9ltg3NtZMVF8g== +eslint-visitor-keys@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/eslint-visitor-keys/-/eslint-visitor-keys-2.0.0.tgz#21fdc8fbcd9c795cc0321f0563702095751511a8" + integrity sha512-QudtT6av5WXels9WjIM7qz1XD1cWGvX4gGXvp/zBn9nXG02D0utdU3Em2m/QjTnrsk6bBjmCygl3rmj118msQQ== + +eslint@^7.8.1: + version "7.8.1" + resolved "https://registry.yarnpkg.com/eslint/-/eslint-7.8.1.tgz#e59de3573fb6a5be8ff526c791571646d124a8fa" + integrity sha512-/2rX2pfhyUG0y+A123d0ccXtMm7DV7sH1m3lk9nk2DZ2LReq39FXHueR9xZwshE5MdfSf0xunSaMWRqyIA6M1w== dependencies: "@babel/code-frame" "^7.0.0" + "@eslint/eslintrc" "^0.1.3" ajv "^6.10.0" chalk "^4.0.0" cross-spawn "^7.0.2" @@ -2438,9 +2263,9 @@ eslint@^7.4.0: doctrine "^3.0.0" enquirer "^2.3.5" eslint-scope "^5.1.0" - eslint-utils "^2.0.0" - eslint-visitor-keys "^1.2.0" - espree "^7.1.0" + eslint-utils "^2.1.0" + eslint-visitor-keys "^1.3.0" + espree "^7.3.0" esquery "^1.2.0" esutils "^2.0.2" file-entry-cache "^5.0.1" @@ -2454,7 +2279,7 @@ eslint@^7.4.0: js-yaml "^3.13.1" json-stable-stringify-without-jsonify "^1.0.1" levn "^0.4.1" - lodash "^4.17.14" + lodash "^4.17.19" minimatch "^3.0.4" natural-compare "^1.4.0" optionator "^0.9.1" @@ -2467,14 +2292,14 @@ eslint@^7.4.0: text-table "^0.2.0" v8-compile-cache "^2.0.3" -espree@^7.1.0: - version "7.1.0" - resolved "https://registry.yarnpkg.com/espree/-/espree-7.1.0.tgz#a9c7f18a752056735bf1ba14cb1b70adc3a5ce1c" - integrity sha512-dcorZSyfmm4WTuTnE5Y7MEN1DyoPYy1ZR783QW1FJoenn7RailyWFsq/UL6ZAAA7uXurN9FIpYyUs3OfiIW+Qw== +espree@^7.3.0: + version "7.3.0" + resolved "https://registry.yarnpkg.com/espree/-/espree-7.3.0.tgz#dc30437cf67947cf576121ebd780f15eeac72348" + integrity sha512-dksIWsvKCixn1yrEXO8UosNSxaDoSYpq9reEjZSbHLpT5hpaCAKTLBwq0RHtLrIr+c0ByiYzWT8KTMRzoRCNlw== dependencies: - acorn "^7.2.0" + acorn "^7.4.0" acorn-jsx "^5.2.0" - eslint-visitor-keys "^1.2.0" + eslint-visitor-keys "^1.3.0" esprima@^4.0.0, esprima@^4.0.1: version "4.0.1" @@ -2566,16 +2391,16 @@ expand-brackets@^2.1.4: snapdragon "^0.8.1" to-regex "^3.0.1" -expect@^26.1.0: - version "26.1.0" - resolved "https://registry.yarnpkg.com/expect/-/expect-26.1.0.tgz#8c62e31d0f8d5a8ebb186ee81473d15dd2fbf7c8" - integrity sha512-QbH4LZXDsno9AACrN9eM0zfnby9G+OsdNgZUohjg/P0mLy1O+/bzTAJGT6VSIjVCe8yKM6SzEl/ckEOFBT7Vnw== +expect@^26.4.2: + version "26.4.2" + resolved "https://registry.yarnpkg.com/expect/-/expect-26.4.2.tgz#36db120928a5a2d7d9736643032de32f24e1b2a1" + integrity sha512-IlJ3X52Z0lDHm7gjEp+m76uX46ldH5VpqmU0006vqDju/285twh7zaWMRhs67VpQhBwjjMchk+p5aA0VkERCAA== dependencies: - "@jest/types" "^26.1.0" + "@jest/types" "^26.3.0" ansi-styles "^4.0.0" - jest-get-type "^26.0.0" - jest-matcher-utils "^26.1.0" - jest-message-util "^26.1.0" + jest-get-type "^26.3.0" + jest-matcher-utils "^26.4.2" + jest-message-util "^26.3.0" jest-regex-util "^26.0.0" express@^4.17.1: @@ -2668,6 +2493,18 @@ fast-diff@^1.1.2: resolved "https://registry.yarnpkg.com/fast-diff/-/fast-diff-1.2.0.tgz#73ee11982d86caaf7959828d519cfe927fac5f03" integrity sha512-xJuoT5+L99XlZ8twedaRf6Ax2TgQVxvgZOYoPKqZufmJib0tL2tegPBOZb1pVNgIhlqDlA0eO0c3wBvQcmzx4w== +fast-glob@^3.1.1: + version "3.2.4" + resolved "https://registry.yarnpkg.com/fast-glob/-/fast-glob-3.2.4.tgz#d20aefbf99579383e7f3cc66529158c9b98554d3" + integrity sha512-kr/Oo6PX51265qeuCYsyGypiO5uJFgBS0jksyG7FUeCyQzNwYnzrNIMR1NXfkZXsMYXYLRAHgISHBz8gQcxKHQ== + dependencies: + "@nodelib/fs.stat" "^2.0.2" + "@nodelib/fs.walk" "^1.2.3" + glob-parent "^5.1.0" + merge2 "^1.3.0" + micromatch "^4.0.2" + picomatch "^2.2.1" + fast-json-stable-stringify@2.x, fast-json-stable-stringify@^2.0.0: version "2.1.0" resolved "https://registry.yarnpkg.com/fast-json-stable-stringify/-/fast-json-stable-stringify-2.1.0.tgz#874bf69c6f404c2b5d99c481341399fd55892633" @@ -2678,6 +2515,13 @@ fast-levenshtein@^2.0.6, fast-levenshtein@~2.0.6: resolved "https://registry.yarnpkg.com/fast-levenshtein/-/fast-levenshtein-2.0.6.tgz#3d8a5c66883a16a30ca8643e851f19baa7797917" integrity sha1-PYpcZog6FqMMqGQ+hR8Zuqd5eRc= +fastq@^1.6.0: + version "1.8.0" + resolved "https://registry.yarnpkg.com/fastq/-/fastq-1.8.0.tgz#550e1f9f59bbc65fe185cb6a9b4d95357107f481" + integrity sha512-SMIZoZdLh/fgofivvIkmknUXyPnvxRE3DhtZ5Me3Mrsk5gyPL42F0xr51TdRXskBxHfMp+07bcYzfsYEsSQA9Q== + dependencies: + reusify "^1.0.4" + fb-watchman@^2.0.0: version "2.0.1" resolved "https://registry.yarnpkg.com/fb-watchman/-/fb-watchman-2.0.1.tgz#fc84fb39d2709cf3ff6d743706157bb5708a8a85" @@ -2685,16 +2529,6 @@ fb-watchman@^2.0.0: dependencies: bser "2.1.1" -feature-policy@0.3.0: - version "0.3.0" - resolved "https://registry.yarnpkg.com/feature-policy/-/feature-policy-0.3.0.tgz#7430e8e54a40da01156ca30aaec1a381ce536069" - integrity sha512-ZtijOTFN7TzCujt1fnNhfWPFPSHeZkesff9AXZj+UEjYBynWNUIYpC87Ve4wHzyexQsImicLu7WsC2LHq7/xrQ== - -figlet@^1.1.1: - version "1.4.0" - resolved "https://registry.yarnpkg.com/figlet/-/figlet-1.4.0.tgz#21c5878b3752a932ebdb8be400e2d10bbcddfd60" - integrity sha512-CxxIjEKHlqGosgXaIA+sikGDdV6KZOOlzPJnYuPgQlOSHZP5h9WIghYI30fyXnwEVeSH7Hedy72gC6zJrFC+SQ== - figures@^3.1.0: version "3.2.0" resolved "https://registry.yarnpkg.com/figures/-/figures-3.2.0.tgz#625c18bd293c604dc4a8ddb2febf0c88341746af" @@ -2783,12 +2617,10 @@ flatted@^2.0.0: resolved "https://registry.yarnpkg.com/flatted/-/flatted-2.0.2.tgz#4575b21e2bcee7434aa9be662f4b7b5f9c2b5138" integrity sha512-r5wGx7YeOwNWNlCA0wQ86zKyDLMQr+/RB8xy74M4hTphfmjlijTSSXGuH8rnvKZnfT9i+75zmd8jcKdMR4O6jA== -follow-redirects@1.5.10: - version "1.5.10" - resolved "https://registry.yarnpkg.com/follow-redirects/-/follow-redirects-1.5.10.tgz#7b7a9f9aea2fdff36786a94ff643ed07f4ff5e2a" - integrity sha512-0V5l4Cizzvqt5D44aTXbFZz+FtyXV1vrDN6qrelxtfYQKW0KO0W2T/hkE8xvGa/540LkZlkaUjO4ailYTFtHVQ== - dependencies: - debug "=3.1.0" +follow-redirects@^1.10.0: + version "1.13.0" + resolved "https://registry.yarnpkg.com/follow-redirects/-/follow-redirects-1.13.0.tgz#b42e8d93a2a7eea5ed88633676d6597bc8e384db" + integrity sha512-aq6gF1BEKje4a9i9+5jimNFIpq4Q1WiwBToeRK5NvZBd/TRsmW8BsJfOEGkr76TbOyPVD3OVDN910EcUNtRYEA== for-in@^1.0.2: version "1.0.2" @@ -2842,15 +2674,6 @@ fs-access@^1.0.1: dependencies: null-check "^1.0.0" -fs-extra@^8.1.0: - version "8.1.0" - resolved "https://registry.yarnpkg.com/fs-extra/-/fs-extra-8.1.0.tgz#49d43c45a88cd9677668cb7be1b46efdb8d2e1c0" - integrity sha512-yhlQgA6mnOJUKOsRUFsgJdQCvkKhcz8tlZG5HBQfReYZy46OwLcY+Zia0mtdHsOo9y/hP+CxMN0TU9QxoOtG4g== - dependencies: - graceful-fs "^4.2.0" - jsonfile "^4.0.0" - universalify "^0.1.0" - fs.realpath@^1.0.0: version "1.0.0" resolved "https://registry.yarnpkg.com/fs.realpath/-/fs.realpath-1.0.0.tgz#1504ad2523158caa40db4a2787cb01411994ea4f" @@ -2897,11 +2720,6 @@ get-pkg-repo@^1.0.0: parse-github-repo-url "^1.3.0" through2 "^2.0.0" -get-stdin@7.0.0: - version "7.0.0" - resolved "https://registry.yarnpkg.com/get-stdin/-/get-stdin-7.0.0.tgz#8d5de98f15171a125c5e516643c7a6d0ea8a96f6" - integrity sha512-zRKcywvrXlXsA0v0i9Io4KDRaAw7+a1ZpjRwl9Wox8PFlVCCHra7E9c4kqXCoCM9nR5tBkaTTZRBoCm60bFqTQ== - get-stdin@^4.0.1: version "4.0.1" resolved "https://registry.yarnpkg.com/get-stdin/-/get-stdin-4.0.1.tgz#b968c6b0a04384324902e8bf1a5df32579a450fe" @@ -2949,17 +2767,6 @@ git-raw-commits@2.0.0: split2 "^2.0.0" through2 "^2.0.0" -git-raw-commits@^2.0.0: - version "2.0.7" - resolved "https://registry.yarnpkg.com/git-raw-commits/-/git-raw-commits-2.0.7.tgz#02e9357727a9755efa8e14dd5e59b381c29068fb" - integrity sha512-SkwrTqrDxw8y0G1uGJ9Zw13F7qu3LF8V4BifyDeiJCxSnjRGZD9SaoMiMqUvvXMXh6S3sOQ1DsBN7L2fMUZW/g== - dependencies: - dargs "^7.0.0" - lodash.template "^4.0.2" - meow "^7.0.0" - split2 "^2.0.0" - through2 "^3.0.0" - git-remote-origin-url@^2.0.0: version "2.0.0" resolved "https://registry.yarnpkg.com/git-remote-origin-url/-/git-remote-origin-url-2.0.0.tgz#5282659dae2107145a11126112ad3216ec5fa65f" @@ -2976,6 +2783,14 @@ git-semver-tags@^4.0.0: meow "^7.0.0" semver "^6.0.0" +git-semver-tags@^4.1.0: + version "4.1.0" + resolved "https://registry.yarnpkg.com/git-semver-tags/-/git-semver-tags-4.1.0.tgz#0146c9bc24ee96104c99f443071c8c2d7dc848e3" + integrity sha512-TcxAGeo03HdErzKzi4fDD+xEL7gi8r2Y5YSxH6N2XYdVSV5UkBwfrt7Gqo1b+uSHCjy/sa9Y6BBBxxFLxfbhTg== + dependencies: + meow "^7.0.0" + semver "^6.0.0" + gitconfiglocal@^1.0.0: version "1.0.0" resolved "https://registry.yarnpkg.com/gitconfiglocal/-/gitconfiglocal-1.0.0.tgz#41d045f3851a5ea88f03f24ca1c6178114464b9b" @@ -2983,14 +2798,14 @@ gitconfiglocal@^1.0.0: dependencies: ini "^1.3.2" -glob-parent@^5.0.0, glob-parent@~5.1.0: +glob-parent@^5.0.0, glob-parent@^5.1.0, glob-parent@~5.1.0: version "5.1.1" resolved "https://registry.yarnpkg.com/glob-parent/-/glob-parent-5.1.1.tgz#b6c1ef417c4e5663ea498f1c45afac6916bbc229" integrity sha512-FnI+VGOpnlGHWZxthPGR+QhR78fuiK0sNLkHQv+bL9fQi57lNNdquIbna/WrfROrolq8GK5Ek6BiMwqL/voRYQ== dependencies: is-glob "^4.0.1" -glob@^7.0.0, glob@^7.1.1, glob@^7.1.2, glob@^7.1.3, glob@^7.1.4, glob@^7.1.6: +glob@^7.0.0, glob@^7.1.1, glob@^7.1.2, glob@^7.1.3, glob@^7.1.4: version "7.1.6" resolved "https://registry.yarnpkg.com/glob/-/glob-7.1.6.tgz#141f33b81a7c2492e125594307480c46679278a6" integrity sha512-LwaxwyZ72Lk7vZINtNNrywX0ZuLyStrdDtabefZKAY5ZGJhVtgdznluResxNmPitE0SAO+O26sWTHeKSI2wMBA== @@ -3002,13 +2817,6 @@ glob@^7.0.0, glob@^7.1.1, glob@^7.1.2, glob@^7.1.3, glob@^7.1.4, glob@^7.1.6: once "^1.3.0" path-is-absolute "^1.0.0" -global-dirs@^0.1.1: - version "0.1.1" - resolved "https://registry.yarnpkg.com/global-dirs/-/global-dirs-0.1.1.tgz#b319c0dd4607f353f3be9cca4c72fc148c49f445" - integrity sha1-sxnA3UYH81PzvpzKTHL8FIxJ9EU= - dependencies: - ini "^1.3.4" - globals@^11.1.0: version "11.12.0" resolved "https://registry.yarnpkg.com/globals/-/globals-11.12.0.tgz#ab8795338868a0babd8525758018c2a7eb95c42e" @@ -3021,12 +2829,24 @@ globals@^12.1.0: dependencies: type-fest "^0.8.1" +globby@^11.0.1: + version "11.0.1" + resolved "https://registry.yarnpkg.com/globby/-/globby-11.0.1.tgz#9a2bf107a068f3ffeabc49ad702c79ede8cfd357" + integrity sha512-iH9RmgwCmUJHi2z5o2l3eTtGBtXek1OYlHrbcxOYugyHLmAsZrPj43OtHThd62Buh/Vv6VyCBD2bdyWcGNQqoQ== + 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" + google-libphonenumber@^3.2.8: version "3.2.10" resolved "https://registry.yarnpkg.com/google-libphonenumber/-/google-libphonenumber-3.2.10.tgz#021a314652747d736a39e2e60dc670f0431425ad" integrity sha512-TsckE9O8QgqaIeaOXPjcJa4/kX3BzFdO1oCbMfmUpRZckml4xJhjJVxaT9Mdt/VrZZkT9lX44eHAEWfJK1tHtw== -graceful-fs@^4.1.2, graceful-fs@^4.1.6, graceful-fs@^4.2.0, graceful-fs@^4.2.4: +graceful-fs@^4.1.2, graceful-fs@^4.2.4: version "4.2.4" resolved "https://registry.yarnpkg.com/graceful-fs/-/graceful-fs-4.2.4.tgz#2256bde14d3632958c465ebc96dc467ca07a29fb" integrity sha512-WjKPNJF79dtJAVniUlGGWHYGz2jWxT6VhN/4m1NdkbZ2nOsEF+cI1Edgql5zCRhs/VsQYRvrXctxktVXZUkixw== @@ -3066,13 +2886,6 @@ hard-rejection@^2.1.0: resolved "https://registry.yarnpkg.com/hard-rejection/-/hard-rejection-2.1.0.tgz#1c6eda5c1685c63942766d79bb40ae773cecd883" integrity sha512-VIZB+ibDhx7ObhAe7OVtoEbuP4h/MuOTHJ+J8h/eBXotJYl0fBgR72xDFCKgIh22OJZIOVNxBMWuhAr10r8HdA== -has-ansi@^2.0.0: - version "2.0.0" - resolved "https://registry.yarnpkg.com/has-ansi/-/has-ansi-2.0.0.tgz#34f5049ce1ecdf2b0649af3ef24e45ed35416d91" - integrity sha1-NPUEnOHs3ysGSa8+8k5F7TVBbZE= - dependencies: - ansi-regex "^2.0.0" - has-flag@^3.0.0: version "3.0.0" resolved "https://registry.yarnpkg.com/has-flag/-/has-flag-3.0.0.tgz#b5d454dc2199ae225699f3467e5a07f3b955bafd" @@ -3126,65 +2939,11 @@ has@^1.0.3: dependencies: function-bind "^1.1.1" -helmet-crossdomain@0.4.0: - version "0.4.0" - resolved "https://registry.yarnpkg.com/helmet-crossdomain/-/helmet-crossdomain-0.4.0.tgz#5f1fe5a836d0325f1da0a78eaa5fd8429078894e" - integrity sha512-AB4DTykRw3HCOxovD1nPR16hllrVImeFp5VBV9/twj66lJ2nU75DP8FPL0/Jp4jj79JhTfG+pFI2MD02kWJ+fA== - -helmet-csp@2.10.0: - version "2.10.0" - resolved "https://registry.yarnpkg.com/helmet-csp/-/helmet-csp-2.10.0.tgz#685dde1747bc16c5e28ad9d91e229a69f0a85e84" - integrity sha512-Rz953ZNEFk8sT2XvewXkYN0Ho4GEZdjAZy4stjiEQV3eN7GDxg1QKmYggH7otDyIA7uGA6XnUMVSgeJwbR5X+w== - dependencies: - bowser "2.9.0" - camelize "1.0.0" - content-security-policy-builder "2.1.0" - dasherize "2.0.0" - -helmet@^3.23.3: - version "3.23.3" - resolved "https://registry.yarnpkg.com/helmet/-/helmet-3.23.3.tgz#5ba30209c5f73ded4ab65746a3a11bedd4579ab7" - integrity sha512-U3MeYdzPJQhtvqAVBPntVgAvNSOJyagwZwyKsFdyRa8TV3pOKVFljalPOCxbw5Wwf2kncGhmP0qHjyazIdNdSA== - dependencies: - depd "2.0.0" - dont-sniff-mimetype "1.1.0" - feature-policy "0.3.0" - helmet-crossdomain "0.4.0" - helmet-csp "2.10.0" - hide-powered-by "1.1.0" - hpkp "2.0.0" - hsts "2.2.0" - nocache "2.1.0" - referrer-policy "1.2.0" - x-xss-protection "1.3.0" - -hide-powered-by@1.1.0: - version "1.1.0" - resolved "https://registry.yarnpkg.com/hide-powered-by/-/hide-powered-by-1.1.0.tgz#be3ea9cab4bdb16f8744be873755ca663383fa7a" - integrity sha512-Io1zA2yOA1YJslkr+AJlWSf2yWFkKjvkcL9Ni1XSUqnGLr/qRQe2UI3Cn/J9MsJht7yEVCe0SscY1HgVMujbgg== - -highlight.js@^9.6.0: - version "9.18.1" - resolved "https://registry.yarnpkg.com/highlight.js/-/highlight.js-9.18.1.tgz#ed21aa001fe6252bb10a3d76d47573c6539fe13c" - integrity sha512-OrVKYz70LHsnCgmbXctv/bfuvntIKDz177h0Co37DQ5jamGZLVmoCVMtjMtNZY3X9DrCcKfklHPNeA0uPZhSJg== - hosted-git-info@^2.1.4: version "2.8.8" resolved "https://registry.yarnpkg.com/hosted-git-info/-/hosted-git-info-2.8.8.tgz#7539bd4bc1e0e0a895815a2e0262420b12858488" integrity sha512-f/wzC2QaWBs7t9IYqB4T3sR1xviIViXJRJTWBlx2Gf3g0Xi5vI7Yy4koXQ1c9OYDGHN9sBy1DQ2AB8fqZBWhUg== -hpkp@2.0.0: - version "2.0.0" - resolved "https://registry.yarnpkg.com/hpkp/-/hpkp-2.0.0.tgz#10e142264e76215a5d30c44ec43de64dee6d1672" - integrity sha1-EOFCJk52IVpdMMROxD3mTe5tFnI= - -hsts@2.2.0: - version "2.2.0" - resolved "https://registry.yarnpkg.com/hsts/-/hsts-2.2.0.tgz#09119d42f7a8587035d027dda4522366fe75d964" - integrity sha512-ToaTnQ2TbJkochoVcdXYm4HOCliNozlviNsg+X2XQLQvZNI/kCHR9rZxVYpJB3UPcHz80PgxRyWQ7PdU1r+VBQ== - dependencies: - depd "2.0.0" - html-encoding-sniffer@^2.0.1: version "2.0.1" resolved "https://registry.yarnpkg.com/html-encoding-sniffer/-/html-encoding-sniffer-2.0.1.tgz#42a6dc4fd33f00281176e8b23759ca4e4fa185f3" @@ -3240,11 +2999,6 @@ iconv-lite@0.4.24: dependencies: safer-buffer ">= 2.1.2 < 3" -ieee754@^1.1.4: - version "1.1.13" - resolved "https://registry.yarnpkg.com/ieee754/-/ieee754-1.1.13.tgz#ec168558e95aa181fd87d37f55c32bbcb6708b84" - integrity sha512-4vf7I2LYV/HaWerSo3XmlMkp5eZ83i+/CDluXi/IGTs/O1sejBNhTtnxzmRZfvOUqj7lZjqHkeTvpgSFDlWZTg== - ignore@^4.0.6: version "4.0.6" resolved "https://registry.yarnpkg.com/ignore/-/ignore-4.0.6.tgz#750e3db5862087b4737ebac8207ffd1ef27b25fc" @@ -3255,7 +3009,12 @@ ignore@^5.1.1: resolved "https://registry.yarnpkg.com/ignore/-/ignore-5.1.6.tgz#643194ad4bf2712f37852e386b6998eff0db2106" integrity sha512-cgXgkypZBcCnOgSihyeqbo6gjIaIyDqPQB7Ra4vhE9m6kigdGoQDMHjviFhRZo3IMlRy6yElosoviMs5YxZXUA== -import-fresh@^3.0.0, import-fresh@^3.1.0: +ignore@^5.1.4: + version "5.1.8" + resolved "https://registry.yarnpkg.com/ignore/-/ignore-5.1.8.tgz#f150a8b50a34289b33e22f5889abd4d8016f0e57" + integrity sha512-BMpfD7PpiETpBl/A6S498BaIJ6Y/ABT93ETbby2fP00v4EbvPBXWEoaR1UBPKs3iR53pJY7EtZk5KACI57i1Uw== + +import-fresh@^3.0.0, import-fresh@^3.2.1: version "3.2.1" resolved "https://registry.yarnpkg.com/import-fresh/-/import-fresh-3.2.1.tgz#633ff618506e793af5ac91bf48b72677e15cbe66" integrity sha512-6e1q1cnWP2RXD9/keSkxHScg508CdXqXWgWBaETNhyuBFz+kUZlKboh+ISK+bU++DmbHimVBrOz/zzPe0sZ3sQ== @@ -3301,7 +3060,7 @@ inflight@^1.0.4: once "^1.3.0" wrappy "1" -inherits@2, inherits@2.0.4, inherits@^2.0.1, inherits@^2.0.3, inherits@~2.0.1, inherits@~2.0.3: +inherits@2, inherits@2.0.4, inherits@^2.0.3, inherits@~2.0.1, inherits@~2.0.3: version "2.0.4" resolved "https://registry.yarnpkg.com/inherits/-/inherits-2.0.4.tgz#0fa2c64f932917c3433a0ded55363aae37416b7c" integrity sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ== @@ -3311,7 +3070,7 @@ inherits@2.0.3: resolved "https://registry.yarnpkg.com/inherits/-/inherits-2.0.3.tgz#633c2c83e3da42a502f52466022480f4208261de" integrity sha1-Yzwsg+PaQqUC9SRmAiSA9CCCYd4= -ini@^1.3.2, ini@^1.3.4: +ini@^1.3.2: version "1.3.5" resolved "https://registry.yarnpkg.com/ini/-/ini-1.3.5.tgz#eee25f56db1c9ec6085e0c22778083f596abf927" integrity sha512-RZY5huIKCMRWDUqZlEi72f/lmXKMvuszcMBduliQ3nnWbx9X/ZBQO7DijMEYS9EhHBb2qacRUMtC7svLwe0lcw== @@ -3472,10 +3231,10 @@ is-number@^7.0.0: resolved "https://registry.yarnpkg.com/is-number/-/is-number-7.0.0.tgz#7535345b896734d5f80c4d06c50955527a14f12b" integrity sha512-41Cifkg6e8TylSpdtTpeLVMqvSBEVzTttHvERD741+pnZ8ANv0004MRL43QKPDlK9cGvNp6NZWZUBlbGXYxxng== -is-obj@^1.0.0: - version "1.0.1" - resolved "https://registry.yarnpkg.com/is-obj/-/is-obj-1.0.1.tgz#3e4729ac1f5fde025cd7d83a896dab9f4f67db0f" - integrity sha1-PkcprB9f3gJc19g6iW2rn09n2w8= +is-obj@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/is-obj/-/is-obj-2.0.0.tgz#473fb05d973705e3fd9620545018ca8e22ef4982" + integrity sha512-drqDG3cbczxxEJRoOXcOjtdp1J/lyp1mNn0xaznRs8+muBhgQcrnbspox5X5fOw0HnMnbfDzvnEMEtqDEJEo8w== is-plain-obj@^1.1.0: version "1.1.0" @@ -3545,7 +3304,7 @@ is-windows@^1.0.2: resolved "https://registry.yarnpkg.com/is-windows/-/is-windows-1.0.2.tgz#d1850eb9791ecd18e6182ce12a30f396634bb19d" integrity sha512-eXK1UInq2bPmjyX6e3VHIzMLobc4J94i4AWn+Hpq3OU5KkrRC96OAcR3PRJ/pGu6m8TRnBHP9dkXQVsT/COVIA== -is-wsl@^2.1.1: +is-wsl@^2.2.0: version "2.2.0" resolved "https://registry.yarnpkg.com/is-wsl/-/is-wsl-2.2.0.tgz#74a4c76e77ca9fd3f932f290c17ea326cd157271" integrity sha512-fKzAra0rGJUUBwGBgNkHZuToZcn+TtXHpeCgmkMJMMYx1sQDYaCSyjJBSCa2nH1DGm7s3n1oBnohoVTBaN7Lww== @@ -3625,57 +3384,57 @@ istanbul-reports@^3.0.2: html-escaper "^2.0.0" istanbul-lib-report "^3.0.0" -jest-changed-files@^26.1.0: - version "26.1.0" - resolved "https://registry.yarnpkg.com/jest-changed-files/-/jest-changed-files-26.1.0.tgz#de66b0f30453bca2aff98e9400f75905da495305" - integrity sha512-HS5MIJp3B8t0NRKGMCZkcDUZo36mVRvrDETl81aqljT1S9tqiHRSpyoOvWg9ZilzZG9TDisDNaN1IXm54fLRZw== +jest-changed-files@^26.3.0: + version "26.3.0" + resolved "https://registry.yarnpkg.com/jest-changed-files/-/jest-changed-files-26.3.0.tgz#68fb2a7eb125f50839dab1f5a17db3607fe195b1" + integrity sha512-1C4R4nijgPltX6fugKxM4oQ18zimS7LqQ+zTTY8lMCMFPrxqBFb7KJH0Z2fRQJvw2Slbaipsqq7s1mgX5Iot+g== dependencies: - "@jest/types" "^26.1.0" + "@jest/types" "^26.3.0" execa "^4.0.0" throat "^5.0.0" -jest-cli@^26.1.0: - version "26.1.0" - resolved "https://registry.yarnpkg.com/jest-cli/-/jest-cli-26.1.0.tgz#eb9ec8a18cf3b6aa556d9deaa9e24be12b43ad87" - integrity sha512-Imumvjgi3rU7stq6SJ1JUEMaV5aAgJYXIs0jPqdUnF47N/Tk83EXfmtvNKQ+SnFVI6t6mDOvfM3aA9Sg6kQPSw== +jest-cli@^26.4.2: + version "26.4.2" + resolved "https://registry.yarnpkg.com/jest-cli/-/jest-cli-26.4.2.tgz#24afc6e4dfc25cde4c7ec4226fb7db5f157c21da" + integrity sha512-zb+lGd/SfrPvoRSC/0LWdaWCnscXc1mGYW//NP4/tmBvRPT3VntZ2jtKUONsRi59zc5JqmsSajA9ewJKFYp8Cw== dependencies: - "@jest/core" "^26.1.0" - "@jest/test-result" "^26.1.0" - "@jest/types" "^26.1.0" + "@jest/core" "^26.4.2" + "@jest/test-result" "^26.3.0" + "@jest/types" "^26.3.0" chalk "^4.0.0" exit "^0.1.2" graceful-fs "^4.2.4" import-local "^3.0.2" is-ci "^2.0.0" - jest-config "^26.1.0" - jest-util "^26.1.0" - jest-validate "^26.1.0" + jest-config "^26.4.2" + jest-util "^26.3.0" + jest-validate "^26.4.2" prompts "^2.0.1" yargs "^15.3.1" -jest-config@^26.1.0: - version "26.1.0" - resolved "https://registry.yarnpkg.com/jest-config/-/jest-config-26.1.0.tgz#9074f7539acc185e0113ad6d22ed589c16a37a73" - integrity sha512-ONTGeoMbAwGCdq4WuKkMcdMoyfs5CLzHEkzFOlVvcDXufZSaIWh/OXMLa2fwKXiOaFcqEw8qFr4VOKJQfn4CVw== +jest-config@^26.4.2: + version "26.4.2" + resolved "https://registry.yarnpkg.com/jest-config/-/jest-config-26.4.2.tgz#da0cbb7dc2c131ffe831f0f7f2a36256e6086558" + integrity sha512-QBf7YGLuToiM8PmTnJEdRxyYy3mHWLh24LJZKVdXZ2PNdizSe1B/E8bVm+HYcjbEzGuVXDv/di+EzdO/6Gq80A== dependencies: "@babel/core" "^7.1.0" - "@jest/test-sequencer" "^26.1.0" - "@jest/types" "^26.1.0" - babel-jest "^26.1.0" + "@jest/test-sequencer" "^26.4.2" + "@jest/types" "^26.3.0" + babel-jest "^26.3.0" chalk "^4.0.0" deepmerge "^4.2.2" glob "^7.1.1" graceful-fs "^4.2.4" - jest-environment-jsdom "^26.1.0" - jest-environment-node "^26.1.0" - jest-get-type "^26.0.0" - jest-jasmine2 "^26.1.0" + jest-environment-jsdom "^26.3.0" + jest-environment-node "^26.3.0" + jest-get-type "^26.3.0" + jest-jasmine2 "^26.4.2" jest-regex-util "^26.0.0" - jest-resolve "^26.1.0" - jest-util "^26.1.0" - jest-validate "^26.1.0" + jest-resolve "^26.4.0" + jest-util "^26.3.0" + jest-validate "^26.4.2" micromatch "^4.0.2" - pretty-format "^26.1.0" + pretty-format "^26.4.2" jest-diff@^25.2.1: version "25.5.0" @@ -3687,15 +3446,15 @@ jest-diff@^25.2.1: jest-get-type "^25.2.6" pretty-format "^25.5.0" -jest-diff@^26.1.0: - version "26.1.0" - resolved "https://registry.yarnpkg.com/jest-diff/-/jest-diff-26.1.0.tgz#00a549bdc936c9691eb4dc25d1fbd78bf456abb2" - integrity sha512-GZpIcom339y0OXznsEKjtkfKxNdg7bVbEofK8Q6MnevTIiR1jNhDWKhRX6X0SDXJlwn3dy59nZ1z55fLkAqPWg== +jest-diff@^26.4.2: + version "26.4.2" + resolved "https://registry.yarnpkg.com/jest-diff/-/jest-diff-26.4.2.tgz#a1b7b303bcc534aabdb3bd4a7caf594ac059f5aa" + integrity sha512-6T1XQY8U28WH0Z5rGpQ+VqZSZz8EN8rZcBtfvXaOkbwxIEeRre6qnuZQlbY1AJ4MKDxQF8EkrCvK+hL/VkyYLQ== dependencies: chalk "^4.0.0" - diff-sequences "^26.0.0" - jest-get-type "^26.0.0" - pretty-format "^26.1.0" + diff-sequences "^26.3.0" + jest-get-type "^26.3.0" + pretty-format "^26.4.2" jest-docblock@^26.0.0: version "26.0.0" @@ -3704,118 +3463,122 @@ jest-docblock@^26.0.0: dependencies: detect-newline "^3.0.0" -jest-each@^26.1.0: - version "26.1.0" - resolved "https://registry.yarnpkg.com/jest-each/-/jest-each-26.1.0.tgz#e35449875009a22d74d1bda183b306db20f286f7" - integrity sha512-lYiSo4Igr81q6QRsVQq9LIkJW0hZcKxkIkHzNeTMPENYYDw/W/Raq28iJ0sLlNFYz2qxxeLnc5K2gQoFYlu2bA== +jest-each@^26.4.2: + version "26.4.2" + resolved "https://registry.yarnpkg.com/jest-each/-/jest-each-26.4.2.tgz#bb14f7f4304f2bb2e2b81f783f989449b8b6ffae" + integrity sha512-p15rt8r8cUcRY0Mvo1fpkOGYm7iI8S6ySxgIdfh3oOIv+gHwrHTy5VWCGOecWUhDsit4Nz8avJWdT07WLpbwDA== dependencies: - "@jest/types" "^26.1.0" + "@jest/types" "^26.3.0" chalk "^4.0.0" - jest-get-type "^26.0.0" - jest-util "^26.1.0" - pretty-format "^26.1.0" - -jest-environment-jsdom@^26.1.0: - version "26.1.0" - resolved "https://registry.yarnpkg.com/jest-environment-jsdom/-/jest-environment-jsdom-26.1.0.tgz#9dc7313ffe1b59761dad1fedb76e2503e5d37c5b" - integrity sha512-dWfiJ+spunVAwzXbdVqPH1LbuJW/kDL+FyqgA5YzquisHqTi0g9hquKif9xKm7c1bKBj6wbmJuDkeMCnxZEpUw== - dependencies: - "@jest/environment" "^26.1.0" - "@jest/fake-timers" "^26.1.0" - "@jest/types" "^26.1.0" - jest-mock "^26.1.0" - jest-util "^26.1.0" + jest-get-type "^26.3.0" + jest-util "^26.3.0" + pretty-format "^26.4.2" + +jest-environment-jsdom@^26.3.0: + version "26.3.0" + resolved "https://registry.yarnpkg.com/jest-environment-jsdom/-/jest-environment-jsdom-26.3.0.tgz#3b749ba0f3a78e92ba2c9ce519e16e5dd515220c" + integrity sha512-zra8He2btIMJkAzvLaiZ9QwEPGEetbxqmjEBQwhH3CA+Hhhu0jSiEJxnJMbX28TGUvPLxBt/zyaTLrOPF4yMJA== + dependencies: + "@jest/environment" "^26.3.0" + "@jest/fake-timers" "^26.3.0" + "@jest/types" "^26.3.0" + "@types/node" "*" + jest-mock "^26.3.0" + jest-util "^26.3.0" jsdom "^16.2.2" -jest-environment-node@^26.1.0: - version "26.1.0" - resolved "https://registry.yarnpkg.com/jest-environment-node/-/jest-environment-node-26.1.0.tgz#8bb387b3eefb132eab7826f9a808e4e05618960b" - integrity sha512-DNm5x1aQH0iRAe9UYAkZenuzuJ69VKzDCAYISFHQ5i9e+2Tbeu2ONGY7YStubCLH8a1wdKBgqScYw85+ySxqxg== +jest-environment-node@^26.3.0: + version "26.3.0" + resolved "https://registry.yarnpkg.com/jest-environment-node/-/jest-environment-node-26.3.0.tgz#56c6cfb506d1597f94ee8d717072bda7228df849" + integrity sha512-c9BvYoo+FGcMj5FunbBgtBnbR5qk3uky8PKyRVpSfe2/8+LrNQMiXX53z6q2kY+j15SkjQCOSL/6LHnCPLVHNw== dependencies: - "@jest/environment" "^26.1.0" - "@jest/fake-timers" "^26.1.0" - "@jest/types" "^26.1.0" - jest-mock "^26.1.0" - jest-util "^26.1.0" + "@jest/environment" "^26.3.0" + "@jest/fake-timers" "^26.3.0" + "@jest/types" "^26.3.0" + "@types/node" "*" + jest-mock "^26.3.0" + jest-util "^26.3.0" jest-get-type@^25.2.6: version "25.2.6" resolved "https://registry.yarnpkg.com/jest-get-type/-/jest-get-type-25.2.6.tgz#0b0a32fab8908b44d508be81681487dbabb8d877" integrity sha512-DxjtyzOHjObRM+sM1knti6or+eOgcGU4xVSb2HNP1TqO4ahsT+rqZg+nyqHWJSvWgKC5cG3QjGFBqxLghiF/Ig== -jest-get-type@^26.0.0: - version "26.0.0" - resolved "https://registry.yarnpkg.com/jest-get-type/-/jest-get-type-26.0.0.tgz#381e986a718998dbfafcd5ec05934be538db4039" - integrity sha512-zRc1OAPnnws1EVfykXOj19zo2EMw5Hi6HLbFCSjpuJiXtOWAYIjNsHVSbpQ8bDX7L5BGYGI8m+HmKdjHYFF0kg== +jest-get-type@^26.3.0: + version "26.3.0" + resolved "https://registry.yarnpkg.com/jest-get-type/-/jest-get-type-26.3.0.tgz#e97dc3c3f53c2b406ca7afaed4493b1d099199e0" + integrity sha512-TpfaviN1R2pQWkIihlfEanwOXK0zcxrKEE4MlU6Tn7keoXdN6/3gK/xl0yEh8DOunn5pOVGKf8hB4R9gVh04ig== -jest-haste-map@^26.1.0: - version "26.1.0" - resolved "https://registry.yarnpkg.com/jest-haste-map/-/jest-haste-map-26.1.0.tgz#ef31209be73f09b0d9445e7d213e1b53d0d1476a" - integrity sha512-WeBS54xCIz9twzkEdm6+vJBXgRBQfdbbXD0dk8lJh7gLihopABlJmIQFdWSDDtuDe4PRiObsjZSUjbJ1uhWEpA== +jest-haste-map@^26.3.0: + version "26.3.0" + resolved "https://registry.yarnpkg.com/jest-haste-map/-/jest-haste-map-26.3.0.tgz#c51a3b40100d53ab777bfdad382d2e7a00e5c726" + integrity sha512-DHWBpTJgJhLLGwE5Z1ZaqLTYqeODQIZpby0zMBsCU9iRFHYyhklYqP4EiG73j5dkbaAdSZhgB938mL51Q5LeZA== dependencies: - "@jest/types" "^26.1.0" + "@jest/types" "^26.3.0" "@types/graceful-fs" "^4.1.2" + "@types/node" "*" anymatch "^3.0.3" fb-watchman "^2.0.0" graceful-fs "^4.2.4" - jest-serializer "^26.1.0" - jest-util "^26.1.0" - jest-worker "^26.1.0" + jest-regex-util "^26.0.0" + jest-serializer "^26.3.0" + jest-util "^26.3.0" + jest-worker "^26.3.0" micromatch "^4.0.2" sane "^4.0.3" walker "^1.0.7" - which "^2.0.2" optionalDependencies: fsevents "^2.1.2" -jest-jasmine2@^26.1.0: - version "26.1.0" - resolved "https://registry.yarnpkg.com/jest-jasmine2/-/jest-jasmine2-26.1.0.tgz#4dfe349b2b2d3c6b3a27c024fd4cb57ac0ed4b6f" - integrity sha512-1IPtoDKOAG+MeBrKvvuxxGPJb35MTTRSDglNdWWCndCB3TIVzbLThRBkwH9P081vXLgiJHZY8Bz3yzFS803xqQ== +jest-jasmine2@^26.4.2: + version "26.4.2" + resolved "https://registry.yarnpkg.com/jest-jasmine2/-/jest-jasmine2-26.4.2.tgz#18a9d5bec30904267ac5e9797570932aec1e2257" + integrity sha512-z7H4EpCldHN1J8fNgsja58QftxBSL+JcwZmaXIvV9WKIM+x49F4GLHu/+BQh2kzRKHAgaN/E82od+8rTOBPyPA== dependencies: "@babel/traverse" "^7.1.0" - "@jest/environment" "^26.1.0" - "@jest/source-map" "^26.1.0" - "@jest/test-result" "^26.1.0" - "@jest/types" "^26.1.0" + "@jest/environment" "^26.3.0" + "@jest/source-map" "^26.3.0" + "@jest/test-result" "^26.3.0" + "@jest/types" "^26.3.0" + "@types/node" "*" chalk "^4.0.0" co "^4.6.0" - expect "^26.1.0" + expect "^26.4.2" is-generator-fn "^2.0.0" - jest-each "^26.1.0" - jest-matcher-utils "^26.1.0" - jest-message-util "^26.1.0" - jest-runtime "^26.1.0" - jest-snapshot "^26.1.0" - jest-util "^26.1.0" - pretty-format "^26.1.0" + jest-each "^26.4.2" + jest-matcher-utils "^26.4.2" + jest-message-util "^26.3.0" + jest-runtime "^26.4.2" + jest-snapshot "^26.4.2" + jest-util "^26.3.0" + pretty-format "^26.4.2" throat "^5.0.0" -jest-leak-detector@^26.1.0: - version "26.1.0" - resolved "https://registry.yarnpkg.com/jest-leak-detector/-/jest-leak-detector-26.1.0.tgz#039c3a07ebcd8adfa984b6ac015752c35792e0a6" - integrity sha512-dsMnKF+4BVOZwvQDlgn3MG+Ns4JuLv8jNvXH56bgqrrboyCbI1rQg6EI5rs+8IYagVcfVP2yZFKfWNZy0rK0Hw== +jest-leak-detector@^26.4.2: + version "26.4.2" + resolved "https://registry.yarnpkg.com/jest-leak-detector/-/jest-leak-detector-26.4.2.tgz#c73e2fa8757bf905f6f66fb9e0070b70fa0f573f" + integrity sha512-akzGcxwxtE+9ZJZRW+M2o+nTNnmQZxrHJxX/HjgDaU5+PLmY1qnQPnMjgADPGCRPhB+Yawe1iij0REe+k/aHoA== dependencies: - jest-get-type "^26.0.0" - pretty-format "^26.1.0" + jest-get-type "^26.3.0" + pretty-format "^26.4.2" -jest-matcher-utils@^26.1.0: - version "26.1.0" - resolved "https://registry.yarnpkg.com/jest-matcher-utils/-/jest-matcher-utils-26.1.0.tgz#cf75a41bd413dda784f022de5a65a2a5c73a5c92" - integrity sha512-PW9JtItbYvES/xLn5mYxjMd+Rk+/kIt88EfH3N7w9KeOrHWaHrdYPnVHndGbsFGRJ2d5gKtwggCvkqbFDoouQA== +jest-matcher-utils@^26.4.2: + version "26.4.2" + resolved "https://registry.yarnpkg.com/jest-matcher-utils/-/jest-matcher-utils-26.4.2.tgz#fa81f3693f7cb67e5fc1537317525ef3b85f4b06" + integrity sha512-KcbNqWfWUG24R7tu9WcAOKKdiXiXCbMvQYT6iodZ9k1f7065k0keUOW6XpJMMvah+hTfqkhJhRXmA3r3zMAg0Q== dependencies: chalk "^4.0.0" - jest-diff "^26.1.0" - jest-get-type "^26.0.0" - pretty-format "^26.1.0" + jest-diff "^26.4.2" + jest-get-type "^26.3.0" + pretty-format "^26.4.2" -jest-message-util@^26.1.0: - version "26.1.0" - resolved "https://registry.yarnpkg.com/jest-message-util/-/jest-message-util-26.1.0.tgz#52573fbb8f5cea443c4d1747804d7a238a3e233c" - integrity sha512-dY0+UlldiAJwNDJ08SF0HdF32g9PkbF2NRK/+2iMPU40O6q+iSn1lgog/u0UH8ksWoPv0+gNq8cjhYO2MFtT0g== +jest-message-util@^26.3.0: + version "26.3.0" + resolved "https://registry.yarnpkg.com/jest-message-util/-/jest-message-util-26.3.0.tgz#3bdb538af27bb417f2d4d16557606fd082d5841a" + integrity sha512-xIavRYqr4/otGOiLxLZGj3ieMmjcNE73Ui+LdSW/Y790j5acqCsAdDiLIbzHCZMpN07JOENRWX5DcU+OQ+TjTA== dependencies: "@babel/code-frame" "^7.0.0" - "@jest/types" "^26.1.0" + "@jest/types" "^26.3.0" "@types/stack-utils" "^1.0.1" chalk "^4.0.0" graceful-fs "^4.2.4" @@ -3823,132 +3586,135 @@ jest-message-util@^26.1.0: slash "^3.0.0" stack-utils "^2.0.2" -jest-mock@^26.1.0: - version "26.1.0" - resolved "https://registry.yarnpkg.com/jest-mock/-/jest-mock-26.1.0.tgz#80d8286da1f05a345fbad1bfd6fa49a899465d3d" - integrity sha512-1Rm8EIJ3ZFA8yCIie92UbxZWj9SuVmUGcyhLHyAhY6WI3NIct38nVcfOPWhJteqSn8V8e3xOMha9Ojfazfpovw== +jest-mock@^26.3.0: + version "26.3.0" + resolved "https://registry.yarnpkg.com/jest-mock/-/jest-mock-26.3.0.tgz#ee62207c3c5ebe5f35b760e1267fee19a1cfdeba" + integrity sha512-PeaRrg8Dc6mnS35gOo/CbZovoDPKAeB1FICZiuagAgGvbWdNNyjQjkOaGUa/3N3JtpQ/Mh9P4A2D4Fv51NnP8Q== dependencies: - "@jest/types" "^26.1.0" + "@jest/types" "^26.3.0" + "@types/node" "*" -jest-pnp-resolver@^1.2.1: - version "1.2.1" - resolved "https://registry.yarnpkg.com/jest-pnp-resolver/-/jest-pnp-resolver-1.2.1.tgz#ecdae604c077a7fbc70defb6d517c3c1c898923a" - integrity sha512-pgFw2tm54fzgYvc/OHrnysABEObZCUNFnhjoRjaVOCN8NYc032/gVjPaHD4Aq6ApkSieWtfKAFQtmDKAmhupnQ== +jest-pnp-resolver@^1.2.2: + version "1.2.2" + resolved "https://registry.yarnpkg.com/jest-pnp-resolver/-/jest-pnp-resolver-1.2.2.tgz#b704ac0ae028a89108a4d040b3f919dfddc8e33c" + integrity sha512-olV41bKSMm8BdnuMsewT4jqlZ8+3TCARAXjZGT9jcoSnrfUnRCqnMoF9XEeoWjbzObpqF9dRhHQj0Xb9QdF6/w== jest-regex-util@^26.0.0: version "26.0.0" resolved "https://registry.yarnpkg.com/jest-regex-util/-/jest-regex-util-26.0.0.tgz#d25e7184b36e39fd466c3bc41be0971e821fee28" integrity sha512-Gv3ZIs/nA48/Zvjrl34bf+oD76JHiGDUxNOVgUjh3j890sblXryjY4rss71fPtD/njchl6PSE2hIhvyWa1eT0A== -jest-resolve-dependencies@^26.1.0: - version "26.1.0" - resolved "https://registry.yarnpkg.com/jest-resolve-dependencies/-/jest-resolve-dependencies-26.1.0.tgz#1ce36472f864a5dadf7dc82fa158e1c77955691b" - integrity sha512-fQVEPHHQ1JjHRDxzlLU/buuQ9om+hqW6Vo928aa4b4yvq4ZHBtRSDsLdKQLuCqn5CkTVpYZ7ARh2fbA8WkRE6g== +jest-resolve-dependencies@^26.4.2: + version "26.4.2" + resolved "https://registry.yarnpkg.com/jest-resolve-dependencies/-/jest-resolve-dependencies-26.4.2.tgz#739bdb027c14befb2fe5aabbd03f7bab355f1dc5" + integrity sha512-ADHaOwqEcVc71uTfySzSowA/RdxUpCxhxa2FNLiin9vWLB1uLPad3we+JSSROq5+SrL9iYPdZZF8bdKM7XABTQ== dependencies: - "@jest/types" "^26.1.0" + "@jest/types" "^26.3.0" jest-regex-util "^26.0.0" - jest-snapshot "^26.1.0" + jest-snapshot "^26.4.2" -jest-resolve@^26.1.0: - version "26.1.0" - resolved "https://registry.yarnpkg.com/jest-resolve/-/jest-resolve-26.1.0.tgz#a530eaa302b1f6fa0479079d1561dd69abc00e68" - integrity sha512-KsY1JV9FeVgEmwIISbZZN83RNGJ1CC+XUCikf/ZWJBX/tO4a4NvA21YixokhdR9UnmPKKAC4LafVixJBrwlmfg== +jest-resolve@^26.4.0: + version "26.4.0" + resolved "https://registry.yarnpkg.com/jest-resolve/-/jest-resolve-26.4.0.tgz#6dc0af7fb93e65b73fec0368ca2b76f3eb59a6d7" + integrity sha512-bn/JoZTEXRSlEx3+SfgZcJAVuTMOksYq9xe9O6s4Ekg84aKBObEaVXKOEilULRqviSLAYJldnoWV9c07kwtiCg== dependencies: - "@jest/types" "^26.1.0" + "@jest/types" "^26.3.0" chalk "^4.0.0" graceful-fs "^4.2.4" - jest-pnp-resolver "^1.2.1" - jest-util "^26.1.0" + jest-pnp-resolver "^1.2.2" + jest-util "^26.3.0" read-pkg-up "^7.0.1" resolve "^1.17.0" slash "^3.0.0" -jest-runner@^26.1.0: - version "26.1.0" - resolved "https://registry.yarnpkg.com/jest-runner/-/jest-runner-26.1.0.tgz#457f7fc522afe46ca6db1dccf19f87f500b3288d" - integrity sha512-elvP7y0fVDREnfqit0zAxiXkDRSw6dgCkzPCf1XvIMnSDZ8yogmSKJf192dpOgnUVykmQXwYYJnCx641uLTgcw== +jest-runner@^26.4.2: + version "26.4.2" + resolved "https://registry.yarnpkg.com/jest-runner/-/jest-runner-26.4.2.tgz#c3ec5482c8edd31973bd3935df5a449a45b5b853" + integrity sha512-FgjDHeVknDjw1gRAYaoUoShe1K3XUuFMkIaXbdhEys+1O4bEJS8Avmn4lBwoMfL8O5oFTdWYKcf3tEJyyYyk8g== dependencies: - "@jest/console" "^26.1.0" - "@jest/environment" "^26.1.0" - "@jest/test-result" "^26.1.0" - "@jest/types" "^26.1.0" + "@jest/console" "^26.3.0" + "@jest/environment" "^26.3.0" + "@jest/test-result" "^26.3.0" + "@jest/types" "^26.3.0" + "@types/node" "*" chalk "^4.0.0" + emittery "^0.7.1" exit "^0.1.2" graceful-fs "^4.2.4" - jest-config "^26.1.0" + jest-config "^26.4.2" jest-docblock "^26.0.0" - jest-haste-map "^26.1.0" - jest-jasmine2 "^26.1.0" - jest-leak-detector "^26.1.0" - jest-message-util "^26.1.0" - jest-resolve "^26.1.0" - jest-runtime "^26.1.0" - jest-util "^26.1.0" - jest-worker "^26.1.0" + jest-haste-map "^26.3.0" + jest-leak-detector "^26.4.2" + jest-message-util "^26.3.0" + jest-resolve "^26.4.0" + jest-runtime "^26.4.2" + jest-util "^26.3.0" + jest-worker "^26.3.0" source-map-support "^0.5.6" throat "^5.0.0" -jest-runtime@^26.1.0: - version "26.1.0" - resolved "https://registry.yarnpkg.com/jest-runtime/-/jest-runtime-26.1.0.tgz#45a37af42115f123ed5c51f126c05502da2469cb" - integrity sha512-1qiYN+EZLmG1QV2wdEBRf+Ci8i3VSfIYLF02U18PiUDrMbhfpN/EAMMkJtT02jgJUoaEOpHAIXG6zS3QRMzRmA== - dependencies: - "@jest/console" "^26.1.0" - "@jest/environment" "^26.1.0" - "@jest/fake-timers" "^26.1.0" - "@jest/globals" "^26.1.0" - "@jest/source-map" "^26.1.0" - "@jest/test-result" "^26.1.0" - "@jest/transform" "^26.1.0" - "@jest/types" "^26.1.0" +jest-runtime@^26.4.2: + version "26.4.2" + resolved "https://registry.yarnpkg.com/jest-runtime/-/jest-runtime-26.4.2.tgz#94ce17890353c92e4206580c73a8f0c024c33c42" + integrity sha512-4Pe7Uk5a80FnbHwSOk7ojNCJvz3Ks2CNQWT5Z7MJo4tX0jb3V/LThKvD9tKPNVNyeMH98J/nzGlcwc00R2dSHQ== + dependencies: + "@jest/console" "^26.3.0" + "@jest/environment" "^26.3.0" + "@jest/fake-timers" "^26.3.0" + "@jest/globals" "^26.4.2" + "@jest/source-map" "^26.3.0" + "@jest/test-result" "^26.3.0" + "@jest/transform" "^26.3.0" + "@jest/types" "^26.3.0" "@types/yargs" "^15.0.0" chalk "^4.0.0" collect-v8-coverage "^1.0.0" exit "^0.1.2" glob "^7.1.3" graceful-fs "^4.2.4" - jest-config "^26.1.0" - jest-haste-map "^26.1.0" - jest-message-util "^26.1.0" - jest-mock "^26.1.0" + jest-config "^26.4.2" + jest-haste-map "^26.3.0" + jest-message-util "^26.3.0" + jest-mock "^26.3.0" jest-regex-util "^26.0.0" - jest-resolve "^26.1.0" - jest-snapshot "^26.1.0" - jest-util "^26.1.0" - jest-validate "^26.1.0" + jest-resolve "^26.4.0" + jest-snapshot "^26.4.2" + jest-util "^26.3.0" + jest-validate "^26.4.2" slash "^3.0.0" strip-bom "^4.0.0" yargs "^15.3.1" -jest-serializer@^26.1.0: - version "26.1.0" - resolved "https://registry.yarnpkg.com/jest-serializer/-/jest-serializer-26.1.0.tgz#72a394531fc9b08e173dc7d297440ac610d95022" - integrity sha512-eqZOQG/0+MHmr25b2Z86g7+Kzd5dG9dhCiUoyUNJPgiqi38DqbDEOlHcNijyfZoj74soGBohKBZuJFS18YTJ5w== +jest-serializer@^26.3.0: + version "26.3.0" + resolved "https://registry.yarnpkg.com/jest-serializer/-/jest-serializer-26.3.0.tgz#1c9d5e1b74d6e5f7e7f9627080fa205d976c33ef" + integrity sha512-IDRBQBLPlKa4flg77fqg0n/pH87tcRKwe8zxOVTWISxGpPHYkRZ1dXKyh04JOja7gppc60+soKVZ791mruVdow== dependencies: + "@types/node" "*" graceful-fs "^4.2.4" -jest-snapshot@^26.1.0: - version "26.1.0" - resolved "https://registry.yarnpkg.com/jest-snapshot/-/jest-snapshot-26.1.0.tgz#c36ed1e0334bd7bd2fe5ad07e93a364ead7e1349" - integrity sha512-YhSbU7eMTVQO/iRbNs8j0mKRxGp4plo7sJ3GzOQ0IYjvsBiwg0T1o0zGQAYepza7lYHuPTrG5J2yDd0CE2YxSw== +jest-snapshot@^26.4.2: + version "26.4.2" + resolved "https://registry.yarnpkg.com/jest-snapshot/-/jest-snapshot-26.4.2.tgz#87d3ac2f2bd87ea8003602fbebd8fcb9e94104f6" + integrity sha512-N6Uub8FccKlf5SBFnL2Ri/xofbaA68Cc3MGjP/NuwgnsvWh+9hLIR/DhrxbSiKXMY9vUW5dI6EW1eHaDHqe9sg== dependencies: "@babel/types" "^7.0.0" - "@jest/types" "^26.1.0" + "@jest/types" "^26.3.0" "@types/prettier" "^2.0.0" chalk "^4.0.0" - expect "^26.1.0" + expect "^26.4.2" graceful-fs "^4.2.4" - jest-diff "^26.1.0" - jest-get-type "^26.0.0" - jest-haste-map "^26.1.0" - jest-matcher-utils "^26.1.0" - jest-message-util "^26.1.0" - jest-resolve "^26.1.0" + jest-diff "^26.4.2" + jest-get-type "^26.3.0" + jest-haste-map "^26.3.0" + jest-matcher-utils "^26.4.2" + jest-message-util "^26.3.0" + jest-resolve "^26.4.0" natural-compare "^1.4.0" - pretty-format "^26.1.0" + pretty-format "^26.4.2" semver "^7.3.2" -jest-util@26.x, jest-util@^26.1.0: +jest-util@26.x: version "26.1.0" resolved "https://registry.yarnpkg.com/jest-util/-/jest-util-26.1.0.tgz#80e85d4ba820decacf41a691c2042d5276e5d8d8" integrity sha512-rNMOwFQevljfNGvbzNQAxdmXQ+NawW/J72dmddsK0E8vgxXCMtwQ/EH0BiWEIxh0hhMcTsxwAxINt7Lh46Uzbg== @@ -3959,46 +3725,60 @@ jest-util@26.x, jest-util@^26.1.0: is-ci "^2.0.0" micromatch "^4.0.2" -jest-validate@^26.1.0: - version "26.1.0" - resolved "https://registry.yarnpkg.com/jest-validate/-/jest-validate-26.1.0.tgz#942c85ad3d60f78250c488a7f85d8f11a29788e7" - integrity sha512-WPApOOnXsiwhZtmkDsxnpye+XLb/tUISP+H6cHjfUIXvlG+eKwP+isnivsxlHCPaO9Q5wvbhloIBkdF3qUn+Nw== +jest-util@^26.3.0: + version "26.3.0" + resolved "https://registry.yarnpkg.com/jest-util/-/jest-util-26.3.0.tgz#a8974b191df30e2bf523ebbfdbaeb8efca535b3e" + integrity sha512-4zpn6bwV0+AMFN0IYhH/wnzIQzRaYVrz1A8sYnRnj4UXDXbOVtWmlaZkO9mipFqZ13okIfN87aDoJWB7VH6hcw== dependencies: - "@jest/types" "^26.1.0" + "@jest/types" "^26.3.0" + "@types/node" "*" + chalk "^4.0.0" + graceful-fs "^4.2.4" + is-ci "^2.0.0" + micromatch "^4.0.2" + +jest-validate@^26.4.2: + version "26.4.2" + resolved "https://registry.yarnpkg.com/jest-validate/-/jest-validate-26.4.2.tgz#e871b0dfe97747133014dcf6445ee8018398f39c" + integrity sha512-blft+xDX7XXghfhY0mrsBCYhX365n8K5wNDC4XAcNKqqjEzsRUSXP44m6PL0QJEW2crxQFLLztVnJ4j7oPlQrQ== + dependencies: + "@jest/types" "^26.3.0" camelcase "^6.0.0" chalk "^4.0.0" - jest-get-type "^26.0.0" + jest-get-type "^26.3.0" leven "^3.1.0" - pretty-format "^26.1.0" + pretty-format "^26.4.2" -jest-watcher@^26.1.0: - version "26.1.0" - resolved "https://registry.yarnpkg.com/jest-watcher/-/jest-watcher-26.1.0.tgz#99812a0cd931f0cb3d153180426135ab83e4d8f2" - integrity sha512-ffEOhJl2EvAIki613oPsSG11usqnGUzIiK7MMX6hE4422aXOcVEG3ySCTDFLn1+LZNXGPE8tuJxhp8OBJ1pgzQ== +jest-watcher@^26.3.0: + version "26.3.0" + resolved "https://registry.yarnpkg.com/jest-watcher/-/jest-watcher-26.3.0.tgz#f8ef3068ddb8af160ef868400318dc4a898eed08" + integrity sha512-XnLdKmyCGJ3VoF6G/p5ohbJ04q/vv5aH9ENI+i6BL0uu9WWB6Z7Z2lhQQk0d2AVZcRGp1yW+/TsoToMhBFPRdQ== dependencies: - "@jest/test-result" "^26.1.0" - "@jest/types" "^26.1.0" + "@jest/test-result" "^26.3.0" + "@jest/types" "^26.3.0" + "@types/node" "*" ansi-escapes "^4.2.1" chalk "^4.0.0" - jest-util "^26.1.0" + jest-util "^26.3.0" string-length "^4.0.1" -jest-worker@^26.1.0: - version "26.1.0" - resolved "https://registry.yarnpkg.com/jest-worker/-/jest-worker-26.1.0.tgz#65d5641af74e08ccd561c240e7db61284f82f33d" - integrity sha512-Z9P5pZ6UC+kakMbNJn+tA2RdVdNX5WH1x+5UCBZ9MxIK24pjYtFt96fK+UwBTrjLYm232g1xz0L3eTh51OW+yQ== +jest-worker@^26.3.0: + version "26.3.0" + resolved "https://registry.yarnpkg.com/jest-worker/-/jest-worker-26.3.0.tgz#7c8a97e4f4364b4f05ed8bca8ca0c24de091871f" + integrity sha512-Vmpn2F6IASefL+DVBhPzI2J9/GJUsqzomdeN+P+dK8/jKxbh8R3BtFnx3FIta7wYlPU62cpJMJQo4kuOowcMnw== dependencies: + "@types/node" "*" merge-stream "^2.0.0" supports-color "^7.0.0" -jest@^26.1.0: - version "26.1.0" - resolved "https://registry.yarnpkg.com/jest/-/jest-26.1.0.tgz#2f3aa7bcffb9bfd025473f83bbbf46a3af026263" - integrity sha512-LIti8jppw5BcQvmNJe4w2g1N/3V68HUfAv9zDVm7v+VAtQulGhH0LnmmiVkbNE4M4I43Bj2fXPiBGKt26k9tHw== +jest@^26.4.2: + version "26.4.2" + resolved "https://registry.yarnpkg.com/jest/-/jest-26.4.2.tgz#7e8bfb348ec33f5459adeaffc1a25d5752d9d312" + integrity sha512-LLCjPrUh98Ik8CzW8LLVnSCfLaiY+wbK53U7VxnFSX7Q+kWC4noVeDvGWIFw0Amfq1lq2VfGm7YHWSLBV62MJw== dependencies: - "@jest/core" "^26.1.0" + "@jest/core" "^26.4.2" import-local "^3.0.2" - jest-cli "^26.1.0" + jest-cli "^26.4.2" js-tokens@^4.0.0: version "4.0.0" @@ -4094,13 +3874,6 @@ json5@^1.0.1: dependencies: minimist "^1.2.0" -jsonfile@^4.0.0: - version "4.0.0" - resolved "https://registry.yarnpkg.com/jsonfile/-/jsonfile-4.0.0.tgz#8771aae0799b64076b76640fca058f9c10e33ecb" - integrity sha1-h3Gq4HmbZAdrdmQPygWPnBDjPss= - optionalDependencies: - graceful-fs "^4.1.6" - jsonparse@^1.2.0: version "1.3.1" resolved "https://registry.yarnpkg.com/jsonparse/-/jsonparse-1.3.1.tgz#3f4dae4a91fac315f71062f8521cc239f1366280" @@ -4260,7 +4033,7 @@ lodash.templatesettings@^4.0.0: dependencies: lodash._reinterpolate "^3.0.0" -lodash@^4.17.13, lodash@^4.17.14, lodash@^4.17.15: +lodash@^4.17.13, lodash@^4.17.14, lodash@^4.17.15, lodash@^4.17.19: version "4.17.19" resolved "https://registry.yarnpkg.com/lodash/-/lodash-4.17.19.tgz#e48ddedbe30b3321783c5b4301fbd353bc1e4a4b" integrity sha512-JNvd8XER9GQX0v2qJgsaN/mzFCNA5BRe/j8JN9d+tWyGLSodKQHKFicdwNYzWwI3wjRnaKPsGj1XkBjx/F96DQ== @@ -4324,21 +4097,6 @@ media-typer@0.3.0: resolved "https://registry.yarnpkg.com/media-typer/-/media-typer-0.3.0.tgz#8710d7af0aa626f8fffa1ce00168545263255748" integrity sha1-hxDXrwqmJvj/+hzgAWhUUmMlV0g= -meow@5.0.0: - version "5.0.0" - resolved "https://registry.yarnpkg.com/meow/-/meow-5.0.0.tgz#dfc73d63a9afc714a5e371760eb5c88b91078aa4" - integrity sha512-CbTqYU17ABaLefO8vCU153ZZlprKYWDljcndKKDCFcYQITzWCXZAVk4QMFZPgvzrnUQ3uItnIE/LoUOwrT15Ig== - dependencies: - camelcase-keys "^4.0.0" - decamelize-keys "^1.0.0" - loud-rejection "^1.0.0" - minimist-options "^3.0.1" - normalize-package-data "^2.3.4" - read-pkg-up "^3.0.0" - redent "^2.0.0" - trim-newlines "^2.0.0" - yargs-parser "^10.0.0" - meow@^3.3.0: version "3.7.0" resolved "https://registry.yarnpkg.com/meow/-/meow-3.7.0.tgz#72cb668b425228290abbfa856892587308a801fb" @@ -4399,6 +4157,11 @@ merge-stream@^2.0.0: resolved "https://registry.yarnpkg.com/merge-stream/-/merge-stream-2.0.0.tgz#52823629a14dd00c9770fb6ad47dc6310f2c1f60" integrity sha512-abv/qOcuPfk3URPfDzmZU1LKmuw8kT+0nIHvKrKgFrwifol/doWcdA4ZqsWQ8ENrFKkd67Mfpo/LovbIUsbt3w== +merge2@^1.3.0: + version "1.4.1" + resolved "https://registry.yarnpkg.com/merge2/-/merge2-1.4.1.tgz#4368892f885e907455a6fd7dc55c0c9d404990ae" + integrity sha512-8q7VEgMJW4J8tcfVPy8g09NcQwZdbwFEqhe/WZkoIzjn/3TGDwtOCYtXGxA3O8tPzpczCCDgv+P2P5y00ZJOOg== + methods@~1.1.2: version "1.1.2" resolved "https://registry.yarnpkg.com/methods/-/methods-1.1.2.tgz#5529a4d67654134edcc5266656835b0f851afcee" @@ -4495,7 +4258,7 @@ mixin-deep@^1.2.0: for-in "^1.0.2" is-extendable "^1.0.1" -mkdirp@1.x, mkdirp@^1.0.3: +mkdirp@1.x: version "1.0.4" resolved "https://registry.yarnpkg.com/mkdirp/-/mkdirp-1.0.4.tgz#3eb5ed62622756d79a5f0e2a221dfebad75c2f7e" integrity sha512-vVqVZQyf3WLx2Shd0qJ9xuvqgAyKPLAiqITEtqW0oIUjzo3PePDd6fW9iFz30ef7Ysp/oiWqbhszeGWW2T6Gzw== @@ -4541,15 +4304,6 @@ multer@^1.4.2: type-is "^1.6.4" xtend "^4.0.0" -mz@^2.4.0: - version "2.7.0" - resolved "https://registry.yarnpkg.com/mz/-/mz-2.7.0.tgz#95008057a56cafadc2bc63dde7f9ff6955948e32" - integrity sha512-z81GNO7nnYMEhrGh9LeymoE4+Yr0Wn5McHIZMK5cfQCl+NDX08sCZgUc9/6MHni9IWuFLm1Z3HTCXu2z9fN62Q== - dependencies: - any-promise "^1.0.0" - object-assign "^4.0.1" - thenify-all "^1.0.0" - nanomatch@^1.2.9: version "1.2.13" resolved "https://registry.yarnpkg.com/nanomatch/-/nanomatch-1.2.13.tgz#b87a8aa4fc0de8fe6be88895b38983ff265bd119" @@ -4587,11 +4341,6 @@ nice-try@^1.0.4: resolved "https://registry.yarnpkg.com/nice-try/-/nice-try-1.0.5.tgz#a3378a7696ce7d223e88fc9b764bd7ef1089e366" integrity sha512-1nh45deeb5olNY7eX82BkPO7SSxR5SSYJiPTrTdFUVYwAl8CKMA5N9PjTYkHiRjisVcxcQ1HXdLhx2qxxJzLNQ== -nocache@2.1.0: - version "2.1.0" - resolved "https://registry.yarnpkg.com/nocache/-/nocache-2.1.0.tgz#120c9ffec43b5729b1d5de88cd71aa75a0ba491f" - integrity sha512-0L9FvHG3nfnnmaEQPjT9xhfN4ISk0A8/2j4M37Np4mcDesJjHgEUfgPhdCyZuFI954tjokaIj/A3NdpFNdEh4Q== - node-int64@^0.4.0: version "0.4.0" resolved "https://registry.yarnpkg.com/node-int64/-/node-int64-0.4.0.tgz#87a9065cdb355d3182d8f94ce11188b825c68a3b" @@ -4602,16 +4351,16 @@ node-modules-regexp@^1.0.0: resolved "https://registry.yarnpkg.com/node-modules-regexp/-/node-modules-regexp-1.0.0.tgz#8d9dbe28964a4ac5712e9131642107c71e90ec40" integrity sha1-jZ2+KJZKSsVxLpExZCEHxx6Q7EA= -node-notifier@^7.0.0: - version "7.0.1" - resolved "https://registry.yarnpkg.com/node-notifier/-/node-notifier-7.0.1.tgz#a355e33e6bebacef9bf8562689aed0f4230ca6f9" - integrity sha512-VkzhierE7DBmQEElhTGJIoiZa1oqRijOtgOlsXg32KrJRXsPy0NXFBqWGW/wTswnJlDCs5viRYaqWguqzsKcmg== +node-notifier@^8.0.0: + version "8.0.0" + resolved "https://registry.yarnpkg.com/node-notifier/-/node-notifier-8.0.0.tgz#a7eee2d51da6d0f7ff5094bc7108c911240c1620" + integrity sha512-46z7DUmcjoYdaWyXouuFNNfUo6eFa94t23c53c+lG/9Cvauk4a98rAUp9672X5dxGdQmLpPzTxzu8f/OeEPaFA== dependencies: growly "^1.3.0" - is-wsl "^2.1.1" - semver "^7.2.1" + is-wsl "^2.2.0" + semver "^7.3.2" shellwords "^0.1.1" - uuid "^7.0.3" + uuid "^8.3.0" which "^2.0.2" normalize-package-data@^2.3.0, normalize-package-data@^2.3.2, normalize-package-data@^2.3.4, normalize-package-data@^2.3.5, normalize-package-data@^2.5.0: @@ -4670,7 +4419,7 @@ oauth-sign@~0.9.0: resolved "https://registry.yarnpkg.com/oauth-sign/-/oauth-sign-0.9.0.tgz#47a7b016baa68b5fa0ecf3dee08a85c679ac6455" integrity sha512-fexhUFFPTGV8ybAtSIGbV6gOkSv8UtRbDBnAyLQw4QPKkgNlsH2ByPGtMUqdWkos6YCRmAqViwgZrJc/mRDzZQ== -object-assign@^4, object-assign@^4.0.1, object-assign@^4.1.1: +object-assign@^4.0.1, object-assign@^4.1.1: version "4.1.1" resolved "https://registry.yarnpkg.com/object-assign/-/object-assign-4.1.1.tgz#2109adc7965887cfc05cbbd442cac8bfbb360863" integrity sha1-IQmtx5ZYh8/AXLvUQsrIv7s2CGM= @@ -4835,11 +4584,6 @@ parent-module@^1.0.0: dependencies: callsites "^3.0.0" -parent-require@^1.0.0: - version "1.0.0" - resolved "https://registry.yarnpkg.com/parent-require/-/parent-require-1.0.0.tgz#746a167638083a860b0eef6732cb27ed46c32977" - integrity sha1-dGoWdjgIOoYLDu9nMssn7UbDKXc= - parse-github-repo-url@^1.3.0: version "1.4.1" resolved "https://registry.yarnpkg.com/parse-github-repo-url/-/parse-github-repo-url-1.4.1.tgz#9e7d8bb252a6cb6ba42595060b7bf6df3dbc1f50" @@ -4870,14 +4614,7 @@ parse-json@^5.0.0: json-parse-better-errors "^1.0.1" lines-and-columns "^1.1.6" -parse5-htmlparser2-tree-adapter@^5.1.1: - version "5.1.1" - resolved "https://registry.yarnpkg.com/parse5-htmlparser2-tree-adapter/-/parse5-htmlparser2-tree-adapter-5.1.1.tgz#e8c743d4e92194d5293ecde2b08be31e67461cbc" - integrity sha512-CF+TKjXqoqyDwHqBhFQ+3l5t83xYi6fVT1tQNg+Ye0JRLnTxWvIroCjEp1A0k4lneHNBGnICUf0cfYVYGEazqw== - dependencies: - parse5 "^5.1.1" - -parse5@5.1.1, parse5@^5.1.1: +parse5@5.1.1: version "5.1.1" resolved "https://registry.yarnpkg.com/parse5/-/parse5-5.1.1.tgz#f68e4e5ba1852ac2cadc00f4555fff6c2abb6178" integrity sha512-ugq4DFI0Ptb+WWjAdOK16+u/nHfiIrcE+sh8kZMaM0WllQKLI9rOUq6c2b7cwPkXdzfQESqvoqK6ug7U/Yyzug== @@ -5037,10 +4774,10 @@ prettier-linter-helpers@^1.0.0: dependencies: fast-diff "^1.1.2" -prettier@2.0.5: - version "2.0.5" - resolved "https://registry.yarnpkg.com/prettier/-/prettier-2.0.5.tgz#d6d56282455243f2f92cc1716692c08aa31522d4" - integrity sha512-7PtVymN48hGcO4fGjybyBSIWDsLU4H4XlvOHfq91pz9kkGlonzwTfYkaIEwiRg/dAJF9YlbsduBAgtYLi+8cFg== +prettier@^2.1.1: + version "2.1.1" + resolved "https://registry.yarnpkg.com/prettier/-/prettier-2.1.1.tgz#d9485dd5e499daa6cb547023b87a6cf51bee37d6" + integrity sha512-9bY+5ZWCfqj3ghYBLxApy2zf6m+NJo5GzmLTpr9FsApsfjriNnS2dahWReHMi7qNPhhHl9SYHJs2cHZLgexNIw== pretty-format@^25.2.1, pretty-format@^25.5.0: version "25.5.0" @@ -5052,12 +4789,12 @@ pretty-format@^25.2.1, pretty-format@^25.5.0: ansi-styles "^4.0.0" react-is "^16.12.0" -pretty-format@^26.1.0: - version "26.1.0" - resolved "https://registry.yarnpkg.com/pretty-format/-/pretty-format-26.1.0.tgz#272b9cd1f1a924ab5d443dc224899d7a65cb96ec" - integrity sha512-GmeO1PEYdM+non4BKCj+XsPJjFOJIPnsLewqhDVoqY1xo0yNmDas7tC2XwpMrRAHR3MaE2hPo37deX5OisJ2Wg== +pretty-format@^26.4.2: + version "26.4.2" + resolved "https://registry.yarnpkg.com/pretty-format/-/pretty-format-26.4.2.tgz#d081d032b398e801e2012af2df1214ef75a81237" + integrity sha512-zK6Gd8zDsEiVydOCGLkoBoZuqv8VTiHyAbKznXe/gaph/DAeZOmit9yMfgIz5adIgAMMs5XfoYSwAX3jcCO1tA== dependencies: - "@jest/types" "^26.1.0" + "@jest/types" "^26.3.0" ansi-regex "^5.0.0" ansi-styles "^4.0.0" react-is "^16.12.0" @@ -5291,21 +5028,6 @@ redent@^3.0.0: indent-string "^4.0.0" strip-indent "^3.0.0" -referrer-policy@1.2.0: - version "1.2.0" - resolved "https://registry.yarnpkg.com/referrer-policy/-/referrer-policy-1.2.0.tgz#b99cfb8b57090dc454895ef897a4cc35ef67a98e" - integrity sha512-LgQJIuS6nAy1Jd88DCQRemyE3mS+ispwlqMk3b0yjZ257fI1v9c+/p6SD5gP5FGyXUIgrNOAfmyioHwZtYv2VA== - -reflect-metadata@^0.1.13: - version "0.1.13" - resolved "https://registry.yarnpkg.com/reflect-metadata/-/reflect-metadata-0.1.13.tgz#67ae3ca57c972a2aa1642b10fe363fe32d49dc08" - integrity sha512-Ts1Y/anZELhSsjMcU605fU9RE4Oi3p5ORujwbIKXfWa+0Zxs510Qrmrce5/Jowq3cHSZSJqBjypxmHarc+vEWg== - -regenerator-runtime@0.13.5, regenerator-runtime@^0.13.4: - version "0.13.5" - resolved "https://registry.yarnpkg.com/regenerator-runtime/-/regenerator-runtime-0.13.5.tgz#d878a1d094b4306d10b9096484b33ebd55e26697" - integrity sha512-ZS5w8CpKFinUzOwW3c83oPeVXoNsrLsaCoLtJvAClH135j/R77RuymhiSErhm2lKcwSCIpmvIWSbDkIfAqKQlA== - regex-not@^1.0.0, regex-not@^1.0.2: version "1.0.2" resolved "https://registry.yarnpkg.com/regex-not/-/regex-not-1.0.2.tgz#1f4ece27e00b0b65e0247a6810e6a85d83a5752c" @@ -5400,22 +5122,15 @@ resolve-cwd@^3.0.0: dependencies: resolve-from "^5.0.0" -resolve-from@5.0.0, resolve-from@^5.0.0: - version "5.0.0" - resolved "https://registry.yarnpkg.com/resolve-from/-/resolve-from-5.0.0.tgz#c35225843df8f776df21c57557bc087e9dfdfc69" - integrity sha512-qYg9KP24dD5qka9J47d0aVky0N+b4fTU89LN9iDnjB5waksiC49rvMB0PrUJQGoTmH50XPiqOvAjDfaijGxYZw== - resolve-from@^4.0.0: version "4.0.0" resolved "https://registry.yarnpkg.com/resolve-from/-/resolve-from-4.0.0.tgz#4abcd852ad32dd7baabfe9b40e00a36db5f392e6" integrity sha512-pb/MYmXstAkysRFx8piNI1tGFNQIFA3vkE3Gq4EuA1dF6gHp/+vgZqsCGJapvy8N3Q+4o7FwvquPJcnZ7RYy4g== -resolve-global@1.0.0, resolve-global@^1.0.0: - version "1.0.0" - resolved "https://registry.yarnpkg.com/resolve-global/-/resolve-global-1.0.0.tgz#a2a79df4af2ca3f49bf77ef9ddacd322dad19255" - integrity sha512-zFa12V4OLtT5XUX/Q4VLvTfBf+Ok0SPc1FNGM/z9ctUdiU618qwKpWnd0CHs3+RqROfyEg/DhuHbMWYqcgljEw== - dependencies: - global-dirs "^0.1.1" +resolve-from@^5.0.0: + version "5.0.0" + resolved "https://registry.yarnpkg.com/resolve-from/-/resolve-from-5.0.0.tgz#c35225843df8f776df21c57557bc087e9dfdfc69" + integrity sha512-qYg9KP24dD5qka9J47d0aVky0N+b4fTU89LN9iDnjB5waksiC49rvMB0PrUJQGoTmH50XPiqOvAjDfaijGxYZw== resolve-url@^0.2.1: version "0.2.1" @@ -5434,6 +5149,11 @@ ret@~0.1.10: resolved "https://registry.yarnpkg.com/ret/-/ret-0.1.15.tgz#b8a4825d5bdb1fc3f6f53c2bc33f81388681c7bc" integrity sha512-TTlYpa+OL+vMMNG24xSlQGEJ3B/RzEfUlLct7b5G/ytav+wPrplCpVMFuwzXbkecJrb6IYo1iFb0S9v37754mg== +reusify@^1.0.4: + version "1.0.4" + resolved "https://registry.yarnpkg.com/reusify/-/reusify-1.0.4.tgz#90da382b1e126efc02146e90845a88db12925d76" + integrity sha512-U9nH88a3fc/ekCF1l0/UP1IosiuIjyTh7hBvXVMHYgVcfGvt897Xguj2UOLDeI5BG2m7/uwyaLVT6fbtCwTyzw== + rimraf@2.6.3: version "2.6.3" resolved "https://registry.yarnpkg.com/rimraf/-/rimraf-2.6.3.tgz#b2d104fe0d8fb27cf9e0a1cda8262dd3833c6cab" @@ -5453,6 +5173,11 @@ rsvp@^4.8.4: resolved "https://registry.yarnpkg.com/rsvp/-/rsvp-4.8.5.tgz#c8f155311d167f68f21e168df71ec5b083113734" integrity sha512-nfMOlASu9OnRJo1mbEk2cz0D56a1MBNrJ7orjRZQG10XDyuvwksKbuXNp6qa+kbn839HwjwhBzhFmdsaEAfauA== +run-parallel@^1.1.9: + version "1.1.9" + resolved "https://registry.yarnpkg.com/run-parallel/-/run-parallel-1.1.9.tgz#c9dd3a7cf9f4b2c4b6244e173a6ed866e61dd679" + integrity sha512-DEqnSRTDw/Tc3FXf49zedI638Z9onwUotBMiUFKmrO2sdFKIbXamXGQ3Axd4qgphxKB4kw/qP1w5kTxnfU1B9Q== + safe-buffer@5.1.2, safe-buffer@~5.1.0, safe-buffer@~5.1.1: version "5.1.2" resolved "https://registry.yarnpkg.com/safe-buffer/-/safe-buffer-5.1.2.tgz#991ec69d296e0313747d59bdfd2b745c35f8828d" @@ -5490,11 +5215,6 @@ sane@^4.0.3: minimist "^1.1.1" walker "~1.0.5" -sax@>=0.6.0: - version "1.2.4" - resolved "https://registry.yarnpkg.com/sax/-/sax-1.2.4.tgz#2816234e2378bddc4e5354fab5caa895df7100d9" - integrity sha512-NqVDv9TpANUjFm0N8uM5GxL36UgKi9/atZw+x7YFnQ8ckwFGKrl4xX4yWtrey3UJm5nP1kUbnYgLopqWNSRhWw== - saxes@^5.0.0: version "5.0.1" resolved "https://registry.yarnpkg.com/saxes/-/saxes-5.0.1.tgz#eebab953fa3b7608dbe94e5dadb15c888fa6696d" @@ -5507,7 +5227,7 @@ saxes@^5.0.0: resolved "https://registry.yarnpkg.com/semver/-/semver-5.7.1.tgz#a954f931aeba508d307bbf069eff0c01c96116f7" integrity sha512-sauaDf/PZdVgrLTNYHRtpXa1iRiKcaebiKQ1BJdpQlWH2lCvexQdX55snPFyK7QzpudqbCI0qXFfOasHdyNDGQ== -semver@7.3.2, semver@7.x, semver@^7.1.1, semver@^7.2.1, semver@^7.3.2: +semver@7.x, semver@^7.1.1, semver@^7.2.1, semver@^7.3.2: version "7.3.2" resolved "https://registry.yarnpkg.com/semver/-/semver-7.3.2.tgz#604962b052b81ed0786aae84389ffba70ffd3938" integrity sha512-OrOb32TeeambH6UrhtShmF7CRDqhL6/5XpPNp2DuRH6+9QLw/orhp72j87v8Qa1ScDkvrrBNpZcDejAirJmfXQ== @@ -5566,14 +5286,6 @@ setprototypeof@1.1.1: resolved "https://registry.yarnpkg.com/setprototypeof/-/setprototypeof-1.1.1.tgz#7e95acb24aa92f5885e0abef5ba131330d4ae683" integrity sha512-JvdAWfbXeIGaZ9cILp38HntZSFSo3mWg6xGcJJsd+d4aRMOqauag1C63dJfDw7OaMYwEbHMOxEZ1lqVRYP2OAw== -sha.js@^2.4.11: - version "2.4.11" - resolved "https://registry.yarnpkg.com/sha.js/-/sha.js-2.4.11.tgz#37a5cf0b81ecbc6943de109ba2960d1b26584ae7" - integrity sha512-QMEp5B7cftE7APOjk5Y6xgrbWu+WkLVQwk8JNjZ8nKRciZaByEW6MubieAiToS7+dwvrjGhH8jRXz3MVd0AYqQ== - dependencies: - inherits "^2.0.1" - safe-buffer "^5.0.1" - shebang-command@^1.2.0: version "1.2.0" resolved "https://registry.yarnpkg.com/shebang-command/-/shebang-command-1.2.0.tgz#44aac65b695b03398968c39f363fee5deafdf1ea" @@ -5779,16 +5491,16 @@ stack-utils@^2.0.2: dependencies: escape-string-regexp "^2.0.0" -standard-version@^8.0.2: - version "8.0.2" - resolved "https://registry.yarnpkg.com/standard-version/-/standard-version-8.0.2.tgz#02ed7131f83046bd04358dc54f97d42c4b2fd828" - integrity sha512-L8X9KFq2SmVmaeZgUmWHFJMOsEWpjgFAwqic6yIIoveM1kdw1vH4Io03WWxUDjypjGqGU6qUtcJoR8UvOv5w3g== +standard-version@^9.0.0: + version "9.0.0" + resolved "https://registry.yarnpkg.com/standard-version/-/standard-version-9.0.0.tgz#814055add91eec8679a773768927f927183fc818" + integrity sha512-eRR04IscMP3xW9MJTykwz13HFNYs8jS33AGuDiBKgfo5YrO0qX0Nxb4rjupVwT5HDYL/aR+MBEVLjlmVFmFEDQ== dependencies: chalk "^2.4.2" - conventional-changelog "3.1.21" + conventional-changelog "3.1.23" conventional-changelog-config-spec "2.1.0" - conventional-changelog-conventionalcommits "4.3.0" - conventional-recommended-bump "6.0.9" + conventional-changelog-conventionalcommits "4.4.0" + conventional-recommended-bump "6.0.10" detect-indent "^6.0.0" detect-newline "^3.1.0" dotgitignore "^2.1.0" @@ -5831,7 +5543,7 @@ string-length@^4.0.1: char-regex "^1.0.2" strip-ansi "^6.0.0" -string-width@^3.0.0, string-width@^3.1.0: +string-width@^3.0.0: version "3.1.0" resolved "https://registry.yarnpkg.com/string-width/-/string-width-3.1.0.tgz#22767be21b62af1081574306f69ac51b62203961" integrity sha512-vafcv6KjVZKSgz06oM/H6GDBrAtz8vdhQakGjFIvNrHA6y3HCF1CInLy+QLq8dTJPQ1b+KDUqDFctkdRW44e1w== @@ -5907,14 +5619,7 @@ stringify-package@^1.0.1: resolved "https://registry.yarnpkg.com/stringify-package/-/stringify-package-1.0.1.tgz#e5aa3643e7f74d0f28628b72f3dad5cecfc3ba85" integrity sha512-sa4DUQsYciMP1xhKWGuFM04fB0LG/9DlluZoSVywUMRNvzid6XucHK0/90xGxRoHrAaROrcHK1aPKaijCtSrhg== -strip-ansi@^3.0.0: - version "3.0.1" - resolved "https://registry.yarnpkg.com/strip-ansi/-/strip-ansi-3.0.1.tgz#6a385fb8853d952d5ff05d0e8aaf94278dc63dcf" - integrity sha1-ajhfuIU9lS1f8F0Oiq+UJ43GPc8= - dependencies: - ansi-regex "^2.0.0" - -strip-ansi@^5.0.0, strip-ansi@^5.1.0, strip-ansi@^5.2.0: +strip-ansi@^5.1.0: version "5.2.0" resolved "https://registry.yarnpkg.com/strip-ansi/-/strip-ansi-5.2.0.tgz#8c9a536feb6afc962bdfa5b104a5091c1ad9c0ae" integrity sha512-DuRs1gKbBqsMKIZlrffwlug8MHkcnpjs5VPmL1PAh+mA30U0DTotfDZ0d2UUsXpPmPmMMJ6W773MaA3J+lbiWA== @@ -5974,16 +5679,11 @@ strip-indent@^3.0.0: dependencies: min-indent "^1.0.0" -strip-json-comments@^3.1.0: +strip-json-comments@^3.1.0, strip-json-comments@^3.1.1: version "3.1.1" resolved "https://registry.yarnpkg.com/strip-json-comments/-/strip-json-comments-3.1.1.tgz#31f1281b3832630434831c310c01cccda8cbe006" integrity sha512-6fPc+R4ihwqP6N/aIv2f1gMH8lOVtWQHoqC4yK6oSDVVocumAsfCqjkXnqiYMhmMwS/mEHLp7Vehlt3ql6lEig== -supports-color@^2.0.0: - version "2.0.0" - resolved "https://registry.yarnpkg.com/supports-color/-/supports-color-2.0.0.tgz#535d045ce6b6363fa40117084629995e9df324c7" - integrity sha1-U10EXOa2Nj+kARcIRimZXp3zJMc= - supports-color@^5.3.0: version "5.5.0" resolved "https://registry.yarnpkg.com/supports-color/-/supports-color-5.5.0.tgz#e2e69a44ac8772f78a1ec0b35b689df6530efc8f" @@ -6048,20 +5748,6 @@ text-table@^0.2.0: resolved "https://registry.yarnpkg.com/text-table/-/text-table-0.2.0.tgz#7f5ee823ae805207c00af2df4a84ec3fcfa570b4" integrity sha1-f17oI66AUgfACvLfSoTsP8+lcLQ= -thenify-all@^1.0.0: - version "1.6.0" - resolved "https://registry.yarnpkg.com/thenify-all/-/thenify-all-1.6.0.tgz#1a1918d402d8fc3f98fbf234db0bcc8cc10e9726" - integrity sha1-GhkY1ALY/D+Y+/I02wvMjMEOlyY= - dependencies: - thenify ">= 3.1.0 < 4" - -"thenify@>= 3.1.0 < 4": - version "3.3.0" - resolved "https://registry.yarnpkg.com/thenify/-/thenify-3.3.0.tgz#e69e38a1babe969b0108207978b9f62b88604839" - integrity sha1-5p44obq+lpsBCCB5eLn2K4hgSDk= - dependencies: - any-promise "^1.0.0" - throat@^5.0.0: version "5.0.0" resolved "https://registry.yarnpkg.com/throat/-/throat-5.0.0.tgz#c5199235803aad18754a667d659b5e72ce16764b" @@ -6178,11 +5864,12 @@ trim-off-newlines@^1.0.0: resolved "https://registry.yarnpkg.com/trim-off-newlines/-/trim-off-newlines-1.0.1.tgz#9f9ba9d9efa8764c387698bcbfeb2c848f11adb3" integrity sha1-n5up2e+odkw4dpi8v+sshI8RrbM= -ts-jest@^26.1.3: - version "26.1.3" - resolved "https://registry.yarnpkg.com/ts-jest/-/ts-jest-26.1.3.tgz#aac928a05fdf13e3e6dfbc8caec3847442667894" - integrity sha512-beUTSvuqR9SmKQEylewqJdnXWMVGJRFqSz2M8wKJe7GBMmLZ5zw6XXKSJckbHNMxn+zdB3guN2eOucSw2gBMnw== +ts-jest@^26.3.0: + version "26.3.0" + resolved "https://registry.yarnpkg.com/ts-jest/-/ts-jest-26.3.0.tgz#6b2845045347dce394f069bb59358253bc1338a9" + integrity sha512-Jq2uKfx6bPd9+JDpZNMBJMdMQUC3sJ08acISj8NXlVgR2d5OqslEHOR2KHMgwymu8h50+lKIm0m0xj/ioYdW2Q== dependencies: + "@types/jest" "26.x" bs-logger "0.x" buffer-from "1.x" fast-json-stable-stringify "2.x" @@ -6205,11 +5892,11 @@ tsconfig-paths@^3.9.0: strip-bom "^3.0.0" tslib@>=1.9.0: - version "2.0.0" - resolved "https://registry.yarnpkg.com/tslib/-/tslib-2.0.0.tgz#18d13fc2dce04051e20f074cc8387fd8089ce4f3" - integrity sha512-lTqkx847PI7xEDYJntxZH89L2/aXInsyF2luSafe/+0fHOMjlBNXdH6th7f70qxLDhul7KZK0zC8V5ZIyHl0/g== + version "2.0.1" + resolved "https://registry.yarnpkg.com/tslib/-/tslib-2.0.1.tgz#410eb0d113e5b6356490eec749603725b021b43e" + integrity sha512-SgIkNheinmEBgx1IUNirK0TUD4X9yjjBRTqqjggWCU3pUEqIk3/Uwl3yRixYKT6WjQuGiwDv4NomL3wqRCj+CQ== -tslib@^1.8.1, tslib@^1.9.0: +tslib@^1.8.1: version "1.13.0" resolved "https://registry.yarnpkg.com/tslib/-/tslib-1.13.0.tgz#c881e13cc7015894ed914862d276436fa9a47043" integrity sha512-i/6DQjL8Xf3be4K/E6Wgpekn5Qasl1usyw++dAA35Ue5orEn65VIxOA+YvNNl9HV3qv70T7CNwjODHZrLwvd1Q== @@ -6292,31 +5979,10 @@ typedarray@^0.0.6: resolved "https://registry.yarnpkg.com/typedarray/-/typedarray-0.0.6.tgz#867ac74e3864187b1d3d47d996a78ec5c8830777" integrity sha1-hnrHTjhkGHsdPUfZlqeOxciDB3c= -typeorm@^0.2.25: - version "0.2.25" - resolved "https://registry.yarnpkg.com/typeorm/-/typeorm-0.2.25.tgz#1a33513b375b78cc7740d2405202208b918d7dde" - integrity sha512-yzQ995fyDy5wolSLK9cmjUNcmQdixaeEm2TnXB5HN++uKbs9TiR6Y7eYAHpDlAE8s9J1uniDBgytecCZVFergQ== - dependencies: - app-root-path "^3.0.0" - buffer "^5.1.0" - chalk "^2.4.2" - cli-highlight "^2.0.0" - debug "^4.1.1" - dotenv "^6.2.0" - glob "^7.1.2" - js-yaml "^3.13.1" - mkdirp "^1.0.3" - reflect-metadata "^0.1.13" - sha.js "^2.4.11" - tslib "^1.9.0" - xml2js "^0.4.17" - yargonaut "^1.1.2" - yargs "^13.2.1" - -typescript@^3.9.7: - version "3.9.7" - resolved "https://registry.yarnpkg.com/typescript/-/typescript-3.9.7.tgz#98d600a5ebdc38f40cb277522f12dc800e9e25fa" - integrity sha512-BLbiRkiBzAwsjut4x/dsibSTB6yWpwT5qWmC2OfuCg3GgVQCSgMs4vEctYPhsaGtd0AeuuHMkjZ2h2WG8MSzRw== +typescript@^4.0.2: + version "4.0.2" + resolved "https://registry.yarnpkg.com/typescript/-/typescript-4.0.2.tgz#7ea7c88777c723c681e33bf7988be5d008d05ac2" + integrity sha512-e4ERvRV2wb+rRZ/IQeb3jm2VxBsirQLpQhdxplZ2MEzGvDkkMmPglecnNDfSUBivMjP93vRbngYYDQqQ/78bcQ== uglify-js@^3.1.4: version "3.9.4" @@ -6335,11 +6001,6 @@ union-value@^1.0.0: is-extendable "^0.1.1" set-value "^2.0.1" -universalify@^0.1.0: - version "0.1.2" - resolved "https://registry.yarnpkg.com/universalify/-/universalify-0.1.2.tgz#b646f69be3942dabcecc9d6639c80dc105efaa66" - integrity sha512-rBJeI5CXAlmy1pV+617WB9J63U6XcazHHF2f2dbJix4XzpUF0RS3Zbj0FGIOCAva5P/d/GBOYaACQ1w+0azUkg== - unpipe@1.0.0, unpipe@~1.0.0: version "1.0.0" resolved "https://registry.yarnpkg.com/unpipe/-/unpipe-1.0.0.tgz#b2bf4ee8514aae6165b4817829d21b2ef49904ec" @@ -6385,20 +6046,20 @@ uuid@^3.3.2: resolved "https://registry.yarnpkg.com/uuid/-/uuid-3.4.0.tgz#b23e4358afa8a202fe7a100af1f5f883f02007ee" integrity sha512-HjSDRw6gZE5JMggctHBcjVak08+KEVhSIiDzFnT9S9aegmp85S/bReBVTb4QTFaRNptJ9kuYaNhnbNEOkbKb/A== -uuid@^7.0.3: - version "7.0.3" - resolved "https://registry.yarnpkg.com/uuid/-/uuid-7.0.3.tgz#c5c9f2c8cf25dc0a372c4df1441c41f5bd0c680b" - integrity sha512-DPSke0pXhTZgoF/d+WSt2QaKMCFSfx7QegxEWT+JOuHF5aWrKEn0G+ztjuJg/gG8/ItK+rbPCD/yNv8yyih6Cg== +uuid@^8.3.0: + version "8.3.0" + resolved "https://registry.yarnpkg.com/uuid/-/uuid-8.3.0.tgz#ab738085ca22dc9a8c92725e459b1d507df5d6ea" + integrity sha512-fX6Z5o4m6XsXBdli9g7DtWgAx+osMsRRZFKma1mIUsLCz6vRvv+pz5VNbyu9UEDzpMWulZfvpgb/cmDXVulYFQ== v8-compile-cache@^2.0.3: version "2.1.0" resolved "https://registry.yarnpkg.com/v8-compile-cache/-/v8-compile-cache-2.1.0.tgz#e14de37b31a6d194f5690d67efc4e7f6fc6ab30e" integrity sha512-usZBT3PW+LOjM25wbqIlZwPeJV+3OSz3M1k1Ws8snlW39dZyYL9lOGC5FgPVHfk0jKmjiDV8Z0mIbVQPiwFs7g== -v8-to-istanbul@^4.1.3: - version "4.1.4" - resolved "https://registry.yarnpkg.com/v8-to-istanbul/-/v8-to-istanbul-4.1.4.tgz#b97936f21c0e2d9996d4985e5c5156e9d4e49cd6" - integrity sha512-Rw6vJHj1mbdK8edjR7+zuJrpDtKIgNdAvTSAcpYfgMIw+u2dPDntD3dgN4XQFLU2/fvFQdzj+EeSGfd/jnY5fQ== +v8-to-istanbul@^5.0.1: + version "5.0.1" + resolved "https://registry.yarnpkg.com/v8-to-istanbul/-/v8-to-istanbul-5.0.1.tgz#0608f5b49a481458625edb058488607f25498ba5" + integrity sha512-mbDNjuDajqYe3TXFk5qxcQy8L1msXNE37WTlLoqqpBfRsimbNcrlhQlDPntmECEcUvdC+AQ8CyMMf6EUx1r74Q== dependencies: "@types/istanbul-lib-coverage" "^2.0.1" convert-source-map "^1.6.0" @@ -6417,11 +6078,16 @@ validator@13.0.0: resolved "https://registry.yarnpkg.com/validator/-/validator-13.0.0.tgz#0fb6c6bb5218ea23d368a8347e6d0f5a70e3bcab" integrity sha512-anYx5fURbgF04lQV18nEQWZ/3wHGnxiKdG4aL8J+jEDsm98n/sU/bey+tYk6tnGJzm7ioh5FoqrAiQ6m03IgaA== -vary@^1, vary@~1.1.2: +vary@~1.1.2: version "1.1.2" resolved "https://registry.yarnpkg.com/vary/-/vary-1.1.2.tgz#2299f02c6ded30d4a5961b0b9f74524a18f634fc" integrity sha1-IpnwLG3tMNSllhsLn3RSShj2NPw= +velona@^0.5.1: + version "0.5.1" + resolved "https://registry.yarnpkg.com/velona/-/velona-0.5.1.tgz#f51c7eb3b2337dd133ac2e7b658ed75a410f8115" + integrity sha512-iUMP7PP2Pzg9N4aQlfKQFGumqM/bQIBbJ1B1d959aeFvzqyIr2VvVISvU7du1WLf0eXHiB0TFuHRxPFFXjVDSw== + verror@1.10.0: version "1.10.0" resolved "https://registry.yarnpkg.com/verror/-/verror-1.10.0.tgz#3a105ca17053af55d6e270c1f8288682e18da400" @@ -6512,15 +6178,6 @@ wordwrap@^1.0.0: resolved "https://registry.yarnpkg.com/wordwrap/-/wordwrap-1.0.0.tgz#27584810891456a4171c8d0226441ade90cbcaeb" integrity sha1-J1hIEIkUVqQXHI0CJkQa3pDLyus= -wrap-ansi@^5.1.0: - version "5.1.0" - resolved "https://registry.yarnpkg.com/wrap-ansi/-/wrap-ansi-5.1.0.tgz#1fd1f67235d5b6d0fee781056001bfb694c03b09" - integrity sha512-QC1/iN/2/RPVJ5jYK8BGttj5z83LmSKmvbvrXPNCLZSEb32KKVDJDl/MOt2N01qU2H/FkzEa9PKto1BqDjtd7Q== - dependencies: - ansi-styles "^3.2.0" - string-width "^3.0.0" - strip-ansi "^5.0.0" - wrap-ansi@^6.2.0: version "6.2.0" resolved "https://registry.yarnpkg.com/wrap-ansi/-/wrap-ansi-6.2.0.tgz#e9393ba07102e6c91a3b221478f0257cd2856e53" @@ -6557,29 +6214,11 @@ ws@^7.2.3: resolved "https://registry.yarnpkg.com/ws/-/ws-7.3.0.tgz#4b2f7f219b3d3737bc1a2fbf145d825b94d38ffd" integrity sha512-iFtXzngZVXPGgpTlP1rBqsUK82p9tKqsWRPg5L56egiljujJT3vGAYnHANvFxBieXrTFavhzhxW52jnaWV+w2w== -x-xss-protection@1.3.0: - version "1.3.0" - resolved "https://registry.yarnpkg.com/x-xss-protection/-/x-xss-protection-1.3.0.tgz#3e3a8dd638da80421b0e9fff11a2dbe168f6d52c" - integrity sha512-kpyBI9TlVipZO4diReZMAHWtS0MMa/7Kgx8hwG/EuZLiA6sg4Ah/4TRdASHhRRN3boobzcYgFRUFSgHRge6Qhg== - xml-name-validator@^3.0.0: version "3.0.0" resolved "https://registry.yarnpkg.com/xml-name-validator/-/xml-name-validator-3.0.0.tgz#6ae73e06de4d8c6e47f9fb181f78d648ad457c6a" integrity sha512-A5CUptxDsvxKJEU3yO6DuWBSJz/qizqzJKOMIfUJHETbBw/sFaDxgd6fxm1ewUaM0jZ444Fc5vC5ROYurg/4Pw== -xml2js@^0.4.17: - version "0.4.23" - resolved "https://registry.yarnpkg.com/xml2js/-/xml2js-0.4.23.tgz#a0c69516752421eb2ac758ee4d4ccf58843eac66" - integrity sha512-ySPiMjM0+pLDftHgXY4By0uswI3SPKLDw/i3UXbnO8M/p28zqexCUoPmQFrYD+/1BzhGJSs2i1ERWKJAtiLrug== - dependencies: - sax ">=0.6.0" - xmlbuilder "~11.0.0" - -xmlbuilder@~11.0.0: - version "11.0.1" - resolved "https://registry.yarnpkg.com/xmlbuilder/-/xmlbuilder-11.0.1.tgz#be9bae1c8a046e76b31127726347d0ad7002beb3" - integrity sha512-fDlsI/kFEx7gLvbecc0/ohLG50fugQp8ryHzMTuW9vSa1GJ0XYWKnhsUx7oie3G98+r56aTQIUB4kht42R3JvA== - xmlchars@^2.2.0: version "2.2.0" resolved "https://registry.yarnpkg.com/xmlchars/-/xmlchars-2.2.0.tgz#060fe1bcb7f9c76fe2a17db86a9bc3ab894210cb" @@ -6595,20 +6234,6 @@ y18n@^4.0.0: resolved "https://registry.yarnpkg.com/y18n/-/y18n-4.0.0.tgz#95ef94f85ecc81d007c264e190a120f0a3c8566b" integrity sha512-r9S/ZyXu/Xu9q1tYlpsLIsa3EeLXXk0VwlxqTcFRfg9EhMW+17kbt9G0NrgCmhGb5vT2hyhJZLfDGx+7+5Uj/w== -yaml@^1.7.2: - version "1.10.0" - resolved "https://registry.yarnpkg.com/yaml/-/yaml-1.10.0.tgz#3b593add944876077d4d683fee01081bd9fff31e" - integrity sha512-yr2icI4glYaNG+KWONODapy2/jDdMSDnrONSjblABjD9B4Z5LgiircSt8m8sRZFNi08kG9Sm0uSHtEmP3zaEGg== - -yargonaut@^1.1.2: - version "1.1.4" - resolved "https://registry.yarnpkg.com/yargonaut/-/yargonaut-1.1.4.tgz#c64f56432c7465271221f53f5cc517890c3d6e0c" - integrity sha512-rHgFmbgXAAzl+1nngqOcwEljqHGG9uUZoPjsdZEs1w5JW9RXYzrSvH/u70C1JE5qFi0qjsdhnUX/dJRpWqitSA== - dependencies: - chalk "^1.1.1" - figlet "^1.1.1" - parent-require "^1.0.0" - yargs-parser@18.x, yargs-parser@^18.1.1, yargs-parser@^18.1.3: version "18.1.3" resolved "https://registry.yarnpkg.com/yargs-parser/-/yargs-parser-18.1.3.tgz#be68c4975c6b2abf469236b0c870362fab09a7b0" @@ -6617,38 +6242,7 @@ yargs-parser@18.x, yargs-parser@^18.1.1, yargs-parser@^18.1.3: camelcase "^5.0.0" decamelize "^1.2.0" -yargs-parser@^10.0.0: - version "10.1.0" - resolved "https://registry.yarnpkg.com/yargs-parser/-/yargs-parser-10.1.0.tgz#7202265b89f7e9e9f2e5765e0fe735a905edbaa8" - integrity sha512-VCIyR1wJoEBZUqk5PA+oOBF6ypbwh5aNB3I50guxAL/quggdfs4TtNHQrSazFA3fYZ+tEqfs0zIGlv0c/rgjbQ== - dependencies: - camelcase "^4.1.0" - -yargs-parser@^13.1.2: - version "13.1.2" - resolved "https://registry.yarnpkg.com/yargs-parser/-/yargs-parser-13.1.2.tgz#130f09702ebaeef2650d54ce6e3e5706f7a4fb38" - integrity sha512-3lbsNRf/j+A4QuSZfDRA7HRSfWrzO0YjqTJd5kjAq37Zep1CEgaYmrH9Q3GwPiB9cHyd1Y1UwggGhJGoxipbzg== - dependencies: - camelcase "^5.0.0" - decamelize "^1.2.0" - -yargs@^13.2.1: - version "13.3.2" - resolved "https://registry.yarnpkg.com/yargs/-/yargs-13.3.2.tgz#ad7ffefec1aa59565ac915f82dccb38a9c31a2dd" - integrity sha512-AX3Zw5iPruN5ie6xGRIDgqkT+ZhnRlZMLMHAs8tg7nRruy2Nb+i5o9bwghAogtM08q1dpr2LVoS8KSTMYpWXUw== - dependencies: - cliui "^5.0.0" - find-up "^3.0.0" - get-caller-file "^2.0.1" - require-directory "^2.1.1" - require-main-filename "^2.0.0" - set-blocking "^2.0.0" - string-width "^3.0.0" - which-module "^2.0.0" - y18n "^4.0.0" - yargs-parser "^13.1.2" - -yargs@^15.0.0, yargs@^15.3.1: +yargs@^15.3.1: version "15.3.1" resolved "https://registry.yarnpkg.com/yargs/-/yargs-15.3.1.tgz#9505b472763963e54afe60148ad27a330818e98b" integrity sha512-92O1HWEjw27sBfgmXiixJWT5hRBp2eobqXicLtPBIDBhYB+1HpwZlXmbW2luivBJHBzki+7VyCLRtAkScbTBQA==