diff --git a/.eslintignore b/.eslintignore new file mode 100644 index 0000000..5b7ad57 --- /dev/null +++ b/.eslintignore @@ -0,0 +1,7 @@ +.yarn +node_modules +tmp +coverage +dist +.idea +yarn.lock diff --git a/.eslintrc b/.eslintrc new file mode 100644 index 0000000..866da96 --- /dev/null +++ b/.eslintrc @@ -0,0 +1,20 @@ +{ + "root": true, + "parser": "@typescript-eslint/parser", + "plugins": ["prettier", "unused-imports", "@typescript-eslint"], + "extends": [ + "eslint:recommended", + "plugin:@typescript-eslint/eslint-recommended", + "plugin:@typescript-eslint/recommended", + "prettier" + ], + "rules": { + "no-console": 1, // Means warning + "prettier/prettier": 2, // Means error, + "unused-imports/no-unused-imports-ts": 2, + "@typescript-eslint/no-unused-vars": 0, + "@typescript-eslint/no-empty-function": 0, + "@typescript-eslint/explicit-module-boundary-types": 0, + "@typescript-eslint/ban-ts-comment": 0 + } +} diff --git a/.github/workflows/setup.sh b/.github/workflows/setup.sh new file mode 100644 index 0000000..03703e0 --- /dev/null +++ b/.github/workflows/setup.sh @@ -0,0 +1,9 @@ +#!/bin/bash + +set -ex + +npm i --silent -g pnpm@6 --unsafe-perm + +pnpm i --no-prefer-frozen-lockfile + +pnpm run setup diff --git a/.github/workflows/test.yml b/.github/workflows/test.yml new file mode 100644 index 0000000..63e77fc --- /dev/null +++ b/.github/workflows/test.yml @@ -0,0 +1,49 @@ +# This workflow will do a clean install of node dependencies, cache/restore them, build the source code and run tests across different versions of node +# For more information see: https://help.github.com/actions/language-and-framework-guides/using-nodejs-with-github-actions + +name: CI + +on: + push: + branches: [ master ] + pull_request: + branches: [ master ] + +jobs: + build: + runs-on: ubuntu-latest + strategy: + matrix: + node-version: [ 12.x, 14.x, 16.x ] + steps: + - uses: actions/checkout@v2 + - uses: pnpm/action-setup@v2.0.1 + with: + version: 6.20.3 + - name: Use Node.js ${{ matrix.node-version }} + uses: actions/setup-node@v2 + with: + node-version: ${{ matrix.node-version }} + cache: 'pnpm' + - name: Install dependencies + run: pnpm install + + test: + timeout-minutes: 7 + runs-on: ubuntu-latest + + steps: + - uses: actions/checkout@v2 + - name: Cache .pnpm-store # From https://pnpm.io/continuous-integration + uses: actions/cache@v1 + with: + path: ~/.pnpm-store + key: ${{ runner.os }}-node-${{ hashFiles('**/pnpm-lock.yaml') }} + + - uses: actions/setup-node@v2 + with: + node-version: ${{ matrix.node-version }} + cache: 'pnpm' + + - run: pnpm test + working-directory: ./ diff --git a/.gitignore b/.gitignore index c5ce6aa..9a7b8c5 100644 --- a/.gitignore +++ b/.gitignore @@ -1,6 +1,9 @@ node_modules -/lib +dist .idea .DS_Store coverage package-lock.json +yarn-error.log +TODO.txt +package \ No newline at end of file diff --git a/.husky/pre-commit b/.husky/pre-commit new file mode 100755 index 0000000..4f65edc --- /dev/null +++ b/.husky/pre-commit @@ -0,0 +1,4 @@ +#!/bin/sh +. "$(dirname "$0")/_/husky.sh" + +yarn build && yarn test && yarn lint && yarn make-badges && git add README.md diff --git a/.npmignore b/.npmignore index 9dcffaa..c61ca82 100644 --- a/.npmignore +++ b/.npmignore @@ -1,13 +1,13 @@ +.* src -test +tests tsconfig.json tslint.json jest.config.js coverage response-samples -.idea -.DS_Store package-lock.json -.travis.yml -.npmrc -.npmrc.template +TODO.txt +yarn-error.log +commitlint.config.js +renovate.json diff --git a/.prettierignore b/.prettierignore new file mode 100644 index 0000000..6e9493b --- /dev/null +++ b/.prettierignore @@ -0,0 +1,6 @@ +.yarn/ +yarn.lock +node_modules +dist +.idea +coverage \ No newline at end of file diff --git a/.prettierrc b/.prettierrc new file mode 100644 index 0000000..d1cd00f --- /dev/null +++ b/.prettierrc @@ -0,0 +1,7 @@ +{ + "semi": true, + "trailingComma": "all", + "singleQuote": false, + "proseWrap": "never", + "printWidth": 120 +} diff --git a/.travis.yml b/.travis.yml deleted file mode 100644 index 173b631..0000000 --- a/.travis.yml +++ /dev/null @@ -1,41 +0,0 @@ -language: node_js - -node_js: - - "10" - -install: - - npm install - -os: - - linux - -stages: - - test - - name: deploy - -jobs: - include: - - stage: lint and test - script: - - node --version - - npm --version - - echo "Linting Started ..." - - npm run tslint - - echo "Linting Finished." - - echo "Testing Started ..." - - npm test - - echo "Testing Finished." - - - stage: publish - if: tag IS present - before_deploy: - - echo "Publishing npm package ..." - after_deploy: - - echo "Publish npm package successfully!" - deploy: - provider: npm - email: $NPM_EMAIL - api_key: $NPM_TOKEN - skip_cleanup: true - on: - tags: true diff --git a/.whitesource b/.whitesource new file mode 100644 index 0000000..12e4aae --- /dev/null +++ b/.whitesource @@ -0,0 +1,12 @@ +{ + "scanSettings": { + "baseBranches": ["master"] + }, + "checkRunSettings": { + "vulnerableCheckRunConclusionLevel": "failure", + "displayMode": "diff" + }, + "issueSettings": { + "minSeverityLevel": "LOW" + } +} \ No newline at end of file diff --git a/LICENSE.txt b/LICENSE.txt index 00345d0..753f896 100644 --- a/LICENSE.txt +++ b/LICENSE.txt @@ -1,6 +1,6 @@ MIT License -Copyright (c) 2019 +Copyright (c) 2021 Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal diff --git a/README-template.md b/README-template.md deleted file mode 100644 index d37ac8f..0000000 --- a/README-template.md +++ /dev/null @@ -1,583 +0,0 @@ -# ts-retrofit - -[![build status](https://travis-ci.org/nullcc/ts-retrofit.svg?branch=master)](https://travis-ci.org/nullcc/ts-retrofit) -[![](https://img.shields.io/npm/dm/ts-retrofit.svg?style=flat)](https://www.npmjs.org/package/ts-retrofit) - -| Statements | Branches | Functions | Lines | -| -----------|----------|-----------|-------| -| ![Statements](#statements# "Make me better!") | ![Branches](#branches# "Make me better!") | ![Functions](#functions# "Make me better!") | ![Lines](#lines# "Make me better!") | - -> A declarative and [axios](https://github.com/axios/axios) based retrofit implementation for JavaScript and TypeScript. - -## Install - -```bash -$ npm i ts-retrofit -``` - -## Quick Overview - -Here is a typical service definition and usage: - -```typescript -import { GET, POST, PUT, PATCH, DELETE, BasePath, Header, Path, Body, BaseService, ServiceBuilder, Response } from "ts-retrofit"; - -interface User { - id?: number; - name: string; - email: string; -} - -@BasePath("/api/v1") -class UserService extends BaseService { - @GET("/users") - async getUsers(@Header("Authorization") authorization: string): Promise>> { return >> {} }; - - @GET("/users/{userId}") - async getUser(@Header("Authorization") authorization: string, @Path("userId") userId: number): Promise> { return > {} }; - - @POST("/users") - async createUser(@Header("Authorization") authorization: string, @Body user: User): Promise { return {} }; - - @PUT("/users/{userId}") - async updateUser(@Header("Authorization") authorization: string, @Path("userId") userId: number, @Body user: User): Promise { return {} }; - - @PATCH("/users/{userId}") - async patchUser(@Header("Authorization") authorization: string, @Path("userId") userId: number, @Body user: Partial): Promise { return {} }; - - @DELETE("/users/{userId}") - async deleteUser(@Header("Authorization") authorization: string, @Path("userId") userId: number): Promise { return {} }; -} - -(async () => { - const authorization = "foobar"; - const userService = new ServiceBuilder() - .setEndpoint("https://www.your-host.com") - .build(UserService); - const response = await userService.getUsers(authorization); - // Now you can get response data from response.data -})() -``` - -You can see [test file](test/ts-retrofit.test.ts) to get more examples. - -## ServiceBuilder - -Example: - -```typescript -import { AxiosRequestConfig } from "axios"; -import { - ServiceBuilder, - ResponseInterceptorFunction, - RequestInterceptorFunction, - RequestInterceptor, - ResponseInterceptor, -} from "ts-retrofit"; - -@BasePath("/api/v1") -class ItemService extends BaseService { - @GET("/items") - async getItems(): Promise>> { return >> {} }; -} - -const RequestInterceptor: RequestInterceptorFunction = (config) => { - console.log("Before sending request to server."); - return config; -}; - -const ResponseInterceptor: ResponseInterceptorFunction = (response) => { - console.log("After receiving response from server."); - return response; -}; - -(async () => { - const itemService = new ServiceBuilder() - .setEndpoint(${ENDPOINT}) - .setStandalone(true) - .setRequestInterceptors(RequestInterceptor) - .setResponseInterceptors(ResponseInterceptor) - .build(ItemService); - const response: any = await itemService.getVersion(); - console.log(response.data); -})(); - -// outputs: -// Before sending request to server. -// After receiving response from server. -// -``` - -## Decorators - -### BasePath - -* Position: Class - -`BasePath` decorator declares the path prefix of a service. - -```typescript -// The common path of ItemService is ${ENDPOINT}/api/v1 -@BasePath("/api/v1") -class ItemService extends BaseService {} -``` - -### HTTP Method Decorators - -All HTTP method decorators have an optional second parameter with type **HttpMethodOptions**: - -```typescript -export interface HttpMethodOptions { - ignoreBasePath?: boolean; -} -``` - -#### GET - -* Position: Method - -`GET` decorator declares that what it decorated use HTTP **GET** method to request server. - -```typescript -@BasePath("/api/v1") -class ItemService extends BaseService { - // GET ${ENDPOINT}/api/v1/items - @GET("/items") - async getItems(): Promise>> { return >> {} }; - - // GET ${ENDPOINT}/items - @GET("/items", { ignoreBasePath: true }) - async getItemsWithoutBasePath(): Promise>> { return >> {} }; -} -``` - -#### POST - -* Position: Method - -`POST` decorator declares that what it decorated use HTTP **POST** method to request server. - -```typescript -@BasePath("/api/v1") -class ItemService extends BaseService { - // POST ${ENDPOINT}/api/v1/items - @POST("/items") - async createItem(@Body item: Item): Promise { return {} }; -} -``` - -#### PUT - -* Position: Method - -`PUT` decorator declares that what it decorated use HTTP **PUT** method to request server. - -```typescript -@BasePath("/api/v1") -class ItemService extends BaseService { - // PUT ${ENDPOINT}/api/v1/items/{itemId} - @PUT("/items/{itemId}") - async updateItem(@Path("itemId") itemId: number, @Body item: Item): Promise { return {} }; -} -``` - -#### PATCH - -* Position: Method - -`PATCH` decorator declares that what it decorated use HTTP **PATCH** method to request server. - -```typescript -@BasePath("/api/v1") -class ItemService extends BaseService { - // PATCH ${ENDPOINT}/api/v1/items/{itemId} - @PATCH("/items/{itemId}") - async patchItem(@Path("itemId") itemId: number, @Body item: Partial): Promise { return {} }; -} -``` - -#### DELETE - -* Position: Method - -`DELETE` decorator declares that what it decorated use HTTP **DELETE** method to request server. - -```typescript -@BasePath("/api/v1") -class ItemService extends BaseService { - // DELETE ${ENDPOINT}/api/v1/items/{itemId} - @DELETE("/items/{itemId}") - async deleteItem(@Path("itemId") itemId: number): Promise { return {} }; -} -``` - -#### HEAD - -* Position: Method - -`HEAD` decorator declares that what it decorated use HTTP **HEAD** method to request server. - -```typescript -@BasePath("/api/v1") -class FileService extends BaseService { - // HEAD ${ENDPOINT}/api/v1/files/{fileId} - @HEAD("/files/{fileId}") - async getFileMetaInfo(@Path("fileId") fileId: number): Promise { return {} }; -} -``` - -#### OPTIONS - -* Position: Method - -`OPTIONS` decorator declares that what it decorated use HTTP **OPTIONS** method to request server. - -```typescript -@BasePath("/api/v1") -class ItemService extends BaseService { - // OPTIONS ${ENDPOINT}/api/v1/items/{itemId} - @OPTIONS("/items/{itemId}") - async getFileMetaInfo(@Path("itemId") itemId: number): Promise { return {} }; -} -``` - -### Headers - -* Position: Method - -`Headers` decorator declares that what **static HTTP headers** should be added to request. - -```typescript -@BasePath("") -export class AuthService extends BaseService { - @POST("/oauth/token") - @Headers({ - "Content-Type": "application/x-www-form-urlencoded;charset=utf-8", - "Accept": "application/json" - }) - async auth(@Body body: OAuth): Promise> { return >{} }; -} -``` - -### Header - -* Position: Method Parameter - -`Header` decorator parameterizes the header in HTTP request. Client can provide a value to **one header**. - -```typescript -@BasePath("/api/v1") -class ItemService extends BaseService { - // GET ${ENDPOINT}/api/v1/items - async getItems(@Header("Authorization") authorization: string): Promise>> { return >> {} }; -} -``` - -### HeaderMap - -- Position: Method Parameter - -`HeaderMap` decorator parameterizes the headers in HTTP request. Client can provide values to **multi headers**. - -```typescript -@BasePath("/api/v1") -class ItemService extends BaseService { - // GET ${ENDPOINT}/api/v1/items - async getItems(@HeaderMap headers: any): Promise>> { return >> {} }; -} -``` - -### Path - -- Position: Method Parameter - -`Path` decorator parameterizes the part of path in HTTP request. - -```typescript -@BasePath("/api/v1") -class ItemService extends BaseService { - // GET ${ENDPOINT}/api/v1/items/{itemId} - @GET("/items/{itemId}") - async getItem(@Path("itemId") itemId: number): Promise> { return > {} }; -} -``` - -### Body - -- Position: Method Parameter - -`Body` decorator parameterizes the body in HTTP request. - -```typescript -@BasePath("/api/v1") -class ItemService extends BaseService { - // POST ${ENDPOINT}/api/v1/items - @POST("/items") - async createItem(@Body item: Item): Promise { return {} }; -} -``` - -### Queries - -- Position: Method - -`Queries` decorator declares that what **static queries** should be added to request. - -```typescript -@BasePath("/api/v1") -class ItemService extends BaseService { - // GET ${ENDPOINT}/api/v1/items?size=20 - @GET("/items") - @Queries({ - size: 20, - }) - async getItems(): Promise>> { return >> {} }; -} -``` - -### Query - -- Position: Method Parameter - -`Query` decorator parameterizes the query in HTTP request. Client can provide a value to **one query parameter**. - -```typescript -@BasePath("/api/v1") -class ItemService extends BaseService { - // GET ${ENDPOINT}/api/v1/items?size=20 - @GET("/items") - @Queries({ - size: 20, - }) - async getItems(): Promise>> { return >> {} }; -} -``` - -### QueryMap - -- Position: Method Parameter - -`QueryMap` decorator parameterizes the queries in HTTP request. Client can provide values to **multi queries**. - -```typescript -@BasePath("") -class SearchService extends BaseService { - // GET ${ENDPOINT}/search?a=foo&b=bar - @GET("/search") - async search(@QueryMap query: SearchQuery): Promise> { return > {} }; -} -``` - -### FormUrlEncoded - -- Position: Method - -`FormUrlEncoded` declares that the content type is **application/x-www-form-urlencoded;charset=utf-8** in HTTP request. - -```typescript -@BasePath("") -export class AuthService extends BaseService { - @POST("/oauth/token") - @FormUrlEncoded - async auth(@Body body: OAuth): Promise> { return >{} }; -} -``` - -### Field - -- Position: Method Parameter - -`Field` decorator parameterizes the field in HTTP request. It only takes effect when method is decorated by **@FormUrlEncoded**. - -```typescript -@BasePath("") -export class AuthService extends BaseService { - @POST("/oauth/token") - @FormUrlEncoded - async auth(@Field("username") username: string, @Field("password") password: string): Promise> { return >{} }; -} -``` - -### FieldMap - -- Position: Method Parameter - -`FieldMap` decorator parameterizes the field in HTTP request. It only takes effect when method is decorated by **@FormUrlEncoded**. - -```typescript -@BasePath("") -export class AuthService extends BaseService { - @POST("/oauth/token") - @FormUrlEncoded - async auth(@FieldMap fields: OAuth): Promise> { return >{} }; -} -``` - -### Multipart - -- Position: Method - -`Multipart` decorator declares that the content type is **multipart/form-data** in HTTP request. - -```typescript -@BasePath("/api/v1") -export class FileService extends BaseService { - @POST("/upload") - @Multipart - async upload(@Part("bucket") bucket: PartDescriptor, @Part("file") file: PartDescriptor): Promise { return {} }; -} -``` - -### Part - -- Position: Method Parameter - -`Part` decorator parameterizes the part in HTTP request. It only takes effect when method is decorated by **@Multipart**. - -```typescript -@BasePath("/api/v1") -export class FileService extends BaseService { - @POST("/upload") - @Multipart - async upload(@Part("bucket") bucket: PartDescriptor, @Part("file") file: PartDescriptor): Promise { return {} }; -} -``` - -### ResponseType - -- Position: Method -- Options: 'arraybuffer' | 'blob' | 'document' | 'json' | 'text' | 'stream' - -`ResponseType` decorator declares response type in axios config. - -```typescript -@BasePath("/api/v1") -export class FileService extends BaseService { - @GET("/file") - @ResponseType("stream") - async getFile(@Path("fileId") fileId: string): Promise { return {} }; -} -``` - -### RequestTransformer - -- Position: Method - -`RequestTransformer` decorator provides a hook to handle request data before sending request to server. - -```typescript -@BasePath(API_PREFIX) -export class TransformerService extends BaseService { - @POST("/request-transformer") - @RequestTransformer((data: any, headers?: any) => { - data.foo = 'foo'; // add something to request data - return JSON.stringify(data); - }) - async createSomething(@Body body: Something): Promise { return {} }; -} -``` - -### ResponseTransformer - -- Position: Method - -`ResponseTransformer` decorator provides a hook to handle response data after receiving response from server. - -```typescript -@BasePath(API_PREFIX) -export class TransformerService extends BaseService { - @POST("/request-transformer") - @RequestTransformer((data: any, headers?: any) => { - data.foo = 'foo'; // add something to response data - return JSON.stringify(data); - }) - async createSomething(@Body body: Something): Promise { return {} }; -} -``` - -### Timeout - -- Position: Method - -`Timeout` decorator declares timeout in axios config. - -```typescript -@BasePath("/api/v1") -class ItemService extends BaseService { - // GET ${ENDPOINT}/api/v1/items - @GET("/items") - @Timeout(3000) - async getItems(): Promise>> { return >> {} }; -} -``` - -### ResponseStatus - -- Position: Method - -`ResponseStatus` decorator declares status code for method, do nothing just a declaration. - -```typescript -@BasePath("/api/v1") -class ItemService extends BaseService { - // GET ${ENDPOINT}/api/v1/items - @GET("/items") - @Timeout(3000) - async getItems(): Promise>> { return >> {} }; -} -``` - -### Config - -- Position: Method - -`Config` decorator provides a direct way to set config for a request in axios. - -```typescript -@BasePath("/api/v1") -export class ConfigService extends BaseService { - @GET("/config") - @Config({ - maxRedirects: 1, - }) - async getConfig(): Promise { return {} }; -} -``` - -### Decorators Summary - -| Category | Name | Description | Decorator Position | Example | -| :-----------------: | :------------------: | :--------------------------------------: | :----------------: | :--------------------------------------: | -| HTTP Method | @GET | GET Method | Method | @GET("/users") | -| HTTP Method | @POST | POST Method | Method | @POST("/users") | -| HTTP Method | @PUT | PUT Method | Method | @PUT("/users/{userId}") | -| HTTP Method | @PATCH | PATCH Method | Method | @PATCH("/users/{userId}") | -| HTTP Method | @DELETE | DELETE Method | Method | @DELETE("/users/{userId}") | -| HTTP Method | @HEAD | HEAD Method | Method | @HEAD("/users/{userId}") | -| HTTP Method | @OPTIONS | OPTIONS Method | Method | @OPTIONS("/users/{userId}") | -| Base Path | @BasePath | Specifying the base path of a series of API endpoints | Class | @BasePath("/api/v1") | -| Static Headers | @Headers | Specifying the static headers of API endpoint | Method | @Headers({ "content-type": "application/x-www-form-urlencoded", "Accept": "application/json" }) | -| Header Parameter | @Header | Parameterized header | Method Parameter | @Header("X-Token") | -| Header Parameters | @HeaderMap | Parameterized header | Method Parameter | @HeaderMap | -| Path Parameter | @Path | Specifying parameter in path of API | Method Parameter | @Path("userId") | -| Body | @Body | Specifying body data | Method Parameter | @Body | -| Static Query | @Queries | Specifying static query data | Method | @Queries({ page: 1, size: 20, sort: "createdAt:desc" }) | -| Query Parameter | @Query | Parameterized query | Method Parameter | @Query("group") | -| Query Parameters | @QueryMap | Parameterized query | Method Parameter | @QueryMap | -| Static Headers | @FormUrlEncoded | Specifying "content-type" to be "application/x-www-form-urlencoded" | Method | @FormUrlEncoded | -| Field Parameter | @Field | Specifying field in method parameter, only takes effect when method has been decorated by @FormUrlEncoded | Method Parameter | @Field("name") | -| Field Parameters | @FieldMap | Specifying field map in method parameter, only takes effect when method has been decorated by @FormUrlEncoded | Method Parameter | @FieldMap | -| Static Headers | @Multipart | Specifying "content-type" to be "multipart/form-data" | Method | @Multipart | -| Part Parameters | @Part | Specifying field map in method parameter, only takes effect when method has been decorated by @Multipart | Method Parameter | @Part("name") | -| Response | @ResponseType | Specifying the response type in axios config | Method | @ResponseType("stream") | -| RequestTransformer | @RequestTransformer | Specifying the request transformer in axios config | Method | @RequestTransformer((data: any, headers?: any) => { data.foo = 'foo'; return JSON.stringify(data); }) | -| ResponseTransformer | @ResponseTransformer | Specifying the response transformer in axios config | Method | @ResponseTransformer((data: any, headers?: any) => { const json = JSON.parse(data); json.foo = 'foo'; return json; }) | -| Timeout | @Timeout | Specifying the timeout in axios config | Method | @Timeout(5000) | -| ResponseStatus | @ResponseStatus | Declare response status code for method, do nothing just a declaration | Method | @ResponseStatus(204) | -| Config | @Config | A direct way to set config for a request in axios | Method | @Config({ maxRedirects: 1 }) | - -## Test - -```bash -$ npm test -``` diff --git a/README.md b/README.md index dec6f2f..4ba81ca 100644 --- a/README.md +++ b/README.md @@ -1,583 +1,169 @@ -# ts-retrofit +

ts-retrofit 2

-[![build status](https://travis-ci.org/nullcc/ts-retrofit.svg?branch=master)](https://travis-ci.org/nullcc/ts-retrofit) -[![](https://img.shields.io/npm/dm/ts-retrofit.svg?style=flat)](https://www.npmjs.org/package/ts-retrofit) +

+ Declarative and type-safe HTTP client for Node.js and Web +

-| Statements | Branches | Functions | Lines | -| ---------------------------------------- | ---------------------------------------- | ---------------------------------------- | ---------------------------------------- | -| ![Statements](https://img.shields.io/badge/Coverage-98.99%25-brightgreen.svg "Make me better!") | ![Branches](https://img.shields.io/badge/Coverage-83.87%25-yellow.svg "Make me better!") | ![Functions](https://img.shields.io/badge/Coverage-98.67%25-brightgreen.svg "Make me better!") | ![Lines](https://img.shields.io/badge/Coverage-98.99%25-brightgreen.svg "Make me better!") | +

+ build status + github package + npm package + npm downloads + license +

-> A declarative and axios based retrofit implementation for JavaScript and TypeScript. +### Test coverage -## Install +| Statements | Branches | Functions | Lines | +| --------------------------- | ----------------------- | ------------------------- | -------------------- | +| ![Statements](https://img.shields.io/badge/statements-96.14%25-brightgreen.svg?style=flat) | ![Branches](https://img.shields.io/badge/branches-88.54%25-yellow.svg?style=flat) | ![Functions](https://img.shields.io/badge/functions-94.21%25-brightgreen.svg?style=flat) | ![Lines](https://img.shields.io/badge/lines-97.58%25-brightgreen.svg?style=flat) | -```bash -$ npm i ts-retrofit -``` - -## Quick Overview - -Here is a typical service definition and usage: - -```typescript -import { GET, POST, PUT, PATCH, DELETE, BasePath, Header, Path, Body, BaseService, ServiceBuilder, Response } from "ts-retrofit"; - -interface User { - id?: number; - name: string; - email: string; -} - -@BasePath("/api/v1") -class UserService extends BaseService { - @GET("/users") - async getUsers(@Header("Authorization") authorization: string): Promise>> { return >> {} }; - - @GET("/users/{userId}") - async getUser(@Header("Authorization") authorization: string, @Path("userId") userId: number): Promise> { return > {} }; - - @POST("/users") - async createUser(@Header("Authorization") authorization: string, @Body user: User): Promise { return {} }; - - @PUT("/users/{userId}") - async updateUser(@Header("Authorization") authorization: string, @Path("userId") userId: number, @Body user: User): Promise { return {} }; - - @PATCH("/users/{userId}") - async patchUser(@Header("Authorization") authorization: string, @Path("userId") userId: number, @Body user: Partial): Promise { return {} }; - - @DELETE("/users/{userId}") - async deleteUser(@Header("Authorization") authorization: string, @Path("userId") userId: number): Promise { return {} }; -} - -(async () => { - const authorization = "foobar"; - const userService = new ServiceBuilder() - .setEndpoint("https://www.your-host.com") - .build(UserService); - const response = await userService.getUsers(authorization); - // Now you can get response data from response.data -})() -``` - -You can see [test file](test/ts-retrofit.test.ts) to get more examples. - -## ServiceBuilder - -Example: - -```typescript -import { AxiosRequestConfig } from "axios"; -import { - ServiceBuilder, - ResponseInterceptorFunction, - RequestInterceptorFunction, - RequestInterceptor, - ResponseInterceptor, -} from "ts-retrofit"; - -@BasePath("/api/v1") -class ItemService extends BaseService { - @GET("/items") - async getItems(): Promise>> { return >> {} }; -} - -const RequestInterceptor: RequestInterceptorFunction = (config) => { - console.log("Before sending request to server."); - return config; -}; - -const ResponseInterceptor: ResponseInterceptorFunction = (response) => { - console.log("After receiving response from server."); - return response; -}; - -(async () => { - const itemService = new ServiceBuilder() - .setEndpoint(${ENDPOINT}) - .setStandalone(true) - .setRequestInterceptors(RequestInterceptor) - .setResponseInterceptors(ResponseInterceptor) - .build(ItemService); - const response: any = await itemService.getVersion(); - console.log(response.data); -})(); - -// outputs: -// Before sending request to server. -// After receiving response from server. -// -``` - -## Decorators - -### BasePath - -* Position: Class - -`BasePath` decorator declares the path prefix of a service. - -```typescript -// The common path of ItemService is ${ENDPOINT}/api/v1 -@BasePath("/api/v1") -class ItemService extends BaseService {} -``` - -### HTTP Method Decorators - -All HTTP method decorators have an optional second parameter with type **HttpMethodOptions**: - -```typescript -export interface HttpMethodOptions { - ignoreBasePath?: boolean; -} -``` - -#### GET - -* Position: Method - -`GET` decorator declares that what it decorated use HTTP **GET** method to request server. - -```typescript -@BasePath("/api/v1") -class ItemService extends BaseService { - // GET ${ENDPOINT}/api/v1/items - @GET("/items") - async getItems(): Promise>> { return >> {} }; - - // GET ${ENDPOINT}/items - @GET("/items", { ignoreBasePath: true }) - async getItemsWithoutBasePath(): Promise>> { return >> {} }; -} -``` - -#### POST - -* Position: Method - -`POST` decorator declares that what it decorated use HTTP **POST** method to request server. - -```typescript -@BasePath("/api/v1") -class ItemService extends BaseService { - // POST ${ENDPOINT}/api/v1/items - @POST("/items") - async createItem(@Body item: Item): Promise { return {} }; -} -``` - -#### PUT - -* Position: Method - -`PUT` decorator declares that what it decorated use HTTP **PUT** method to request server. - -```typescript -@BasePath("/api/v1") -class ItemService extends BaseService { - // PUT ${ENDPOINT}/api/v1/items/{itemId} - @PUT("/items/{itemId}") - async updateItem(@Path("itemId") itemId: number, @Body item: Item): Promise { return {} }; -} -``` - -#### PATCH - -* Position: Method - -`PATCH` decorator declares that what it decorated use HTTP **PATCH** method to request server. - -```typescript -@BasePath("/api/v1") -class ItemService extends BaseService { - // PATCH ${ENDPOINT}/api/v1/items/{itemId} - @PATCH("/items/{itemId}") - async patchItem(@Path("itemId") itemId: number, @Body item: Partial): Promise { return {} }; -} -``` - -#### DELETE - -* Position: Method - -`DELETE` decorator declares that what it decorated use HTTP **DELETE** method to request server. - -```typescript -@BasePath("/api/v1") -class ItemService extends BaseService { - // DELETE ${ENDPOINT}/api/v1/items/{itemId} - @DELETE("/items/{itemId}") - async deleteItem(@Path("itemId") itemId: number): Promise { return {} }; -} -``` - -#### HEAD - -* Position: Method - -`HEAD` decorator declares that what it decorated use HTTP **HEAD** method to request server. - -```typescript -@BasePath("/api/v1") -class FileService extends BaseService { - // HEAD ${ENDPOINT}/api/v1/files/{fileId} - @HEAD("/files/{fileId}") - async getFileMetaInfo(@Path("fileId") fileId: number): Promise { return {} }; -} -``` -#### OPTIONS -* Position: Method +## Installing -`OPTIONS` decorator declares that what it decorated use HTTP **OPTIONS** method to request server. +Using npm: -```typescript -@BasePath("/api/v1") -class ItemService extends BaseService { - // OPTIONS ${ENDPOINT}/api/v1/items/{itemId} - @OPTIONS("/items/{itemId}") - async getFileMetaInfo(@Path("itemId") itemId: number): Promise { return {} }; -} +```bash +$ npm install ts-retrofit2 ``` -### Headers - -* Position: Method - -`Headers` decorator declares that what **static HTTP headers** should be added to request. +Using yarn: -```typescript -@BasePath("") -export class AuthService extends BaseService { - @POST("/oauth/token") - @Headers({ - "Content-Type": "application/x-www-form-urlencoded;charset=utf-8", - "Accept": "application/json" - }) - async auth(@Body body: OAuth): Promise> { return >{} }; -} +```bash +$ yarn add ts-retrofit2 ``` -### Header - -* Position: Method Parameter - -`Header` decorator parameterizes the header in HTTP request. Client can provide a value to **one header**. +## Introduction +Automatically turn your decorated methods into axios HTTP requests. ```typescript -@BasePath("/api/v1") -class ItemService extends BaseService { - // GET ${ENDPOINT}/api/v1/items - async getItems(@Header("Authorization") authorization: string): Promise>> { return >> {} }; +export class GitHubService extends BaseService { + @GET("/users/{user}/repos") + listRepos(@Path("user") user: string): ApiResponse {} } ``` -### HeaderMap - -- Position: Method Parameter - -`HeaderMap` decorator parameterizes the headers in HTTP request. Client can provide values to **multi headers**. +Build a service: ```typescript -@BasePath("/api/v1") -class ItemService extends BaseService { - // GET ${ENDPOINT}/api/v1/items - async getItems(@HeaderMap headers: any): Promise>> { return >> {} }; -} -``` - -### Path +const service = new ServiceBuilder() + .baseUrl("https://api.github.com/") + .build(GitHubService); -- Position: Method Parameter - -`Path` decorator parameterizes the part of path in HTTP request. - -```typescript -@BasePath("/api/v1") -class ItemService extends BaseService { - // GET ${ENDPOINT}/api/v1/items/{itemId} - @GET("/items/{itemId}") - async getItem(@Path("itemId") itemId: number): Promise> { return > {} }; -} +const repose = await service.listRepos("octocat"); ``` -### Body - -- Position: Method Parameter - -`Body` decorator parameterizes the body in HTTP request. +Use decorators to describe the HTTP request. +### Inlined response body +If you need only response body you can inline it ```typescript -@BasePath("/api/v1") -class ItemService extends BaseService { - // POST ${ENDPOINT}/api/v1/items - @POST("/items") - async createItem(@Body item: Item): Promise { return {} }; +export class GitHubService extends BaseService { + @GET("/users/{user}/repos") + listReposWithInlinedBody(@Path("user") user: string): ApiResponseBody {} } ``` -### Queries - -- Position: Method - -`Queries` decorator declares that what **static queries** should be added to request. - ```typescript -@BasePath("/api/v1") -class ItemService extends BaseService { - // GET ${ENDPOINT}/api/v1/items?size=20 - @GET("/items") - @Queries({ - size: 20, - }) - async getItems(): Promise>> { return >> {} }; -} -``` - -### Query - -- Position: Method Parameter +const service = new ServiceBuilder() + .baseUrl("https://api.github.com/") + .inlineResponseBody() + .build(GitHubService); -`Query` decorator parameterizes the query in HTTP request. Client can provide a value to **one query parameter**. - -```typescript -@BasePath("/api/v1") -class ItemService extends BaseService { - // GET ${ENDPOINT}/api/v1/items?size=20 - @GET("/items") - @Queries({ - size: 20, - }) - async getItems(): Promise>> { return >> {} }; -} +const repose = await service.listRepos("octocat"); ``` -### QueryMap - -- Position: Method Parameter +## API Declaration +Decorators on the methods and its parameters indicate how a request will be handled. -`QueryMap` decorator parameterizes the queries in HTTP request. Client can provide values to **multi queries**. +### REQUEST METHOD +Every method must have an HTTP decorator that provides the request method and relative URL. There are built-in decorators: `GET`, `POST`, `PUT`, `PATCH`, `DELETE`, `OPTIONS` and `HEAD`. The relative URL of the resource is specified in the decorator param. ```typescript -@BasePath("") -class SearchService extends BaseService { - // GET ${ENDPOINT}/search?a=foo&b=bar - @GET("/search") - async search(@QueryMap query: SearchQuery): Promise> { return > {} }; -} +@GET("users/list") ``` - -### FormUrlEncoded - -- Position: Method - -`FormUrlEncoded` declares that the content type is **application/x-www-form-urlencoded;charset=utf-8** in HTTP request. - +You can also specify query parameters in the URL. ```typescript -@BasePath("") -export class AuthService extends BaseService { - @POST("/oauth/token") - @FormUrlEncoded - async auth(@Body body: OAuth): Promise> { return >{} }; -} +@GET("users/list?sort=desc") ``` - -### Field - -- Position: Method Parameter - -`Field` decorator parameterizes the field in HTTP request. It only takes effect when method is decorated by **@FormUrlEncoded**. - +### URL MANIPULATION +A request URL can be updated dynamically using replacement blocks and parameters on the method. A replacement block is an alphanumeric string surrounded by { and }. A corresponding parameter must be decorated with `@Path` using the same string. ```typescript -@BasePath("") -export class AuthService extends BaseService { - @POST("/oauth/token") - @FormUrlEncoded - async auth(@Field("username") username: string, @Field("password") password: string): Promise> { return >{} }; -} +@GET("group/{id}/users") +groupList(@Path("id") groupId: string): ApiResponse {} ``` -### FieldMap - -- Position: Method Parameter - -`FieldMap` decorator parameterizes the field in HTTP request. It only takes effect when method is decorated by **@FormUrlEncoded**. +Query parameters can also be added using `@Query`. ```typescript -@BasePath("") -export class AuthService extends BaseService { - @POST("/oauth/token") - @FormUrlEncoded - async auth(@FieldMap fields: OAuth): Promise> { return >{} }; -} +@GET("group/{id}/users") +groupList(@Path("id") groupId: string, @Query("sort") sort: string): ApiResponse {} ``` -### Multipart - -- Position: Method - -`Multipart` decorator declares that the content type is **multipart/form-data** in HTTP request. +For complex query parameter can be added using `@QueryMap`. It should be object with primitive properties. ```typescript -@BasePath("/api/v1") -export class FileService extends BaseService { - @POST("/upload") - @Multipart - async upload(@Part("bucket") bucket: PartDescriptor, @Part("file") file: PartDescriptor): Promise { return {} }; -} +@GET("group/{id}/users") +groupList(@Path("id") groupId: string, @QueryMap query: SearchQuery): ApiResponse {} ``` -### Part - -- Position: Method Parameter - -`Part` decorator parameterizes the part in HTTP request. It only takes effect when method is decorated by **@Multipart**. - +### REQUEST BODY ```typescript -@BasePath("/api/v1") -export class FileService extends BaseService { - @POST("/upload") - @Multipart - async upload(@Part("bucket") bucket: PartDescriptor, @Part("file") file: PartDescriptor): Promise { return {} }; -} +@POST("users/new") +groupList(@Body user: User): ApiResponse {} ``` -### ResponseType - -- Position: Method -- Options: 'arraybuffer' | 'blob' | 'document' | 'json' | 'text' | 'stream' - -`ResponseType` decorator declares response type in axios config. - +### FORM ENCODED AND MULTIPART ```typescript -@BasePath("/api/v1") -export class FileService extends BaseService { - @GET("/file") - @ResponseType("stream") - async getFile(@Path("fileId") fileId: string): Promise { return {} }; -} +@POST("/user/edit") +@FormUrlEncoded +formUrlEncoded( + @Field("first_name") first: string, + @Field("last_name") last: string, +): ApiResponse {} ``` -### RequestTransformer - -- Position: Method - -`RequestTransformer` decorator provides a hook to handle request data before sending request to server. - +Multipart requests are used when @Multipart is present on the method. Parts are declared using the @Part decorator. ```typescript -@BasePath(API_PREFIX) -export class TransformerService extends BaseService { - @POST("/request-transformer") - @RequestTransformer((data: any, headers?: any) => { - data.foo = 'foo'; // add something to request data - return JSON.stringify(data); - }) - async createSomething(@Body body: Something): Promise { return {} }; -} +@PUT("user/photo") +@Multipart +updateUser( + @Part("description") description: PartDescriptor, + @Part("photo") file: PartDescriptor, +): ApiResponse {} ``` -### ResponseTransformer - -- Position: Method - -`ResponseTransformer` decorator provides a hook to handle response data after receiving response from server. +### HEADER MANIPULATION +You can set static headers for a method using the @Headers decorator. ```typescript -@BasePath(API_PREFIX) -export class TransformerService extends BaseService { - @POST("/request-transformer") - @RequestTransformer((data: any, headers?: any) => { - data.foo = 'foo'; // add something to response data - return JSON.stringify(data); - }) - async createSomething(@Body body: Something): Promise { return {} }; -} +@GET("widget/list") +@Headers({ + "Cache-Control": "max-age=640000", +}) +widgetList(): ApiResponse {} ``` - -### Timeout - -- Position: Method - -`Timeout` decorator declares timeout in axios config. - ```typescript -@BasePath("/api/v1") -class ItemService extends BaseService { - // GET ${ENDPOINT}/api/v1/items - @GET("/items") - @Timeout(3000) - async getItems(): Promise>> { return >> {} }; -} +@GET("users/{username}") +@Headers({ + "Accept": "application/vnd.github.v3.full+json", + "User-Agent": "Retrofit-Sample-App" +}) +getUser(@Path("username") username: string): ApiResponse {} ``` -### ResponseStatus - -- Position: Method - -`ResponseStatus` decorator declares status code for method, do nothing just a declaration. +A request Header can be updated dynamically using the `@Header` decorator. A corresponding parameter must be provided to the @Header. If the value is null, the header will be omitted. Otherwise, toString will be called on the value, and the result used. ```typescript -@BasePath("/api/v1") -class ItemService extends BaseService { - // GET ${ENDPOINT}/api/v1/items - @GET("/items") - @Timeout(3000) - async getItems(): Promise>> { return >> {} }; -} +@GET("user") +getUser(@Header("Authorization") authorization: string): ApiResponse {} ``` - -### Config - -- Position: Method - -`Config` decorator provides a direct way to set config for a request in axios. +Similar to query parameters, for complex header combinations, a `@HeaderMap` can be used. ```typescript -@BasePath("/api/v1") -export class ConfigService extends BaseService { - @GET("/config") - @Config({ - maxRedirects: 1, - }) - async getConfig(): Promise { return {} }; -} +@GET("user") +getUser(@HeaderMap headers: MyHeaders): ApiResponse {} ``` +Headers that need to be added to every request can be specified using an interceptor. -### Decorators Summary - -| Category | Name | Description | Decorator Position | Example | -| :-----------------: | :------------------: | :--------------------------------------: | :----------------: | :--------------------------------------: | -| HTTP Method | @GET | GET Method | Method | @GET("/users") | -| HTTP Method | @POST | POST Method | Method | @POST("/users") | -| HTTP Method | @PUT | PUT Method | Method | @PUT("/users/{userId}") | -| HTTP Method | @PATCH | PATCH Method | Method | @PATCH("/users/{userId}") | -| HTTP Method | @DELETE | DELETE Method | Method | @DELETE("/users/{userId}") | -| HTTP Method | @HEAD | HEAD Method | Method | @HEAD("/users/{userId}") | -| HTTP Method | @OPTIONS | OPTIONS Method | Method | @OPTIONS("/users/{userId}") | -| Base Path | @BasePath | Specifying the base path of a series of API endpoints | Class | @BasePath("/api/v1") | -| Static Headers | @Headers | Specifying the static headers of API endpoint | Method | @Headers({ "content-type": "application/x-www-form-urlencoded", "Accept": "application/json" }) | -| Header Parameter | @Header | Parameterized header | Method Parameter | @Header("X-Token") | -| Header Parameters | @HeaderMap | Parameterized header | Method Parameter | @HeaderMap | -| Path Parameter | @Path | Specifying parameter in path of API | Method Parameter | @Path("userId") | -| Body | @Body | Specifying body data | Method Parameter | @Body | -| Static Query | @Queries | Specifying static query data | Method | @Queries({ page: 1, size: 20, sort: "createdAt:desc" }) | -| Query Parameter | @Query | Parameterized query | Method Parameter | @Query("group") | -| Query Parameters | @QueryMap | Parameterized query | Method Parameter | @QueryMap | -| Static Headers | @FormUrlEncoded | Specifying "content-type" to be "application/x-www-form-urlencoded" | Method | @FormUrlEncoded | -| Field Parameter | @Field | Specifying field in method parameter, only takes effect when method has been decorated by @FormUrlEncoded | Method Parameter | @Field("name") | -| Field Parameters | @FieldMap | Specifying field map in method parameter, only takes effect when method has been decorated by @FormUrlEncoded | Method Parameter | @FieldMap | -| Static Headers | @Multipart | Specifying "content-type" to be "multipart/form-data" | Method | @Multipart | -| Part Parameters | @Part | Specifying field map in method parameter, only takes effect when method has been decorated by @Multipart | Method Parameter | @Part("name") | -| Response | @ResponseType | Specifying the response type in axios config | Method | @ResponseType("stream") | -| RequestTransformer | @RequestTransformer | Specifying the request transformer in axios config | Method | @RequestTransformer((data: any, headers?: any) => { data.foo = 'foo'; return JSON.stringify(data); }) | -| ResponseTransformer | @ResponseTransformer | Specifying the response transformer in axios config | Method | @ResponseTransformer((data: any, headers?: any) => { const json = JSON.parse(data); json.foo = 'foo'; return json; }) | -| Timeout | @Timeout | Specifying the timeout in axios config | Method | @Timeout(5000) | -| ResponseStatus | @ResponseStatus | Declare response status code for method, do nothing just a declaration | Method | @ResponseStatus(204) | -| Config | @Config | A direct way to set config for a request in axios | Method | @Config({ maxRedirects: 1 }) | - -## Test - -```bash -$ npm test -``` diff --git a/commitlint.config.js b/commitlint.config.js new file mode 100644 index 0000000..5073c20 --- /dev/null +++ b/commitlint.config.js @@ -0,0 +1 @@ +module.exports = { extends: ["@commitlint/config-conventional"] }; diff --git a/jest.config.js b/jest.config.js index c6a1522..33ad195 100644 --- a/jest.config.js +++ b/jest.config.js @@ -1,18 +1,22 @@ module.exports = { - roots: [''], + roots: [""], transform: { - '^.+\\.tsx?$': 'ts-jest' + "^.+\\.tsx?$": "ts-jest", }, - testRegex: '(/test/.*|(\\.|/)(test|spec))\\.(jsx?|tsx?)$', - modulePathIgnorePatterns: ["fixtures", "testSetupFile", "server"], + testRegex: "(/tests/.*|(\\.|/)(test|spec))\\.(jsx?|tsx?)$", + modulePathIgnorePatterns: ["fixtures", "testSetupFile", "server", "coverage"], moduleFileExtensions: ["ts", "tsx", "js", "jsx", "json", "node"], testURL: "http://localhost/", testEnvironment: "node", rootDir: ".", - setupFilesAfterEnv: ["./test/testSetupFile.js"], - "coverageReporters": [ - "json-summary", - "text", - "lcov" - ] + setupFilesAfterEnv: ["./tests/testSetupFile.ts"], + coverageReporters: ["json-summary", "text", "lcov"], + coverageThreshold: { + global: { + branches: 85, + functions: 90, + lines: 90, + statements: 90, + }, + }, }; diff --git a/package-lock.json b/package-lock.json deleted file mode 100644 index ba989f0..0000000 --- a/package-lock.json +++ /dev/null @@ -1,5899 +0,0 @@ -{ - "name": "ts-retrofit", - "version": "1.11.1", - "lockfileVersion": 1, - "requires": true, - "dependencies": { - "@babel/code-frame": { - "version": "7.5.5", - "resolved": "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.5.5.tgz", - "integrity": "sha512-27d4lZoomVyo51VegxI20xZPuSHusqbQag/ztrBC7wegWoQ1nLREPVSKSW8byhTlzTKyNE4ifaTA6lCp7JjpFw==", - "dev": true, - "requires": { - "@babel/highlight": "^7.0.0" - } - }, - "@babel/core": { - "version": "7.6.2", - "resolved": "https://registry.npmjs.org/@babel/core/-/core-7.6.2.tgz", - "integrity": "sha512-l8zto/fuoZIbncm+01p8zPSDZu/VuuJhAfA7d/AbzM09WR7iVhavvfNDYCNpo1VvLk6E6xgAoP9P+/EMJHuRkQ==", - "dev": true, - "requires": { - "@babel/code-frame": "^7.5.5", - "@babel/generator": "^7.6.2", - "@babel/helpers": "^7.6.2", - "@babel/parser": "^7.6.2", - "@babel/template": "^7.6.0", - "@babel/traverse": "^7.6.2", - "@babel/types": "^7.6.0", - "convert-source-map": "^1.1.0", - "debug": "^4.1.0", - "json5": "^2.1.0", - "lodash": "^4.17.13", - "resolve": "^1.3.2", - "semver": "^5.4.1", - "source-map": "^0.5.0" - }, - "dependencies": { - "debug": { - "version": "4.1.1", - "resolved": "https://registry.npmjs.org/debug/-/debug-4.1.1.tgz", - "integrity": "sha512-pYAIzeRo8J6KPEaJ0VWOh5Pzkbw/RetuzehGM7QRRX5he4fPHx2rdKMB256ehJCkX+XRQm16eZLqLNS8RSZXZw==", - "dev": true, - "requires": { - "ms": "^2.1.1" - } - }, - "ms": { - "version": "2.1.2", - "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz", - "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==", - "dev": true - }, - "source-map": { - "version": "0.5.7", - "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.5.7.tgz", - "integrity": "sha1-igOdLRAh0i0eoUyA2OpGi6LvP8w=", - "dev": true - } - } - }, - "@babel/generator": { - "version": "7.6.2", - "resolved": "https://registry.npmjs.org/@babel/generator/-/generator-7.6.2.tgz", - "integrity": "sha512-j8iHaIW4gGPnViaIHI7e9t/Hl8qLjERI6DcV9kEpAIDJsAOrcnXqRS7t+QbhL76pwbtqP+QCQLL0z1CyVmtjjQ==", - "dev": true, - "requires": { - "@babel/types": "^7.6.0", - "jsesc": "^2.5.1", - "lodash": "^4.17.13", - "source-map": "^0.5.0" - }, - "dependencies": { - "source-map": { - "version": "0.5.7", - "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.5.7.tgz", - "integrity": "sha1-igOdLRAh0i0eoUyA2OpGi6LvP8w=", - "dev": true - } - } - }, - "@babel/helper-function-name": { - "version": "7.1.0", - "resolved": "https://registry.npmjs.org/@babel/helper-function-name/-/helper-function-name-7.1.0.tgz", - "integrity": "sha512-A95XEoCpb3TO+KZzJ4S/5uW5fNe26DjBGqf1o9ucyLyCmi1dXq/B3c8iaWTfBk3VvetUxl16e8tIrd5teOCfGw==", - "dev": true, - "requires": { - "@babel/helper-get-function-arity": "^7.0.0", - "@babel/template": "^7.1.0", - "@babel/types": "^7.0.0" - } - }, - "@babel/helper-get-function-arity": { - "version": "7.0.0", - "resolved": "https://registry.npmjs.org/@babel/helper-get-function-arity/-/helper-get-function-arity-7.0.0.tgz", - "integrity": "sha512-r2DbJeg4svYvt3HOS74U4eWKsUAMRH01Z1ds1zx8KNTPtpTL5JAsdFv8BNyOpVqdFhHkkRDIg5B4AsxmkjAlmQ==", - "dev": true, - "requires": { - "@babel/types": "^7.0.0" - } - }, - "@babel/helper-plugin-utils": { - "version": "7.0.0", - "resolved": "https://registry.npmjs.org/@babel/helper-plugin-utils/-/helper-plugin-utils-7.0.0.tgz", - "integrity": "sha512-CYAOUCARwExnEixLdB6sDm2dIJ/YgEAKDM1MOeMeZu9Ld/bDgVo8aiWrXwcY7OBh+1Ea2uUcVRcxKk0GJvW7QA==", - "dev": true - }, - "@babel/helper-split-export-declaration": { - "version": "7.4.4", - "resolved": "https://registry.npmjs.org/@babel/helper-split-export-declaration/-/helper-split-export-declaration-7.4.4.tgz", - "integrity": "sha512-Ro/XkzLf3JFITkW6b+hNxzZ1n5OQ80NvIUdmHspih1XAhtN3vPTuUFT4eQnela+2MaZ5ulH+iyP513KJrxbN7Q==", - "dev": true, - "requires": { - "@babel/types": "^7.4.4" - } - }, - "@babel/helpers": { - "version": "7.6.2", - "resolved": "https://registry.npmjs.org/@babel/helpers/-/helpers-7.6.2.tgz", - "integrity": "sha512-3/bAUL8zZxYs1cdX2ilEE0WobqbCmKWr/889lf2SS0PpDcpEIY8pb1CCyz0pEcX3pEb+MCbks1jIokz2xLtGTA==", - "dev": true, - "requires": { - "@babel/template": "^7.6.0", - "@babel/traverse": "^7.6.2", - "@babel/types": "^7.6.0" - } - }, - "@babel/highlight": { - "version": "7.5.0", - "resolved": "https://registry.npmjs.org/@babel/highlight/-/highlight-7.5.0.tgz", - "integrity": "sha512-7dV4eu9gBxoM0dAnj/BCFDW9LFU0zvTrkq0ugM7pnHEgguOEeOz1so2ZghEdzviYzQEED0r4EAgpsBChKy1TRQ==", - "dev": true, - "requires": { - "chalk": "^2.0.0", - "esutils": "^2.0.2", - "js-tokens": "^4.0.0" - } - }, - "@babel/parser": { - "version": "7.6.2", - "resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.6.2.tgz", - "integrity": "sha512-mdFqWrSPCmikBoaBYMuBulzTIKuXVPtEISFbRRVNwMWpCms/hmE2kRq0bblUHaNRKrjRlmVbx1sDHmjmRgD2Xg==", - "dev": true - }, - "@babel/plugin-syntax-object-rest-spread": { - "version": "7.2.0", - "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-object-rest-spread/-/plugin-syntax-object-rest-spread-7.2.0.tgz", - "integrity": "sha512-t0JKGgqk2We+9may3t0xDdmneaXmyxq0xieYcKHxIsrJO64n1OiMWNUtc5gQK1PA0NpdCRrtZp4z+IUaKugrSA==", - "dev": true, - "requires": { - "@babel/helper-plugin-utils": "^7.0.0" - } - }, - "@babel/template": { - "version": "7.6.0", - "resolved": "https://registry.npmjs.org/@babel/template/-/template-7.6.0.tgz", - "integrity": "sha512-5AEH2EXD8euCk446b7edmgFdub/qfH1SN6Nii3+fyXP807QRx9Q73A2N5hNwRRslC2H9sNzaFhsPubkS4L8oNQ==", - "dev": true, - "requires": { - "@babel/code-frame": "^7.0.0", - "@babel/parser": "^7.6.0", - "@babel/types": "^7.6.0" - } - }, - "@babel/traverse": { - "version": "7.6.2", - "resolved": "https://registry.npmjs.org/@babel/traverse/-/traverse-7.6.2.tgz", - "integrity": "sha512-8fRE76xNwNttVEF2TwxJDGBLWthUkHWSldmfuBzVRmEDWOtu4XdINTgN7TDWzuLg4bbeIMLvfMFD9we5YcWkRQ==", - "dev": true, - "requires": { - "@babel/code-frame": "^7.5.5", - "@babel/generator": "^7.6.2", - "@babel/helper-function-name": "^7.1.0", - "@babel/helper-split-export-declaration": "^7.4.4", - "@babel/parser": "^7.6.2", - "@babel/types": "^7.6.0", - "debug": "^4.1.0", - "globals": "^11.1.0", - "lodash": "^4.17.13" - }, - "dependencies": { - "debug": { - "version": "4.1.1", - "resolved": "https://registry.npmjs.org/debug/-/debug-4.1.1.tgz", - "integrity": "sha512-pYAIzeRo8J6KPEaJ0VWOh5Pzkbw/RetuzehGM7QRRX5he4fPHx2rdKMB256ehJCkX+XRQm16eZLqLNS8RSZXZw==", - "dev": true, - "requires": { - "ms": "^2.1.1" - } - }, - "ms": { - "version": "2.1.2", - "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz", - "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==", - "dev": true - } - } - }, - "@babel/types": { - "version": "7.6.1", - "resolved": "https://registry.npmjs.org/@babel/types/-/types-7.6.1.tgz", - "integrity": "sha512-X7gdiuaCmA0uRjCmRtYJNAVCc/q+5xSgsfKJHqMN4iNLILX39677fJE1O40arPMh0TTtS9ItH67yre6c7k6t0g==", - "dev": true, - "requires": { - "esutils": "^2.0.2", - "lodash": "^4.17.13", - "to-fast-properties": "^2.0.0" - } - }, - "@cnakazawa/watch": { - "version": "1.0.3", - "resolved": "https://registry.npmjs.org/@cnakazawa/watch/-/watch-1.0.3.tgz", - "integrity": "sha512-r5160ogAvGyHsal38Kux7YYtodEKOj89RGb28ht1jh3SJb08VwRwAKKJL0bGb04Zd/3r9FL3BFIc3bBidYffCA==", - "dev": true, - "requires": { - "exec-sh": "^0.3.2", - "minimist": "^1.2.0" - } - }, - "@jest/console": { - "version": "24.9.0", - "resolved": "https://registry.npmjs.org/@jest/console/-/console-24.9.0.tgz", - "integrity": "sha512-Zuj6b8TnKXi3q4ymac8EQfc3ea/uhLeCGThFqXeC8H9/raaH8ARPUTdId+XyGd03Z4In0/VjD2OYFcBF09fNLQ==", - "dev": true, - "requires": { - "@jest/source-map": "^24.9.0", - "chalk": "^2.0.1", - "slash": "^2.0.0" - } - }, - "@jest/core": { - "version": "24.9.0", - "resolved": "https://registry.npmjs.org/@jest/core/-/core-24.9.0.tgz", - "integrity": "sha512-Fogg3s4wlAr1VX7q+rhV9RVnUv5tD7VuWfYy1+whMiWUrvl7U3QJSJyWcDio9Lq2prqYsZaeTv2Rz24pWGkJ2A==", - "dev": true, - "requires": { - "@jest/console": "^24.7.1", - "@jest/reporters": "^24.9.0", - "@jest/test-result": "^24.9.0", - "@jest/transform": "^24.9.0", - "@jest/types": "^24.9.0", - "ansi-escapes": "^3.0.0", - "chalk": "^2.0.1", - "exit": "^0.1.2", - "graceful-fs": "^4.1.15", - "jest-changed-files": "^24.9.0", - "jest-config": "^24.9.0", - "jest-haste-map": "^24.9.0", - "jest-message-util": "^24.9.0", - "jest-regex-util": "^24.3.0", - "jest-resolve": "^24.9.0", - "jest-resolve-dependencies": "^24.9.0", - "jest-runner": "^24.9.0", - "jest-runtime": "^24.9.0", - "jest-snapshot": "^24.9.0", - "jest-util": "^24.9.0", - "jest-validate": "^24.9.0", - "jest-watcher": "^24.9.0", - "micromatch": "^3.1.10", - "p-each-series": "^1.0.0", - "realpath-native": "^1.1.0", - "rimraf": "^2.5.4", - "slash": "^2.0.0", - "strip-ansi": "^5.0.0" - } - }, - "@jest/environment": { - "version": "24.9.0", - "resolved": "https://registry.npmjs.org/@jest/environment/-/environment-24.9.0.tgz", - "integrity": "sha512-5A1QluTPhvdIPFYnO3sZC3smkNeXPVELz7ikPbhUj0bQjB07EoE9qtLrem14ZUYWdVayYbsjVwIiL4WBIMV4aQ==", - "dev": true, - "requires": { - "@jest/fake-timers": "^24.9.0", - "@jest/transform": "^24.9.0", - "@jest/types": "^24.9.0", - "jest-mock": "^24.9.0" - } - }, - "@jest/fake-timers": { - "version": "24.9.0", - "resolved": "https://registry.npmjs.org/@jest/fake-timers/-/fake-timers-24.9.0.tgz", - "integrity": "sha512-eWQcNa2YSwzXWIMC5KufBh3oWRIijrQFROsIqt6v/NS9Io/gknw1jsAC9c+ih/RQX4A3O7SeWAhQeN0goKhT9A==", - "dev": true, - "requires": { - "@jest/types": "^24.9.0", - "jest-message-util": "^24.9.0", - "jest-mock": "^24.9.0" - } - }, - "@jest/reporters": { - "version": "24.9.0", - "resolved": "https://registry.npmjs.org/@jest/reporters/-/reporters-24.9.0.tgz", - "integrity": "sha512-mu4X0yjaHrffOsWmVLzitKmmmWSQ3GGuefgNscUSWNiUNcEOSEQk9k3pERKEQVBb0Cnn88+UESIsZEMH3o88Gw==", - "dev": true, - "requires": { - "@jest/environment": "^24.9.0", - "@jest/test-result": "^24.9.0", - "@jest/transform": "^24.9.0", - "@jest/types": "^24.9.0", - "chalk": "^2.0.1", - "exit": "^0.1.2", - "glob": "^7.1.2", - "istanbul-lib-coverage": "^2.0.2", - "istanbul-lib-instrument": "^3.0.1", - "istanbul-lib-report": "^2.0.4", - "istanbul-lib-source-maps": "^3.0.1", - "istanbul-reports": "^2.2.6", - "jest-haste-map": "^24.9.0", - "jest-resolve": "^24.9.0", - "jest-runtime": "^24.9.0", - "jest-util": "^24.9.0", - "jest-worker": "^24.6.0", - "node-notifier": "^5.4.2", - "slash": "^2.0.0", - "source-map": "^0.6.0", - "string-length": "^2.0.0" - } - }, - "@jest/source-map": { - "version": "24.9.0", - "resolved": "https://registry.npmjs.org/@jest/source-map/-/source-map-24.9.0.tgz", - "integrity": "sha512-/Xw7xGlsZb4MJzNDgB7PW5crou5JqWiBQaz6xyPd3ArOg2nfn/PunV8+olXbbEZzNl591o5rWKE9BRDaFAuIBg==", - "dev": true, - "requires": { - "callsites": "^3.0.0", - "graceful-fs": "^4.1.15", - "source-map": "^0.6.0" - } - }, - "@jest/test-result": { - "version": "24.9.0", - "resolved": "https://registry.npmjs.org/@jest/test-result/-/test-result-24.9.0.tgz", - "integrity": "sha512-XEFrHbBonBJ8dGp2JmF8kP/nQI/ImPpygKHwQ/SY+es59Z3L5PI4Qb9TQQMAEeYsThG1xF0k6tmG0tIKATNiiA==", - "dev": true, - "requires": { - "@jest/console": "^24.9.0", - "@jest/types": "^24.9.0", - "@types/istanbul-lib-coverage": "^2.0.0" - } - }, - "@jest/test-sequencer": { - "version": "24.9.0", - "resolved": "https://registry.npmjs.org/@jest/test-sequencer/-/test-sequencer-24.9.0.tgz", - "integrity": "sha512-6qqsU4o0kW1dvA95qfNog8v8gkRN9ph6Lz7r96IvZpHdNipP2cBcb07J1Z45mz/VIS01OHJ3pY8T5fUY38tg4A==", - "dev": true, - "requires": { - "@jest/test-result": "^24.9.0", - "jest-haste-map": "^24.9.0", - "jest-runner": "^24.9.0", - "jest-runtime": "^24.9.0" - } - }, - "@jest/transform": { - "version": "24.9.0", - "resolved": "https://registry.npmjs.org/@jest/transform/-/transform-24.9.0.tgz", - "integrity": "sha512-TcQUmyNRxV94S0QpMOnZl0++6RMiqpbH/ZMccFB/amku6Uwvyb1cjYX7xkp5nGNkbX4QPH/FcB6q1HBTHynLmQ==", - "dev": true, - "requires": { - "@babel/core": "^7.1.0", - "@jest/types": "^24.9.0", - "babel-plugin-istanbul": "^5.1.0", - "chalk": "^2.0.1", - "convert-source-map": "^1.4.0", - "fast-json-stable-stringify": "^2.0.0", - "graceful-fs": "^4.1.15", - "jest-haste-map": "^24.9.0", - "jest-regex-util": "^24.9.0", - "jest-util": "^24.9.0", - "micromatch": "^3.1.10", - "pirates": "^4.0.1", - "realpath-native": "^1.1.0", - "slash": "^2.0.0", - "source-map": "^0.6.1", - "write-file-atomic": "2.4.1" - } - }, - "@jest/types": { - "version": "24.9.0", - "resolved": "https://registry.npmjs.org/@jest/types/-/types-24.9.0.tgz", - "integrity": "sha512-XKK7ze1apu5JWQ5eZjHITP66AX+QsLlbaJRBGYr8pNzwcAE2JVkwnf0yqjHTsDRcjR0mujy/NmZMXw5kl+kGBw==", - "dev": true, - "requires": { - "@types/istanbul-lib-coverage": "^2.0.0", - "@types/istanbul-reports": "^1.1.1", - "@types/yargs": "^13.0.0" - } - }, - "@olavoparno/jest-badges-readme": { - "version": "1.4.0", - "resolved": "https://registry.npmjs.org/@olavoparno/jest-badges-readme/-/jest-badges-readme-1.4.0.tgz", - "integrity": "sha512-LC71BlkUmhSer0kkrFXBT791+iS5exUAFTrC1Q31ylrlEguMw+NdPffYUWbLqMP+DdS9fMf/IGeSGL4w+H6nhw==", - "dev": true - }, - "@types/babel__core": { - "version": "7.1.3", - "resolved": "https://registry.npmjs.org/@types/babel__core/-/babel__core-7.1.3.tgz", - "integrity": "sha512-8fBo0UR2CcwWxeX7WIIgJ7lXjasFxoYgRnFHUj+hRvKkpiBJbxhdAPTCY6/ZKM0uxANFVzt4yObSLuTiTnazDA==", - "dev": true, - "requires": { - "@babel/parser": "^7.1.0", - "@babel/types": "^7.0.0", - "@types/babel__generator": "*", - "@types/babel__template": "*", - "@types/babel__traverse": "*" - } - }, - "@types/babel__generator": { - "version": "7.6.0", - "resolved": "https://registry.npmjs.org/@types/babel__generator/-/babel__generator-7.6.0.tgz", - "integrity": "sha512-c1mZUu4up5cp9KROs/QAw0gTeHrw/x7m52LcnvMxxOZ03DmLwPV0MlGmlgzV3cnSdjhJOZsj7E7FHeioai+egw==", - "dev": true, - "requires": { - "@babel/types": "^7.0.0" - } - }, - "@types/babel__template": { - "version": "7.0.2", - "resolved": "https://registry.npmjs.org/@types/babel__template/-/babel__template-7.0.2.tgz", - "integrity": "sha512-/K6zCpeW7Imzgab2bLkLEbz0+1JlFSrUMdw7KoIIu+IUdu51GWaBZpd3y1VXGVXzynvGa4DaIaxNZHiON3GXUg==", - "dev": true, - "requires": { - "@babel/parser": "^7.1.0", - "@babel/types": "^7.0.0" - } - }, - "@types/babel__traverse": { - "version": "7.0.7", - "resolved": "https://registry.npmjs.org/@types/babel__traverse/-/babel__traverse-7.0.7.tgz", - "integrity": "sha512-CeBpmX1J8kWLcDEnI3Cl2Eo6RfbGvzUctA+CjZUhOKDFbLfcr7fc4usEqLNWetrlJd7RhAkyYe2czXop4fICpw==", - "dev": true, - "requires": { - "@babel/types": "^7.3.0" - } - }, - "@types/body-parser": { - "version": "1.17.1", - "resolved": "https://registry.npmjs.org/@types/body-parser/-/body-parser-1.17.1.tgz", - "integrity": "sha512-RoX2EZjMiFMjZh9lmYrwgoP9RTpAjSHiJxdp4oidAQVO02T7HER3xj9UKue5534ULWeqVEkujhWcyvUce+d68w==", - "dev": true, - "requires": { - "@types/connect": "*", - "@types/node": "*" - } - }, - "@types/connect": { - "version": "3.4.32", - "resolved": "https://registry.npmjs.org/@types/connect/-/connect-3.4.32.tgz", - "integrity": "sha512-4r8qa0quOvh7lGD0pre62CAb1oni1OO6ecJLGCezTmhQ8Fz50Arx9RUszryR8KlgK6avuSXvviL6yWyViQABOg==", - "dev": true, - "requires": { - "@types/node": "*" - } - }, - "@types/express": { - "version": "4.17.1", - "resolved": "https://registry.npmjs.org/@types/express/-/express-4.17.1.tgz", - "integrity": "sha512-VfH/XCP0QbQk5B5puLqTLEeFgR8lfCJHZJKkInZ9mkYd+u8byX0kztXEQxEk4wZXJs8HI+7km2ALXjn4YKcX9w==", - "dev": true, - "requires": { - "@types/body-parser": "*", - "@types/express-serve-static-core": "*", - "@types/serve-static": "*" - } - }, - "@types/express-serve-static-core": { - "version": "4.16.9", - "resolved": "https://registry.npmjs.org/@types/express-serve-static-core/-/express-serve-static-core-4.16.9.tgz", - "integrity": "sha512-GqpaVWR0DM8FnRUJYKlWgyARoBUAVfRIeVDZQKOttLFp5SmhhF9YFIYeTPwMd/AXfxlP7xVO2dj1fGu0Q+krKQ==", - "dev": true, - "requires": { - "@types/node": "*", - "@types/range-parser": "*" - } - }, - "@types/istanbul-lib-coverage": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/@types/istanbul-lib-coverage/-/istanbul-lib-coverage-2.0.1.tgz", - "integrity": "sha512-hRJD2ahnnpLgsj6KWMYSrmXkM3rm2Dl1qkx6IOFD5FnuNPXJIG5L0dhgKXCYTRMGzU4n0wImQ/xfmRc4POUFlg==", - "dev": true - }, - "@types/istanbul-lib-report": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/@types/istanbul-lib-report/-/istanbul-lib-report-1.1.1.tgz", - "integrity": "sha512-3BUTyMzbZa2DtDI2BkERNC6jJw2Mr2Y0oGI7mRxYNBPxppbtEK1F66u3bKwU2g+wxwWI7PAoRpJnOY1grJqzHg==", - "dev": true, - "requires": { - "@types/istanbul-lib-coverage": "*" - } - }, - "@types/istanbul-reports": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/@types/istanbul-reports/-/istanbul-reports-1.1.1.tgz", - "integrity": "sha512-UpYjBi8xefVChsCoBpKShdxTllC9pwISirfoZsUa2AAdQg/Jd2KQGtSbw+ya7GPo7x/wAPlH6JBhKhAsXUEZNA==", - "dev": true, - "requires": { - "@types/istanbul-lib-coverage": "*", - "@types/istanbul-lib-report": "*" - } - }, - "@types/jest": { - "version": "24.0.18", - "resolved": "https://registry.npmjs.org/@types/jest/-/jest-24.0.18.tgz", - "integrity": "sha512-jcDDXdjTcrQzdN06+TSVsPPqxvsZA/5QkYfIZlq1JMw7FdP5AZylbOc+6B/cuDurctRe+MziUMtQ3xQdrbjqyQ==", - "dev": true, - "requires": { - "@types/jest-diff": "*" - } - }, - "@types/jest-diff": { - "version": "20.0.1", - "resolved": "https://registry.npmjs.org/@types/jest-diff/-/jest-diff-20.0.1.tgz", - "integrity": "sha512-yALhelO3i0hqZwhjtcr6dYyaLoCHbAMshwtj6cGxTvHZAKXHsYGdff6E8EPw3xLKY0ELUTQ69Q1rQiJENnccMA==", - "dev": true - }, - "@types/mime": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/@types/mime/-/mime-2.0.1.tgz", - "integrity": "sha512-FwI9gX75FgVBJ7ywgnq/P7tw+/o1GUbtP0KzbtusLigAOgIgNISRK0ZPl4qertvXSIE8YbsVJueQ90cDt9YYyw==", - "dev": true - }, - "@types/multer": { - "version": "1.3.10", - "resolved": "https://registry.npmjs.org/@types/multer/-/multer-1.3.10.tgz", - "integrity": "sha512-3hECfz+W0ix/LvPanp87mjO3kOyDnJYTpY9y7gdBxXnYXqEcj21pD0lW7KEUFFr8CHrDF5Mhh7o241KLEXDRoQ==", - "dev": true, - "requires": { - "@types/express": "*" - } - }, - "@types/node": { - "version": "12.7.8", - "resolved": "https://registry.npmjs.org/@types/node/-/node-12.7.8.tgz", - "integrity": "sha512-FMdVn84tJJdV+xe+53sYiZS4R5yn1mAIxfj+DVoNiQjTYz1+OYmjwEZr1ev9nU0axXwda0QDbYl06QHanRVH3A==", - "dev": true - }, - "@types/normalize-package-data": { - "version": "2.4.0", - "resolved": "https://registry.npmjs.org/@types/normalize-package-data/-/normalize-package-data-2.4.0.tgz", - "integrity": "sha512-f5j5b/Gf71L+dbqxIpQ4Z2WlmI/mPJ0fOkGGmFgtb6sAu97EPczzbS3/tJKxmcYDj55OX6ssqwDAWOHIYDRDGA==", - "dev": true - }, - "@types/qs": { - "version": "6.5.3", - "resolved": "https://registry.npmjs.org/@types/qs/-/qs-6.5.3.tgz", - "integrity": "sha512-Jugo5V/1bS0fRhy2z8+cUAHEyWOATaz4rbyLVvcFs7+dXp5HfwpEwzF1Q11bB10ApUqHf+yTauxI0UXQDwGrbA==", - "dev": true - }, - "@types/range-parser": { - "version": "1.2.3", - "resolved": "https://registry.npmjs.org/@types/range-parser/-/range-parser-1.2.3.tgz", - "integrity": "sha512-ewFXqrQHlFsgc09MK5jP5iR7vumV/BYayNC6PgJO2LPe8vrnNFyjQjSppfEngITi0qvfKtzFvgKymGheFM9UOA==", - "dev": true - }, - "@types/serve-static": { - "version": "1.13.3", - "resolved": "https://registry.npmjs.org/@types/serve-static/-/serve-static-1.13.3.tgz", - "integrity": "sha512-oprSwp094zOglVrXdlo/4bAHtKTAxX6VT8FOZlBKrmyLbNvE1zxZyJ6yikMVtHIvwP45+ZQGJn+FdXGKTozq0g==", - "dev": true, - "requires": { - "@types/express-serve-static-core": "*", - "@types/mime": "*" - } - }, - "@types/stack-utils": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/@types/stack-utils/-/stack-utils-1.0.1.tgz", - "integrity": "sha512-l42BggppR6zLmpfU6fq9HEa2oGPEI8yrSPL3GITjfRInppYFahObbIQOQK3UGxEnyQpltZLaPe75046NOZQikw==", - "dev": true - }, - "@types/yargs": { - "version": "13.0.3", - "resolved": "https://registry.npmjs.org/@types/yargs/-/yargs-13.0.3.tgz", - "integrity": "sha512-K8/LfZq2duW33XW/tFwEAfnZlqIfVsoyRB3kfXdPXYhl0nfM8mmh7GS0jg7WrX2Dgq/0Ha/pR1PaR+BvmWwjiQ==", - "dev": true, - "requires": { - "@types/yargs-parser": "*" - } - }, - "@types/yargs-parser": { - "version": "13.1.0", - "resolved": "https://registry.npmjs.org/@types/yargs-parser/-/yargs-parser-13.1.0.tgz", - "integrity": "sha512-gCubfBUZ6KxzoibJ+SCUc/57Ms1jz5NjHe4+dI2krNmU5zCPAphyLJYyTOg06ueIyfj+SaCUqmzun7ImlxDcKg==", - "dev": true - }, - "abab": { - "version": "2.0.2", - "resolved": "https://registry.npmjs.org/abab/-/abab-2.0.2.tgz", - "integrity": "sha512-2scffjvioEmNz0OyDSLGWDfKCVwaKc6l9Pm9kOIREU13ClXZvHpg/nRL5xyjSSSLhOnXqft2HpsAzNEEA8cFFg==", - "dev": true - }, - "accepts": { - "version": "1.3.7", - "resolved": "https://registry.npmjs.org/accepts/-/accepts-1.3.7.tgz", - "integrity": "sha512-Il80Qs2WjYlJIBNzNkK6KYqlVMTbZLXgHx2oT0pU/fjRHyEp+PEfEPY0R3WCwAGVOtauxh1hOxNgIf5bv7dQpA==", - "dev": true, - "requires": { - "mime-types": "~2.1.24", - "negotiator": "0.6.2" - } - }, - "acorn": { - "version": "5.7.4", - "resolved": "https://registry.npmjs.org/acorn/-/acorn-5.7.4.tgz", - "integrity": "sha512-1D++VG7BhrtvQpNbBzovKNc1FLGGEE/oGe7b9xJm/RFHMBeUaUGpluV9RLjZa47YFdPcDAenEYuq9pQPcMdLJg==", - "dev": true - }, - "acorn-globals": { - "version": "4.3.4", - "resolved": "https://registry.npmjs.org/acorn-globals/-/acorn-globals-4.3.4.tgz", - "integrity": "sha512-clfQEh21R+D0leSbUdWf3OcfqyaCSAQ8Ryq00bofSekfr9W8u1jyYZo6ir0xu9Gtcf7BjcHJpnbZH7JOCpP60A==", - "dev": true, - "requires": { - "acorn": "^6.0.1", - "acorn-walk": "^6.0.1" - }, - "dependencies": { - "acorn": { - "version": "6.4.1", - "resolved": "https://registry.npmjs.org/acorn/-/acorn-6.4.1.tgz", - "integrity": "sha512-ZVA9k326Nwrj3Cj9jlh3wGFutC2ZornPNARZwsNYqQYgN0EsV2d53w5RN/co65Ohn4sUAUtb1rSUAOD6XN9idA==", - "dev": true - } - } - }, - "acorn-walk": { - "version": "6.2.0", - "resolved": "https://registry.npmjs.org/acorn-walk/-/acorn-walk-6.2.0.tgz", - "integrity": "sha512-7evsyfH1cLOCdAzZAd43Cic04yKydNx0cF+7tiA19p1XnLLPU4dpCQOqpjqwokFe//vS0QqfqqjCS2JkiIs0cA==", - "dev": true - }, - "ajv": { - "version": "6.10.2", - "resolved": "https://registry.npmjs.org/ajv/-/ajv-6.10.2.tgz", - "integrity": "sha512-TXtUUEYHuaTEbLZWIKUr5pmBuhDLy+8KYtPYdcV8qC+pOZL+NKqYwvWSRrVXHn+ZmRRAu8vJTAznH7Oag6RVRw==", - "dev": true, - "requires": { - "fast-deep-equal": "^2.0.1", - "fast-json-stable-stringify": "^2.0.0", - "json-schema-traverse": "^0.4.1", - "uri-js": "^4.2.2" - } - }, - "ansi-escapes": { - "version": "3.2.0", - "resolved": "https://registry.npmjs.org/ansi-escapes/-/ansi-escapes-3.2.0.tgz", - "integrity": "sha512-cBhpre4ma+U0T1oM5fXg7Dy1Jw7zzwv7lt/GoCpr+hDQJoYnKVPLL4dCvSEFMmQurOQvSrwT7SL/DAlhBI97RQ==", - "dev": true - }, - "ansi-regex": { - "version": "4.1.0", - "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-4.1.0.tgz", - "integrity": "sha512-1apePfXM1UOSqw0o9IiFAovVz9M5S1Dg+4TrDwfMewQ6p/rmMueb7tWZjQ1rx4Loy1ArBggoqGpfqqdI4rondg==", - "dev": true - }, - "ansi-styles": { - "version": "3.2.1", - "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-3.2.1.tgz", - "integrity": "sha512-VT0ZI6kZRdTh8YyJw3SMbYm/u+NqfsAxEpWO0Pf9sq8/e94WxxOpPKx9FR1FlyCtOVDNOQ+8ntlqFxiRc+r5qA==", - "dev": true, - "requires": { - "color-convert": "^1.9.0" - } - }, - "anymatch": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/anymatch/-/anymatch-2.0.0.tgz", - "integrity": "sha512-5teOsQWABXHHBFP9y3skS5P3d/WfWXpv3FUpy+LorMrNYaT9pI4oLMQX7jzQ2KklNpGpWHzdCXTDT2Y3XGlZBw==", - "dev": true, - "requires": { - "micromatch": "^3.1.4", - "normalize-path": "^2.1.1" - } - }, - "append-field": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/append-field/-/append-field-1.0.0.tgz", - "integrity": "sha1-HjRA6RXwsSA9I3SOeO3XubW0PlY=", - "dev": true - }, - "argparse": { - "version": "1.0.10", - "resolved": "https://registry.npmjs.org/argparse/-/argparse-1.0.10.tgz", - "integrity": "sha512-o5Roy6tNG4SL/FOkCAN6RzjiakZS25RLYFrcMttJqbdd8BWrnA+fGz57iN5Pb06pvBGvl5gQ0B48dJlslXvoTg==", - "dev": true, - "requires": { - "sprintf-js": "~1.0.2" - } - }, - "arr-diff": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/arr-diff/-/arr-diff-4.0.0.tgz", - "integrity": "sha1-1kYQdP6/7HHn4VI1dhoyml3HxSA=", - "dev": true - }, - "arr-flatten": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/arr-flatten/-/arr-flatten-1.1.0.tgz", - "integrity": "sha512-L3hKV5R/p5o81R7O02IGnwpDmkp6E982XhtbuwSe3O4qOtMMMtodicASA1Cny2U+aCXcNpml+m4dPsvsJ3jatg==", - "dev": true - }, - "arr-union": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/arr-union/-/arr-union-3.1.0.tgz", - "integrity": "sha1-45sJrqne+Gao8gbiiK9jkZuuOcQ=", - "dev": true - }, - "array-equal": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/array-equal/-/array-equal-1.0.0.tgz", - "integrity": "sha1-jCpe8kcv2ep0KwTHenUJO6J1fJM=", - "dev": true - }, - "array-flatten": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/array-flatten/-/array-flatten-1.1.1.tgz", - "integrity": "sha1-ml9pkFGx5wczKPKgCJaLZOopVdI=", - "dev": true - }, - "array-unique": { - "version": "0.3.2", - "resolved": "https://registry.npmjs.org/array-unique/-/array-unique-0.3.2.tgz", - "integrity": "sha1-qJS3XUvE9s1nnvMkSp/Y9Gri1Cg=", - "dev": true - }, - "asn1": { - "version": "0.2.4", - "resolved": "https://registry.npmjs.org/asn1/-/asn1-0.2.4.tgz", - "integrity": "sha512-jxwzQpLQjSmWXgwaCZE9Nz+glAG01yF1QnWgbhGwHI5A6FRIEY6IVqtHhIepHqI7/kyEyQEagBC5mBEFlIYvdg==", - "dev": true, - "requires": { - "safer-buffer": "~2.1.0" - } - }, - "assert-plus": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/assert-plus/-/assert-plus-1.0.0.tgz", - "integrity": "sha1-8S4PPF13sLHN2RRpQuTpbB5N1SU=", - "dev": true - }, - "assign-symbols": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/assign-symbols/-/assign-symbols-1.0.0.tgz", - "integrity": "sha1-WWZ/QfrdTyDMvCu5a41Pf3jsA2c=", - "dev": true - }, - "astral-regex": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/astral-regex/-/astral-regex-1.0.0.tgz", - "integrity": "sha512-+Ryf6g3BKoRc7jfp7ad8tM4TtMiaWvbF/1/sQcZPkkS7ag3D5nMBCe2UfOTONtAkaG0tO0ij3C5Lwmf1EiyjHg==", - "dev": true - }, - "async-limiter": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/async-limiter/-/async-limiter-1.0.1.tgz", - "integrity": "sha512-csOlWGAcRFJaI6m+F2WKdnMKr4HhdhFVBk0H/QbJFMCr+uO2kwohwXQPxw/9OCxp05r5ghVBFSyioixx3gfkNQ==", - "dev": true - }, - "asynckit": { - "version": "0.4.0", - "resolved": "https://registry.npmjs.org/asynckit/-/asynckit-0.4.0.tgz", - "integrity": "sha1-x57Zf380y48robyXkLzDZkdLS3k=" - }, - "atob": { - "version": "2.1.2", - "resolved": "https://registry.npmjs.org/atob/-/atob-2.1.2.tgz", - "integrity": "sha512-Wm6ukoaOGJi/73p/cl2GvLjTI5JM1k/O14isD73YML8StrH/7/lRFgmg8nICZgD3bZZvjwCGxtMOD3wWNAu8cg==", - "dev": true - }, - "aws-sign2": { - "version": "0.7.0", - "resolved": "https://registry.npmjs.org/aws-sign2/-/aws-sign2-0.7.0.tgz", - "integrity": "sha1-tG6JCTSpWR8tL2+G1+ap8bP+dqg=", - "dev": true - }, - "aws4": { - "version": "1.8.0", - "resolved": "https://registry.npmjs.org/aws4/-/aws4-1.8.0.tgz", - "integrity": "sha512-ReZxvNHIOv88FlT7rxcXIIC0fPt4KZqZbOlivyWtXLt8ESx84zd3kMC6iK5jVeS2qt+g7ftS7ye4fi06X5rtRQ==", - "dev": true - }, - "axios": { - "version": "0.19.0", - "resolved": "https://registry.npmjs.org/axios/-/axios-0.19.0.tgz", - "integrity": "sha512-1uvKqKQta3KBxIz14F2v06AEHZ/dIoeKfbTRkK1E5oqjDnuEerLmYTgJB5AiQZHJcljpg1TuRzdjDR06qNk0DQ==", - "requires": { - "follow-redirects": "1.5.10", - "is-buffer": "^2.0.2" - } - }, - "babel-jest": { - "version": "24.9.0", - "resolved": "https://registry.npmjs.org/babel-jest/-/babel-jest-24.9.0.tgz", - "integrity": "sha512-ntuddfyiN+EhMw58PTNL1ph4C9rECiQXjI4nMMBKBaNjXvqLdkXpPRcMSr4iyBrJg/+wz9brFUD6RhOAT6r4Iw==", - "dev": true, - "requires": { - "@jest/transform": "^24.9.0", - "@jest/types": "^24.9.0", - "@types/babel__core": "^7.1.0", - "babel-plugin-istanbul": "^5.1.0", - "babel-preset-jest": "^24.9.0", - "chalk": "^2.4.2", - "slash": "^2.0.0" - } - }, - "babel-plugin-istanbul": { - "version": "5.2.0", - "resolved": "https://registry.npmjs.org/babel-plugin-istanbul/-/babel-plugin-istanbul-5.2.0.tgz", - "integrity": "sha512-5LphC0USA8t4i1zCtjbbNb6jJj/9+X6P37Qfirc/70EQ34xKlMW+a1RHGwxGI+SwWpNwZ27HqvzAobeqaXwiZw==", - "dev": true, - "requires": { - "@babel/helper-plugin-utils": "^7.0.0", - "find-up": "^3.0.0", - "istanbul-lib-instrument": "^3.3.0", - "test-exclude": "^5.2.3" - } - }, - "babel-plugin-jest-hoist": { - "version": "24.9.0", - "resolved": "https://registry.npmjs.org/babel-plugin-jest-hoist/-/babel-plugin-jest-hoist-24.9.0.tgz", - "integrity": "sha512-2EMA2P8Vp7lG0RAzr4HXqtYwacfMErOuv1U3wrvxHX6rD1sV6xS3WXG3r8TRQ2r6w8OhvSdWt+z41hQNwNm3Xw==", - "dev": true, - "requires": { - "@types/babel__traverse": "^7.0.6" - } - }, - "babel-preset-jest": { - "version": "24.9.0", - "resolved": "https://registry.npmjs.org/babel-preset-jest/-/babel-preset-jest-24.9.0.tgz", - "integrity": "sha512-izTUuhE4TMfTRPF92fFwD2QfdXaZW08qvWTFCI51V8rW5x00UuPgc3ajRoWofXOuxjfcOM5zzSYsQS3H8KGCAg==", - "dev": true, - "requires": { - "@babel/plugin-syntax-object-rest-spread": "^7.0.0", - "babel-plugin-jest-hoist": "^24.9.0" - } - }, - "balanced-match": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.0.tgz", - "integrity": "sha1-ibTRmasr7kneFk6gK4nORi1xt2c=", - "dev": true - }, - "base": { - "version": "0.11.2", - "resolved": "https://registry.npmjs.org/base/-/base-0.11.2.tgz", - "integrity": "sha512-5T6P4xPgpp0YDFvSWwEZ4NoE3aM4QBQXDzmVbraCkFj8zHM+mba8SyqB5DbZWyR7mYHo6Y7BdQo3MoA4m0TeQg==", - "dev": true, - "requires": { - "cache-base": "^1.0.1", - "class-utils": "^0.3.5", - "component-emitter": "^1.2.1", - "define-property": "^1.0.0", - "isobject": "^3.0.1", - "mixin-deep": "^1.2.0", - "pascalcase": "^0.1.1" - }, - "dependencies": { - "define-property": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/define-property/-/define-property-1.0.0.tgz", - "integrity": "sha1-dp66rz9KY6rTr56NMEybvnm/sOY=", - "dev": true, - "requires": { - "is-descriptor": "^1.0.0" - } - }, - "is-accessor-descriptor": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/is-accessor-descriptor/-/is-accessor-descriptor-1.0.0.tgz", - "integrity": "sha512-m5hnHTkcVsPfqx3AKlyttIPb7J+XykHvJP2B9bZDjlhLIoEq4XoK64Vg7boZlVWYK6LUY94dYPEE7Lh0ZkZKcQ==", - "dev": true, - "requires": { - "kind-of": "^6.0.0" - } - }, - "is-data-descriptor": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/is-data-descriptor/-/is-data-descriptor-1.0.0.tgz", - "integrity": "sha512-jbRXy1FmtAoCjQkVmIVYwuuqDFUbaOeDjmed1tOGPrsMhtJA4rD9tkgA0F1qJ3gRFRXcHYVkdeaP50Q5rE/jLQ==", - "dev": true, - "requires": { - "kind-of": "^6.0.0" - } - }, - "is-descriptor": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/is-descriptor/-/is-descriptor-1.0.2.tgz", - "integrity": "sha512-2eis5WqQGV7peooDyLmNEPUrps9+SXX5c9pL3xEB+4e9HnGuDa7mB7kHxHw4CbqS9k1T2hOH3miL8n8WtiYVtg==", - "dev": true, - "requires": { - "is-accessor-descriptor": "^1.0.0", - "is-data-descriptor": "^1.0.0", - "kind-of": "^6.0.2" - } - } - } - }, - "bcrypt-pbkdf": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/bcrypt-pbkdf/-/bcrypt-pbkdf-1.0.2.tgz", - "integrity": "sha1-pDAdOJtqQ/m2f/PKEaP2Y342Dp4=", - "dev": true, - "requires": { - "tweetnacl": "^0.14.3" - } - }, - "body-parser": { - "version": "1.19.0", - "resolved": "https://registry.npmjs.org/body-parser/-/body-parser-1.19.0.tgz", - "integrity": "sha512-dhEPs72UPbDnAQJ9ZKMNTP6ptJaionhP5cBb541nXPlW60Jepo9RV/a4fX4XWW9CuFNK22krhrj1+rgzifNCsw==", - "dev": true, - "requires": { - "bytes": "3.1.0", - "content-type": "~1.0.4", - "debug": "2.6.9", - "depd": "~1.1.2", - "http-errors": "1.7.2", - "iconv-lite": "0.4.24", - "on-finished": "~2.3.0", - "qs": "6.7.0", - "raw-body": "2.4.0", - "type-is": "~1.6.17" - }, - "dependencies": { - "debug": { - "version": "2.6.9", - "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", - "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==", - "dev": true, - "requires": { - "ms": "2.0.0" - } - }, - "qs": { - "version": "6.7.0", - "resolved": "https://registry.npmjs.org/qs/-/qs-6.7.0.tgz", - "integrity": "sha512-VCdBRNFTX1fyE7Nb6FYoURo/SPe62QCaAyzJvUjwRaIsc+NePBEniHlvxFmmX56+HZphIGtV0XeCirBtpDrTyQ==", - "dev": true - } - } - }, - "brace-expansion": { - "version": "1.1.11", - "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz", - "integrity": "sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==", - "dev": true, - "requires": { - "balanced-match": "^1.0.0", - "concat-map": "0.0.1" - } - }, - "braces": { - "version": "2.3.2", - "resolved": "https://registry.npmjs.org/braces/-/braces-2.3.2.tgz", - "integrity": "sha512-aNdbnj9P8PjdXU4ybaWLK2IF3jc/EoDYbC7AazW6to3TRsfXxscC9UXOB5iDiEQrkyIbWp2SLQda4+QAa7nc3w==", - "dev": true, - "requires": { - "arr-flatten": "^1.1.0", - "array-unique": "^0.3.2", - "extend-shallow": "^2.0.1", - "fill-range": "^4.0.0", - "isobject": "^3.0.1", - "repeat-element": "^1.1.2", - "snapdragon": "^0.8.1", - "snapdragon-node": "^2.0.1", - "split-string": "^3.0.2", - "to-regex": "^3.0.1" - }, - "dependencies": { - "extend-shallow": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/extend-shallow/-/extend-shallow-2.0.1.tgz", - "integrity": "sha1-Ua99YUrZqfYQ6huvu5idaxxWiQ8=", - "dev": true, - "requires": { - "is-extendable": "^0.1.0" - } - } - } - }, - "browser-process-hrtime": { - "version": "0.1.3", - "resolved": "https://registry.npmjs.org/browser-process-hrtime/-/browser-process-hrtime-0.1.3.tgz", - "integrity": "sha512-bRFnI4NnjO6cnyLmOV/7PVoDEMJChlcfN0z4s1YMBY989/SvlfMI1lgCnkFUs53e9gQF+w7qu7XdllSTiSl8Aw==", - "dev": true - }, - "browser-resolve": { - "version": "1.11.3", - "resolved": "https://registry.npmjs.org/browser-resolve/-/browser-resolve-1.11.3.tgz", - "integrity": "sha512-exDi1BYWB/6raKHmDTCicQfTkqwN5fioMFV4j8BsfMU4R2DK/QfZfK7kOVkmWCNANf0snkBzqGqAJBao9gZMdQ==", - "dev": true, - "requires": { - "resolve": "1.1.7" - }, - "dependencies": { - "resolve": { - "version": "1.1.7", - "resolved": "https://registry.npmjs.org/resolve/-/resolve-1.1.7.tgz", - "integrity": "sha1-IDEU2CrSxe2ejgQRs5ModeiJ6Xs=", - "dev": true - } - } - }, - "bs-logger": { - "version": "0.2.6", - "resolved": "https://registry.npmjs.org/bs-logger/-/bs-logger-0.2.6.tgz", - "integrity": "sha512-pd8DCoxmbgc7hyPKOvxtqNcjYoOsABPQdcCUjGp3d42VR2CX1ORhk2A87oqqu5R1kk+76nsxZupkmyd+MVtCog==", - "dev": true, - "requires": { - "fast-json-stable-stringify": "2.x" - } - }, - "bser": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/bser/-/bser-2.1.0.tgz", - "integrity": "sha512-8zsjWrQkkBoLK6uxASk1nJ2SKv97ltiGDo6A3wA0/yRPz+CwmEyDo0hUrhIuukG2JHpAl3bvFIixw2/3Hi0DOg==", - "dev": true, - "requires": { - "node-int64": "^0.4.0" - } - }, - "buffer-from": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/buffer-from/-/buffer-from-1.1.1.tgz", - "integrity": "sha512-MQcXEUbCKtEo7bhqEs6560Hyd4XaovZlO/k9V3hjVUF/zwW7KBVdSK4gIt/bzwS9MbR5qob+F5jusZsb0YQK2A==", - "dev": true - }, - "builtin-modules": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/builtin-modules/-/builtin-modules-1.1.1.tgz", - "integrity": "sha1-Jw8HbFpywC9bZaR9+Uxf46J4iS8=", - "dev": true - }, - "busboy": { - "version": "0.2.14", - "resolved": "https://registry.npmjs.org/busboy/-/busboy-0.2.14.tgz", - "integrity": "sha1-bCpiLvz0fFe7vh4qnDetNseSVFM=", - "dev": true, - "requires": { - "dicer": "0.2.5", - "readable-stream": "1.1.x" - } - }, - "bytes": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/bytes/-/bytes-3.1.0.tgz", - "integrity": "sha512-zauLjrfCG+xvoyaqLoV8bLVXXNGC4JqlxFCutSDWA6fJrTo2ZuvLYTqZ7aHBLZSMOopbzwv8f+wZcVzfVTI2Dg==", - "dev": true - }, - "cache-base": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/cache-base/-/cache-base-1.0.1.tgz", - "integrity": "sha512-AKcdTnFSWATd5/GCPRxr2ChwIJ85CeyrEyjRHlKxQ56d4XJMGym0uAiKn0xbLOGOl3+yRpOTi484dVCEc5AUzQ==", - "dev": true, - "requires": { - "collection-visit": "^1.0.0", - "component-emitter": "^1.2.1", - "get-value": "^2.0.6", - "has-value": "^1.0.0", - "isobject": "^3.0.1", - "set-value": "^2.0.0", - "to-object-path": "^0.3.0", - "union-value": "^1.0.0", - "unset-value": "^1.0.0" - } - }, - "caller-callsite": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/caller-callsite/-/caller-callsite-2.0.0.tgz", - "integrity": "sha1-hH4PzgoiN1CpoCfFSzNzGtMVQTQ=", - "dev": true, - "requires": { - "callsites": "^2.0.0" - }, - "dependencies": { - "callsites": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/callsites/-/callsites-2.0.0.tgz", - "integrity": "sha1-BuuE8A7qQT2oav/vrL/7Ngk7PFA=", - "dev": true - } - } - }, - "caller-path": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/caller-path/-/caller-path-2.0.0.tgz", - "integrity": "sha1-Ro+DBE42mrIBD6xfBs7uFbsssfQ=", - "dev": true, - "requires": { - "caller-callsite": "^2.0.0" - } - }, - "callsites": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/callsites/-/callsites-3.1.0.tgz", - "integrity": "sha512-P8BjAsXvZS+VIDUI11hHCQEv74YT67YUi5JJFNWIqL235sBmjX4+qx9Muvls5ivyNENctx46xQLQ3aTuE7ssaQ==", - "dev": true - }, - "camelcase": { - "version": "5.3.1", - "resolved": "https://registry.npmjs.org/camelcase/-/camelcase-5.3.1.tgz", - "integrity": "sha512-L28STB170nwWS63UjtlEOE3dldQApaJXZkOI1uMFfzf3rRuPegHaHesyee+YxQ+W6SvRDQV6UrdOdRiR153wJg==", - "dev": true - }, - "capture-exit": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/capture-exit/-/capture-exit-2.0.0.tgz", - "integrity": "sha512-PiT/hQmTonHhl/HFGN+Lx3JJUznrVYJ3+AQsnthneZbvW7x+f08Tk7yLJTLEOUvBTbduLeeBkxEaYXUOUrRq6g==", - "dev": true, - "requires": { - "rsvp": "^4.8.4" - } - }, - "caseless": { - "version": "0.12.0", - "resolved": "https://registry.npmjs.org/caseless/-/caseless-0.12.0.tgz", - "integrity": "sha1-G2gcIf+EAzyCZUMJBolCDRhxUdw=", - "dev": true - }, - "chalk": { - "version": "2.4.2", - "resolved": "https://registry.npmjs.org/chalk/-/chalk-2.4.2.tgz", - "integrity": "sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ==", - "dev": true, - "requires": { - "ansi-styles": "^3.2.1", - "escape-string-regexp": "^1.0.5", - "supports-color": "^5.3.0" - } - }, - "ci-info": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/ci-info/-/ci-info-2.0.0.tgz", - "integrity": "sha512-5tK7EtrZ0N+OLFMthtqOj4fI2Jeb88C4CAZPu25LDVUgXJ0A3Js4PMGqrn0JU1W0Mh1/Z8wZzYPxqUrXeBboCQ==", - "dev": true - }, - "class-utils": { - "version": "0.3.6", - "resolved": "https://registry.npmjs.org/class-utils/-/class-utils-0.3.6.tgz", - "integrity": "sha512-qOhPa/Fj7s6TY8H8esGu5QNpMMQxz79h+urzrNYN6mn+9BnxlDGf5QZ+XeCDsxSjPqsSR56XOZOJmpeurnLMeg==", - "dev": true, - "requires": { - "arr-union": "^3.1.0", - "define-property": "^0.2.5", - "isobject": "^3.0.0", - "static-extend": "^0.1.1" - }, - "dependencies": { - "define-property": { - "version": "0.2.5", - "resolved": "https://registry.npmjs.org/define-property/-/define-property-0.2.5.tgz", - "integrity": "sha1-w1se+RjsPJkPmlvFe+BKrOxcgRY=", - "dev": true, - "requires": { - "is-descriptor": "^0.1.0" - } - } - } - }, - "cliui": { - "version": "5.0.0", - "resolved": "https://registry.npmjs.org/cliui/-/cliui-5.0.0.tgz", - "integrity": "sha512-PYeGSEmmHM6zvoef2w8TPzlrnNpXIjTipYK780YswmIP9vjxmd6Y2a3CB2Ks6/AU8NHjZugXvo8w3oWM2qnwXA==", - "dev": true, - "requires": { - "string-width": "^3.1.0", - "strip-ansi": "^5.2.0", - "wrap-ansi": "^5.1.0" - } - }, - "co": { - "version": "4.6.0", - "resolved": "https://registry.npmjs.org/co/-/co-4.6.0.tgz", - "integrity": "sha1-bqa989hTrlTMuOR7+gvz+QMfsYQ=", - "dev": true - }, - "collection-visit": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/collection-visit/-/collection-visit-1.0.0.tgz", - "integrity": "sha1-S8A3PBZLwykbTTaMgpzxqApZ3KA=", - "dev": true, - "requires": { - "map-visit": "^1.0.0", - "object-visit": "^1.0.0" - } - }, - "color-convert": { - "version": "1.9.3", - "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-1.9.3.tgz", - "integrity": "sha512-QfAUtd+vFdAtFQcC8CCyYt1fYWxSqAiK2cSD6zDB8N3cpsEBAvRxp9zOGg6G/SHHJYAT88/az/IuDGALsNVbGg==", - "dev": true, - "requires": { - "color-name": "1.1.3" - } - }, - "color-name": { - "version": "1.1.3", - "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.3.tgz", - "integrity": "sha1-p9BVi9icQveV3UIyj3QIMcpTvCU=", - "dev": true - }, - "combined-stream": { - "version": "1.0.8", - "resolved": "https://registry.npmjs.org/combined-stream/-/combined-stream-1.0.8.tgz", - "integrity": "sha512-FQN4MRfuJeHf7cBbBMJFXhKSDq+2kAArBlmRBvcvFE5BB1HZKXtSFASDhdlz9zOYwxh8lDdnvmMOe/+5cdoEdg==", - "requires": { - "delayed-stream": "~1.0.0" - } - }, - "commander": { - "version": "2.20.0", - "resolved": "https://registry.npmjs.org/commander/-/commander-2.20.0.tgz", - "integrity": "sha512-7j2y+40w61zy6YC2iRNpUe/NwhNyoXrYpHMrSunaMG64nRnaf96zO/KMQR4OyN/UnE5KLyEBnKHd4aG3rskjpQ==", - "dev": true - }, - "component-emitter": { - "version": "1.3.0", - "resolved": "https://registry.npmjs.org/component-emitter/-/component-emitter-1.3.0.tgz", - "integrity": "sha512-Rd3se6QB+sO1TwqZjscQrurpEPIfO0/yYnSin6Q/rD3mOutHvUrCAhJub3r90uNb+SESBuE0QYoB90YdfatsRg==", - "dev": true - }, - "concat-map": { - "version": "0.0.1", - "resolved": "https://registry.npmjs.org/concat-map/-/concat-map-0.0.1.tgz", - "integrity": "sha1-2Klr13/Wjfd5OnMDajug1UBdR3s=", - "dev": true - }, - "concat-stream": { - "version": "1.6.2", - "resolved": "https://registry.npmjs.org/concat-stream/-/concat-stream-1.6.2.tgz", - "integrity": "sha512-27HBghJxjiZtIk3Ycvn/4kbJk/1uZuJFfuPEns6LaEvpvG1f0hTea8lilrouyo9mVc2GWdcEZ8OLoGmSADlrCw==", - "dev": true, - "requires": { - "buffer-from": "^1.0.0", - "inherits": "^2.0.3", - "readable-stream": "^2.2.2", - "typedarray": "^0.0.6" - }, - "dependencies": { - "readable-stream": { - "version": "2.3.6", - "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-2.3.6.tgz", - "integrity": "sha512-tQtKA9WIAhBF3+VLAseyMqZeBjW0AHJoxOtYqSUZNJxauErmLbVm2FW1y+J/YA9dUrAC39ITejlZWhVIwawkKw==", - "dev": true, - "requires": { - "core-util-is": "~1.0.0", - "inherits": "~2.0.3", - "isarray": "~1.0.0", - "process-nextick-args": "~2.0.0", - "safe-buffer": "~5.1.1", - "string_decoder": "~1.1.1", - "util-deprecate": "~1.0.1" - } - }, - "string_decoder": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.1.1.tgz", - "integrity": "sha512-n/ShnvDi6FHbbVfviro+WojiFzv+s8MPMHBczVePfUpDJLwoLT0ht1l4YwBCbi8pJAveEEdnkHyPyTP/mzRfwg==", - "dev": true, - "requires": { - "safe-buffer": "~5.1.0" - } - } - } - }, - "content-disposition": { - "version": "0.5.3", - "resolved": "https://registry.npmjs.org/content-disposition/-/content-disposition-0.5.3.tgz", - "integrity": "sha512-ExO0774ikEObIAEV9kDo50o+79VCUdEB6n6lzKgGwupcVeRlhrj3qGAfwq8G6uBJjkqLrhT0qEYFcWng8z1z0g==", - "dev": true, - "requires": { - "safe-buffer": "5.1.2" - } - }, - "content-type": { - "version": "1.0.4", - "resolved": "https://registry.npmjs.org/content-type/-/content-type-1.0.4.tgz", - "integrity": "sha512-hIP3EEPs8tB9AT1L+NUqtwOAps4mk2Zob89MWXMHjHWg9milF/j4osnnQLXBCBFBk/tvIG/tUc9mOUJiPBhPXA==", - "dev": true - }, - "convert-source-map": { - "version": "1.6.0", - "resolved": "https://registry.npmjs.org/convert-source-map/-/convert-source-map-1.6.0.tgz", - "integrity": "sha512-eFu7XigvxdZ1ETfbgPBohgyQ/Z++C0eEhTor0qRwBw9unw+L0/6V8wkSuGgzdThkiS5lSpdptOQPD8Ak40a+7A==", - "dev": true, - "requires": { - "safe-buffer": "~5.1.1" - } - }, - "cookie": { - "version": "0.4.0", - "resolved": "https://registry.npmjs.org/cookie/-/cookie-0.4.0.tgz", - "integrity": "sha512-+Hp8fLp57wnUSt0tY0tHEXh4voZRDnoIrZPqlo3DPiI4y9lwg/jqx+1Om94/W6ZaPDOUbnjOt/99w66zk+l1Xg==", - "dev": true - }, - "cookie-signature": { - "version": "1.0.6", - "resolved": "https://registry.npmjs.org/cookie-signature/-/cookie-signature-1.0.6.tgz", - "integrity": "sha1-4wOogrNCzD7oylE6eZmXNNqzriw=", - "dev": true - }, - "copy-descriptor": { - "version": "0.1.1", - "resolved": "https://registry.npmjs.org/copy-descriptor/-/copy-descriptor-0.1.1.tgz", - "integrity": "sha1-Z29us8OZl8LuGsOpJP1hJHSPV40=", - "dev": true - }, - "core-util-is": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/core-util-is/-/core-util-is-1.0.2.tgz", - "integrity": "sha1-tf1UIgqivFq1eqtxQMlAdUUDwac=", - "dev": true - }, - "cosmiconfig": { - "version": "5.2.1", - "resolved": "https://registry.npmjs.org/cosmiconfig/-/cosmiconfig-5.2.1.tgz", - "integrity": "sha512-H65gsXo1SKjf8zmrJ67eJk8aIRKV5ff2D4uKZIBZShbhGSpEmsQOPW/SKMKYhSTrqR7ufy6RP69rPogdaPh/kA==", - "dev": true, - "requires": { - "import-fresh": "^2.0.0", - "is-directory": "^0.3.1", - "js-yaml": "^3.13.1", - "parse-json": "^4.0.0" - } - }, - "cross-spawn": { - "version": "6.0.5", - "resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-6.0.5.tgz", - "integrity": "sha512-eTVLrBSt7fjbDygz805pMnstIs2VTBNkRm0qxZd+M7A5XDdxVRWO5MxGBXZhjY4cqLYLdtrGqRf8mBPmzwSpWQ==", - "dev": true, - "requires": { - "nice-try": "^1.0.4", - "path-key": "^2.0.1", - "semver": "^5.5.0", - "shebang-command": "^1.2.0", - "which": "^1.2.9" - } - }, - "cssom": { - "version": "0.3.8", - "resolved": "https://registry.npmjs.org/cssom/-/cssom-0.3.8.tgz", - "integrity": "sha512-b0tGHbfegbhPJpxpiBPU2sCkigAqtM9O121le6bbOlgyV+NyGyCmVfJ6QW9eRjz8CpNfWEOYBIMIGRYkLwsIYg==", - "dev": true - }, - "cssstyle": { - "version": "1.4.0", - "resolved": "https://registry.npmjs.org/cssstyle/-/cssstyle-1.4.0.tgz", - "integrity": "sha512-GBrLZYZ4X4x6/QEoBnIrqb8B/f5l4+8me2dkom/j1Gtbxy0kBv6OGzKuAsGM75bkGwGAFkt56Iwg28S3XTZgSA==", - "dev": true, - "requires": { - "cssom": "0.3.x" - } - }, - "dashdash": { - "version": "1.14.1", - "resolved": "https://registry.npmjs.org/dashdash/-/dashdash-1.14.1.tgz", - "integrity": "sha1-hTz6D3y+L+1d4gMmuN1YEDX24vA=", - "dev": true, - "requires": { - "assert-plus": "^1.0.0" - } - }, - "data-urls": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/data-urls/-/data-urls-1.1.0.tgz", - "integrity": "sha512-YTWYI9se1P55u58gL5GkQHW4P6VJBJ5iBT+B5a7i2Tjadhv52paJG0qHX4A0OR6/t52odI64KP2YvFpkDOi3eQ==", - "dev": true, - "requires": { - "abab": "^2.0.0", - "whatwg-mimetype": "^2.2.0", - "whatwg-url": "^7.0.0" - }, - "dependencies": { - "whatwg-url": { - "version": "7.0.0", - "resolved": "https://registry.npmjs.org/whatwg-url/-/whatwg-url-7.0.0.tgz", - "integrity": "sha512-37GeVSIJ3kn1JgKyjiYNmSLP1yzbpb29jdmwBSgkD9h40/hyrR/OifpVUndji3tmwGgD8qpw7iQu3RSbCrBpsQ==", - "dev": true, - "requires": { - "lodash.sortby": "^4.7.0", - "tr46": "^1.0.1", - "webidl-conversions": "^4.0.2" - } - } - } - }, - "debug": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/debug/-/debug-3.1.0.tgz", - "integrity": "sha512-OX8XqP7/1a9cqkxYw2yXss15f26NKWBpDXQd0/uK/KPqdQhxbPa994hnzjcE2VqQpDslf55723cKPUOGSmMY3g==", - "requires": { - "ms": "2.0.0" - } - }, - "decamelize": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/decamelize/-/decamelize-1.2.0.tgz", - "integrity": "sha1-9lNNFRSCabIDUue+4m9QH5oZEpA=", - "dev": true - }, - "decode-uri-component": { - "version": "0.2.0", - "resolved": "https://registry.npmjs.org/decode-uri-component/-/decode-uri-component-0.2.0.tgz", - "integrity": "sha1-6zkTMzRYd1y4TNGh+uBiEGu4dUU=", - "dev": true - }, - "deep-is": { - "version": "0.1.3", - "resolved": "https://registry.npmjs.org/deep-is/-/deep-is-0.1.3.tgz", - "integrity": "sha1-s2nW+128E+7PUk+RsHD+7cNXzzQ=", - "dev": true - }, - "define-properties": { - "version": "1.1.3", - "resolved": "https://registry.npmjs.org/define-properties/-/define-properties-1.1.3.tgz", - "integrity": "sha512-3MqfYKj2lLzdMSf8ZIZE/V+Zuy+BgD6f164e8K2w7dgnpKArBDerGYpM46IYYcjnkdPNMjPk9A6VFB8+3SKlXQ==", - "dev": true, - "requires": { - "object-keys": "^1.0.12" - } - }, - "define-property": { - "version": "2.0.2", - "resolved": "https://registry.npmjs.org/define-property/-/define-property-2.0.2.tgz", - "integrity": "sha512-jwK2UV4cnPpbcG7+VRARKTZPUWowwXA8bzH5NP6ud0oeAxyYPuGZUAC7hMugpCdz4BeSZl2Dl9k66CHJ/46ZYQ==", - "dev": true, - "requires": { - "is-descriptor": "^1.0.2", - "isobject": "^3.0.1" - }, - "dependencies": { - "is-accessor-descriptor": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/is-accessor-descriptor/-/is-accessor-descriptor-1.0.0.tgz", - "integrity": "sha512-m5hnHTkcVsPfqx3AKlyttIPb7J+XykHvJP2B9bZDjlhLIoEq4XoK64Vg7boZlVWYK6LUY94dYPEE7Lh0ZkZKcQ==", - "dev": true, - "requires": { - "kind-of": "^6.0.0" - } - }, - "is-data-descriptor": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/is-data-descriptor/-/is-data-descriptor-1.0.0.tgz", - "integrity": "sha512-jbRXy1FmtAoCjQkVmIVYwuuqDFUbaOeDjmed1tOGPrsMhtJA4rD9tkgA0F1qJ3gRFRXcHYVkdeaP50Q5rE/jLQ==", - "dev": true, - "requires": { - "kind-of": "^6.0.0" - } - }, - "is-descriptor": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/is-descriptor/-/is-descriptor-1.0.2.tgz", - "integrity": "sha512-2eis5WqQGV7peooDyLmNEPUrps9+SXX5c9pL3xEB+4e9HnGuDa7mB7kHxHw4CbqS9k1T2hOH3miL8n8WtiYVtg==", - "dev": true, - "requires": { - "is-accessor-descriptor": "^1.0.0", - "is-data-descriptor": "^1.0.0", - "kind-of": "^6.0.2" - } - } - } - }, - "delayed-stream": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/delayed-stream/-/delayed-stream-1.0.0.tgz", - "integrity": "sha1-3zrhmayt+31ECqrgsp4icrJOxhk=" - }, - "depd": { - "version": "1.1.2", - "resolved": "https://registry.npmjs.org/depd/-/depd-1.1.2.tgz", - "integrity": "sha1-m81S4UwJd2PnSbJ0xDRu0uVgtak=", - "dev": true - }, - "destroy": { - "version": "1.0.4", - "resolved": "https://registry.npmjs.org/destroy/-/destroy-1.0.4.tgz", - "integrity": "sha1-l4hXRCxEdJ5CBmE+N5RiBYJqvYA=", - "dev": true - }, - "detect-newline": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/detect-newline/-/detect-newline-2.1.0.tgz", - "integrity": "sha1-9B8cEL5LAOh7XxPaaAdZ8sW/0+I=", - "dev": true - }, - "dicer": { - "version": "0.2.5", - "resolved": "https://registry.npmjs.org/dicer/-/dicer-0.2.5.tgz", - "integrity": "sha1-WZbAhrszIYyBLAkL3cCc0S+stw8=", - "dev": true, - "requires": { - "readable-stream": "1.1.x", - "streamsearch": "0.1.2" - } - }, - "diff": { - "version": "4.0.1", - "resolved": "https://registry.npmjs.org/diff/-/diff-4.0.1.tgz", - "integrity": "sha512-s2+XdvhPCOF01LRQBC8hf4vhbVmI2CGS5aZnxLJlT5FtdhPCDFq80q++zK2KlrVorVDdL5BOGZ/VfLrVtYNF+Q==", - "dev": true - }, - "diff-sequences": { - "version": "24.9.0", - "resolved": "https://registry.npmjs.org/diff-sequences/-/diff-sequences-24.9.0.tgz", - "integrity": "sha512-Dj6Wk3tWyTE+Fo1rW8v0Xhwk80um6yFYKbuAxc9c3EZxIHFDYwbi34Uk42u1CdnIiVorvt4RmlSDjIPyzGC2ew==", - "dev": true - }, - "domexception": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/domexception/-/domexception-1.0.1.tgz", - "integrity": "sha512-raigMkn7CJNNo6Ihro1fzG7wr3fHuYVytzquZKX5n0yizGsTcYgzdIUwj1X9pK0VvjeihV+XiclP+DjwbsSKug==", - "dev": true, - "requires": { - "webidl-conversions": "^4.0.2" - } - }, - "ecc-jsbn": { - "version": "0.1.2", - "resolved": "https://registry.npmjs.org/ecc-jsbn/-/ecc-jsbn-0.1.2.tgz", - "integrity": "sha1-OoOpBOVDUyh4dMVkt1SThoSamMk=", - "dev": true, - "requires": { - "jsbn": "~0.1.0", - "safer-buffer": "^2.1.0" - } - }, - "ee-first": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/ee-first/-/ee-first-1.1.1.tgz", - "integrity": "sha1-WQxhFWsK4vTwJVcyoViyZrxWsh0=", - "dev": true - }, - "emoji-regex": { - "version": "7.0.3", - "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-7.0.3.tgz", - "integrity": "sha512-CwBLREIQ7LvYFB0WyRvwhq5N5qPhc6PMjD6bYggFlI5YyDgl+0vxq5VHbMOFqLg7hfWzmu8T5Z1QofhmTIhItA==", - "dev": true - }, - "encodeurl": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/encodeurl/-/encodeurl-1.0.2.tgz", - "integrity": "sha1-rT/0yG7C0CkyL1oCw6mmBslbP1k=", - "dev": true - }, - "end-of-stream": { - "version": "1.4.4", - "resolved": "https://registry.npmjs.org/end-of-stream/-/end-of-stream-1.4.4.tgz", - "integrity": "sha512-+uw1inIHVPQoaVuHzRyXd21icM+cnt4CzD5rW+NC1wjOUSTOs+Te7FOv7AhN7vS9x/oIyhLP5PR1H+phQAHu5Q==", - "dev": true, - "requires": { - "once": "^1.4.0" - } - }, - "error-ex": { - "version": "1.3.2", - "resolved": "https://registry.npmjs.org/error-ex/-/error-ex-1.3.2.tgz", - "integrity": "sha512-7dFHNmqeFSEt2ZBsCriorKnn3Z2pj+fd9kmI6QoWw4//DL+icEBfc0U7qJCisqrTsKTjw4fNFy2pW9OqStD84g==", - "dev": true, - "requires": { - "is-arrayish": "^0.2.1" - } - }, - "es-abstract": { - "version": "1.14.2", - "resolved": "https://registry.npmjs.org/es-abstract/-/es-abstract-1.14.2.tgz", - "integrity": "sha512-DgoQmbpFNOofkjJtKwr87Ma5EW4Dc8fWhD0R+ndq7Oc456ivUfGOOP6oAZTTKl5/CcNMP+EN+e3/iUzgE0veZg==", - "dev": true, - "requires": { - "es-to-primitive": "^1.2.0", - "function-bind": "^1.1.1", - "has": "^1.0.3", - "has-symbols": "^1.0.0", - "is-callable": "^1.1.4", - "is-regex": "^1.0.4", - "object-inspect": "^1.6.0", - "object-keys": "^1.1.1", - "string.prototype.trimleft": "^2.0.0", - "string.prototype.trimright": "^2.0.0" - } - }, - "es-to-primitive": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/es-to-primitive/-/es-to-primitive-1.2.0.tgz", - "integrity": "sha512-qZryBOJjV//LaxLTV6UC//WewneB3LcXOL9NP++ozKVXsIIIpm/2c13UDiD9Jp2eThsecw9m3jPqDwTyobcdbg==", - "dev": true, - "requires": { - "is-callable": "^1.1.4", - "is-date-object": "^1.0.1", - "is-symbol": "^1.0.2" - } - }, - "escape-html": { - "version": "1.0.3", - "resolved": "https://registry.npmjs.org/escape-html/-/escape-html-1.0.3.tgz", - "integrity": "sha1-Aljq5NPQwJdN4cFpGI7wBR0dGYg=", - "dev": true - }, - "escape-string-regexp": { - "version": "1.0.5", - "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-1.0.5.tgz", - "integrity": "sha1-G2HAViGQqN/2rjuyzwIAyhMLhtQ=", - "dev": true - }, - "escodegen": { - "version": "1.12.0", - "resolved": "https://registry.npmjs.org/escodegen/-/escodegen-1.12.0.tgz", - "integrity": "sha512-TuA+EhsanGcme5T3R0L80u4t8CpbXQjegRmf7+FPTJrtCTErXFeelblRgHQa1FofEzqYYJmJ/OqjTwREp9qgmg==", - "dev": true, - "requires": { - "esprima": "^3.1.3", - "estraverse": "^4.2.0", - "esutils": "^2.0.2", - "optionator": "^0.8.1", - "source-map": "~0.6.1" - } - }, - "esprima": { - "version": "3.1.3", - "resolved": "https://registry.npmjs.org/esprima/-/esprima-3.1.3.tgz", - "integrity": "sha1-/cpRzuYTOJXjyI1TXOSdv/YqRjM=", - "dev": true - }, - "estraverse": { - "version": "4.3.0", - "resolved": "https://registry.npmjs.org/estraverse/-/estraverse-4.3.0.tgz", - "integrity": "sha512-39nnKffWz8xN1BU/2c79n9nB9HDzo0niYUqx6xyqUnyoAnQyyWpOTdZEeiCch8BBu515t4wp9ZmgVfVhn9EBpw==", - "dev": true - }, - "esutils": { - "version": "2.0.3", - "resolved": "https://registry.npmjs.org/esutils/-/esutils-2.0.3.tgz", - "integrity": "sha512-kVscqXk4OCp68SZ0dkgEKVi6/8ij300KBWTJq32P/dYeWTSwK41WyTxalN1eRmA5Z9UU/LX9D7FWSmV9SAYx6g==", - "dev": true - }, - "etag": { - "version": "1.8.1", - "resolved": "https://registry.npmjs.org/etag/-/etag-1.8.1.tgz", - "integrity": "sha1-Qa4u62XvpiJorr/qg6x9eSmbCIc=", - "dev": true - }, - "exec-sh": { - "version": "0.3.2", - "resolved": "https://registry.npmjs.org/exec-sh/-/exec-sh-0.3.2.tgz", - "integrity": "sha512-9sLAvzhI5nc8TpuQUh4ahMdCrWT00wPWz7j47/emR5+2qEfoZP5zzUXvx+vdx+H6ohhnsYC31iX04QLYJK8zTg==", - "dev": true - }, - "execa": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/execa/-/execa-1.0.0.tgz", - "integrity": "sha512-adbxcyWV46qiHyvSp50TKt05tB4tK3HcmF7/nxfAdhnox83seTDbwnaqKO4sXRy7roHAIFqJP/Rw/AuEbX61LA==", - "dev": true, - "requires": { - "cross-spawn": "^6.0.0", - "get-stream": "^4.0.0", - "is-stream": "^1.1.0", - "npm-run-path": "^2.0.0", - "p-finally": "^1.0.0", - "signal-exit": "^3.0.0", - "strip-eof": "^1.0.0" - } - }, - "exit": { - "version": "0.1.2", - "resolved": "https://registry.npmjs.org/exit/-/exit-0.1.2.tgz", - "integrity": "sha1-BjJjj42HfMghB9MKD/8aF8uhzQw=", - "dev": true - }, - "expand-brackets": { - "version": "2.1.4", - "resolved": "https://registry.npmjs.org/expand-brackets/-/expand-brackets-2.1.4.tgz", - "integrity": "sha1-t3c14xXOMPa27/D4OwQVGiJEliI=", - "dev": true, - "requires": { - "debug": "^2.3.3", - "define-property": "^0.2.5", - "extend-shallow": "^2.0.1", - "posix-character-classes": "^0.1.0", - "regex-not": "^1.0.0", - "snapdragon": "^0.8.1", - "to-regex": "^3.0.1" - }, - "dependencies": { - "debug": { - "version": "2.6.9", - "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", - "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==", - "dev": true, - "requires": { - "ms": "2.0.0" - } - }, - "define-property": { - "version": "0.2.5", - "resolved": "https://registry.npmjs.org/define-property/-/define-property-0.2.5.tgz", - "integrity": "sha1-w1se+RjsPJkPmlvFe+BKrOxcgRY=", - "dev": true, - "requires": { - "is-descriptor": "^0.1.0" - } - }, - "extend-shallow": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/extend-shallow/-/extend-shallow-2.0.1.tgz", - "integrity": "sha1-Ua99YUrZqfYQ6huvu5idaxxWiQ8=", - "dev": true, - "requires": { - "is-extendable": "^0.1.0" - } - } - } - }, - "expect": { - "version": "24.9.0", - "resolved": "https://registry.npmjs.org/expect/-/expect-24.9.0.tgz", - "integrity": "sha512-wvVAx8XIol3Z5m9zvZXiyZOQ+sRJqNTIm6sGjdWlaZIeupQGO3WbYI+15D/AmEwZywL6wtJkbAbJtzkOfBuR0Q==", - "dev": true, - "requires": { - "@jest/types": "^24.9.0", - "ansi-styles": "^3.2.0", - "jest-get-type": "^24.9.0", - "jest-matcher-utils": "^24.9.0", - "jest-message-util": "^24.9.0", - "jest-regex-util": "^24.9.0" - } - }, - "express": { - "version": "4.17.1", - "resolved": "https://registry.npmjs.org/express/-/express-4.17.1.tgz", - "integrity": "sha512-mHJ9O79RqluphRrcw2X/GTh3k9tVv8YcoyY4Kkh4WDMUYKRZUq0h1o0w2rrrxBqM7VoeUVqgb27xlEMXTnYt4g==", - "dev": true, - "requires": { - "accepts": "~1.3.7", - "array-flatten": "1.1.1", - "body-parser": "1.19.0", - "content-disposition": "0.5.3", - "content-type": "~1.0.4", - "cookie": "0.4.0", - "cookie-signature": "1.0.6", - "debug": "2.6.9", - "depd": "~1.1.2", - "encodeurl": "~1.0.2", - "escape-html": "~1.0.3", - "etag": "~1.8.1", - "finalhandler": "~1.1.2", - "fresh": "0.5.2", - "merge-descriptors": "1.0.1", - "methods": "~1.1.2", - "on-finished": "~2.3.0", - "parseurl": "~1.3.3", - "path-to-regexp": "0.1.7", - "proxy-addr": "~2.0.5", - "qs": "6.7.0", - "range-parser": "~1.2.1", - "safe-buffer": "5.1.2", - "send": "0.17.1", - "serve-static": "1.14.1", - "setprototypeof": "1.1.1", - "statuses": "~1.5.0", - "type-is": "~1.6.18", - "utils-merge": "1.0.1", - "vary": "~1.1.2" - }, - "dependencies": { - "debug": { - "version": "2.6.9", - "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", - "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==", - "dev": true, - "requires": { - "ms": "2.0.0" - } - }, - "qs": { - "version": "6.7.0", - "resolved": "https://registry.npmjs.org/qs/-/qs-6.7.0.tgz", - "integrity": "sha512-VCdBRNFTX1fyE7Nb6FYoURo/SPe62QCaAyzJvUjwRaIsc+NePBEniHlvxFmmX56+HZphIGtV0XeCirBtpDrTyQ==", - "dev": true - } - } - }, - "extend": { - "version": "3.0.2", - "resolved": "https://registry.npmjs.org/extend/-/extend-3.0.2.tgz", - "integrity": "sha512-fjquC59cD7CyW6urNXK0FBufkZcoiGG80wTuPujX590cB5Ttln20E2UB4S/WARVqhXffZl2LNgS+gQdPIIim/g==", - "dev": true - }, - "extend-shallow": { - "version": "3.0.2", - "resolved": "https://registry.npmjs.org/extend-shallow/-/extend-shallow-3.0.2.tgz", - "integrity": "sha1-Jqcarwc7OfshJxcnRhMcJwQCjbg=", - "dev": true, - "requires": { - "assign-symbols": "^1.0.0", - "is-extendable": "^1.0.1" - }, - "dependencies": { - "is-extendable": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/is-extendable/-/is-extendable-1.0.1.tgz", - "integrity": "sha512-arnXMxT1hhoKo9k1LZdmlNyJdDDfy2v0fXjFlmok4+i8ul/6WlbVge9bhM74OpNPQPMGUToDtz+KXa1PneJxOA==", - "dev": true, - "requires": { - "is-plain-object": "^2.0.4" - } - } - } - }, - "extglob": { - "version": "2.0.4", - "resolved": "https://registry.npmjs.org/extglob/-/extglob-2.0.4.tgz", - "integrity": "sha512-Nmb6QXkELsuBr24CJSkilo6UHHgbekK5UiZgfE6UHD3Eb27YC6oD+bhcT+tJ6cl8dmsgdQxnWlcry8ksBIBLpw==", - "dev": true, - "requires": { - "array-unique": "^0.3.2", - "define-property": "^1.0.0", - "expand-brackets": "^2.1.4", - "extend-shallow": "^2.0.1", - "fragment-cache": "^0.2.1", - "regex-not": "^1.0.0", - "snapdragon": "^0.8.1", - "to-regex": "^3.0.1" - }, - "dependencies": { - "define-property": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/define-property/-/define-property-1.0.0.tgz", - "integrity": "sha1-dp66rz9KY6rTr56NMEybvnm/sOY=", - "dev": true, - "requires": { - "is-descriptor": "^1.0.0" - } - }, - "extend-shallow": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/extend-shallow/-/extend-shallow-2.0.1.tgz", - "integrity": "sha1-Ua99YUrZqfYQ6huvu5idaxxWiQ8=", - "dev": true, - "requires": { - "is-extendable": "^0.1.0" - } - }, - "is-accessor-descriptor": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/is-accessor-descriptor/-/is-accessor-descriptor-1.0.0.tgz", - "integrity": "sha512-m5hnHTkcVsPfqx3AKlyttIPb7J+XykHvJP2B9bZDjlhLIoEq4XoK64Vg7boZlVWYK6LUY94dYPEE7Lh0ZkZKcQ==", - "dev": true, - "requires": { - "kind-of": "^6.0.0" - } - }, - "is-data-descriptor": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/is-data-descriptor/-/is-data-descriptor-1.0.0.tgz", - "integrity": "sha512-jbRXy1FmtAoCjQkVmIVYwuuqDFUbaOeDjmed1tOGPrsMhtJA4rD9tkgA0F1qJ3gRFRXcHYVkdeaP50Q5rE/jLQ==", - "dev": true, - "requires": { - "kind-of": "^6.0.0" - } - }, - "is-descriptor": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/is-descriptor/-/is-descriptor-1.0.2.tgz", - "integrity": "sha512-2eis5WqQGV7peooDyLmNEPUrps9+SXX5c9pL3xEB+4e9HnGuDa7mB7kHxHw4CbqS9k1T2hOH3miL8n8WtiYVtg==", - "dev": true, - "requires": { - "is-accessor-descriptor": "^1.0.0", - "is-data-descriptor": "^1.0.0", - "kind-of": "^6.0.2" - } - } - } - }, - "extsprintf": { - "version": "1.3.0", - "resolved": "https://registry.npmjs.org/extsprintf/-/extsprintf-1.3.0.tgz", - "integrity": "sha1-lpGEQOMEGnpBT4xS48V06zw+HgU=", - "dev": true - }, - "fast-deep-equal": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/fast-deep-equal/-/fast-deep-equal-2.0.1.tgz", - "integrity": "sha1-ewUhjd+WZ79/Nwv3/bLLFf3Qqkk=", - "dev": true - }, - "fast-json-stable-stringify": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/fast-json-stable-stringify/-/fast-json-stable-stringify-2.0.0.tgz", - "integrity": "sha1-1RQsDK7msRifh9OnYREGT4bIu/I=", - "dev": true - }, - "fast-levenshtein": { - "version": "2.0.6", - "resolved": "https://registry.npmjs.org/fast-levenshtein/-/fast-levenshtein-2.0.6.tgz", - "integrity": "sha1-PYpcZog6FqMMqGQ+hR8Zuqd5eRc=", - "dev": true - }, - "fb-watchman": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/fb-watchman/-/fb-watchman-2.0.0.tgz", - "integrity": "sha1-VOmr99+i8mzZsWNsWIwa/AXeXVg=", - "dev": true, - "requires": { - "bser": "^2.0.0" - } - }, - "fill-range": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/fill-range/-/fill-range-4.0.0.tgz", - "integrity": "sha1-1USBHUKPmOsGpj3EAtJAPDKMOPc=", - "dev": true, - "requires": { - "extend-shallow": "^2.0.1", - "is-number": "^3.0.0", - "repeat-string": "^1.6.1", - "to-regex-range": "^2.1.0" - }, - "dependencies": { - "extend-shallow": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/extend-shallow/-/extend-shallow-2.0.1.tgz", - "integrity": "sha1-Ua99YUrZqfYQ6huvu5idaxxWiQ8=", - "dev": true, - "requires": { - "is-extendable": "^0.1.0" - } - } - } - }, - "finalhandler": { - "version": "1.1.2", - "resolved": "https://registry.npmjs.org/finalhandler/-/finalhandler-1.1.2.tgz", - "integrity": "sha512-aAWcW57uxVNrQZqFXjITpW3sIUQmHGG3qSb9mUah9MgMC4NeWhNOlNjXEYq3HjRAvL6arUviZGGJsBg6z0zsWA==", - "dev": true, - "requires": { - "debug": "2.6.9", - "encodeurl": "~1.0.2", - "escape-html": "~1.0.3", - "on-finished": "~2.3.0", - "parseurl": "~1.3.3", - "statuses": "~1.5.0", - "unpipe": "~1.0.0" - }, - "dependencies": { - "debug": { - "version": "2.6.9", - "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", - "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==", - "dev": true, - "requires": { - "ms": "2.0.0" - } - } - } - }, - "find-up": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/find-up/-/find-up-3.0.0.tgz", - "integrity": "sha512-1yD6RmLI1XBfxugvORwlck6f75tYL+iR0jqwsOrOxMZyGYqUuDhJ0l4AXdO1iX/FTs9cBAMEk1gWSEx1kSbylg==", - "dev": true, - "requires": { - "locate-path": "^3.0.0" - } - }, - "follow-redirects": { - "version": "1.5.10", - "resolved": "https://registry.npmjs.org/follow-redirects/-/follow-redirects-1.5.10.tgz", - "integrity": "sha512-0V5l4Cizzvqt5D44aTXbFZz+FtyXV1vrDN6qrelxtfYQKW0KO0W2T/hkE8xvGa/540LkZlkaUjO4ailYTFtHVQ==", - "requires": { - "debug": "=3.1.0" - } - }, - "for-in": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/for-in/-/for-in-1.0.2.tgz", - "integrity": "sha1-gQaNKVqBQuwKxybG4iAMMPttXoA=", - "dev": true - }, - "forever-agent": { - "version": "0.6.1", - "resolved": "https://registry.npmjs.org/forever-agent/-/forever-agent-0.6.1.tgz", - "integrity": "sha1-+8cfDEGt6zf5bFd60e1C2P2sypE=", - "dev": true - }, - "form-data": { - "version": "2.5.1", - "resolved": "https://registry.npmjs.org/form-data/-/form-data-2.5.1.tgz", - "integrity": "sha512-m21N3WOmEEURgk6B9GLOE4RuWOFf28Lhh9qGYeNlGq4VDXUlJy2th2slBNU8Gp8EzloYZOibZJ7t5ecIrFSjVA==", - "requires": { - "asynckit": "^0.4.0", - "combined-stream": "^1.0.6", - "mime-types": "^2.1.12" - } - }, - "forwarded": { - "version": "0.1.2", - "resolved": "https://registry.npmjs.org/forwarded/-/forwarded-0.1.2.tgz", - "integrity": "sha1-mMI9qxF1ZXuMBXPozszZGw/xjIQ=", - "dev": true - }, - "fragment-cache": { - "version": "0.2.1", - "resolved": "https://registry.npmjs.org/fragment-cache/-/fragment-cache-0.2.1.tgz", - "integrity": "sha1-QpD60n8T6Jvn8zeZxrxaCr//DRk=", - "dev": true, - "requires": { - "map-cache": "^0.2.2" - } - }, - "fresh": { - "version": "0.5.2", - "resolved": "https://registry.npmjs.org/fresh/-/fresh-0.5.2.tgz", - "integrity": "sha1-PYyt2Q2XZWn6g1qx+OSyOhBWBac=", - "dev": true - }, - "fs.realpath": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/fs.realpath/-/fs.realpath-1.0.0.tgz", - "integrity": "sha1-FQStJSMVjKpA20onh8sBQRmU6k8=", - "dev": true - }, - "fsevents": { - "version": "1.2.9", - "resolved": "https://registry.npmjs.org/fsevents/-/fsevents-1.2.9.tgz", - "integrity": "sha512-oeyj2H3EjjonWcFjD5NvZNE9Rqe4UW+nQBU2HNeKw0koVLEFIhtyETyAakeAM3de7Z/SW5kcA+fZUait9EApnw==", - "dev": true, - "optional": true, - "requires": { - "nan": "^2.12.1", - "node-pre-gyp": "^0.12.0" - }, - "dependencies": { - "abbrev": { - "version": "1.1.1", - "bundled": true, - "dev": true, - "optional": true - }, - "ansi-regex": { - "version": "2.1.1", - "bundled": true, - "dev": true, - "optional": true - }, - "aproba": { - "version": "1.2.0", - "bundled": true, - "dev": true, - "optional": true - }, - "are-we-there-yet": { - "version": "1.1.5", - "bundled": true, - "dev": true, - "optional": true, - "requires": { - "delegates": "^1.0.0", - "readable-stream": "^2.0.6" - } - }, - "balanced-match": { - "version": "1.0.0", - "bundled": true, - "dev": true, - "optional": true - }, - "brace-expansion": { - "version": "1.1.11", - "bundled": true, - "dev": true, - "optional": true, - "requires": { - "balanced-match": "^1.0.0", - "concat-map": "0.0.1" - } - }, - "chownr": { - "version": "1.1.1", - "bundled": true, - "dev": true, - "optional": true - }, - "code-point-at": { - "version": "1.1.0", - "bundled": true, - "dev": true, - "optional": true - }, - "concat-map": { - "version": "0.0.1", - "bundled": true, - "dev": true, - "optional": true - }, - "console-control-strings": { - "version": "1.1.0", - "bundled": true, - "dev": true, - "optional": true - }, - "core-util-is": { - "version": "1.0.2", - "bundled": true, - "dev": true, - "optional": true - }, - "debug": { - "version": "4.1.1", - "bundled": true, - "dev": true, - "optional": true, - "requires": { - "ms": "^2.1.1" - } - }, - "deep-extend": { - "version": "0.6.0", - "bundled": true, - "dev": true, - "optional": true - }, - "delegates": { - "version": "1.0.0", - "bundled": true, - "dev": true, - "optional": true - }, - "detect-libc": { - "version": "1.0.3", - "bundled": true, - "dev": true, - "optional": true - }, - "fs-minipass": { - "version": "1.2.5", - "bundled": true, - "dev": true, - "optional": true, - "requires": { - "minipass": "^2.2.1" - } - }, - "fs.realpath": { - "version": "1.0.0", - "bundled": true, - "dev": true, - "optional": true - }, - "gauge": { - "version": "2.7.4", - "bundled": true, - "dev": true, - "optional": true, - "requires": { - "aproba": "^1.0.3", - "console-control-strings": "^1.0.0", - "has-unicode": "^2.0.0", - "object-assign": "^4.1.0", - "signal-exit": "^3.0.0", - "string-width": "^1.0.1", - "strip-ansi": "^3.0.1", - "wide-align": "^1.1.0" - } - }, - "glob": { - "version": "7.1.3", - "bundled": true, - "dev": true, - "optional": true, - "requires": { - "fs.realpath": "^1.0.0", - "inflight": "^1.0.4", - "inherits": "2", - "minimatch": "^3.0.4", - "once": "^1.3.0", - "path-is-absolute": "^1.0.0" - } - }, - "has-unicode": { - "version": "2.0.1", - "bundled": true, - "dev": true, - "optional": true - }, - "iconv-lite": { - "version": "0.4.24", - "bundled": true, - "dev": true, - "optional": true, - "requires": { - "safer-buffer": ">= 2.1.2 < 3" - } - }, - "ignore-walk": { - "version": "3.0.1", - "bundled": true, - "dev": true, - "optional": true, - "requires": { - "minimatch": "^3.0.4" - } - }, - "inflight": { - "version": "1.0.6", - "bundled": true, - "dev": true, - "optional": true, - "requires": { - "once": "^1.3.0", - "wrappy": "1" - } - }, - "inherits": { - "version": "2.0.3", - "bundled": true, - "dev": true, - "optional": true - }, - "ini": { - "version": "1.3.5", - "bundled": true, - "dev": true, - "optional": true - }, - "is-fullwidth-code-point": { - "version": "1.0.0", - "bundled": true, - "dev": true, - "optional": true, - "requires": { - "number-is-nan": "^1.0.0" - } - }, - "isarray": { - "version": "1.0.0", - "bundled": true, - "dev": true, - "optional": true - }, - "minimatch": { - "version": "3.0.4", - "bundled": true, - "dev": true, - "optional": true, - "requires": { - "brace-expansion": "^1.1.7" - } - }, - "minimist": { - "version": "0.0.8", - "bundled": true, - "dev": true, - "optional": true - }, - "minipass": { - "version": "2.3.5", - "bundled": true, - "dev": true, - "optional": true, - "requires": { - "safe-buffer": "^5.1.2", - "yallist": "^3.0.0" - } - }, - "minizlib": { - "version": "1.2.1", - "bundled": true, - "dev": true, - "optional": true, - "requires": { - "minipass": "^2.2.1" - } - }, - "mkdirp": { - "version": "0.5.1", - "bundled": true, - "dev": true, - "optional": true, - "requires": { - "minimist": "0.0.8" - } - }, - "ms": { - "version": "2.1.1", - "bundled": true, - "dev": true, - "optional": true - }, - "needle": { - "version": "2.3.0", - "bundled": true, - "dev": true, - "optional": true, - "requires": { - "debug": "^4.1.0", - "iconv-lite": "^0.4.4", - "sax": "^1.2.4" - } - }, - "node-pre-gyp": { - "version": "0.12.0", - "bundled": true, - "dev": true, - "optional": true, - "requires": { - "detect-libc": "^1.0.2", - "mkdirp": "^0.5.1", - "needle": "^2.2.1", - "nopt": "^4.0.1", - "npm-packlist": "^1.1.6", - "npmlog": "^4.0.2", - "rc": "^1.2.7", - "rimraf": "^2.6.1", - "semver": "^5.3.0", - "tar": "^4" - } - }, - "nopt": { - "version": "4.0.1", - "bundled": true, - "dev": true, - "optional": true, - "requires": { - "abbrev": "1", - "osenv": "^0.1.4" - } - }, - "npm-bundled": { - "version": "1.0.6", - "bundled": true, - "dev": true, - "optional": true - }, - "npm-packlist": { - "version": "1.4.1", - "bundled": true, - "dev": true, - "optional": true, - "requires": { - "ignore-walk": "^3.0.1", - "npm-bundled": "^1.0.1" - } - }, - "npmlog": { - "version": "4.1.2", - "bundled": true, - "dev": true, - "optional": true, - "requires": { - "are-we-there-yet": "~1.1.2", - "console-control-strings": "~1.1.0", - "gauge": "~2.7.3", - "set-blocking": "~2.0.0" - } - }, - "number-is-nan": { - "version": "1.0.1", - "bundled": true, - "dev": true, - "optional": true - }, - "object-assign": { - "version": "4.1.1", - "bundled": true, - "dev": true, - "optional": true - }, - "once": { - "version": "1.4.0", - "bundled": true, - "dev": true, - "optional": true, - "requires": { - "wrappy": "1" - } - }, - "os-homedir": { - "version": "1.0.2", - "bundled": true, - "dev": true, - "optional": true - }, - "os-tmpdir": { - "version": "1.0.2", - "bundled": true, - "dev": true, - "optional": true - }, - "osenv": { - "version": "0.1.5", - "bundled": true, - "dev": true, - "optional": true, - "requires": { - "os-homedir": "^1.0.0", - "os-tmpdir": "^1.0.0" - } - }, - "path-is-absolute": { - "version": "1.0.1", - "bundled": true, - "dev": true, - "optional": true - }, - "process-nextick-args": { - "version": "2.0.0", - "bundled": true, - "dev": true, - "optional": true - }, - "rc": { - "version": "1.2.8", - "bundled": true, - "dev": true, - "optional": true, - "requires": { - "deep-extend": "^0.6.0", - "ini": "~1.3.0", - "minimist": "^1.2.0", - "strip-json-comments": "~2.0.1" - }, - "dependencies": { - "minimist": { - "version": "1.2.0", - "bundled": true, - "dev": true, - "optional": true - } - } - }, - "readable-stream": { - "version": "2.3.6", - "bundled": true, - "dev": true, - "optional": true, - "requires": { - "core-util-is": "~1.0.0", - "inherits": "~2.0.3", - "isarray": "~1.0.0", - "process-nextick-args": "~2.0.0", - "safe-buffer": "~5.1.1", - "string_decoder": "~1.1.1", - "util-deprecate": "~1.0.1" - } - }, - "rimraf": { - "version": "2.6.3", - "bundled": true, - "dev": true, - "optional": true, - "requires": { - "glob": "^7.1.3" - } - }, - "safe-buffer": { - "version": "5.1.2", - "bundled": true, - "dev": true, - "optional": true - }, - "safer-buffer": { - "version": "2.1.2", - "bundled": true, - "dev": true, - "optional": true - }, - "sax": { - "version": "1.2.4", - "bundled": true, - "dev": true, - "optional": true - }, - "semver": { - "version": "5.7.0", - "bundled": true, - "dev": true, - "optional": true - }, - "set-blocking": { - "version": "2.0.0", - "bundled": true, - "dev": true, - "optional": true - }, - "signal-exit": { - "version": "3.0.2", - "bundled": true, - "dev": true, - "optional": true - }, - "string-width": { - "version": "1.0.2", - "bundled": true, - "dev": true, - "optional": true, - "requires": { - "code-point-at": "^1.0.0", - "is-fullwidth-code-point": "^1.0.0", - "strip-ansi": "^3.0.0" - } - }, - "string_decoder": { - "version": "1.1.1", - "bundled": true, - "dev": true, - "optional": true, - "requires": { - "safe-buffer": "~5.1.0" - } - }, - "strip-ansi": { - "version": "3.0.1", - "bundled": true, - "dev": true, - "optional": true, - "requires": { - "ansi-regex": "^2.0.0" - } - }, - "strip-json-comments": { - "version": "2.0.1", - "bundled": true, - "dev": true, - "optional": true - }, - "tar": { - "version": "4.4.8", - "bundled": true, - "dev": true, - "optional": true, - "requires": { - "chownr": "^1.1.1", - "fs-minipass": "^1.2.5", - "minipass": "^2.3.4", - "minizlib": "^1.1.1", - "mkdirp": "^0.5.0", - "safe-buffer": "^5.1.2", - "yallist": "^3.0.2" - } - }, - "util-deprecate": { - "version": "1.0.2", - "bundled": true, - "dev": true, - "optional": true - }, - "wide-align": { - "version": "1.1.3", - "bundled": true, - "dev": true, - "optional": true, - "requires": { - "string-width": "^1.0.2 || 2" - } - }, - "wrappy": { - "version": "1.0.2", - "bundled": true, - "dev": true, - "optional": true - }, - "yallist": { - "version": "3.0.3", - "bundled": true, - "dev": true, - "optional": true - } - } - }, - "function-bind": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/function-bind/-/function-bind-1.1.1.tgz", - "integrity": "sha512-yIovAzMX49sF8Yl58fSCWJ5svSLuaibPxXQJFLmBObTuCr0Mf1KiPopGM9NiFjiYBCbfaa2Fh6breQ6ANVTI0A==", - "dev": true - }, - "get-caller-file": { - "version": "2.0.5", - "resolved": "https://registry.npmjs.org/get-caller-file/-/get-caller-file-2.0.5.tgz", - "integrity": "sha512-DyFP3BM/3YHTQOCUL/w0OZHR0lpKeGrxotcHWcqNEdnltqFwXVfhEBQ94eIo34AfQpo0rGki4cyIiftY06h2Fg==", - "dev": true - }, - "get-stdin": { - "version": "7.0.0", - "resolved": "https://registry.npmjs.org/get-stdin/-/get-stdin-7.0.0.tgz", - "integrity": "sha512-zRKcywvrXlXsA0v0i9Io4KDRaAw7+a1ZpjRwl9Wox8PFlVCCHra7E9c4kqXCoCM9nR5tBkaTTZRBoCm60bFqTQ==", - "dev": true - }, - "get-stream": { - "version": "4.1.0", - "resolved": "https://registry.npmjs.org/get-stream/-/get-stream-4.1.0.tgz", - "integrity": "sha512-GMat4EJ5161kIy2HevLlr4luNjBgvmj413KaQA7jt4V8B4RDsfpHk7WQ9GVqfYyyx8OS/L66Kox+rJRNklLK7w==", - "dev": true, - "requires": { - "pump": "^3.0.0" - } - }, - "get-value": { - "version": "2.0.6", - "resolved": "https://registry.npmjs.org/get-value/-/get-value-2.0.6.tgz", - "integrity": "sha1-3BXKHGcjh8p2vTesCjlbogQqLCg=", - "dev": true - }, - "getpass": { - "version": "0.1.7", - "resolved": "https://registry.npmjs.org/getpass/-/getpass-0.1.7.tgz", - "integrity": "sha1-Xv+OPmhNVprkyysSgmBOi6YhSfo=", - "dev": true, - "requires": { - "assert-plus": "^1.0.0" - } - }, - "glob": { - "version": "7.1.4", - "resolved": "https://registry.npmjs.org/glob/-/glob-7.1.4.tgz", - "integrity": "sha512-hkLPepehmnKk41pUGm3sYxoFs/umurYfYJCerbXEyFIWcAzvpipAgVkBqqT9RBKMGjnq6kMuyYwha6csxbiM1A==", - "dev": true, - "requires": { - "fs.realpath": "^1.0.0", - "inflight": "^1.0.4", - "inherits": "2", - "minimatch": "^3.0.4", - "once": "^1.3.0", - "path-is-absolute": "^1.0.0" - } - }, - "globals": { - "version": "11.12.0", - "resolved": "https://registry.npmjs.org/globals/-/globals-11.12.0.tgz", - "integrity": "sha512-WOBp/EEGUiIsJSp7wcv/y6MO+lV9UoncWqxuFfm8eBwzWNgyfBd6Gz+IeKQ9jCmyhoH99g15M3T+QaVHFjizVA==", - "dev": true - }, - "graceful-fs": { - "version": "4.2.2", - "resolved": "https://registry.npmjs.org/graceful-fs/-/graceful-fs-4.2.2.tgz", - "integrity": "sha512-IItsdsea19BoLC7ELy13q1iJFNmd7ofZH5+X/pJr90/nRoPEX0DJo1dHDbgtYWOhJhcCgMDTOw84RZ72q6lB+Q==", - "dev": true - }, - "growly": { - "version": "1.3.0", - "resolved": "https://registry.npmjs.org/growly/-/growly-1.3.0.tgz", - "integrity": "sha1-8QdIy+dq+WS3yWyTxrzCivEgwIE=", - "dev": true - }, - "handlebars": { - "version": "4.3.3", - "resolved": "https://registry.npmjs.org/handlebars/-/handlebars-4.3.3.tgz", - "integrity": "sha512-VupOxR91xcGojfINrzMqrvlyYbBs39sXIrWa7YdaQWeBudOlvKEGvCczMfJPgnuwHE/zyH1M6J+IUP6cgDVyxg==", - "dev": true, - "requires": { - "neo-async": "^2.6.0", - "optimist": "^0.6.1", - "source-map": "^0.6.1", - "uglify-js": "^3.1.4" - } - }, - "har-schema": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/har-schema/-/har-schema-2.0.0.tgz", - "integrity": "sha1-qUwiJOvKwEeCoNkDVSHyRzW37JI=", - "dev": true - }, - "har-validator": { - "version": "5.1.3", - "resolved": "https://registry.npmjs.org/har-validator/-/har-validator-5.1.3.tgz", - "integrity": "sha512-sNvOCzEQNr/qrvJgc3UG/kD4QtlHycrzwS+6mfTrrSq97BvaYcPZZI1ZSqGSPR73Cxn4LKTD4PttRwfU7jWq5g==", - "dev": true, - "requires": { - "ajv": "^6.5.5", - "har-schema": "^2.0.0" - } - }, - "has": { - "version": "1.0.3", - "resolved": "https://registry.npmjs.org/has/-/has-1.0.3.tgz", - "integrity": "sha512-f2dvO0VU6Oej7RkWJGrehjbzMAjFp5/VKPp5tTpWIV4JHHZK1/BxbFRtf/siA2SWTe09caDmVtYYzWEIbBS4zw==", - "dev": true, - "requires": { - "function-bind": "^1.1.1" - } - }, - "has-flag": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-3.0.0.tgz", - "integrity": "sha1-tdRU3CGZriJWmfNGfloH87lVuv0=", - "dev": true - }, - "has-symbols": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/has-symbols/-/has-symbols-1.0.0.tgz", - "integrity": "sha1-uhqPGvKg/DllD1yFA2dwQSIGO0Q=", - "dev": true - }, - "has-value": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/has-value/-/has-value-1.0.0.tgz", - "integrity": "sha1-GLKB2lhbHFxR3vJMkw7SmgvmsXc=", - "dev": true, - "requires": { - "get-value": "^2.0.6", - "has-values": "^1.0.0", - "isobject": "^3.0.0" - } - }, - "has-values": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/has-values/-/has-values-1.0.0.tgz", - "integrity": "sha1-lbC2P+whRmGab+V/51Yo1aOe/k8=", - "dev": true, - "requires": { - "is-number": "^3.0.0", - "kind-of": "^4.0.0" - }, - "dependencies": { - "is-buffer": { - "version": "1.1.6", - "resolved": "https://registry.npmjs.org/is-buffer/-/is-buffer-1.1.6.tgz", - "integrity": "sha512-NcdALwpXkTm5Zvvbk7owOUSvVvBKDgKP5/ewfXEznmQFfs4ZRmanOeKBTjRVjka3QFoN6XJ+9F3USqfHqTaU5w==", - "dev": true - }, - "kind-of": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-4.0.0.tgz", - "integrity": "sha1-IIE989cSkosgc3hpGkUGb65y3Vc=", - "dev": true, - "requires": { - "is-buffer": "^1.1.5" - } - } - } - }, - "hosted-git-info": { - "version": "2.8.4", - "resolved": "https://registry.npmjs.org/hosted-git-info/-/hosted-git-info-2.8.4.tgz", - "integrity": "sha512-pzXIvANXEFrc5oFFXRMkbLPQ2rXRoDERwDLyrcUxGhaZhgP54BBSl9Oheh7Vv0T090cszWBxPjkQQ5Sq1PbBRQ==", - "dev": true - }, - "html-encoding-sniffer": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/html-encoding-sniffer/-/html-encoding-sniffer-1.0.2.tgz", - "integrity": "sha512-71lZziiDnsuabfdYiUeWdCVyKuqwWi23L8YeIgV9jSSZHCtb6wB1BKWooH7L3tn4/FuZJMVWyNaIDr4RGmaSYw==", - "dev": true, - "requires": { - "whatwg-encoding": "^1.0.1" - } - }, - "http-errors": { - "version": "1.7.2", - "resolved": "https://registry.npmjs.org/http-errors/-/http-errors-1.7.2.tgz", - "integrity": "sha512-uUQBt3H/cSIVfch6i1EuPNy/YsRSOUBXTVfZ+yR7Zjez3qjBz6i9+i4zjNaoqcoFVI4lQJ5plg63TvGfRSDCRg==", - "dev": true, - "requires": { - "depd": "~1.1.2", - "inherits": "2.0.3", - "setprototypeof": "1.1.1", - "statuses": ">= 1.5.0 < 2", - "toidentifier": "1.0.0" - } - }, - "http-signature": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/http-signature/-/http-signature-1.2.0.tgz", - "integrity": "sha1-muzZJRFHcvPZW2WmCruPfBj7rOE=", - "dev": true, - "requires": { - "assert-plus": "^1.0.0", - "jsprim": "^1.2.2", - "sshpk": "^1.7.0" - } - }, - "husky": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/husky/-/husky-3.1.0.tgz", - "integrity": "sha512-FJkPoHHB+6s4a+jwPqBudBDvYZsoQW5/HBuMSehC8qDiCe50kpcxeqFoDSlow+9I6wg47YxBoT3WxaURlrDIIQ==", - "dev": true, - "requires": { - "chalk": "^2.4.2", - "ci-info": "^2.0.0", - "cosmiconfig": "^5.2.1", - "execa": "^1.0.0", - "get-stdin": "^7.0.0", - "opencollective-postinstall": "^2.0.2", - "pkg-dir": "^4.2.0", - "please-upgrade-node": "^3.2.0", - "read-pkg": "^5.2.0", - "run-node": "^1.0.0", - "slash": "^3.0.0" - }, - "dependencies": { - "find-up": { - "version": "4.1.0", - "resolved": "https://registry.npmjs.org/find-up/-/find-up-4.1.0.tgz", - "integrity": "sha512-PpOwAdQ/YlXQ2vj8a3h8IipDuYRi3wceVQQGYWxNINccq40Anw7BlsEXCMbt1Zt+OLA6Fq9suIpIWD0OsnISlw==", - "dev": true, - "requires": { - "locate-path": "^5.0.0", - "path-exists": "^4.0.0" - } - }, - "locate-path": { - "version": "5.0.0", - "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-5.0.0.tgz", - "integrity": "sha512-t7hw9pI+WvuwNJXwk5zVHpyhIqzg2qTlklJOf0mVxGSbe3Fp2VieZcduNYjaLDoy6p9uGpQEGWG87WpMKlNq8g==", - "dev": true, - "requires": { - "p-locate": "^4.1.0" - } - }, - "p-locate": { - "version": "4.1.0", - "resolved": "https://registry.npmjs.org/p-locate/-/p-locate-4.1.0.tgz", - "integrity": "sha512-R79ZZ/0wAxKGu3oYMlz8jy/kbhsNrS7SKZ7PxEHBgJ5+F2mtFW2fK2cOtBh1cHYkQsbzFV7I+EoRKe6Yt0oK7A==", - "dev": true, - "requires": { - "p-limit": "^2.2.0" - } - }, - "parse-json": { - "version": "5.0.0", - "resolved": "https://registry.npmjs.org/parse-json/-/parse-json-5.0.0.tgz", - "integrity": "sha512-OOY5b7PAEFV0E2Fir1KOkxchnZNCdowAJgQ5NuxjpBKTRP3pQhwkrkxqQjeoKJ+fO7bCpmIZaogI4eZGDMEGOw==", - "dev": true, - "requires": { - "@babel/code-frame": "^7.0.0", - "error-ex": "^1.3.1", - "json-parse-better-errors": "^1.0.1", - "lines-and-columns": "^1.1.6" - } - }, - "path-exists": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/path-exists/-/path-exists-4.0.0.tgz", - "integrity": "sha512-ak9Qy5Q7jYb2Wwcey5Fpvg2KoAc/ZIhLSLOSBmRmygPsGwkVVt0fZa0qrtMz+m6tJTAHfZQ8FnmB4MG4LWy7/w==", - "dev": true - }, - "pkg-dir": { - "version": "4.2.0", - "resolved": "https://registry.npmjs.org/pkg-dir/-/pkg-dir-4.2.0.tgz", - "integrity": "sha512-HRDzbaKjC+AOWVXxAU/x54COGeIv9eb+6CkDSQoNTt4XyWoIJvuPsXizxu/Fr23EiekbtZwmh1IcIG/l/a10GQ==", - "dev": true, - "requires": { - "find-up": "^4.0.0" - } - }, - "read-pkg": { - "version": "5.2.0", - "resolved": "https://registry.npmjs.org/read-pkg/-/read-pkg-5.2.0.tgz", - "integrity": "sha512-Ug69mNOpfvKDAc2Q8DRpMjjzdtrnv9HcSMX+4VsZxD1aZ6ZzrIE7rlzXBtWTyhULSMKg076AW6WR5iZpD0JiOg==", - "dev": true, - "requires": { - "@types/normalize-package-data": "^2.4.0", - "normalize-package-data": "^2.5.0", - "parse-json": "^5.0.0", - "type-fest": "^0.6.0" - } - }, - "slash": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/slash/-/slash-3.0.0.tgz", - "integrity": "sha512-g9Q1haeby36OSStwb4ntCGGGaKsaVSjQ68fBxoQcutl5fS1vuY18H3wSt3jFyFtrkx+Kz0V1G85A4MyAdDMi2Q==", - "dev": true - } - } - }, - "iconv-lite": { - "version": "0.4.24", - "resolved": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.4.24.tgz", - "integrity": "sha512-v3MXnZAcvnywkTUEZomIActle7RXXeedOR31wwl7VlyoXO4Qi9arvSenNQWne1TcRwhCL1HwLI21bEqdpj8/rA==", - "dev": true, - "requires": { - "safer-buffer": ">= 2.1.2 < 3" - } - }, - "import-fresh": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/import-fresh/-/import-fresh-2.0.0.tgz", - "integrity": "sha1-2BNVwVYS04bGH53dOSLUMEgipUY=", - "dev": true, - "requires": { - "caller-path": "^2.0.0", - "resolve-from": "^3.0.0" - } - }, - "import-local": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/import-local/-/import-local-2.0.0.tgz", - "integrity": "sha512-b6s04m3O+s3CGSbqDIyP4R6aAwAeYlVq9+WUWep6iHa8ETRf9yei1U48C5MmfJmV9AiLYYBKPMq/W+/WRpQmCQ==", - "dev": true, - "requires": { - "pkg-dir": "^3.0.0", - "resolve-cwd": "^2.0.0" - } - }, - "imurmurhash": { - "version": "0.1.4", - "resolved": "https://registry.npmjs.org/imurmurhash/-/imurmurhash-0.1.4.tgz", - "integrity": "sha1-khi5srkoojixPcT7a21XbyMUU+o=", - "dev": true - }, - "inflight": { - "version": "1.0.6", - "resolved": "https://registry.npmjs.org/inflight/-/inflight-1.0.6.tgz", - "integrity": "sha1-Sb1jMdfQLQwJvJEKEHW6gWW1bfk=", - "dev": true, - "requires": { - "once": "^1.3.0", - "wrappy": "1" - } - }, - "inherits": { - "version": "2.0.3", - "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.3.tgz", - "integrity": "sha1-Yzwsg+PaQqUC9SRmAiSA9CCCYd4=", - "dev": true - }, - "invariant": { - "version": "2.2.4", - "resolved": "https://registry.npmjs.org/invariant/-/invariant-2.2.4.tgz", - "integrity": "sha512-phJfQVBuaJM5raOpJjSfkiD6BpbCE4Ns//LaXl6wGYtUBY83nWS6Rf9tXm2e8VaK60JEjYldbPif/A2B1C2gNA==", - "dev": true, - "requires": { - "loose-envify": "^1.0.0" - } - }, - "ipaddr.js": { - "version": "1.9.0", - "resolved": "https://registry.npmjs.org/ipaddr.js/-/ipaddr.js-1.9.0.tgz", - "integrity": "sha512-M4Sjn6N/+O6/IXSJseKqHoFc+5FdGJ22sXqnjTpdZweHK64MzEPAyQZyEU3R/KRv2GLoa7nNtg/C2Ev6m7z+eA==", - "dev": true - }, - "is-accessor-descriptor": { - "version": "0.1.6", - "resolved": "https://registry.npmjs.org/is-accessor-descriptor/-/is-accessor-descriptor-0.1.6.tgz", - "integrity": "sha1-qeEss66Nh2cn7u84Q/igiXtcmNY=", - "dev": true, - "requires": { - "kind-of": "^3.0.2" - }, - "dependencies": { - "is-buffer": { - "version": "1.1.6", - "resolved": "https://registry.npmjs.org/is-buffer/-/is-buffer-1.1.6.tgz", - "integrity": "sha512-NcdALwpXkTm5Zvvbk7owOUSvVvBKDgKP5/ewfXEznmQFfs4ZRmanOeKBTjRVjka3QFoN6XJ+9F3USqfHqTaU5w==", - "dev": true - }, - "kind-of": { - "version": "3.2.2", - "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-3.2.2.tgz", - "integrity": "sha1-MeohpzS6ubuw8yRm2JOupR5KPGQ=", - "dev": true, - "requires": { - "is-buffer": "^1.1.5" - } - } - } - }, - "is-arrayish": { - "version": "0.2.1", - "resolved": "https://registry.npmjs.org/is-arrayish/-/is-arrayish-0.2.1.tgz", - "integrity": "sha1-d8mYQFJ6qOyxqLppe4BkWnqSap0=", - "dev": true - }, - "is-buffer": { - "version": "2.0.3", - "resolved": "https://registry.npmjs.org/is-buffer/-/is-buffer-2.0.3.tgz", - "integrity": "sha512-U15Q7MXTuZlrbymiz95PJpZxu8IlipAp4dtS3wOdgPXx3mqBnslrWU14kxfHB+Py/+2PVKSr37dMAgM2A4uArw==" - }, - "is-callable": { - "version": "1.1.4", - "resolved": "https://registry.npmjs.org/is-callable/-/is-callable-1.1.4.tgz", - "integrity": "sha512-r5p9sxJjYnArLjObpjA4xu5EKI3CuKHkJXMhT7kwbpUyIFD1n5PMAsoPvWnvtZiNz7LjkYDRZhd7FlI0eMijEA==", - "dev": true - }, - "is-ci": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/is-ci/-/is-ci-2.0.0.tgz", - "integrity": "sha512-YfJT7rkpQB0updsdHLGWrvhBJfcfzNNawYDNIyQXJz0IViGf75O8EBPKSdvw2rF+LGCsX4FZ8tcr3b19LcZq4w==", - "dev": true, - "requires": { - "ci-info": "^2.0.0" - } - }, - "is-data-descriptor": { - "version": "0.1.4", - "resolved": "https://registry.npmjs.org/is-data-descriptor/-/is-data-descriptor-0.1.4.tgz", - "integrity": "sha1-C17mSDiOLIYCgueT8YVv7D8wG1Y=", - "dev": true, - "requires": { - "kind-of": "^3.0.2" - }, - "dependencies": { - "is-buffer": { - "version": "1.1.6", - "resolved": "https://registry.npmjs.org/is-buffer/-/is-buffer-1.1.6.tgz", - "integrity": "sha512-NcdALwpXkTm5Zvvbk7owOUSvVvBKDgKP5/ewfXEznmQFfs4ZRmanOeKBTjRVjka3QFoN6XJ+9F3USqfHqTaU5w==", - "dev": true - }, - "kind-of": { - "version": "3.2.2", - "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-3.2.2.tgz", - "integrity": "sha1-MeohpzS6ubuw8yRm2JOupR5KPGQ=", - "dev": true, - "requires": { - "is-buffer": "^1.1.5" - } - } - } - }, - "is-date-object": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/is-date-object/-/is-date-object-1.0.1.tgz", - "integrity": "sha1-mqIOtq7rv/d/vTPnTKAbM1gdOhY=", - "dev": true - }, - "is-descriptor": { - "version": "0.1.6", - "resolved": "https://registry.npmjs.org/is-descriptor/-/is-descriptor-0.1.6.tgz", - "integrity": "sha512-avDYr0SB3DwO9zsMov0gKCESFYqCnE4hq/4z3TdUlukEy5t9C0YRq7HLrsN52NAcqXKaepeCD0n+B0arnVG3Hg==", - "dev": true, - "requires": { - "is-accessor-descriptor": "^0.1.6", - "is-data-descriptor": "^0.1.4", - "kind-of": "^5.0.0" - }, - "dependencies": { - "kind-of": { - "version": "5.1.0", - "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-5.1.0.tgz", - "integrity": "sha512-NGEErnH6F2vUuXDh+OlbcKW7/wOcfdRHaZ7VWtqCztfHri/++YKmP51OdWeGPuqCOba6kk2OTe5d02VmTB80Pw==", - "dev": true - } - } - }, - "is-directory": { - "version": "0.3.1", - "resolved": "https://registry.npmjs.org/is-directory/-/is-directory-0.3.1.tgz", - "integrity": "sha1-YTObbyR1/Hcv2cnYP1yFddwVSuE=", - "dev": true - }, - "is-extendable": { - "version": "0.1.1", - "resolved": "https://registry.npmjs.org/is-extendable/-/is-extendable-0.1.1.tgz", - "integrity": "sha1-YrEQ4omkcUGOPsNqYX1HLjAd/Ik=", - "dev": true - }, - "is-fullwidth-code-point": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-2.0.0.tgz", - "integrity": "sha1-o7MKXE8ZkYMWeqq5O+764937ZU8=", - "dev": true - }, - "is-generator-fn": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/is-generator-fn/-/is-generator-fn-2.1.0.tgz", - "integrity": "sha512-cTIB4yPYL/Grw0EaSzASzg6bBy9gqCofvWN8okThAYIxKJZC+udlRAmGbM0XLeniEJSs8uEgHPGuHSe1XsOLSQ==", - "dev": true - }, - "is-number": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/is-number/-/is-number-3.0.0.tgz", - "integrity": "sha1-JP1iAaR4LPUFYcgQJ2r8fRLXEZU=", - "dev": true, - "requires": { - "kind-of": "^3.0.2" - }, - "dependencies": { - "is-buffer": { - "version": "1.1.6", - "resolved": "https://registry.npmjs.org/is-buffer/-/is-buffer-1.1.6.tgz", - "integrity": "sha512-NcdALwpXkTm5Zvvbk7owOUSvVvBKDgKP5/ewfXEznmQFfs4ZRmanOeKBTjRVjka3QFoN6XJ+9F3USqfHqTaU5w==", - "dev": true - }, - "kind-of": { - "version": "3.2.2", - "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-3.2.2.tgz", - "integrity": "sha1-MeohpzS6ubuw8yRm2JOupR5KPGQ=", - "dev": true, - "requires": { - "is-buffer": "^1.1.5" - } - } - } - }, - "is-plain-object": { - "version": "2.0.4", - "resolved": "https://registry.npmjs.org/is-plain-object/-/is-plain-object-2.0.4.tgz", - "integrity": "sha512-h5PpgXkWitc38BBMYawTYMWJHFZJVnBquFE57xFpjB8pJFiF6gZ+bU+WyI/yqXiFR5mdLsgYNaPe8uao6Uv9Og==", - "dev": true, - "requires": { - "isobject": "^3.0.1" - } - }, - "is-regex": { - "version": "1.0.4", - "resolved": "https://registry.npmjs.org/is-regex/-/is-regex-1.0.4.tgz", - "integrity": "sha1-VRdIm1RwkbCTDglWVM7SXul+lJE=", - "dev": true, - "requires": { - "has": "^1.0.1" - } - }, - "is-stream": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/is-stream/-/is-stream-1.1.0.tgz", - "integrity": "sha1-EtSj3U5o4Lec6428hBc66A2RykQ=", - "dev": true - }, - "is-symbol": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/is-symbol/-/is-symbol-1.0.2.tgz", - "integrity": "sha512-HS8bZ9ox60yCJLH9snBpIwv9pYUAkcuLhSA1oero1UB5y9aiQpRA8y2ex945AOtCZL1lJDeIk3G5LthswI46Lw==", - "dev": true, - "requires": { - "has-symbols": "^1.0.0" - } - }, - "is-typedarray": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/is-typedarray/-/is-typedarray-1.0.0.tgz", - "integrity": "sha1-5HnICFjfDBsR3dppQPlgEfzaSpo=", - "dev": true - }, - "is-windows": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/is-windows/-/is-windows-1.0.2.tgz", - "integrity": "sha512-eXK1UInq2bPmjyX6e3VHIzMLobc4J94i4AWn+Hpq3OU5KkrRC96OAcR3PRJ/pGu6m8TRnBHP9dkXQVsT/COVIA==", - "dev": true - }, - "is-wsl": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/is-wsl/-/is-wsl-1.1.0.tgz", - "integrity": "sha1-HxbkqiKwTRM2tmGIpmrzxgDDpm0=", - "dev": true - }, - "isarray": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/isarray/-/isarray-1.0.0.tgz", - "integrity": "sha1-u5NdSFgsuhaMBoNJV6VKPgcSTxE=", - "dev": true - }, - "isexe": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/isexe/-/isexe-2.0.0.tgz", - "integrity": "sha1-6PvzdNxVb/iUehDcsFctYz8s+hA=", - "dev": true - }, - "isobject": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/isobject/-/isobject-3.0.1.tgz", - "integrity": "sha1-TkMekrEalzFjaqH5yNHMvP2reN8=", - "dev": true - }, - "isstream": { - "version": "0.1.2", - "resolved": "https://registry.npmjs.org/isstream/-/isstream-0.1.2.tgz", - "integrity": "sha1-R+Y/evVa+m+S4VAOaQ64uFKcCZo=", - "dev": true - }, - "istanbul-lib-coverage": { - "version": "2.0.5", - "resolved": "https://registry.npmjs.org/istanbul-lib-coverage/-/istanbul-lib-coverage-2.0.5.tgz", - "integrity": "sha512-8aXznuEPCJvGnMSRft4udDRDtb1V3pkQkMMI5LI+6HuQz5oQ4J2UFn1H82raA3qJtyOLkkwVqICBQkjnGtn5mA==", - "dev": true - }, - "istanbul-lib-instrument": { - "version": "3.3.0", - "resolved": "https://registry.npmjs.org/istanbul-lib-instrument/-/istanbul-lib-instrument-3.3.0.tgz", - "integrity": "sha512-5nnIN4vo5xQZHdXno/YDXJ0G+I3dAm4XgzfSVTPLQpj/zAV2dV6Juy0yaf10/zrJOJeHoN3fraFe+XRq2bFVZA==", - "dev": true, - "requires": { - "@babel/generator": "^7.4.0", - "@babel/parser": "^7.4.3", - "@babel/template": "^7.4.0", - "@babel/traverse": "^7.4.3", - "@babel/types": "^7.4.0", - "istanbul-lib-coverage": "^2.0.5", - "semver": "^6.0.0" - }, - "dependencies": { - "semver": { - "version": "6.3.0", - "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.0.tgz", - "integrity": "sha512-b39TBaTSfV6yBrapU89p5fKekE2m/NwnDocOVruQFS1/veMgdzuPcnOM34M6CwxW8jH/lxEa5rBoDeUwu5HHTw==", - "dev": true - } - } - }, - "istanbul-lib-report": { - "version": "2.0.8", - "resolved": "https://registry.npmjs.org/istanbul-lib-report/-/istanbul-lib-report-2.0.8.tgz", - "integrity": "sha512-fHBeG573EIihhAblwgxrSenp0Dby6tJMFR/HvlerBsrCTD5bkUuoNtn3gVh29ZCS824cGGBPn7Sg7cNk+2xUsQ==", - "dev": true, - "requires": { - "istanbul-lib-coverage": "^2.0.5", - "make-dir": "^2.1.0", - "supports-color": "^6.1.0" - }, - "dependencies": { - "supports-color": { - "version": "6.1.0", - "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-6.1.0.tgz", - "integrity": "sha512-qe1jfm1Mg7Nq/NSh6XE24gPXROEVsWHxC1LIx//XNlD9iw7YZQGjZNjYN7xGaEG6iKdA8EtNFW6R0gjnVXp+wQ==", - "dev": true, - "requires": { - "has-flag": "^3.0.0" - } - } - } - }, - "istanbul-lib-source-maps": { - "version": "3.0.6", - "resolved": "https://registry.npmjs.org/istanbul-lib-source-maps/-/istanbul-lib-source-maps-3.0.6.tgz", - "integrity": "sha512-R47KzMtDJH6X4/YW9XTx+jrLnZnscW4VpNN+1PViSYTejLVPWv7oov+Duf8YQSPyVRUvueQqz1TcsC6mooZTXw==", - "dev": true, - "requires": { - "debug": "^4.1.1", - "istanbul-lib-coverage": "^2.0.5", - "make-dir": "^2.1.0", - "rimraf": "^2.6.3", - "source-map": "^0.6.1" - }, - "dependencies": { - "debug": { - "version": "4.1.1", - "resolved": "https://registry.npmjs.org/debug/-/debug-4.1.1.tgz", - "integrity": "sha512-pYAIzeRo8J6KPEaJ0VWOh5Pzkbw/RetuzehGM7QRRX5he4fPHx2rdKMB256ehJCkX+XRQm16eZLqLNS8RSZXZw==", - "dev": true, - "requires": { - "ms": "^2.1.1" - } - }, - "ms": { - "version": "2.1.2", - "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz", - "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==", - "dev": true - } - } - }, - "istanbul-reports": { - "version": "2.2.6", - "resolved": "https://registry.npmjs.org/istanbul-reports/-/istanbul-reports-2.2.6.tgz", - "integrity": "sha512-SKi4rnMyLBKe0Jy2uUdx28h8oG7ph2PPuQPvIAh31d+Ci+lSiEu4C+h3oBPuJ9+mPKhOyW0M8gY4U5NM1WLeXA==", - "dev": true, - "requires": { - "handlebars": "^4.1.2" - } - }, - "jest": { - "version": "24.9.0", - "resolved": "https://registry.npmjs.org/jest/-/jest-24.9.0.tgz", - "integrity": "sha512-YvkBL1Zm7d2B1+h5fHEOdyjCG+sGMz4f8D86/0HiqJ6MB4MnDc8FgP5vdWsGnemOQro7lnYo8UakZ3+5A0jxGw==", - "dev": true, - "requires": { - "import-local": "^2.0.0", - "jest-cli": "^24.9.0" - }, - "dependencies": { - "jest-cli": { - "version": "24.9.0", - "resolved": "https://registry.npmjs.org/jest-cli/-/jest-cli-24.9.0.tgz", - "integrity": "sha512-+VLRKyitT3BWoMeSUIHRxV/2g8y9gw91Jh5z2UmXZzkZKpbC08CSehVxgHUwTpy+HwGcns/tqafQDJW7imYvGg==", - "dev": true, - "requires": { - "@jest/core": "^24.9.0", - "@jest/test-result": "^24.9.0", - "@jest/types": "^24.9.0", - "chalk": "^2.0.1", - "exit": "^0.1.2", - "import-local": "^2.0.0", - "is-ci": "^2.0.0", - "jest-config": "^24.9.0", - "jest-util": "^24.9.0", - "jest-validate": "^24.9.0", - "prompts": "^2.0.1", - "realpath-native": "^1.1.0", - "yargs": "^13.3.0" - } - } - } - }, - "jest-changed-files": { - "version": "24.9.0", - "resolved": "https://registry.npmjs.org/jest-changed-files/-/jest-changed-files-24.9.0.tgz", - "integrity": "sha512-6aTWpe2mHF0DhL28WjdkO8LyGjs3zItPET4bMSeXU6T3ub4FPMw+mcOcbdGXQOAfmLcxofD23/5Bl9Z4AkFwqg==", - "dev": true, - "requires": { - "@jest/types": "^24.9.0", - "execa": "^1.0.0", - "throat": "^4.0.0" - } - }, - "jest-config": { - "version": "24.9.0", - "resolved": "https://registry.npmjs.org/jest-config/-/jest-config-24.9.0.tgz", - "integrity": "sha512-RATtQJtVYQrp7fvWg6f5y3pEFj9I+H8sWw4aKxnDZ96mob5i5SD6ZEGWgMLXQ4LE8UurrjbdlLWdUeo+28QpfQ==", - "dev": true, - "requires": { - "@babel/core": "^7.1.0", - "@jest/test-sequencer": "^24.9.0", - "@jest/types": "^24.9.0", - "babel-jest": "^24.9.0", - "chalk": "^2.0.1", - "glob": "^7.1.1", - "jest-environment-jsdom": "^24.9.0", - "jest-environment-node": "^24.9.0", - "jest-get-type": "^24.9.0", - "jest-jasmine2": "^24.9.0", - "jest-regex-util": "^24.3.0", - "jest-resolve": "^24.9.0", - "jest-util": "^24.9.0", - "jest-validate": "^24.9.0", - "micromatch": "^3.1.10", - "pretty-format": "^24.9.0", - "realpath-native": "^1.1.0" - } - }, - "jest-diff": { - "version": "24.9.0", - "resolved": "https://registry.npmjs.org/jest-diff/-/jest-diff-24.9.0.tgz", - "integrity": "sha512-qMfrTs8AdJE2iqrTp0hzh7kTd2PQWrsFyj9tORoKmu32xjPjeE4NyjVRDz8ybYwqS2ik8N4hsIpiVTyFeo2lBQ==", - "dev": true, - "requires": { - "chalk": "^2.0.1", - "diff-sequences": "^24.9.0", - "jest-get-type": "^24.9.0", - "pretty-format": "^24.9.0" - } - }, - "jest-docblock": { - "version": "24.9.0", - "resolved": "https://registry.npmjs.org/jest-docblock/-/jest-docblock-24.9.0.tgz", - "integrity": "sha512-F1DjdpDMJMA1cN6He0FNYNZlo3yYmOtRUnktrT9Q37njYzC5WEaDdmbynIgy0L/IvXvvgsG8OsqhLPXTpfmZAA==", - "dev": true, - "requires": { - "detect-newline": "^2.1.0" - } - }, - "jest-each": { - "version": "24.9.0", - "resolved": "https://registry.npmjs.org/jest-each/-/jest-each-24.9.0.tgz", - "integrity": "sha512-ONi0R4BvW45cw8s2Lrx8YgbeXL1oCQ/wIDwmsM3CqM/nlblNCPmnC3IPQlMbRFZu3wKdQ2U8BqM6lh3LJ5Bsog==", - "dev": true, - "requires": { - "@jest/types": "^24.9.0", - "chalk": "^2.0.1", - "jest-get-type": "^24.9.0", - "jest-util": "^24.9.0", - "pretty-format": "^24.9.0" - } - }, - "jest-environment-jsdom": { - "version": "24.9.0", - "resolved": "https://registry.npmjs.org/jest-environment-jsdom/-/jest-environment-jsdom-24.9.0.tgz", - "integrity": "sha512-Zv9FV9NBRzLuALXjvRijO2351DRQeLYXtpD4xNvfoVFw21IOKNhZAEUKcbiEtjTkm2GsJ3boMVgkaR7rN8qetA==", - "dev": true, - "requires": { - "@jest/environment": "^24.9.0", - "@jest/fake-timers": "^24.9.0", - "@jest/types": "^24.9.0", - "jest-mock": "^24.9.0", - "jest-util": "^24.9.0", - "jsdom": "^11.5.1" - } - }, - "jest-environment-node": { - "version": "24.9.0", - "resolved": "https://registry.npmjs.org/jest-environment-node/-/jest-environment-node-24.9.0.tgz", - "integrity": "sha512-6d4V2f4nxzIzwendo27Tr0aFm+IXWa0XEUnaH6nU0FMaozxovt+sfRvh4J47wL1OvF83I3SSTu0XK+i4Bqe7uA==", - "dev": true, - "requires": { - "@jest/environment": "^24.9.0", - "@jest/fake-timers": "^24.9.0", - "@jest/types": "^24.9.0", - "jest-mock": "^24.9.0", - "jest-util": "^24.9.0" - } - }, - "jest-get-type": { - "version": "24.9.0", - "resolved": "https://registry.npmjs.org/jest-get-type/-/jest-get-type-24.9.0.tgz", - "integrity": "sha512-lUseMzAley4LhIcpSP9Jf+fTrQ4a1yHQwLNeeVa2cEmbCGeoZAtYPOIv8JaxLD/sUpKxetKGP+gsHl8f8TSj8Q==", - "dev": true - }, - "jest-haste-map": { - "version": "24.9.0", - "resolved": "https://registry.npmjs.org/jest-haste-map/-/jest-haste-map-24.9.0.tgz", - "integrity": "sha512-kfVFmsuWui2Sj1Rp1AJ4D9HqJwE4uwTlS/vO+eRUaMmd54BFpli2XhMQnPC2k4cHFVbB2Q2C+jtI1AGLgEnCjQ==", - "dev": true, - "requires": { - "@jest/types": "^24.9.0", - "anymatch": "^2.0.0", - "fb-watchman": "^2.0.0", - "fsevents": "^1.2.7", - "graceful-fs": "^4.1.15", - "invariant": "^2.2.4", - "jest-serializer": "^24.9.0", - "jest-util": "^24.9.0", - "jest-worker": "^24.9.0", - "micromatch": "^3.1.10", - "sane": "^4.0.3", - "walker": "^1.0.7" - } - }, - "jest-jasmine2": { - "version": "24.9.0", - "resolved": "https://registry.npmjs.org/jest-jasmine2/-/jest-jasmine2-24.9.0.tgz", - "integrity": "sha512-Cq7vkAgaYKp+PsX+2/JbTarrk0DmNhsEtqBXNwUHkdlbrTBLtMJINADf2mf5FkowNsq8evbPc07/qFO0AdKTzw==", - "dev": true, - "requires": { - "@babel/traverse": "^7.1.0", - "@jest/environment": "^24.9.0", - "@jest/test-result": "^24.9.0", - "@jest/types": "^24.9.0", - "chalk": "^2.0.1", - "co": "^4.6.0", - "expect": "^24.9.0", - "is-generator-fn": "^2.0.0", - "jest-each": "^24.9.0", - "jest-matcher-utils": "^24.9.0", - "jest-message-util": "^24.9.0", - "jest-runtime": "^24.9.0", - "jest-snapshot": "^24.9.0", - "jest-util": "^24.9.0", - "pretty-format": "^24.9.0", - "throat": "^4.0.0" - } - }, - "jest-leak-detector": { - "version": "24.9.0", - "resolved": "https://registry.npmjs.org/jest-leak-detector/-/jest-leak-detector-24.9.0.tgz", - "integrity": "sha512-tYkFIDsiKTGwb2FG1w8hX9V0aUb2ot8zY/2nFg087dUageonw1zrLMP4W6zsRO59dPkTSKie+D4rhMuP9nRmrA==", - "dev": true, - "requires": { - "jest-get-type": "^24.9.0", - "pretty-format": "^24.9.0" - } - }, - "jest-matcher-utils": { - "version": "24.9.0", - "resolved": "https://registry.npmjs.org/jest-matcher-utils/-/jest-matcher-utils-24.9.0.tgz", - "integrity": "sha512-OZz2IXsu6eaiMAwe67c1T+5tUAtQyQx27/EMEkbFAGiw52tB9em+uGbzpcgYVpA8wl0hlxKPZxrly4CXU/GjHA==", - "dev": true, - "requires": { - "chalk": "^2.0.1", - "jest-diff": "^24.9.0", - "jest-get-type": "^24.9.0", - "pretty-format": "^24.9.0" - } - }, - "jest-message-util": { - "version": "24.9.0", - "resolved": "https://registry.npmjs.org/jest-message-util/-/jest-message-util-24.9.0.tgz", - "integrity": "sha512-oCj8FiZ3U0hTP4aSui87P4L4jC37BtQwUMqk+zk/b11FR19BJDeZsZAvIHutWnmtw7r85UmR3CEWZ0HWU2mAlw==", - "dev": true, - "requires": { - "@babel/code-frame": "^7.0.0", - "@jest/test-result": "^24.9.0", - "@jest/types": "^24.9.0", - "@types/stack-utils": "^1.0.1", - "chalk": "^2.0.1", - "micromatch": "^3.1.10", - "slash": "^2.0.0", - "stack-utils": "^1.0.1" - } - }, - "jest-mock": { - "version": "24.9.0", - "resolved": "https://registry.npmjs.org/jest-mock/-/jest-mock-24.9.0.tgz", - "integrity": "sha512-3BEYN5WbSq9wd+SyLDES7AHnjH9A/ROBwmz7l2y+ol+NtSFO8DYiEBzoO1CeFc9a8DYy10EO4dDFVv/wN3zl1w==", - "dev": true, - "requires": { - "@jest/types": "^24.9.0" - } - }, - "jest-pnp-resolver": { - "version": "1.2.1", - "resolved": "https://registry.npmjs.org/jest-pnp-resolver/-/jest-pnp-resolver-1.2.1.tgz", - "integrity": "sha512-pgFw2tm54fzgYvc/OHrnysABEObZCUNFnhjoRjaVOCN8NYc032/gVjPaHD4Aq6ApkSieWtfKAFQtmDKAmhupnQ==", - "dev": true - }, - "jest-regex-util": { - "version": "24.9.0", - "resolved": "https://registry.npmjs.org/jest-regex-util/-/jest-regex-util-24.9.0.tgz", - "integrity": "sha512-05Cmb6CuxaA+Ys6fjr3PhvV3bGQmO+2p2La4hFbU+W5uOc479f7FdLXUWXw4pYMAhhSZIuKHwSXSu6CsSBAXQA==", - "dev": true - }, - "jest-resolve": { - "version": "24.9.0", - "resolved": "https://registry.npmjs.org/jest-resolve/-/jest-resolve-24.9.0.tgz", - "integrity": "sha512-TaLeLVL1l08YFZAt3zaPtjiVvyy4oSA6CRe+0AFPPVX3Q/VI0giIWWoAvoS5L96vj9Dqxj4fB5p2qrHCmTU/MQ==", - "dev": true, - "requires": { - "@jest/types": "^24.9.0", - "browser-resolve": "^1.11.3", - "chalk": "^2.0.1", - "jest-pnp-resolver": "^1.2.1", - "realpath-native": "^1.1.0" - } - }, - "jest-resolve-dependencies": { - "version": "24.9.0", - "resolved": "https://registry.npmjs.org/jest-resolve-dependencies/-/jest-resolve-dependencies-24.9.0.tgz", - "integrity": "sha512-Fm7b6AlWnYhT0BXy4hXpactHIqER7erNgIsIozDXWl5dVm+k8XdGVe1oTg1JyaFnOxarMEbax3wyRJqGP2Pq+g==", - "dev": true, - "requires": { - "@jest/types": "^24.9.0", - "jest-regex-util": "^24.3.0", - "jest-snapshot": "^24.9.0" - } - }, - "jest-runner": { - "version": "24.9.0", - "resolved": "https://registry.npmjs.org/jest-runner/-/jest-runner-24.9.0.tgz", - "integrity": "sha512-KksJQyI3/0mhcfspnxxEOBueGrd5E4vV7ADQLT9ESaCzz02WnbdbKWIf5Mkaucoaj7obQckYPVX6JJhgUcoWWg==", - "dev": true, - "requires": { - "@jest/console": "^24.7.1", - "@jest/environment": "^24.9.0", - "@jest/test-result": "^24.9.0", - "@jest/types": "^24.9.0", - "chalk": "^2.4.2", - "exit": "^0.1.2", - "graceful-fs": "^4.1.15", - "jest-config": "^24.9.0", - "jest-docblock": "^24.3.0", - "jest-haste-map": "^24.9.0", - "jest-jasmine2": "^24.9.0", - "jest-leak-detector": "^24.9.0", - "jest-message-util": "^24.9.0", - "jest-resolve": "^24.9.0", - "jest-runtime": "^24.9.0", - "jest-util": "^24.9.0", - "jest-worker": "^24.6.0", - "source-map-support": "^0.5.6", - "throat": "^4.0.0" - } - }, - "jest-runtime": { - "version": "24.9.0", - "resolved": "https://registry.npmjs.org/jest-runtime/-/jest-runtime-24.9.0.tgz", - "integrity": "sha512-8oNqgnmF3v2J6PVRM2Jfuj8oX3syKmaynlDMMKQ4iyzbQzIG6th5ub/lM2bCMTmoTKM3ykcUYI2Pw9xwNtjMnw==", - "dev": true, - "requires": { - "@jest/console": "^24.7.1", - "@jest/environment": "^24.9.0", - "@jest/source-map": "^24.3.0", - "@jest/transform": "^24.9.0", - "@jest/types": "^24.9.0", - "@types/yargs": "^13.0.0", - "chalk": "^2.0.1", - "exit": "^0.1.2", - "glob": "^7.1.3", - "graceful-fs": "^4.1.15", - "jest-config": "^24.9.0", - "jest-haste-map": "^24.9.0", - "jest-message-util": "^24.9.0", - "jest-mock": "^24.9.0", - "jest-regex-util": "^24.3.0", - "jest-resolve": "^24.9.0", - "jest-snapshot": "^24.9.0", - "jest-util": "^24.9.0", - "jest-validate": "^24.9.0", - "realpath-native": "^1.1.0", - "slash": "^2.0.0", - "strip-bom": "^3.0.0", - "yargs": "^13.3.0" - } - }, - "jest-serializer": { - "version": "24.9.0", - "resolved": "https://registry.npmjs.org/jest-serializer/-/jest-serializer-24.9.0.tgz", - "integrity": "sha512-DxYipDr8OvfrKH3Kel6NdED3OXxjvxXZ1uIY2I9OFbGg+vUkkg7AGvi65qbhbWNPvDckXmzMPbK3u3HaDO49bQ==", - "dev": true - }, - "jest-snapshot": { - "version": "24.9.0", - "resolved": "https://registry.npmjs.org/jest-snapshot/-/jest-snapshot-24.9.0.tgz", - "integrity": "sha512-uI/rszGSs73xCM0l+up7O7a40o90cnrk429LOiK3aeTvfC0HHmldbd81/B7Ix81KSFe1lwkbl7GnBGG4UfuDew==", - "dev": true, - "requires": { - "@babel/types": "^7.0.0", - "@jest/types": "^24.9.0", - "chalk": "^2.0.1", - "expect": "^24.9.0", - "jest-diff": "^24.9.0", - "jest-get-type": "^24.9.0", - "jest-matcher-utils": "^24.9.0", - "jest-message-util": "^24.9.0", - "jest-resolve": "^24.9.0", - "mkdirp": "^0.5.1", - "natural-compare": "^1.4.0", - "pretty-format": "^24.9.0", - "semver": "^6.2.0" - }, - "dependencies": { - "semver": { - "version": "6.3.0", - "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.0.tgz", - "integrity": "sha512-b39TBaTSfV6yBrapU89p5fKekE2m/NwnDocOVruQFS1/veMgdzuPcnOM34M6CwxW8jH/lxEa5rBoDeUwu5HHTw==", - "dev": true - } - } - }, - "jest-util": { - "version": "24.9.0", - "resolved": "https://registry.npmjs.org/jest-util/-/jest-util-24.9.0.tgz", - "integrity": "sha512-x+cZU8VRmOJxbA1K5oDBdxQmdq0OIdADarLxk0Mq+3XS4jgvhG/oKGWcIDCtPG0HgjxOYvF+ilPJQsAyXfbNOg==", - "dev": true, - "requires": { - "@jest/console": "^24.9.0", - "@jest/fake-timers": "^24.9.0", - "@jest/source-map": "^24.9.0", - "@jest/test-result": "^24.9.0", - "@jest/types": "^24.9.0", - "callsites": "^3.0.0", - "chalk": "^2.0.1", - "graceful-fs": "^4.1.15", - "is-ci": "^2.0.0", - "mkdirp": "^0.5.1", - "slash": "^2.0.0", - "source-map": "^0.6.0" - } - }, - "jest-validate": { - "version": "24.9.0", - "resolved": "https://registry.npmjs.org/jest-validate/-/jest-validate-24.9.0.tgz", - "integrity": "sha512-HPIt6C5ACwiqSiwi+OfSSHbK8sG7akG8eATl+IPKaeIjtPOeBUd/g3J7DghugzxrGjI93qS/+RPKe1H6PqvhRQ==", - "dev": true, - "requires": { - "@jest/types": "^24.9.0", - "camelcase": "^5.3.1", - "chalk": "^2.0.1", - "jest-get-type": "^24.9.0", - "leven": "^3.1.0", - "pretty-format": "^24.9.0" - } - }, - "jest-watcher": { - "version": "24.9.0", - "resolved": "https://registry.npmjs.org/jest-watcher/-/jest-watcher-24.9.0.tgz", - "integrity": "sha512-+/fLOfKPXXYJDYlks62/4R4GoT+GU1tYZed99JSCOsmzkkF7727RqKrjNAxtfO4YpGv11wybgRvCjR73lK2GZw==", - "dev": true, - "requires": { - "@jest/test-result": "^24.9.0", - "@jest/types": "^24.9.0", - "@types/yargs": "^13.0.0", - "ansi-escapes": "^3.0.0", - "chalk": "^2.0.1", - "jest-util": "^24.9.0", - "string-length": "^2.0.0" - } - }, - "jest-worker": { - "version": "24.9.0", - "resolved": "https://registry.npmjs.org/jest-worker/-/jest-worker-24.9.0.tgz", - "integrity": "sha512-51PE4haMSXcHohnSMdM42anbvZANYTqMrr52tVKPqqsPJMzoP6FYYDVqahX/HrAoKEKz3uUPzSvKs9A3qR4iVw==", - "dev": true, - "requires": { - "merge-stream": "^2.0.0", - "supports-color": "^6.1.0" - }, - "dependencies": { - "supports-color": { - "version": "6.1.0", - "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-6.1.0.tgz", - "integrity": "sha512-qe1jfm1Mg7Nq/NSh6XE24gPXROEVsWHxC1LIx//XNlD9iw7YZQGjZNjYN7xGaEG6iKdA8EtNFW6R0gjnVXp+wQ==", - "dev": true, - "requires": { - "has-flag": "^3.0.0" - } - } - } - }, - "js-tokens": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/js-tokens/-/js-tokens-4.0.0.tgz", - "integrity": "sha512-RdJUflcE3cUzKiMqQgsCu06FPu9UdIJO0beYbPhHN4k6apgJtifcoCtT9bcxOpYBtpD2kCM6Sbzg4CausW/PKQ==", - "dev": true - }, - "js-yaml": { - "version": "3.13.1", - "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-3.13.1.tgz", - "integrity": "sha512-YfbcO7jXDdyj0DGxYVSlSeQNHbD7XPWvrVWeVUujrQEoZzWJIRrCPoyk6kL6IAjAG2IolMK4T0hNUe0HOUs5Jw==", - "dev": true, - "requires": { - "argparse": "^1.0.7", - "esprima": "^4.0.0" - }, - "dependencies": { - "esprima": { - "version": "4.0.1", - "resolved": "https://registry.npmjs.org/esprima/-/esprima-4.0.1.tgz", - "integrity": "sha512-eGuFFw7Upda+g4p+QHvnW0RyTX/SVeJBDM/gCtMARO0cLuT2HcEKnTPvhjV6aGeqrCB/sbNop0Kszm0jsaWU4A==", - "dev": true - } - } - }, - "jsbn": { - "version": "0.1.1", - "resolved": "https://registry.npmjs.org/jsbn/-/jsbn-0.1.1.tgz", - "integrity": "sha1-peZUwuWi3rXyAdls77yoDA7y9RM=", - "dev": true - }, - "jsdom": { - "version": "11.12.0", - "resolved": "https://registry.npmjs.org/jsdom/-/jsdom-11.12.0.tgz", - "integrity": "sha512-y8Px43oyiBM13Zc1z780FrfNLJCXTL40EWlty/LXUtcjykRBNgLlCjWXpfSPBl2iv+N7koQN+dvqszHZgT/Fjw==", - "dev": true, - "requires": { - "abab": "^2.0.0", - "acorn": "^5.5.3", - "acorn-globals": "^4.1.0", - "array-equal": "^1.0.0", - "cssom": ">= 0.3.2 < 0.4.0", - "cssstyle": "^1.0.0", - "data-urls": "^1.0.0", - "domexception": "^1.0.1", - "escodegen": "^1.9.1", - "html-encoding-sniffer": "^1.0.2", - "left-pad": "^1.3.0", - "nwsapi": "^2.0.7", - "parse5": "4.0.0", - "pn": "^1.1.0", - "request": "^2.87.0", - "request-promise-native": "^1.0.5", - "sax": "^1.2.4", - "symbol-tree": "^3.2.2", - "tough-cookie": "^2.3.4", - "w3c-hr-time": "^1.0.1", - "webidl-conversions": "^4.0.2", - "whatwg-encoding": "^1.0.3", - "whatwg-mimetype": "^2.1.0", - "whatwg-url": "^6.4.1", - "ws": "^5.2.0", - "xml-name-validator": "^3.0.0" - } - }, - "jsesc": { - "version": "2.5.2", - "resolved": "https://registry.npmjs.org/jsesc/-/jsesc-2.5.2.tgz", - "integrity": "sha512-OYu7XEzjkCQ3C5Ps3QIZsQfNpqoJyZZA99wd9aWd05NCtC5pWOkShK2mkL6HXQR6/Cy2lbNdPlZBpuQHXE63gA==", - "dev": true - }, - "json-parse-better-errors": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/json-parse-better-errors/-/json-parse-better-errors-1.0.2.tgz", - "integrity": "sha512-mrqyZKfX5EhL7hvqcV6WG1yYjnjeuYDzDhhcAAUrq8Po85NBQBJP+ZDUT75qZQ98IkUoBqdkExkukOU7Ts2wrw==", - "dev": true - }, - "json-schema": { - "version": "0.2.3", - "resolved": "https://registry.npmjs.org/json-schema/-/json-schema-0.2.3.tgz", - "integrity": "sha1-tIDIkuWaLwWVTOcnvT8qTogvnhM=", - "dev": true - }, - "json-schema-traverse": { - "version": "0.4.1", - "resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-0.4.1.tgz", - "integrity": "sha512-xbbCH5dCYU5T8LcEhhuh7HJ88HXuW3qsI3Y0zOZFKfZEHcpWiHU/Jxzk629Brsab/mMiHQti9wMP+845RPe3Vg==", - "dev": true - }, - "json-stringify-safe": { - "version": "5.0.1", - "resolved": "https://registry.npmjs.org/json-stringify-safe/-/json-stringify-safe-5.0.1.tgz", - "integrity": "sha1-Epai1Y/UXxmg9s4B1lcB4sc1tus=", - "dev": true - }, - "json5": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/json5/-/json5-2.1.0.tgz", - "integrity": "sha512-8Mh9h6xViijj36g7Dxi+Y4S6hNGV96vcJZr/SrlHh1LR/pEn/8j/+qIBbs44YKl69Lrfctp4QD+AdWLTMqEZAQ==", - "dev": true, - "requires": { - "minimist": "^1.2.0" - } - }, - "jsprim": { - "version": "1.4.1", - "resolved": "https://registry.npmjs.org/jsprim/-/jsprim-1.4.1.tgz", - "integrity": "sha1-MT5mvB5cwG5Di8G3SZwuXFastqI=", - "dev": true, - "requires": { - "assert-plus": "1.0.0", - "extsprintf": "1.3.0", - "json-schema": "0.2.3", - "verror": "1.10.0" - } - }, - "kind-of": { - "version": "6.0.2", - "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-6.0.2.tgz", - "integrity": "sha512-s5kLOcnH0XqDO+FvuaLX8DDjZ18CGFk7VygH40QoKPUQhW4e2rvM0rwUq0t8IQDOwYSeLK01U90OjzBTme2QqA==", - "dev": true - }, - "kleur": { - "version": "3.0.3", - "resolved": "https://registry.npmjs.org/kleur/-/kleur-3.0.3.tgz", - "integrity": "sha512-eTIzlVOSUR+JxdDFepEYcBMtZ9Qqdef+rnzWdRZuMbOywu5tO2w2N7rqjoANZ5k9vywhL6Br1VRjUIgTQx4E8w==", - "dev": true - }, - "left-pad": { - "version": "1.3.0", - "resolved": "https://registry.npmjs.org/left-pad/-/left-pad-1.3.0.tgz", - "integrity": "sha512-XI5MPzVNApjAyhQzphX8BkmKsKUxD4LdyK24iZeQGinBN9yTQT3bFlCBy/aVx2HrNcqQGsdot8ghrjyrvMCoEA==", - "dev": true - }, - "leven": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/leven/-/leven-3.1.0.tgz", - "integrity": "sha512-qsda+H8jTaUaN/x5vzW2rzc+8Rw4TAQ/4KjB46IwK5VH+IlVeeeje/EoZRpiXvIqjFgK84QffqPztGI3VBLG1A==", - "dev": true - }, - "levn": { - "version": "0.3.0", - "resolved": "https://registry.npmjs.org/levn/-/levn-0.3.0.tgz", - "integrity": "sha1-OwmSTt+fCDwEkP3UwLxEIeBHZO4=", - "dev": true, - "requires": { - "prelude-ls": "~1.1.2", - "type-check": "~0.3.2" - } - }, - "lines-and-columns": { - "version": "1.1.6", - "resolved": "https://registry.npmjs.org/lines-and-columns/-/lines-and-columns-1.1.6.tgz", - "integrity": "sha1-HADHQ7QzzQpOgHWPe2SldEDZ/wA=", - "dev": true - }, - "load-json-file": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/load-json-file/-/load-json-file-4.0.0.tgz", - "integrity": "sha1-L19Fq5HjMhYjT9U62rZo607AmTs=", - "dev": true, - "requires": { - "graceful-fs": "^4.1.2", - "parse-json": "^4.0.0", - "pify": "^3.0.0", - "strip-bom": "^3.0.0" - } - }, - "locate-path": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-3.0.0.tgz", - "integrity": "sha512-7AO748wWnIhNqAuaty2ZWHkQHRSNfPVIsPIfwEOWO22AmaoVrWavlOcMR5nzTLNYvp36X220/maaRsrec1G65A==", - "dev": true, - "requires": { - "p-locate": "^3.0.0", - "path-exists": "^3.0.0" - } - }, - "lodash": { - "version": "4.17.15", - "resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.15.tgz", - "integrity": "sha512-8xOcRHvCjnocdS5cpwXQXVzmmh5e5+saE2QGoeQmbKmRS6J3VQppPOIt0MnmE+4xlZoumy0GPG0D0MVIQbNA1A==", - "dev": true - }, - "lodash.memoize": { - "version": "4.1.2", - "resolved": "https://registry.npmjs.org/lodash.memoize/-/lodash.memoize-4.1.2.tgz", - "integrity": "sha1-vMbEmkKihA7Zl/Mj6tpezRguC/4=", - "dev": true - }, - "lodash.sortby": { - "version": "4.7.0", - "resolved": "https://registry.npmjs.org/lodash.sortby/-/lodash.sortby-4.7.0.tgz", - "integrity": "sha1-7dFMgk4sycHgsKG0K7UhBRakJDg=", - "dev": true - }, - "loose-envify": { - "version": "1.4.0", - "resolved": "https://registry.npmjs.org/loose-envify/-/loose-envify-1.4.0.tgz", - "integrity": "sha512-lyuxPGr/Wfhrlem2CL/UcnUc1zcqKAImBDzukY7Y5F/yQiNdko6+fRLevlw1HgMySw7f611UIY408EtxRSoK3Q==", - "dev": true, - "requires": { - "js-tokens": "^3.0.0 || ^4.0.0" - } - }, - "make-dir": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/make-dir/-/make-dir-2.1.0.tgz", - "integrity": "sha512-LS9X+dc8KLxXCb8dni79fLIIUA5VyZoyjSMCwTluaXA0o27cCK0bhXkpgw+sTXVpPy/lSO57ilRixqk0vDmtRA==", - "dev": true, - "requires": { - "pify": "^4.0.1", - "semver": "^5.6.0" - }, - "dependencies": { - "pify": { - "version": "4.0.1", - "resolved": "https://registry.npmjs.org/pify/-/pify-4.0.1.tgz", - "integrity": "sha512-uB80kBFb/tfd68bVleG9T5GGsGPjJrLAUpR5PZIrhBnIaRTQRjqdJSsIKkOP6OAIFbj7GOrcudc5pNjZ+geV2g==", - "dev": true - } - } - }, - "make-error": { - "version": "1.3.5", - "resolved": "https://registry.npmjs.org/make-error/-/make-error-1.3.5.tgz", - "integrity": "sha512-c3sIjNUow0+8swNwVpqoH4YCShKNFkMaw6oH1mNS2haDZQqkeZFlHS3dhoeEbKKmJB4vXpJucU6oH75aDYeE9g==", - "dev": true - }, - "makeerror": { - "version": "1.0.11", - "resolved": "https://registry.npmjs.org/makeerror/-/makeerror-1.0.11.tgz", - "integrity": "sha1-4BpckQnyr3lmDk6LlYd5AYT1qWw=", - "dev": true, - "requires": { - "tmpl": "1.0.x" - } - }, - "map-cache": { - "version": "0.2.2", - "resolved": "https://registry.npmjs.org/map-cache/-/map-cache-0.2.2.tgz", - "integrity": "sha1-wyq9C9ZSXZsFFkW7TyasXcmKDb8=", - "dev": true - }, - "map-visit": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/map-visit/-/map-visit-1.0.0.tgz", - "integrity": "sha1-7Nyo8TFE5mDxtb1B8S80edmN+48=", - "dev": true, - "requires": { - "object-visit": "^1.0.0" - } - }, - "media-typer": { - "version": "0.3.0", - "resolved": "https://registry.npmjs.org/media-typer/-/media-typer-0.3.0.tgz", - "integrity": "sha1-hxDXrwqmJvj/+hzgAWhUUmMlV0g=", - "dev": true - }, - "merge-descriptors": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/merge-descriptors/-/merge-descriptors-1.0.1.tgz", - "integrity": "sha1-sAqqVW3YtEVoFQ7J0blT8/kMu2E=", - "dev": true - }, - "merge-stream": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/merge-stream/-/merge-stream-2.0.0.tgz", - "integrity": "sha512-abv/qOcuPfk3URPfDzmZU1LKmuw8kT+0nIHvKrKgFrwifol/doWcdA4ZqsWQ8ENrFKkd67Mfpo/LovbIUsbt3w==", - "dev": true - }, - "methods": { - "version": "1.1.2", - "resolved": "https://registry.npmjs.org/methods/-/methods-1.1.2.tgz", - "integrity": "sha1-VSmk1nZUE07cxSZmVoNbD4Ua/O4=", - "dev": true - }, - "micromatch": { - "version": "3.1.10", - "resolved": "https://registry.npmjs.org/micromatch/-/micromatch-3.1.10.tgz", - "integrity": "sha512-MWikgl9n9M3w+bpsY3He8L+w9eF9338xRl8IAO5viDizwSzziFEyUzo2xrrloB64ADbTf8uA8vRqqttDTOmccg==", - "dev": true, - "requires": { - "arr-diff": "^4.0.0", - "array-unique": "^0.3.2", - "braces": "^2.3.1", - "define-property": "^2.0.2", - "extend-shallow": "^3.0.2", - "extglob": "^2.0.4", - "fragment-cache": "^0.2.1", - "kind-of": "^6.0.2", - "nanomatch": "^1.2.9", - "object.pick": "^1.3.0", - "regex-not": "^1.0.0", - "snapdragon": "^0.8.1", - "to-regex": "^3.0.2" - } - }, - "mime": { - "version": "1.6.0", - "resolved": "https://registry.npmjs.org/mime/-/mime-1.6.0.tgz", - "integrity": "sha512-x0Vn8spI+wuJ1O6S7gnbaQg8Pxh4NNHb7KSINmEWKiPE4RKOplvijn+NkmYmmRgP68mc70j2EbeTFRsrswaQeg==", - "dev": true - }, - "mime-db": { - "version": "1.40.0", - "resolved": "https://registry.npmjs.org/mime-db/-/mime-db-1.40.0.tgz", - "integrity": "sha512-jYdeOMPy9vnxEqFRRo6ZvTZ8d9oPb+k18PKoYNYUe2stVEBPPwsln/qWzdbmaIvnhZ9v2P+CuecK+fpUfsV2mA==" - }, - "mime-types": { - "version": "2.1.24", - "resolved": "https://registry.npmjs.org/mime-types/-/mime-types-2.1.24.tgz", - "integrity": "sha512-WaFHS3MCl5fapm3oLxU4eYDw77IQM2ACcxQ9RIxfaC3ooc6PFuBMGZZsYpvoXS5D5QTWPieo1jjLdAm3TBP3cQ==", - "requires": { - "mime-db": "1.40.0" - } - }, - "minimatch": { - "version": "3.0.4", - "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.0.4.tgz", - "integrity": "sha512-yJHVQEhyqPLUTgt9B83PXu6W3rx4MvvHvSUvToogpwoGDOUQ+yDrR0HRot+yOCdCO7u4hX3pWft6kWBBcqh0UA==", - "dev": true, - "requires": { - "brace-expansion": "^1.1.7" - } - }, - "minimist": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/minimist/-/minimist-1.2.0.tgz", - "integrity": "sha1-o1AIsg9BOD7sH7kU9M1d95omQoQ=", - "dev": true - }, - "mixin-deep": { - "version": "1.3.2", - "resolved": "https://registry.npmjs.org/mixin-deep/-/mixin-deep-1.3.2.tgz", - "integrity": "sha512-WRoDn//mXBiJ1H40rqa3vH0toePwSsGb45iInWlTySa+Uu4k3tYUSxa2v1KqAiLtvlrSzaExqS1gtk96A9zvEA==", - "dev": true, - "requires": { - "for-in": "^1.0.2", - "is-extendable": "^1.0.1" - }, - "dependencies": { - "is-extendable": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/is-extendable/-/is-extendable-1.0.1.tgz", - "integrity": "sha512-arnXMxT1hhoKo9k1LZdmlNyJdDDfy2v0fXjFlmok4+i8ul/6WlbVge9bhM74OpNPQPMGUToDtz+KXa1PneJxOA==", - "dev": true, - "requires": { - "is-plain-object": "^2.0.4" - } - } - } - }, - "mkdirp": { - "version": "0.5.1", - "resolved": "https://registry.npmjs.org/mkdirp/-/mkdirp-0.5.1.tgz", - "integrity": "sha1-MAV0OOrGz3+MR2fzhkjWaX11yQM=", - "dev": true, - "requires": { - "minimist": "0.0.8" - }, - "dependencies": { - "minimist": { - "version": "0.0.8", - "resolved": "https://registry.npmjs.org/minimist/-/minimist-0.0.8.tgz", - "integrity": "sha1-hX/Kv8M5fSYluCKCYuhqp6ARsF0=", - "dev": true - } - } - }, - "ms": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", - "integrity": "sha1-VgiurfwAvmwpAd9fmGF4jeDVl8g=" - }, - "multer": { - "version": "1.4.2", - "resolved": "https://registry.npmjs.org/multer/-/multer-1.4.2.tgz", - "integrity": "sha512-xY8pX7V+ybyUpbYMxtjM9KAiD9ixtg5/JkeKUTD6xilfDv0vzzOFcCp4Ljb1UU3tSOM3VTZtKo63OmzOrGi3Cg==", - "dev": true, - "requires": { - "append-field": "^1.0.0", - "busboy": "^0.2.11", - "concat-stream": "^1.5.2", - "mkdirp": "^0.5.1", - "object-assign": "^4.1.1", - "on-finished": "^2.3.0", - "type-is": "^1.6.4", - "xtend": "^4.0.0" - } - }, - "nan": { - "version": "2.14.0", - "resolved": "https://registry.npmjs.org/nan/-/nan-2.14.0.tgz", - "integrity": "sha512-INOFj37C7k3AfaNTtX8RhsTw7qRy7eLET14cROi9+5HAVbbHuIWUHEauBv5qT4Av2tWasiTY1Jw6puUNqRJXQg==", - "dev": true, - "optional": true - }, - "nanomatch": { - "version": "1.2.13", - "resolved": "https://registry.npmjs.org/nanomatch/-/nanomatch-1.2.13.tgz", - "integrity": "sha512-fpoe2T0RbHwBTBUOftAfBPaDEi06ufaUai0mE6Yn1kacc3SnTErfb/h+X94VXzI64rKFHYImXSvdwGGCmwOqCA==", - "dev": true, - "requires": { - "arr-diff": "^4.0.0", - "array-unique": "^0.3.2", - "define-property": "^2.0.2", - "extend-shallow": "^3.0.2", - "fragment-cache": "^0.2.1", - "is-windows": "^1.0.2", - "kind-of": "^6.0.2", - "object.pick": "^1.3.0", - "regex-not": "^1.0.0", - "snapdragon": "^0.8.1", - "to-regex": "^3.0.1" - } - }, - "natural-compare": { - "version": "1.4.0", - "resolved": "https://registry.npmjs.org/natural-compare/-/natural-compare-1.4.0.tgz", - "integrity": "sha1-Sr6/7tdUHywnrPspvbvRXI1bpPc=", - "dev": true - }, - "negotiator": { - "version": "0.6.2", - "resolved": "https://registry.npmjs.org/negotiator/-/negotiator-0.6.2.tgz", - "integrity": "sha512-hZXc7K2e+PgeI1eDBe/10Ard4ekbfrrqG8Ep+8Jmf4JID2bNg7NvCPOZN+kfF574pFQI7mum2AUqDidoKqcTOw==", - "dev": true - }, - "neo-async": { - "version": "2.6.1", - "resolved": "https://registry.npmjs.org/neo-async/-/neo-async-2.6.1.tgz", - "integrity": "sha512-iyam8fBuCUpWeKPGpaNMetEocMt364qkCsfL9JuhjXX6dRnguRVOfk2GZaDpPjcOKiiXCPINZC1GczQ7iTq3Zw==", - "dev": true - }, - "nice-try": { - "version": "1.0.5", - "resolved": "https://registry.npmjs.org/nice-try/-/nice-try-1.0.5.tgz", - "integrity": "sha512-1nh45deeb5olNY7eX82BkPO7SSxR5SSYJiPTrTdFUVYwAl8CKMA5N9PjTYkHiRjisVcxcQ1HXdLhx2qxxJzLNQ==", - "dev": true - }, - "node-int64": { - "version": "0.4.0", - "resolved": "https://registry.npmjs.org/node-int64/-/node-int64-0.4.0.tgz", - "integrity": "sha1-h6kGXNs1XTGC2PlM4RGIuCXGijs=", - "dev": true - }, - "node-modules-regexp": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/node-modules-regexp/-/node-modules-regexp-1.0.0.tgz", - "integrity": "sha1-jZ2+KJZKSsVxLpExZCEHxx6Q7EA=", - "dev": true - }, - "node-notifier": { - "version": "5.4.3", - "resolved": "https://registry.npmjs.org/node-notifier/-/node-notifier-5.4.3.tgz", - "integrity": "sha512-M4UBGcs4jeOK9CjTsYwkvH6/MzuUmGCyTW+kCY7uO+1ZVr0+FHGdPdIf5CCLqAaxnRrWidyoQlNkMIIVwbKB8Q==", - "dev": true, - "requires": { - "growly": "^1.3.0", - "is-wsl": "^1.1.0", - "semver": "^5.5.0", - "shellwords": "^0.1.1", - "which": "^1.3.0" - } - }, - "normalize-package-data": { - "version": "2.5.0", - "resolved": "https://registry.npmjs.org/normalize-package-data/-/normalize-package-data-2.5.0.tgz", - "integrity": "sha512-/5CMN3T0R4XTj4DcGaexo+roZSdSFW/0AOOTROrjxzCG1wrWXEsGbRKevjlIL+ZDE4sZlJr5ED4YW0yqmkK+eA==", - "dev": true, - "requires": { - "hosted-git-info": "^2.1.4", - "resolve": "^1.10.0", - "semver": "2 || 3 || 4 || 5", - "validate-npm-package-license": "^3.0.1" - } - }, - "normalize-path": { - "version": "2.1.1", - "resolved": "https://registry.npmjs.org/normalize-path/-/normalize-path-2.1.1.tgz", - "integrity": "sha1-GrKLVW4Zg2Oowab35vogE3/mrtk=", - "dev": true, - "requires": { - "remove-trailing-separator": "^1.0.1" - } - }, - "npm-run-path": { - "version": "2.0.2", - "resolved": "https://registry.npmjs.org/npm-run-path/-/npm-run-path-2.0.2.tgz", - "integrity": "sha1-NakjLfo11wZ7TLLd8jV7GHFTbF8=", - "dev": true, - "requires": { - "path-key": "^2.0.0" - } - }, - "nwsapi": { - "version": "2.1.4", - "resolved": "https://registry.npmjs.org/nwsapi/-/nwsapi-2.1.4.tgz", - "integrity": "sha512-iGfd9Y6SFdTNldEy2L0GUhcarIutFmk+MPWIn9dmj8NMIup03G08uUF2KGbbmv/Ux4RT0VZJoP/sVbWA6d/VIw==", - "dev": true - }, - "oauth-sign": { - "version": "0.9.0", - "resolved": "https://registry.npmjs.org/oauth-sign/-/oauth-sign-0.9.0.tgz", - "integrity": "sha512-fexhUFFPTGV8ybAtSIGbV6gOkSv8UtRbDBnAyLQw4QPKkgNlsH2ByPGtMUqdWkos6YCRmAqViwgZrJc/mRDzZQ==", - "dev": true - }, - "object-assign": { - "version": "4.1.1", - "resolved": "https://registry.npmjs.org/object-assign/-/object-assign-4.1.1.tgz", - "integrity": "sha1-IQmtx5ZYh8/AXLvUQsrIv7s2CGM=", - "dev": true - }, - "object-copy": { - "version": "0.1.0", - "resolved": "https://registry.npmjs.org/object-copy/-/object-copy-0.1.0.tgz", - "integrity": "sha1-fn2Fi3gb18mRpBupde04EnVOmYw=", - "dev": true, - "requires": { - "copy-descriptor": "^0.1.0", - "define-property": "^0.2.5", - "kind-of": "^3.0.3" - }, - "dependencies": { - "define-property": { - "version": "0.2.5", - "resolved": "https://registry.npmjs.org/define-property/-/define-property-0.2.5.tgz", - "integrity": "sha1-w1se+RjsPJkPmlvFe+BKrOxcgRY=", - "dev": true, - "requires": { - "is-descriptor": "^0.1.0" - } - }, - "is-buffer": { - "version": "1.1.6", - "resolved": "https://registry.npmjs.org/is-buffer/-/is-buffer-1.1.6.tgz", - "integrity": "sha512-NcdALwpXkTm5Zvvbk7owOUSvVvBKDgKP5/ewfXEznmQFfs4ZRmanOeKBTjRVjka3QFoN6XJ+9F3USqfHqTaU5w==", - "dev": true - }, - "kind-of": { - "version": "3.2.2", - "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-3.2.2.tgz", - "integrity": "sha1-MeohpzS6ubuw8yRm2JOupR5KPGQ=", - "dev": true, - "requires": { - "is-buffer": "^1.1.5" - } - } - } - }, - "object-inspect": { - "version": "1.6.0", - "resolved": "https://registry.npmjs.org/object-inspect/-/object-inspect-1.6.0.tgz", - "integrity": "sha512-GJzfBZ6DgDAmnuaM3104jR4s1Myxr3Y3zfIyN4z3UdqN69oSRacNK8UhnobDdC+7J2AHCjGwxQubNJfE70SXXQ==", - "dev": true - }, - "object-keys": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/object-keys/-/object-keys-1.1.1.tgz", - "integrity": "sha512-NuAESUOUMrlIXOfHKzD6bpPu3tYt3xvjNdRIQ+FeT0lNb4K8WR70CaDxhuNguS2XG+GjkyMwOzsN5ZktImfhLA==", - "dev": true - }, - "object-visit": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/object-visit/-/object-visit-1.0.1.tgz", - "integrity": "sha1-95xEk68MU3e1n+OdOV5BBC3QRbs=", - "dev": true, - "requires": { - "isobject": "^3.0.0" - } - }, - "object.getownpropertydescriptors": { - "version": "2.0.3", - "resolved": "https://registry.npmjs.org/object.getownpropertydescriptors/-/object.getownpropertydescriptors-2.0.3.tgz", - "integrity": "sha1-h1jIRvW0B62rDyNuCYbxSwUcqhY=", - "dev": true, - "requires": { - "define-properties": "^1.1.2", - "es-abstract": "^1.5.1" - } - }, - "object.pick": { - "version": "1.3.0", - "resolved": "https://registry.npmjs.org/object.pick/-/object.pick-1.3.0.tgz", - "integrity": "sha1-h6EKxMFpS9Lhy/U1kaZhQftd10c=", - "dev": true, - "requires": { - "isobject": "^3.0.1" - } - }, - "on-finished": { - "version": "2.3.0", - "resolved": "https://registry.npmjs.org/on-finished/-/on-finished-2.3.0.tgz", - "integrity": "sha1-IPEzZIGwg811M3mSoWlxqi2QaUc=", - "dev": true, - "requires": { - "ee-first": "1.1.1" - } - }, - "once": { - "version": "1.4.0", - "resolved": "https://registry.npmjs.org/once/-/once-1.4.0.tgz", - "integrity": "sha1-WDsap3WWHUsROsF9nFC6753Xa9E=", - "dev": true, - "requires": { - "wrappy": "1" - } - }, - "opencollective-postinstall": { - "version": "2.0.2", - "resolved": "https://registry.npmjs.org/opencollective-postinstall/-/opencollective-postinstall-2.0.2.tgz", - "integrity": "sha512-pVOEP16TrAO2/fjej1IdOyupJY8KDUM1CvsaScRbw6oddvpQoOfGk4ywha0HKKVAD6RkW4x6Q+tNBwhf3Bgpuw==", - "dev": true - }, - "optimist": { - "version": "0.6.1", - "resolved": "https://registry.npmjs.org/optimist/-/optimist-0.6.1.tgz", - "integrity": "sha1-2j6nRob6IaGaERwybpDrFaAZZoY=", - "dev": true, - "requires": { - "minimist": "~0.0.1", - "wordwrap": "~0.0.2" - }, - "dependencies": { - "minimist": { - "version": "0.0.10", - "resolved": "https://registry.npmjs.org/minimist/-/minimist-0.0.10.tgz", - "integrity": "sha1-3j+YVD2/lggr5IrRoMfNqDYwHc8=", - "dev": true - } - } - }, - "optionator": { - "version": "0.8.2", - "resolved": "https://registry.npmjs.org/optionator/-/optionator-0.8.2.tgz", - "integrity": "sha1-NkxeQJ0/TWMB1sC0wFu6UBgK62Q=", - "dev": true, - "requires": { - "deep-is": "~0.1.3", - "fast-levenshtein": "~2.0.4", - "levn": "~0.3.0", - "prelude-ls": "~1.1.2", - "type-check": "~0.3.2", - "wordwrap": "~1.0.0" - }, - "dependencies": { - "wordwrap": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/wordwrap/-/wordwrap-1.0.0.tgz", - "integrity": "sha1-J1hIEIkUVqQXHI0CJkQa3pDLyus=", - "dev": true - } - } - }, - "p-each-series": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/p-each-series/-/p-each-series-1.0.0.tgz", - "integrity": "sha1-kw89Et0fUOdDRFeiLNbwSsatf3E=", - "dev": true, - "requires": { - "p-reduce": "^1.0.0" - } - }, - "p-finally": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/p-finally/-/p-finally-1.0.0.tgz", - "integrity": "sha1-P7z7FbiZpEEjs0ttzBi3JDNqLK4=", - "dev": true - }, - "p-limit": { - "version": "2.2.1", - "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-2.2.1.tgz", - "integrity": "sha512-85Tk+90UCVWvbDavCLKPOLC9vvY8OwEX/RtKF+/1OADJMVlFfEHOiMTPVyxg7mk/dKa+ipdHm0OUkTvCpMTuwg==", - "dev": true, - "requires": { - "p-try": "^2.0.0" - } - }, - "p-locate": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/p-locate/-/p-locate-3.0.0.tgz", - "integrity": "sha512-x+12w/To+4GFfgJhBEpiDcLozRJGegY+Ei7/z0tSLkMmxGZNybVMSfWj9aJn8Z5Fc7dBUNJOOVgPv2H7IwulSQ==", - "dev": true, - "requires": { - "p-limit": "^2.0.0" - } - }, - "p-reduce": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/p-reduce/-/p-reduce-1.0.0.tgz", - "integrity": "sha1-GMKw3ZNqRpClKfgjH1ig/bakffo=", - "dev": true - }, - "p-try": { - "version": "2.2.0", - "resolved": "https://registry.npmjs.org/p-try/-/p-try-2.2.0.tgz", - "integrity": "sha512-R4nPAVTAU0B9D35/Gk3uJf/7XYbQcyohSKdvAxIRSNghFl4e71hVoGnBNQz9cWaXxO2I10KTC+3jMdvvoKw6dQ==", - "dev": true - }, - "parse-json": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/parse-json/-/parse-json-4.0.0.tgz", - "integrity": "sha1-vjX1Qlvh9/bHRxhPmKeIy5lHfuA=", - "dev": true, - "requires": { - "error-ex": "^1.3.1", - "json-parse-better-errors": "^1.0.1" - } - }, - "parse5": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/parse5/-/parse5-4.0.0.tgz", - "integrity": "sha512-VrZ7eOd3T1Fk4XWNXMgiGBK/z0MG48BWG2uQNU4I72fkQuKUTZpl+u9k+CxEG0twMVzSmXEEz12z5Fnw1jIQFA==", - "dev": true - }, - "parseurl": { - "version": "1.3.3", - "resolved": "https://registry.npmjs.org/parseurl/-/parseurl-1.3.3.tgz", - "integrity": "sha512-CiyeOxFT/JZyN5m0z9PfXw4SCBJ6Sygz1Dpl0wqjlhDEGGBP1GnsUVEL0p63hoG1fcj3fHynXi9NYO4nWOL+qQ==", - "dev": true - }, - "pascalcase": { - "version": "0.1.1", - "resolved": "https://registry.npmjs.org/pascalcase/-/pascalcase-0.1.1.tgz", - "integrity": "sha1-s2PlXoAGym/iF4TS2yK9FdeRfxQ=", - "dev": true - }, - "path-exists": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/path-exists/-/path-exists-3.0.0.tgz", - "integrity": "sha1-zg6+ql94yxiSXqfYENe1mwEP1RU=", - "dev": true - }, - "path-is-absolute": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/path-is-absolute/-/path-is-absolute-1.0.1.tgz", - "integrity": "sha1-F0uSaHNVNP+8es5r9TpanhtcX18=", - "dev": true - }, - "path-key": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/path-key/-/path-key-2.0.1.tgz", - "integrity": "sha1-QRyttXTFoUDTpLGRDUDYDMn0C0A=", - "dev": true - }, - "path-parse": { - "version": "1.0.6", - "resolved": "https://registry.npmjs.org/path-parse/-/path-parse-1.0.6.tgz", - "integrity": "sha512-GSmOT2EbHrINBf9SR7CDELwlJ8AENk3Qn7OikK4nFYAu3Ote2+JYNVvkpAEQm3/TLNEJFD/xZJjzyxg3KBWOzw==", - "dev": true - }, - "path-to-regexp": { - "version": "0.1.7", - "resolved": "https://registry.npmjs.org/path-to-regexp/-/path-to-regexp-0.1.7.tgz", - "integrity": "sha1-32BBeABfUi8V60SQ5yR6G/qmf4w=", - "dev": true - }, - "path-type": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/path-type/-/path-type-3.0.0.tgz", - "integrity": "sha512-T2ZUsdZFHgA3u4e5PfPbjd7HDDpxPnQb5jN0SrDsjNSuVXHJqtwTnWqG0B1jZrgmJ/7lj1EmVIByWt1gxGkWvg==", - "dev": true, - "requires": { - "pify": "^3.0.0" - } - }, - "performance-now": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/performance-now/-/performance-now-2.1.0.tgz", - "integrity": "sha1-Ywn04OX6kT7BxpMHrjZLSzd8nns=", - "dev": true - }, - "pify": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/pify/-/pify-3.0.0.tgz", - "integrity": "sha1-5aSs0sEB/fPZpNB/DbxNtJ3SgXY=", - "dev": true - }, - "pirates": { - "version": "4.0.1", - "resolved": "https://registry.npmjs.org/pirates/-/pirates-4.0.1.tgz", - "integrity": "sha512-WuNqLTbMI3tmfef2TKxlQmAiLHKtFhlsCZnPIpuv2Ow0RDVO8lfy1Opf4NUzlMXLjPl+Men7AuVdX6TA+s+uGA==", - "dev": true, - "requires": { - "node-modules-regexp": "^1.0.0" - } - }, - "pkg-dir": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/pkg-dir/-/pkg-dir-3.0.0.tgz", - "integrity": "sha512-/E57AYkoeQ25qkxMj5PBOVgF8Kiu/h7cYS30Z5+R7WaiCCBfLq58ZI/dSeaEKb9WVJV5n/03QwrN3IeWIFllvw==", - "dev": true, - "requires": { - "find-up": "^3.0.0" - } - }, - "please-upgrade-node": { - "version": "3.2.0", - "resolved": "https://registry.npmjs.org/please-upgrade-node/-/please-upgrade-node-3.2.0.tgz", - "integrity": "sha512-gQR3WpIgNIKwBMVLkpMUeR3e1/E1y42bqDQZfql+kDeXd8COYfM8PQA4X6y7a8u9Ua9FHmsrrmirW2vHs45hWg==", - "dev": true, - "requires": { - "semver-compare": "^1.0.0" - } - }, - "pn": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/pn/-/pn-1.1.0.tgz", - "integrity": "sha512-2qHaIQr2VLRFoxe2nASzsV6ef4yOOH+Fi9FBOVH6cqeSgUnoyySPZkxzLuzd+RYOQTRpROA0ztTMqxROKSb/nA==", - "dev": true - }, - "posix-character-classes": { - "version": "0.1.1", - "resolved": "https://registry.npmjs.org/posix-character-classes/-/posix-character-classes-0.1.1.tgz", - "integrity": "sha1-AerA/jta9xoqbAL+q7jB/vfgDqs=", - "dev": true - }, - "prelude-ls": { - "version": "1.1.2", - "resolved": "https://registry.npmjs.org/prelude-ls/-/prelude-ls-1.1.2.tgz", - "integrity": "sha1-IZMqVJ9eUv/ZqCf1cOBL5iqX2lQ=", - "dev": true - }, - "pretty-format": { - "version": "24.9.0", - "resolved": "https://registry.npmjs.org/pretty-format/-/pretty-format-24.9.0.tgz", - "integrity": "sha512-00ZMZUiHaJrNfk33guavqgvfJS30sLYf0f8+Srklv0AMPodGGHcoHgksZ3OThYnIvOd+8yMCn0YiEOogjlgsnA==", - "dev": true, - "requires": { - "@jest/types": "^24.9.0", - "ansi-regex": "^4.0.0", - "ansi-styles": "^3.2.0", - "react-is": "^16.8.4" - } - }, - "process-nextick-args": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/process-nextick-args/-/process-nextick-args-2.0.1.tgz", - "integrity": "sha512-3ouUOpQhtgrbOa17J7+uxOTpITYWaGP7/AhoR3+A+/1e9skrzelGi/dXzEYyvbxubEF6Wn2ypscTKiKJFFn1ag==", - "dev": true - }, - "prompts": { - "version": "2.2.1", - "resolved": "https://registry.npmjs.org/prompts/-/prompts-2.2.1.tgz", - "integrity": "sha512-VObPvJiWPhpZI6C5m60XOzTfnYg/xc/an+r9VYymj9WJW3B/DIH+REzjpAACPf8brwPeP+7vz3bIim3S+AaMjw==", - "dev": true, - "requires": { - "kleur": "^3.0.3", - "sisteransi": "^1.0.3" - } - }, - "proxy-addr": { - "version": "2.0.5", - "resolved": "https://registry.npmjs.org/proxy-addr/-/proxy-addr-2.0.5.tgz", - "integrity": "sha512-t/7RxHXPH6cJtP0pRG6smSr9QJidhB+3kXu0KgXnbGYMgzEnUxRQ4/LDdfOwZEMyIh3/xHb8PX3t+lfL9z+YVQ==", - "dev": true, - "requires": { - "forwarded": "~0.1.2", - "ipaddr.js": "1.9.0" - } - }, - "psl": { - "version": "1.4.0", - "resolved": "https://registry.npmjs.org/psl/-/psl-1.4.0.tgz", - "integrity": "sha512-HZzqCGPecFLyoRj5HLfuDSKYTJkAfB5thKBIkRHtGjWwY7p1dAyveIbXIq4tO0KYfDF2tHqPUgY9SDnGm00uFw==", - "dev": true - }, - "pump": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/pump/-/pump-3.0.0.tgz", - "integrity": "sha512-LwZy+p3SFs1Pytd/jYct4wpv49HiYCqd9Rlc5ZVdk0V+8Yzv6jR5Blk3TRmPL1ft69TxP0IMZGJ+WPFU2BFhww==", - "dev": true, - "requires": { - "end-of-stream": "^1.1.0", - "once": "^1.3.1" - } - }, - "punycode": { - "version": "2.1.1", - "resolved": "https://registry.npmjs.org/punycode/-/punycode-2.1.1.tgz", - "integrity": "sha512-XRsRjdf+j5ml+y/6GKHPZbrF/8p2Yga0JPtdqTIY2Xe5ohJPD9saDJJLPvp9+NSBprVvevdXZybnj2cv8OEd0A==", - "dev": true - }, - "qs": { - "version": "6.9.0", - "resolved": "https://registry.npmjs.org/qs/-/qs-6.9.0.tgz", - "integrity": "sha512-27RP4UotQORTpmNQDX8BHPukOnBP3p1uUJY5UnDhaJB+rMt9iMsok724XL+UHU23bEFOHRMQ2ZhI99qOWUMGFA==" - }, - "range-parser": { - "version": "1.2.1", - "resolved": "https://registry.npmjs.org/range-parser/-/range-parser-1.2.1.tgz", - "integrity": "sha512-Hrgsx+orqoygnmhFbKaHE6c296J+HTAQXoxEF6gNupROmmGJRoyzfG3ccAveqCBrwr/2yxQ5BVd/GTl5agOwSg==", - "dev": true - }, - "raw-body": { - "version": "2.4.0", - "resolved": "https://registry.npmjs.org/raw-body/-/raw-body-2.4.0.tgz", - "integrity": "sha512-4Oz8DUIwdvoa5qMJelxipzi/iJIi40O5cGV1wNYp5hvZP8ZN0T+jiNkL0QepXs+EsQ9XJ8ipEDoiH70ySUJP3Q==", - "dev": true, - "requires": { - "bytes": "3.1.0", - "http-errors": "1.7.2", - "iconv-lite": "0.4.24", - "unpipe": "1.0.0" - } - }, - "react-is": { - "version": "16.10.0", - "resolved": "https://registry.npmjs.org/react-is/-/react-is-16.10.0.tgz", - "integrity": "sha512-WRki2sBb7MTpYp7FtDEmSeGKX2vamYyq3rc9o7fKUG+/DHVyJu69NnvJsiSwwhh2Tt8XN40MQHkDBEXwyfxncQ==", - "dev": true - }, - "read-pkg": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/read-pkg/-/read-pkg-3.0.0.tgz", - "integrity": "sha1-nLxoaXj+5l0WwA4rGcI3/Pbjg4k=", - "dev": true, - "requires": { - "load-json-file": "^4.0.0", - "normalize-package-data": "^2.3.2", - "path-type": "^3.0.0" - } - }, - "read-pkg-up": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/read-pkg-up/-/read-pkg-up-4.0.0.tgz", - "integrity": "sha512-6etQSH7nJGsK0RbG/2TeDzZFa8shjQ1um+SwQQ5cwKy0dhSXdOncEhb1CPpvQG4h7FyOV6EB6YlV0yJvZQNAkA==", - "dev": true, - "requires": { - "find-up": "^3.0.0", - "read-pkg": "^3.0.0" - } - }, - "readable-stream": { - "version": "1.1.14", - "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-1.1.14.tgz", - "integrity": "sha1-fPTFTvZI44EwhMY23SB54WbAgdk=", - "dev": true, - "requires": { - "core-util-is": "~1.0.0", - "inherits": "~2.0.1", - "isarray": "0.0.1", - "string_decoder": "~0.10.x" - }, - "dependencies": { - "isarray": { - "version": "0.0.1", - "resolved": "https://registry.npmjs.org/isarray/-/isarray-0.0.1.tgz", - "integrity": "sha1-ihis/Kmo9Bd+Cav8YDiTmwXR7t8=", - "dev": true - } - } - }, - "realpath-native": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/realpath-native/-/realpath-native-1.1.0.tgz", - "integrity": "sha512-wlgPA6cCIIg9gKz0fgAPjnzh4yR/LnXovwuo9hvyGvx3h8nX4+/iLZplfUWasXpqD8BdnGnP5njOFjkUwPzvjA==", - "dev": true, - "requires": { - "util.promisify": "^1.0.0" - } - }, - "regex-not": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/regex-not/-/regex-not-1.0.2.tgz", - "integrity": "sha512-J6SDjUgDxQj5NusnOtdFxDwN/+HWykR8GELwctJ7mdqhcyy1xEc4SRFHUXvxTp661YaVKAjfRLZ9cCqS6tn32A==", - "dev": true, - "requires": { - "extend-shallow": "^3.0.2", - "safe-regex": "^1.1.0" - } - }, - "remove-trailing-separator": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/remove-trailing-separator/-/remove-trailing-separator-1.1.0.tgz", - "integrity": "sha1-wkvOKig62tW8P1jg1IJJuSN52O8=", - "dev": true - }, - "repeat-element": { - "version": "1.1.3", - "resolved": "https://registry.npmjs.org/repeat-element/-/repeat-element-1.1.3.tgz", - "integrity": "sha512-ahGq0ZnV5m5XtZLMb+vP76kcAM5nkLqk0lpqAuojSKGgQtn4eRi4ZZGm2olo2zKFH+sMsWaqOCW1dqAnOru72g==", - "dev": true - }, - "repeat-string": { - "version": "1.6.1", - "resolved": "https://registry.npmjs.org/repeat-string/-/repeat-string-1.6.1.tgz", - "integrity": "sha1-jcrkcOHIirwtYA//Sndihtp15jc=", - "dev": true - }, - "request": { - "version": "2.88.0", - "resolved": "https://registry.npmjs.org/request/-/request-2.88.0.tgz", - "integrity": "sha512-NAqBSrijGLZdM0WZNsInLJpkJokL72XYjUpnB0iwsRgxh7dB6COrHnTBNwN0E+lHDAJzu7kLAkDeY08z2/A0hg==", - "dev": true, - "requires": { - "aws-sign2": "~0.7.0", - "aws4": "^1.8.0", - "caseless": "~0.12.0", - "combined-stream": "~1.0.6", - "extend": "~3.0.2", - "forever-agent": "~0.6.1", - "form-data": "~2.3.2", - "har-validator": "~5.1.0", - "http-signature": "~1.2.0", - "is-typedarray": "~1.0.0", - "isstream": "~0.1.2", - "json-stringify-safe": "~5.0.1", - "mime-types": "~2.1.19", - "oauth-sign": "~0.9.0", - "performance-now": "^2.1.0", - "qs": "~6.5.2", - "safe-buffer": "^5.1.2", - "tough-cookie": "~2.4.3", - "tunnel-agent": "^0.6.0", - "uuid": "^3.3.2" - }, - "dependencies": { - "form-data": { - "version": "2.3.3", - "resolved": "https://registry.npmjs.org/form-data/-/form-data-2.3.3.tgz", - "integrity": "sha512-1lLKB2Mu3aGP1Q/2eCOx0fNbRMe7XdwktwOruhfqqd0rIJWwN4Dh+E3hrPSlDCXnSR7UtZ1N38rVXm+6+MEhJQ==", - "dev": true, - "requires": { - "asynckit": "^0.4.0", - "combined-stream": "^1.0.6", - "mime-types": "^2.1.12" - } - }, - "punycode": { - "version": "1.4.1", - "resolved": "https://registry.npmjs.org/punycode/-/punycode-1.4.1.tgz", - "integrity": "sha1-wNWmOycYgArY4esPpSachN1BhF4=", - "dev": true - }, - "qs": { - "version": "6.5.2", - "resolved": "https://registry.npmjs.org/qs/-/qs-6.5.2.tgz", - "integrity": "sha512-N5ZAX4/LxJmF+7wN74pUD6qAh9/wnvdQcjq9TZjevvXzSUo7bfmw91saqMjzGS2xq91/odN2dW/WOl7qQHNDGA==", - "dev": true - }, - "tough-cookie": { - "version": "2.4.3", - "resolved": "https://registry.npmjs.org/tough-cookie/-/tough-cookie-2.4.3.tgz", - "integrity": "sha512-Q5srk/4vDM54WJsJio3XNn6K2sCG+CQ8G5Wz6bZhRZoAe/+TxjWB/GlFAnYEbkYVlON9FMk/fE3h2RLpPXo4lQ==", - "dev": true, - "requires": { - "psl": "^1.1.24", - "punycode": "^1.4.1" - } - } - } - }, - "request-promise-core": { - "version": "1.1.2", - "resolved": "https://registry.npmjs.org/request-promise-core/-/request-promise-core-1.1.2.tgz", - "integrity": "sha512-UHYyq1MO8GsefGEt7EprS8UrXsm1TxEvFUX1IMTuSLU2Rh7fTIdFtl8xD7JiEYiWU2dl+NYAjCTksTehQUxPag==", - "dev": true, - "requires": { - "lodash": "^4.17.11" - } - }, - "request-promise-native": { - "version": "1.0.7", - "resolved": "https://registry.npmjs.org/request-promise-native/-/request-promise-native-1.0.7.tgz", - "integrity": "sha512-rIMnbBdgNViL37nZ1b3L/VfPOpSi0TqVDQPAvO6U14lMzOLrt5nilxCQqtDKhZeDiW0/hkCXGoQjhgJd/tCh6w==", - "dev": true, - "requires": { - "request-promise-core": "1.1.2", - "stealthy-require": "^1.1.1", - "tough-cookie": "^2.3.3" - } - }, - "require-directory": { - "version": "2.1.1", - "resolved": "https://registry.npmjs.org/require-directory/-/require-directory-2.1.1.tgz", - "integrity": "sha1-jGStX9MNqxyXbiNE/+f3kqam30I=", - "dev": true - }, - "require-main-filename": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/require-main-filename/-/require-main-filename-2.0.0.tgz", - "integrity": "sha512-NKN5kMDylKuldxYLSUfrbo5Tuzh4hd+2E8NPPX02mZtn1VuREQToYe/ZdlJy+J3uCpfaiGF05e7B8W0iXbQHmg==", - "dev": true - }, - "resolve": { - "version": "1.12.0", - "resolved": "https://registry.npmjs.org/resolve/-/resolve-1.12.0.tgz", - "integrity": "sha512-B/dOmuoAik5bKcD6s6nXDCjzUKnaDvdkRyAk6rsmsKLipWj4797iothd7jmmUhWTfinVMU+wc56rYKsit2Qy4w==", - "dev": true, - "requires": { - "path-parse": "^1.0.6" - } - }, - "resolve-cwd": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/resolve-cwd/-/resolve-cwd-2.0.0.tgz", - "integrity": "sha1-AKn3OHVW4nA46uIyyqNypqWbZlo=", - "dev": true, - "requires": { - "resolve-from": "^3.0.0" - } - }, - "resolve-from": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/resolve-from/-/resolve-from-3.0.0.tgz", - "integrity": "sha1-six699nWiBvItuZTM17rywoYh0g=", - "dev": true - }, - "resolve-url": { - "version": "0.2.1", - "resolved": "https://registry.npmjs.org/resolve-url/-/resolve-url-0.2.1.tgz", - "integrity": "sha1-LGN/53yJOv0qZj/iGqkIAGjiBSo=", - "dev": true - }, - "ret": { - "version": "0.1.15", - "resolved": "https://registry.npmjs.org/ret/-/ret-0.1.15.tgz", - "integrity": "sha512-TTlYpa+OL+vMMNG24xSlQGEJ3B/RzEfUlLct7b5G/ytav+wPrplCpVMFuwzXbkecJrb6IYo1iFb0S9v37754mg==", - "dev": true - }, - "rimraf": { - "version": "2.7.1", - "resolved": "https://registry.npmjs.org/rimraf/-/rimraf-2.7.1.tgz", - "integrity": "sha512-uWjbaKIK3T1OSVptzX7Nl6PvQ3qAGtKEtVRjRuazjfL3Bx5eI409VZSqgND+4UNnmzLVdPj9FqFJNPqBZFve4w==", - "dev": true, - "requires": { - "glob": "^7.1.3" - } - }, - "rsvp": { - "version": "4.8.5", - "resolved": "https://registry.npmjs.org/rsvp/-/rsvp-4.8.5.tgz", - "integrity": "sha512-nfMOlASu9OnRJo1mbEk2cz0D56a1MBNrJ7orjRZQG10XDyuvwksKbuXNp6qa+kbn839HwjwhBzhFmdsaEAfauA==", - "dev": true - }, - "run-node": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/run-node/-/run-node-1.0.0.tgz", - "integrity": "sha512-kc120TBlQ3mih1LSzdAJXo4xn/GWS2ec0l3S+syHDXP9uRr0JAT8Qd3mdMuyjqCzeZktgP3try92cEgf9Nks8A==", - "dev": true - }, - "safe-buffer": { - "version": "5.1.2", - "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.1.2.tgz", - "integrity": "sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g==", - "dev": true - }, - "safe-regex": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/safe-regex/-/safe-regex-1.1.0.tgz", - "integrity": "sha1-QKNmnzsHfR6UPURinhV91IAjvy4=", - "dev": true, - "requires": { - "ret": "~0.1.10" - } - }, - "safer-buffer": { - "version": "2.1.2", - "resolved": "https://registry.npmjs.org/safer-buffer/-/safer-buffer-2.1.2.tgz", - "integrity": "sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg==", - "dev": true - }, - "sane": { - "version": "4.1.0", - "resolved": "https://registry.npmjs.org/sane/-/sane-4.1.0.tgz", - "integrity": "sha512-hhbzAgTIX8O7SHfp2c8/kREfEn4qO/9q8C9beyY6+tvZ87EpoZ3i1RIEvp27YBswnNbY9mWd6paKVmKbAgLfZA==", - "dev": true, - "requires": { - "@cnakazawa/watch": "^1.0.3", - "anymatch": "^2.0.0", - "capture-exit": "^2.0.0", - "exec-sh": "^0.3.2", - "execa": "^1.0.0", - "fb-watchman": "^2.0.0", - "micromatch": "^3.1.4", - "minimist": "^1.1.1", - "walker": "~1.0.5" - } - }, - "sax": { - "version": "1.2.4", - "resolved": "https://registry.npmjs.org/sax/-/sax-1.2.4.tgz", - "integrity": "sha512-NqVDv9TpANUjFm0N8uM5GxL36UgKi9/atZw+x7YFnQ8ckwFGKrl4xX4yWtrey3UJm5nP1kUbnYgLopqWNSRhWw==", - "dev": true - }, - "semver": { - "version": "5.7.1", - "resolved": "https://registry.npmjs.org/semver/-/semver-5.7.1.tgz", - "integrity": "sha512-sauaDf/PZdVgrLTNYHRtpXa1iRiKcaebiKQ1BJdpQlWH2lCvexQdX55snPFyK7QzpudqbCI0qXFfOasHdyNDGQ==", - "dev": true - }, - "semver-compare": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/semver-compare/-/semver-compare-1.0.0.tgz", - "integrity": "sha1-De4hahyUGrN+nvsXiPavxf9VN/w=", - "dev": true - }, - "send": { - "version": "0.17.1", - "resolved": "https://registry.npmjs.org/send/-/send-0.17.1.tgz", - "integrity": "sha512-BsVKsiGcQMFwT8UxypobUKyv7irCNRHk1T0G680vk88yf6LBByGcZJOTJCrTP2xVN6yI+XjPJcNuE3V4fT9sAg==", - "dev": true, - "requires": { - "debug": "2.6.9", - "depd": "~1.1.2", - "destroy": "~1.0.4", - "encodeurl": "~1.0.2", - "escape-html": "~1.0.3", - "etag": "~1.8.1", - "fresh": "0.5.2", - "http-errors": "~1.7.2", - "mime": "1.6.0", - "ms": "2.1.1", - "on-finished": "~2.3.0", - "range-parser": "~1.2.1", - "statuses": "~1.5.0" - }, - "dependencies": { - "debug": { - "version": "2.6.9", - "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", - "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==", - "dev": true, - "requires": { - "ms": "2.0.0" - }, - "dependencies": { - "ms": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", - "integrity": "sha1-VgiurfwAvmwpAd9fmGF4jeDVl8g=", - "dev": true - } - } - }, - "ms": { - "version": "2.1.1", - "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.1.tgz", - "integrity": "sha512-tgp+dl5cGk28utYktBsrFqA7HKgrhgPsg6Z/EfhWI4gl1Hwq8B/GmY/0oXZ6nF8hDVesS/FpnYaD/kOWhYQvyg==", - "dev": true - } - } - }, - "serve-static": { - "version": "1.14.1", - "resolved": "https://registry.npmjs.org/serve-static/-/serve-static-1.14.1.tgz", - "integrity": "sha512-JMrvUwE54emCYWlTI+hGrGv5I8dEwmco/00EvkzIIsR7MqrHonbD9pO2MOfFnpFntl7ecpZs+3mW+XbQZu9QCg==", - "dev": true, - "requires": { - "encodeurl": "~1.0.2", - "escape-html": "~1.0.3", - "parseurl": "~1.3.3", - "send": "0.17.1" - } - }, - "set-blocking": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/set-blocking/-/set-blocking-2.0.0.tgz", - "integrity": "sha1-BF+XgtARrppoA93TgrJDkrPYkPc=", - "dev": true - }, - "set-value": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/set-value/-/set-value-2.0.1.tgz", - "integrity": "sha512-JxHc1weCN68wRY0fhCoXpyK55m/XPHafOmK4UWD7m2CI14GMcFypt4w/0+NV5f/ZMby2F6S2wwA7fgynh9gWSw==", - "dev": true, - "requires": { - "extend-shallow": "^2.0.1", - "is-extendable": "^0.1.1", - "is-plain-object": "^2.0.3", - "split-string": "^3.0.1" - }, - "dependencies": { - "extend-shallow": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/extend-shallow/-/extend-shallow-2.0.1.tgz", - "integrity": "sha1-Ua99YUrZqfYQ6huvu5idaxxWiQ8=", - "dev": true, - "requires": { - "is-extendable": "^0.1.0" - } - } - } - }, - "setprototypeof": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/setprototypeof/-/setprototypeof-1.1.1.tgz", - "integrity": "sha512-JvdAWfbXeIGaZ9cILp38HntZSFSo3mWg6xGcJJsd+d4aRMOqauag1C63dJfDw7OaMYwEbHMOxEZ1lqVRYP2OAw==", - "dev": true - }, - "shebang-command": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/shebang-command/-/shebang-command-1.2.0.tgz", - "integrity": "sha1-RKrGW2lbAzmJaMOfNj/uXer98eo=", - "dev": true, - "requires": { - "shebang-regex": "^1.0.0" - } - }, - "shebang-regex": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/shebang-regex/-/shebang-regex-1.0.0.tgz", - "integrity": "sha1-2kL0l0DAtC2yypcoVxyxkMmO/qM=", - "dev": true - }, - "shellwords": { - "version": "0.1.1", - "resolved": "https://registry.npmjs.org/shellwords/-/shellwords-0.1.1.tgz", - "integrity": "sha512-vFwSUfQvqybiICwZY5+DAWIPLKsWO31Q91JSKl3UYv+K5c2QRPzn0qzec6QPu1Qc9eHYItiP3NdJqNVqetYAww==", - "dev": true - }, - "signal-exit": { - "version": "3.0.2", - "resolved": "https://registry.npmjs.org/signal-exit/-/signal-exit-3.0.2.tgz", - "integrity": "sha1-tf3AjxKH6hF4Yo5BXiUTK3NkbG0=", - "dev": true - }, - "sisteransi": { - "version": "1.0.3", - "resolved": "https://registry.npmjs.org/sisteransi/-/sisteransi-1.0.3.tgz", - "integrity": "sha512-SbEG75TzH8G7eVXFSN5f9EExILKfly7SUvVY5DhhYLvfhKqhDFY0OzevWa/zwak0RLRfWS5AvfMWpd9gJvr5Yg==", - "dev": true - }, - "slash": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/slash/-/slash-2.0.0.tgz", - "integrity": "sha512-ZYKh3Wh2z1PpEXWr0MpSBZ0V6mZHAQfYevttO11c51CaWjGTaadiKZ+wVt1PbMlDV5qhMFslpZCemhwOK7C89A==", - "dev": true - }, - "snapdragon": { - "version": "0.8.2", - "resolved": "https://registry.npmjs.org/snapdragon/-/snapdragon-0.8.2.tgz", - "integrity": "sha512-FtyOnWN/wCHTVXOMwvSv26d+ko5vWlIDD6zoUJ7LW8vh+ZBC8QdljveRP+crNrtBwioEUWy/4dMtbBjA4ioNlg==", - "dev": true, - "requires": { - "base": "^0.11.1", - "debug": "^2.2.0", - "define-property": "^0.2.5", - "extend-shallow": "^2.0.1", - "map-cache": "^0.2.2", - "source-map": "^0.5.6", - "source-map-resolve": "^0.5.0", - "use": "^3.1.0" - }, - "dependencies": { - "debug": { - "version": "2.6.9", - "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", - "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==", - "dev": true, - "requires": { - "ms": "2.0.0" - } - }, - "define-property": { - "version": "0.2.5", - "resolved": "https://registry.npmjs.org/define-property/-/define-property-0.2.5.tgz", - "integrity": "sha1-w1se+RjsPJkPmlvFe+BKrOxcgRY=", - "dev": true, - "requires": { - "is-descriptor": "^0.1.0" - } - }, - "extend-shallow": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/extend-shallow/-/extend-shallow-2.0.1.tgz", - "integrity": "sha1-Ua99YUrZqfYQ6huvu5idaxxWiQ8=", - "dev": true, - "requires": { - "is-extendable": "^0.1.0" - } - }, - "source-map": { - "version": "0.5.7", - "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.5.7.tgz", - "integrity": "sha1-igOdLRAh0i0eoUyA2OpGi6LvP8w=", - "dev": true - } - } - }, - "snapdragon-node": { - "version": "2.1.1", - "resolved": "https://registry.npmjs.org/snapdragon-node/-/snapdragon-node-2.1.1.tgz", - "integrity": "sha512-O27l4xaMYt/RSQ5TR3vpWCAB5Kb/czIcqUFOM/C4fYcLnbZUc1PkjTAMjof2pBWaSTwOUd6qUHcFGVGj7aIwnw==", - "dev": true, - "requires": { - "define-property": "^1.0.0", - "isobject": "^3.0.0", - "snapdragon-util": "^3.0.1" - }, - "dependencies": { - "define-property": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/define-property/-/define-property-1.0.0.tgz", - "integrity": "sha1-dp66rz9KY6rTr56NMEybvnm/sOY=", - "dev": true, - "requires": { - "is-descriptor": "^1.0.0" - } - }, - "is-accessor-descriptor": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/is-accessor-descriptor/-/is-accessor-descriptor-1.0.0.tgz", - "integrity": "sha512-m5hnHTkcVsPfqx3AKlyttIPb7J+XykHvJP2B9bZDjlhLIoEq4XoK64Vg7boZlVWYK6LUY94dYPEE7Lh0ZkZKcQ==", - "dev": true, - "requires": { - "kind-of": "^6.0.0" - } - }, - "is-data-descriptor": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/is-data-descriptor/-/is-data-descriptor-1.0.0.tgz", - "integrity": "sha512-jbRXy1FmtAoCjQkVmIVYwuuqDFUbaOeDjmed1tOGPrsMhtJA4rD9tkgA0F1qJ3gRFRXcHYVkdeaP50Q5rE/jLQ==", - "dev": true, - "requires": { - "kind-of": "^6.0.0" - } - }, - "is-descriptor": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/is-descriptor/-/is-descriptor-1.0.2.tgz", - "integrity": "sha512-2eis5WqQGV7peooDyLmNEPUrps9+SXX5c9pL3xEB+4e9HnGuDa7mB7kHxHw4CbqS9k1T2hOH3miL8n8WtiYVtg==", - "dev": true, - "requires": { - "is-accessor-descriptor": "^1.0.0", - "is-data-descriptor": "^1.0.0", - "kind-of": "^6.0.2" - } - } - } - }, - "snapdragon-util": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/snapdragon-util/-/snapdragon-util-3.0.1.tgz", - "integrity": "sha512-mbKkMdQKsjX4BAL4bRYTj21edOf8cN7XHdYUJEe+Zn99hVEYcMvKPct1IqNe7+AZPirn8BCDOQBHQZknqmKlZQ==", - "dev": true, - "requires": { - "kind-of": "^3.2.0" - }, - "dependencies": { - "is-buffer": { - "version": "1.1.6", - "resolved": "https://registry.npmjs.org/is-buffer/-/is-buffer-1.1.6.tgz", - "integrity": "sha512-NcdALwpXkTm5Zvvbk7owOUSvVvBKDgKP5/ewfXEznmQFfs4ZRmanOeKBTjRVjka3QFoN6XJ+9F3USqfHqTaU5w==", - "dev": true - }, - "kind-of": { - "version": "3.2.2", - "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-3.2.2.tgz", - "integrity": "sha1-MeohpzS6ubuw8yRm2JOupR5KPGQ=", - "dev": true, - "requires": { - "is-buffer": "^1.1.5" - } - } - } - }, - "source-map": { - "version": "0.6.1", - "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", - "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==", - "dev": true - }, - "source-map-resolve": { - "version": "0.5.2", - "resolved": "https://registry.npmjs.org/source-map-resolve/-/source-map-resolve-0.5.2.tgz", - "integrity": "sha512-MjqsvNwyz1s0k81Goz/9vRBe9SZdB09Bdw+/zYyO+3CuPk6fouTaxscHkgtE8jKvf01kVfl8riHzERQ/kefaSA==", - "dev": true, - "requires": { - "atob": "^2.1.1", - "decode-uri-component": "^0.2.0", - "resolve-url": "^0.2.1", - "source-map-url": "^0.4.0", - "urix": "^0.1.0" - } - }, - "source-map-support": { - "version": "0.5.13", - "resolved": "https://registry.npmjs.org/source-map-support/-/source-map-support-0.5.13.tgz", - "integrity": "sha512-SHSKFHadjVA5oR4PPqhtAVdcBWwRYVd6g6cAXnIbRiIwc2EhPrTuKUBdSLvlEKyIP3GCf89fltvcZiP9MMFA1w==", - "dev": true, - "requires": { - "buffer-from": "^1.0.0", - "source-map": "^0.6.0" - } - }, - "source-map-url": { - "version": "0.4.0", - "resolved": "https://registry.npmjs.org/source-map-url/-/source-map-url-0.4.0.tgz", - "integrity": "sha1-PpNdfd1zYxuXZZlW1VEo6HtQhKM=", - "dev": true - }, - "spdx-correct": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/spdx-correct/-/spdx-correct-3.1.0.tgz", - "integrity": "sha512-lr2EZCctC2BNR7j7WzJ2FpDznxky1sjfxvvYEyzxNyb6lZXHODmEoJeFu4JupYlkfha1KZpJyoqiJ7pgA1qq8Q==", - "dev": true, - "requires": { - "spdx-expression-parse": "^3.0.0", - "spdx-license-ids": "^3.0.0" - } - }, - "spdx-exceptions": { - "version": "2.2.0", - "resolved": "https://registry.npmjs.org/spdx-exceptions/-/spdx-exceptions-2.2.0.tgz", - "integrity": "sha512-2XQACfElKi9SlVb1CYadKDXvoajPgBVPn/gOQLrTvHdElaVhr7ZEbqJaRnJLVNeaI4cMEAgVCeBMKF6MWRDCRA==", - "dev": true - }, - "spdx-expression-parse": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/spdx-expression-parse/-/spdx-expression-parse-3.0.0.tgz", - "integrity": "sha512-Yg6D3XpRD4kkOmTpdgbUiEJFKghJH03fiC1OPll5h/0sO6neh2jqRDVHOQ4o/LMea0tgCkbMgea5ip/e+MkWyg==", - "dev": true, - "requires": { - "spdx-exceptions": "^2.1.0", - "spdx-license-ids": "^3.0.0" - } - }, - "spdx-license-ids": { - "version": "3.0.5", - "resolved": "https://registry.npmjs.org/spdx-license-ids/-/spdx-license-ids-3.0.5.tgz", - "integrity": "sha512-J+FWzZoynJEXGphVIS+XEh3kFSjZX/1i9gFBaWQcB+/tmpe2qUsSBABpcxqxnAxFdiUFEgAX1bjYGQvIZmoz9Q==", - "dev": true - }, - "split-string": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/split-string/-/split-string-3.1.0.tgz", - "integrity": "sha512-NzNVhJDYpwceVVii8/Hu6DKfD2G+NrQHlS/V/qgv763EYudVwEcMQNxd2lh+0VrUByXN/oJkl5grOhYWvQUYiw==", - "dev": true, - "requires": { - "extend-shallow": "^3.0.0" - } - }, - "sprintf-js": { - "version": "1.0.3", - "resolved": "https://registry.npmjs.org/sprintf-js/-/sprintf-js-1.0.3.tgz", - "integrity": "sha1-BOaSb2YolTVPPdAVIDYzuFcpfiw=", - "dev": true - }, - "sshpk": { - "version": "1.16.1", - "resolved": "https://registry.npmjs.org/sshpk/-/sshpk-1.16.1.tgz", - "integrity": "sha512-HXXqVUq7+pcKeLqqZj6mHFUMvXtOJt1uoUx09pFW6011inTMxqI8BA8PM95myrIyyKwdnzjdFjLiE6KBPVtJIg==", - "dev": true, - "requires": { - "asn1": "~0.2.3", - "assert-plus": "^1.0.0", - "bcrypt-pbkdf": "^1.0.0", - "dashdash": "^1.12.0", - "ecc-jsbn": "~0.1.1", - "getpass": "^0.1.1", - "jsbn": "~0.1.0", - "safer-buffer": "^2.0.2", - "tweetnacl": "~0.14.0" - } - }, - "stack-utils": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/stack-utils/-/stack-utils-1.0.2.tgz", - "integrity": "sha512-MTX+MeG5U994cazkjd/9KNAapsHnibjMLnfXodlkXw76JEea0UiNzrqidzo1emMwk7w5Qhc9jd4Bn9TBb1MFwA==", - "dev": true - }, - "static-extend": { - "version": "0.1.2", - "resolved": "https://registry.npmjs.org/static-extend/-/static-extend-0.1.2.tgz", - "integrity": "sha1-YICcOcv/VTNyJv1eC1IPNB8ftcY=", - "dev": true, - "requires": { - "define-property": "^0.2.5", - "object-copy": "^0.1.0" - }, - "dependencies": { - "define-property": { - "version": "0.2.5", - "resolved": "https://registry.npmjs.org/define-property/-/define-property-0.2.5.tgz", - "integrity": "sha1-w1se+RjsPJkPmlvFe+BKrOxcgRY=", - "dev": true, - "requires": { - "is-descriptor": "^0.1.0" - } - } - } - }, - "statuses": { - "version": "1.5.0", - "resolved": "https://registry.npmjs.org/statuses/-/statuses-1.5.0.tgz", - "integrity": "sha1-Fhx9rBd2Wf2YEfQ3cfqZOBR4Yow=", - "dev": true - }, - "stealthy-require": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/stealthy-require/-/stealthy-require-1.1.1.tgz", - "integrity": "sha1-NbCYdbT/SfJqd35QmzCQoyJr8ks=", - "dev": true - }, - "streamsearch": { - "version": "0.1.2", - "resolved": "https://registry.npmjs.org/streamsearch/-/streamsearch-0.1.2.tgz", - "integrity": "sha1-gIudDlb8Jz2Am6VzOOkpkZoanxo=", - "dev": true - }, - "string-length": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/string-length/-/string-length-2.0.0.tgz", - "integrity": "sha1-1A27aGo6zpYMHP/KVivyxF+DY+0=", - "dev": true, - "requires": { - "astral-regex": "^1.0.0", - "strip-ansi": "^4.0.0" - }, - "dependencies": { - "ansi-regex": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-3.0.0.tgz", - "integrity": "sha1-7QMXwyIGT3lGbAKWa922Bas32Zg=", - "dev": true - }, - "strip-ansi": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-4.0.0.tgz", - "integrity": "sha1-qEeQIusaw2iocTibY1JixQXuNo8=", - "dev": true, - "requires": { - "ansi-regex": "^3.0.0" - } - } - } - }, - "string-width": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/string-width/-/string-width-3.1.0.tgz", - "integrity": "sha512-vafcv6KjVZKSgz06oM/H6GDBrAtz8vdhQakGjFIvNrHA6y3HCF1CInLy+QLq8dTJPQ1b+KDUqDFctkdRW44e1w==", - "dev": true, - "requires": { - "emoji-regex": "^7.0.1", - "is-fullwidth-code-point": "^2.0.0", - "strip-ansi": "^5.1.0" - } - }, - "string.prototype.trimleft": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/string.prototype.trimleft/-/string.prototype.trimleft-2.1.0.tgz", - "integrity": "sha512-FJ6b7EgdKxxbDxc79cOlok6Afd++TTs5szo+zJTUyow3ycrRfJVE2pq3vcN53XexvKZu/DJMDfeI/qMiZTrjTw==", - "dev": true, - "requires": { - "define-properties": "^1.1.3", - "function-bind": "^1.1.1" - } - }, - "string.prototype.trimright": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/string.prototype.trimright/-/string.prototype.trimright-2.1.0.tgz", - "integrity": "sha512-fXZTSV55dNBwv16uw+hh5jkghxSnc5oHq+5K/gXgizHwAvMetdAJlHqqoFC1FSDVPYWLkAKl2cxpUT41sV7nSg==", - "dev": true, - "requires": { - "define-properties": "^1.1.3", - "function-bind": "^1.1.1" - } - }, - "string_decoder": { - "version": "0.10.31", - "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-0.10.31.tgz", - "integrity": "sha1-YuIDvEF2bGwoyfyEMB2rHFMQ+pQ=", - "dev": true - }, - "strip-ansi": { - "version": "5.2.0", - "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-5.2.0.tgz", - "integrity": "sha512-DuRs1gKbBqsMKIZlrffwlug8MHkcnpjs5VPmL1PAh+mA30U0DTotfDZ0d2UUsXpPmPmMMJ6W773MaA3J+lbiWA==", - "dev": true, - "requires": { - "ansi-regex": "^4.1.0" - } - }, - "strip-bom": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/strip-bom/-/strip-bom-3.0.0.tgz", - "integrity": "sha1-IzTBjpx1n3vdVv3vfprj1YjmjtM=", - "dev": true - }, - "strip-eof": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/strip-eof/-/strip-eof-1.0.0.tgz", - "integrity": "sha1-u0P/VZim6wXYm1n80SnJgzE2Br8=", - "dev": true - }, - "supports-color": { - "version": "5.5.0", - "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-5.5.0.tgz", - "integrity": "sha512-QjVjwdXIt408MIiAqCX4oUKsgU2EqAGzs2Ppkm4aQYbjm+ZEWEcW4SfFNTr4uMNZma0ey4f5lgLrkB0aX0QMow==", - "dev": true, - "requires": { - "has-flag": "^3.0.0" - } - }, - "symbol-tree": { - "version": "3.2.4", - "resolved": "https://registry.npmjs.org/symbol-tree/-/symbol-tree-3.2.4.tgz", - "integrity": "sha512-9QNk5KwDF+Bvz+PyObkmSYjI5ksVUYtjW7AU22r2NKcfLJcXp96hkDWU3+XndOsUb+AQ9QhfzfCT2O+CNWT5Tw==", - "dev": true - }, - "test-exclude": { - "version": "5.2.3", - "resolved": "https://registry.npmjs.org/test-exclude/-/test-exclude-5.2.3.tgz", - "integrity": "sha512-M+oxtseCFO3EDtAaGH7iiej3CBkzXqFMbzqYAACdzKui4eZA+pq3tZEwChvOdNfa7xxy8BfbmgJSIr43cC/+2g==", - "dev": true, - "requires": { - "glob": "^7.1.3", - "minimatch": "^3.0.4", - "read-pkg-up": "^4.0.0", - "require-main-filename": "^2.0.0" - } - }, - "throat": { - "version": "4.1.0", - "resolved": "https://registry.npmjs.org/throat/-/throat-4.1.0.tgz", - "integrity": "sha1-iQN8vJLFarGJJua6TLsgDhVnKmo=", - "dev": true - }, - "tmpl": { - "version": "1.0.4", - "resolved": "https://registry.npmjs.org/tmpl/-/tmpl-1.0.4.tgz", - "integrity": "sha1-I2QN17QtAEM5ERQIIOXPRA5SHdE=", - "dev": true - }, - "to-fast-properties": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/to-fast-properties/-/to-fast-properties-2.0.0.tgz", - "integrity": "sha1-3F5pjL0HkmW8c+A3doGk5Og/YW4=", - "dev": true - }, - "to-object-path": { - "version": "0.3.0", - "resolved": "https://registry.npmjs.org/to-object-path/-/to-object-path-0.3.0.tgz", - "integrity": "sha1-KXWIt7Dn4KwI4E5nL4XB9JmeF68=", - "dev": true, - "requires": { - "kind-of": "^3.0.2" - }, - "dependencies": { - "is-buffer": { - "version": "1.1.6", - "resolved": "https://registry.npmjs.org/is-buffer/-/is-buffer-1.1.6.tgz", - "integrity": "sha512-NcdALwpXkTm5Zvvbk7owOUSvVvBKDgKP5/ewfXEznmQFfs4ZRmanOeKBTjRVjka3QFoN6XJ+9F3USqfHqTaU5w==", - "dev": true - }, - "kind-of": { - "version": "3.2.2", - "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-3.2.2.tgz", - "integrity": "sha1-MeohpzS6ubuw8yRm2JOupR5KPGQ=", - "dev": true, - "requires": { - "is-buffer": "^1.1.5" - } - } - } - }, - "to-regex": { - "version": "3.0.2", - "resolved": "https://registry.npmjs.org/to-regex/-/to-regex-3.0.2.tgz", - "integrity": "sha512-FWtleNAtZ/Ki2qtqej2CXTOayOH9bHDQF+Q48VpWyDXjbYxA4Yz8iDB31zXOBUlOHHKidDbqGVrTUvQMPmBGBw==", - "dev": true, - "requires": { - "define-property": "^2.0.2", - "extend-shallow": "^3.0.2", - "regex-not": "^1.0.2", - "safe-regex": "^1.1.0" - } - }, - "to-regex-range": { - "version": "2.1.1", - "resolved": "https://registry.npmjs.org/to-regex-range/-/to-regex-range-2.1.1.tgz", - "integrity": "sha1-fIDBe53+vlmeJzZ+DU3VWQFB2zg=", - "dev": true, - "requires": { - "is-number": "^3.0.0", - "repeat-string": "^1.6.1" - } - }, - "toidentifier": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/toidentifier/-/toidentifier-1.0.0.tgz", - "integrity": "sha512-yaOH/Pk/VEhBWWTlhI+qXxDFXlejDGcQipMlyxda9nthulaxLZUNcUqFxokp0vcYnvteJln5FNQDRrxj3YcbVw==", - "dev": true - }, - "tough-cookie": { - "version": "2.5.0", - "resolved": "https://registry.npmjs.org/tough-cookie/-/tough-cookie-2.5.0.tgz", - "integrity": "sha512-nlLsUzgm1kfLXSXfRZMc1KLAugd4hqJHDTvc2hDIwS3mZAfMEuMbc03SujMF+GEcpaX/qboeycw6iO8JwVv2+g==", - "dev": true, - "requires": { - "psl": "^1.1.28", - "punycode": "^2.1.1" - } - }, - "tr46": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/tr46/-/tr46-1.0.1.tgz", - "integrity": "sha1-qLE/1r/SSJUZZ0zN5VujaTtwbQk=", - "dev": true, - "requires": { - "punycode": "^2.1.0" - } - }, - "ts-jest": { - "version": "24.1.0", - "resolved": "https://registry.npmjs.org/ts-jest/-/ts-jest-24.1.0.tgz", - "integrity": "sha512-HEGfrIEAZKfu1pkaxB9au17b1d9b56YZSqz5eCVE8mX68+5reOvlM93xGOzzCREIov9mdH7JBG+s0UyNAqr0tQ==", - "dev": true, - "requires": { - "bs-logger": "0.x", - "buffer-from": "1.x", - "fast-json-stable-stringify": "2.x", - "json5": "2.x", - "lodash.memoize": "4.x", - "make-error": "1.x", - "mkdirp": "0.x", - "resolve": "1.x", - "semver": "^5.5", - "yargs-parser": "10.x" - }, - "dependencies": { - "camelcase": { - "version": "4.1.0", - "resolved": "https://registry.npmjs.org/camelcase/-/camelcase-4.1.0.tgz", - "integrity": "sha1-1UVjW+HjPFQmScaRc+Xeas+uNN0=", - "dev": true - }, - "yargs-parser": { - "version": "10.1.0", - "resolved": "https://registry.npmjs.org/yargs-parser/-/yargs-parser-10.1.0.tgz", - "integrity": "sha512-VCIyR1wJoEBZUqk5PA+oOBF6ypbwh5aNB3I50guxAL/quggdfs4TtNHQrSazFA3fYZ+tEqfs0zIGlv0c/rgjbQ==", - "dev": true, - "requires": { - "camelcase": "^4.1.0" - } - } - } - }, - "tslib": { - "version": "1.10.0", - "resolved": "https://registry.npmjs.org/tslib/-/tslib-1.10.0.tgz", - "integrity": "sha512-qOebF53frne81cf0S9B41ByenJ3/IuH8yJKngAX35CmiZySA0khhkovshKK+jGCaMnVomla7gVlIcc3EvKPbTQ==", - "dev": true - }, - "tslint": { - "version": "5.20.0", - "resolved": "https://registry.npmjs.org/tslint/-/tslint-5.20.0.tgz", - "integrity": "sha512-2vqIvkMHbnx8acMogAERQ/IuINOq6DFqgF8/VDvhEkBqQh/x6SP0Y+OHnKth9/ZcHQSroOZwUQSN18v8KKF0/g==", - "dev": true, - "requires": { - "@babel/code-frame": "^7.0.0", - "builtin-modules": "^1.1.1", - "chalk": "^2.3.0", - "commander": "^2.12.1", - "diff": "^4.0.1", - "glob": "^7.1.1", - "js-yaml": "^3.13.1", - "minimatch": "^3.0.4", - "mkdirp": "^0.5.1", - "resolve": "^1.3.2", - "semver": "^5.3.0", - "tslib": "^1.8.0", - "tsutils": "^2.29.0" - } - }, - "tsutils": { - "version": "2.29.0", - "resolved": "https://registry.npmjs.org/tsutils/-/tsutils-2.29.0.tgz", - "integrity": "sha512-g5JVHCIJwzfISaXpXE1qvNalca5Jwob6FjI4AoPlqMusJ6ftFE7IkkFoMhVLRgK+4Kx3gkzb8UZK5t5yTTvEmA==", - "dev": true, - "requires": { - "tslib": "^1.8.1" - } - }, - "tunnel-agent": { - "version": "0.6.0", - "resolved": "https://registry.npmjs.org/tunnel-agent/-/tunnel-agent-0.6.0.tgz", - "integrity": "sha1-J6XeoGs2sEoKmWZ3SykIaPD8QP0=", - "dev": true, - "requires": { - "safe-buffer": "^5.0.1" - } - }, - "tweetnacl": { - "version": "0.14.5", - "resolved": "https://registry.npmjs.org/tweetnacl/-/tweetnacl-0.14.5.tgz", - "integrity": "sha1-WuaBd/GS1EViadEIr6k/+HQ/T2Q=", - "dev": true - }, - "type-check": { - "version": "0.3.2", - "resolved": "https://registry.npmjs.org/type-check/-/type-check-0.3.2.tgz", - "integrity": "sha1-WITKtRLPHTVeP7eE8wgEsrUg23I=", - "dev": true, - "requires": { - "prelude-ls": "~1.1.2" - } - }, - "type-fest": { - "version": "0.6.0", - "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-0.6.0.tgz", - "integrity": "sha512-q+MB8nYR1KDLrgr4G5yemftpMC7/QLqVndBmEEdqzmNj5dcFOO4Oo8qlwZE3ULT3+Zim1F8Kq4cBnikNhlCMlg==", - "dev": true - }, - "type-is": { - "version": "1.6.18", - "resolved": "https://registry.npmjs.org/type-is/-/type-is-1.6.18.tgz", - "integrity": "sha512-TkRKr9sUTxEH8MdfuCSP7VizJyzRNMjj2J2do2Jr3Kym598JVdEksuzPQCnlFPW4ky9Q+iA+ma9BGm06XQBy8g==", - "dev": true, - "requires": { - "media-typer": "0.3.0", - "mime-types": "~2.1.24" - } - }, - "typedarray": { - "version": "0.0.6", - "resolved": "https://registry.npmjs.org/typedarray/-/typedarray-0.0.6.tgz", - "integrity": "sha1-hnrHTjhkGHsdPUfZlqeOxciDB3c=", - "dev": true - }, - "typescript": { - "version": "3.7.5", - "resolved": "https://registry.npmjs.org/typescript/-/typescript-3.7.5.tgz", - "integrity": "sha512-/P5lkRXkWHNAbcJIiHPfRoKqyd7bsyCma1hZNUGfn20qm64T6ZBlrzprymeu918H+mB/0rIg2gGK/BXkhhYgBw==", - "dev": true - }, - "uglify-js": { - "version": "3.6.0", - "resolved": "https://registry.npmjs.org/uglify-js/-/uglify-js-3.6.0.tgz", - "integrity": "sha512-W+jrUHJr3DXKhrsS7NUVxn3zqMOFn0hL/Ei6v0anCIMoKC93TjcflTagwIHLW7SfMFfiQuktQyFVCFHGUE0+yg==", - "dev": true, - "optional": true, - "requires": { - "commander": "~2.20.0", - "source-map": "~0.6.1" - } - }, - "union-value": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/union-value/-/union-value-1.0.1.tgz", - "integrity": "sha512-tJfXmxMeWYnczCVs7XAEvIV7ieppALdyepWMkHkwciRpZraG/xwT+s2JN8+pr1+8jCRf80FFzvr+MpQeeoF4Xg==", - "dev": true, - "requires": { - "arr-union": "^3.1.0", - "get-value": "^2.0.6", - "is-extendable": "^0.1.1", - "set-value": "^2.0.1" - } - }, - "unpipe": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/unpipe/-/unpipe-1.0.0.tgz", - "integrity": "sha1-sr9O6FFKrmFltIF4KdIbLvSZBOw=", - "dev": true - }, - "unset-value": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/unset-value/-/unset-value-1.0.0.tgz", - "integrity": "sha1-g3aHP30jNRef+x5vw6jtDfyKtVk=", - "dev": true, - "requires": { - "has-value": "^0.3.1", - "isobject": "^3.0.0" - }, - "dependencies": { - "has-value": { - "version": "0.3.1", - "resolved": "https://registry.npmjs.org/has-value/-/has-value-0.3.1.tgz", - "integrity": "sha1-ex9YutpiyoJ+wKIHgCVlSEWZXh8=", - "dev": true, - "requires": { - "get-value": "^2.0.3", - "has-values": "^0.1.4", - "isobject": "^2.0.0" - }, - "dependencies": { - "isobject": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/isobject/-/isobject-2.1.0.tgz", - "integrity": "sha1-8GVWEJaj8dou9GJy+BXIQNh+DIk=", - "dev": true, - "requires": { - "isarray": "1.0.0" - } - } - } - }, - "has-values": { - "version": "0.1.4", - "resolved": "https://registry.npmjs.org/has-values/-/has-values-0.1.4.tgz", - "integrity": "sha1-bWHeldkd/Km5oCCJrThL/49it3E=", - "dev": true - } - } - }, - "uri-js": { - "version": "4.2.2", - "resolved": "https://registry.npmjs.org/uri-js/-/uri-js-4.2.2.tgz", - "integrity": "sha512-KY9Frmirql91X2Qgjry0Wd4Y+YTdrdZheS8TFwvkbLWf/G5KNJDCh6pKL5OZctEW4+0Baa5idK2ZQuELRwPznQ==", - "dev": true, - "requires": { - "punycode": "^2.1.0" - } - }, - "urix": { - "version": "0.1.0", - "resolved": "https://registry.npmjs.org/urix/-/urix-0.1.0.tgz", - "integrity": "sha1-2pN/emLiH+wf0Y1Js1wpNQZ6bHI=", - "dev": true - }, - "use": { - "version": "3.1.1", - "resolved": "https://registry.npmjs.org/use/-/use-3.1.1.tgz", - "integrity": "sha512-cwESVXlO3url9YWlFW/TA9cshCEhtu7IKJ/p5soJ/gGpj7vbvFrAY/eIioQ6Dw23KjZhYgiIo8HOs1nQ2vr/oQ==", - "dev": true - }, - "util-deprecate": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/util-deprecate/-/util-deprecate-1.0.2.tgz", - "integrity": "sha1-RQ1Nyfpw3nMnYvvS1KKJgUGaDM8=", - "dev": true - }, - "util.promisify": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/util.promisify/-/util.promisify-1.0.0.tgz", - "integrity": "sha512-i+6qA2MPhvoKLuxnJNpXAGhg7HphQOSUq2LKMZD0m15EiskXUkMvKdF4Uui0WYeCUGea+o2cw/ZuwehtfsrNkA==", - "dev": true, - "requires": { - "define-properties": "^1.1.2", - "object.getownpropertydescriptors": "^2.0.3" - } - }, - "utils-merge": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/utils-merge/-/utils-merge-1.0.1.tgz", - "integrity": "sha1-n5VxD1CiZ5R7LMwSR0HBAoQn5xM=", - "dev": true - }, - "uuid": { - "version": "3.3.3", - "resolved": "https://registry.npmjs.org/uuid/-/uuid-3.3.3.tgz", - "integrity": "sha512-pW0No1RGHgzlpHJO1nsVrHKpOEIxkGg1xB+v0ZmdNH5OAeAwzAVrCnI2/6Mtx+Uys6iaylxa+D3g4j63IKKjSQ==", - "dev": true - }, - "validate-npm-package-license": { - "version": "3.0.4", - "resolved": "https://registry.npmjs.org/validate-npm-package-license/-/validate-npm-package-license-3.0.4.tgz", - "integrity": "sha512-DpKm2Ui/xN7/HQKCtpZxoRWBhZ9Z0kqtygG8XCgNQ8ZlDnxuQmWhj566j8fN4Cu3/JmbhsDo7fcAJq4s9h27Ew==", - "dev": true, - "requires": { - "spdx-correct": "^3.0.0", - "spdx-expression-parse": "^3.0.0" - } - }, - "vary": { - "version": "1.1.2", - "resolved": "https://registry.npmjs.org/vary/-/vary-1.1.2.tgz", - "integrity": "sha1-IpnwLG3tMNSllhsLn3RSShj2NPw=", - "dev": true - }, - "verror": { - "version": "1.10.0", - "resolved": "https://registry.npmjs.org/verror/-/verror-1.10.0.tgz", - "integrity": "sha1-OhBcoXBTr1XW4nDB+CiGguGNpAA=", - "dev": true, - "requires": { - "assert-plus": "^1.0.0", - "core-util-is": "1.0.2", - "extsprintf": "^1.2.0" - } - }, - "w3c-hr-time": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/w3c-hr-time/-/w3c-hr-time-1.0.1.tgz", - "integrity": "sha1-gqwr/2PZUOqeMYmlimViX+3xkEU=", - "dev": true, - "requires": { - "browser-process-hrtime": "^0.1.2" - } - }, - "walker": { - "version": "1.0.7", - "resolved": "https://registry.npmjs.org/walker/-/walker-1.0.7.tgz", - "integrity": "sha1-L3+bj9ENZ3JisYqITijRlhjgKPs=", - "dev": true, - "requires": { - "makeerror": "1.0.x" - } - }, - "webidl-conversions": { - "version": "4.0.2", - "resolved": "https://registry.npmjs.org/webidl-conversions/-/webidl-conversions-4.0.2.tgz", - "integrity": "sha512-YQ+BmxuTgd6UXZW3+ICGfyqRyHXVlD5GtQr5+qjiNW7bF0cqrzX500HVXPBOvgXb5YnzDd+h0zqyv61KUD7+Sg==", - "dev": true - }, - "whatwg-encoding": { - "version": "1.0.5", - "resolved": "https://registry.npmjs.org/whatwg-encoding/-/whatwg-encoding-1.0.5.tgz", - "integrity": "sha512-b5lim54JOPN9HtzvK9HFXvBma/rnfFeqsic0hSpjtDbVxR3dJKLc+KB4V6GgiGOvl7CY/KNh8rxSo9DKQrnUEw==", - "dev": true, - "requires": { - "iconv-lite": "0.4.24" - } - }, - "whatwg-mimetype": { - "version": "2.3.0", - "resolved": "https://registry.npmjs.org/whatwg-mimetype/-/whatwg-mimetype-2.3.0.tgz", - "integrity": "sha512-M4yMwr6mAnQz76TbJm914+gPpB/nCwvZbJU28cUD6dR004SAxDLOOSUaB1JDRqLtaOV/vi0IC5lEAGFgrjGv/g==", - "dev": true - }, - "whatwg-url": { - "version": "6.5.0", - "resolved": "https://registry.npmjs.org/whatwg-url/-/whatwg-url-6.5.0.tgz", - "integrity": "sha512-rhRZRqx/TLJQWUpQ6bmrt2UV4f0HCQ463yQuONJqC6fO2VoEb1pTYddbe59SkYq87aoM5A3bdhMZiUiVws+fzQ==", - "dev": true, - "requires": { - "lodash.sortby": "^4.7.0", - "tr46": "^1.0.1", - "webidl-conversions": "^4.0.2" - } - }, - "which": { - "version": "1.3.1", - "resolved": "https://registry.npmjs.org/which/-/which-1.3.1.tgz", - "integrity": "sha512-HxJdYWq1MTIQbJ3nw0cqssHoTNU267KlrDuGZ1WYlxDStUtKUhOaJmh112/TZmHxxUfuJqPXSOm7tDyas0OSIQ==", - "dev": true, - "requires": { - "isexe": "^2.0.0" - } - }, - "which-module": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/which-module/-/which-module-2.0.0.tgz", - "integrity": "sha1-2e8H3Od7mQK4o6j6SzHD4/fm6Ho=", - "dev": true - }, - "wordwrap": { - "version": "0.0.3", - "resolved": "https://registry.npmjs.org/wordwrap/-/wordwrap-0.0.3.tgz", - "integrity": "sha1-o9XabNXAvAAI03I0u68b7WMFkQc=", - "dev": true - }, - "wrap-ansi": { - "version": "5.1.0", - "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-5.1.0.tgz", - "integrity": "sha512-QC1/iN/2/RPVJ5jYK8BGttj5z83LmSKmvbvrXPNCLZSEb32KKVDJDl/MOt2N01qU2H/FkzEa9PKto1BqDjtd7Q==", - "dev": true, - "requires": { - "ansi-styles": "^3.2.0", - "string-width": "^3.0.0", - "strip-ansi": "^5.0.0" - } - }, - "wrappy": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/wrappy/-/wrappy-1.0.2.tgz", - "integrity": "sha1-tSQ9jz7BqjXxNkYFvA0QNuMKtp8=", - "dev": true - }, - "write-file-atomic": { - "version": "2.4.1", - "resolved": "https://registry.npmjs.org/write-file-atomic/-/write-file-atomic-2.4.1.tgz", - "integrity": "sha512-TGHFeZEZMnv+gBFRfjAcxL5bPHrsGKtnb4qsFAws7/vlh+QfwAaySIw4AXP9ZskTTh5GWu3FLuJhsWVdiJPGvg==", - "dev": true, - "requires": { - "graceful-fs": "^4.1.11", - "imurmurhash": "^0.1.4", - "signal-exit": "^3.0.2" - } - }, - "ws": { - "version": "5.2.2", - "resolved": "https://registry.npmjs.org/ws/-/ws-5.2.2.tgz", - "integrity": "sha512-jaHFD6PFv6UgoIVda6qZllptQsMlDEJkTQcybzzXDYM1XO9Y8em691FGMPmM46WGyLU4z9KMgQN+qrux/nhlHA==", - "dev": true, - "requires": { - "async-limiter": "~1.0.0" - } - }, - "xml-name-validator": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/xml-name-validator/-/xml-name-validator-3.0.0.tgz", - "integrity": "sha512-A5CUptxDsvxKJEU3yO6DuWBSJz/qizqzJKOMIfUJHETbBw/sFaDxgd6fxm1ewUaM0jZ444Fc5vC5ROYurg/4Pw==", - "dev": true - }, - "xtend": { - "version": "4.0.2", - "resolved": "https://registry.npmjs.org/xtend/-/xtend-4.0.2.tgz", - "integrity": "sha512-LKYU1iAXJXUgAXn9URjiu+MWhyUXHsvfp7mcuYm9dSUKK0/CjtrUwFAxD82/mCWbtLsGjFIad0wIsod4zrTAEQ==", - "dev": true - }, - "y18n": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/y18n/-/y18n-4.0.0.tgz", - "integrity": "sha512-r9S/ZyXu/Xu9q1tYlpsLIsa3EeLXXk0VwlxqTcFRfg9EhMW+17kbt9G0NrgCmhGb5vT2hyhJZLfDGx+7+5Uj/w==", - "dev": true - }, - "yargs": { - "version": "13.3.0", - "resolved": "https://registry.npmjs.org/yargs/-/yargs-13.3.0.tgz", - "integrity": "sha512-2eehun/8ALW8TLoIl7MVaRUrg+yCnenu8B4kBlRxj3GJGDKU1Og7sMXPNm1BYyM1DOJmTZ4YeN/Nwxv+8XJsUA==", - "dev": true, - "requires": { - "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.1" - } - }, - "yargs-parser": { - "version": "13.1.1", - "resolved": "https://registry.npmjs.org/yargs-parser/-/yargs-parser-13.1.1.tgz", - "integrity": "sha512-oVAVsHz6uFrg3XQheFII8ESO2ssAf9luWuAd6Wexsu4F3OtIW0o8IribPXYrD4WC24LWtPrJlGy87y5udK+dxQ==", - "dev": true, - "requires": { - "camelcase": "^5.0.0", - "decamelize": "^1.2.0" - } - } - } -} diff --git a/package.json b/package.json index 91f64a6..385e264 100644 --- a/package.json +++ b/package.json @@ -1,52 +1,60 @@ { - "name": "ts-retrofit", - "version": "1.11.1", - "description": "A declarative and axios based retrofit implementation for JavaScript and TypeScript.", - "repository": "https://github.com/nullcc/ts-retrofit", - "main": "lib/index.js", - "types": "lib/types/index.d.ts", + "name": "ts-retrofit2", + "version": "2.2.2", + "description": "A declarative and axios based retrofit implementation for JavaScript and TypeScript. (forked from https://github.com/nullcc/ts-retrofit)", + "repository": "https://github.com/npwork/ts-retrofit2", + "main": "dist/index.js", + "types": "dist/index.d.ts", "keywords": [ "retrofit", "ts", "js", "axios" ], - "bugs": "https://github.com/nullcc/ts-retrofit/issues", + "bugs": "https://github.com/npwork/ts-retrofit2/issues", "scripts": { "test": "jest --coverage", - "tslint": "tslint -c tslint.json --project . src/**/*.ts test/**/*.test.ts", + "test:watch": "jest --watch", "build": "tsc", - "make-badges": "node_modules/.bin/jest-badges-readme", - "prepare": "npm run build", - "prepublishOnly": "npm run tslint", - "preversion": "npm run tslint", - "postversion": "git push && git push --tags" + "format": "prettier --config .prettierrc '{src,test}/**/*.ts' --write", + "lint": "eslint . --ext .ts", + "lint:fix": "eslint . --ext .ts --fix", + "make-badges": "istanbul-badges-readme", + "prepare": "husky install", + "prepublishOnly": "yarn run lint" }, - "author": "Ethan Zhang", + "author": "NP", "license": "MIT", - "husky": { - "hooks": { - "pre-commit": "npm test && npm run make-badges && git add README.md" - } - }, "dependencies": { - "axios": "^0.19.0", - "form-data": "^2.5.1", - "qs": "^6.8.0" + "axios": "^0.24.0", + "class-transformer": "^0.5.1", + "class-validator": "^0.13.2", + "form-data": "^4.0.0", + "qs": "^6.10.2", + "reflect-metadata": "^0.1.13" }, "devDependencies": { - "@olavoparno/jest-badges-readme": "^1.4.0", - "@types/express": "^4.17.1", - "@types/jest": "^24.0.18", - "@types/multer": "^1.3.10", - "@types/qs": "^6.5.3", - "body-parser": "^1.19.0", - "express": "^4.17.1", - "husky": "^3.1.0", - "jest": "^24.9.0", - "multer": "^1.4.2", - "ts-jest": "^24.0.2", - "tslint": "^5.19.0", - "typescript": "^3.7.5" + "@commitlint/cli": "15.0.0", + "@commitlint/config-conventional": "15.0.0", + "@types/express": "4.17.13", + "@types/jest": "27.0.3", + "@types/multer": "1.4.7", + "@types/qs": "6.9.7", + "@types/validator": "^13.7.0", + "@typescript-eslint/eslint-plugin": "^5.7.0", + "@typescript-eslint/parser": "^5.7.0", + "body-parser": "1.19.1", + "eslint": "8.5.0", + "eslint-config-prettier": "8.3.0", + "eslint-plugin-prettier": "4.0.0", + "eslint-plugin-unused-imports": "2.0.0", + "express": "4.17.2", + "husky": "7.0.4", + "istanbul-badges-readme": "1.8.1", + "jest": "27.4.5", + "multer": "1.4.4", + "prettier": "2.5.1", + "ts-jest": "27.1.2", + "typescript": "^4.5.4" } } diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml new file mode 100644 index 0000000..5720357 --- /dev/null +++ b/pnpm-lock.yaml @@ -0,0 +1,4605 @@ +lockfileVersion: 5.3 + +specifiers: + '@commitlint/cli': 15.0.0 + '@commitlint/config-conventional': 15.0.0 + '@types/express': 4.17.13 + '@types/jest': 27.0.3 + '@types/multer': 1.4.7 + '@types/qs': 6.9.7 + '@types/validator': ^13.7.0 + '@typescript-eslint/eslint-plugin': ^5.7.0 + '@typescript-eslint/parser': ^5.7.0 + axios: ^0.24.0 + body-parser: 1.19.1 + class-transformer: ^0.5.1 + class-validator: ^0.13.2 + eslint: 8.5.0 + eslint-config-prettier: 8.3.0 + eslint-plugin-prettier: 4.0.0 + eslint-plugin-unused-imports: 2.0.0 + express: 4.17.2 + form-data: ^4.0.0 + husky: 7.0.4 + istanbul-badges-readme: 1.8.1 + jest: 27.4.5 + multer: 1.4.4 + prettier: 2.5.1 + qs: ^6.10.2 + reflect-metadata: ^0.1.13 + ts-jest: 27.1.2 + typescript: ^4.5.4 + +dependencies: + axios: 0.24.0 + class-transformer: 0.5.1 + class-validator: 0.13.2 + form-data: 4.0.0 + qs: 6.10.2 + reflect-metadata: 0.1.13 + +devDependencies: + '@commitlint/cli': 15.0.0 + '@commitlint/config-conventional': 15.0.0 + '@types/express': 4.17.13 + '@types/jest': 27.0.3 + '@types/multer': 1.4.7 + '@types/qs': 6.9.7 + '@types/validator': 13.7.0 + '@typescript-eslint/eslint-plugin': 5.7.0_a6f6159640504abdd3de077f8bcadb33 + '@typescript-eslint/parser': 5.7.0_eslint@8.5.0+typescript@4.5.4 + body-parser: 1.19.1 + eslint: 8.5.0 + eslint-config-prettier: 8.3.0_eslint@8.5.0 + eslint-plugin-prettier: 4.0.0_94e1b6d3ce6ea916847122712570e9ae + eslint-plugin-unused-imports: 2.0.0_5a3e1449e31fbcbb167860ec6a3f3d63 + express: 4.17.2 + husky: 7.0.4 + istanbul-badges-readme: 1.8.1 + jest: 27.4.5 + multer: 1.4.4 + prettier: 2.5.1 + ts-jest: 27.1.2_b65cae1b46840061996b6cc0ea16ca56 + typescript: 4.5.4 + +packages: + + /@babel/code-frame/7.16.0: + resolution: {integrity: sha512-IF4EOMEV+bfYwOmNxGzSnjR2EmQod7f1UXOpZM3l4i4o4QNwzjtJAu/HxdjHq0aYBvdqMuQEY1eg0nqW9ZPORA==} + engines: {node: '>=6.9.0'} + dependencies: + '@babel/highlight': 7.16.0 + dev: true + + /@babel/compat-data/7.16.4: + resolution: {integrity: sha512-1o/jo7D+kC9ZjHX5v+EHrdjl3PhxMrLSOTGsOdHJ+KL8HCaEK6ehrVL2RS6oHDZp+L7xLirLrPmQtEng769J/Q==} + engines: {node: '>=6.9.0'} + dev: true + + /@babel/core/7.16.5: + resolution: {integrity: sha512-wUcenlLzuWMZ9Zt8S0KmFwGlH6QKRh3vsm/dhDA3CHkiTA45YuG1XkHRcNRl73EFPXDp/d5kVOU0/y7x2w6OaQ==} + engines: {node: '>=6.9.0'} + dependencies: + '@babel/code-frame': 7.16.0 + '@babel/generator': 7.16.5 + '@babel/helper-compilation-targets': 7.16.3_@babel+core@7.16.5 + '@babel/helper-module-transforms': 7.16.5 + '@babel/helpers': 7.16.5 + '@babel/parser': 7.16.6 + '@babel/template': 7.16.0 + '@babel/traverse': 7.16.5 + '@babel/types': 7.16.0 + convert-source-map: 1.8.0 + debug: 4.3.3 + gensync: 1.0.0-beta.2 + json5: 2.2.0 + semver: 6.3.0 + source-map: 0.5.7 + transitivePeerDependencies: + - supports-color + dev: true + + /@babel/generator/7.16.5: + resolution: {integrity: sha512-kIvCdjZqcdKqoDbVVdt5R99icaRtrtYhYK/xux5qiWCBmfdvEYMFZ68QCrpE5cbFM1JsuArUNs1ZkuKtTtUcZA==} + engines: {node: '>=6.9.0'} + dependencies: + '@babel/types': 7.16.0 + jsesc: 2.5.2 + source-map: 0.5.7 + dev: true + + /@babel/helper-compilation-targets/7.16.3_@babel+core@7.16.5: + resolution: {integrity: sha512-vKsoSQAyBmxS35JUOOt+07cLc6Nk/2ljLIHwmq2/NM6hdioUaqEXq/S+nXvbvXbZkNDlWOymPanJGOc4CBjSJA==} + engines: {node: '>=6.9.0'} + peerDependencies: + '@babel/core': ^7.0.0 + dependencies: + '@babel/compat-data': 7.16.4 + '@babel/core': 7.16.5 + '@babel/helper-validator-option': 7.14.5 + browserslist: 4.19.1 + semver: 6.3.0 + dev: true + + /@babel/helper-environment-visitor/7.16.5: + resolution: {integrity: sha512-ODQyc5AnxmZWm/R2W7fzhamOk1ey8gSguo5SGvF0zcB3uUzRpTRmM/jmLSm9bDMyPlvbyJ+PwPEK0BWIoZ9wjg==} + engines: {node: '>=6.9.0'} + dependencies: + '@babel/types': 7.16.0 + dev: true + + /@babel/helper-function-name/7.16.0: + resolution: {integrity: sha512-BZh4mEk1xi2h4HFjWUXRQX5AEx4rvaZxHgax9gcjdLWdkjsY7MKt5p0otjsg5noXw+pB+clMCjw+aEVYADMjog==} + engines: {node: '>=6.9.0'} + dependencies: + '@babel/helper-get-function-arity': 7.16.0 + '@babel/template': 7.16.0 + '@babel/types': 7.16.0 + dev: true + + /@babel/helper-get-function-arity/7.16.0: + resolution: {integrity: sha512-ASCquNcywC1NkYh/z7Cgp3w31YW8aojjYIlNg4VeJiHkqyP4AzIvr4qx7pYDb4/s8YcsZWqqOSxgkvjUz1kpDQ==} + engines: {node: '>=6.9.0'} + dependencies: + '@babel/types': 7.16.0 + dev: true + + /@babel/helper-hoist-variables/7.16.0: + resolution: {integrity: sha512-1AZlpazjUR0EQZQv3sgRNfM9mEVWPK3M6vlalczA+EECcPz3XPh6VplbErL5UoMpChhSck5wAJHthlj1bYpcmg==} + engines: {node: '>=6.9.0'} + dependencies: + '@babel/types': 7.16.0 + dev: true + + /@babel/helper-module-imports/7.16.0: + resolution: {integrity: sha512-kkH7sWzKPq0xt3H1n+ghb4xEMP8k0U7XV3kkB+ZGy69kDk2ySFW1qPi06sjKzFY3t1j6XbJSqr4mF9L7CYVyhg==} + engines: {node: '>=6.9.0'} + dependencies: + '@babel/types': 7.16.0 + dev: true + + /@babel/helper-module-transforms/7.16.5: + resolution: {integrity: sha512-CkvMxgV4ZyyioElFwcuWnDCcNIeyqTkCm9BxXZi73RR1ozqlpboqsbGUNvRTflgZtFbbJ1v5Emvm+lkjMYY/LQ==} + engines: {node: '>=6.9.0'} + dependencies: + '@babel/helper-environment-visitor': 7.16.5 + '@babel/helper-module-imports': 7.16.0 + '@babel/helper-simple-access': 7.16.0 + '@babel/helper-split-export-declaration': 7.16.0 + '@babel/helper-validator-identifier': 7.15.7 + '@babel/template': 7.16.0 + '@babel/traverse': 7.16.5 + '@babel/types': 7.16.0 + transitivePeerDependencies: + - supports-color + dev: true + + /@babel/helper-plugin-utils/7.16.5: + resolution: {integrity: sha512-59KHWHXxVA9K4HNF4sbHCf+eJeFe0Te/ZFGqBT4OjXhrwvA04sGfaEGsVTdsjoszq0YTP49RC9UKe5g8uN2RwQ==} + engines: {node: '>=6.9.0'} + dev: true + + /@babel/helper-simple-access/7.16.0: + resolution: {integrity: sha512-o1rjBT/gppAqKsYfUdfHq5Rk03lMQrkPHG1OWzHWpLgVXRH4HnMM9Et9CVdIqwkCQlobnGHEJMsgWP/jE1zUiw==} + engines: {node: '>=6.9.0'} + dependencies: + '@babel/types': 7.16.0 + dev: true + + /@babel/helper-split-export-declaration/7.16.0: + resolution: {integrity: sha512-0YMMRpuDFNGTHNRiiqJX19GjNXA4H0E8jZ2ibccfSxaCogbm3am5WN/2nQNj0YnQwGWM1J06GOcQ2qnh3+0paw==} + engines: {node: '>=6.9.0'} + dependencies: + '@babel/types': 7.16.0 + dev: true + + /@babel/helper-validator-identifier/7.15.7: + resolution: {integrity: sha512-K4JvCtQqad9OY2+yTU8w+E82ywk/fe+ELNlt1G8z3bVGlZfn/hOcQQsUhGhW/N+tb3fxK800wLtKOE/aM0m72w==} + engines: {node: '>=6.9.0'} + dev: true + + /@babel/helper-validator-option/7.14.5: + resolution: {integrity: sha512-OX8D5eeX4XwcroVW45NMvoYaIuFI+GQpA2a8Gi+X/U/cDUIRsV37qQfF905F0htTRCREQIB4KqPeaveRJUl3Ow==} + engines: {node: '>=6.9.0'} + dev: true + + /@babel/helpers/7.16.5: + resolution: {integrity: sha512-TLgi6Lh71vvMZGEkFuIxzaPsyeYCHQ5jJOOX1f0xXn0uciFuE8cEk0wyBquMcCxBXZ5BJhE2aUB7pnWTD150Tw==} + engines: {node: '>=6.9.0'} + dependencies: + '@babel/template': 7.16.0 + '@babel/traverse': 7.16.5 + '@babel/types': 7.16.0 + transitivePeerDependencies: + - supports-color + dev: true + + /@babel/highlight/7.16.0: + resolution: {integrity: sha512-t8MH41kUQylBtu2+4IQA3atqevA2lRgqA2wyVB/YiWmsDSuylZZuXOUy9ric30hfzauEFfdsuk/eXTRrGrfd0g==} + engines: {node: '>=6.9.0'} + dependencies: + '@babel/helper-validator-identifier': 7.15.7 + chalk: 2.4.2 + js-tokens: 4.0.0 + dev: true + + /@babel/parser/7.16.6: + resolution: {integrity: sha512-Gr86ujcNuPDnNOY8mi383Hvi8IYrJVJYuf3XcuBM/Dgd+bINn/7tHqsj+tKkoreMbmGsFLsltI/JJd8fOFWGDQ==} + engines: {node: '>=6.0.0'} + hasBin: true + dev: true + + /@babel/plugin-syntax-async-generators/7.8.4_@babel+core@7.16.5: + resolution: {integrity: sha512-tycmZxkGfZaxhMRbXlPXuVFpdWlXpir2W4AMhSJgRKzk/eDlIXOhb2LHWoLpDF7TEHylV5zNhykX6KAgHJmTNw==} + peerDependencies: + '@babel/core': ^7.0.0-0 + dependencies: + '@babel/core': 7.16.5 + '@babel/helper-plugin-utils': 7.16.5 + dev: true + + /@babel/plugin-syntax-bigint/7.8.3_@babel+core@7.16.5: + resolution: {integrity: sha512-wnTnFlG+YxQm3vDxpGE57Pj0srRU4sHE/mDkt1qv2YJJSeUAec2ma4WLUnUPeKjyrfntVwe/N6dCXpU+zL3Npg==} + peerDependencies: + '@babel/core': ^7.0.0-0 + dependencies: + '@babel/core': 7.16.5 + '@babel/helper-plugin-utils': 7.16.5 + dev: true + + /@babel/plugin-syntax-class-properties/7.12.13_@babel+core@7.16.5: + resolution: {integrity: sha512-fm4idjKla0YahUNgFNLCB0qySdsoPiZP3iQE3rky0mBUtMZ23yDJ9SJdg6dXTSDnulOVqiF3Hgr9nbXvXTQZYA==} + peerDependencies: + '@babel/core': ^7.0.0-0 + dependencies: + '@babel/core': 7.16.5 + '@babel/helper-plugin-utils': 7.16.5 + dev: true + + /@babel/plugin-syntax-import-meta/7.10.4_@babel+core@7.16.5: + resolution: {integrity: sha512-Yqfm+XDx0+Prh3VSeEQCPU81yC+JWZ2pDPFSS4ZdpfZhp4MkFMaDC1UqseovEKwSUpnIL7+vK+Clp7bfh0iD7g==} + peerDependencies: + '@babel/core': ^7.0.0-0 + dependencies: + '@babel/core': 7.16.5 + '@babel/helper-plugin-utils': 7.16.5 + dev: true + + /@babel/plugin-syntax-json-strings/7.8.3_@babel+core@7.16.5: + resolution: {integrity: sha512-lY6kdGpWHvjoe2vk4WrAapEuBR69EMxZl+RoGRhrFGNYVK8mOPAW8VfbT/ZgrFbXlDNiiaxQnAtgVCZ6jv30EA==} + peerDependencies: + '@babel/core': ^7.0.0-0 + dependencies: + '@babel/core': 7.16.5 + '@babel/helper-plugin-utils': 7.16.5 + dev: true + + /@babel/plugin-syntax-logical-assignment-operators/7.10.4_@babel+core@7.16.5: + resolution: {integrity: sha512-d8waShlpFDinQ5MtvGU9xDAOzKH47+FFoney2baFIoMr952hKOLp1HR7VszoZvOsV/4+RRszNY7D17ba0te0ig==} + peerDependencies: + '@babel/core': ^7.0.0-0 + dependencies: + '@babel/core': 7.16.5 + '@babel/helper-plugin-utils': 7.16.5 + dev: true + + /@babel/plugin-syntax-nullish-coalescing-operator/7.8.3_@babel+core@7.16.5: + resolution: {integrity: sha512-aSff4zPII1u2QD7y+F8oDsz19ew4IGEJg9SVW+bqwpwtfFleiQDMdzA/R+UlWDzfnHFCxxleFT0PMIrR36XLNQ==} + peerDependencies: + '@babel/core': ^7.0.0-0 + dependencies: + '@babel/core': 7.16.5 + '@babel/helper-plugin-utils': 7.16.5 + dev: true + + /@babel/plugin-syntax-numeric-separator/7.10.4_@babel+core@7.16.5: + resolution: {integrity: sha512-9H6YdfkcK/uOnY/K7/aA2xpzaAgkQn37yzWUMRK7OaPOqOpGS1+n0H5hxT9AUw9EsSjPW8SVyMJwYRtWs3X3ug==} + peerDependencies: + '@babel/core': ^7.0.0-0 + dependencies: + '@babel/core': 7.16.5 + '@babel/helper-plugin-utils': 7.16.5 + dev: true + + /@babel/plugin-syntax-object-rest-spread/7.8.3_@babel+core@7.16.5: + resolution: {integrity: sha512-XoqMijGZb9y3y2XskN+P1wUGiVwWZ5JmoDRwx5+3GmEplNyVM2s2Dg8ILFQm8rWM48orGy5YpI5Bl8U1y7ydlA==} + peerDependencies: + '@babel/core': ^7.0.0-0 + dependencies: + '@babel/core': 7.16.5 + '@babel/helper-plugin-utils': 7.16.5 + dev: true + + /@babel/plugin-syntax-optional-catch-binding/7.8.3_@babel+core@7.16.5: + resolution: {integrity: sha512-6VPD0Pc1lpTqw0aKoeRTMiB+kWhAoT24PA+ksWSBrFtl5SIRVpZlwN3NNPQjehA2E/91FV3RjLWoVTglWcSV3Q==} + peerDependencies: + '@babel/core': ^7.0.0-0 + dependencies: + '@babel/core': 7.16.5 + '@babel/helper-plugin-utils': 7.16.5 + dev: true + + /@babel/plugin-syntax-optional-chaining/7.8.3_@babel+core@7.16.5: + resolution: {integrity: sha512-KoK9ErH1MBlCPxV0VANkXW2/dw4vlbGDrFgz8bmUsBGYkFRcbRwMh6cIJubdPrkxRwuGdtCk0v/wPTKbQgBjkg==} + peerDependencies: + '@babel/core': ^7.0.0-0 + dependencies: + '@babel/core': 7.16.5 + '@babel/helper-plugin-utils': 7.16.5 + dev: true + + /@babel/plugin-syntax-top-level-await/7.14.5_@babel+core@7.16.5: + resolution: {integrity: sha512-hx++upLv5U1rgYfwe1xBQUhRmU41NEvpUvrp8jkrSCdvGSnM5/qdRMtylJ6PG5OFkBaHkbTAKTnd3/YyESRHFw==} + engines: {node: '>=6.9.0'} + peerDependencies: + '@babel/core': ^7.0.0-0 + dependencies: + '@babel/core': 7.16.5 + '@babel/helper-plugin-utils': 7.16.5 + dev: true + + /@babel/plugin-syntax-typescript/7.16.5_@babel+core@7.16.5: + resolution: {integrity: sha512-/d4//lZ1Vqb4mZ5xTep3dDK888j7BGM/iKqBmndBaoYAFPlPKrGU608VVBz5JeyAb6YQDjRu1UKqj86UhwWVgw==} + engines: {node: '>=6.9.0'} + peerDependencies: + '@babel/core': ^7.0.0-0 + dependencies: + '@babel/core': 7.16.5 + '@babel/helper-plugin-utils': 7.16.5 + dev: true + + /@babel/template/7.16.0: + resolution: {integrity: sha512-MnZdpFD/ZdYhXwiunMqqgyZyucaYsbL0IrjoGjaVhGilz+x8YB++kRfygSOIj1yOtWKPlx7NBp+9I1RQSgsd5A==} + engines: {node: '>=6.9.0'} + dependencies: + '@babel/code-frame': 7.16.0 + '@babel/parser': 7.16.6 + '@babel/types': 7.16.0 + dev: true + + /@babel/traverse/7.16.5: + resolution: {integrity: sha512-FOCODAzqUMROikDYLYxl4nmwiLlu85rNqBML/A5hKRVXG2LV8d0iMqgPzdYTcIpjZEBB7D6UDU9vxRZiriASdQ==} + engines: {node: '>=6.9.0'} + dependencies: + '@babel/code-frame': 7.16.0 + '@babel/generator': 7.16.5 + '@babel/helper-environment-visitor': 7.16.5 + '@babel/helper-function-name': 7.16.0 + '@babel/helper-hoist-variables': 7.16.0 + '@babel/helper-split-export-declaration': 7.16.0 + '@babel/parser': 7.16.6 + '@babel/types': 7.16.0 + debug: 4.3.3 + globals: 11.12.0 + transitivePeerDependencies: + - supports-color + dev: true + + /@babel/types/7.16.0: + resolution: {integrity: sha512-PJgg/k3SdLsGb3hhisFvtLOw5ts113klrpLuIPtCJIU+BB24fqq6lf8RWqKJEjzqXR9AEH1rIb5XTqwBHB+kQg==} + engines: {node: '>=6.9.0'} + dependencies: + '@babel/helper-validator-identifier': 7.15.7 + to-fast-properties: 2.0.0 + dev: true + + /@bcoe/v8-coverage/0.2.3: + resolution: {integrity: sha512-0hYQ8SB4Db5zvZB4axdMHGwEaQjkZzFjQiN9LVYvIFB2nSUHW9tYpxWriPrWDASIxiaXax83REcLxuSdnGPZtw==} + dev: true + + /@commitlint/cli/15.0.0: + resolution: {integrity: sha512-Y5xmDCweytqzo4N4lOI2YRiuX35xTjcs8n5hUceBH8eyK0YbwtgWX50BJOH2XbkwEmII9blNhlBog6AdQsqicg==} + engines: {node: '>=v12'} + hasBin: true + dependencies: + '@commitlint/format': 15.0.0 + '@commitlint/lint': 15.0.0 + '@commitlint/load': 15.0.0 + '@commitlint/read': 15.0.0 + '@commitlint/types': 15.0.0 + lodash: 4.17.21 + resolve-from: 5.0.0 + resolve-global: 1.0.0 + yargs: 17.3.0 + dev: true + + /@commitlint/config-conventional/15.0.0: + resolution: {integrity: sha512-eZBRL8Lk3hMNHp1wUMYj0qrZQEsST1ai7KHR8J1IDD9aHgT7L2giciibuQ+Og7vxVhR5WtYDvh9xirXFVPaSkQ==} + engines: {node: '>=v12'} + dependencies: + conventional-changelog-conventionalcommits: 4.6.1 + dev: true + + /@commitlint/ensure/15.0.0: + resolution: {integrity: sha512-7DV4iNIald3vycwaWBNGk5FbonaNzOlU8nBe5m5AgU2dIeNKuXwLm+zzJzG27j0Ho56rgz//3F6RIvmsoxY9ZA==} + engines: {node: '>=v12'} + dependencies: + '@commitlint/types': 15.0.0 + lodash: 4.17.21 + dev: true + + /@commitlint/execute-rule/15.0.0: + resolution: {integrity: sha512-pyE4ApxjbWhb1TXz5vRiGwI2ssdMMgZbaaheZq1/7WC0xRnqnIhE1yUC1D2q20qPtvkZPstTYvMiRVtF+DvjUg==} + engines: {node: '>=v12'} + dev: true + + /@commitlint/format/15.0.0: + resolution: {integrity: sha512-bPhAfqwRhPk92WiuY0ktEJNpRRHSCd+Eg1MdhGyL9Bl3U25E5zvuInA+dNctnzZiOBSH/37ZaD0eOKCpQE6acg==} + engines: {node: '>=v12'} + dependencies: + '@commitlint/types': 15.0.0 + chalk: 4.1.2 + dev: true + + /@commitlint/is-ignored/15.0.0: + resolution: {integrity: sha512-edtnkf2QZ/7e/YCJDgn1WDw9wfF1WfOitW5YEoSOb4SxjJEb/oE87kxNPZ2j8mnDMuunspcMfGHeg6fRlwaEWg==} + engines: {node: '>=v12'} + dependencies: + '@commitlint/types': 15.0.0 + semver: 7.3.5 + dev: true + + /@commitlint/lint/15.0.0: + resolution: {integrity: sha512-hUi2+Im/2dJ5FBvWnodypTkg+5haCgsDzB0fyMApWLUA1IucYUAqRCQCW5em1Mhk9Crw1pd5YzFNikhIclkqCw==} + engines: {node: '>=v12'} + dependencies: + '@commitlint/is-ignored': 15.0.0 + '@commitlint/parse': 15.0.0 + '@commitlint/rules': 15.0.0 + '@commitlint/types': 15.0.0 + dev: true + + /@commitlint/load/15.0.0: + resolution: {integrity: sha512-Ak1YPeOhvxmY3ioe0o6m1yLGvUAYb4BdfGgShU8jiTCmU3Mnmms0Xh/kfQz8AybhezCC3AmVTyBLaBZxOHR8kg==} + engines: {node: '>=v12'} + dependencies: + '@commitlint/execute-rule': 15.0.0 + '@commitlint/resolve-extends': 15.0.0 + '@commitlint/types': 15.0.0 + '@endemolshinegroup/cosmiconfig-typescript-loader': 3.0.2_71a2f61964e37a4d68dab6dadd2a99a0 + chalk: 4.1.2 + cosmiconfig: 7.0.1 + lodash: 4.17.21 + resolve-from: 5.0.0 + typescript: 4.5.4 + dev: true + + /@commitlint/message/15.0.0: + resolution: {integrity: sha512-L8euabzboKavPuDJsdIYAY2wx97LbiGEYsckMo6NmV8pOun50c8hQx6ouXFSAx4pp+mX9yUGmMiVqfrk2LKDJQ==} + engines: {node: '>=v12'} + dev: true + + /@commitlint/parse/15.0.0: + resolution: {integrity: sha512-7fweM67tZfBNS7zw1KTuuT5K2u9nGytUJqFqT/1Ln3Na9cBCsoAqR47mfsNOTlRCgGwakm4xiQ7BpS2gN0OGuw==} + engines: {node: '>=v12'} + dependencies: + '@commitlint/types': 15.0.0 + conventional-changelog-angular: 5.0.13 + conventional-commits-parser: 3.2.3 + dev: true + + /@commitlint/read/15.0.0: + resolution: {integrity: sha512-5yI1o2HKZFVe7RTjL7IhuhHMKar/MDNY34vEHqqz9gMI7BK/rdP8uVb4Di1efl2V0UPnwID0nPKWESjQ8Ti0gw==} + engines: {node: '>=v12'} + dependencies: + '@commitlint/top-level': 15.0.0 + '@commitlint/types': 15.0.0 + fs-extra: 10.0.0 + git-raw-commits: 2.0.10 + dev: true + + /@commitlint/resolve-extends/15.0.0: + resolution: {integrity: sha512-7apfRJjgJsKja7lHsPfEFixKjA/fk/UeD3owkOw1174yYu4u8xBDLSeU3IinGPdMuF9m245eX8wo7vLUy+EBSg==} + engines: {node: '>=v12'} + dependencies: + import-fresh: 3.3.0 + lodash: 4.17.21 + resolve-from: 5.0.0 + resolve-global: 1.0.0 + dev: true + + /@commitlint/rules/15.0.0: + resolution: {integrity: sha512-SqXfp6QUlwBS+0IZm4FEA/NmmAwcFQIkG3B05BtemOVWXQdZ8j1vV6hDwvA9oMPCmUSrrGpHOtZK7HaHhng2yA==} + engines: {node: '>=v12'} + dependencies: + '@commitlint/ensure': 15.0.0 + '@commitlint/message': 15.0.0 + '@commitlint/to-lines': 15.0.0 + '@commitlint/types': 15.0.0 + execa: 5.1.1 + dev: true + + /@commitlint/to-lines/15.0.0: + resolution: {integrity: sha512-mY3MNA9ujPqVpiJjTYG9MDsYCobue5PJFO0MfcIzS1mCVvngH8ZFTPAh1fT5t+t1h876boS88+9WgqjRvbYItw==} + engines: {node: '>=v12'} + dev: true + + /@commitlint/top-level/15.0.0: + resolution: {integrity: sha512-7Gz3t7xcuuUw1d1Nou6YLaztzp2Em+qZ6YdCzrqYc+aquca3Vt0O696nuiBDU/oE+tls4Hx2CNpAbWhTgEwB5A==} + engines: {node: '>=v12'} + dependencies: + find-up: 5.0.0 + dev: true + + /@commitlint/types/15.0.0: + resolution: {integrity: sha512-OMSLX+QJnyNoTwws54ULv9sOvuw9GdVezln76oyUd4YbMMJyaav62aSXDuCdWyL2sm9hTkSzyEi52PNaIj/vqw==} + engines: {node: '>=v12'} + dependencies: + chalk: 4.1.2 + dev: true + + /@endemolshinegroup/cosmiconfig-typescript-loader/3.0.2_71a2f61964e37a4d68dab6dadd2a99a0: + resolution: {integrity: sha512-QRVtqJuS1mcT56oHpVegkKBlgtWjXw/gHNWO3eL9oyB5Sc7HBoc2OLG/nYpVfT/Jejvo3NUrD0Udk7XgoyDKkA==} + engines: {node: '>=10.0.0'} + peerDependencies: + cosmiconfig: '>=6' + dependencies: + cosmiconfig: 7.0.1 + lodash.get: 4.4.2 + make-error: 1.3.6 + ts-node: 9.1.1_typescript@4.5.4 + tslib: 2.3.1 + transitivePeerDependencies: + - typescript + dev: true + + /@eslint/eslintrc/1.0.5: + resolution: {integrity: sha512-BLxsnmK3KyPunz5wmCCpqy0YelEoxxGmH73Is+Z74oOTMtExcjkr3dDR6quwrjh1YspA8DH9gnX1o069KiS9AQ==} + engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0} + dependencies: + ajv: 6.12.6 + debug: 4.3.3 + espree: 9.2.0 + globals: 13.12.0 + ignore: 4.0.6 + import-fresh: 3.3.0 + js-yaml: 4.1.0 + minimatch: 3.0.4 + strip-json-comments: 3.1.1 + transitivePeerDependencies: + - supports-color + dev: true + + /@humanwhocodes/config-array/0.9.2: + resolution: {integrity: sha512-UXOuFCGcwciWckOpmfKDq/GyhlTf9pN/BzG//x8p8zTOFEcGuA68ANXheFS0AGvy3qgZqLBUkMs7hqzqCKOVwA==} + engines: {node: '>=10.10.0'} + dependencies: + '@humanwhocodes/object-schema': 1.2.1 + debug: 4.3.3 + minimatch: 3.0.4 + transitivePeerDependencies: + - supports-color + dev: true + + /@humanwhocodes/object-schema/1.2.1: + resolution: {integrity: sha512-ZnQMnLV4e7hDlUvw8H+U8ASL02SS2Gn6+9Ac3wGGLIe7+je2AeAOxPY+izIPJDfFDb7eDjev0Us8MO1iFRN8hA==} + dev: true + + /@istanbuljs/load-nyc-config/1.1.0: + resolution: {integrity: sha512-VjeHSlIzpv/NyD3N0YuHfXOPDIixcA1q2ZV98wsMqcYlPmv2n3Yb2lYP9XMElnaFVXg5A7YLTeLu6V84uQDjmQ==} + engines: {node: '>=8'} + dependencies: + camelcase: 5.3.1 + find-up: 4.1.0 + get-package-type: 0.1.0 + js-yaml: 3.14.1 + resolve-from: 5.0.0 + dev: true + + /@istanbuljs/schema/0.1.3: + resolution: {integrity: sha512-ZXRY4jNvVgSVQ8DL3LTcakaAtXwTVUxE81hslsyD2AtoXW/wVob10HkOJ1X/pAlcI7D+2YoZKg5do8G/w6RYgA==} + engines: {node: '>=8'} + dev: true + + /@jest/console/27.4.2: + resolution: {integrity: sha512-xknHThRsPB/To1FUbi6pCe43y58qFC03zfb6R7fDb/FfC7k2R3i1l+izRBJf8DI46KhYGRaF14Eo9A3qbBoixg==} + engines: {node: ^10.13.0 || ^12.13.0 || ^14.15.0 || >=15.0.0} + dependencies: + '@jest/types': 27.4.2 + '@types/node': 17.0.0 + chalk: 4.1.2 + jest-message-util: 27.4.2 + jest-util: 27.4.2 + slash: 3.0.0 + dev: true + + /@jest/core/27.4.5: + resolution: {integrity: sha512-3tm/Pevmi8bDsgvo73nX8p/WPng6KWlCyScW10FPEoN1HU4pwI83tJ3TsFvi1FfzsjwUlMNEPowgb/rPau/LTQ==} + engines: {node: ^10.13.0 || ^12.13.0 || ^14.15.0 || >=15.0.0} + peerDependencies: + node-notifier: ^8.0.1 || ^9.0.0 || ^10.0.0 + peerDependenciesMeta: + node-notifier: + optional: true + dependencies: + '@jest/console': 27.4.2 + '@jest/reporters': 27.4.5 + '@jest/test-result': 27.4.2 + '@jest/transform': 27.4.5 + '@jest/types': 27.4.2 + '@types/node': 17.0.0 + ansi-escapes: 4.3.2 + chalk: 4.1.2 + emittery: 0.8.1 + exit: 0.1.2 + graceful-fs: 4.2.8 + jest-changed-files: 27.4.2 + jest-config: 27.4.5 + jest-haste-map: 27.4.5 + jest-message-util: 27.4.2 + jest-regex-util: 27.4.0 + jest-resolve: 27.4.5 + jest-resolve-dependencies: 27.4.5 + jest-runner: 27.4.5 + jest-runtime: 27.4.5 + jest-snapshot: 27.4.5 + jest-util: 27.4.2 + jest-validate: 27.4.2 + jest-watcher: 27.4.2 + micromatch: 4.0.4 + rimraf: 3.0.2 + slash: 3.0.0 + strip-ansi: 6.0.1 + transitivePeerDependencies: + - bufferutil + - canvas + - supports-color + - ts-node + - utf-8-validate + dev: true + + /@jest/environment/27.4.4: + resolution: {integrity: sha512-q+niMx7cJgt/t/b6dzLOh4W8Ef/8VyKG7hxASK39jakijJzbFBGpptx3RXz13FFV7OishQ9lTbv+dQ5K3EhfDQ==} + engines: {node: ^10.13.0 || ^12.13.0 || ^14.15.0 || >=15.0.0} + dependencies: + '@jest/fake-timers': 27.4.2 + '@jest/types': 27.4.2 + '@types/node': 17.0.0 + jest-mock: 27.4.2 + dev: true + + /@jest/fake-timers/27.4.2: + resolution: {integrity: sha512-f/Xpzn5YQk5adtqBgvw1V6bF8Nx3hY0OIRRpCvWcfPl0EAjdqWPdhH3t/3XpiWZqtjIEHDyMKP9ajpva1l4Zmg==} + engines: {node: ^10.13.0 || ^12.13.0 || ^14.15.0 || >=15.0.0} + dependencies: + '@jest/types': 27.4.2 + '@sinonjs/fake-timers': 8.1.0 + '@types/node': 17.0.0 + jest-message-util: 27.4.2 + jest-mock: 27.4.2 + jest-util: 27.4.2 + dev: true + + /@jest/globals/27.4.4: + resolution: {integrity: sha512-bqpqQhW30BOreXM8bA8t8JbOQzsq/WnPTnBl+It3UxAD9J8yxEAaBEylHx1dtBapAr/UBk8GidXbzmqnee8tYQ==} + engines: {node: ^10.13.0 || ^12.13.0 || ^14.15.0 || >=15.0.0} + dependencies: + '@jest/environment': 27.4.4 + '@jest/types': 27.4.2 + expect: 27.4.2 + dev: true + + /@jest/reporters/27.4.5: + resolution: {integrity: sha512-3orsG4vi8zXuBqEoy2LbnC1kuvkg1KQUgqNxmxpQgIOQEPeV0onvZu+qDQnEoX8qTQErtqn/xzcnbpeTuOLSiA==} + engines: {node: ^10.13.0 || ^12.13.0 || ^14.15.0 || >=15.0.0} + peerDependencies: + node-notifier: ^8.0.1 || ^9.0.0 || ^10.0.0 + peerDependenciesMeta: + node-notifier: + optional: true + dependencies: + '@bcoe/v8-coverage': 0.2.3 + '@jest/console': 27.4.2 + '@jest/test-result': 27.4.2 + '@jest/transform': 27.4.5 + '@jest/types': 27.4.2 + '@types/node': 17.0.0 + chalk: 4.1.2 + collect-v8-coverage: 1.0.1 + exit: 0.1.2 + glob: 7.2.0 + graceful-fs: 4.2.8 + istanbul-lib-coverage: 3.2.0 + istanbul-lib-instrument: 4.0.3 + istanbul-lib-report: 3.0.0 + istanbul-lib-source-maps: 4.0.1 + istanbul-reports: 3.1.1 + jest-haste-map: 27.4.5 + jest-resolve: 27.4.5 + jest-util: 27.4.2 + jest-worker: 27.4.5 + slash: 3.0.0 + source-map: 0.6.1 + string-length: 4.0.2 + terminal-link: 2.1.1 + v8-to-istanbul: 8.1.0 + transitivePeerDependencies: + - supports-color + dev: true + + /@jest/source-map/27.4.0: + resolution: {integrity: sha512-Ntjx9jzP26Bvhbm93z/AKcPRj/9wrkI88/gK60glXDx1q+IeI0rf7Lw2c89Ch6ofonB0On/iRDreQuQ6te9pgQ==} + engines: {node: ^10.13.0 || ^12.13.0 || ^14.15.0 || >=15.0.0} + dependencies: + callsites: 3.1.0 + graceful-fs: 4.2.8 + source-map: 0.6.1 + dev: true + + /@jest/test-result/27.4.2: + resolution: {integrity: sha512-kr+bCrra9jfTgxHXHa2UwoQjxvQk3Am6QbpAiJ5x/50LW8llOYrxILkqY0lZRW/hu8FXesnudbql263+EW9iNA==} + engines: {node: ^10.13.0 || ^12.13.0 || ^14.15.0 || >=15.0.0} + dependencies: + '@jest/console': 27.4.2 + '@jest/types': 27.4.2 + '@types/istanbul-lib-coverage': 2.0.3 + collect-v8-coverage: 1.0.1 + dev: true + + /@jest/test-sequencer/27.4.5: + resolution: {integrity: sha512-n5woIn/1v+FT+9hniymHPARA9upYUmfi5Pw9ewVwXCDlK4F5/Gkees9v8vdjGdAIJ2MPHLHodiajLpZZanWzEQ==} + engines: {node: ^10.13.0 || ^12.13.0 || ^14.15.0 || >=15.0.0} + dependencies: + '@jest/test-result': 27.4.2 + graceful-fs: 4.2.8 + jest-haste-map: 27.4.5 + jest-runtime: 27.4.5 + transitivePeerDependencies: + - supports-color + dev: true + + /@jest/transform/27.4.5: + resolution: {integrity: sha512-PuMet2UlZtlGzwc6L+aZmR3I7CEBpqadO03pU40l2RNY2fFJ191b9/ITB44LNOhVtsyykx0OZvj0PCyuLm7Eew==} + engines: {node: ^10.13.0 || ^12.13.0 || ^14.15.0 || >=15.0.0} + dependencies: + '@babel/core': 7.16.5 + '@jest/types': 27.4.2 + babel-plugin-istanbul: 6.1.1 + chalk: 4.1.2 + convert-source-map: 1.8.0 + fast-json-stable-stringify: 2.1.0 + graceful-fs: 4.2.8 + jest-haste-map: 27.4.5 + jest-regex-util: 27.4.0 + jest-util: 27.4.2 + micromatch: 4.0.4 + pirates: 4.0.4 + slash: 3.0.0 + source-map: 0.6.1 + write-file-atomic: 3.0.3 + transitivePeerDependencies: + - supports-color + dev: true + + /@jest/types/27.4.2: + resolution: {integrity: sha512-j35yw0PMTPpZsUoOBiuHzr1zTYoad1cVIE0ajEjcrJONxxrko/IRGKkXx3os0Nsi4Hu3+5VmDbVfq5WhG/pWAg==} + engines: {node: ^10.13.0 || ^12.13.0 || ^14.15.0 || >=15.0.0} + dependencies: + '@types/istanbul-lib-coverage': 2.0.3 + '@types/istanbul-reports': 3.0.1 + '@types/node': 17.0.0 + '@types/yargs': 16.0.4 + chalk: 4.1.2 + dev: true + + /@nodelib/fs.scandir/2.1.5: + resolution: {integrity: sha512-vq24Bq3ym5HEQm2NKCr3yXDwjc7vTsEThRDnkp2DK9p1uqLR+DHurm/NOTo0KG7HYHU7eppKZj3MyqYuMBf62g==} + engines: {node: '>= 8'} + dependencies: + '@nodelib/fs.stat': 2.0.5 + run-parallel: 1.2.0 + dev: true + + /@nodelib/fs.stat/2.0.5: + resolution: {integrity: sha512-RkhPPp2zrqDAQA/2jNhnztcPAlv64XdhIp7a7454A5ovI7Bukxgt7MX7udwAu3zg1DcpPU0rz3VV1SeaqvY4+A==} + engines: {node: '>= 8'} + dev: true + + /@nodelib/fs.walk/1.2.8: + resolution: {integrity: sha512-oGB+UxlgWcgQkgwo8GcEGwemoTFt3FIO9ababBmaGwXIoBKZ+GTy0pP185beGg7Llih/NSHSV2XAs1lnznocSg==} + engines: {node: '>= 8'} + dependencies: + '@nodelib/fs.scandir': 2.1.5 + fastq: 1.13.0 + dev: true + + /@sinonjs/commons/1.8.3: + resolution: {integrity: sha512-xkNcLAn/wZaX14RPlwizcKicDk9G3F8m2nU3L7Ukm5zBgTwiT0wsoFAHx9Jq56fJA1z/7uKGtCRu16sOUCLIHQ==} + dependencies: + type-detect: 4.0.8 + dev: true + + /@sinonjs/fake-timers/8.1.0: + resolution: {integrity: sha512-OAPJUAtgeINhh/TAlUID4QTs53Njm7xzddaVlEs/SXwgtiD1tW22zAB/W1wdqfrpmikgaWQ9Fw6Ws+hsiRm5Vg==} + dependencies: + '@sinonjs/commons': 1.8.3 + dev: true + + /@tootallnate/once/1.1.2: + resolution: {integrity: sha512-RbzJvlNzmRq5c3O09UipeuXno4tA1FE6ikOjxZK0tuxVv3412l64l5t1W5pj4+rJq9vpkm/kwiR07aZXnsKPxw==} + engines: {node: '>= 6'} + dev: true + + /@types/babel__core/7.1.17: + resolution: {integrity: sha512-6zzkezS9QEIL8yCBvXWxPTJPNuMeECJVxSOhxNY/jfq9LxOTHivaYTqr37n9LknWWRTIkzqH2UilS5QFvfa90A==} + dependencies: + '@babel/parser': 7.16.6 + '@babel/types': 7.16.0 + '@types/babel__generator': 7.6.3 + '@types/babel__template': 7.4.1 + '@types/babel__traverse': 7.14.2 + dev: true + + /@types/babel__generator/7.6.3: + resolution: {integrity: sha512-/GWCmzJWqV7diQW54smJZzWbSFf4QYtF71WCKhcx6Ru/tFyQIY2eiiITcCAeuPbNSvT9YCGkVMqqvSk2Z0mXiA==} + dependencies: + '@babel/types': 7.16.0 + dev: true + + /@types/babel__template/7.4.1: + resolution: {integrity: sha512-azBFKemX6kMg5Io+/rdGT0dkGreboUVR0Cdm3fz9QJWpaQGJRQXl7C+6hOTCZcMll7KFyEQpgbYI2lHdsS4U7g==} + dependencies: + '@babel/parser': 7.16.6 + '@babel/types': 7.16.0 + dev: true + + /@types/babel__traverse/7.14.2: + resolution: {integrity: sha512-K2waXdXBi2302XUdcHcR1jCeU0LL4TD9HRs/gk0N2Xvrht+G/BfJa4QObBQZfhMdxiCpV3COl5Nfq4uKTeTnJA==} + dependencies: + '@babel/types': 7.16.0 + dev: true + + /@types/body-parser/1.19.2: + resolution: {integrity: sha512-ALYone6pm6QmwZoAgeyNksccT9Q4AWZQ6PvfwR37GT6r6FWUPguq6sUmNGSMV2Wr761oQoBxwGGa6DR5o1DC9g==} + dependencies: + '@types/connect': 3.4.35 + '@types/node': 17.0.0 + dev: true + + /@types/connect/3.4.35: + resolution: {integrity: sha512-cdeYyv4KWoEgpBISTxWvqYsVy444DOqehiF3fM3ne10AmJ62RSyNkUnxMJXHQWRQQX2eR94m5y1IZyDwBjV9FQ==} + dependencies: + '@types/node': 17.0.0 + dev: true + + /@types/express-serve-static-core/4.17.26: + resolution: {integrity: sha512-zeu3tpouA043RHxW0gzRxwCHchMgftE8GArRsvYT0ByDMbn19olQHx5jLue0LxWY6iYtXb7rXmuVtSkhy9YZvQ==} + dependencies: + '@types/node': 17.0.0 + '@types/qs': 6.9.7 + '@types/range-parser': 1.2.4 + dev: true + + /@types/express/4.17.13: + resolution: {integrity: sha512-6bSZTPaTIACxn48l50SR+axgrqm6qXFIxrdAKaG6PaJk3+zuUr35hBlgT7vOmJcum+OEaIBLtHV/qloEAFITeA==} + dependencies: + '@types/body-parser': 1.19.2 + '@types/express-serve-static-core': 4.17.26 + '@types/qs': 6.9.7 + '@types/serve-static': 1.13.10 + dev: true + + /@types/graceful-fs/4.1.5: + resolution: {integrity: sha512-anKkLmZZ+xm4p8JWBf4hElkM4XR+EZeA2M9BAkkTldmcyDY4mbdIJnRghDJH3Ov5ooY7/UAoENtmdMSkaAd7Cw==} + dependencies: + '@types/node': 17.0.0 + dev: true + + /@types/istanbul-lib-coverage/2.0.3: + resolution: {integrity: sha512-sz7iLqvVUg1gIedBOvlkxPlc8/uVzyS5OwGz1cKjXzkl3FpL3al0crU8YGU1WoHkxn0Wxbw5tyi6hvzJKNzFsw==} + dev: true + + /@types/istanbul-lib-report/3.0.0: + resolution: {integrity: sha512-plGgXAPfVKFoYfa9NpYDAkseG+g6Jr294RqeqcqDixSbU34MZVJRi/P+7Y8GDpzkEwLaGZZOpKIEmeVZNtKsrg==} + dependencies: + '@types/istanbul-lib-coverage': 2.0.3 + dev: true + + /@types/istanbul-reports/3.0.1: + resolution: {integrity: sha512-c3mAZEuK0lvBp8tmuL74XRKn1+y2dcwOUpH7x4WrF6gk1GIgiluDRgMYQtw2OFcBvAJWlt6ASU3tSqxp0Uu0Aw==} + dependencies: + '@types/istanbul-lib-report': 3.0.0 + dev: true + + /@types/jest/27.0.3: + resolution: {integrity: sha512-cmmwv9t7gBYt7hNKH5Spu7Kuu/DotGa+Ff+JGRKZ4db5eh8PnKS4LuebJ3YLUoyOyIHraTGyULn23YtEAm0VSg==} + dependencies: + jest-diff: 27.4.2 + pretty-format: 27.4.2 + dev: true + + /@types/json-schema/7.0.9: + resolution: {integrity: sha512-qcUXuemtEu+E5wZSJHNxUXeCZhAfXKQ41D+duX+VYPde7xyEVZci+/oXKJL13tnRs9lR2pr4fod59GT6/X1/yQ==} + dev: true + + /@types/mime/1.3.2: + resolution: {integrity: sha512-YATxVxgRqNH6nHEIsvg6k2Boc1JHI9ZbH5iWFFv/MTkchz3b1ieGDa5T0a9RznNdI0KhVbdbWSN+KWWrQZRxTw==} + dev: true + + /@types/minimist/1.2.2: + resolution: {integrity: sha512-jhuKLIRrhvCPLqwPcx6INqmKeiA5EWrsCOPhrlFSrbrmU4ZMPjj5Ul/oLCMDO98XRUIwVm78xICz4EPCektzeQ==} + dev: true + + /@types/multer/1.4.7: + resolution: {integrity: sha512-/SNsDidUFCvqqcWDwxv2feww/yqhNeTRL5CVoL3jU4Goc4kKEL10T7Eye65ZqPNi4HRx8sAEX59pV1aEH7drNA==} + dependencies: + '@types/express': 4.17.13 + dev: true + + /@types/node/17.0.0: + resolution: {integrity: sha512-eMhwJXc931Ihh4tkU+Y7GiLzT/y/DBNpNtr4yU9O2w3SYBsr9NaOPhQlLKRmoWtI54uNwuo0IOUFQjVOTZYRvw==} + dev: true + + /@types/normalize-package-data/2.4.1: + resolution: {integrity: sha512-Gj7cI7z+98M282Tqmp2K5EIsoouUEzbBJhQQzDE3jSIRk6r9gsz0oUokqIUR4u1R3dMHo0pDHM7sNOHyhulypw==} + dev: true + + /@types/parse-json/4.0.0: + resolution: {integrity: sha512-//oorEZjL6sbPcKUaCdIGlIUeH26mgzimjBB77G6XRgnDl/L5wOnpyBGRe/Mmf5CVW3PwEBE1NjiMZ/ssFh4wA==} + dev: true + + /@types/prettier/2.4.2: + resolution: {integrity: sha512-ekoj4qOQYp7CvjX8ZDBgN86w3MqQhLE1hczEJbEIjgFEumDy+na/4AJAbLXfgEWFNB2pKadM5rPFtuSGMWK7xA==} + dev: true + + /@types/qs/6.9.7: + resolution: {integrity: sha512-FGa1F62FT09qcrueBA6qYTrJPVDzah9a+493+o2PCXsesWHIn27G98TsSMs3WPNbZIEj4+VJf6saSFpvD+3Zsw==} + dev: true + + /@types/range-parser/1.2.4: + resolution: {integrity: sha512-EEhsLsD6UsDM1yFhAvy0Cjr6VwmpMWqFBCb9w07wVugF7w9nfajxLuVmngTIpgS6svCnm6Vaw+MZhoDCKnOfsw==} + dev: true + + /@types/serve-static/1.13.10: + resolution: {integrity: sha512-nCkHGI4w7ZgAdNkrEu0bv+4xNV/XDqW+DydknebMOQwkpDGx8G+HTlj7R7ABI8i8nKxVw0wtKPi1D+lPOkh4YQ==} + dependencies: + '@types/mime': 1.3.2 + '@types/node': 17.0.0 + dev: true + + /@types/stack-utils/2.0.1: + resolution: {integrity: sha512-Hl219/BT5fLAaz6NDkSuhzasy49dwQS/DSdu4MdggFB8zcXv7vflBI3xp7FEmkmdDkBUI2bPUNeMttp2knYdxw==} + dev: true + + /@types/validator/13.7.0: + resolution: {integrity: sha512-+jBxVvXVuggZOrm04NR8z+5+bgoW4VZyLzUO+hmPPW1mVFL/HaitLAkizfv4yg9TbG8lkfHWVMQ11yDqrVVCzA==} + dev: true + + /@types/yargs-parser/20.2.1: + resolution: {integrity: sha512-7tFImggNeNBVMsn0vLrpn1H1uPrUBdnARPTpZoitY37ZrdJREzf7I16tMrlK3hen349gr1NYh8CmZQa7CTG6Aw==} + dev: true + + /@types/yargs/16.0.4: + resolution: {integrity: sha512-T8Yc9wt/5LbJyCaLiHPReJa0kApcIgJ7Bn735GjItUfh08Z1pJvu8QZqb9s+mMvKV6WUQRV7K2R46YbjMXTTJw==} + dependencies: + '@types/yargs-parser': 20.2.1 + dev: true + + /@typescript-eslint/eslint-plugin/5.7.0_a6f6159640504abdd3de077f8bcadb33: + resolution: {integrity: sha512-8RTGBpNn5a9M628wBPrCbJ+v3YTEOE2qeZb7TDkGKTDXSj36KGRg92SpFFaR/0S3rSXQxM0Og/kV9EyadsYSBg==} + engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0} + peerDependencies: + '@typescript-eslint/parser': ^5.0.0 + eslint: ^6.0.0 || ^7.0.0 || ^8.0.0 + typescript: '*' + peerDependenciesMeta: + typescript: + optional: true + dependencies: + '@typescript-eslint/experimental-utils': 5.7.0_eslint@8.5.0+typescript@4.5.4 + '@typescript-eslint/parser': 5.7.0_eslint@8.5.0+typescript@4.5.4 + '@typescript-eslint/scope-manager': 5.7.0 + debug: 4.3.3 + eslint: 8.5.0 + functional-red-black-tree: 1.0.1 + ignore: 5.2.0 + regexpp: 3.2.0 + semver: 7.3.5 + tsutils: 3.21.0_typescript@4.5.4 + typescript: 4.5.4 + transitivePeerDependencies: + - supports-color + dev: true + + /@typescript-eslint/experimental-utils/5.7.0_eslint@8.5.0+typescript@4.5.4: + resolution: {integrity: sha512-u57eZ5FbEpzN5kSjmVrSesovWslH2ZyNPnaXQMXWgH57d5+EVHEt76W75vVuI9qKZ5BMDKNfRN+pxcPEjQjb2A==} + engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0} + peerDependencies: + eslint: '*' + dependencies: + '@types/json-schema': 7.0.9 + '@typescript-eslint/scope-manager': 5.7.0 + '@typescript-eslint/types': 5.7.0 + '@typescript-eslint/typescript-estree': 5.7.0_typescript@4.5.4 + eslint: 8.5.0 + eslint-scope: 5.1.1 + eslint-utils: 3.0.0_eslint@8.5.0 + transitivePeerDependencies: + - supports-color + - typescript + dev: true + + /@typescript-eslint/parser/5.7.0_eslint@8.5.0+typescript@4.5.4: + resolution: {integrity: sha512-m/gWCCcS4jXw6vkrPQ1BjZ1vomP01PArgzvauBqzsoZ3urLbsRChexB8/YV8z9HwE3qlJM35FxfKZ1nfP/4x8g==} + engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0} + peerDependencies: + eslint: ^6.0.0 || ^7.0.0 || ^8.0.0 + typescript: '*' + peerDependenciesMeta: + typescript: + optional: true + dependencies: + '@typescript-eslint/scope-manager': 5.7.0 + '@typescript-eslint/types': 5.7.0 + '@typescript-eslint/typescript-estree': 5.7.0_typescript@4.5.4 + debug: 4.3.3 + eslint: 8.5.0 + typescript: 4.5.4 + transitivePeerDependencies: + - supports-color + dev: true + + /@typescript-eslint/scope-manager/5.7.0: + resolution: {integrity: sha512-7mxR520DGq5F7sSSgM0HSSMJ+TFUymOeFRMfUfGFAVBv8BR+Jv1vHgAouYUvWRZeszVBJlLcc9fDdktxb5kmxA==} + engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0} + dependencies: + '@typescript-eslint/types': 5.7.0 + '@typescript-eslint/visitor-keys': 5.7.0 + dev: true + + /@typescript-eslint/types/5.7.0: + resolution: {integrity: sha512-5AeYIF5p2kAneIpnLFve8g50VyAjq7udM7ApZZ9JYjdPjkz0LvODfuSHIDUVnIuUoxafoWzpFyU7Sqbxgi79mA==} + engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0} + dev: true + + /@typescript-eslint/typescript-estree/5.7.0_typescript@4.5.4: + resolution: {integrity: sha512-aO1Ql+izMrTnPj5aFFlEJkpD4jRqC4Gwhygu2oHK2wfVQpmOPbyDSveJ+r/NQo+PWV43M6uEAeLVbTi09dFLhg==} + engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0} + peerDependencies: + typescript: '*' + peerDependenciesMeta: + typescript: + optional: true + dependencies: + '@typescript-eslint/types': 5.7.0 + '@typescript-eslint/visitor-keys': 5.7.0 + debug: 4.3.3 + globby: 11.0.4 + is-glob: 4.0.3 + semver: 7.3.5 + tsutils: 3.21.0_typescript@4.5.4 + typescript: 4.5.4 + transitivePeerDependencies: + - supports-color + dev: true + + /@typescript-eslint/visitor-keys/5.7.0: + resolution: {integrity: sha512-hdohahZ4lTFcglZSJ3DGdzxQHBSxsLVqHzkiOmKi7xVAWC4y2c1bIMKmPJSrA4aOEoRUPOKQ87Y/taC7yVHpFg==} + engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0} + dependencies: + '@typescript-eslint/types': 5.7.0 + eslint-visitor-keys: 3.1.0 + dev: true + + /JSONStream/1.3.5: + resolution: {integrity: sha512-E+iruNOY8VV9s4JEbe1aNEm6MiszPRr/UfcHMz0TQh1BXSxHK+ASV1R6W4HpjBhSeS+54PIsAMCBmwD06LLsqQ==} + hasBin: true + dependencies: + jsonparse: 1.3.1 + through: 2.3.8 + dev: true + + /abab/2.0.5: + resolution: {integrity: sha512-9IK9EadsbHo6jLWIpxpR6pL0sazTXV6+SQv25ZB+F7Bj9mJNaOc4nCRabwd5M/JwmUa8idz6Eci6eKfJryPs6Q==} + dev: true + + /accepts/1.3.7: + resolution: {integrity: sha512-Il80Qs2WjYlJIBNzNkK6KYqlVMTbZLXgHx2oT0pU/fjRHyEp+PEfEPY0R3WCwAGVOtauxh1hOxNgIf5bv7dQpA==} + engines: {node: '>= 0.6'} + dependencies: + mime-types: 2.1.34 + negotiator: 0.6.2 + dev: true + + /acorn-globals/6.0.0: + resolution: {integrity: sha512-ZQl7LOWaF5ePqqcX4hLuv/bLXYQNfNWw2c0/yX/TsPRKamzHcTGQnlCjHT3TsmkOUVEPS3crCxiPfdzE/Trlhg==} + dependencies: + acorn: 7.4.1 + acorn-walk: 7.2.0 + dev: true + + /acorn-jsx/5.3.2_acorn@8.6.0: + resolution: {integrity: sha512-rq9s+JNhf0IChjtDXxllJ7g41oZk5SlXtp0LHwyA5cejwn7vKmKp4pPri6YEePv2PU65sAsegbXtIinmDFDXgQ==} + peerDependencies: + acorn: ^6.0.0 || ^7.0.0 || ^8.0.0 + dependencies: + acorn: 8.6.0 + dev: true + + /acorn-walk/7.2.0: + resolution: {integrity: sha512-OPdCF6GsMIP+Az+aWfAAOEt2/+iVDKE7oy6lJ098aoe59oAmK76qV6Gw60SbZ8jHuG2wH058GF4pLFbYamYrVA==} + engines: {node: '>=0.4.0'} + dev: true + + /acorn/7.4.1: + resolution: {integrity: sha512-nQyp0o1/mNdbTO1PO6kHkwSrmgZ0MT/jCCpNiwbUjGoRN4dlBhqJtoQuCnEOKzgTVwg0ZWiCoQy6SxMebQVh8A==} + engines: {node: '>=0.4.0'} + hasBin: true + dev: true + + /acorn/8.6.0: + resolution: {integrity: sha512-U1riIR+lBSNi3IbxtaHOIKdH8sLFv3NYfNv8sg7ZsNhcfl4HF2++BfqqrNAxoCLQW1iiylOj76ecnaUxz+z9yw==} + engines: {node: '>=0.4.0'} + hasBin: true + dev: true + + /agent-base/6.0.2: + resolution: {integrity: sha512-RZNwNclF7+MS/8bDg70amg32dyeZGZxiDuQmZxKLAlQjr3jGyLx+4Kkk58UO7D2QdgFIQCovuSuZESne6RG6XQ==} + engines: {node: '>= 6.0.0'} + dependencies: + debug: 4.3.3 + transitivePeerDependencies: + - supports-color + dev: true + + /ajv/6.12.6: + resolution: {integrity: sha512-j3fVLgvTo527anyYyJOGTYJbG+vnnQYvE0m5mmkc1TK+nxAppkCLMIL0aZ4dblVCNoGShhm+kzE4ZUykBoMg4g==} + dependencies: + fast-deep-equal: 3.1.3 + fast-json-stable-stringify: 2.1.0 + json-schema-traverse: 0.4.1 + uri-js: 4.4.1 + dev: true + + /ansi-colors/4.1.1: + resolution: {integrity: sha512-JoX0apGbHaUJBNl6yF+p6JAFYZ666/hhCGKN5t9QFjbJQKUU/g8MNbFDbvfrgKXvI1QpZplPOnwIo99lX/AAmA==} + engines: {node: '>=6'} + dev: true + + /ansi-escapes/4.3.2: + resolution: {integrity: sha512-gKXj5ALrKWQLsYG9jlTRmR/xKluxHV+Z9QEwNIgCfM1/uwPMCuzVVnh5mwTd+OuBZcwSIMbqssNWRm1lE51QaQ==} + engines: {node: '>=8'} + dependencies: + type-fest: 0.21.3 + dev: true + + /ansi-regex/5.0.1: + resolution: {integrity: sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==} + engines: {node: '>=8'} + dev: true + + /ansi-styles/3.2.1: + resolution: {integrity: sha512-VT0ZI6kZRdTh8YyJw3SMbYm/u+NqfsAxEpWO0Pf9sq8/e94WxxOpPKx9FR1FlyCtOVDNOQ+8ntlqFxiRc+r5qA==} + engines: {node: '>=4'} + dependencies: + color-convert: 1.9.3 + dev: true + + /ansi-styles/4.3.0: + resolution: {integrity: sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==} + engines: {node: '>=8'} + dependencies: + color-convert: 2.0.1 + dev: true + + /ansi-styles/5.2.0: + resolution: {integrity: sha512-Cxwpt2SfTzTtXcfOlzGEee8O+c+MmUgGrNiBcXnuWxuFJHe6a5Hz7qwhwe5OgaSYI0IJvkLqWX1ASG+cJOkEiA==} + engines: {node: '>=10'} + dev: true + + /anymatch/3.1.2: + resolution: {integrity: sha512-P43ePfOAIupkguHUycrc4qJ9kz8ZiuOUijaETwX7THt0Y/GNK7v0aa8rY816xWjZ7rJdA5XdMcpVFTKMq+RvWg==} + engines: {node: '>= 8'} + dependencies: + normalize-path: 3.0.0 + picomatch: 2.3.0 + dev: true + + /append-field/1.0.0: + resolution: {integrity: sha1-HjRA6RXwsSA9I3SOeO3XubW0PlY=} + dev: true + + /arg/4.1.3: + resolution: {integrity: sha512-58S9QDqG0Xx27YwPSt9fJxivjYl432YCwfDMfZ+71RAqUrZef7LrKQZ3LHLOwCS4FLNBplP533Zx895SeOCHvA==} + dev: true + + /argparse/1.0.10: + resolution: {integrity: sha512-o5Roy6tNG4SL/FOkCAN6RzjiakZS25RLYFrcMttJqbdd8BWrnA+fGz57iN5Pb06pvBGvl5gQ0B48dJlslXvoTg==} + dependencies: + sprintf-js: 1.0.3 + dev: true + + /argparse/2.0.1: + resolution: {integrity: sha512-8+9WqebbFzpX9OR+Wa6O29asIogeRMzcGtAINdpMHHyAg10f05aSFVBbcEqGf/PXw1EjAZ+q2/bEBg3DvurK3Q==} + dev: true + + /array-flatten/1.1.1: + resolution: {integrity: sha1-ml9pkFGx5wczKPKgCJaLZOopVdI=} + dev: true + + /array-ify/1.0.0: + resolution: {integrity: sha1-nlKHYrSpBmrRY6aWKjZEGOlibs4=} + dev: true + + /array-union/2.1.0: + resolution: {integrity: sha512-HGyxoOTYUyCM6stUe6EJgnd4EoewAI7zMdfqO+kGjnlZmBDz/cR5pf8r/cR4Wq60sL/p0IkcjUEEPwS3GFrIyw==} + engines: {node: '>=8'} + dev: true + + /arrify/1.0.1: + resolution: {integrity: sha1-iYUI2iIm84DfkEcoRWhJwVAaSw0=} + engines: {node: '>=0.10.0'} + dev: true + + /asynckit/0.4.0: + resolution: {integrity: sha1-x57Zf380y48robyXkLzDZkdLS3k=} + + /axios/0.24.0: + resolution: {integrity: sha512-Q6cWsys88HoPgAaFAVUb0WpPk0O8iTeisR9IMqy9G8AbO4NlpVknrnQS03zzF9PGAWgO3cgletO3VjV/P7VztA==} + dependencies: + follow-redirects: 1.14.6 + transitivePeerDependencies: + - debug + dev: false + + /babel-jest/27.4.5_@babel+core@7.16.5: + resolution: {integrity: sha512-3uuUTjXbgtODmSv/DXO9nZfD52IyC2OYTFaXGRzL0kpykzroaquCrD5+lZNafTvZlnNqZHt5pb0M08qVBZnsnA==} + engines: {node: ^10.13.0 || ^12.13.0 || ^14.15.0 || >=15.0.0} + peerDependencies: + '@babel/core': ^7.8.0 + dependencies: + '@babel/core': 7.16.5 + '@jest/transform': 27.4.5 + '@jest/types': 27.4.2 + '@types/babel__core': 7.1.17 + babel-plugin-istanbul: 6.1.1 + babel-preset-jest: 27.4.0_@babel+core@7.16.5 + chalk: 4.1.2 + graceful-fs: 4.2.8 + slash: 3.0.0 + transitivePeerDependencies: + - supports-color + dev: true + + /babel-plugin-istanbul/6.1.1: + resolution: {integrity: sha512-Y1IQok9821cC9onCx5otgFfRm7Lm+I+wwxOx738M/WLPZ9Q42m4IG5W0FNX8WLL2gYMZo3JkuXIH2DOpWM+qwA==} + engines: {node: '>=8'} + dependencies: + '@babel/helper-plugin-utils': 7.16.5 + '@istanbuljs/load-nyc-config': 1.1.0 + '@istanbuljs/schema': 0.1.3 + istanbul-lib-instrument: 5.1.0 + test-exclude: 6.0.0 + transitivePeerDependencies: + - supports-color + dev: true + + /babel-plugin-jest-hoist/27.4.0: + resolution: {integrity: sha512-Jcu7qS4OX5kTWBc45Hz7BMmgXuJqRnhatqpUhnzGC3OBYpOmf2tv6jFNwZpwM7wU7MUuv2r9IPS/ZlYOuburVw==} + engines: {node: ^10.13.0 || ^12.13.0 || ^14.15.0 || >=15.0.0} + dependencies: + '@babel/template': 7.16.0 + '@babel/types': 7.16.0 + '@types/babel__core': 7.1.17 + '@types/babel__traverse': 7.14.2 + dev: true + + /babel-preset-current-node-syntax/1.0.1_@babel+core@7.16.5: + resolution: {integrity: sha512-M7LQ0bxarkxQoN+vz5aJPsLBn77n8QgTFmo8WK0/44auK2xlCXrYcUxHFxgU7qW5Yzw/CjmLRK2uJzaCd7LvqQ==} + peerDependencies: + '@babel/core': ^7.0.0 + dependencies: + '@babel/core': 7.16.5 + '@babel/plugin-syntax-async-generators': 7.8.4_@babel+core@7.16.5 + '@babel/plugin-syntax-bigint': 7.8.3_@babel+core@7.16.5 + '@babel/plugin-syntax-class-properties': 7.12.13_@babel+core@7.16.5 + '@babel/plugin-syntax-import-meta': 7.10.4_@babel+core@7.16.5 + '@babel/plugin-syntax-json-strings': 7.8.3_@babel+core@7.16.5 + '@babel/plugin-syntax-logical-assignment-operators': 7.10.4_@babel+core@7.16.5 + '@babel/plugin-syntax-nullish-coalescing-operator': 7.8.3_@babel+core@7.16.5 + '@babel/plugin-syntax-numeric-separator': 7.10.4_@babel+core@7.16.5 + '@babel/plugin-syntax-object-rest-spread': 7.8.3_@babel+core@7.16.5 + '@babel/plugin-syntax-optional-catch-binding': 7.8.3_@babel+core@7.16.5 + '@babel/plugin-syntax-optional-chaining': 7.8.3_@babel+core@7.16.5 + '@babel/plugin-syntax-top-level-await': 7.14.5_@babel+core@7.16.5 + dev: true + + /babel-preset-jest/27.4.0_@babel+core@7.16.5: + resolution: {integrity: sha512-NK4jGYpnBvNxcGo7/ZpZJr51jCGT+3bwwpVIDY2oNfTxJJldRtB4VAcYdgp1loDE50ODuTu+yBjpMAswv5tlpg==} + engines: {node: ^10.13.0 || ^12.13.0 || ^14.15.0 || >=15.0.0} + peerDependencies: + '@babel/core': ^7.0.0 + dependencies: + '@babel/core': 7.16.5 + babel-plugin-jest-hoist: 27.4.0 + babel-preset-current-node-syntax: 1.0.1_@babel+core@7.16.5 + dev: true + + /balanced-match/1.0.2: + resolution: {integrity: sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw==} + dev: true + + /body-parser/1.19.1: + resolution: {integrity: sha512-8ljfQi5eBk8EJfECMrgqNGWPEY5jWP+1IzkzkGdFFEwFQZZyaZ21UqdaHktgiMlH0xLHqIFtE/u2OYE5dOtViA==} + engines: {node: '>= 0.8'} + dependencies: + bytes: 3.1.1 + content-type: 1.0.4 + debug: 2.6.9 + depd: 1.1.2 + http-errors: 1.8.1 + iconv-lite: 0.4.24 + on-finished: 2.3.0 + qs: 6.9.6 + raw-body: 2.4.2 + type-is: 1.6.18 + dev: true + + /brace-expansion/1.1.11: + resolution: {integrity: sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==} + dependencies: + balanced-match: 1.0.2 + concat-map: 0.0.1 + dev: true + + /braces/3.0.2: + resolution: {integrity: sha512-b8um+L1RzM3WDSzvhm6gIz1yfTbBt6YTlcEKAvsmqCZZFw46z626lVj9j1yEPW33H5H+lBQpZMP1k8l+78Ha0A==} + engines: {node: '>=8'} + dependencies: + fill-range: 7.0.1 + dev: true + + /browser-process-hrtime/1.0.0: + resolution: {integrity: sha512-9o5UecI3GhkpM6DrXr69PblIuWxPKk9Y0jHBRhdocZ2y7YECBFCsHm79Pr3OyR2AvjhDkabFJaDJMYRazHgsow==} + dev: true + + /browserslist/4.19.1: + resolution: {integrity: sha512-u2tbbG5PdKRTUoctO3NBD8FQ5HdPh1ZXPHzp1rwaa5jTc+RV9/+RlWiAIKmjRPQF+xbGM9Kklj5bZQFa2s/38A==} + engines: {node: ^6 || ^7 || ^8 || ^9 || ^10 || ^11 || ^12 || >=13.7} + hasBin: true + dependencies: + caniuse-lite: 1.0.30001291 + electron-to-chromium: 1.4.24 + escalade: 3.1.1 + node-releases: 2.0.1 + picocolors: 1.0.0 + dev: true + + /bs-logger/0.2.6: + resolution: {integrity: sha512-pd8DCoxmbgc7hyPKOvxtqNcjYoOsABPQdcCUjGp3d42VR2CX1ORhk2A87oqqu5R1kk+76nsxZupkmyd+MVtCog==} + engines: {node: '>= 6'} + dependencies: + fast-json-stable-stringify: 2.1.0 + dev: true + + /bser/2.1.1: + resolution: {integrity: sha512-gQxTNE/GAfIIrmHLUE3oJyp5FO6HRBfhjnw4/wMmA63ZGDJnWBmgY/lyQBpnDUkGmAhbSe39tx2d/iTOAfglwQ==} + dependencies: + node-int64: 0.4.0 + dev: true + + /buffer-from/1.1.2: + resolution: {integrity: sha512-E+XQCRwSbaaiChtv6k6Dwgc+bx+Bs6vuKJHHl5kox/BaKbhiXzqQOwK4cO22yElGp2OCmjwVhT3HmxgyPGnJfQ==} + dev: true + + /busboy/0.2.14: + resolution: {integrity: sha1-bCpiLvz0fFe7vh4qnDetNseSVFM=} + engines: {node: '>=0.8.0'} + dependencies: + dicer: 0.2.5 + readable-stream: 1.1.14 + dev: true + + /bytes/3.1.1: + resolution: {integrity: sha512-dWe4nWO/ruEOY7HkUJ5gFt1DCFV9zPRoJr8pV0/ASQermOZjtq8jMjOprC0Kd10GLN+l7xaUPvxzJFWtxGu8Fg==} + engines: {node: '>= 0.8'} + dev: true + + /call-bind/1.0.2: + resolution: {integrity: sha512-7O+FbCihrB5WGbFYesctwmTKae6rOiIzmz1icreWJ+0aA7LJfuqhEso2T9ncpcFtzMQtzXf2QGGueWJGTYsqrA==} + dependencies: + function-bind: 1.1.1 + get-intrinsic: 1.1.1 + dev: false + + /callsites/3.1.0: + resolution: {integrity: sha512-P8BjAsXvZS+VIDUI11hHCQEv74YT67YUi5JJFNWIqL235sBmjX4+qx9Muvls5ivyNENctx46xQLQ3aTuE7ssaQ==} + engines: {node: '>=6'} + dev: true + + /camelcase-keys/6.2.2: + resolution: {integrity: sha512-YrwaA0vEKazPBkn0ipTiMpSajYDSe+KjQfrjhcBMxJt/znbvlHd8Pw/Vamaz5EB4Wfhs3SUR3Z9mwRu/P3s3Yg==} + engines: {node: '>=8'} + dependencies: + camelcase: 5.3.1 + map-obj: 4.3.0 + quick-lru: 4.0.1 + dev: true + + /camelcase/5.3.1: + resolution: {integrity: sha512-L28STB170nwWS63UjtlEOE3dldQApaJXZkOI1uMFfzf3rRuPegHaHesyee+YxQ+W6SvRDQV6UrdOdRiR153wJg==} + engines: {node: '>=6'} + dev: true + + /camelcase/6.2.1: + resolution: {integrity: sha512-tVI4q5jjFV5CavAU8DXfza/TJcZutVKo/5Foskmsqcm0MsL91moHvwiGNnqaa2o6PF/7yT5ikDRcVcl8Rj6LCA==} + engines: {node: '>=10'} + dev: true + + /caniuse-lite/1.0.30001291: + resolution: {integrity: sha512-roMV5V0HNGgJ88s42eE70sstqGW/gwFndosYrikHthw98N5tLnOTxFqMLQjZVRxTWFlJ4rn+MsgXrR7MDPY4jA==} + dev: true + + /chalk/2.4.2: + resolution: {integrity: sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ==} + engines: {node: '>=4'} + dependencies: + ansi-styles: 3.2.1 + escape-string-regexp: 1.0.5 + supports-color: 5.5.0 + dev: true + + /chalk/4.1.2: + resolution: {integrity: sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==} + engines: {node: '>=10'} + dependencies: + ansi-styles: 4.3.0 + supports-color: 7.2.0 + dev: true + + /char-regex/1.0.2: + resolution: {integrity: sha512-kWWXztvZ5SBQV+eRgKFeh8q5sLuZY2+8WUIzlxWVTg+oGwY14qylx1KbKzHd8P6ZYkAg0xyIDU9JMHhyJMZ1jw==} + engines: {node: '>=10'} + dev: true + + /ci-info/3.3.0: + resolution: {integrity: sha512-riT/3vI5YpVH6/qomlDnJow6TBee2PBKSEpx3O32EGPYbWGIRsIlGRms3Sm74wYE1JMo8RnO04Hb12+v1J5ICw==} + dev: true + + /cjs-module-lexer/1.2.2: + resolution: {integrity: sha512-cOU9usZw8/dXIXKtwa8pM0OTJQuJkxMN6w30csNRUerHfeQ5R6U3kkU/FtJeIf3M202OHfY2U8ccInBG7/xogA==} + dev: true + + /class-transformer/0.5.1: + resolution: {integrity: sha512-SQa1Ws6hUbfC98vKGxZH3KFY0Y1lm5Zm0SY8XX9zbK7FJCyVEac3ATW0RIpwzW+oOfmHE5PMPufDG9hCfoEOMw==} + dev: false + + /class-validator/0.13.2: + resolution: {integrity: sha512-yBUcQy07FPlGzUjoLuUfIOXzgynnQPPruyK1Ge2B74k9ROwnle1E+NxLWnUv5OLU8hA/qL5leAE9XnXq3byaBw==} + dependencies: + libphonenumber-js: 1.9.44 + validator: 13.7.0 + dev: false + + /cliui/7.0.4: + resolution: {integrity: sha512-OcRE68cOsVMXp1Yvonl/fzkQOyjLSu/8bhPDfQt0e0/Eb283TKP20Fs2MqoPsr9SwA595rRCA+QMzYc9nBP+JQ==} + dependencies: + string-width: 4.2.3 + strip-ansi: 6.0.1 + wrap-ansi: 7.0.0 + dev: true + + /co/4.6.0: + resolution: {integrity: sha1-bqa989hTrlTMuOR7+gvz+QMfsYQ=} + engines: {iojs: '>= 1.0.0', node: '>= 0.12.0'} + dev: true + + /collect-v8-coverage/1.0.1: + resolution: {integrity: sha512-iBPtljfCNcTKNAto0KEtDfZ3qzjJvqE3aTGZsbhjSBlorqpXJlaWWtPO35D+ZImoC3KWejX64o+yPGxhWSTzfg==} + dev: true + + /color-convert/1.9.3: + resolution: {integrity: sha512-QfAUtd+vFdAtFQcC8CCyYt1fYWxSqAiK2cSD6zDB8N3cpsEBAvRxp9zOGg6G/SHHJYAT88/az/IuDGALsNVbGg==} + dependencies: + color-name: 1.1.3 + dev: true + + /color-convert/2.0.1: + resolution: {integrity: sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==} + engines: {node: '>=7.0.0'} + dependencies: + color-name: 1.1.4 + dev: true + + /color-name/1.1.3: + resolution: {integrity: sha1-p9BVi9icQveV3UIyj3QIMcpTvCU=} + dev: true + + /color-name/1.1.4: + resolution: {integrity: sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==} + dev: true + + /combined-stream/1.0.8: + resolution: {integrity: sha512-FQN4MRfuJeHf7cBbBMJFXhKSDq+2kAArBlmRBvcvFE5BB1HZKXtSFASDhdlz9zOYwxh8lDdnvmMOe/+5cdoEdg==} + engines: {node: '>= 0.8'} + dependencies: + delayed-stream: 1.0.0 + + /compare-func/2.0.0: + resolution: {integrity: sha512-zHig5N+tPWARooBnb0Zx1MFcdfpyJrfTJ3Y5L+IFvUm8rM74hHz66z0gw0x4tijh5CorKkKUCnW82R2vmpeCRA==} + dependencies: + array-ify: 1.0.0 + dot-prop: 5.3.0 + dev: true + + /concat-map/0.0.1: + resolution: {integrity: sha1-2Klr13/Wjfd5OnMDajug1UBdR3s=} + dev: true + + /concat-stream/1.6.2: + resolution: {integrity: sha512-27HBghJxjiZtIk3Ycvn/4kbJk/1uZuJFfuPEns6LaEvpvG1f0hTea8lilrouyo9mVc2GWdcEZ8OLoGmSADlrCw==} + engines: {'0': node >= 0.8} + dependencies: + buffer-from: 1.1.2 + inherits: 2.0.4 + readable-stream: 2.3.7 + typedarray: 0.0.6 + dev: true + + /content-disposition/0.5.4: + resolution: {integrity: sha512-FveZTNuGw04cxlAiWbzi6zTAL/lhehaWbTtgluJh4/E95DqMwTmha3KZN1aAWA8cFIhHzMZUvLevkw5Rqk+tSQ==} + engines: {node: '>= 0.6'} + dependencies: + safe-buffer: 5.2.1 + dev: true + + /content-type/1.0.4: + resolution: {integrity: sha512-hIP3EEPs8tB9AT1L+NUqtwOAps4mk2Zob89MWXMHjHWg9milF/j4osnnQLXBCBFBk/tvIG/tUc9mOUJiPBhPXA==} + engines: {node: '>= 0.6'} + dev: true + + /conventional-changelog-angular/5.0.13: + resolution: {integrity: sha512-i/gipMxs7s8L/QeuavPF2hLnJgH6pEZAttySB6aiQLWcX3puWDL3ACVmvBhJGxnAy52Qc15ua26BufY6KpmrVA==} + engines: {node: '>=10'} + dependencies: + compare-func: 2.0.0 + q: 1.5.1 + dev: true + + /conventional-changelog-conventionalcommits/4.6.1: + resolution: {integrity: sha512-lzWJpPZhbM1R0PIzkwzGBCnAkH5RKJzJfFQZcl/D+2lsJxAwGnDKBqn/F4C1RD31GJNn8NuKWQzAZDAVXPp2Mw==} + engines: {node: '>=10'} + dependencies: + compare-func: 2.0.0 + lodash: 4.17.21 + q: 1.5.1 + dev: true + + /conventional-commits-parser/3.2.3: + resolution: {integrity: sha512-YyRDR7On9H07ICFpRm/igcdjIqebXbvf4Cff+Pf0BrBys1i1EOzx9iFXNlAbdrLAR8jf7bkUYkDAr8pEy0q4Pw==} + engines: {node: '>=10'} + hasBin: true + dependencies: + is-text-path: 1.0.1 + JSONStream: 1.3.5 + lodash: 4.17.21 + meow: 8.1.2 + split2: 3.2.2 + through2: 4.0.2 + dev: true + + /convert-source-map/1.8.0: + resolution: {integrity: sha512-+OQdjP49zViI/6i7nIJpA8rAl4sV/JdPfU9nZs3VqOwGIgizICvuN2ru6fMd+4llL0tar18UYJXfZ/TWtmhUjA==} + dependencies: + safe-buffer: 5.1.2 + dev: true + + /cookie-signature/1.0.6: + resolution: {integrity: sha1-4wOogrNCzD7oylE6eZmXNNqzriw=} + dev: true + + /cookie/0.4.1: + resolution: {integrity: sha512-ZwrFkGJxUR3EIoXtO+yVE69Eb7KlixbaeAWfBQB9vVsNn/o+Yw69gBWSSDK825hQNdN+wF8zELf3dFNl/kxkUA==} + engines: {node: '>= 0.6'} + dev: true + + /core-util-is/1.0.3: + resolution: {integrity: sha512-ZQBvi1DcpJ4GDqanjucZ2Hj3wEO5pZDS89BWbkcrvdxksJorwUDDZamX9ldFkp9aw2lmBDLgkObEA4DWNJ9FYQ==} + dev: true + + /cosmiconfig/7.0.1: + resolution: {integrity: sha512-a1YWNUV2HwGimB7dU2s1wUMurNKjpx60HxBB6xUM8Re+2s1g1IIfJvFR0/iCF+XHdE0GMTKTuLR32UQff4TEyQ==} + engines: {node: '>=10'} + dependencies: + '@types/parse-json': 4.0.0 + import-fresh: 3.3.0 + parse-json: 5.2.0 + path-type: 4.0.0 + yaml: 1.10.2 + dev: true + + /create-require/1.1.1: + resolution: {integrity: sha512-dcKFX3jn0MpIaXjisoRvexIJVEKzaq7z2rZKxf+MSr9TkdmHmsU4m2lcLojrj/FHl8mk5VxMmYA+ftRkP/3oKQ==} + dev: true + + /cross-spawn/7.0.3: + resolution: {integrity: sha512-iRDPJKUPVEND7dHPO8rkbOnPpyDygcDFtWjpeWNCgy8WP2rXcxXL8TskReQl6OrB2G7+UJrags1q15Fudc7G6w==} + engines: {node: '>= 8'} + dependencies: + path-key: 3.1.1 + shebang-command: 2.0.0 + which: 2.0.2 + dev: true + + /cssom/0.3.8: + resolution: {integrity: sha512-b0tGHbfegbhPJpxpiBPU2sCkigAqtM9O121le6bbOlgyV+NyGyCmVfJ6QW9eRjz8CpNfWEOYBIMIGRYkLwsIYg==} + dev: true + + /cssom/0.4.4: + resolution: {integrity: sha512-p3pvU7r1MyyqbTk+WbNJIgJjG2VmTIaB10rI93LzVPrmDJKkzKYMtxxyAvQXR/NS6otuzveI7+7BBq3SjBS2mw==} + dev: true + + /cssstyle/2.3.0: + resolution: {integrity: sha512-AZL67abkUzIuvcHqk7c09cezpGNcxUxU4Ioi/05xHk4DQeTkWmGYftIE6ctU6AEt+Gn4n1lDStOtj7FKycP71A==} + engines: {node: '>=8'} + dependencies: + cssom: 0.3.8 + dev: true + + /dargs/7.0.0: + resolution: {integrity: sha512-2iy1EkLdlBzQGvbweYRFxmFath8+K7+AKB0TlhHWkNuH+TmovaMH/Wp7V7R4u7f4SnX3OgLsU9t1NI9ioDnUpg==} + engines: {node: '>=8'} + dev: true + + /data-urls/2.0.0: + resolution: {integrity: sha512-X5eWTSXO/BJmpdIKCRuKUgSCgAN0OwliVK3yPKbwIWU1Tdw5BRajxlzMidvh+gwko9AfQ9zIj52pzF91Q3YAvQ==} + engines: {node: '>=10'} + dependencies: + abab: 2.0.5 + whatwg-mimetype: 2.3.0 + whatwg-url: 8.7.0 + dev: true + + /debug/2.6.9: + resolution: {integrity: sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==} + dependencies: + ms: 2.0.0 + dev: true + + /debug/4.3.3: + resolution: {integrity: sha512-/zxw5+vh1Tfv+4Qn7a5nsbcJKPaSvCDhojn6FEl9vupwK2VCSDtEiEtqr8DFtzYFOdz63LBkxec7DYuc2jon6Q==} + engines: {node: '>=6.0'} + peerDependencies: + supports-color: '*' + peerDependenciesMeta: + supports-color: + optional: true + dependencies: + ms: 2.1.2 + dev: true + + /decamelize-keys/1.1.0: + resolution: {integrity: sha1-0XGoeTMlKAfrPLYdwcFEXQeN8tk=} + engines: {node: '>=0.10.0'} + dependencies: + decamelize: 1.2.0 + map-obj: 1.0.1 + dev: true + + /decamelize/1.2.0: + resolution: {integrity: sha1-9lNNFRSCabIDUue+4m9QH5oZEpA=} + engines: {node: '>=0.10.0'} + dev: true + + /decimal.js/10.3.1: + resolution: {integrity: sha512-V0pfhfr8suzyPGOx3nmq4aHqabehUZn6Ch9kyFpV79TGDTWFmHqUqXdabR7QHqxzrYolF4+tVmJhUG4OURg5dQ==} + dev: true + + /dedent/0.7.0: + resolution: {integrity: sha1-JJXduvbrh0q7Dhvp3yLS5aVEMmw=} + dev: true + + /deep-is/0.1.4: + resolution: {integrity: sha512-oIPzksmTg4/MriiaYGO+okXDT7ztn/w3Eptv/+gSIdMdKsJo0u4CfYNFJPy+4SKMuCqGw2wxnA+URMg3t8a/bQ==} + dev: true + + /deepmerge/4.2.2: + resolution: {integrity: sha512-FJ3UgI4gIl+PHZm53knsuSFpE+nESMr7M4v9QcgB7S63Kj/6WqMiFQJpBBYz1Pt+66bZpP3Q7Lye0Oo9MPKEdg==} + engines: {node: '>=0.10.0'} + dev: true + + /delayed-stream/1.0.0: + resolution: {integrity: sha1-3zrhmayt+31ECqrgsp4icrJOxhk=} + engines: {node: '>=0.4.0'} + + /depd/1.1.2: + resolution: {integrity: sha1-m81S4UwJd2PnSbJ0xDRu0uVgtak=} + engines: {node: '>= 0.6'} + dev: true + + /destroy/1.0.4: + resolution: {integrity: sha1-l4hXRCxEdJ5CBmE+N5RiBYJqvYA=} + dev: true + + /detect-newline/3.1.0: + resolution: {integrity: sha512-TLz+x/vEXm/Y7P7wn1EJFNLxYpUD4TgMosxY6fAVJUnJMbupHBOncxyWUG9OpTaH9EBD7uFI5LfEgmMOc54DsA==} + engines: {node: '>=8'} + dev: true + + /dicer/0.2.5: + resolution: {integrity: sha1-WZbAhrszIYyBLAkL3cCc0S+stw8=} + engines: {node: '>=0.8.0'} + dependencies: + readable-stream: 1.1.14 + streamsearch: 0.1.2 + dev: true + + /diff-sequences/27.4.0: + resolution: {integrity: sha512-YqiQzkrsmHMH5uuh8OdQFU9/ZpADnwzml8z0O5HvRNda+5UZsaX/xN+AAxfR2hWq1Y7HZnAzO9J5lJXOuDz2Ww==} + engines: {node: ^10.13.0 || ^12.13.0 || ^14.15.0 || >=15.0.0} + dev: true + + /diff/4.0.2: + resolution: {integrity: sha512-58lmxKSA4BNyLz+HHMUzlOEpg09FV+ev6ZMe3vJihgdxzgcwZ8VoEEPmALCZG9LmqfVoNMMKpttIYTVG6uDY7A==} + engines: {node: '>=0.3.1'} + dev: true + + /dir-glob/3.0.1: + resolution: {integrity: sha512-WkrWp9GR4KXfKGYzOLmTuGVi1UWFfws377n9cc55/tb6DuqyF6pcQ5AbiHEshaDpY9v6oaSr2XCDidGmMwdzIA==} + engines: {node: '>=8'} + dependencies: + path-type: 4.0.0 + dev: true + + /doctrine/3.0.0: + resolution: {integrity: sha512-yS+Q5i3hBf7GBkd4KG8a7eBNNWNGLTaEwwYWUijIYM7zrlYDM0BFXHjjPWlWZ1Rg7UaddZeIDmi9jF3HmqiQ2w==} + engines: {node: '>=6.0.0'} + dependencies: + esutils: 2.0.3 + dev: true + + /domexception/2.0.1: + resolution: {integrity: sha512-yxJ2mFy/sibVQlu5qHjOkf9J3K6zgmCxgJ94u2EdvDOV09H+32LtRswEcUsmUWN72pVLOEnTSRaIVVzVQgS0dg==} + engines: {node: '>=8'} + dependencies: + webidl-conversions: 5.0.0 + dev: true + + /dot-prop/5.3.0: + resolution: {integrity: sha512-QM8q3zDe58hqUqjraQOmzZ1LIH9SWQJTlEKCH4kJ2oQvLZk7RbQXvtDM2XEq3fwkV9CCvvH4LA0AV+ogFsBM2Q==} + engines: {node: '>=8'} + dependencies: + is-obj: 2.0.0 + dev: true + + /ee-first/1.1.1: + resolution: {integrity: sha1-WQxhFWsK4vTwJVcyoViyZrxWsh0=} + dev: true + + /electron-to-chromium/1.4.24: + resolution: {integrity: sha512-erwx5r69B/WFfFuF2jcNN0817BfDBdC4765kQ6WltOMuwsimlQo3JTEq0Cle+wpHralwdeX3OfAtw/mHxPK0Wg==} + dev: true + + /emittery/0.8.1: + resolution: {integrity: sha512-uDfvUjVrfGJJhymx/kz6prltenw1u7WrCg1oa94zYY8xxVpLLUu045LAT0dhDZdXG58/EpPL/5kA180fQ/qudg==} + engines: {node: '>=10'} + dev: true + + /emoji-regex/8.0.0: + resolution: {integrity: sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A==} + dev: true + + /encodeurl/1.0.2: + resolution: {integrity: sha1-rT/0yG7C0CkyL1oCw6mmBslbP1k=} + engines: {node: '>= 0.8'} + dev: true + + /enquirer/2.3.6: + resolution: {integrity: sha512-yjNnPr315/FjS4zIsUxYguYUPP2e1NK4d7E7ZOLiyYCcbFBiTMyID+2wvm2w6+pZ/odMA7cRkjhsPbltwBOrLg==} + engines: {node: '>=8.6'} + dependencies: + ansi-colors: 4.1.1 + dev: true + + /error-ex/1.3.2: + resolution: {integrity: sha512-7dFHNmqeFSEt2ZBsCriorKnn3Z2pj+fd9kmI6QoWw4//DL+icEBfc0U7qJCisqrTsKTjw4fNFy2pW9OqStD84g==} + dependencies: + is-arrayish: 0.2.1 + dev: true + + /escalade/3.1.1: + resolution: {integrity: sha512-k0er2gUkLf8O0zKJiAhmkTnJlTvINGv7ygDNPbeIsX/TJjGJZHuh9B2UxbsaEkmlEo9MfhrSzmhIlhRlI2GXnw==} + engines: {node: '>=6'} + dev: true + + /escape-html/1.0.3: + resolution: {integrity: sha1-Aljq5NPQwJdN4cFpGI7wBR0dGYg=} + dev: true + + /escape-string-regexp/1.0.5: + resolution: {integrity: sha1-G2HAViGQqN/2rjuyzwIAyhMLhtQ=} + engines: {node: '>=0.8.0'} + dev: true + + /escape-string-regexp/2.0.0: + resolution: {integrity: sha512-UpzcLCXolUWcNu5HtVMHYdXJjArjsF9C0aNnquZYY4uW/Vu0miy5YoWvbV345HauVvcAUnpRuhMMcqTcGOY2+w==} + engines: {node: '>=8'} + dev: true + + /escape-string-regexp/4.0.0: + resolution: {integrity: sha512-TtpcNJ3XAzx3Gq8sWRzJaVajRs0uVxA2YAkdb1jm2YkPz4G6egUFAyA3n5vtEIZefPk5Wa4UXbKuS5fKkJWdgA==} + engines: {node: '>=10'} + dev: true + + /escodegen/2.0.0: + resolution: {integrity: sha512-mmHKys/C8BFUGI+MAWNcSYoORYLMdPzjrknd2Vc+bUsjN5bXcr8EhrNB+UTqfL1y3I9c4fw2ihgtMPQLBRiQxw==} + engines: {node: '>=6.0'} + hasBin: true + dependencies: + esprima: 4.0.1 + estraverse: 5.3.0 + esutils: 2.0.3 + optionator: 0.8.3 + optionalDependencies: + source-map: 0.6.1 + dev: true + + /eslint-config-prettier/8.3.0_eslint@8.5.0: + resolution: {integrity: sha512-BgZuLUSeKzvlL/VUjx/Yb787VQ26RU3gGjA3iiFvdsp/2bMfVIWUVP7tjxtjS0e+HP409cPlPvNkQloz8C91ew==} + hasBin: true + peerDependencies: + eslint: '>=7.0.0' + dependencies: + eslint: 8.5.0 + dev: true + + /eslint-plugin-prettier/4.0.0_94e1b6d3ce6ea916847122712570e9ae: + resolution: {integrity: sha512-98MqmCJ7vJodoQK359bqQWaxOE0CS8paAz/GgjaZLyex4TTk3g9HugoO89EqWCrFiOqn9EVvcoo7gZzONCWVwQ==} + engines: {node: '>=6.0.0'} + peerDependencies: + eslint: '>=7.28.0' + eslint-config-prettier: '*' + prettier: '>=2.0.0' + peerDependenciesMeta: + eslint-config-prettier: + optional: true + dependencies: + eslint: 8.5.0 + eslint-config-prettier: 8.3.0_eslint@8.5.0 + prettier: 2.5.1 + prettier-linter-helpers: 1.0.0 + dev: true + + /eslint-plugin-unused-imports/2.0.0_5a3e1449e31fbcbb167860ec6a3f3d63: + resolution: {integrity: sha512-3APeS/tQlTrFa167ThtP0Zm0vctjr4M44HMpeg1P4bK6wItarumq0Ma82xorMKdFsWpphQBlRPzw/pxiVELX1A==} + engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0} + peerDependencies: + '@typescript-eslint/eslint-plugin': ^5.0.0 + eslint: ^8.0.0 + peerDependenciesMeta: + '@typescript-eslint/eslint-plugin': + optional: true + dependencies: + '@typescript-eslint/eslint-plugin': 5.7.0_a6f6159640504abdd3de077f8bcadb33 + eslint: 8.5.0 + eslint-rule-composer: 0.3.0 + dev: true + + /eslint-rule-composer/0.3.0: + resolution: {integrity: sha512-bt+Sh8CtDmn2OajxvNO+BX7Wn4CIWMpTRm3MaiKPCQcnnlm0CS2mhui6QaoeQugs+3Kj2ESKEEGJUdVafwhiCg==} + engines: {node: '>=4.0.0'} + dev: true + + /eslint-scope/5.1.1: + resolution: {integrity: sha512-2NxwbF/hZ0KpepYN0cNbo+FN6XoK7GaHlQhgx/hIZl6Va0bF45RQOOwhLIy8lQDbuCiadSLCBnH2CFYquit5bw==} + engines: {node: '>=8.0.0'} + dependencies: + esrecurse: 4.3.0 + estraverse: 4.3.0 + dev: true + + /eslint-scope/7.1.0: + resolution: {integrity: sha512-aWwkhnS0qAXqNOgKOK0dJ2nvzEbhEvpy8OlJ9kZ0FeZnA6zpjv1/Vei+puGFFX7zkPCkHHXb7IDX3A+7yPrRWg==} + engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0} + dependencies: + esrecurse: 4.3.0 + estraverse: 5.3.0 + dev: true + + /eslint-utils/3.0.0_eslint@8.5.0: + resolution: {integrity: sha512-uuQC43IGctw68pJA1RgbQS8/NP7rch6Cwd4j3ZBtgo4/8Flj4eGE7ZYSZRN3iq5pVUv6GPdW5Z1RFleo84uLDA==} + engines: {node: ^10.0.0 || ^12.0.0 || >= 14.0.0} + peerDependencies: + eslint: '>=5' + dependencies: + eslint: 8.5.0 + eslint-visitor-keys: 2.1.0 + dev: true + + /eslint-visitor-keys/2.1.0: + resolution: {integrity: sha512-0rSmRBzXgDzIsD6mGdJgevzgezI534Cer5L/vyMX0kHzT/jiB43jRhd9YUlMGYLQy2zprNmoT8qasCGtY+QaKw==} + engines: {node: '>=10'} + dev: true + + /eslint-visitor-keys/3.1.0: + resolution: {integrity: sha512-yWJFpu4DtjsWKkt5GeNBBuZMlNcYVs6vRCLoCVEJrTjaSB6LC98gFipNK/erM2Heg/E8mIK+hXG/pJMLK+eRZA==} + engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0} + dev: true + + /eslint/8.5.0: + resolution: {integrity: sha512-tVGSkgNbOfiHyVte8bCM8OmX+xG9PzVG/B4UCF60zx7j61WIVY/AqJECDgpLD4DbbESD0e174gOg3ZlrX15GDg==} + engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0} + hasBin: true + dependencies: + '@eslint/eslintrc': 1.0.5 + '@humanwhocodes/config-array': 0.9.2 + ajv: 6.12.6 + chalk: 4.1.2 + cross-spawn: 7.0.3 + debug: 4.3.3 + doctrine: 3.0.0 + enquirer: 2.3.6 + escape-string-regexp: 4.0.0 + eslint-scope: 7.1.0 + eslint-utils: 3.0.0_eslint@8.5.0 + eslint-visitor-keys: 3.1.0 + espree: 9.2.0 + esquery: 1.4.0 + esutils: 2.0.3 + fast-deep-equal: 3.1.3 + file-entry-cache: 6.0.1 + functional-red-black-tree: 1.0.1 + glob-parent: 6.0.2 + globals: 13.12.0 + ignore: 4.0.6 + import-fresh: 3.3.0 + imurmurhash: 0.1.4 + is-glob: 4.0.3 + js-yaml: 4.1.0 + json-stable-stringify-without-jsonify: 1.0.1 + levn: 0.4.1 + lodash.merge: 4.6.2 + minimatch: 3.0.4 + natural-compare: 1.4.0 + optionator: 0.9.1 + progress: 2.0.3 + regexpp: 3.2.0 + semver: 7.3.5 + strip-ansi: 6.0.1 + strip-json-comments: 3.1.1 + text-table: 0.2.0 + v8-compile-cache: 2.3.0 + transitivePeerDependencies: + - supports-color + dev: true + + /espree/9.2.0: + resolution: {integrity: sha512-oP3utRkynpZWF/F2x/HZJ+AGtnIclaR7z1pYPxy7NYM2fSO6LgK/Rkny8anRSPK/VwEA1eqm2squui0T7ZMOBg==} + engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0} + dependencies: + acorn: 8.6.0 + acorn-jsx: 5.3.2_acorn@8.6.0 + eslint-visitor-keys: 3.1.0 + dev: true + + /esprima/4.0.1: + resolution: {integrity: sha512-eGuFFw7Upda+g4p+QHvnW0RyTX/SVeJBDM/gCtMARO0cLuT2HcEKnTPvhjV6aGeqrCB/sbNop0Kszm0jsaWU4A==} + engines: {node: '>=4'} + hasBin: true + dev: true + + /esquery/1.4.0: + resolution: {integrity: sha512-cCDispWt5vHHtwMY2YrAQ4ibFkAL8RbH5YGBnZBc90MolvvfkkQcJro/aZiAQUlQ3qgrYS6D6v8Gc5G5CQsc9w==} + engines: {node: '>=0.10'} + dependencies: + estraverse: 5.3.0 + dev: true + + /esrecurse/4.3.0: + resolution: {integrity: sha512-KmfKL3b6G+RXvP8N1vr3Tq1kL/oCFgn2NYXEtqP8/L3pKapUA4G8cFVaoF3SU323CD4XypR/ffioHmkti6/Tag==} + engines: {node: '>=4.0'} + dependencies: + estraverse: 5.3.0 + dev: true + + /estraverse/4.3.0: + resolution: {integrity: sha512-39nnKffWz8xN1BU/2c79n9nB9HDzo0niYUqx6xyqUnyoAnQyyWpOTdZEeiCch8BBu515t4wp9ZmgVfVhn9EBpw==} + engines: {node: '>=4.0'} + dev: true + + /estraverse/5.3.0: + resolution: {integrity: sha512-MMdARuVEQziNTeJD8DgMqmhwR11BRQ/cBP+pLtYdSTnf3MIO8fFeiINEbX36ZdNlfU/7A9f3gUw49B3oQsvwBA==} + engines: {node: '>=4.0'} + dev: true + + /esutils/2.0.3: + resolution: {integrity: sha512-kVscqXk4OCp68SZ0dkgEKVi6/8ij300KBWTJq32P/dYeWTSwK41WyTxalN1eRmA5Z9UU/LX9D7FWSmV9SAYx6g==} + engines: {node: '>=0.10.0'} + dev: true + + /etag/1.8.1: + resolution: {integrity: sha1-Qa4u62XvpiJorr/qg6x9eSmbCIc=} + engines: {node: '>= 0.6'} + dev: true + + /execa/5.1.1: + resolution: {integrity: sha512-8uSpZZocAZRBAPIEINJj3Lo9HyGitllczc27Eh5YYojjMFMn8yHMDMaUHE2Jqfq05D/wucwI4JGURyXt1vchyg==} + engines: {node: '>=10'} + dependencies: + cross-spawn: 7.0.3 + get-stream: 6.0.1 + human-signals: 2.1.0 + is-stream: 2.0.1 + merge-stream: 2.0.0 + npm-run-path: 4.0.1 + onetime: 5.1.2 + signal-exit: 3.0.6 + strip-final-newline: 2.0.0 + dev: true + + /exit/0.1.2: + resolution: {integrity: sha1-BjJjj42HfMghB9MKD/8aF8uhzQw=} + engines: {node: '>= 0.8.0'} + dev: true + + /expect/27.4.2: + resolution: {integrity: sha512-BjAXIDC6ZOW+WBFNg96J22D27Nq5ohn+oGcuP2rtOtcjuxNoV9McpQ60PcQWhdFOSBIQdR72e+4HdnbZTFSTyg==} + engines: {node: ^10.13.0 || ^12.13.0 || ^14.15.0 || >=15.0.0} + dependencies: + '@jest/types': 27.4.2 + ansi-styles: 5.2.0 + jest-get-type: 27.4.0 + jest-matcher-utils: 27.4.2 + jest-message-util: 27.4.2 + jest-regex-util: 27.4.0 + dev: true + + /express/4.17.2: + resolution: {integrity: sha512-oxlxJxcQlYwqPWKVJJtvQiwHgosH/LrLSPA+H4UxpyvSS6jC5aH+5MoHFM+KABgTOt0APue4w66Ha8jCUo9QGg==} + engines: {node: '>= 0.10.0'} + dependencies: + accepts: 1.3.7 + array-flatten: 1.1.1 + body-parser: 1.19.1 + content-disposition: 0.5.4 + content-type: 1.0.4 + cookie: 0.4.1 + cookie-signature: 1.0.6 + debug: 2.6.9 + depd: 1.1.2 + encodeurl: 1.0.2 + escape-html: 1.0.3 + etag: 1.8.1 + finalhandler: 1.1.2 + fresh: 0.5.2 + merge-descriptors: 1.0.1 + methods: 1.1.2 + on-finished: 2.3.0 + parseurl: 1.3.3 + path-to-regexp: 0.1.7 + proxy-addr: 2.0.7 + qs: 6.9.6 + range-parser: 1.2.1 + safe-buffer: 5.2.1 + send: 0.17.2 + serve-static: 1.14.2 + setprototypeof: 1.2.0 + statuses: 1.5.0 + type-is: 1.6.18 + utils-merge: 1.0.1 + vary: 1.1.2 + dev: true + + /fast-deep-equal/3.1.3: + resolution: {integrity: sha512-f3qQ9oQy9j2AhBe/H9VC91wLmKBCCU/gDOnKNAYG5hswO7BLKj09Hc5HYNz9cGI++xlpDCIgDaitVs03ATR84Q==} + dev: true + + /fast-diff/1.2.0: + resolution: {integrity: sha512-xJuoT5+L99XlZ8twedaRf6Ax2TgQVxvgZOYoPKqZufmJib0tL2tegPBOZb1pVNgIhlqDlA0eO0c3wBvQcmzx4w==} + dev: true + + /fast-glob/3.2.7: + resolution: {integrity: sha512-rYGMRwip6lUMvYD3BTScMwT1HtAs2d71SMv66Vrxs0IekGZEjhM0pcMfjQPnknBt2zeCwQMEupiN02ZP4DiT1Q==} + engines: {node: '>=8'} + dependencies: + '@nodelib/fs.stat': 2.0.5 + '@nodelib/fs.walk': 1.2.8 + glob-parent: 5.1.2 + merge2: 1.4.1 + micromatch: 4.0.4 + dev: true + + /fast-json-stable-stringify/2.1.0: + resolution: {integrity: sha512-lhd/wF+Lk98HZoTCtlVraHtfh5XYijIjalXck7saUtuanSDyLMxnHhSXEDJqHxD7msR8D0uCmqlkwjCV8xvwHw==} + dev: true + + /fast-levenshtein/2.0.6: + resolution: {integrity: sha1-PYpcZog6FqMMqGQ+hR8Zuqd5eRc=} + dev: true + + /fastq/1.13.0: + resolution: {integrity: sha512-YpkpUnK8od0o1hmeSc7UUs/eB/vIPWJYjKck2QKIzAf71Vm1AAQ3EbuZB3g2JIy+pg+ERD0vqI79KyZiB2e2Nw==} + dependencies: + reusify: 1.0.4 + dev: true + + /fb-watchman/2.0.1: + resolution: {integrity: sha512-DkPJKQeY6kKwmuMretBhr7G6Vodr7bFwDYTXIkfG1gjvNpaxBTQV3PbXg6bR1c1UP4jPOX0jHUbbHANL9vRjVg==} + dependencies: + bser: 2.1.1 + dev: true + + /file-entry-cache/6.0.1: + resolution: {integrity: sha512-7Gps/XWymbLk2QLYK4NzpMOrYjMhdIxXuIvy2QBsLE6ljuodKvdkWs/cpyJJ3CVIVpH0Oi1Hvg1ovbMzLdFBBg==} + engines: {node: ^10.12.0 || >=12.0.0} + dependencies: + flat-cache: 3.0.4 + dev: true + + /fill-range/7.0.1: + resolution: {integrity: sha512-qOo9F+dMUmC2Lcb4BbVvnKJxTPjCm+RRpe4gDuGrzkL7mEVl/djYSu2OdQ2Pa302N4oqkSg9ir6jaLWJ2USVpQ==} + engines: {node: '>=8'} + dependencies: + to-regex-range: 5.0.1 + dev: true + + /finalhandler/1.1.2: + resolution: {integrity: sha512-aAWcW57uxVNrQZqFXjITpW3sIUQmHGG3qSb9mUah9MgMC4NeWhNOlNjXEYq3HjRAvL6arUviZGGJsBg6z0zsWA==} + engines: {node: '>= 0.8'} + dependencies: + debug: 2.6.9 + encodeurl: 1.0.2 + escape-html: 1.0.3 + on-finished: 2.3.0 + parseurl: 1.3.3 + statuses: 1.5.0 + unpipe: 1.0.0 + dev: true + + /find-up/4.1.0: + resolution: {integrity: sha512-PpOwAdQ/YlXQ2vj8a3h8IipDuYRi3wceVQQGYWxNINccq40Anw7BlsEXCMbt1Zt+OLA6Fq9suIpIWD0OsnISlw==} + engines: {node: '>=8'} + dependencies: + locate-path: 5.0.0 + path-exists: 4.0.0 + dev: true + + /find-up/5.0.0: + resolution: {integrity: sha512-78/PXT1wlLLDgTzDs7sjq9hzz0vXD+zn+7wypEe4fXQxCmdmqfGsEPQxmiCSQI3ajFV91bVSsvNtrJRiW6nGng==} + engines: {node: '>=10'} + dependencies: + locate-path: 6.0.0 + path-exists: 4.0.0 + dev: true + + /flat-cache/3.0.4: + resolution: {integrity: sha512-dm9s5Pw7Jc0GvMYbshN6zchCA9RgQlzzEZX3vylR9IqFfS8XciblUXOKfW6SiuJ0e13eDYZoZV5wdrev7P3Nwg==} + engines: {node: ^10.12.0 || >=12.0.0} + dependencies: + flatted: 3.2.4 + rimraf: 3.0.2 + dev: true + + /flatted/3.2.4: + resolution: {integrity: sha512-8/sOawo8tJ4QOBX8YlQBMxL8+RLZfxMQOif9o0KUKTNTjMYElWPE0r/m5VNFxTRd0NSw8qSy8dajrwX4RYI1Hw==} + dev: true + + /follow-redirects/1.14.6: + resolution: {integrity: sha512-fhUl5EwSJbbl8AR+uYL2KQDxLkdSjZGR36xy46AO7cOMTrCMON6Sa28FmAnC2tRTDbd/Uuzz3aJBv7EBN7JH8A==} + engines: {node: '>=4.0'} + peerDependencies: + debug: '*' + peerDependenciesMeta: + debug: + optional: true + dev: false + + /form-data/3.0.1: + resolution: {integrity: sha512-RHkBKtLWUVwd7SqRIvCZMEvAMoGUp0XU+seQiZejj0COz3RI3hWP4sCv3gZWWLjJTd7rGwcsF5eKZGii0r/hbg==} + engines: {node: '>= 6'} + dependencies: + asynckit: 0.4.0 + combined-stream: 1.0.8 + mime-types: 2.1.34 + dev: true + + /form-data/4.0.0: + resolution: {integrity: sha512-ETEklSGi5t0QMZuiXoA/Q6vcnxcLQP5vdugSpuAyi6SVGi2clPPp+xgEhuMaHC+zGgn31Kd235W35f7Hykkaww==} + engines: {node: '>= 6'} + dependencies: + asynckit: 0.4.0 + combined-stream: 1.0.8 + mime-types: 2.1.34 + dev: false + + /forwarded/0.2.0: + resolution: {integrity: sha512-buRG0fpBtRHSTCOASe6hD258tEubFoRLb4ZNA6NxMVHNw2gOcwHo9wyablzMzOA5z9xA9L1KNjk/Nt6MT9aYow==} + engines: {node: '>= 0.6'} + dev: true + + /fresh/0.5.2: + resolution: {integrity: sha1-PYyt2Q2XZWn6g1qx+OSyOhBWBac=} + engines: {node: '>= 0.6'} + dev: true + + /fs-extra/10.0.0: + resolution: {integrity: sha512-C5owb14u9eJwizKGdchcDUQeFtlSHHthBk8pbX9Vc1PFZrLombudjDnNns88aYslCyF6IY5SUw3Roz6xShcEIQ==} + engines: {node: '>=12'} + dependencies: + graceful-fs: 4.2.8 + jsonfile: 6.1.0 + universalify: 2.0.0 + dev: true + + /fs.realpath/1.0.0: + resolution: {integrity: sha1-FQStJSMVjKpA20onh8sBQRmU6k8=} + dev: true + + /fsevents/2.3.2: + resolution: {integrity: sha512-xiqMQR4xAeHTuB9uWm+fFRcIOgKBMiOBP+eXiyT7jsgVCq1bkVygt00oASowB7EdtpOHaaPgKt812P9ab+DDKA==} + engines: {node: ^8.16.0 || ^10.6.0 || >=11.0.0} + os: [darwin] + requiresBuild: true + dev: true + optional: true + + /function-bind/1.1.1: + resolution: {integrity: sha512-yIovAzMX49sF8Yl58fSCWJ5svSLuaibPxXQJFLmBObTuCr0Mf1KiPopGM9NiFjiYBCbfaa2Fh6breQ6ANVTI0A==} + + /functional-red-black-tree/1.0.1: + resolution: {integrity: sha1-GwqzvVU7Kg1jmdKcDj6gslIHgyc=} + dev: true + + /gensync/1.0.0-beta.2: + resolution: {integrity: sha512-3hN7NaskYvMDLQY55gnW3NQ+mesEAepTqlg+VEbj7zzqEMBVNhzcGYYeqFo/TlYz6eQiFcp1HcsCZO+nGgS8zg==} + engines: {node: '>=6.9.0'} + dev: true + + /get-caller-file/2.0.5: + resolution: {integrity: sha512-DyFP3BM/3YHTQOCUL/w0OZHR0lpKeGrxotcHWcqNEdnltqFwXVfhEBQ94eIo34AfQpo0rGki4cyIiftY06h2Fg==} + engines: {node: 6.* || 8.* || >= 10.*} + dev: true + + /get-intrinsic/1.1.1: + resolution: {integrity: sha512-kWZrnVM42QCiEA2Ig1bG8zjoIMOgxWwYCEeNdwY6Tv/cOSeGpcoX4pXHfKUxNKVoArnrEr2e9srnAxxGIraS9Q==} + dependencies: + function-bind: 1.1.1 + has: 1.0.3 + has-symbols: 1.0.2 + dev: false + + /get-package-type/0.1.0: + resolution: {integrity: sha512-pjzuKtY64GYfWizNAJ0fr9VqttZkNiK2iS430LtIHzjBEr6bX8Am2zm4sW4Ro5wjWW5cAlRL1qAMTcXbjNAO2Q==} + engines: {node: '>=8.0.0'} + dev: true + + /get-stream/6.0.1: + resolution: {integrity: sha512-ts6Wi+2j3jQjqi70w5AlN8DFnkSwC+MqmxEzdEALB2qXZYV3X/b1CTfgPLGJNMeAWxdPfU8FO1ms3NUfaHCPYg==} + engines: {node: '>=10'} + dev: true + + /git-raw-commits/2.0.10: + resolution: {integrity: sha512-sHhX5lsbG9SOO6yXdlwgEMQ/ljIn7qMpAbJZCGfXX2fq5T8M5SrDnpYk9/4HswTildcIqatsWa91vty6VhWSaQ==} + engines: {node: '>=10'} + hasBin: true + dependencies: + dargs: 7.0.0 + lodash: 4.17.21 + meow: 8.1.2 + split2: 3.2.2 + through2: 4.0.2 + dev: true + + /glob-parent/5.1.2: + resolution: {integrity: sha512-AOIgSQCepiJYwP3ARnGx+5VnTu2HBYdzbGP45eLw1vr3zB3vZLeyed1sC9hnbcOc9/SrMyM5RPQrkGz4aS9Zow==} + engines: {node: '>= 6'} + dependencies: + is-glob: 4.0.3 + dev: true + + /glob-parent/6.0.2: + resolution: {integrity: sha512-XxwI8EOhVQgWp6iDL+3b0r86f4d6AX6zSU55HfB4ydCEuXLXc5FcYeOu+nnGftS4TEju/11rt4KJPTMgbfmv4A==} + engines: {node: '>=10.13.0'} + dependencies: + is-glob: 4.0.3 + dev: true + + /glob/7.2.0: + resolution: {integrity: sha512-lmLf6gtyrPq8tTjSmrO94wBeQbFR3HbLHbuyD69wuyQkImp2hWqMGB47OX65FBkPffO641IP9jWa1z4ivqG26Q==} + dependencies: + fs.realpath: 1.0.0 + inflight: 1.0.6 + inherits: 2.0.4 + minimatch: 3.0.4 + once: 1.4.0 + path-is-absolute: 1.0.1 + dev: true + + /global-dirs/0.1.1: + resolution: {integrity: sha1-sxnA3UYH81PzvpzKTHL8FIxJ9EU=} + engines: {node: '>=4'} + dependencies: + ini: 1.3.8 + dev: true + + /globals/11.12.0: + resolution: {integrity: sha512-WOBp/EEGUiIsJSp7wcv/y6MO+lV9UoncWqxuFfm8eBwzWNgyfBd6Gz+IeKQ9jCmyhoH99g15M3T+QaVHFjizVA==} + engines: {node: '>=4'} + dev: true + + /globals/13.12.0: + resolution: {integrity: sha512-uS8X6lSKN2JumVoXrbUz+uG4BYG+eiawqm3qFcT7ammfbUHeCBoJMlHcec/S3krSk73/AE/f0szYFmgAA3kYZg==} + engines: {node: '>=8'} + dependencies: + type-fest: 0.20.2 + dev: true + + /globby/11.0.4: + resolution: {integrity: sha512-9O4MVG9ioZJ08ffbcyVYyLOJLk5JQ688pJ4eMGLpdWLHq/Wr1D9BlriLQyL0E+jbkuePVZXYFj47QM/v093wHg==} + engines: {node: '>=10'} + dependencies: + array-union: 2.1.0 + dir-glob: 3.0.1 + fast-glob: 3.2.7 + ignore: 5.2.0 + merge2: 1.4.1 + slash: 3.0.0 + dev: true + + /graceful-fs/4.2.8: + resolution: {integrity: sha512-qkIilPUYcNhJpd33n0GBXTB1MMPp14TxEsEs0pTrsSVucApsYzW5V+Q8Qxhik6KU3evy+qkAAowTByymK0avdg==} + dev: true + + /hard-rejection/2.1.0: + resolution: {integrity: sha512-VIZB+ibDhx7ObhAe7OVtoEbuP4h/MuOTHJ+J8h/eBXotJYl0fBgR72xDFCKgIh22OJZIOVNxBMWuhAr10r8HdA==} + engines: {node: '>=6'} + dev: true + + /has-flag/3.0.0: + resolution: {integrity: sha1-tdRU3CGZriJWmfNGfloH87lVuv0=} + engines: {node: '>=4'} + dev: true + + /has-flag/4.0.0: + resolution: {integrity: sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==} + engines: {node: '>=8'} + dev: true + + /has-symbols/1.0.2: + resolution: {integrity: sha512-chXa79rL/UC2KlX17jo3vRGz0azaWEx5tGqZg5pO3NUyEJVB17dMruQlzCCOfUvElghKcm5194+BCRvi2Rv/Gw==} + engines: {node: '>= 0.4'} + dev: false + + /has/1.0.3: + resolution: {integrity: sha512-f2dvO0VU6Oej7RkWJGrehjbzMAjFp5/VKPp5tTpWIV4JHHZK1/BxbFRtf/siA2SWTe09caDmVtYYzWEIbBS4zw==} + engines: {node: '>= 0.4.0'} + dependencies: + function-bind: 1.1.1 + + /hosted-git-info/2.8.9: + resolution: {integrity: sha512-mxIDAb9Lsm6DoOJ7xH+5+X4y1LU/4Hi50L9C5sIswK3JzULS4bwk1FvjdBgvYR4bzT4tuUQiC15FE2f5HbLvYw==} + dev: true + + /hosted-git-info/4.0.2: + resolution: {integrity: sha512-c9OGXbZ3guC/xOlCg1Ci/VgWlwsqDv1yMQL1CWqXDL0hDjXuNcq0zuR4xqPSuasI3kqFDhqSyTjREz5gzq0fXg==} + engines: {node: '>=10'} + dependencies: + lru-cache: 6.0.0 + dev: true + + /html-encoding-sniffer/2.0.1: + resolution: {integrity: sha512-D5JbOMBIR/TVZkubHT+OyT2705QvogUW4IBn6nHd756OwieSF9aDYFj4dv6HHEVGYbHaLETa3WggZYWWMyy3ZQ==} + engines: {node: '>=10'} + dependencies: + whatwg-encoding: 1.0.5 + dev: true + + /html-escaper/2.0.2: + resolution: {integrity: sha512-H2iMtd0I4Mt5eYiapRdIDjp+XzelXQ0tFE4JS7YFwFevXXMmOp9myNrUvCg0D6ws8iqkRPBfKHgbwig1SmlLfg==} + dev: true + + /http-errors/1.8.1: + resolution: {integrity: sha512-Kpk9Sm7NmI+RHhnj6OIWDI1d6fIoFAtFt9RLaTMRlg/8w49juAStsrBgp0Dp4OdxdVbRIeKhtCUvoi/RuAhO4g==} + engines: {node: '>= 0.6'} + dependencies: + depd: 1.1.2 + inherits: 2.0.4 + setprototypeof: 1.2.0 + statuses: 1.5.0 + toidentifier: 1.0.1 + dev: true + + /http-proxy-agent/4.0.1: + resolution: {integrity: sha512-k0zdNgqWTGA6aeIRVpvfVob4fL52dTfaehylg0Y4UvSySvOq/Y+BOyPrgpUrA7HylqvU8vIZGsRuXmspskV0Tg==} + engines: {node: '>= 6'} + dependencies: + '@tootallnate/once': 1.1.2 + agent-base: 6.0.2 + debug: 4.3.3 + transitivePeerDependencies: + - supports-color + dev: true + + /https-proxy-agent/5.0.0: + resolution: {integrity: sha512-EkYm5BcKUGiduxzSt3Eppko+PiNWNEpa4ySk9vTC6wDsQJW9rHSa+UhGNJoRYp7bz6Ht1eaRIa6QaJqO5rCFbA==} + engines: {node: '>= 6'} + dependencies: + agent-base: 6.0.2 + debug: 4.3.3 + transitivePeerDependencies: + - supports-color + dev: true + + /human-signals/2.1.0: + resolution: {integrity: sha512-B4FFZ6q/T2jhhksgkbEW3HBvWIfDW85snkQgawt07S7J5QXTk6BkNV+0yAeZrM5QpMAdYlocGoljn0sJ/WQkFw==} + engines: {node: '>=10.17.0'} + dev: true + + /husky/7.0.4: + resolution: {integrity: sha512-vbaCKN2QLtP/vD4yvs6iz6hBEo6wkSzs8HpRah1Z6aGmF2KW5PdYuAd7uX5a+OyBZHBhd+TFLqgjUgytQr4RvQ==} + engines: {node: '>=12'} + hasBin: true + dev: true + + /iconv-lite/0.4.24: + resolution: {integrity: sha512-v3MXnZAcvnywkTUEZomIActle7RXXeedOR31wwl7VlyoXO4Qi9arvSenNQWne1TcRwhCL1HwLI21bEqdpj8/rA==} + engines: {node: '>=0.10.0'} + dependencies: + safer-buffer: 2.1.2 + dev: true + + /ignore/4.0.6: + resolution: {integrity: sha512-cyFDKrqc/YdcWFniJhzI42+AzS+gNwmUzOSFcRCQYwySuBBBy/KjuxWLZ/FHEH6Moq1NizMOBWyTcv8O4OZIMg==} + engines: {node: '>= 4'} + dev: true + + /ignore/5.2.0: + resolution: {integrity: sha512-CmxgYGiEPCLhfLnpPp1MoRmifwEIOgjcHXxOBjv7mY96c+eWScsOP9c112ZyLdWHi0FxHjI+4uVhKYp/gcdRmQ==} + engines: {node: '>= 4'} + dev: true + + /import-fresh/3.3.0: + resolution: {integrity: sha512-veYYhQa+D1QBKznvhUHxb8faxlrwUnxseDAbAp457E0wLNio2bOSKnjYDhMj+YiAq61xrMGhQk9iXVk5FzgQMw==} + engines: {node: '>=6'} + dependencies: + parent-module: 1.0.1 + resolve-from: 4.0.0 + dev: true + + /import-local/3.0.3: + resolution: {integrity: sha512-bE9iaUY3CXH8Cwfan/abDKAxe1KGT9kyGsBPqf6DMK/z0a2OzAsrukeYNgIH6cH5Xr452jb1TUL8rSfCLjZ9uA==} + engines: {node: '>=8'} + hasBin: true + dependencies: + pkg-dir: 4.2.0 + resolve-cwd: 3.0.0 + dev: true + + /imurmurhash/0.1.4: + resolution: {integrity: sha1-khi5srkoojixPcT7a21XbyMUU+o=} + engines: {node: '>=0.8.19'} + dev: true + + /indent-string/4.0.0: + resolution: {integrity: sha512-EdDDZu4A2OyIK7Lr/2zG+w5jmbuk1DVBnEwREQvBzspBJkCEbRa8GxU1lghYcaGJCnRWibjDXlq779X1/y5xwg==} + engines: {node: '>=8'} + dev: true + + /inflight/1.0.6: + resolution: {integrity: sha1-Sb1jMdfQLQwJvJEKEHW6gWW1bfk=} + dependencies: + once: 1.4.0 + wrappy: 1.0.2 + dev: true + + /inherits/2.0.4: + resolution: {integrity: sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==} + dev: true + + /ini/1.3.8: + resolution: {integrity: sha512-JV/yugV2uzW5iMRSiZAyDtQd+nxtUnjeLt0acNdw98kKLrvuRVyB80tsREOE7yvGVgalhZ6RNXCmEHkUKBKxew==} + dev: true + + /ipaddr.js/1.9.1: + resolution: {integrity: sha512-0KI/607xoxSToH7GjN1FfSbLoU0+btTicjsQSWQlh/hZykN8KpmMf7uYwPW3R+akZ6R/w18ZlXSHBYXiYUPO3g==} + engines: {node: '>= 0.10'} + dev: true + + /is-arrayish/0.2.1: + resolution: {integrity: sha1-d8mYQFJ6qOyxqLppe4BkWnqSap0=} + dev: true + + /is-core-module/2.8.0: + resolution: {integrity: sha512-vd15qHsaqrRL7dtH6QNuy0ndJmRDrS9HAM1CAiSifNUFv4x1a0CCVsj18hJ1mShxIG6T2i1sO78MkP56r0nYRw==} + dependencies: + has: 1.0.3 + dev: true + + /is-extglob/2.1.1: + resolution: {integrity: sha1-qIwCU1eR8C7TfHahueqXc8gz+MI=} + engines: {node: '>=0.10.0'} + dev: true + + /is-fullwidth-code-point/3.0.0: + resolution: {integrity: sha512-zymm5+u+sCsSWyD9qNaejV3DFvhCKclKdizYaJUuHA83RLjb7nSuGnddCHGv0hk+KY7BMAlsWeK4Ueg6EV6XQg==} + engines: {node: '>=8'} + dev: true + + /is-generator-fn/2.1.0: + resolution: {integrity: sha512-cTIB4yPYL/Grw0EaSzASzg6bBy9gqCofvWN8okThAYIxKJZC+udlRAmGbM0XLeniEJSs8uEgHPGuHSe1XsOLSQ==} + engines: {node: '>=6'} + dev: true + + /is-glob/4.0.3: + resolution: {integrity: sha512-xelSayHH36ZgE7ZWhli7pW34hNbNl8Ojv5KVmkJD4hBdD3th8Tfk9vYasLM+mXWOZhFkgZfxhLSnrwRr4elSSg==} + engines: {node: '>=0.10.0'} + dependencies: + is-extglob: 2.1.1 + dev: true + + /is-number/7.0.0: + resolution: {integrity: sha512-41Cifkg6e8TylSpdtTpeLVMqvSBEVzTttHvERD741+pnZ8ANv0004MRL43QKPDlK9cGvNp6NZWZUBlbGXYxxng==} + engines: {node: '>=0.12.0'} + dev: true + + /is-obj/2.0.0: + resolution: {integrity: sha512-drqDG3cbczxxEJRoOXcOjtdp1J/lyp1mNn0xaznRs8+muBhgQcrnbspox5X5fOw0HnMnbfDzvnEMEtqDEJEo8w==} + engines: {node: '>=8'} + dev: true + + /is-plain-obj/1.1.0: + resolution: {integrity: sha1-caUMhCnfync8kqOQpKA7OfzVHT4=} + engines: {node: '>=0.10.0'} + dev: true + + /is-potential-custom-element-name/1.0.1: + resolution: {integrity: sha512-bCYeRA2rVibKZd+s2625gGnGF/t7DSqDs4dP7CrLA1m7jKWz6pps0LpYLJN8Q64HtmPKJ1hrN3nzPNKFEKOUiQ==} + dev: true + + /is-stream/2.0.1: + resolution: {integrity: sha512-hFoiJiTl63nn+kstHGBtewWSKnQLpyb155KHheA1l39uvtO9nWIop1p3udqPcUd/xbF1VLMO4n7OI6p7RbngDg==} + engines: {node: '>=8'} + dev: true + + /is-text-path/1.0.1: + resolution: {integrity: sha1-Thqg+1G/vLPpJogAE5cgLBd1tm4=} + engines: {node: '>=0.10.0'} + dependencies: + text-extensions: 1.9.0 + dev: true + + /is-typedarray/1.0.0: + resolution: {integrity: sha1-5HnICFjfDBsR3dppQPlgEfzaSpo=} + dev: true + + /isarray/0.0.1: + resolution: {integrity: sha1-ihis/Kmo9Bd+Cav8YDiTmwXR7t8=} + dev: true + + /isarray/1.0.0: + resolution: {integrity: sha1-u5NdSFgsuhaMBoNJV6VKPgcSTxE=} + dev: true + + /isexe/2.0.0: + resolution: {integrity: sha1-6PvzdNxVb/iUehDcsFctYz8s+hA=} + dev: true + + /istanbul-badges-readme/1.8.1: + resolution: {integrity: sha512-I7cEFAFlWc5VB17a71U0TgQbez5+U78F0f4kky1w33L4t3BC4/8gbN1tbmX4LVaki52Op4LrkttpvcdZ6kd/jg==} + hasBin: true + dev: true + + /istanbul-lib-coverage/3.2.0: + resolution: {integrity: sha512-eOeJ5BHCmHYvQK7xt9GkdHuzuCGS1Y6g9Gvnx3Ym33fz/HpLRYxiS0wHNr+m/MBC8B647Xt608vCDEvhl9c6Mw==} + engines: {node: '>=8'} + dev: true + + /istanbul-lib-instrument/4.0.3: + resolution: {integrity: sha512-BXgQl9kf4WTCPCCpmFGoJkz/+uhvm7h7PFKUYxh7qarQd3ER33vHG//qaE8eN25l07YqZPpHXU9I09l/RD5aGQ==} + engines: {node: '>=8'} + dependencies: + '@babel/core': 7.16.5 + '@istanbuljs/schema': 0.1.3 + istanbul-lib-coverage: 3.2.0 + semver: 6.3.0 + transitivePeerDependencies: + - supports-color + dev: true + + /istanbul-lib-instrument/5.1.0: + resolution: {integrity: sha512-czwUz525rkOFDJxfKK6mYfIs9zBKILyrZQxjz3ABhjQXhbhFsSbo1HW/BFcsDnfJYJWA6thRR5/TUY2qs5W99Q==} + engines: {node: '>=8'} + dependencies: + '@babel/core': 7.16.5 + '@babel/parser': 7.16.6 + '@istanbuljs/schema': 0.1.3 + istanbul-lib-coverage: 3.2.0 + semver: 6.3.0 + transitivePeerDependencies: + - supports-color + dev: true + + /istanbul-lib-report/3.0.0: + resolution: {integrity: sha512-wcdi+uAKzfiGT2abPpKZ0hSU1rGQjUQnLvtY5MpQ7QCTahD3VODhcu4wcfY1YtkGaDD5yuydOLINXsfbus9ROw==} + engines: {node: '>=8'} + dependencies: + istanbul-lib-coverage: 3.2.0 + make-dir: 3.1.0 + supports-color: 7.2.0 + dev: true + + /istanbul-lib-source-maps/4.0.1: + resolution: {integrity: sha512-n3s8EwkdFIJCG3BPKBYvskgXGoy88ARzvegkitk60NxRdwltLOTaH7CUiMRXvwYorl0Q712iEjcWB+fK/MrWVw==} + engines: {node: '>=10'} + dependencies: + debug: 4.3.3 + istanbul-lib-coverage: 3.2.0 + source-map: 0.6.1 + transitivePeerDependencies: + - supports-color + dev: true + + /istanbul-reports/3.1.1: + resolution: {integrity: sha512-q1kvhAXWSsXfMjCdNHNPKZZv94OlspKnoGv+R9RGbnqOOQ0VbNfLFgQDVgi7hHenKsndGq3/o0OBdzDXthWcNw==} + engines: {node: '>=8'} + dependencies: + html-escaper: 2.0.2 + istanbul-lib-report: 3.0.0 + dev: true + + /jest-changed-files/27.4.2: + resolution: {integrity: sha512-/9x8MjekuzUQoPjDHbBiXbNEBauhrPU2ct7m8TfCg69ywt1y/N+yYwGh3gCpnqUS3klYWDU/lSNgv+JhoD2k1A==} + engines: {node: ^10.13.0 || ^12.13.0 || ^14.15.0 || >=15.0.0} + dependencies: + '@jest/types': 27.4.2 + execa: 5.1.1 + throat: 6.0.1 + dev: true + + /jest-circus/27.4.5: + resolution: {integrity: sha512-eTNWa9wsvBwPykhMMShheafbwyakcdHZaEYh5iRrQ0PFJxkDP/e3U/FvzGuKWu2WpwUA3C3hPlfpuzvOdTVqnw==} + engines: {node: ^10.13.0 || ^12.13.0 || ^14.15.0 || >=15.0.0} + dependencies: + '@jest/environment': 27.4.4 + '@jest/test-result': 27.4.2 + '@jest/types': 27.4.2 + '@types/node': 17.0.0 + chalk: 4.1.2 + co: 4.6.0 + dedent: 0.7.0 + expect: 27.4.2 + is-generator-fn: 2.1.0 + jest-each: 27.4.2 + jest-matcher-utils: 27.4.2 + jest-message-util: 27.4.2 + jest-runtime: 27.4.5 + jest-snapshot: 27.4.5 + jest-util: 27.4.2 + pretty-format: 27.4.2 + slash: 3.0.0 + stack-utils: 2.0.5 + throat: 6.0.1 + transitivePeerDependencies: + - supports-color + dev: true + + /jest-cli/27.4.5: + resolution: {integrity: sha512-hrky3DSgE0u7sQxaCL7bdebEPHx5QzYmrGuUjaPLmPE8jx5adtvGuOlRspvMoVLTTDOHRnZDoRLYJuA+VCI7Hg==} + engines: {node: ^10.13.0 || ^12.13.0 || ^14.15.0 || >=15.0.0} + hasBin: true + peerDependencies: + node-notifier: ^8.0.1 || ^9.0.0 || ^10.0.0 + peerDependenciesMeta: + node-notifier: + optional: true + dependencies: + '@jest/core': 27.4.5 + '@jest/test-result': 27.4.2 + '@jest/types': 27.4.2 + chalk: 4.1.2 + exit: 0.1.2 + graceful-fs: 4.2.8 + import-local: 3.0.3 + jest-config: 27.4.5 + jest-util: 27.4.2 + jest-validate: 27.4.2 + prompts: 2.4.2 + yargs: 16.2.0 + transitivePeerDependencies: + - bufferutil + - canvas + - supports-color + - ts-node + - utf-8-validate + dev: true + + /jest-config/27.4.5: + resolution: {integrity: sha512-t+STVJtPt+fpqQ8GBw850NtSQbnDOw/UzdPfzDaHQ48/AylQlW7LHj3dH+ndxhC1UxJ0Q3qkq7IH+nM1skwTwA==} + engines: {node: ^10.13.0 || ^12.13.0 || ^14.15.0 || >=15.0.0} + peerDependencies: + ts-node: '>=9.0.0' + peerDependenciesMeta: + ts-node: + optional: true + dependencies: + '@babel/core': 7.16.5 + '@jest/test-sequencer': 27.4.5 + '@jest/types': 27.4.2 + babel-jest: 27.4.5_@babel+core@7.16.5 + chalk: 4.1.2 + ci-info: 3.3.0 + deepmerge: 4.2.2 + glob: 7.2.0 + graceful-fs: 4.2.8 + jest-circus: 27.4.5 + jest-environment-jsdom: 27.4.4 + jest-environment-node: 27.4.4 + jest-get-type: 27.4.0 + jest-jasmine2: 27.4.5 + jest-regex-util: 27.4.0 + jest-resolve: 27.4.5 + jest-runner: 27.4.5 + jest-util: 27.4.2 + jest-validate: 27.4.2 + micromatch: 4.0.4 + pretty-format: 27.4.2 + slash: 3.0.0 + transitivePeerDependencies: + - bufferutil + - canvas + - supports-color + - utf-8-validate + dev: true + + /jest-diff/27.4.2: + resolution: {integrity: sha512-ujc9ToyUZDh9KcqvQDkk/gkbf6zSaeEg9AiBxtttXW59H/AcqEYp1ciXAtJp+jXWva5nAf/ePtSsgWwE5mqp4Q==} + engines: {node: ^10.13.0 || ^12.13.0 || ^14.15.0 || >=15.0.0} + dependencies: + chalk: 4.1.2 + diff-sequences: 27.4.0 + jest-get-type: 27.4.0 + pretty-format: 27.4.2 + dev: true + + /jest-docblock/27.4.0: + resolution: {integrity: sha512-7TBazUdCKGV7svZ+gh7C8esAnweJoG+SvcF6Cjqj4l17zA2q1cMwx2JObSioubk317H+cjcHgP+7fTs60paulg==} + engines: {node: ^10.13.0 || ^12.13.0 || ^14.15.0 || >=15.0.0} + dependencies: + detect-newline: 3.1.0 + dev: true + + /jest-each/27.4.2: + resolution: {integrity: sha512-53V2MNyW28CTruB3lXaHNk6PkiIFuzdOC9gR3C6j8YE/ACfrPnz+slB0s17AgU1TtxNzLuHyvNlLJ+8QYw9nBg==} + engines: {node: ^10.13.0 || ^12.13.0 || ^14.15.0 || >=15.0.0} + dependencies: + '@jest/types': 27.4.2 + chalk: 4.1.2 + jest-get-type: 27.4.0 + jest-util: 27.4.2 + pretty-format: 27.4.2 + dev: true + + /jest-environment-jsdom/27.4.4: + resolution: {integrity: sha512-cYR3ndNfHBqQgFvS1RL7dNqSvD//K56j/q1s2ygNHcfTCAp12zfIromO1w3COmXrxS8hWAh7+CmZmGCIoqGcGA==} + engines: {node: ^10.13.0 || ^12.13.0 || ^14.15.0 || >=15.0.0} + dependencies: + '@jest/environment': 27.4.4 + '@jest/fake-timers': 27.4.2 + '@jest/types': 27.4.2 + '@types/node': 17.0.0 + jest-mock: 27.4.2 + jest-util: 27.4.2 + jsdom: 16.7.0 + transitivePeerDependencies: + - bufferutil + - canvas + - supports-color + - utf-8-validate + dev: true + + /jest-environment-node/27.4.4: + resolution: {integrity: sha512-D+v3lbJ2GjQTQR23TK0kY3vFVmSeea05giInI41HHOaJnAwOnmUHTZgUaZL+VxUB43pIzoa7PMwWtCVlIUoVoA==} + engines: {node: ^10.13.0 || ^12.13.0 || ^14.15.0 || >=15.0.0} + dependencies: + '@jest/environment': 27.4.4 + '@jest/fake-timers': 27.4.2 + '@jest/types': 27.4.2 + '@types/node': 17.0.0 + jest-mock: 27.4.2 + jest-util: 27.4.2 + dev: true + + /jest-get-type/27.4.0: + resolution: {integrity: sha512-tk9o+ld5TWq41DkK14L4wox4s2D9MtTpKaAVzXfr5CUKm5ZK2ExcaFE0qls2W71zE/6R2TxxrK9w2r6svAFDBQ==} + engines: {node: ^10.13.0 || ^12.13.0 || ^14.15.0 || >=15.0.0} + dev: true + + /jest-haste-map/27.4.5: + resolution: {integrity: sha512-oJm1b5qhhPs78K24EDGifWS0dELYxnoBiDhatT/FThgB9yxqUm5F6li3Pv+Q+apMBmmPNzOBnZ7ZxWMB1Leq1Q==} + engines: {node: ^10.13.0 || ^12.13.0 || ^14.15.0 || >=15.0.0} + dependencies: + '@jest/types': 27.4.2 + '@types/graceful-fs': 4.1.5 + '@types/node': 17.0.0 + anymatch: 3.1.2 + fb-watchman: 2.0.1 + graceful-fs: 4.2.8 + jest-regex-util: 27.4.0 + jest-serializer: 27.4.0 + jest-util: 27.4.2 + jest-worker: 27.4.5 + micromatch: 4.0.4 + walker: 1.0.8 + optionalDependencies: + fsevents: 2.3.2 + dev: true + + /jest-jasmine2/27.4.5: + resolution: {integrity: sha512-oUnvwhJDj2LhOiUB1kdnJjkx8C5PwgUZQb9urF77mELH9DGR4e2GqpWQKBOYXWs5+uTN9BGDqRz3Aeg5Wts7aw==} + engines: {node: ^10.13.0 || ^12.13.0 || ^14.15.0 || >=15.0.0} + dependencies: + '@babel/traverse': 7.16.5 + '@jest/environment': 27.4.4 + '@jest/source-map': 27.4.0 + '@jest/test-result': 27.4.2 + '@jest/types': 27.4.2 + '@types/node': 17.0.0 + chalk: 4.1.2 + co: 4.6.0 + expect: 27.4.2 + is-generator-fn: 2.1.0 + jest-each: 27.4.2 + jest-matcher-utils: 27.4.2 + jest-message-util: 27.4.2 + jest-runtime: 27.4.5 + jest-snapshot: 27.4.5 + jest-util: 27.4.2 + pretty-format: 27.4.2 + throat: 6.0.1 + transitivePeerDependencies: + - supports-color + dev: true + + /jest-leak-detector/27.4.2: + resolution: {integrity: sha512-ml0KvFYZllzPBJWDei3mDzUhyp/M4ubKebX++fPaudpe8OsxUE+m+P6ciVLboQsrzOCWDjE20/eXew9QMx/VGw==} + engines: {node: ^10.13.0 || ^12.13.0 || ^14.15.0 || >=15.0.0} + dependencies: + jest-get-type: 27.4.0 + pretty-format: 27.4.2 + dev: true + + /jest-matcher-utils/27.4.2: + resolution: {integrity: sha512-jyP28er3RRtMv+fmYC/PKG8wvAmfGcSNproVTW2Y0P/OY7/hWUOmsPfxN1jOhM+0u2xU984u2yEagGivz9OBGQ==} + engines: {node: ^10.13.0 || ^12.13.0 || ^14.15.0 || >=15.0.0} + dependencies: + chalk: 4.1.2 + jest-diff: 27.4.2 + jest-get-type: 27.4.0 + pretty-format: 27.4.2 + dev: true + + /jest-message-util/27.4.2: + resolution: {integrity: sha512-OMRqRNd9E0DkBLZpFtZkAGYOXl6ZpoMtQJWTAREJKDOFa0M6ptB7L67tp+cszMBkvSgKOhNtQp2Vbcz3ZZKo/w==} + engines: {node: ^10.13.0 || ^12.13.0 || ^14.15.0 || >=15.0.0} + dependencies: + '@babel/code-frame': 7.16.0 + '@jest/types': 27.4.2 + '@types/stack-utils': 2.0.1 + chalk: 4.1.2 + graceful-fs: 4.2.8 + micromatch: 4.0.4 + pretty-format: 27.4.2 + slash: 3.0.0 + stack-utils: 2.0.5 + dev: true + + /jest-mock/27.4.2: + resolution: {integrity: sha512-PDDPuyhoukk20JrQKeofK12hqtSka7mWH0QQuxSNgrdiPsrnYYLS6wbzu/HDlxZRzji5ylLRULeuI/vmZZDrYA==} + engines: {node: ^10.13.0 || ^12.13.0 || ^14.15.0 || >=15.0.0} + dependencies: + '@jest/types': 27.4.2 + '@types/node': 17.0.0 + dev: true + + /jest-pnp-resolver/1.2.2_jest-resolve@27.4.5: + resolution: {integrity: sha512-olV41bKSMm8BdnuMsewT4jqlZ8+3TCARAXjZGT9jcoSnrfUnRCqnMoF9XEeoWjbzObpqF9dRhHQj0Xb9QdF6/w==} + engines: {node: '>=6'} + peerDependencies: + jest-resolve: '*' + peerDependenciesMeta: + jest-resolve: + optional: true + dependencies: + jest-resolve: 27.4.5 + dev: true + + /jest-regex-util/27.4.0: + resolution: {integrity: sha512-WeCpMpNnqJYMQoOjm1nTtsgbR4XHAk1u00qDoNBQoykM280+/TmgA5Qh5giC1ecy6a5d4hbSsHzpBtu5yvlbEg==} + engines: {node: ^10.13.0 || ^12.13.0 || ^14.15.0 || >=15.0.0} + dev: true + + /jest-resolve-dependencies/27.4.5: + resolution: {integrity: sha512-elEVvkvRK51y037NshtEkEnukMBWvlPzZHiL847OrIljJ8yIsujD2GXRPqDXC4rEVKbcdsy7W0FxoZb4WmEs7w==} + engines: {node: ^10.13.0 || ^12.13.0 || ^14.15.0 || >=15.0.0} + dependencies: + '@jest/types': 27.4.2 + jest-regex-util: 27.4.0 + jest-snapshot: 27.4.5 + transitivePeerDependencies: + - supports-color + dev: true + + /jest-resolve/27.4.5: + resolution: {integrity: sha512-xU3z1BuOz/hUhVUL+918KqUgK+skqOuUsAi7A+iwoUldK6/+PW+utK8l8cxIWT9AW7IAhGNXjSAh1UYmjULZZw==} + engines: {node: ^10.13.0 || ^12.13.0 || ^14.15.0 || >=15.0.0} + dependencies: + '@jest/types': 27.4.2 + chalk: 4.1.2 + graceful-fs: 4.2.8 + jest-haste-map: 27.4.5 + jest-pnp-resolver: 1.2.2_jest-resolve@27.4.5 + jest-util: 27.4.2 + jest-validate: 27.4.2 + resolve: 1.20.0 + resolve.exports: 1.1.0 + slash: 3.0.0 + dev: true + + /jest-runner/27.4.5: + resolution: {integrity: sha512-/irauncTfmY1WkTaRQGRWcyQLzK1g98GYG/8QvIPviHgO1Fqz1JYeEIsSfF+9mc/UTA6S+IIHFgKyvUrtiBIZg==} + engines: {node: ^10.13.0 || ^12.13.0 || ^14.15.0 || >=15.0.0} + dependencies: + '@jest/console': 27.4.2 + '@jest/environment': 27.4.4 + '@jest/test-result': 27.4.2 + '@jest/transform': 27.4.5 + '@jest/types': 27.4.2 + '@types/node': 17.0.0 + chalk: 4.1.2 + emittery: 0.8.1 + exit: 0.1.2 + graceful-fs: 4.2.8 + jest-docblock: 27.4.0 + jest-environment-jsdom: 27.4.4 + jest-environment-node: 27.4.4 + jest-haste-map: 27.4.5 + jest-leak-detector: 27.4.2 + jest-message-util: 27.4.2 + jest-resolve: 27.4.5 + jest-runtime: 27.4.5 + jest-util: 27.4.2 + jest-worker: 27.4.5 + source-map-support: 0.5.21 + throat: 6.0.1 + transitivePeerDependencies: + - bufferutil + - canvas + - supports-color + - utf-8-validate + dev: true + + /jest-runtime/27.4.5: + resolution: {integrity: sha512-CIYqwuJQXHQtPd/idgrx4zgJ6iCb6uBjQq1RSAGQrw2S8XifDmoM1Ot8NRd80ooAm+ZNdHVwsktIMGlA1F1FAQ==} + engines: {node: ^10.13.0 || ^12.13.0 || ^14.15.0 || >=15.0.0} + dependencies: + '@jest/console': 27.4.2 + '@jest/environment': 27.4.4 + '@jest/globals': 27.4.4 + '@jest/source-map': 27.4.0 + '@jest/test-result': 27.4.2 + '@jest/transform': 27.4.5 + '@jest/types': 27.4.2 + '@types/yargs': 16.0.4 + chalk: 4.1.2 + cjs-module-lexer: 1.2.2 + collect-v8-coverage: 1.0.1 + execa: 5.1.1 + exit: 0.1.2 + glob: 7.2.0 + graceful-fs: 4.2.8 + jest-haste-map: 27.4.5 + jest-message-util: 27.4.2 + jest-mock: 27.4.2 + jest-regex-util: 27.4.0 + jest-resolve: 27.4.5 + jest-snapshot: 27.4.5 + jest-util: 27.4.2 + jest-validate: 27.4.2 + slash: 3.0.0 + strip-bom: 4.0.0 + yargs: 16.2.0 + transitivePeerDependencies: + - supports-color + dev: true + + /jest-serializer/27.4.0: + resolution: {integrity: sha512-RDhpcn5f1JYTX2pvJAGDcnsNTnsV9bjYPU8xcV+xPwOXnUPOQwf4ZEuiU6G9H1UztH+OapMgu/ckEVwO87PwnQ==} + engines: {node: ^10.13.0 || ^12.13.0 || ^14.15.0 || >=15.0.0} + dependencies: + '@types/node': 17.0.0 + graceful-fs: 4.2.8 + dev: true + + /jest-snapshot/27.4.5: + resolution: {integrity: sha512-eCi/iM1YJFrJWiT9de4+RpWWWBqsHiYxFG9V9o/n0WXs6GpW4lUt4FAHAgFPTLPqCUVzrMQmSmTZSgQzwqR7IQ==} + engines: {node: ^10.13.0 || ^12.13.0 || ^14.15.0 || >=15.0.0} + dependencies: + '@babel/core': 7.16.5 + '@babel/generator': 7.16.5 + '@babel/parser': 7.16.6 + '@babel/plugin-syntax-typescript': 7.16.5_@babel+core@7.16.5 + '@babel/traverse': 7.16.5 + '@babel/types': 7.16.0 + '@jest/transform': 27.4.5 + '@jest/types': 27.4.2 + '@types/babel__traverse': 7.14.2 + '@types/prettier': 2.4.2 + babel-preset-current-node-syntax: 1.0.1_@babel+core@7.16.5 + chalk: 4.1.2 + expect: 27.4.2 + graceful-fs: 4.2.8 + jest-diff: 27.4.2 + jest-get-type: 27.4.0 + jest-haste-map: 27.4.5 + jest-matcher-utils: 27.4.2 + jest-message-util: 27.4.2 + jest-resolve: 27.4.5 + jest-util: 27.4.2 + natural-compare: 1.4.0 + pretty-format: 27.4.2 + semver: 7.3.5 + transitivePeerDependencies: + - supports-color + dev: true + + /jest-util/27.4.2: + resolution: {integrity: sha512-YuxxpXU6nlMan9qyLuxHaMMOzXAl5aGZWCSzben5DhLHemYQxCc4YK+4L3ZrCutT8GPQ+ui9k5D8rUJoDioMnA==} + engines: {node: ^10.13.0 || ^12.13.0 || ^14.15.0 || >=15.0.0} + dependencies: + '@jest/types': 27.4.2 + '@types/node': 17.0.0 + chalk: 4.1.2 + ci-info: 3.3.0 + graceful-fs: 4.2.8 + picomatch: 2.3.0 + dev: true + + /jest-validate/27.4.2: + resolution: {integrity: sha512-hWYsSUej+Fs8ZhOm5vhWzwSLmVaPAxRy+Mr+z5MzeaHm9AxUpXdoVMEW4R86y5gOobVfBsMFLk4Rb+QkiEpx1A==} + engines: {node: ^10.13.0 || ^12.13.0 || ^14.15.0 || >=15.0.0} + dependencies: + '@jest/types': 27.4.2 + camelcase: 6.2.1 + chalk: 4.1.2 + jest-get-type: 27.4.0 + leven: 3.1.0 + pretty-format: 27.4.2 + dev: true + + /jest-watcher/27.4.2: + resolution: {integrity: sha512-NJvMVyyBeXfDezhWzUOCOYZrUmkSCiatpjpm+nFUid74OZEHk6aMLrZAukIiFDwdbqp6mTM6Ui1w4oc+8EobQg==} + engines: {node: ^10.13.0 || ^12.13.0 || ^14.15.0 || >=15.0.0} + dependencies: + '@jest/test-result': 27.4.2 + '@jest/types': 27.4.2 + '@types/node': 17.0.0 + ansi-escapes: 4.3.2 + chalk: 4.1.2 + jest-util: 27.4.2 + string-length: 4.0.2 + dev: true + + /jest-worker/27.4.5: + resolution: {integrity: sha512-f2s8kEdy15cv9r7q4KkzGXvlY0JTcmCbMHZBfSQDwW77REr45IDWwd0lksDFeVHH2jJ5pqb90T77XscrjeGzzg==} + engines: {node: '>= 10.13.0'} + dependencies: + '@types/node': 17.0.0 + merge-stream: 2.0.0 + supports-color: 8.1.1 + dev: true + + /jest/27.4.5: + resolution: {integrity: sha512-uT5MiVN3Jppt314kidCk47MYIRilJjA/l2mxwiuzzxGUeJIvA8/pDaJOAX5KWvjAo7SCydcW0/4WEtgbLMiJkg==} + engines: {node: ^10.13.0 || ^12.13.0 || ^14.15.0 || >=15.0.0} + hasBin: true + peerDependencies: + node-notifier: ^8.0.1 || ^9.0.0 || ^10.0.0 + peerDependenciesMeta: + node-notifier: + optional: true + dependencies: + '@jest/core': 27.4.5 + import-local: 3.0.3 + jest-cli: 27.4.5 + transitivePeerDependencies: + - bufferutil + - canvas + - supports-color + - ts-node + - utf-8-validate + dev: true + + /js-tokens/4.0.0: + resolution: {integrity: sha512-RdJUflcE3cUzKiMqQgsCu06FPu9UdIJO0beYbPhHN4k6apgJtifcoCtT9bcxOpYBtpD2kCM6Sbzg4CausW/PKQ==} + dev: true + + /js-yaml/3.14.1: + resolution: {integrity: sha512-okMH7OXXJ7YrN9Ok3/SXrnu4iX9yOk+25nqX4imS2npuvTYDmo/QEZoqwZkYaIDk3jVvBOTOIEgEhaLOynBS9g==} + hasBin: true + dependencies: + argparse: 1.0.10 + esprima: 4.0.1 + dev: true + + /js-yaml/4.1.0: + resolution: {integrity: sha512-wpxZs9NoxZaJESJGIZTyDEaYpl0FKSA+FB9aJiyemKhMwkxQg63h4T1KJgUGHpTqPDNRcmmYLugrRjJlBtWvRA==} + hasBin: true + dependencies: + argparse: 2.0.1 + dev: true + + /jsdom/16.7.0: + resolution: {integrity: sha512-u9Smc2G1USStM+s/x1ru5Sxrl6mPYCbByG1U/hUmqaVsm4tbNyS7CicOSRyuGQYZhTu0h84qkZZQ/I+dzizSVw==} + engines: {node: '>=10'} + peerDependencies: + canvas: ^2.5.0 + peerDependenciesMeta: + canvas: + optional: true + dependencies: + abab: 2.0.5 + acorn: 8.6.0 + acorn-globals: 6.0.0 + cssom: 0.4.4 + cssstyle: 2.3.0 + data-urls: 2.0.0 + decimal.js: 10.3.1 + domexception: 2.0.1 + escodegen: 2.0.0 + form-data: 3.0.1 + html-encoding-sniffer: 2.0.1 + http-proxy-agent: 4.0.1 + https-proxy-agent: 5.0.0 + is-potential-custom-element-name: 1.0.1 + nwsapi: 2.2.0 + parse5: 6.0.1 + saxes: 5.0.1 + symbol-tree: 3.2.4 + tough-cookie: 4.0.0 + w3c-hr-time: 1.0.2 + w3c-xmlserializer: 2.0.0 + webidl-conversions: 6.1.0 + whatwg-encoding: 1.0.5 + whatwg-mimetype: 2.3.0 + whatwg-url: 8.7.0 + ws: 7.5.6 + xml-name-validator: 3.0.0 + transitivePeerDependencies: + - bufferutil + - supports-color + - utf-8-validate + dev: true + + /jsesc/2.5.2: + resolution: {integrity: sha512-OYu7XEzjkCQ3C5Ps3QIZsQfNpqoJyZZA99wd9aWd05NCtC5pWOkShK2mkL6HXQR6/Cy2lbNdPlZBpuQHXE63gA==} + engines: {node: '>=4'} + hasBin: true + dev: true + + /json-parse-even-better-errors/2.3.1: + resolution: {integrity: sha512-xyFwyhro/JEof6Ghe2iz2NcXoj2sloNsWr/XsERDK/oiPCfaNhl5ONfp+jQdAZRQQ0IJWNzH9zIZF7li91kh2w==} + dev: true + + /json-schema-traverse/0.4.1: + resolution: {integrity: sha512-xbbCH5dCYU5T8LcEhhuh7HJ88HXuW3qsI3Y0zOZFKfZEHcpWiHU/Jxzk629Brsab/mMiHQti9wMP+845RPe3Vg==} + dev: true + + /json-stable-stringify-without-jsonify/1.0.1: + resolution: {integrity: sha1-nbe1lJatPzz+8wp1FC0tkwrXJlE=} + dev: true + + /json5/2.2.0: + resolution: {integrity: sha512-f+8cldu7X/y7RAJurMEJmdoKXGB/X550w2Nr3tTbezL6RwEE/iMcm+tZnXeoZtKuOq6ft8+CqzEkrIgx1fPoQA==} + engines: {node: '>=6'} + hasBin: true + dependencies: + minimist: 1.2.5 + dev: true + + /jsonfile/6.1.0: + resolution: {integrity: sha512-5dgndWOriYSm5cnYaJNhalLNDKOqFwyDB/rr1E9ZsGciGvKPs8R2xYGCacuf3z6K1YKDz182fd+fY3cn3pMqXQ==} + dependencies: + universalify: 2.0.0 + optionalDependencies: + graceful-fs: 4.2.8 + dev: true + + /jsonparse/1.3.1: + resolution: {integrity: sha1-P02uSpH6wxX3EGL4UhzCOfE2YoA=} + engines: {'0': node >= 0.2.0} + dev: true + + /kind-of/6.0.3: + resolution: {integrity: sha512-dcS1ul+9tmeD95T+x28/ehLgd9mENa3LsvDTtzm3vyBEO7RPptvAD+t44WVXaUjTBRcrpFeFlC8WCruUR456hw==} + engines: {node: '>=0.10.0'} + dev: true + + /kleur/3.0.3: + resolution: {integrity: sha512-eTIzlVOSUR+JxdDFepEYcBMtZ9Qqdef+rnzWdRZuMbOywu5tO2w2N7rqjoANZ5k9vywhL6Br1VRjUIgTQx4E8w==} + engines: {node: '>=6'} + dev: true + + /leven/3.1.0: + resolution: {integrity: sha512-qsda+H8jTaUaN/x5vzW2rzc+8Rw4TAQ/4KjB46IwK5VH+IlVeeeje/EoZRpiXvIqjFgK84QffqPztGI3VBLG1A==} + engines: {node: '>=6'} + dev: true + + /levn/0.3.0: + resolution: {integrity: sha1-OwmSTt+fCDwEkP3UwLxEIeBHZO4=} + engines: {node: '>= 0.8.0'} + dependencies: + prelude-ls: 1.1.2 + type-check: 0.3.2 + dev: true + + /levn/0.4.1: + resolution: {integrity: sha512-+bT2uH4E5LGE7h/n3evcS/sQlJXCpIp6ym8OWJ5eV6+67Dsql/LaaT7qJBAt2rzfoa/5QBGBhxDix1dMt2kQKQ==} + engines: {node: '>= 0.8.0'} + dependencies: + prelude-ls: 1.2.1 + type-check: 0.4.0 + dev: true + + /libphonenumber-js/1.9.44: + resolution: {integrity: sha512-zhw8nUMJuQf7jG1dZfEOKKOS6M3QYIv3HnvB/vGohNd0QfxIQcObH3a6Y6s350H+9xgBeOXClOJkS0hJ0yvS3g==} + dev: false + + /lines-and-columns/1.2.4: + resolution: {integrity: sha512-7ylylesZQ/PV29jhEDl3Ufjo6ZX7gCqJr5F7PKrqc93v7fzSymt1BpwEU8nAUXs8qzzvqhbjhK5QZg6Mt/HkBg==} + dev: true + + /locate-path/5.0.0: + resolution: {integrity: sha512-t7hw9pI+WvuwNJXwk5zVHpyhIqzg2qTlklJOf0mVxGSbe3Fp2VieZcduNYjaLDoy6p9uGpQEGWG87WpMKlNq8g==} + engines: {node: '>=8'} + dependencies: + p-locate: 4.1.0 + dev: true + + /locate-path/6.0.0: + resolution: {integrity: sha512-iPZK6eYjbxRu3uB4/WZ3EsEIMJFMqAoopl3R+zuq0UjcAm/MO6KCweDgPfP3elTztoKP3KtnVHxTn2NHBSDVUw==} + engines: {node: '>=10'} + dependencies: + p-locate: 5.0.0 + dev: true + + /lodash.get/4.4.2: + resolution: {integrity: sha1-LRd/ZS+jHpObRDjVNBSZ36OCXpk=} + dev: true + + /lodash.memoize/4.1.2: + resolution: {integrity: sha1-vMbEmkKihA7Zl/Mj6tpezRguC/4=} + dev: true + + /lodash.merge/4.6.2: + resolution: {integrity: sha512-0KpjqXRVvrYyCsX1swR/XTK0va6VQkQM6MNo7PqW77ByjAhoARA8EfrP1N4+KlKj8YS0ZUCtRT/YUuhyYDujIQ==} + dev: true + + /lodash/4.17.21: + resolution: {integrity: sha512-v2kDEe57lecTulaDIuNTPy3Ry4gLGJ6Z1O3vE1krgXZNrsQ+LFTGHVxVjcXPs17LhbZVGedAJv8XZ1tvj5FvSg==} + dev: true + + /lru-cache/6.0.0: + resolution: {integrity: sha512-Jo6dJ04CmSjuznwJSS3pUeWmd/H0ffTlkXXgwZi+eq1UCmqQwCh+eLsYOYCwY991i2Fah4h1BEMCx4qThGbsiA==} + engines: {node: '>=10'} + dependencies: + yallist: 4.0.0 + dev: true + + /make-dir/3.1.0: + resolution: {integrity: sha512-g3FeP20LNwhALb/6Cz6Dd4F2ngze0jz7tbzrD2wAV+o9FeNHe4rL+yK2md0J/fiSf1sa1ADhXqi5+oVwOM/eGw==} + engines: {node: '>=8'} + dependencies: + semver: 6.3.0 + dev: true + + /make-error/1.3.6: + resolution: {integrity: sha512-s8UhlNe7vPKomQhC1qFelMokr/Sc3AgNbso3n74mVPA5LTZwkB9NlXf4XPamLxJE8h0gh73rM94xvwRT2CVInw==} + dev: true + + /makeerror/1.0.12: + resolution: {integrity: sha512-JmqCvUhmt43madlpFzG4BQzG2Z3m6tvQDNKdClZnO3VbIudJYmxsT0FNJMeiB2+JTSlTQTSbU8QdesVmwJcmLg==} + dependencies: + tmpl: 1.0.5 + dev: true + + /map-obj/1.0.1: + resolution: {integrity: sha1-2TPOuSBdgr3PSIb2dCvcK03qFG0=} + engines: {node: '>=0.10.0'} + dev: true + + /map-obj/4.3.0: + resolution: {integrity: sha512-hdN1wVrZbb29eBGiGjJbeP8JbKjq1urkHJ/LIP/NY48MZ1QVXUsQBV1G1zvYFHn1XE06cwjBsOI2K3Ulnj1YXQ==} + engines: {node: '>=8'} + dev: true + + /media-typer/0.3.0: + resolution: {integrity: sha1-hxDXrwqmJvj/+hzgAWhUUmMlV0g=} + engines: {node: '>= 0.6'} + dev: true + + /meow/8.1.2: + resolution: {integrity: sha512-r85E3NdZ+mpYk1C6RjPFEMSE+s1iZMuHtsHAqY0DT3jZczl0diWUZ8g6oU7h0M9cD2EL+PzaYghhCLzR0ZNn5Q==} + engines: {node: '>=10'} + dependencies: + '@types/minimist': 1.2.2 + camelcase-keys: 6.2.2 + decamelize-keys: 1.1.0 + hard-rejection: 2.1.0 + minimist-options: 4.1.0 + normalize-package-data: 3.0.3 + read-pkg-up: 7.0.1 + redent: 3.0.0 + trim-newlines: 3.0.1 + type-fest: 0.18.1 + yargs-parser: 20.2.9 + dev: true + + /merge-descriptors/1.0.1: + resolution: {integrity: sha1-sAqqVW3YtEVoFQ7J0blT8/kMu2E=} + dev: true + + /merge-stream/2.0.0: + resolution: {integrity: sha512-abv/qOcuPfk3URPfDzmZU1LKmuw8kT+0nIHvKrKgFrwifol/doWcdA4ZqsWQ8ENrFKkd67Mfpo/LovbIUsbt3w==} + dev: true + + /merge2/1.4.1: + resolution: {integrity: sha512-8q7VEgMJW4J8tcfVPy8g09NcQwZdbwFEqhe/WZkoIzjn/3TGDwtOCYtXGxA3O8tPzpczCCDgv+P2P5y00ZJOOg==} + engines: {node: '>= 8'} + dev: true + + /methods/1.1.2: + resolution: {integrity: sha1-VSmk1nZUE07cxSZmVoNbD4Ua/O4=} + engines: {node: '>= 0.6'} + dev: true + + /micromatch/4.0.4: + resolution: {integrity: sha512-pRmzw/XUcwXGpD9aI9q/0XOwLNygjETJ8y0ao0wdqprrzDa4YnxLcz7fQRZr8voh8V10kGhABbNcHVk5wHgWwg==} + engines: {node: '>=8.6'} + dependencies: + braces: 3.0.2 + picomatch: 2.3.0 + dev: true + + /mime-db/1.51.0: + resolution: {integrity: sha512-5y8A56jg7XVQx2mbv1lu49NR4dokRnhZYTtL+KGfaa27uq4pSTXkwQkFJl4pkRMyNFz/EtYDSkiiEHx3F7UN6g==} + engines: {node: '>= 0.6'} + + /mime-types/2.1.34: + resolution: {integrity: sha512-6cP692WwGIs9XXdOO4++N+7qjqv0rqxxVvJ3VHPh/Sc9mVZcQP+ZGhkKiTvWMQRr2tbHkJP/Yn7Y0npb3ZBs4A==} + engines: {node: '>= 0.6'} + dependencies: + mime-db: 1.51.0 + + /mime/1.6.0: + resolution: {integrity: sha512-x0Vn8spI+wuJ1O6S7gnbaQg8Pxh4NNHb7KSINmEWKiPE4RKOplvijn+NkmYmmRgP68mc70j2EbeTFRsrswaQeg==} + engines: {node: '>=4'} + hasBin: true + dev: true + + /mimic-fn/2.1.0: + resolution: {integrity: sha512-OqbOk5oEQeAZ8WXWydlu9HJjz9WVdEIvamMCcXmuqUYjTknH/sqsWvhQ3vgwKFRR1HpjvNBKQ37nbJgYzGqGcg==} + engines: {node: '>=6'} + dev: true + + /min-indent/1.0.1: + resolution: {integrity: sha512-I9jwMn07Sy/IwOj3zVkVik2JTvgpaykDZEigL6Rx6N9LbMywwUSMtxET+7lVoDLLd3O3IXwJwvuuns8UB/HeAg==} + engines: {node: '>=4'} + dev: true + + /minimatch/3.0.4: + resolution: {integrity: sha512-yJHVQEhyqPLUTgt9B83PXu6W3rx4MvvHvSUvToogpwoGDOUQ+yDrR0HRot+yOCdCO7u4hX3pWft6kWBBcqh0UA==} + dependencies: + brace-expansion: 1.1.11 + dev: true + + /minimist-options/4.1.0: + resolution: {integrity: sha512-Q4r8ghd80yhO/0j1O3B2BjweX3fiHg9cdOwjJd2J76Q135c+NDxGCqdYKQ1SKBuFfgWbAUzBfvYjPUEeNgqN1A==} + engines: {node: '>= 6'} + dependencies: + arrify: 1.0.1 + is-plain-obj: 1.1.0 + kind-of: 6.0.3 + dev: true + + /minimist/1.2.5: + resolution: {integrity: sha512-FM9nNUYrRBAELZQT3xeZQ7fmMOBg6nWNmJKTcgsJeaLstP/UODVpGsr5OhXhhXg6f+qtJ8uiZ+PUxkDWcgIXLw==} + dev: true + + /mkdirp/0.5.5: + resolution: {integrity: sha512-NKmAlESf6jMGym1++R0Ra7wvhV+wFW63FaSOFPwRahvea0gMUcGUhVeAg/0BC0wiv9ih5NYPB1Wn1UEI1/L+xQ==} + hasBin: true + dependencies: + minimist: 1.2.5 + dev: true + + /ms/2.0.0: + resolution: {integrity: sha1-VgiurfwAvmwpAd9fmGF4jeDVl8g=} + dev: true + + /ms/2.1.2: + resolution: {integrity: sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==} + dev: true + + /ms/2.1.3: + resolution: {integrity: sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==} + dev: true + + /multer/1.4.4: + resolution: {integrity: sha512-2wY2+xD4udX612aMqMcB8Ws2Voq6NIUPEtD1be6m411T4uDH/VtL9i//xvcyFlTVfRdaBsk7hV5tgrGQqhuBiw==} + engines: {node: '>= 0.10.0'} + dependencies: + append-field: 1.0.0 + busboy: 0.2.14 + concat-stream: 1.6.2 + mkdirp: 0.5.5 + object-assign: 4.1.1 + on-finished: 2.3.0 + type-is: 1.6.18 + xtend: 4.0.2 + dev: true + + /natural-compare/1.4.0: + resolution: {integrity: sha1-Sr6/7tdUHywnrPspvbvRXI1bpPc=} + dev: true + + /negotiator/0.6.2: + resolution: {integrity: sha512-hZXc7K2e+PgeI1eDBe/10Ard4ekbfrrqG8Ep+8Jmf4JID2bNg7NvCPOZN+kfF574pFQI7mum2AUqDidoKqcTOw==} + engines: {node: '>= 0.6'} + dev: true + + /node-int64/0.4.0: + resolution: {integrity: sha1-h6kGXNs1XTGC2PlM4RGIuCXGijs=} + dev: true + + /node-releases/2.0.1: + resolution: {integrity: sha512-CqyzN6z7Q6aMeF/ktcMVTzhAHCEpf8SOarwpzpf8pNBY2k5/oM34UHldUwp8VKI7uxct2HxSRdJjBaZeESzcxA==} + dev: true + + /normalize-package-data/2.5.0: + resolution: {integrity: sha512-/5CMN3T0R4XTj4DcGaexo+roZSdSFW/0AOOTROrjxzCG1wrWXEsGbRKevjlIL+ZDE4sZlJr5ED4YW0yqmkK+eA==} + dependencies: + hosted-git-info: 2.8.9 + resolve: 1.20.0 + semver: 5.7.1 + validate-npm-package-license: 3.0.4 + dev: true + + /normalize-package-data/3.0.3: + resolution: {integrity: sha512-p2W1sgqij3zMMyRC067Dg16bfzVH+w7hyegmpIvZ4JNjqtGOVAIvLmjBx3yP7YTe9vKJgkoNOPjwQGogDoMXFA==} + engines: {node: '>=10'} + dependencies: + hosted-git-info: 4.0.2 + is-core-module: 2.8.0 + semver: 7.3.5 + validate-npm-package-license: 3.0.4 + dev: true + + /normalize-path/3.0.0: + resolution: {integrity: sha512-6eZs5Ls3WtCisHWp9S2GUy8dqkpGi4BVSz3GaqiE6ezub0512ESztXUwUB6C6IKbQkY2Pnb/mD4WYojCRwcwLA==} + engines: {node: '>=0.10.0'} + dev: true + + /npm-run-path/4.0.1: + resolution: {integrity: sha512-S48WzZW777zhNIrn7gxOlISNAqi9ZC/uQFnRdbeIHhZhCA6UqpkOT8T1G7BvfdgP4Er8gF4sUbaS0i7QvIfCWw==} + engines: {node: '>=8'} + dependencies: + path-key: 3.1.1 + dev: true + + /nwsapi/2.2.0: + resolution: {integrity: sha512-h2AatdwYH+JHiZpv7pt/gSX1XoRGb7L/qSIeuqA6GwYoF9w1vP1cw42TO0aI2pNyshRK5893hNSl+1//vHK7hQ==} + dev: true + + /object-assign/4.1.1: + resolution: {integrity: sha1-IQmtx5ZYh8/AXLvUQsrIv7s2CGM=} + engines: {node: '>=0.10.0'} + dev: true + + /object-inspect/1.12.0: + resolution: {integrity: sha512-Ho2z80bVIvJloH+YzRmpZVQe87+qASmBUKZDWgx9cu+KDrX2ZDH/3tMy+gXbZETVGs2M8YdxObOh7XAtim9Y0g==} + dev: false + + /on-finished/2.3.0: + resolution: {integrity: sha1-IPEzZIGwg811M3mSoWlxqi2QaUc=} + engines: {node: '>= 0.8'} + dependencies: + ee-first: 1.1.1 + dev: true + + /once/1.4.0: + resolution: {integrity: sha1-WDsap3WWHUsROsF9nFC6753Xa9E=} + dependencies: + wrappy: 1.0.2 + dev: true + + /onetime/5.1.2: + resolution: {integrity: sha512-kbpaSSGJTWdAY5KPVeMOKXSrPtr8C8C7wodJbcsd51jRnmD+GZu8Y0VoU6Dm5Z4vWr0Ig/1NKuWRKf7j5aaYSg==} + engines: {node: '>=6'} + dependencies: + mimic-fn: 2.1.0 + dev: true + + /optionator/0.8.3: + resolution: {integrity: sha512-+IW9pACdk3XWmmTXG8m3upGUJst5XRGzxMRjXzAuJ1XnIFNvfhjjIuYkDvysnPQ7qzqVzLt78BCruntqRhWQbA==} + engines: {node: '>= 0.8.0'} + dependencies: + deep-is: 0.1.4 + fast-levenshtein: 2.0.6 + levn: 0.3.0 + prelude-ls: 1.1.2 + type-check: 0.3.2 + word-wrap: 1.2.3 + dev: true + + /optionator/0.9.1: + resolution: {integrity: sha512-74RlY5FCnhq4jRxVUPKDaRwrVNXMqsGsiW6AJw4XK8hmtm10wC0ypZBLw5IIp85NZMr91+qd1RvvENwg7jjRFw==} + engines: {node: '>= 0.8.0'} + dependencies: + deep-is: 0.1.4 + fast-levenshtein: 2.0.6 + levn: 0.4.1 + prelude-ls: 1.2.1 + type-check: 0.4.0 + word-wrap: 1.2.3 + dev: true + + /p-limit/2.3.0: + resolution: {integrity: sha512-//88mFWSJx8lxCzwdAABTJL2MyWB12+eIY7MDL2SqLmAkeKU9qxRvWuSyTjm3FUmpBEMuFfckAIqEaVGUDxb6w==} + engines: {node: '>=6'} + dependencies: + p-try: 2.2.0 + dev: true + + /p-limit/3.1.0: + resolution: {integrity: sha512-TYOanM3wGwNGsZN2cVTYPArw454xnXj5qmWF1bEoAc4+cU/ol7GVh7odevjp1FNHduHc3KZMcFduxU5Xc6uJRQ==} + engines: {node: '>=10'} + dependencies: + yocto-queue: 0.1.0 + dev: true + + /p-locate/4.1.0: + resolution: {integrity: sha512-R79ZZ/0wAxKGu3oYMlz8jy/kbhsNrS7SKZ7PxEHBgJ5+F2mtFW2fK2cOtBh1cHYkQsbzFV7I+EoRKe6Yt0oK7A==} + engines: {node: '>=8'} + dependencies: + p-limit: 2.3.0 + dev: true + + /p-locate/5.0.0: + resolution: {integrity: sha512-LaNjtRWUBY++zB5nE/NwcaoMylSPk+S+ZHNB1TzdbMJMny6dynpAGt7X/tl/QYq3TIeE6nxHppbo2LGymrG5Pw==} + engines: {node: '>=10'} + dependencies: + p-limit: 3.1.0 + dev: true + + /p-try/2.2.0: + resolution: {integrity: sha512-R4nPAVTAU0B9D35/Gk3uJf/7XYbQcyohSKdvAxIRSNghFl4e71hVoGnBNQz9cWaXxO2I10KTC+3jMdvvoKw6dQ==} + engines: {node: '>=6'} + dev: true + + /parent-module/1.0.1: + resolution: {integrity: sha512-GQ2EWRpQV8/o+Aw8YqtfZZPfNRWZYkbidE9k5rpl/hC3vtHHBfGm2Ifi6qWV+coDGkrUKZAxE3Lot5kcsRlh+g==} + engines: {node: '>=6'} + dependencies: + callsites: 3.1.0 + dev: true + + /parse-json/5.2.0: + resolution: {integrity: sha512-ayCKvm/phCGxOkYRSCM82iDwct8/EonSEgCSxWxD7ve6jHggsFl4fZVQBPRNgQoKiuV/odhFrGzQXZwbifC8Rg==} + engines: {node: '>=8'} + dependencies: + '@babel/code-frame': 7.16.0 + error-ex: 1.3.2 + json-parse-even-better-errors: 2.3.1 + lines-and-columns: 1.2.4 + dev: true + + /parse5/6.0.1: + resolution: {integrity: sha512-Ofn/CTFzRGTTxwpNEs9PP93gXShHcTq255nzRYSKe8AkVpZY7e1fpmTfOyoIvjP5HG7Z2ZM7VS9PPhQGW2pOpw==} + dev: true + + /parseurl/1.3.3: + resolution: {integrity: sha512-CiyeOxFT/JZyN5m0z9PfXw4SCBJ6Sygz1Dpl0wqjlhDEGGBP1GnsUVEL0p63hoG1fcj3fHynXi9NYO4nWOL+qQ==} + engines: {node: '>= 0.8'} + dev: true + + /path-exists/4.0.0: + resolution: {integrity: sha512-ak9Qy5Q7jYb2Wwcey5Fpvg2KoAc/ZIhLSLOSBmRmygPsGwkVVt0fZa0qrtMz+m6tJTAHfZQ8FnmB4MG4LWy7/w==} + engines: {node: '>=8'} + dev: true + + /path-is-absolute/1.0.1: + resolution: {integrity: sha1-F0uSaHNVNP+8es5r9TpanhtcX18=} + engines: {node: '>=0.10.0'} + dev: true + + /path-key/3.1.1: + resolution: {integrity: sha512-ojmeN0qd+y0jszEtoY48r0Peq5dwMEkIlCOu6Q5f41lfkswXuKtYrhgoTpLnyIcHm24Uhqx+5Tqm2InSwLhE6Q==} + engines: {node: '>=8'} + dev: true + + /path-parse/1.0.7: + resolution: {integrity: sha512-LDJzPVEEEPR+y48z93A0Ed0yXb8pAByGWo/k5YYdYgpY2/2EsOsksJrq7lOHxryrVOn1ejG6oAp8ahvOIQD8sw==} + dev: true + + /path-to-regexp/0.1.7: + resolution: {integrity: sha1-32BBeABfUi8V60SQ5yR6G/qmf4w=} + dev: true + + /path-type/4.0.0: + resolution: {integrity: sha512-gDKb8aZMDeD/tZWs9P6+q0J9Mwkdl6xMV8TjnGP3qJVJ06bdMgkbBlLU8IdfOsIsFz2BW1rNVT3XuNEl8zPAvw==} + engines: {node: '>=8'} + dev: true + + /picocolors/1.0.0: + resolution: {integrity: sha512-1fygroTLlHu66zi26VoTDv8yRgm0Fccecssto+MhsZ0D/DGW2sm8E8AjW7NU5VVTRt5GxbeZ5qBuJr+HyLYkjQ==} + dev: true + + /picomatch/2.3.0: + resolution: {integrity: sha512-lY1Q/PiJGC2zOv/z391WOTD+Z02bCgsFfvxoXXf6h7kv9o+WmsmzYqrAwY63sNgOxE4xEdq0WyUnXfKeBrSvYw==} + engines: {node: '>=8.6'} + dev: true + + /pirates/4.0.4: + resolution: {integrity: sha512-ZIrVPH+A52Dw84R0L3/VS9Op04PuQ2SEoJL6bkshmiTic/HldyW9Tf7oH5mhJZBK7NmDx27vSMrYEXPXclpDKw==} + engines: {node: '>= 6'} + dev: true + + /pkg-dir/4.2.0: + resolution: {integrity: sha512-HRDzbaKjC+AOWVXxAU/x54COGeIv9eb+6CkDSQoNTt4XyWoIJvuPsXizxu/Fr23EiekbtZwmh1IcIG/l/a10GQ==} + engines: {node: '>=8'} + dependencies: + find-up: 4.1.0 + dev: true + + /prelude-ls/1.1.2: + resolution: {integrity: sha1-IZMqVJ9eUv/ZqCf1cOBL5iqX2lQ=} + engines: {node: '>= 0.8.0'} + dev: true + + /prelude-ls/1.2.1: + resolution: {integrity: sha512-vkcDPrRZo1QZLbn5RLGPpg/WmIQ65qoWWhcGKf/b5eplkkarX0m9z8ppCat4mlOqUsWpyNuYgO3VRyrYHSzX5g==} + engines: {node: '>= 0.8.0'} + dev: true + + /prettier-linter-helpers/1.0.0: + resolution: {integrity: sha512-GbK2cP9nraSSUF9N2XwUwqfzlAFlMNYYl+ShE/V+H8a9uNl/oUqB1w2EL54Jh0OlyRSd8RfWYJ3coVS4TROP2w==} + engines: {node: '>=6.0.0'} + dependencies: + fast-diff: 1.2.0 + dev: true + + /prettier/2.5.1: + resolution: {integrity: sha512-vBZcPRUR5MZJwoyi3ZoyQlc1rXeEck8KgeC9AwwOn+exuxLxq5toTRDTSaVrXHxelDMHy9zlicw8u66yxoSUFg==} + engines: {node: '>=10.13.0'} + hasBin: true + dev: true + + /pretty-format/27.4.2: + resolution: {integrity: sha512-p0wNtJ9oLuvgOQDEIZ9zQjZffK7KtyR6Si0jnXULIDwrlNF8Cuir3AZP0hHv0jmKuNN/edOnbMjnzd4uTcmWiw==} + engines: {node: ^10.13.0 || ^12.13.0 || ^14.15.0 || >=15.0.0} + dependencies: + '@jest/types': 27.4.2 + ansi-regex: 5.0.1 + ansi-styles: 5.2.0 + react-is: 17.0.2 + dev: true + + /process-nextick-args/2.0.1: + resolution: {integrity: sha512-3ouUOpQhtgrbOa17J7+uxOTpITYWaGP7/AhoR3+A+/1e9skrzelGi/dXzEYyvbxubEF6Wn2ypscTKiKJFFn1ag==} + dev: true + + /progress/2.0.3: + resolution: {integrity: sha512-7PiHtLll5LdnKIMw100I+8xJXR5gW2QwWYkT6iJva0bXitZKa/XMrSbdmg3r2Xnaidz9Qumd0VPaMrZlF9V9sA==} + engines: {node: '>=0.4.0'} + dev: true + + /prompts/2.4.2: + resolution: {integrity: sha512-NxNv/kLguCA7p3jE8oL2aEBsrJWgAakBpgmgK6lpPWV+WuOmY6r2/zbAVnP+T8bQlA0nzHXSJSJW0Hq7ylaD2Q==} + engines: {node: '>= 6'} + dependencies: + kleur: 3.0.3 + sisteransi: 1.0.5 + dev: true + + /proxy-addr/2.0.7: + resolution: {integrity: sha512-llQsMLSUDUPT44jdrU/O37qlnifitDP+ZwrmmZcoSKyLKvtZxpyV0n2/bD/N4tBAAZ/gJEdZU7KMraoK1+XYAg==} + engines: {node: '>= 0.10'} + dependencies: + forwarded: 0.2.0 + ipaddr.js: 1.9.1 + dev: true + + /psl/1.8.0: + resolution: {integrity: sha512-RIdOzyoavK+hA18OGGWDqUTsCLhtA7IcZ/6NCs4fFJaHBDab+pDDmDIByWFRQJq2Cd7r1OoQxBGKOaztq+hjIQ==} + dev: true + + /punycode/2.1.1: + resolution: {integrity: sha512-XRsRjdf+j5ml+y/6GKHPZbrF/8p2Yga0JPtdqTIY2Xe5ohJPD9saDJJLPvp9+NSBprVvevdXZybnj2cv8OEd0A==} + engines: {node: '>=6'} + dev: true + + /q/1.5.1: + resolution: {integrity: sha1-fjL3W0E4EpHQRhHxvxQQmsAGUdc=} + engines: {node: '>=0.6.0', teleport: '>=0.2.0'} + dev: true + + /qs/6.10.2: + resolution: {integrity: sha512-mSIdjzqznWgfd4pMii7sHtaYF8rx8861hBO80SraY5GT0XQibWZWJSid0avzHGkDIZLImux2S5mXO0Hfct2QCw==} + engines: {node: '>=0.6'} + dependencies: + side-channel: 1.0.4 + dev: false + + /qs/6.9.6: + resolution: {integrity: sha512-TIRk4aqYLNoJUbd+g2lEdz5kLWIuTMRagAXxl78Q0RiVjAOugHmeKNGdd3cwo/ktpf9aL9epCfFqWDEKysUlLQ==} + engines: {node: '>=0.6'} + dev: true + + /queue-microtask/1.2.3: + resolution: {integrity: sha512-NuaNSa6flKT5JaSYQzJok04JzTL1CA6aGhv5rfLW3PgqA+M2ChpZQnAC8h8i4ZFkBS8X5RqkDBHA7r4hej3K9A==} + dev: true + + /quick-lru/4.0.1: + resolution: {integrity: sha512-ARhCpm70fzdcvNQfPoy49IaanKkTlRWF2JMzqhcJbhSFRZv7nPTvZJdcY7301IPmvW+/p0RgIWnQDLJxifsQ7g==} + engines: {node: '>=8'} + dev: true + + /range-parser/1.2.1: + resolution: {integrity: sha512-Hrgsx+orqoygnmhFbKaHE6c296J+HTAQXoxEF6gNupROmmGJRoyzfG3ccAveqCBrwr/2yxQ5BVd/GTl5agOwSg==} + engines: {node: '>= 0.6'} + dev: true + + /raw-body/2.4.2: + resolution: {integrity: sha512-RPMAFUJP19WIet/99ngh6Iv8fzAbqum4Li7AD6DtGaW2RpMB/11xDoalPiJMTbu6I3hkbMVkATvZrqb9EEqeeQ==} + engines: {node: '>= 0.8'} + dependencies: + bytes: 3.1.1 + http-errors: 1.8.1 + iconv-lite: 0.4.24 + unpipe: 1.0.0 + dev: true + + /react-is/17.0.2: + resolution: {integrity: sha512-w2GsyukL62IJnlaff/nRegPQR94C/XXamvMWmSHRJ4y7Ts/4ocGRmTHvOs8PSE6pB3dWOrD/nueuU5sduBsQ4w==} + dev: true + + /read-pkg-up/7.0.1: + resolution: {integrity: sha512-zK0TB7Xd6JpCLmlLmufqykGE+/TlOePD6qKClNW7hHDKFh/J7/7gCWGR7joEQEW1bKq3a3yUZSObOoWLFQ4ohg==} + engines: {node: '>=8'} + dependencies: + find-up: 4.1.0 + read-pkg: 5.2.0 + type-fest: 0.8.1 + dev: true + + /read-pkg/5.2.0: + resolution: {integrity: sha512-Ug69mNOpfvKDAc2Q8DRpMjjzdtrnv9HcSMX+4VsZxD1aZ6ZzrIE7rlzXBtWTyhULSMKg076AW6WR5iZpD0JiOg==} + engines: {node: '>=8'} + dependencies: + '@types/normalize-package-data': 2.4.1 + normalize-package-data: 2.5.0 + parse-json: 5.2.0 + type-fest: 0.6.0 + dev: true + + /readable-stream/1.1.14: + resolution: {integrity: sha1-fPTFTvZI44EwhMY23SB54WbAgdk=} + dependencies: + core-util-is: 1.0.3 + inherits: 2.0.4 + isarray: 0.0.1 + string_decoder: 0.10.31 + dev: true + + /readable-stream/2.3.7: + resolution: {integrity: sha512-Ebho8K4jIbHAxnuxi7o42OrZgF/ZTNcsZj6nRKyUmkhLFq8CHItp/fy6hQZuZmP/n3yZ9VBUbp4zz/mX8hmYPw==} + dependencies: + core-util-is: 1.0.3 + inherits: 2.0.4 + isarray: 1.0.0 + process-nextick-args: 2.0.1 + safe-buffer: 5.1.2 + string_decoder: 1.1.1 + util-deprecate: 1.0.2 + dev: true + + /readable-stream/3.6.0: + resolution: {integrity: sha512-BViHy7LKeTz4oNnkcLJ+lVSL6vpiFeX6/d3oSH8zCW7UxP2onchk+vTGB143xuFjHS3deTgkKoXXymXqymiIdA==} + engines: {node: '>= 6'} + dependencies: + inherits: 2.0.4 + string_decoder: 1.3.0 + util-deprecate: 1.0.2 + dev: true + + /redent/3.0.0: + resolution: {integrity: sha512-6tDA8g98We0zd0GvVeMT9arEOnTw9qM03L9cJXaCjrip1OO764RDBLBfrB4cwzNGDj5OA5ioymC9GkizgWJDUg==} + engines: {node: '>=8'} + dependencies: + indent-string: 4.0.0 + strip-indent: 3.0.0 + dev: true + + /reflect-metadata/0.1.13: + resolution: {integrity: sha512-Ts1Y/anZELhSsjMcU605fU9RE4Oi3p5ORujwbIKXfWa+0Zxs510Qrmrce5/Jowq3cHSZSJqBjypxmHarc+vEWg==} + dev: false + + /regexpp/3.2.0: + resolution: {integrity: sha512-pq2bWo9mVD43nbts2wGv17XLiNLya+GklZ8kaDLV2Z08gDCsGpnKn9BFMepvWuHCbyVvY7J5o5+BVvoQbmlJLg==} + engines: {node: '>=8'} + dev: true + + /require-directory/2.1.1: + resolution: {integrity: sha1-jGStX9MNqxyXbiNE/+f3kqam30I=} + engines: {node: '>=0.10.0'} + dev: true + + /resolve-cwd/3.0.0: + resolution: {integrity: sha512-OrZaX2Mb+rJCpH/6CpSqt9xFVpN++x01XnN2ie9g6P5/3xelLAkXWVADpdz1IHD/KFfEXyE6V0U01OQ3UO2rEg==} + engines: {node: '>=8'} + dependencies: + resolve-from: 5.0.0 + dev: true + + /resolve-from/4.0.0: + resolution: {integrity: sha512-pb/MYmXstAkysRFx8piNI1tGFNQIFA3vkE3Gq4EuA1dF6gHp/+vgZqsCGJapvy8N3Q+4o7FwvquPJcnZ7RYy4g==} + engines: {node: '>=4'} + dev: true + + /resolve-from/5.0.0: + resolution: {integrity: sha512-qYg9KP24dD5qka9J47d0aVky0N+b4fTU89LN9iDnjB5waksiC49rvMB0PrUJQGoTmH50XPiqOvAjDfaijGxYZw==} + engines: {node: '>=8'} + dev: true + + /resolve-global/1.0.0: + resolution: {integrity: sha512-zFa12V4OLtT5XUX/Q4VLvTfBf+Ok0SPc1FNGM/z9ctUdiU618qwKpWnd0CHs3+RqROfyEg/DhuHbMWYqcgljEw==} + engines: {node: '>=8'} + dependencies: + global-dirs: 0.1.1 + dev: true + + /resolve.exports/1.1.0: + resolution: {integrity: sha512-J1l+Zxxp4XK3LUDZ9m60LRJF/mAe4z6a4xyabPHk7pvK5t35dACV32iIjJDFeWZFfZlO29w6SZ67knR0tHzJtQ==} + engines: {node: '>=10'} + dev: true + + /resolve/1.20.0: + resolution: {integrity: sha512-wENBPt4ySzg4ybFQW2TT1zMQucPK95HSh/nq2CFTZVOGut2+pQvSsgtda4d26YrYcr067wjbmzOG8byDPBX63A==} + dependencies: + is-core-module: 2.8.0 + path-parse: 1.0.7 + dev: true + + /reusify/1.0.4: + resolution: {integrity: sha512-U9nH88a3fc/ekCF1l0/UP1IosiuIjyTh7hBvXVMHYgVcfGvt897Xguj2UOLDeI5BG2m7/uwyaLVT6fbtCwTyzw==} + engines: {iojs: '>=1.0.0', node: '>=0.10.0'} + dev: true + + /rimraf/3.0.2: + resolution: {integrity: sha512-JZkJMZkAGFFPP2YqXZXPbMlMBgsxzE8ILs4lMIX/2o0L9UBw9O/Y3o6wFw/i9YLapcUJWwqbi3kdxIPdC62TIA==} + hasBin: true + dependencies: + glob: 7.2.0 + dev: true + + /run-parallel/1.2.0: + resolution: {integrity: sha512-5l4VyZR86LZ/lDxZTR6jqL8AFE2S0IFLMP26AbjsLVADxHdhB/c0GUsH+y39UfCi3dzz8OlQuPmnaJOMoDHQBA==} + dependencies: + queue-microtask: 1.2.3 + dev: true + + /safe-buffer/5.1.2: + resolution: {integrity: sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g==} + dev: true + + /safe-buffer/5.2.1: + resolution: {integrity: sha512-rp3So07KcdmmKbGvgaNxQSJr7bGVSVk5S9Eq1F+ppbRo70+YeaDxkw5Dd8NPN+GD6bjnYm2VuPuCXmpuYvmCXQ==} + dev: true + + /safer-buffer/2.1.2: + resolution: {integrity: sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg==} + dev: true + + /saxes/5.0.1: + resolution: {integrity: sha512-5LBh1Tls8c9xgGjw3QrMwETmTMVk0oFgvrFSvWx62llR2hcEInrKNZ2GZCCuuy2lvWrdl5jhbpeqc5hRYKFOcw==} + engines: {node: '>=10'} + dependencies: + xmlchars: 2.2.0 + dev: true + + /semver/5.7.1: + resolution: {integrity: sha512-sauaDf/PZdVgrLTNYHRtpXa1iRiKcaebiKQ1BJdpQlWH2lCvexQdX55snPFyK7QzpudqbCI0qXFfOasHdyNDGQ==} + hasBin: true + dev: true + + /semver/6.3.0: + resolution: {integrity: sha512-b39TBaTSfV6yBrapU89p5fKekE2m/NwnDocOVruQFS1/veMgdzuPcnOM34M6CwxW8jH/lxEa5rBoDeUwu5HHTw==} + hasBin: true + dev: true + + /semver/7.3.5: + resolution: {integrity: sha512-PoeGJYh8HK4BTO/a9Tf6ZG3veo/A7ZVsYrSA6J8ny9nb3B1VrpkuN+z9OE5wfE5p6H4LchYZsegiQgbJD94ZFQ==} + engines: {node: '>=10'} + hasBin: true + dependencies: + lru-cache: 6.0.0 + dev: true + + /send/0.17.2: + resolution: {integrity: sha512-UJYB6wFSJE3G00nEivR5rgWp8c2xXvJ3OPWPhmuteU0IKj8nKbG3DrjiOmLwpnHGYWAVwA69zmTm++YG0Hmwww==} + engines: {node: '>= 0.8.0'} + dependencies: + debug: 2.6.9 + depd: 1.1.2 + destroy: 1.0.4 + encodeurl: 1.0.2 + escape-html: 1.0.3 + etag: 1.8.1 + fresh: 0.5.2 + http-errors: 1.8.1 + mime: 1.6.0 + ms: 2.1.3 + on-finished: 2.3.0 + range-parser: 1.2.1 + statuses: 1.5.0 + dev: true + + /serve-static/1.14.2: + resolution: {integrity: sha512-+TMNA9AFxUEGuC0z2mevogSnn9MXKb4fa7ngeRMJaaGv8vTwnIEkKi+QGvPt33HSnf8pRS+WGM0EbMtCJLKMBQ==} + engines: {node: '>= 0.8.0'} + dependencies: + encodeurl: 1.0.2 + escape-html: 1.0.3 + parseurl: 1.3.3 + send: 0.17.2 + dev: true + + /setprototypeof/1.2.0: + resolution: {integrity: sha512-E5LDX7Wrp85Kil5bhZv46j8jOeboKq5JMmYM3gVGdGH8xFpPWXUMsNrlODCrkoxMEeNi/XZIwuRvY4XNwYMJpw==} + dev: true + + /shebang-command/2.0.0: + resolution: {integrity: sha512-kHxr2zZpYtdmrN1qDjrrX/Z1rR1kG8Dx+gkpK1G4eXmvXswmcE1hTWBWYUzlraYw1/yZp6YuDY77YtvbN0dmDA==} + engines: {node: '>=8'} + dependencies: + shebang-regex: 3.0.0 + dev: true + + /shebang-regex/3.0.0: + resolution: {integrity: sha512-7++dFhtcx3353uBaq8DDR4NuxBetBzC7ZQOhmTQInHEd6bSrXdiEyzCvG07Z44UYdLShWUyXt5M/yhz8ekcb1A==} + engines: {node: '>=8'} + dev: true + + /side-channel/1.0.4: + resolution: {integrity: sha512-q5XPytqFEIKHkGdiMIrY10mvLRvnQh42/+GoBlFW3b2LXLE2xxJpZFdm94we0BaoV3RwJyGqg5wS7epxTv0Zvw==} + dependencies: + call-bind: 1.0.2 + get-intrinsic: 1.1.1 + object-inspect: 1.12.0 + dev: false + + /signal-exit/3.0.6: + resolution: {integrity: sha512-sDl4qMFpijcGw22U5w63KmD3cZJfBuFlVNbVMKje2keoKML7X2UzWbc4XrmEbDwg0NXJc3yv4/ox7b+JWb57kQ==} + dev: true + + /sisteransi/1.0.5: + resolution: {integrity: sha512-bLGGlR1QxBcynn2d5YmDX4MGjlZvy2MRBDRNHLJ8VI6l6+9FUiyTFNJ0IveOSP0bcXgVDPRcfGqA0pjaqUpfVg==} + dev: true + + /slash/3.0.0: + resolution: {integrity: sha512-g9Q1haeby36OSStwb4ntCGGGaKsaVSjQ68fBxoQcutl5fS1vuY18H3wSt3jFyFtrkx+Kz0V1G85A4MyAdDMi2Q==} + engines: {node: '>=8'} + dev: true + + /source-map-support/0.5.21: + resolution: {integrity: sha512-uBHU3L3czsIyYXKX88fdrGovxdSCoTGDRZ6SYXtSRxLZUzHg5P/66Ht6uoUlHu9EZod+inXhKo3qQgwXUT/y1w==} + dependencies: + buffer-from: 1.1.2 + source-map: 0.6.1 + dev: true + + /source-map/0.5.7: + resolution: {integrity: sha1-igOdLRAh0i0eoUyA2OpGi6LvP8w=} + engines: {node: '>=0.10.0'} + dev: true + + /source-map/0.6.1: + resolution: {integrity: sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==} + engines: {node: '>=0.10.0'} + dev: true + + /source-map/0.7.3: + resolution: {integrity: sha512-CkCj6giN3S+n9qrYiBTX5gystlENnRW5jZeNLHpe6aue+SrHcG5VYwujhW9s4dY31mEGsxBDrHR6oI69fTXsaQ==} + engines: {node: '>= 8'} + dev: true + + /spdx-correct/3.1.1: + resolution: {integrity: sha512-cOYcUWwhCuHCXi49RhFRCyJEK3iPj1Ziz9DpViV3tbZOwXD49QzIN3MpOLJNxh2qwq2lJJZaKMVw9qNi4jTC0w==} + dependencies: + spdx-expression-parse: 3.0.1 + spdx-license-ids: 3.0.11 + dev: true + + /spdx-exceptions/2.3.0: + resolution: {integrity: sha512-/tTrYOC7PPI1nUAgx34hUpqXuyJG+DTHJTnIULG4rDygi4xu/tfgmq1e1cIRwRzwZgo4NLySi+ricLkZkw4i5A==} + dev: true + + /spdx-expression-parse/3.0.1: + resolution: {integrity: sha512-cbqHunsQWnJNE6KhVSMsMeH5H/L9EpymbzqTQ3uLwNCLZ1Q481oWaofqH7nO6V07xlXwY6PhQdQ2IedWx/ZK4Q==} + dependencies: + spdx-exceptions: 2.3.0 + spdx-license-ids: 3.0.11 + dev: true + + /spdx-license-ids/3.0.11: + resolution: {integrity: sha512-Ctl2BrFiM0X3MANYgj3CkygxhRmr9mi6xhejbdO960nF6EDJApTYpn0BQnDKlnNBULKiCN1n3w9EBkHK8ZWg+g==} + dev: true + + /split2/3.2.2: + resolution: {integrity: sha512-9NThjpgZnifTkJpzTZ7Eue85S49QwpNhZTq6GRJwObb6jnLFNGB7Qm73V5HewTROPyxD0C29xqmaI68bQtV+hg==} + dependencies: + readable-stream: 3.6.0 + dev: true + + /sprintf-js/1.0.3: + resolution: {integrity: sha1-BOaSb2YolTVPPdAVIDYzuFcpfiw=} + dev: true + + /stack-utils/2.0.5: + resolution: {integrity: sha512-xrQcmYhOsn/1kX+Vraq+7j4oE2j/6BFscZ0etmYg81xuM8Gq0022Pxb8+IqgOFUIaxHs0KaSb7T1+OegiNrNFA==} + engines: {node: '>=10'} + dependencies: + escape-string-regexp: 2.0.0 + dev: true + + /statuses/1.5.0: + resolution: {integrity: sha1-Fhx9rBd2Wf2YEfQ3cfqZOBR4Yow=} + engines: {node: '>= 0.6'} + dev: true + + /streamsearch/0.1.2: + resolution: {integrity: sha1-gIudDlb8Jz2Am6VzOOkpkZoanxo=} + engines: {node: '>=0.8.0'} + dev: true + + /string-length/4.0.2: + resolution: {integrity: sha512-+l6rNN5fYHNhZZy41RXsYptCjA2Igmq4EG7kZAYFQI1E1VTXarr6ZPXBg6eq7Y6eK4FEhY6AJlyuFIb/v/S0VQ==} + engines: {node: '>=10'} + dependencies: + char-regex: 1.0.2 + strip-ansi: 6.0.1 + dev: true + + /string-width/4.2.3: + resolution: {integrity: sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g==} + engines: {node: '>=8'} + dependencies: + emoji-regex: 8.0.0 + is-fullwidth-code-point: 3.0.0 + strip-ansi: 6.0.1 + dev: true + + /string_decoder/0.10.31: + resolution: {integrity: sha1-YuIDvEF2bGwoyfyEMB2rHFMQ+pQ=} + dev: true + + /string_decoder/1.1.1: + resolution: {integrity: sha512-n/ShnvDi6FHbbVfviro+WojiFzv+s8MPMHBczVePfUpDJLwoLT0ht1l4YwBCbi8pJAveEEdnkHyPyTP/mzRfwg==} + dependencies: + safe-buffer: 5.1.2 + dev: true + + /string_decoder/1.3.0: + resolution: {integrity: sha512-hkRX8U1WjJFd8LsDJ2yQ/wWWxaopEsABU1XfkM8A+j0+85JAGppt16cr1Whg6KIbb4okU6Mql6BOj+uup/wKeA==} + dependencies: + safe-buffer: 5.2.1 + dev: true + + /strip-ansi/6.0.1: + resolution: {integrity: sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==} + engines: {node: '>=8'} + dependencies: + ansi-regex: 5.0.1 + dev: true + + /strip-bom/4.0.0: + resolution: {integrity: sha512-3xurFv5tEgii33Zi8Jtp55wEIILR9eh34FAW00PZf+JnSsTmV/ioewSgQl97JHvgjoRGwPShsWm+IdrxB35d0w==} + engines: {node: '>=8'} + dev: true + + /strip-final-newline/2.0.0: + resolution: {integrity: sha512-BrpvfNAE3dcvq7ll3xVumzjKjZQ5tI1sEUIKr3Uoks0XUl45St3FlatVqef9prk4jRDzhW6WZg+3bk93y6pLjA==} + engines: {node: '>=6'} + dev: true + + /strip-indent/3.0.0: + resolution: {integrity: sha512-laJTa3Jb+VQpaC6DseHhF7dXVqHTfJPCRDaEbid/drOhgitgYku/letMUqOXFoWV0zIIUbjpdH2t+tYj4bQMRQ==} + engines: {node: '>=8'} + dependencies: + min-indent: 1.0.1 + dev: true + + /strip-json-comments/3.1.1: + resolution: {integrity: sha512-6fPc+R4ihwqP6N/aIv2f1gMH8lOVtWQHoqC4yK6oSDVVocumAsfCqjkXnqiYMhmMwS/mEHLp7Vehlt3ql6lEig==} + engines: {node: '>=8'} + dev: true + + /supports-color/5.5.0: + resolution: {integrity: sha512-QjVjwdXIt408MIiAqCX4oUKsgU2EqAGzs2Ppkm4aQYbjm+ZEWEcW4SfFNTr4uMNZma0ey4f5lgLrkB0aX0QMow==} + engines: {node: '>=4'} + dependencies: + has-flag: 3.0.0 + dev: true + + /supports-color/7.2.0: + resolution: {integrity: sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==} + engines: {node: '>=8'} + dependencies: + has-flag: 4.0.0 + dev: true + + /supports-color/8.1.1: + resolution: {integrity: sha512-MpUEN2OodtUzxvKQl72cUF7RQ5EiHsGvSsVG0ia9c5RbWGL2CI4C7EpPS8UTBIplnlzZiNuV56w+FuNxy3ty2Q==} + engines: {node: '>=10'} + dependencies: + has-flag: 4.0.0 + dev: true + + /supports-hyperlinks/2.2.0: + resolution: {integrity: sha512-6sXEzV5+I5j8Bmq9/vUphGRM/RJNT9SCURJLjwfOg51heRtguGWDzcaBlgAzKhQa0EVNpPEKzQuBwZ8S8WaCeQ==} + engines: {node: '>=8'} + dependencies: + has-flag: 4.0.0 + supports-color: 7.2.0 + dev: true + + /symbol-tree/3.2.4: + resolution: {integrity: sha512-9QNk5KwDF+Bvz+PyObkmSYjI5ksVUYtjW7AU22r2NKcfLJcXp96hkDWU3+XndOsUb+AQ9QhfzfCT2O+CNWT5Tw==} + dev: true + + /terminal-link/2.1.1: + resolution: {integrity: sha512-un0FmiRUQNr5PJqy9kP7c40F5BOfpGlYTrxonDChEZB7pzZxRNp/bt+ymiy9/npwXya9KH99nJ/GXFIiUkYGFQ==} + engines: {node: '>=8'} + dependencies: + ansi-escapes: 4.3.2 + supports-hyperlinks: 2.2.0 + dev: true + + /test-exclude/6.0.0: + resolution: {integrity: sha512-cAGWPIyOHU6zlmg88jwm7VRyXnMN7iV68OGAbYDk/Mh/xC/pzVPlQtY6ngoIH/5/tciuhGfvESU8GrHrcxD56w==} + engines: {node: '>=8'} + dependencies: + '@istanbuljs/schema': 0.1.3 + glob: 7.2.0 + minimatch: 3.0.4 + dev: true + + /text-extensions/1.9.0: + resolution: {integrity: sha512-wiBrwC1EhBelW12Zy26JeOUkQ5mRu+5o8rpsJk5+2t+Y5vE7e842qtZDQ2g1NpX/29HdyFeJ4nSIhI47ENSxlQ==} + engines: {node: '>=0.10'} + dev: true + + /text-table/0.2.0: + resolution: {integrity: sha1-f17oI66AUgfACvLfSoTsP8+lcLQ=} + dev: true + + /throat/6.0.1: + resolution: {integrity: sha512-8hmiGIJMDlwjg7dlJ4yKGLK8EsYqKgPWbG3b4wjJddKNwc7N7Dpn08Df4szr/sZdMVeOstrdYSsqzX6BYbcB+w==} + dev: true + + /through/2.3.8: + resolution: {integrity: sha1-DdTJ/6q8NXlgsbckEV1+Doai4fU=} + dev: true + + /through2/4.0.2: + resolution: {integrity: sha512-iOqSav00cVxEEICeD7TjLB1sueEL+81Wpzp2bY17uZjZN0pWZPuo4suZ/61VujxmqSGFfgOcNuTZ85QJwNZQpw==} + dependencies: + readable-stream: 3.6.0 + dev: true + + /tmpl/1.0.5: + resolution: {integrity: sha512-3f0uOEAQwIqGuWW2MVzYg8fV/QNnc/IpuJNG837rLuczAaLVHslWHZQj4IGiEl5Hs3kkbhwL9Ab7Hrsmuj+Smw==} + dev: true + + /to-fast-properties/2.0.0: + resolution: {integrity: sha1-3F5pjL0HkmW8c+A3doGk5Og/YW4=} + engines: {node: '>=4'} + dev: true + + /to-regex-range/5.0.1: + resolution: {integrity: sha512-65P7iz6X5yEr1cwcgvQxbbIw7Uk3gOy5dIdtZ4rDveLqhrdJP+Li/Hx6tyK0NEb+2GCyneCMJiGqrADCSNk8sQ==} + engines: {node: '>=8.0'} + dependencies: + is-number: 7.0.0 + dev: true + + /toidentifier/1.0.1: + resolution: {integrity: sha512-o5sSPKEkg/DIQNmH43V0/uerLrpzVedkUh8tGNvaeXpfpuwjKenlSox/2O/BTlZUtEe+JG7s5YhEz608PlAHRA==} + engines: {node: '>=0.6'} + dev: true + + /tough-cookie/4.0.0: + resolution: {integrity: sha512-tHdtEpQCMrc1YLrMaqXXcj6AxhYi/xgit6mZu1+EDWUn+qhUf8wMQoFIy9NXuq23zAwtcB0t/MjACGR18pcRbg==} + engines: {node: '>=6'} + dependencies: + psl: 1.8.0 + punycode: 2.1.1 + universalify: 0.1.2 + dev: true + + /tr46/2.1.0: + resolution: {integrity: sha512-15Ih7phfcdP5YxqiB+iDtLoaTz4Nd35+IiAv0kQ5FNKHzXgdWqPoTIqEDDJmXceQt4JZk6lVPT8lnDlPpGDppw==} + engines: {node: '>=8'} + dependencies: + punycode: 2.1.1 + dev: true + + /trim-newlines/3.0.1: + resolution: {integrity: sha512-c1PTsA3tYrIsLGkJkzHF+w9F2EyxfXGo4UyJc4pFL++FMjnq0HJS69T3M7d//gKrFKwy429bouPescbjecU+Zw==} + engines: {node: '>=8'} + dev: true + + /ts-jest/27.1.2_b65cae1b46840061996b6cc0ea16ca56: + resolution: {integrity: sha512-eSOiJOWq6Hhs6Khzk5wKC5sgWIXgXqOCiIl1+3lfnearu58Hj4QpE5tUhQcA3xtZrELbcvAGCsd6HB8OsaVaTA==} + engines: {node: ^10.13.0 || ^12.13.0 || ^14.15.0 || >=15.0.0} + hasBin: true + peerDependencies: + '@babel/core': '>=7.0.0-beta.0 <8' + '@types/jest': ^27.0.0 + babel-jest: '>=27.0.0 <28' + esbuild: ~0.14.0 + jest: ^27.0.0 + typescript: '>=3.8 <5.0' + peerDependenciesMeta: + '@babel/core': + optional: true + '@types/jest': + optional: true + babel-jest: + optional: true + esbuild: + optional: true + dependencies: + '@types/jest': 27.0.3 + bs-logger: 0.2.6 + fast-json-stable-stringify: 2.1.0 + jest: 27.4.5 + jest-util: 27.4.2 + json5: 2.2.0 + lodash.memoize: 4.1.2 + make-error: 1.3.6 + semver: 7.3.5 + typescript: 4.5.4 + yargs-parser: 20.2.9 + dev: true + + /ts-node/9.1.1_typescript@4.5.4: + resolution: {integrity: sha512-hPlt7ZACERQGf03M253ytLY3dHbGNGrAq9qIHWUY9XHYl1z7wYngSr3OQ5xmui8o2AaxsONxIzjafLUiWBo1Fg==} + engines: {node: '>=10.0.0'} + hasBin: true + peerDependencies: + typescript: '>=2.7' + dependencies: + arg: 4.1.3 + create-require: 1.1.1 + diff: 4.0.2 + make-error: 1.3.6 + source-map-support: 0.5.21 + typescript: 4.5.4 + yn: 3.1.1 + dev: true + + /tslib/1.14.1: + resolution: {integrity: sha512-Xni35NKzjgMrwevysHTCArtLDpPvye8zV/0E4EyYn43P7/7qvQwPh9BGkHewbMulVntbigmcT7rdX3BNo9wRJg==} + dev: true + + /tslib/2.3.1: + resolution: {integrity: sha512-77EbyPPpMz+FRFRuAFlWMtmgUWGe9UOG2Z25NqCwiIjRhOf5iKGuzSe5P2w1laq+FkRy4p+PCuVkJSGkzTEKVw==} + dev: true + + /tsutils/3.21.0_typescript@4.5.4: + resolution: {integrity: sha512-mHKK3iUXL+3UF6xL5k0PEhKRUBKPBCv/+RkEOpjRWxxx27KKRBmmA60A9pgOUvMi8GKhRMPEmjBRPzs2W7O1OA==} + engines: {node: '>= 6'} + peerDependencies: + typescript: '>=2.8.0 || >= 3.2.0-dev || >= 3.3.0-dev || >= 3.4.0-dev || >= 3.5.0-dev || >= 3.6.0-dev || >= 3.6.0-beta || >= 3.7.0-dev || >= 3.7.0-beta' + dependencies: + tslib: 1.14.1 + typescript: 4.5.4 + dev: true + + /type-check/0.3.2: + resolution: {integrity: sha1-WITKtRLPHTVeP7eE8wgEsrUg23I=} + engines: {node: '>= 0.8.0'} + dependencies: + prelude-ls: 1.1.2 + dev: true + + /type-check/0.4.0: + resolution: {integrity: sha512-XleUoc9uwGXqjWwXaUTZAmzMcFZ5858QA2vvx1Ur5xIcixXIP+8LnFDgRplU30us6teqdlskFfu+ae4K79Ooew==} + engines: {node: '>= 0.8.0'} + dependencies: + prelude-ls: 1.2.1 + dev: true + + /type-detect/4.0.8: + resolution: {integrity: sha512-0fr/mIH1dlO+x7TlcMy+bIDqKPsw/70tVyeHW787goQjhmqaZe10uwLujubK9q9Lg6Fiho1KUKDYz0Z7k7g5/g==} + engines: {node: '>=4'} + dev: true + + /type-fest/0.18.1: + resolution: {integrity: sha512-OIAYXk8+ISY+qTOwkHtKqzAuxchoMiD9Udx+FSGQDuiRR+PJKJHc2NJAXlbhkGwTt/4/nKZxELY1w3ReWOL8mw==} + engines: {node: '>=10'} + dev: true + + /type-fest/0.20.2: + resolution: {integrity: sha512-Ne+eE4r0/iWnpAxD852z3A+N0Bt5RN//NjJwRd2VFHEmrywxf5vsZlh4R6lixl6B+wz/8d+maTSAkN1FIkI3LQ==} + engines: {node: '>=10'} + dev: true + + /type-fest/0.21.3: + resolution: {integrity: sha512-t0rzBq87m3fVcduHDUFhKmyyX+9eo6WQjZvf51Ea/M0Q7+T374Jp1aUiyUl0GKxp8M/OETVHSDvmkyPgvX+X2w==} + engines: {node: '>=10'} + dev: true + + /type-fest/0.6.0: + resolution: {integrity: sha512-q+MB8nYR1KDLrgr4G5yemftpMC7/QLqVndBmEEdqzmNj5dcFOO4Oo8qlwZE3ULT3+Zim1F8Kq4cBnikNhlCMlg==} + engines: {node: '>=8'} + dev: true + + /type-fest/0.8.1: + resolution: {integrity: sha512-4dbzIzqvjtgiM5rw1k5rEHtBANKmdudhGyBEajN01fEyhaAIhsoKNy6y7+IN93IfpFtwY9iqi7kD+xwKhQsNJA==} + engines: {node: '>=8'} + dev: true + + /type-is/1.6.18: + resolution: {integrity: sha512-TkRKr9sUTxEH8MdfuCSP7VizJyzRNMjj2J2do2Jr3Kym598JVdEksuzPQCnlFPW4ky9Q+iA+ma9BGm06XQBy8g==} + engines: {node: '>= 0.6'} + dependencies: + media-typer: 0.3.0 + mime-types: 2.1.34 + dev: true + + /typedarray-to-buffer/3.1.5: + resolution: {integrity: sha512-zdu8XMNEDepKKR+XYOXAVPtWui0ly0NtohUscw+UmaHiAWT8hrV1rr//H6V+0DvJ3OQ19S979M0laLfX8rm82Q==} + dependencies: + is-typedarray: 1.0.0 + dev: true + + /typedarray/0.0.6: + resolution: {integrity: sha1-hnrHTjhkGHsdPUfZlqeOxciDB3c=} + dev: true + + /typescript/4.5.4: + resolution: {integrity: sha512-VgYs2A2QIRuGphtzFV7aQJduJ2gyfTljngLzjpfW9FoYZF6xuw1W0vW9ghCKLfcWrCFxK81CSGRAvS1pn4fIUg==} + engines: {node: '>=4.2.0'} + hasBin: true + dev: true + + /universalify/0.1.2: + resolution: {integrity: sha512-rBJeI5CXAlmy1pV+617WB9J63U6XcazHHF2f2dbJix4XzpUF0RS3Zbj0FGIOCAva5P/d/GBOYaACQ1w+0azUkg==} + engines: {node: '>= 4.0.0'} + dev: true + + /universalify/2.0.0: + resolution: {integrity: sha512-hAZsKq7Yy11Zu1DE0OzWjw7nnLZmJZYTDZZyEFHZdUhV8FkH5MCfoU1XMaxXovpyW5nq5scPqq0ZDP9Zyl04oQ==} + engines: {node: '>= 10.0.0'} + dev: true + + /unpipe/1.0.0: + resolution: {integrity: sha1-sr9O6FFKrmFltIF4KdIbLvSZBOw=} + engines: {node: '>= 0.8'} + dev: true + + /uri-js/4.4.1: + resolution: {integrity: sha512-7rKUyy33Q1yc98pQ1DAmLtwX109F7TIfWlW1Ydo8Wl1ii1SeHieeh0HHfPeL2fMXK6z0s8ecKs9frCuLJvndBg==} + dependencies: + punycode: 2.1.1 + dev: true + + /util-deprecate/1.0.2: + resolution: {integrity: sha1-RQ1Nyfpw3nMnYvvS1KKJgUGaDM8=} + dev: true + + /utils-merge/1.0.1: + resolution: {integrity: sha1-n5VxD1CiZ5R7LMwSR0HBAoQn5xM=} + engines: {node: '>= 0.4.0'} + dev: true + + /v8-compile-cache/2.3.0: + resolution: {integrity: sha512-l8lCEmLcLYZh4nbunNZvQCJc5pv7+RCwa8q/LdUx8u7lsWvPDKmpodJAJNwkAhJC//dFY48KuIEmjtd4RViDrA==} + dev: true + + /v8-to-istanbul/8.1.0: + resolution: {integrity: sha512-/PRhfd8aTNp9Ggr62HPzXg2XasNFGy5PBt0Rp04du7/8GNNSgxFL6WBTkgMKSL9bFjH+8kKEG3f37FmxiTqUUA==} + engines: {node: '>=10.12.0'} + dependencies: + '@types/istanbul-lib-coverage': 2.0.3 + convert-source-map: 1.8.0 + source-map: 0.7.3 + dev: true + + /validate-npm-package-license/3.0.4: + resolution: {integrity: sha512-DpKm2Ui/xN7/HQKCtpZxoRWBhZ9Z0kqtygG8XCgNQ8ZlDnxuQmWhj566j8fN4Cu3/JmbhsDo7fcAJq4s9h27Ew==} + dependencies: + spdx-correct: 3.1.1 + spdx-expression-parse: 3.0.1 + dev: true + + /validator/13.7.0: + resolution: {integrity: sha512-nYXQLCBkpJ8X6ltALua9dRrZDHVYxjJ1wgskNt1lH9fzGjs3tgojGSCBjmEPwkWS1y29+DrizMTW19Pr9uB2nw==} + engines: {node: '>= 0.10'} + dev: false + + /vary/1.1.2: + resolution: {integrity: sha1-IpnwLG3tMNSllhsLn3RSShj2NPw=} + engines: {node: '>= 0.8'} + dev: true + + /w3c-hr-time/1.0.2: + resolution: {integrity: sha512-z8P5DvDNjKDoFIHK7q8r8lackT6l+jo/Ye3HOle7l9nICP9lf1Ci25fy9vHd0JOWewkIFzXIEig3TdKT7JQ5fQ==} + dependencies: + browser-process-hrtime: 1.0.0 + dev: true + + /w3c-xmlserializer/2.0.0: + resolution: {integrity: sha512-4tzD0mF8iSiMiNs30BiLO3EpfGLZUT2MSX/G+o7ZywDzliWQ3OPtTZ0PTC3B3ca1UAf4cJMHB+2Bf56EriJuRA==} + engines: {node: '>=10'} + dependencies: + xml-name-validator: 3.0.0 + dev: true + + /walker/1.0.8: + resolution: {integrity: sha512-ts/8E8l5b7kY0vlWLewOkDXMmPdLcVV4GmOQLyxuSswIJsweeFZtAsMF7k1Nszz+TYBQrlYRmzOnr398y1JemQ==} + dependencies: + makeerror: 1.0.12 + dev: true + + /webidl-conversions/5.0.0: + resolution: {integrity: sha512-VlZwKPCkYKxQgeSbH5EyngOmRp7Ww7I9rQLERETtf5ofd9pGeswWiOtogpEO850jziPRarreGxn5QIiTqpb2wA==} + engines: {node: '>=8'} + dev: true + + /webidl-conversions/6.1.0: + resolution: {integrity: sha512-qBIvFLGiBpLjfwmYAaHPXsn+ho5xZnGvyGvsarywGNc8VyQJUMHJ8OBKGGrPER0okBeMDaan4mNBlgBROxuI8w==} + engines: {node: '>=10.4'} + dev: true + + /whatwg-encoding/1.0.5: + resolution: {integrity: sha512-b5lim54JOPN9HtzvK9HFXvBma/rnfFeqsic0hSpjtDbVxR3dJKLc+KB4V6GgiGOvl7CY/KNh8rxSo9DKQrnUEw==} + dependencies: + iconv-lite: 0.4.24 + dev: true + + /whatwg-mimetype/2.3.0: + resolution: {integrity: sha512-M4yMwr6mAnQz76TbJm914+gPpB/nCwvZbJU28cUD6dR004SAxDLOOSUaB1JDRqLtaOV/vi0IC5lEAGFgrjGv/g==} + dev: true + + /whatwg-url/8.7.0: + resolution: {integrity: sha512-gAojqb/m9Q8a5IV96E3fHJM70AzCkgt4uXYX2O7EmuyOnLrViCQlsEBmF9UQIu3/aeAIp2U17rtbpZWNntQqdg==} + engines: {node: '>=10'} + dependencies: + lodash: 4.17.21 + tr46: 2.1.0 + webidl-conversions: 6.1.0 + dev: true + + /which/2.0.2: + resolution: {integrity: sha512-BLI3Tl1TW3Pvl70l3yq3Y64i+awpwXqsGBYWkkqMtnbXgrMD+yj7rhW0kuEDxzJaYXGjEW5ogapKNMEKNMjibA==} + engines: {node: '>= 8'} + hasBin: true + dependencies: + isexe: 2.0.0 + dev: true + + /word-wrap/1.2.3: + resolution: {integrity: sha512-Hz/mrNwitNRh/HUAtM/VT/5VH+ygD6DV7mYKZAtHOrbs8U7lvPS6xf7EJKMF0uW1KJCl0H701g3ZGus+muE5vQ==} + engines: {node: '>=0.10.0'} + dev: true + + /wrap-ansi/7.0.0: + resolution: {integrity: sha512-YVGIj2kamLSTxw6NsZjoBxfSwsn0ycdesmc4p+Q21c5zPuZ1pl+NfxVdxPtdHvmNVOQ6XSYG4AUtyt/Fi7D16Q==} + engines: {node: '>=10'} + dependencies: + ansi-styles: 4.3.0 + string-width: 4.2.3 + strip-ansi: 6.0.1 + dev: true + + /wrappy/1.0.2: + resolution: {integrity: sha1-tSQ9jz7BqjXxNkYFvA0QNuMKtp8=} + dev: true + + /write-file-atomic/3.0.3: + resolution: {integrity: sha512-AvHcyZ5JnSfq3ioSyjrBkH9yW4m7Ayk8/9My/DD9onKeu/94fwrMocemO2QAJFAlnnDN+ZDS+ZjAR5ua1/PV/Q==} + dependencies: + imurmurhash: 0.1.4 + is-typedarray: 1.0.0 + signal-exit: 3.0.6 + typedarray-to-buffer: 3.1.5 + dev: true + + /ws/7.5.6: + resolution: {integrity: sha512-6GLgCqo2cy2A2rjCNFlxQS6ZljG/coZfZXclldI8FB/1G3CCI36Zd8xy2HrFVACi8tfk5XrgLQEk+P0Tnz9UcA==} + engines: {node: '>=8.3.0'} + peerDependencies: + bufferutil: ^4.0.1 + utf-8-validate: ^5.0.2 + peerDependenciesMeta: + bufferutil: + optional: true + utf-8-validate: + optional: true + dev: true + + /xml-name-validator/3.0.0: + resolution: {integrity: sha512-A5CUptxDsvxKJEU3yO6DuWBSJz/qizqzJKOMIfUJHETbBw/sFaDxgd6fxm1ewUaM0jZ444Fc5vC5ROYurg/4Pw==} + dev: true + + /xmlchars/2.2.0: + resolution: {integrity: sha512-JZnDKK8B0RCDw84FNdDAIpZK+JuJw+s7Lz8nksI7SIuU3UXJJslUthsi+uWBUYOwPFwW7W7PRLRfUKpxjtjFCw==} + dev: true + + /xtend/4.0.2: + resolution: {integrity: sha512-LKYU1iAXJXUgAXn9URjiu+MWhyUXHsvfp7mcuYm9dSUKK0/CjtrUwFAxD82/mCWbtLsGjFIad0wIsod4zrTAEQ==} + engines: {node: '>=0.4'} + dev: true + + /y18n/5.0.8: + resolution: {integrity: sha512-0pfFzegeDWJHJIAmTLRP2DwHjdF5s7jo9tuztdQxAhINCdvS+3nGINqPd00AphqJR/0LhANUS6/+7SCb98YOfA==} + engines: {node: '>=10'} + dev: true + + /yallist/4.0.0: + resolution: {integrity: sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A==} + dev: true + + /yaml/1.10.2: + resolution: {integrity: sha512-r3vXyErRCYJ7wg28yvBY5VSoAF8ZvlcW9/BwUzEtUsjvX/DKs24dIkuwjtuprwJJHsbyUbLApepYTR1BN4uHrg==} + engines: {node: '>= 6'} + dev: true + + /yargs-parser/20.2.9: + resolution: {integrity: sha512-y11nGElTIV+CT3Zv9t7VKl+Q3hTQoT9a1Qzezhhl6Rp21gJ/IVTW7Z3y9EWXhuUBC2Shnf+DX0antecpAwSP8w==} + engines: {node: '>=10'} + dev: true + + /yargs-parser/21.0.0: + resolution: {integrity: sha512-z9kApYUOCwoeZ78rfRYYWdiU/iNL6mwwYlkkZfJoyMR1xps+NEBX5X7XmRpxkZHhXJ6+Ey00IwKxBBSW9FIjyA==} + engines: {node: '>=12'} + dev: true + + /yargs/16.2.0: + resolution: {integrity: sha512-D1mvvtDG0L5ft/jGWkLpG1+m0eQxOfaBvTNELraWj22wSVUMWxZUvYgJYcKh6jGGIkJFhH4IZPQhR4TKpc8mBw==} + engines: {node: '>=10'} + dependencies: + cliui: 7.0.4 + escalade: 3.1.1 + get-caller-file: 2.0.5 + require-directory: 2.1.1 + string-width: 4.2.3 + y18n: 5.0.8 + yargs-parser: 20.2.9 + dev: true + + /yargs/17.3.0: + resolution: {integrity: sha512-GQl1pWyDoGptFPJx9b9L6kmR33TGusZvXIZUT+BOz9f7X2L94oeAskFYLEg/FkhV06zZPBYLvLZRWeYId29lew==} + engines: {node: '>=12'} + dependencies: + cliui: 7.0.4 + escalade: 3.1.1 + get-caller-file: 2.0.5 + require-directory: 2.1.1 + string-width: 4.2.3 + y18n: 5.0.8 + yargs-parser: 21.0.0 + dev: true + + /yn/3.1.1: + resolution: {integrity: sha512-Ux4ygGWsu2c7isFWe8Yu1YluJmqVhxqK2cLXNQA5AcC3QfbGNpM7fu0Y8b/z16pXLnFxZYvWhd3fhBY9DLmC6Q==} + engines: {node: '>=6'} + dev: true + + /yocto-queue/0.1.0: + resolution: {integrity: sha512-rVksvsnNCdJ/ohGc6xgPwyN8eheCxsiLM8mxuE/t/mOVqJewPuO1miLpTHQiRgTKCLexL4MeAFVagts7HmNZ2Q==} + engines: {node: '>=10'} + dev: true diff --git a/renovate.json b/renovate.json new file mode 100644 index 0000000..d370c85 --- /dev/null +++ b/renovate.json @@ -0,0 +1,19 @@ +{ + "extends": [ + "config:base" + ], + "baseBranches": ["master"], + "automerge": true, + "major": { + "automerge": false + }, + "packageRules": [ + { + "packageNames": ["@types/node"], + "allowedVersions": "<15" + } + ], + "schedule": ["after 1am and before 7am"], + "timezone": "Europe/Paris", + "prHourlyLimit": 0 +} \ No newline at end of file diff --git a/src/baseService.ts b/src/baseService.ts index 957612d..f76e40d 100644 --- a/src/baseService.ts +++ b/src/baseService.ts @@ -1,431 +1,295 @@ -import axios, { AxiosRequestConfig, AxiosResponse, AxiosInstance } from "axios"; +import axios, { AxiosRequestConfig, AxiosResponse, AxiosResponseHeaders } from "axios"; import FormData from "form-data"; -import { DataResolverFactory } from "./dataResolver"; -import { HttpMethod } from "./constants"; -import { HttpMethodOptions } from "./decorators"; +import { + CONTENT_TYPE, + CONTENT_TYPE_HEADER, + DataType, + HttpMethod, + HttpMethodOptions, + MethodMetadata, + QueriesParamType, + ValidationErrors, +} from "./constants"; import { isNode } from "./util"; +import { RetrofitHttpClient } from "./http.client"; +import { ServiceBuilder } from "./service.builder"; +import { ServiceMetaData } from "./metadata"; +import { requestHeadersResolver } from "./request-resolvers/headers-request-resolver"; +import { requestQueryParamsResolver } from "./request-resolvers/query-params-request-resolver"; +import { requestBodyResolver } from "./request-resolvers/body-request-resolver"; +import { validateSync } from "class-validator"; +import { plainToClass } from "class-transformer"; +import { ValidationError } from "class-validator/types/validation/ValidationError"; +import { makeConfig } from "./request-config-builder"; axios.defaults.withCredentials = true; -export interface Response extends AxiosResponse { } +export type HttpApiResponse = Awaited>>; -const NON_HTTP_REQUEST_PROPERTY_NAME = "__nonHTTPRequestMethod__"; +export type ApiResponse = HttpApiResponse & void; +export type ApiResponseBody = Awaited> & void; -export const nonHTTPRequestMethod = (target: any, methodName: string) => { - const descriptor = { - value: true, - writable: false, - }; - Object.defineProperty(target[methodName], NON_HTTP_REQUEST_PROPERTY_NAME, descriptor); +export const ErrorMessages = { + NO_HTTP_METHOD: "No http method for method (Add @GET / @POST ...)", + + EMPTY_HEADER_KEY: "Header key can't be empty", + WRONG_HEADERS_PROPERTY_TYPE: "Header's property can be only number / string / boolean", + WRONG_HEADER_TYPE: "Header type can be only number / string / boolean", + + EMPTY_QUERY_KEY: "Query key can't be empty", + WRONG_QUERY_TYPE: "Query type can be only number / string / boolean", + WRONG_QUERY_MAP_PROPERTY_TYPE: "QueryMap should only contain number / string / boolean", + + EMPTY_FIELD_KEY: "Field key can't be empty", + EMPTY_PART_KEY: "Part key can't be empty", + + FIELD_WITH_ARRAY_BODY: "Field can't be used when array passed in @Body", + FIELD_MAP_FOR_ARRAY_BODY: "@FieldMap can't be used with array @Body", + FIELD_MAP_PARAM_TYPE: "@FieldMap should be object", + + MULTIPART_WITH_ARRAY_BODY: "@Multipart can't be used with array @Body", + MULTIPART_PARAM_WRONG_TYPE: "Multipart param should be PartDescriptor", + + VALIDATION_NOT_OBJECT: `Response is not an object or array: "{}"`, + + __TEST_NO_REQUESTS_IN_HISTORY: "No requests in history", }; export class BaseService { - public __meta__: any; - private _endpoint: string; - private _httpClient: HttpClient; - private _methodMap: Map; - private _timeout: number; - - constructor(serviceBuilder: ServiceBuilder) { + // Generated before constructor call from decorators + // @ts-ignore + private __meta__: ServiceMetaData; + private readonly _endpoint: string; + private readonly _httpClient: RetrofitHttpClient; + public readonly __requestsHistory: AxiosResponse[] = []; + + constructor(private serviceBuilder: ServiceBuilder) { this._endpoint = serviceBuilder.endpoint; - this._httpClient = new HttpClient(serviceBuilder); - this._methodMap = new Map(); - this._timeout = serviceBuilder.timeout; + this._httpClient = new RetrofitHttpClient(serviceBuilder); const methodNames = this._getInstanceMethodNames(); - methodNames.forEach((methodName) => { - this._methodMap[methodName] = this[methodName]; - }); - const self = this; for (const methodName of methodNames) { + const get = () => { + return (...args: unknown[]) => { + if (serviceBuilder.withInlineResponseBody) { + return this._wrapToInlinedResponse(methodName, args); + } else { + return this._wrapToAxiosResponse(methodName, args); + } + }; + }; + const descriptor = { enumerable: true, configurable: true, - get(): Function { - const method = self._methodMap[methodName]; - const methodOriginalDescriptor = Object.getOwnPropertyDescriptor(method, NON_HTTP_REQUEST_PROPERTY_NAME); - if (methodOriginalDescriptor && methodOriginalDescriptor.value === true) { - return method; - } - return (...args: any[]) => { - return self._wrap(methodName, args); - }; - }, + get, }; Object.defineProperty(this, methodName, descriptor); } } - @nonHTTPRequestMethod - public isClientStandalone(): boolean { - return this._httpClient.isStandalone(); + __getServiceMetadata() { + if (!this.__meta__) this.__meta__ = new ServiceMetaData(); + return this.__meta__; } - @nonHTTPRequestMethod - public useRequestInterceptor(interceptor: RequestInterceptorFunction): number { - return this._httpClient.useRequestInterceptor(interceptor); + async __performRequest( + methodName: keyof this, + args: unknown[] = [], + ): Promise> { + return await this._wrapToAxiosResponse(methodName as string, args); } - @nonHTTPRequestMethod - public useResponseInterceptor(interceptor: ResponseInterceptorFunction): number { - return this._httpClient.useResponseInterceptor(interceptor); - } + // For testing purposes + __getLastRequest() { + const last = this.__requestsHistory.pop(); + if (last) return last; - @nonHTTPRequestMethod - public ejectRequestInterceptor(id: number): void { - this._httpClient.ejectRequestInterceptor(id); + throw new Error(ErrorMessages.__TEST_NO_REQUESTS_IN_HISTORY); } - @nonHTTPRequestMethod - public ejectResponseInterceptor(id: number): void { - this._httpClient.ejectResponseInterceptor(id); - } + private _getInstanceMethodNames(): string[] { + function props(obj: unknown) { + const p = []; + for (; obj != null; obj = Object.getPrototypeOf(obj)) { + const op = Object.getOwnPropertyNames(obj); + for (let i = 0; i < op.length; i++) if (p.indexOf(op[i]) == -1) p.push(op[i]); + } + return p; + } - @nonHTTPRequestMethod - public setEndpoint(endpoint: string): void { - this._endpoint = endpoint; + return props(this) + .sort() + .filter((e, i, arr) => { + return e !== arr[i + 1] && this[e] && typeof this[e] === "function" && this.__meta__.methodMetadata.has(e); + }); } - @nonHTTPRequestMethod - private _getInstanceMethodNames(): string[] { - let properties: string[] = []; - let obj = this; - do { - properties = properties.concat(Object.getOwnPropertyNames(obj)); - obj = Object.getPrototypeOf(obj); - } while (obj); - return properties.sort().filter((e, i, arr) => { - return e !== arr[i + 1] && this[e] && typeof this[e] === "function"; - }); - } + private async _wrapToAxiosResponse( + methodName: string, + args: unknown[], + ): Promise> { + const metadata = this.__meta__.getMetadata(methodName); + this._resolveConverterAndValidator(methodName, metadata); - @nonHTTPRequestMethod - private _wrap(methodName: string, args: any[]): Promise { const { url, method, headers, query, data } = this._resolveParameters(methodName, args); - const config = this._makeConfig(methodName, url, method, headers, query, data); - return this._httpClient.sendRequest(config); - } + const config = makeConfig(metadata, this.serviceBuilder, methodName, url, method, headers, query, data); - @nonHTTPRequestMethod - private _resolveParameters(methodName: string, args: any[]): any { - const url = this._resolveUrl(methodName, args); - const method = this._resolveHttpMethod(methodName); - let headers = this._resolveHeaders(methodName, args); - const query = this._resolveQuery(methodName, args); - const data = this._resolveData(methodName, headers, args); - if (headers["content-type"] && headers["content-type"].indexOf("multipart/form-data") !== -1 && isNode) { - headers = { ...headers, ...(data as FormData).getHeaders() }; - } - return { url, method, headers, query, data }; - } + const result = await this._httpClient.sendRequest(config); - @nonHTTPRequestMethod - private _makeConfig(methodName: string, url: string, method: HttpMethod, headers: any, query: any, data: any) - : AxiosRequestConfig { - let config: AxiosRequestConfig = { - url, - method, - headers, - params: query, - data, - }; - // response type - if (this.__meta__[methodName].responseType) { - config.responseType = this.__meta__[methodName].responseType; - } - // request transformer - if (this.__meta__[methodName].requestTransformer) { - config.transformRequest = this.__meta__[methodName].requestTransformer; - } - // response transformer - if (this.__meta__[methodName].responseTransformer) { - config.transformResponse = this.__meta__[methodName].responseTransformer; - } - // timeout - config.timeout = this.__meta__[methodName].timeout || this._timeout; - // mix in config set by @Config - config = { - ...config, - ...this.__meta__[methodName].config, - }; - return config; - } + this._responseValidator(result, methodName, metadata); - @nonHTTPRequestMethod - private _resolveUrl(methodName: string, args: any[]): string { - const meta = this.__meta__; - const endpoint = this._endpoint; - const basePath = meta.basePath; - const path = meta[methodName].path; - const pathParams = meta[methodName].pathParams; - const options = meta[methodName].options || {}; - let url = this.makeURL(endpoint, basePath, path, options); - for (const pos in pathParams) { - if (pathParams[pos]) { - url = url.replace(new RegExp(`\{${pathParams[pos]}}`), args[pos]); - } - } - return url; - } + this._saveToRequestHistory(result); - @nonHTTPRequestMethod - private makeURL(endpoint: string, basePath: string, path: string, options: HttpMethodOptions): string { - const isAbsoluteURL = /^([a-z][a-z\d\+\-\.]*:)?\/\//i.test(path); - if (isAbsoluteURL) { - return path; - } - if (options.ignoreBasePath) { - return [endpoint, path].join(""); - } - return [endpoint, basePath, path].join(""); + return result; } - @nonHTTPRequestMethod - private _resolveHttpMethod(methodName: string): HttpMethod { - const meta = this.__meta__; - return meta[methodName].method; + private _wrapToInlinedResponse>(methodName: string, args: unknown[]): Promise { + return this._wrapToAxiosResponse(methodName, args).then((r) => r.data); } - @nonHTTPRequestMethod - private _resolveHeaders(methodName: string, args: any[]): any { - const meta = this.__meta__; - const headers = meta[methodName].headers || {}; - const headerParams = meta[methodName].headerParams; - for (const pos in headerParams) { - if (headerParams[pos]) { - headers[headerParams[pos]] = args[pos]; - } - } - const headerMapIndex = meta[methodName].headerMapIndex; - if (headerMapIndex >= 0) { - for (const key in args[headerMapIndex]) { - if (args[headerMapIndex][key]) { - headers[key] = args[headerMapIndex][key]; - } - } - } - return headers; - } + private _saveToRequestHistory(result: AxiosResponse) { + if (!this.serviceBuilder.shouldSaveRequestHistory) return; - @nonHTTPRequestMethod - private _resolveQuery(methodName: string, args: any[]): any { - const meta = this.__meta__; - const query = meta[methodName].query || {}; - const queryParams = meta[methodName].queryParams; - for (const pos in queryParams) { - if (queryParams[pos]) { - query[queryParams[pos]] = args[pos]; - } - } - const queryMapIndex = meta[methodName].queryMapIndex; - if (queryMapIndex >= 0) { - for (const key in args[queryMapIndex]) { - if (args[queryMapIndex][key]) { - query[key] = args[queryMapIndex][key]; - } - } - } - return query; + this.__requestsHistory.push(result); } - @nonHTTPRequestMethod - private _resolveData(methodName: string, headers: any, args: any[]): any { - const meta = this.__meta__; - const bodyIndex = meta[methodName].bodyIndex; - const fields = meta[methodName].fields || {}; - const parts = meta[methodName].parts || {}; - const fieldMapIndex = meta[methodName].fieldMapIndex; - let data = {}; - - // @Body - if (bodyIndex >= 0) { - if (Array.isArray(args[bodyIndex])) { - data = args[bodyIndex]; - } else { - data = { ...data, ...args[bodyIndex] }; - } - } + private _responseValidator>( + response: AxiosResponse, + methodName: string, + metadata: MethodMetadata, + ) { + if (!response || !this.serviceBuilder.responseValidator || !metadata.convertTo) return; - // @Field - if (Object.keys(fields).length > 0) { - const reqData = {}; - for (const pos in fields) { - if (fields[pos]) { - reqData[fields[pos]] = args[pos]; - } - } - data = { ...data, ...reqData }; - } + const data = response.data; - // @FieldMap - if (fieldMapIndex >= 0) { - const reqData = {}; - for (const key in args[fieldMapIndex]) { - if (args[fieldMapIndex][key]) { - reqData[key] = args[fieldMapIndex][key]; - } - } - data = { ...data, ...reqData }; + let errors: ValidationError[] = []; + if (Array.isArray(data)) { + errors = Array.prototype.concat.apply( + [], + data.map((e) => validateSync(e)), + ); + } else if (typeof data === "object") { + errors = validateSync(data as Record); + } else { + throw new Error(ErrorMessages.VALIDATION_NOT_OBJECT.replace("{}", "" + data)); } - // @MultiPart - if (Object.keys(parts).length > 0) { - const reqData = {}; - for (const pos in parts) { - if (parts[pos]) { - reqData[parts[pos]] = args[pos]; - } - } - data = { ...data, ...reqData }; - } - - const contentType = headers["content-type"] || "application/json"; - const dataResolverFactory = new DataResolverFactory(); - const dataResolver = dataResolverFactory.createDataResolver(contentType); - return dataResolver.resolve(headers, data); + if (errors.length !== 0) throw new ValidationErrors(errors, JSON.stringify(data)); } -} - -export type RequestInterceptorFunction = - (value: AxiosRequestConfig) => AxiosRequestConfig | Promise; -export type ResponseInterceptorFunction = - (value: AxiosResponse) => AxiosResponse | Promise>; -abstract class BaseInterceptor { - public onRejected(error: any) { return; } -} + private _resolveConverterAndValidator(methodName: string, metadata: MethodMetadata) { + if (metadata.convertTo) { + const convert = (data: Record) => { + if (!metadata.convertTo) throw new Error("metadata.convertTo null???"); -export abstract class RequestInterceptor extends BaseInterceptor { - public abstract onFulfilled(value: AxiosRequestConfig): AxiosRequestConfig | Promise; -} - -export abstract class ResponseInterceptor extends BaseInterceptor { - public abstract onFulfilled(value: AxiosResponse): AxiosResponse | Promise>; -} + if (typeof data !== "object") return data; -export class ServiceBuilder { - private _endpoint: string = ""; - private _standalone: boolean | AxiosInstance = false; - private _requestInterceptors: Array = []; - private _responseInterceptors: Array = []; - private _timeout: number = 60000; + return plainToClass(metadata.convertTo, data); + }; - public build(service: new (builder: ServiceBuilder) => T): T { - return new service(this); - } + metadata.responseTransformer.push((data) => { + if (!data) return data; - public setEndpoint(endpoint: string): ServiceBuilder { - this._endpoint = endpoint; - return this; + if (Array.isArray(data)) { + return data.map(convert); + } else { + return convert(data); + } + }); + } } - // 单例模式 - public setStandalone(standalone: boolean | AxiosInstance): ServiceBuilder { - this._standalone = standalone; - return this; - } + private _resolveParameters( + methodName: string, + args: unknown[], + ): { + url: string; + method: HttpMethod; + headers: AxiosResponseHeaders; + query: QueriesParamType; + data: DataType | DataType[]; + } { + const metadata = this.__meta__.getMetadata(methodName); - // 插入请求拦截器 - public setRequestInterceptors(...interceptors: Array) - : ServiceBuilder { - this._requestInterceptors.push(...interceptors); - return this; + const url = this._resolveUrl(methodName, args); + const method = this._resolveHttpMethod(methodName); + let headers = requestHeadersResolver(metadata, methodName, args); + const query = requestQueryParamsResolver(metadata, methodName, args); + const data = requestBodyResolver(metadata, methodName, headers, args); + if ( + headers[CONTENT_TYPE_HEADER] && + (headers[CONTENT_TYPE_HEADER] as string).indexOf(CONTENT_TYPE.MULTIPART_FORM_DATA) !== -1 && + isNode + ) { + headers = { ...headers, ...(data as FormData).getHeaders() }; + } + return { url, method, headers, query, data }; } - // 插入应答拦截器 - public setResponseInterceptors(...interceptors: Array) - : ServiceBuilder { - this._responseInterceptors.push(...interceptors); - return this; - } + private _resolveUrl(methodName: string, args: unknown[]): string { + const metadata = this.__meta__.getMetadata(methodName); - public setTimeout(timeout: number): ServiceBuilder { - this._timeout = timeout; - return this; - } + const endpoint = this._endpoint; + const pathParams = metadata.pathParams; + let url = this.makeURL(endpoint, this.__meta__.basePath, metadata.path, metadata.options); - get endpoint(): string { - return this._endpoint; - } + Object.entries(pathParams).map((e) => { + const [idx, pathParamName] = e; + url = url.replace(new RegExp(`{${pathParamName}}`), args[idx]); + }); - get standalone(): boolean | AxiosInstance { - return this._standalone; + return url; } - get requestInterceptors(): Array { - return this._requestInterceptors; - } + private makeURL(endpoint: string, basePath?: string, path?: string, options?: HttpMethodOptions): string { + const buf = [endpoint]; - get responseInterceptors(): Array { - return this._responseInterceptors; - } + if (basePath) buf.push(basePath); - get timeout(): number { - return this._timeout; - } -} + if (path) { + const isAbsoluteURL = /^([a-z][a-z\d+\-.]*:)?\/\//i.test(path); + if (isAbsoluteURL) { + return path; + } -class HttpClient { - private axios: AxiosInstance = axios; - private standalone: boolean = false; + if (options && options.ignoreBasePath) { + return [endpoint, path].join(""); + } - constructor(builder: ServiceBuilder) { - if (builder.standalone === true) { - this.axios = axios.create(); - this.standalone = true; - } else if (typeof builder.standalone === "function") { - this.axios = builder.standalone; + buf.push(path); } - builder.requestInterceptors.forEach((interceptor) => { - if (interceptor instanceof RequestInterceptor) { - this.axios.interceptors.request.use( - interceptor.onFulfilled.bind(interceptor), - interceptor.onRejected.bind(interceptor), - ); - } else { - this.axios.interceptors.request.use(interceptor); - } - }); - - builder.responseInterceptors.forEach((interceptor) => { - if (interceptor instanceof ResponseInterceptor) { - this.axios.interceptors.response.use( - interceptor.onFulfilled.bind(interceptor), - interceptor.onRejected.bind(interceptor), - ); - } else { - this.axios.interceptors.response.use(interceptor); - } - }); + return buf.join(""); } - public isStandalone(): boolean { - return this.standalone; - } + private _resolveHttpMethod(methodName: string): HttpMethod { + const httpMethod = this.__meta__.getMetadata(methodName).httpMethod; + if (!httpMethod) throw new Error(ErrorMessages.NO_HTTP_METHOD); - public async sendRequest(config: AxiosRequestConfig): Promise { - try { - return await this.axios(config); - } catch (err) { - throw err; - } + return httpMethod; } +} - public useRequestInterceptor(interceptor: RequestInterceptorFunction): number { - return this.axios.interceptors.request.use(interceptor); - } +export type RequestInterceptorFunction = ( + value: AxiosRequestConfig, +) => AxiosRequestConfig | Promise; - public useResponseInterceptor(interceptor: ResponseInterceptorFunction): number { - return this.axios.interceptors.response.use(interceptor); - } +export type ResponseInterceptorFunction = Record> = ( + value: AxiosResponse, +) => AxiosResponse | Promise>; - public ejectRequestInterceptor(id: number): void { - this.axios.interceptors.request.eject(id); +abstract class BaseInterceptor { + public onRejected(error: Error) { + throw error; } +} - public ejectResponseInterceptor(id: number): void { - this.axios.interceptors.response.eject(id); - } +export abstract class RequestInterceptor extends BaseInterceptor { + public abstract onFulfilled(value: AxiosRequestConfig): AxiosRequestConfig | Promise; +} + +export abstract class ResponseInterceptor extends BaseInterceptor { + public abstract onFulfilled(value: AxiosResponse): AxiosResponse | Promise>; } diff --git a/src/constants.ts b/src/constants.ts index f64346f..a15e898 100644 --- a/src/constants.ts +++ b/src/constants.ts @@ -1,17 +1,80 @@ -import { Method } from "axios"; +import { + AxiosRequestConfig, + AxiosRequestHeaders, + AxiosRequestTransformer, + AxiosResponseTransformer, + Method, + ResponseType as AxiosResponseType, +} from "axios"; +import { ValidationError } from "class-validator"; + +export enum ValidationMethod { + CLASS_VALIDATOR = "CLASS_VALIDATOR", +} + +export class ValidationErrors extends Error { + constructor(public errors: ValidationError[], public response: string) { + super(`Response:\n${response}\n\nHas validation errors: ${errors.length}\n${errors.map((e) => e.toString())}`); + } +} + +export type ResponseConvertTo = new () => void; +export type DataType = Record | unknown; export type HttpMethod = Method; -export const DATA_CONTENT_TYPES = [ - "application/x-www-form-urlencoded", - "multipart/form-data", - "application/json", - "text/xml", -]; - -export enum HttpContentType { - urlencoded = "application/x-www-form-urlencoded", - multipart = "multipart/form-data", - json = "application/json", - xml = "text/xml", +export const CONTENT_TYPE_HEADER = "Content-Type"; +export const CHARSET_UTF_8 = "charset=utf-8"; +export type Primitive = string | number | boolean; + +export enum CONTENT_TYPE { + FORM_URL_ENCODED = "application/x-www-form-urlencoded", + MULTIPART_FORM_DATA = "multipart/form-data", + APPLICATION_JSON = "application/json", + XML = "text/xml", + HTML = "text/html", +} + +export type QueriesParamType = { + [x: string]: Primitive; +}; + +export interface TransformerType { + (data: T, headers?: AxiosRequestHeaders): T; +} + +export type MethodMetadata = { + config?: Partial; + responseType?: AxiosResponseType; + requestTransformer: AxiosRequestTransformer[]; + responseTransformer: AxiosResponseTransformer[]; + timeout?: number; + convertTo?: ResponseConvertTo; + path?: string; + pathParams: { [key: number]: string }; + //basePath?: string; + options?: HttpMethodOptions; + httpMethod?: HttpMethod; + bodyIndex?: number; + fields: { [key: number]: string }; + parts: { [key: number]: string }; + fieldMapIndex?: number; + + headers: AxiosRequestHeaders; + headerParams: { [key: number]: string }; + headerMapIndex?: number; + query: QueriesParamType; + queryMapIndex?: number; + queryParams: { [key: number]: string | number }; + responseStatus?: number; +}; + +export type HttpMethodOptions = { + ignoreBasePath?: boolean; + convertTo?: ResponseConvertTo; +}; + +export interface PartDescriptor { + value: T; + filename?: string; } diff --git a/src/dataResolver.ts b/src/dataResolver.ts index dfbaa0a..8d9492b 100644 --- a/src/dataResolver.ts +++ b/src/dataResolver.ts @@ -1,23 +1,21 @@ import * as qs from "qs"; import FormData from "form-data"; -import { DATA_CONTENT_TYPES } from "./constants"; +import { CONTENT_TYPE, CONTENT_TYPE_HEADER, DataType } from "./constants"; +import { ErrorMessages } from "./baseService"; +import { AxiosRequestHeaders } from "axios"; export class BaseDataResolver { - public resolve(headers: any, data: any): any { + public resolve(headers: AxiosRequestHeaders, data: DataType): DataType { throw new Error("Can not call this method in BaseDataResolver."); } } export class FormUrlencodedResolver extends BaseDataResolver { - constructor() { - super(); - } - - public resolve(headers: any, data: any): any { - const deepStringify = (obj: any) => { + public resolve(headers: AxiosRequestHeaders, data: DataType): DataType { + const deepStringify = (obj: Record) => { const res = {}; for (const key in obj) { - if (!obj.hasOwnProperty(key)) { + if (!Object.prototype.hasOwnProperty.call(obj, key)) { continue; } if (typeof obj[key] === "object") { @@ -28,73 +26,72 @@ export class FormUrlencodedResolver extends BaseDataResolver { } return qs.stringify(res); }; - return deepStringify(data); + return deepStringify(data as Record); } } export class MultiPartResolver extends BaseDataResolver { - constructor() { - super(); - } - - public resolve(headers: any, data: any): any { + public resolve(headers: AxiosRequestHeaders, data: Record): FormData { const formData = new FormData(); - for (const key in data) { - if (data[key].filename) { - formData.append(key, data[key].value, { filename: data[key].filename }); + Object.entries(data).map((e) => { + if (typeof e[1] !== "object") throw new Error(ErrorMessages.MULTIPART_PARAM_WRONG_TYPE); + const [key] = e; + const value = e[1] as Record; + + if (value && "filename" in value) { + formData.append(key, value.value, { filename: value.filename as string }); } else { - if (Array.isArray(data[key].value)) { - for (const element of data[key].value) { + if (Array.isArray(value.value)) { + for (const element of value.value) { formData.append(key, element); } } else { - formData.append(key, data[key].value); + formData.append(key, value.value); } } - } + }); return formData; } } export class JsonResolver extends BaseDataResolver { - constructor() { - super(); - } - - public resolve(headers: any, data: any): any { - return data; + public resolve(headers: AxiosRequestHeaders, data: DataType): DataType { + return data && typeof data === "string" ? JSON.parse(data) : data; } } export class TextXmlResolver extends BaseDataResolver { - constructor() { - super(); - } - - public resolve(headers: any, data: any): any { + public resolve(headers: AxiosRequestHeaders, data: DataType): DataType { return data; } } -const dataResolverMap: Map = new Map(); -dataResolverMap.set("application/x-www-form-urlencoded", FormUrlencodedResolver); -dataResolverMap.set("multipart/form-data", MultiPartResolver); -dataResolverMap.set("application/json", JsonResolver); -dataResolverMap.set("text/xml", TextXmlResolver); +const dataResolverMap = new Map(); +dataResolverMap.set(CONTENT_TYPE.FORM_URL_ENCODED, FormUrlencodedResolver); +dataResolverMap.set(CONTENT_TYPE.MULTIPART_FORM_DATA, MultiPartResolver); +dataResolverMap.set(CONTENT_TYPE.APPLICATION_JSON, JsonResolver); +dataResolverMap.set(CONTENT_TYPE.XML, TextXmlResolver); +dataResolverMap.set(CONTENT_TYPE.HTML, TextXmlResolver); export class DataResolverFactory { - public createDataResolver(contentType: string): BaseDataResolver { + public static createDataResolver(contentType: string): BaseDataResolver; + public static createDataResolver(headers: AxiosRequestHeaders): BaseDataResolver; + + public static createDataResolver(arg: string | AxiosRequestHeaders): BaseDataResolver { + const argElement = arg[CONTENT_TYPE_HEADER] || arg[CONTENT_TYPE_HEADER.toLocaleLowerCase()]; + const contentType = typeof arg === "string" ? arg : (argElement as string); + const contentTypeLowCased = contentType.toLowerCase(); - for (const dataContentType of DATA_CONTENT_TYPES) { + for (const dataContentType of Object.values(CONTENT_TYPE)) { if (contentTypeLowCased.includes(dataContentType)) { const resolverCls = this._getDataResolverCls(dataContentType); return new resolverCls(); } } - return new (this._getDataResolverCls("application/json"))(); + return new (this._getDataResolverCls(CONTENT_TYPE.APPLICATION_JSON))(); } - private _getDataResolverCls(dataContentType: string): typeof BaseDataResolver { + private static _getDataResolverCls(dataContentType: string): typeof BaseDataResolver { return dataResolverMap.get(dataContentType) || JsonResolver; } } diff --git a/src/decorators.ts b/src/decorators.ts index 32d8381..5856a8c 100644 --- a/src/decorators.ts +++ b/src/decorators.ts @@ -1,422 +1,290 @@ +import { AxiosRequestConfig, AxiosRequestHeaders, ResponseType as AxiosResponseType } from "axios"; import { - ResponseType as AxiosResponseType, - AxiosTransformer, AxiosRequestConfig, -} from "axios"; -import { HttpMethod } from "./constants"; + CHARSET_UTF_8, + CONTENT_TYPE, + CONTENT_TYPE_HEADER, + DataType, + HttpMethod, + HttpMethodOptions, + MethodMetadata, + QueriesParamType, + ResponseConvertTo, + TransformerType, +} from "./constants"; import { BaseService } from "./baseService"; -interface Headers { - [x: string]: string | number; -} - -interface Query { - [x: string]: string | number | boolean; -} - -export interface PartDescriptor { - value: T; - filename?: string; -} - -export interface HttpMethodOptions { - ignoreBasePath?: boolean; -} - -/** - * Ensure the `__meta__` attribute is in the target object and `methodName` has been initialized. - * @param target - * @param methodName - */ -const ensureMeta = (target: BaseService, methodName: string) => { - if (!target.__meta__) { - target.__meta__ = {}; - } - if (!target.__meta__[methodName]) { - target.__meta__[methodName] = {}; - } -}; - /** * Register HTTP method and path in API method. - * @param method - * @param url - * @param options */ -const registerMethod = (method: HttpMethod, url: string, options?: HttpMethodOptions) => { - return (target: BaseService, methodName: string, descriptor: PropertyDescriptor) => { - ensureMeta(target, methodName); - target.__meta__[methodName].method = method; - target.__meta__[methodName].path = url; - target.__meta__[methodName].options = options; +const registerMethod = (method: HttpMethod, url: string, options?: HttpMethodOptions) => { + return (target: T, methodName: string, descriptor: PropertyDescriptor) => { + if (options?.convertTo) handleConvertTo(target, methodName, options?.convertTo); + + target.__getServiceMetadata().setMetadata(methodName, (prev: MethodMetadata) => ({ + httpMethod: method, + path: url, + options: { + ...prev.options, + ...options, + }, + })); }; }; -/** - * GET decorator. - * @param url - * @param options - * @sample @GET("/users") - * @constructor - */ -export const GET = (url: string, options?: HttpMethodOptions) => { - return registerMethod("GET", url, options); -}; - -/** - * POST decorator. - * @param url - * @param options - * @sample @POST("/users") - * @constructor - */ -export const POST = (url: string, options?: HttpMethodOptions) => { - return registerMethod("POST", url, options); -}; - -/** - * PUT decorator. - * @param url - * @param options - * @sample @PUT("/users/{userId}") - * @constructor - */ -export const PUT = (url: string, options?: HttpMethodOptions) => { - return registerMethod("PUT", url, options); -}; - -/** - * PATCH decorator. - * @param url - * @param options - * @sample @PATCH("/users/{userId}") - * @constructor - */ -export const PATCH = (url: string, options?: HttpMethodOptions) => { - return registerMethod("PATCH", url, options); -}; - -/** - * DELETE decorator. - * @param url - * @param options - * @sample @DELETE("/users/{userId}") - * @constructor - */ -export const DELETE = (url: string, options?: HttpMethodOptions) => { - return registerMethod("DELETE", url, options); -}; - -/** - * HEAD decorator. - * @param url - * @param options - * @sample @HEAD("/users/{userId}") - * @constructor - */ -export const HEAD = (url: string, options?: HttpMethodOptions) => { - return registerMethod("HEAD", url, options); -}; - -/** - * OPTIONS decorator. - * @param url - * @param options - * @sample @OPTIONS("/users/{userId}") - * @constructor - */ -export const OPTIONS = (url: string, options?: HttpMethodOptions) => { - return registerMethod("OPTIONS", url, options); -}; +export const GET = (url: string, options?: HttpMethodOptions) => + registerMethod("GET", url, options); + +export const POST = (url: string, options?: HttpMethodOptions) => + registerMethod("POST", url, options); +export const PUT = (url: string, options?: HttpMethodOptions) => + registerMethod("PUT", url, options); +export const PATCH = (url: string, options?: HttpMethodOptions) => + registerMethod("PATCH", url, options); +export const DELETE = (url: string, options?: HttpMethodOptions) => + registerMethod("DELETE", url, options); +export const HEAD = (url: string, options?: HttpMethodOptions) => + registerMethod("HEAD", url, options); +export const OPTIONS = (url: string, options?: HttpMethodOptions) => + registerMethod("OPTIONS", url, options); /** - * Set base path for API service. - * @param path * @sample @BasePath("/api/v1") - * @constructor */ export const BasePath = (path: string) => { return (target: typeof BaseService) => { - ensureMeta(target.prototype, "basePath"); - target.prototype.__meta__.basePath = path; + target.prototype.__getServiceMetadata().basePath = path; }; }; -/** - * Set path parameter for API endpoint. - * @param paramName - * @sample @Path("userId") userId: number - * @constructor - */ -export const Path = (paramName: string) => { - return (target: any, methodName: string, paramIndex: number) => { - ensureMeta(target, methodName); - if (!target.__meta__[methodName].pathParams) { - target.__meta__[methodName].pathParams = {}; - } - target.__meta__[methodName].pathParams[paramIndex] = paramName; +/** @sample @Path("userId") userId: number */ +export const Path = (paramName: string) => { + return (target: T, methodName: string, paramIndex: number) => { + target.__getServiceMetadata().setMetadata(methodName, (prev: MethodMetadata) => ({ + pathParams: { + ...prev.pathParams, + [paramIndex]: paramName, + }, + })); }; }; -/** - * Set body for API endpoint. - * @param target - * @param methodName - * @param paramIndex - * @sample @Body user: User - * @constructor - */ -export const Body = (target: any, methodName: string, paramIndex: number) => { - ensureMeta(target, methodName); - target.__meta__[methodName].bodyIndex = paramIndex; +/** @sample @Body user: User */ +export const Body = (target: T, methodName: string, paramIndex: number) => { + target.__getServiceMetadata().setMetadata(methodName, { bodyIndex: paramIndex }); }; /** - * Set static HTTP headers for API endpoint. - * @param headers * @sample @Headers({ * "Content-Type": "application/x-www-form-urlencoded;charset=utf-8", * "Accept": "application/json" * }) - * @constructor */ -export const Headers = (headers: Headers) => { - return (target: any, methodName: string, descriptor: PropertyDescriptor) => { - ensureMeta(target, methodName); - if (!target.__meta__[methodName].headers) { - target.__meta__[methodName].headers = {}; - } - target.__meta__[methodName].headers = headers; +export const Headers = (headers: AxiosRequestHeaders) => { + return (target: T, methodName: string, descriptor: PropertyDescriptor) => { + target.__getServiceMetadata().setMetadata(methodName, (prev: MethodMetadata) => ({ + headers: { + ...prev.headers, + ...headers, + }, + })); }; }; -/** - * Set HTTP header as variable in API method. - * @param paramName - * @sample @Header("X-Token") token: string - * @constructor - */ -export const Header = (paramName: string) => { - return (target: any, methodName: string, paramIndex: number) => { - ensureMeta(target, methodName); - if (!target.__meta__[methodName].headerParams) { - target.__meta__[methodName].headerParams = {}; - } - target.__meta__[methodName].headerParams[paramIndex] = paramName; +/** @sample @Header("X-Token") token: string */ +export const Header = (paramName: string) => { + return (target: T, methodName: string, paramIndex: number) => { + target.__getServiceMetadata().setMetadata(methodName, (prev: MethodMetadata) => ({ + headerParams: { + ...prev.headerParams, + [paramIndex]: paramName, + }, + })); }; }; -/** - * Set header map for API endpoint. - * @param target - * @param methodName - * @param paramIndex - * @sample @HeaderMap headers: any - * @constructor - */ -export const HeaderMap = (target: any, methodName: string, paramIndex: number) => { - ensureMeta(target, methodName); - target.__meta__[methodName].headerMapIndex = paramIndex; +/** @sample @HeaderMap headers: any */ +export const HeaderMap = (target: T, methodName: string, paramIndex: number) => { + target.__getServiceMetadata().setMetadata(methodName, { headerMapIndex: paramIndex }); }; /** - * Set static query for API endpoint. - * @param query * @sample @Queries({ * page: 1, * size: 20, * sort: "createdAt:desc", * }) - * @constructor */ -export const Queries = (query: Query) => { - return (target: any, methodName: string, descriptor: PropertyDescriptor) => { - ensureMeta(target, methodName); - if (!target.__meta__[methodName].query) { - target.__meta__[methodName].query = {}; - } - target.__meta__[methodName].query = query; +export const Queries = (query: QueriesParamType) => { + return (target: T, methodName: string, descriptor: PropertyDescriptor) => { + target.__getServiceMetadata().setMetadata(methodName, { query: query }); }; }; -/** - * Set query as variable in API method. - * @param paramName - * @sample @Query('group') group: string - * @constructor - */ -export const Query = (paramName: string) => { - return (target: any, methodName: string, paramIndex: number) => { - ensureMeta(target, methodName); - if (!target.__meta__[methodName].queryParams) { - target.__meta__[methodName].queryParams = {}; - } - target.__meta__[methodName].queryParams[paramIndex] = paramName; +/** @sample @Query('group') group: string */ +export const Query = (paramName: string) => { + return (target: T, methodName: string, paramIndex: number) => { + target.__getServiceMetadata().setMetadata(methodName, (prev: MethodMetadata) => ({ + queryParams: { + ...prev.queryParams, + [paramIndex]: paramName, + }, + })); }; }; /** - * Set query map for API endpoint. - * @param target - * @param methodName - * @param paramIndex * @sample @QueryMap query: SearchQuery - * @constructor */ -export const QueryMap = (target: any, methodName: string, paramIndex: number) => { - ensureMeta(target, methodName); - target.__meta__[methodName].queryMapIndex = paramIndex; +export const QueryMap = (target: T, methodName: string, paramIndex: number) => { + target.__getServiceMetadata().setMetadata(methodName, { queryMapIndex: paramIndex }); }; /** * 'content-type': 'application/x-www-form-urlencoded;charset=utf-8' will be added. - * @param target - * @param methodName - * @param descriptor * @sample @FormUrlEncoded - * @constructor */ -export const FormUrlEncoded = (target: any, methodName: string, descriptor: PropertyDescriptor) => { - Headers({ "content-type": "application/x-www-form-urlencoded;charset=utf-8" })(target, methodName, descriptor); +export const FormUrlEncoded = ( + target: T, + methodName: string, + descriptor: PropertyDescriptor, +) => { + Headers({ [CONTENT_TYPE_HEADER]: `${CONTENT_TYPE.FORM_URL_ENCODED};${CHARSET_UTF_8}` })( + target, + methodName, + descriptor, + ); }; /** * Set field of form for API endpoint. Only effective when method has been decorated by @FormUrlEncoded. - * @param paramName * @sample @Field("title") title: string - * @constructor */ -export const Field = (paramName: string) => { - return (target: any, methodName: string, paramIndex: number) => { - ensureMeta(target, methodName); - if (!target.__meta__[methodName].fields) { - target.__meta__[methodName].fields = {}; - } - target.__meta__[methodName].fields[paramIndex] = paramName; +export const Field = (paramName: string) => { + return (target: T, methodName: string, paramIndex: number) => { + target.__getServiceMetadata().setMetadata(methodName, (prev: MethodMetadata) => ({ + fields: { + ...prev.fields, + [paramIndex]: paramName, + }, + })); }; }; /** - * Set field map for API endpoint. - * @param target - * @param methodName - * @param paramIndex * @sample @FieldMap post: Post - * @constructor */ -export const FieldMap = (target: any, methodName: string, paramIndex: number) => { - ensureMeta(target, methodName); - target.__meta__[methodName].fieldMapIndex = paramIndex; +export const FieldMap = (target: T, methodName: string, paramIndex: number) => { + target.__getServiceMetadata().setMetadata(methodName, { fieldMapIndex: paramIndex }); }; /** * 'content-type': 'multipart/form-data' will be added to HTTP headers. - * @param target - * @param methodName - * @param descriptor * @sample @Multipart - * @constructor */ -export const Multipart = (target: any, methodName: string, descriptor: PropertyDescriptor) => { - Headers({ "content-type": "multipart/form-data" })(target, methodName, descriptor); +export const Multipart = (target: T, methodName: string, descriptor: PropertyDescriptor) => { + Headers({ [CONTENT_TYPE_HEADER]: CONTENT_TYPE.MULTIPART_FORM_DATA })(target, methodName, descriptor); }; /** * Set part of form data for API endpoint. Only effective when method has been decorated by @Multipart. - * @param paramName * @sample @Part("bucket") bucket: PartDescriptor - * @constructor */ -export const Part = (paramName: string) => { - return (target: any, methodName: string, paramIndex: number) => { - ensureMeta(target, methodName); - if (!target.__meta__[methodName].parts) { - target.__meta__[methodName].parts = {}; - } - target.__meta__[methodName].parts[paramIndex] = paramName; +export const Part = (paramName: string) => { + return (target: T, methodName: string, paramIndex: number) => { + target.__getServiceMetadata().setMetadata(methodName, (old: MethodMetadata) => ({ + parts: { + ...old.parts, + [paramIndex]: paramName, + }, + })); }; }; /** * Set the response type for method. - * @param responseType * @sample @ResponseType("stream") - * @constructor */ -export const ResponseType = (responseType: AxiosResponseType) => { - return (target: any, methodName: string) => { - ensureMeta(target, methodName); - target.__meta__[methodName].responseType = responseType; +export const ResponseType = (responseType: AxiosResponseType) => { + return (target: T, methodName: string) => { + target.__getServiceMetadata().setMetadata(methodName, { responseType: responseType }); }; }; /** * Set request transformer for method. - * @param transformer * @sample @RequestTransformer((data: any, headers?: any) => { * data.foo = 'foo'; * return JSON.stringify(data); * }) - * @constructor */ -export const RequestTransformer = (transformer: AxiosTransformer) => { - return (target: any, methodName: string) => { - ensureMeta(target, methodName); - target.__meta__[methodName].requestTransformer = transformer; +export const RequestTransformer = ( + ...transformers: TransformerType[] +) => { + return (target: T, methodName: string) => { + target.__getServiceMetadata().setMetadata(methodName, (prev) => ({ + ...prev, + requestTransformer: [...transformers, ...prev.requestTransformer], + })); }; }; /** * Set response transformer for method. - * @param transformer * @sample @ResponseTransformer((data: any, headers?: any) => { * const json = JSON.parse(data); * json.foo = 'foo'; * return json; * }) - * @constructor */ -export const ResponseTransformer = (transformer: AxiosTransformer) => { - return (target: any, methodName: string) => { - ensureMeta(target, methodName); - target.__meta__[methodName].responseTransformer = transformer; +export const ResponseTransformer = ( + ...transformers: TransformerType[] +) => { + return (target: T, methodName: string) => { + target.__getServiceMetadata().setMetadata(methodName, (prev) => ({ + ...prev, + responseTransformer: [...transformers, ...prev.responseTransformer], + })); + }; +}; + +// public id: number, public userId: number, public title: string, public body: string +// ...args: object[] +export const ConvertTo = (returnClass: new () => void) => { + return (target: T, methodName: string) => { + handleConvertTo(target, methodName, returnClass); }; }; +function handleConvertTo(target: T, methodName: string, returnClass: ResponseConvertTo) { + target.__getServiceMetadata().setMetadata(methodName, { convertTo: returnClass }); +} + /** * Set timeout for method, this config will shield service timeout. - * @param timeout * @sample @Timeout(5000) - * @constructor */ -export const Timeout = (timeout: number) => { - return (target: any, methodName: string) => { - ensureMeta(target, methodName); - target.__meta__[methodName].timeout = timeout; +export const Timeout = (timeout: number) => { + return (target: T, methodName: string) => { + target.__getServiceMetadata().setMetadata(methodName, { timeout: timeout }); }; }; /** * Declare response status code for method, do nothing just a declaration. - * @param responseStatus * @sample ResponseStatus(204) - * @constructor */ -export const ResponseStatus = (responseStatus: number) => { - return (target: any, methodName: string) => { - ensureMeta(target, methodName); - target.__meta__[methodName].responseStatus = responseStatus; +export const ResponseStatus = (responseStatus: number) => { + return (target: T, methodName: string) => { + target.__getServiceMetadata().setMetadata(methodName, { responseStatus: responseStatus }); }; }; /** * A direct way to set config for a request in axios. - * @param config * @sample @Config({ maxRedirects: 1 }) - * @constructor */ -export const Config = (config: Partial) => { - return (target: any, methodName: string) => { - ensureMeta(target, methodName); - target.__meta__[methodName].config = config; +export const Config = (config: Partial) => { + return (target: T, methodName: string) => { + target.__getServiceMetadata().setMetadata(methodName, { config: config }); }; }; diff --git a/src/http.client.ts b/src/http.client.ts new file mode 100644 index 0000000..4d706d3 --- /dev/null +++ b/src/http.client.ts @@ -0,0 +1,43 @@ +import { HttpApiResponse, RequestInterceptor, ResponseInterceptor } from "./baseService"; +import axios, { AxiosInstance, AxiosRequestConfig } from "axios"; +import { ServiceBuilder } from "./service.builder"; + +export class RetrofitHttpClient { + private readonly axios: AxiosInstance = axios; + public readonly standalone: boolean = false; + + constructor(builder: ServiceBuilder) { + if (builder.standalone === true) { + this.axios = axios.create(); + this.standalone = true; + } else if (typeof builder.standalone === "function") { + this.axios = builder.standalone; + } + + builder.requestInterceptors.forEach((interceptor) => { + if (interceptor instanceof RequestInterceptor) { + this.axios.interceptors.request.use( + interceptor.onFulfilled.bind(interceptor), + interceptor.onRejected.bind(interceptor), + ); + } else { + this.axios.interceptors.request.use(interceptor); + } + }); + + builder.responseInterceptors.forEach((interceptor) => { + if (interceptor instanceof ResponseInterceptor) { + this.axios.interceptors.response.use( + interceptor.onFulfilled.bind(interceptor), + interceptor.onRejected.bind(interceptor), + ); + } else { + this.axios.interceptors.response.use(interceptor); + } + }); + } + + public async sendRequest(config: AxiosRequestConfig): Promise> { + return this.axios(config); + } +} diff --git a/src/index.ts b/src/index.ts index 41a74c5..9566791 100644 --- a/src/index.ts +++ b/src/index.ts @@ -1,2 +1,5 @@ export * from "./baseService"; export * from "./decorators"; +export * from "./service.builder"; + +export { ValidationErrors } from "./constants"; diff --git a/src/metadata.ts b/src/metadata.ts new file mode 100644 index 0000000..9a506cf --- /dev/null +++ b/src/metadata.ts @@ -0,0 +1,50 @@ +import { CONTENT_TYPE, CONTENT_TYPE_HEADER, MethodMetadata } from "./constants"; +import { BaseService } from "./baseService"; + +export class ServiceMetaData { + public methodMetadata: Map = new Map(); + public basePath?: string; + + setMetadata( + method: string, + valueOrFn: Partial | ((oldValue: MethodMetadata) => Partial), + ) { + const oldValue = this.getMetaOrSetEmptyObject(method); + + if (typeof valueOrFn === "function") { + this.methodMetadata.set(method, { ...oldValue, ...valueOrFn(oldValue) }); + } else { + this.methodMetadata.set(method, { ...oldValue, ...valueOrFn }); + } + } + + getMetadata(method: string): MethodMetadata; + getMetadata(method: keyof T): MethodMetadata; + getMetadata(method: string | keyof T): MethodMetadata { + const metadata = this.methodMetadata.get(method as string); + if (!metadata) throw new Error(`Method ${method} does not exist`); + return metadata; + } + + private getMetaOrSetEmptyObject(method: string): MethodMetadata { + const meta = this.methodMetadata.get(method); + if (meta) return meta; + + const initial: MethodMetadata = { + query: {}, + fields: {}, + queryParams: {}, + parts: {}, + headers: { + [CONTENT_TYPE_HEADER]: CONTENT_TYPE.APPLICATION_JSON, + }, + pathParams: {}, + headerParams: {}, + requestTransformer: [], + responseTransformer: [], + }; + + this.methodMetadata.set(method, initial); + return initial; + } +} diff --git a/src/request-config-builder.ts b/src/request-config-builder.ts new file mode 100644 index 0000000..98c4a26 --- /dev/null +++ b/src/request-config-builder.ts @@ -0,0 +1,93 @@ +import { DataType, HttpMethod, MethodMetadata, QueriesParamType } from "./constants"; +import { AxiosRequestConfig, AxiosRequestHeaders, AxiosResponseHeaders } from "axios"; +import { DataResolverFactory } from "./dataResolver"; +import { ServiceBuilder } from "./service.builder"; + +export function makeConfig( + metadata: MethodMetadata, + serviceBuilder: ServiceBuilder, + methodName: string, + url: string, + method: HttpMethod, + headers: AxiosRequestHeaders, + query: QueriesParamType, + data: unknown, +): AxiosRequestConfig { + let config: AxiosRequestConfig = { + url, + method, + headers, + params: query, + data, + }; + // response type + if (metadata.responseType) { + config.responseType = metadata.responseType; + } + + const logger = getLoggerAfterTransformer(config, serviceBuilder); + + // request transformer + const transformRequest = []; + + if (metadata.requestTransformer.length > 0) { + transformRequest.push(...metadata.requestTransformer); + } + + if (logger) transformRequest.push(logger); + + if (transformRequest.length > 0) { + config.transformRequest = [ + ...transformRequest, + (data: DataType) => { + // @TODO what if not json ??? response content type? + if (typeof data === "string") return data; + else return JSON.stringify(data); + }, + ]; + } + + // response transformer + if (metadata.responseTransformer.length > 0) { + config.transformResponse = [ + (body: string, headers?: AxiosResponseHeaders) => { + return DataResolverFactory.createDataResolver(headers || {}).resolve(headers || {}, body); + }, + ...metadata.responseTransformer, + ]; + } + + // timeout + config.timeout = metadata.timeout || serviceBuilder.timeout; + + // mix in config set by @Config + config = { + ...config, + ...metadata.config, + }; + return config; +} + +function getLoggerAfterTransformer(config: AxiosRequestConfig, serviceBuilder: ServiceBuilder) { + const loggerOptions = serviceBuilder.loggerOptions; + if (!loggerOptions.showLogs) return undefined; + + const logLevelFn = loggerOptions.logLevel === "DEBUG" ? console.debug : console.log; + + const urlAndMethod = `[${config.method?.toUpperCase()}] ${config.url}`; + + return (data: string) => { + let dataRow = ""; + if (Object.keys(config.data).length !== 0) { + logLevelFn(urlAndMethod); + if (typeof data === "object" || Array.isArray(data)) { + dataRow += "\n" + JSON.stringify(data); + } else { + dataRow += "\n" + data; + } + } + + logLevelFn(`${urlAndMethod}${dataRow}`); + return data; + }; +} diff --git a/src/request-resolvers/body-request-resolver.ts b/src/request-resolvers/body-request-resolver.ts new file mode 100644 index 0000000..de7a785 --- /dev/null +++ b/src/request-resolvers/body-request-resolver.ts @@ -0,0 +1,123 @@ +import { CONTENT_TYPE_HEADER, DataType, MethodMetadata } from "../constants"; +import { DataResolverFactory } from "../dataResolver"; +import { ErrorMessages } from "../baseService"; +import { AxiosRequestHeaders } from "axios"; + +export const requestBodyResolver = ( + metadata: MethodMetadata, + methodName: string, + headers: AxiosRequestHeaders, + args: unknown[], +): DataType => { + const bodyIndex = metadata.bodyIndex; + const fieldMapIndex = metadata.fieldMapIndex; + let data: DataType | DataType[] = {}; + + // @Body + data = resolveBody(bodyIndex, args, data); + + // @Field + data = resolveField(metadata, args, data); + + // @FieldMap + data = resolveFieldMap(fieldMapIndex, args, data); + + // @MultiPart + data = resolveMultipart(metadata, args, data); + + const contentType = headers[CONTENT_TYPE_HEADER] as string; + const dataResolver = DataResolverFactory.createDataResolver(contentType); + return dataResolver.resolve(headers, data); +}; + +// @Body +function resolveBody( + bodyIndex: number | undefined, + args: unknown[], + data: DataType | DataType[], +): DataType | DataType[] { + if (bodyIndex === undefined) return data; + + const argValue = args[bodyIndex]; + + if (Array.isArray(argValue)) { + data = argValue; + } else { + data = { ...(data as Record), ...(argValue as Record) }; + } + return data; +} + +// @Field +const resolveField = ( + metadata: MethodMetadata, + args: unknown[], + data: DataType | DataType[], +): DataType | DataType[] => { + if (Object.keys(metadata.fields).length === 0) return data; + + const result = {}; + Object.entries(metadata.fields).map((e) => { + const [idx, fieldKey] = e; + if (fieldKey === "") throw new Error(ErrorMessages.EMPTY_FIELD_KEY); + + result[fieldKey] = args[idx]; + }); + + if (Array.isArray(data)) { + throw new Error(ErrorMessages.FIELD_WITH_ARRAY_BODY); + } + + return { ...(data as Record), ...result }; +}; + +// @MultiPart +const resolveMultipart = ( + metadata: MethodMetadata, + args: unknown[], + data: DataType | DataType[], +): DataType | DataType[] => { + if (Object.keys(metadata.parts).length === 0) return data; + + if (Array.isArray(data)) { + throw new Error(ErrorMessages.MULTIPART_WITH_ARRAY_BODY); + } + + const result = {}; + Object.entries(metadata.parts).map((e) => { + const [idx, partKey] = e; + if (partKey === "") throw new Error(ErrorMessages.EMPTY_PART_KEY); + + result[partKey] = args[idx]; + }); + + return { ...(data as Record), ...result }; +}; + +// @FieldMap +const resolveFieldMap = ( + fieldMapIndex: number | undefined, + args: unknown[], + data: DataType | DataType[], +): DataType | DataType[] => { + if (fieldMapIndex === undefined) return data; + + if (Array.isArray(data)) { + throw new Error(ErrorMessages.FIELD_MAP_FOR_ARRAY_BODY); + } + + const fieldMap = args[fieldMapIndex] as Record; + if (Array.isArray(fieldMap)) { + throw new Error(ErrorMessages.FIELD_MAP_PARAM_TYPE); + } + + const result = {}; + Object.entries(fieldMap).map((e) => { + const [fieldKey, fieldValue] = e; + if (fieldKey === "") throw new Error(ErrorMessages.EMPTY_FIELD_KEY); + + result[fieldKey] = fieldValue; + }); + + return { ...(data as Record), ...result }; +}; diff --git a/src/request-resolvers/headers-request-resolver.ts b/src/request-resolvers/headers-request-resolver.ts new file mode 100644 index 0000000..12fa50b --- /dev/null +++ b/src/request-resolvers/headers-request-resolver.ts @@ -0,0 +1,41 @@ +import { ErrorMessages } from "../baseService"; +import { MethodMetadata } from "../constants"; +import { AxiosRequestHeaders } from "axios"; + +export const requestHeadersResolver = ( + metadata: MethodMetadata, + methodName: string, + args: unknown[], +): AxiosRequestHeaders => { + const headers = metadata.headers; + + Object.entries(metadata.headerParams).map((e) => { + const [idx, headerKey] = e; + if (headerKey === "") throw new Error(ErrorMessages.EMPTY_HEADER_KEY); + + const value = args[idx]; + if (typeof value === "number" || typeof value === "string" || typeof value === "boolean") { + metadata.headers[headerKey] = args[idx]; + } else { + throw new Error(ErrorMessages.WRONG_HEADER_TYPE); + } + }); + + const headerMapIndex = metadata.headerMapIndex; + if (headerMapIndex === undefined) return headers; + + const headerMap = args[headerMapIndex] as Record; + + Object.entries(headerMap).map((e) => { + const [headerKey, headerValue] = e; + if (headerKey === "") throw new Error(ErrorMessages.EMPTY_HEADER_KEY); + + if (typeof headerValue === "number" || typeof headerValue === "string" || typeof headerValue === "boolean") { + metadata.headers[headerKey] = `${headerValue}`; + } else { + throw new Error(ErrorMessages.WRONG_HEADERS_PROPERTY_TYPE); + } + }); + + return headers; +}; diff --git a/src/request-resolvers/query-params-request-resolver.ts b/src/request-resolvers/query-params-request-resolver.ts new file mode 100644 index 0000000..336827e --- /dev/null +++ b/src/request-resolvers/query-params-request-resolver.ts @@ -0,0 +1,38 @@ +import { MethodMetadata, QueriesParamType } from "../constants"; +import { ErrorMessages } from "../baseService"; + +export const requestQueryParamsResolver = ( + metadata: MethodMetadata, + methodName: string, + args: unknown[], +): QueriesParamType => { + const query = metadata.query; + + Object.entries(metadata.queryParams).map((e) => { + const [idx, queryKey] = e; + if (queryKey === "") throw new Error(ErrorMessages.EMPTY_QUERY_KEY); + + const queryValue = args[idx]; + + if (typeof queryValue === "number" || typeof queryValue === "string" || typeof queryValue === "boolean") { + query[queryKey] = queryValue; + } else { + throw new Error(ErrorMessages.WRONG_QUERY_TYPE); + } + }); + const queryMapIndex = metadata.queryMapIndex; + if (queryMapIndex === undefined) return query; + + const queryMap = args[queryMapIndex] as Record; + Object.entries(queryMap).map((e) => { + const [queryKey, queryValue] = e; + if (queryKey === "") throw new Error(ErrorMessages.EMPTY_QUERY_KEY); + + if (typeof queryValue === "number" || typeof queryValue === "string" || typeof queryValue === "boolean") { + query[queryKey] = queryValue; + } else { + throw new Error(ErrorMessages.WRONG_QUERY_MAP_PROPERTY_TYPE); + } + }); + return query; +}; diff --git a/src/service.builder.ts b/src/service.builder.ts new file mode 100644 index 0000000..a282be5 --- /dev/null +++ b/src/service.builder.ts @@ -0,0 +1,133 @@ +import { AxiosInstance, AxiosRequestConfig } from "axios"; +import { + RequestInterceptor, + RequestInterceptorFunction, + ResponseInterceptor, + ResponseInterceptorFunction, +} from "./baseService"; +import { Primitive, ValidationMethod } from "./constants"; + +export class ServiceBuilder { + private _endpoint = ""; + private _standalone: boolean | AxiosInstance = false; + private _requestInterceptors: Array = []; + private _responseInterceptors: Array = []; + private _withInlineResponseBody = false; + private _responseValidator?: ValidationMethod; + private _shouldSaveRequestHistory = false; + private _timeout = 60000; + private _loggerOptions: { showLogs?: boolean; logLevel?: "LOG" | "DEBUG" } = { showLogs: false }; + + public build(service: new (builder: ServiceBuilder) => T): T { + return new service(this); + } + + public baseUrl(endpoint: string): ServiceBuilder { + this._endpoint = endpoint; + return this; + } + + public setStandalone(standalone: boolean | AxiosInstance): ServiceBuilder { + this._standalone = standalone; + return this; + } + + public validateResponse(type: ValidationMethod = ValidationMethod.CLASS_VALIDATOR): ServiceBuilder { + this._responseValidator = type; + return this; + } + + public setRequestInterceptors( + ...interceptors: Array + ): ServiceBuilder { + this._requestInterceptors.push(...interceptors); + return this; + } + + public setResponseInterceptors( + ...interceptors: Array + ): ServiceBuilder { + this._responseInterceptors.push(...interceptors); + return this; + } + + public setTimeout(timeout: number): ServiceBuilder { + this._timeout = timeout; + return this; + } + + /** + * Sends request header "Authorization": "Bearer ${token}" + */ + public withOauth(token?: string): ServiceBuilder { + return this.withRequestHeader("Authorization", `Bearer ${token ? token : ""}`); + } + + public withRequestHeader(key: string, value?: Primitive): ServiceBuilder { + this.setRequestInterceptors((config: AxiosRequestConfig) => { + if (!value) return config; + + return { + ...config, + headers: { + ...config.headers, + [key]: `${value}`, + }, + }; + }); + return this; + } + + public withRequestLogger( + options: { showLogs?: boolean; logLevel?: "LOG" | "DEBUG" } = { showLogs: true }, + ): ServiceBuilder { + this._loggerOptions = options; + return this; + } + + public inlineResponseBody(): ServiceBuilder { + this._withInlineResponseBody = true; + return this; + } + + public saveRequestHistory(): ServiceBuilder { + this._shouldSaveRequestHistory = true; + return this; + } + + get loggerOptions() { + return this._loggerOptions; + } + + get shouldSaveRequestHistory() { + return this._shouldSaveRequestHistory; + } + + get withInlineResponseBody(): boolean { + return this._withInlineResponseBody; + } + + get responseValidator() { + return this._responseValidator; + } + + get endpoint(): string { + return this._endpoint; + } + + get standalone(): boolean | AxiosInstance { + return this._standalone; + } + + get requestInterceptors(): Array { + return this._requestInterceptors; + } + + get responseInterceptors(): Array { + return this._responseInterceptors; + } + + get timeout(): number { + return this._timeout; + } +} diff --git a/src/util.ts b/src/util.ts index dea827b..5715d55 100644 --- a/src/util.ts +++ b/src/util.ts @@ -1,3 +1 @@ -export const isNode = typeof process !== "undefined" - && process.versions != null - && process.versions.node != null; +export const isNode = typeof process !== "undefined" && process.versions != null && process.versions.node != null; diff --git a/test/fixture/fixtures.ts b/test/fixture/fixtures.ts deleted file mode 100644 index 00f9c3e..0000000 --- a/test/fixture/fixtures.ts +++ /dev/null @@ -1,225 +0,0 @@ -import { - GET, POST, PUT, PATCH, DELETE, HEAD, OPTIONS, BasePath, Header, Queries, Headers, Path, Query, QueryMap, Body, - FormUrlEncoded, Field, FieldMap, Multipart, ResponseType, Part, PartDescriptor, BaseService, Response, HeaderMap, - RequestTransformer, ResponseTransformer, Timeout, ResponseStatus, Config, -} from "../../src"; - -export const TEST_SERVER_HOST = "http://localhost"; -export const TEST_SERVER_PORT = 12345; -export const TEST_SERVER_ENDPOINT = `${TEST_SERVER_HOST}:${TEST_SERVER_PORT}`; -export const API_PREFIX = "/api/v1"; -export const TOKEN = "abcdef123456"; - -export interface User { - id?: number; - name: string; - age: number; - [x: string]: any; -} - -export interface SearchQuery { - title?: string; - author?: string; - category?: string; -} - -export interface Auth { - username: string; - password: string; -} - -export interface Post { - title: string; - content: string; -} - -export interface Group { - name: string; - description: string; - members: number[]; - tags: string[]; -} - -export interface Something { - name: string; -} - -@BasePath(API_PREFIX) -export class UserService extends BaseService { - @GET("/users") - async getUsers(@Header("X-Token") token: string): Promise { return {} }; - - @GET(`${TEST_SERVER_ENDPOINT}/users`) - async getUsersOther(@Header("X-Token") token: string): Promise { return {} }; - - @GET("/users/{userId}") - async getUser(@Header("X-Token") token: string, @Path("userId") userId: number): Promise { return {} }; - - @GET("/users/uid-{userId}") - async getUser1(@Header("X-Token") token: string, @Path("userId") userId: number): Promise { return {} }; - - @POST("/users") - async createUser(@Header("X-Token") token: string, @Body user: User): Promise { return {} }; - - @PUT("/users/{userId}") - async replaceUser(@Header("X-Token") token: string, @Path("userId") userId: number, @Body user: User): Promise { return {} }; - - @PATCH("/users/{userId}") - async updateUser(@Header("X-Token") token: string, @Path("userId") userId: number, @Body user: Partial): Promise { return {} }; - - @DELETE("/users/{userId}") - async deleteUser(@Header("X-Token") token: string, @Path("userId") userId: number): Promise { return {} }; - - @HEAD("/users/{userId}") - async headUser(@Header("X-Token") token: string, @Path("userId") userId: number): Promise { return {} }; - - @OPTIONS("/users/{userId}") - async optionsUser(@Header("X-Token") token: string, @Path("userId") userId: number): Promise { return {} }; -} - -@BasePath(API_PREFIX) -export class SearchService extends BaseService { - @GET("/search") - async search(@Header("X-Token") token: string, @QueryMap query: SearchQuery): Promise { return {} }; -} - -@BasePath("") -export class AuthService extends BaseService { - @POST("/oauth2/authorize") - @Headers({ - "Content-Type": "application/x-www-form-urlencoded;charset=utf-8", - "Accept": "application/json" - }) - async auth(@Body body: Auth): Promise { return {} }; -} - -@BasePath(API_PREFIX) -export class PostService extends BaseService { - @GET("/posts") - @Queries({ - page: 1, - size: 20, - sort: "createdAt:desc", - }) - async getPosts(): Promise { return {} }; - - @GET("/posts") - @Queries({ - page: 1, - size: 20, - sort: "createdAt:desc", - }) - async getPosts1(@Query('group') group: string): Promise { return {} }; - - @POST("/posts") - @FormUrlEncoded - async createPost(@Field("title") title: string, @Field("content") content: string): Promise { return {} }; - - @POST("/posts") - @FormUrlEncoded - async createPost2(@FieldMap post: Post): Promise { return {} }; - - @POST("/posts") - @FormUrlEncoded - async createPost3(@HeaderMap headers: any, @FieldMap post: Post): Promise { return {} }; -} - -@BasePath(API_PREFIX) -export class FileService extends BaseService { - @POST("/upload") - @Multipart - async upload(@Part("bucket") bucket: PartDescriptor, @Part("file") file: PartDescriptor): Promise { return {} }; - - @GET("/file") - @ResponseType("stream") - async getFile(@Path("fileId") fileId: string): Promise { return {} }; -} - -@BasePath(API_PREFIX) -export class MessagingService extends BaseService { - @POST("/sms") - @Multipart - async createSMS(@Part("from") from: PartDescriptor, @Part("to") to: PartDescriptor): Promise { return {} }; -} - -@BasePath(API_PREFIX) -export class GroupService extends BaseService { - @POST("/groups") - @FormUrlEncoded - async createGroup(@Body body: Group): Promise { return {} }; -} - -@BasePath(API_PREFIX) -export class InterceptorService extends BaseService { - @GET("/interceptor") - async getParams(): Promise { return {} }; - - @POST("/interceptor") - async createParams(@Body body: Post): Promise { return {} }; - - @GET("/header") - async getHeader(): Promise { return {} }; -} - -@BasePath(API_PREFIX) -export class TransformerService extends BaseService { - @POST("/request-transformer") - @RequestTransformer((data: any, headers?: any) => { - data.foo = 'foo'; - return JSON.stringify(data); - }) - async createSomething(@Body body: Something): Promise { return {} }; - - @GET("/response-transformer") - @ResponseTransformer((data: any, headers?: any) => { - const json = JSON.parse(data); - json.foo = 'foo'; - return json; - }) - async getSomething(): Promise> { return >{} }; -} - -@BasePath(API_PREFIX) -export class TimeoutService extends BaseService { - @GET("/sleep-5000") - async sleep5000(): Promise { return {} }; - - @GET("/sleep-5000") - @Timeout(3000) - async timeoutIn3000(): Promise { return {} }; - - @GET("/sleep-5000") - @Timeout(6000) - async timeoutIn6000(): Promise { return {} }; -} - -@BasePath(API_PREFIX) -export class ResponseStatusService extends BaseService { - @GET("/response-status") - @ResponseStatus(200) - async getSomething(): Promise { return {} }; -} - -@BasePath(API_PREFIX) -export class ConfigService extends BaseService { - @GET("/config") - @Config({ - maxRedirects: 1, - }) - @ResponseStatus(200) - async getConfig(): Promise { return {} }; -} - -@BasePath(API_PREFIX) -export class AbsoluteURLService extends BaseService { - @GET("https://absolute-foobar.com") - @ResponseStatus(200) - async getSomethingAbsolute(): Promise { return {} }; -} - -@BasePath(API_PREFIX) -export class HttpMethodOptionsService extends BaseService { - @GET("/ping", { ignoreBasePath: true }) - @ResponseStatus(200) - async ping(): Promise { return {} }; -} \ No newline at end of file diff --git a/test/fixture/server.ts b/test/fixture/server.ts deleted file mode 100644 index cb0bb1d..0000000 --- a/test/fixture/server.ts +++ /dev/null @@ -1,129 +0,0 @@ -import express from "express"; -import bodyParser from "body-parser"; -import multer from "multer"; - -export const app = express(); - -const jsonParser = bodyParser.json(); -const upload = multer(); -app.use(bodyParser.urlencoded({ extended: false })); - -const sleep = async (milliseconds: number): Promise => { - return new Promise((resolve, reject) => { - setTimeout(() => { - resolve(); - }, milliseconds); - }); -}; - -app.get("/api/v1/users", function (req, res) { - res.status(200).json({}); -}); - -app.get("/users", function (req, res) { - res.status(200).json({}); -}); - -app.get("/api/v1/users/:userId", jsonParser, function (req, res) { - res.status(200).json({}); -}); - -app.get("/api/v1/users/user-:userId", jsonParser, function (req, res) { - res.status(200).json({}); -}); - -app.post("/api/v1/users", jsonParser, function (req, res) { - res.status(200).json({}); -}); - -app.put("/api/v1/users/:userId", jsonParser, function (req, res) { - res.status(200).json({}); -}); - -app.patch("/api/v1/users/:userId", jsonParser, function (req, res) { - res.status(200).json({}); -}); - -app.delete("/api/v1/users/:userId", jsonParser, function (req, res) { - res.status(200).json({}); -}); - -app.head("/api/v1/users/:userId", jsonParser, function (req, res) { - res.status(200).json({}); -}); - -app.options("/api/v1/users/:userId", jsonParser, function (req, res) { - res.status(200).json({}); -}); - -app.get("/api/v1/search", jsonParser, function (req, res) { - res.status(200).json({}); -}); - -app.post("/oauth2/authorize", jsonParser, function (req, res) { - res.status(200).json({}); -}); - -app.get("/api/v1/posts", jsonParser, function (req, res) { - res.status(200).json({}); -}); - -app.post("/api/v1/posts", jsonParser, function (req, res) { - res.status(200).json({}); -}); - -app.post("/api/v1/upload", upload.any(), function (req, res) { - // get fields of form data from `req.body` - // get files from req.files array - res.status(200).json({}); -}); - -app.get("/api/v1/file", upload.any(), function (req, res) { - res.status(200).json({}); -}); - -app.post("/api/v1/sms", jsonParser, function (req, res) { - // get fields of form data from `req.body` - // get files from req.files array - res.status(200).json({}); -}); - -app.post("/api/v1/groups", jsonParser, function (req, res) { - // get fields of form data from `req.body` - // get files from req.files array - res.status(200).json({}); -}); - -app.get("/api/v1/interceptor", function (req, res) { - res.status(200).json(req.query); -}); - -app.post("/api/v1/interceptor", function (req, res) { - res.status(200).json(req.body); -}); - -app.get("/api/v1/header", function (req, res) { - res.status(200).json({ role: req.header('X-Role') }); -}); - -app.post("/api/v1/request-transformer", function (req, res) { - res.status(200).json({}); -}); - -app.get("/api/v1/response-transformer", function (req, res) { - res.status(200).json({}); -}); - -app.get("/api/v1/sleep-5000", async function (req, res) { - await sleep(5000); - res.status(200).json({}); -}); - -app.get("/api/v1/config", async function (req, res) { - await sleep(5000); - res.status(200).json({}); -}); - -app.get("/ping", async function (req, res) { - res.status(200).json({ result: "pong" }); -}); \ No newline at end of file diff --git a/test/testSetupFile.js b/test/testSetupFile.js deleted file mode 100644 index 09ffd35..0000000 --- a/test/testSetupFile.js +++ /dev/null @@ -1 +0,0 @@ -jest.setTimeout(60000); diff --git a/test/ts-retrofit.test.ts b/test/ts-retrofit.test.ts deleted file mode 100644 index 622def3..0000000 --- a/test/ts-retrofit.test.ts +++ /dev/null @@ -1,531 +0,0 @@ -import * as http from "http"; -import * as fs from "fs"; -import axios, { AxiosRequestConfig } from "axios"; -import { app } from "./fixture/server"; -import { ServiceBuilder, RequestInterceptorFunction, ResponseInterceptorFunction, RequestInterceptor } from "../src"; -import { - TEST_SERVER_ENDPOINT, - TEST_SERVER_PORT, - API_PREFIX, - TOKEN, - UserService, - SearchService, - GroupService, - PostService, - AuthService, - FileService, - MessagingService, - User, - SearchQuery, - Auth, - Post, - Group, - InterceptorService, - TransformerService, - TimeoutService, - ResponseStatusService, - ConfigService, - AbsoluteURLService, - HttpMethodOptionsService, -} from "./fixture/fixtures"; -import { DATA_CONTENT_TYPES, HttpContentType } from "../src/constants"; - -declare module 'axios' { - interface AxiosRequestConfig { - standaloneId?: string; - } -} - -describe("Test ts-retrofit.", () => { - - let server: http.Server; - - beforeAll(() => { - server = app.listen(TEST_SERVER_PORT); - }); - - afterAll(() => { - server.close(); - }); - - test("Test `@BasePath` decorator.", async () => { - const userService = new ServiceBuilder() - .setEndpoint(TEST_SERVER_ENDPOINT) - .build(UserService); - const response = await userService.getUsers(TOKEN); - expect(response.config.url).toEqual(`${TEST_SERVER_ENDPOINT}${API_PREFIX}/users`); - }); - - test("Test `@GET` decorator.", async () => { - const userService = new ServiceBuilder() - .setEndpoint(TEST_SERVER_ENDPOINT) - .build(UserService); - const response = await userService.getUsers(TOKEN); - expect(response.config.method).toEqual("get"); - expect(response.config.url).toEqual(`${TEST_SERVER_ENDPOINT}${API_PREFIX}/users`); - }); - - test("Test `@POST` decorator.", async () => { - const userService = new ServiceBuilder() - .setEndpoint(TEST_SERVER_ENDPOINT) - .build(UserService); - const newUser: User = { - name: "Jane", - age: 18 - }; - const response = await userService.createUser(TOKEN, newUser); - expect(response.config.method).toEqual("post"); - expect(response.config.url).toEqual(`${TEST_SERVER_ENDPOINT}${API_PREFIX}/users`); - }); - - test("Test `@PUT` decorator.", async () => { - const userService = new ServiceBuilder() - .setEndpoint(TEST_SERVER_ENDPOINT) - .build(UserService); - const userId = 1; - const name = "Johnny"; - const age = 21; - const country = "US"; - const user = { name, age, country }; - const response = await userService.replaceUser(TOKEN, userId, user); - expect(response.config.method).toEqual("put"); - expect(response.config.url).toEqual(`${TEST_SERVER_ENDPOINT}${API_PREFIX}/users/${userId}`); - }); - - test("Test `@PATCH` decorator.", async () => { - const userService = new ServiceBuilder() - .setEndpoint(TEST_SERVER_ENDPOINT) - .build(UserService); - const userId = 1; - const age = 21; - const user = { age }; - const response = await userService.updateUser(TOKEN, userId, user); - expect(response.config.method).toEqual("patch"); - expect(response.config.url).toEqual(`${TEST_SERVER_ENDPOINT}${API_PREFIX}/users/${userId}`); - }); - - test("Test `@DELETE` decorator.", async () => { - const userService = new ServiceBuilder() - .setEndpoint(TEST_SERVER_ENDPOINT) - .build(UserService); - const userId = 1; - const response = await userService.deleteUser(TOKEN, userId); - expect(response.config.method).toEqual("delete"); - expect(response.config.url).toEqual(`${TEST_SERVER_ENDPOINT}${API_PREFIX}/users/${userId}`); - }); - - test("Test `@HEAD` decorator.", async () => { - const userService = new ServiceBuilder() - .setEndpoint(TEST_SERVER_ENDPOINT) - .build(UserService); - const userId = 1; - const response = await userService.headUser(TOKEN, userId); - expect(response.config.method).toEqual("head"); - expect(response.config.url).toEqual(`${TEST_SERVER_ENDPOINT}${API_PREFIX}/users/${userId}`); - }); - - test("Test `@OPTIONS` decorator.", async () => { - const userService = new ServiceBuilder() - .setEndpoint(TEST_SERVER_ENDPOINT) - .build(UserService); - const userId = 1; - const response = await userService.optionsUser(TOKEN, userId); - expect(response.config.method).toEqual("options"); - expect(response.config.url).toEqual(`${TEST_SERVER_ENDPOINT}${API_PREFIX}/users/${userId}`); - }); - - test("Test `@Path` decorator.", async () => { - const userService = new ServiceBuilder() - .setEndpoint(TEST_SERVER_ENDPOINT) - .build(UserService); - const userId = 1; - const response = await userService.getUser(TOKEN, userId); - expect(response.config.url).toEqual(`${TEST_SERVER_ENDPOINT}${API_PREFIX}/users/${userId}`); - }); - - test("Test `@Path` decorator 1.", async () => { - const userService = new ServiceBuilder() - .setEndpoint(TEST_SERVER_ENDPOINT) - .build(UserService); - const userId = 1; - const response = await userService.getUser1(TOKEN, userId); - expect(response.config.url).toEqual(`${TEST_SERVER_ENDPOINT}${API_PREFIX}/users/uid-${userId}`); - }); - - test("Test `@Body` decorator.", async () => { - const userService = new ServiceBuilder() - .setEndpoint(TEST_SERVER_ENDPOINT) - .build(UserService); - const newUser: User = { - name: "Jane", - age: 18 - }; - const response = await userService.createUser(TOKEN, newUser); - expect(response.config.data).toEqual(JSON.stringify(newUser)); - }); - - test("Test `@Headers` decorator.", async () => { - const authService = new ServiceBuilder() - .setEndpoint(TEST_SERVER_ENDPOINT) - .build(AuthService); - const auth: Auth = { - username: "test", - password: "123456", - }; - const response = await authService.auth(auth); - expect(response.config.headers["Content-Type"]).toEqual("application/x-www-form-urlencoded;charset=utf-8"); - expect(response.config.headers["Accept"]).toEqual("application/json"); - }); - - test("Test `@Header` decorator.", async () => { - const userService = new ServiceBuilder() - .setEndpoint(TEST_SERVER_ENDPOINT) - .build(UserService); - const response = await userService.getUsers(TOKEN); - expect(response.config.headers["X-Token"]).toEqual(TOKEN); - }); - - test("Test `@HeaderMap` decorator.", async () => { - const postService = new ServiceBuilder() - .setEndpoint(TEST_SERVER_ENDPOINT) - .build(PostService); - const post: Post = { title: "hello", content: "world" }; - const response = await postService.createPost3({ "X-Foo": "foo", "X-Bar": "bar" }, post); - expect(response.config.headers["X-Foo"]).toEqual("foo"); - expect(response.config.headers["X-Bar"]).toEqual("bar"); - }); - - test("Test `@Queries` decorator.", async () => { - const postService = new ServiceBuilder() - .setEndpoint(TEST_SERVER_ENDPOINT) - .build(PostService); - const response = await postService.getPosts(); - expect(response.config.params).toMatchObject({ - page: 1, - size: 20, - sort: "createdAt:desc" - }); - }); - - test("Test `@Query` decorator.", async () => { - const postService = new ServiceBuilder() - .setEndpoint(TEST_SERVER_ENDPOINT) - .build(PostService); - const response = await postService.getPosts1("typescript"); - expect(response.config.params.group).toEqual("typescript"); - }); - - test("Test `@QueryMap` decorator.", async () => { - const searchService = new ServiceBuilder() - .setEndpoint(TEST_SERVER_ENDPOINT) - .build(SearchService); - const query: SearchQuery = { - title: "TypeScript", - author: "John Doe", - }; - const response = await searchService.search(TOKEN, query); - expect(response.config.url).toEqual(`${TEST_SERVER_ENDPOINT}${API_PREFIX}/search`); - expect(response.config.params).toMatchObject(query); - }); - - test("Test `@FormUrlEncoded` decorator.", async () => { - const postService = new ServiceBuilder() - .setEndpoint(TEST_SERVER_ENDPOINT) - .build(PostService); - const response = await postService.createPost("hello", "world"); - expect(response.config.headers["Content-Type"]).toEqual("application/x-www-form-urlencoded;charset=utf-8"); - }); - - test("Test `@FormUrlEncoded` decorator with nested object.", async () => { - const groupService = new ServiceBuilder() - .setEndpoint(TEST_SERVER_ENDPOINT) - .build(GroupService); - const group: Group = { - name: "Video Game", - description: "Video game group!", - members: [1, 2, 3], - tags: ["video", "game", "PS4", "XBox"], - }; - const response = await groupService.createGroup(group); - expect(response.config.data).toEqual("name=Video%20Game&description=Video%20game%20group%21&members=%5B1%2C2%2C3%5D&tags=%5B%22video%22%2C%22game%22%2C%22PS4%22%2C%22XBox%22%5D"); - }); - - test("Test `@Field` decorator.", async () => { - const postService = new ServiceBuilder() - .setEndpoint(TEST_SERVER_ENDPOINT) - .build(PostService); - const response = await postService.createPost("hello", "world"); - expect(response.config.headers["Content-Type"]).toEqual("application/x-www-form-urlencoded;charset=utf-8"); - expect(response.config.data).toEqual("title=hello&content=world"); - }); - - test("Test `@FieldMap` decorator.", async () => { - const postService = new ServiceBuilder() - .setEndpoint(TEST_SERVER_ENDPOINT) - .build(PostService); - const response = await postService.createPost2({ title: "hello", content: "world" }); - expect(response.config.headers["Content-Type"]).toEqual("application/x-www-form-urlencoded;charset=utf-8"); - expect(response.config.data).toEqual("title=hello&content=world"); - }); - - test("Test `@Multipart` decorator.", async () => { - const fileService = new ServiceBuilder() - .setEndpoint(TEST_SERVER_ENDPOINT) - .build(FileService); - const bucket = { - value: "test-bucket", - }; - const file = { - value: fs.readFileSync("test/fixture/pic.png"), - filename: "pic.png", - }; - const response = await fileService.upload(bucket, file); - expect(response.config.headers["Content-Type"]).toContain("multipart/form-data"); - }); - - test("Test `@Multipart` decorator 1.", async () => { - const messagingService = new ServiceBuilder() - .setEndpoint(TEST_SERVER_ENDPOINT) - .build(MessagingService); - const from = { value: "+11111111" }; - const to = { value: ["+22222222", "+33333333"] }; - const response = await messagingService.createSMS(from, to); - expect(response.config.headers["Content-Type"]).toContain("multipart/form-data"); - }); - - test("Test multi-standalone services", async () => { - const standaloneId1 = Math.random().toString() - const axiosInstance1 = axios.create(); - axiosInstance1.interceptors.response.use((value) => { - value.config.standaloneId = standaloneId1; - return value; - }); - const userService1 = new ServiceBuilder() - .setStandalone(axiosInstance1) - .setEndpoint(TEST_SERVER_ENDPOINT) - .build(UserService); - - const response1 = await userService1.getUsers(TOKEN); - expect(response1.config.standaloneId).toEqual(standaloneId1); - - const standaloneId2 = Math.random().toString() - const axiosInstance2 = axios.create(); - axiosInstance2.interceptors.response.use((value) => { - value.config.standaloneId = standaloneId2; - return value; - }); - const userService2 = new ServiceBuilder() - .setStandalone(axiosInstance2) - .setEndpoint(TEST_SERVER_ENDPOINT) - .build(UserService); - - const response2 = await userService2.getUsers(TOKEN); - expect(response2.config.standaloneId).toEqual(standaloneId2); - - const standaloneId3 = Math.random().toString() - const axiosInstance3 = axios.create(); - axiosInstance3.interceptors.response.use((value) => { - value.config.standaloneId = standaloneId3; - return value; - }); - const userService3 = new ServiceBuilder() - .setStandalone(axiosInstance3) - .setEndpoint(TEST_SERVER_ENDPOINT) - .build(UserService); - - const response3 = await userService3.getUsers(TOKEN); - expect(response3.config.standaloneId).toEqual(standaloneId3); - }); - - test("Test Request Interceptors", async () => { - const requestInterceptor: RequestInterceptorFunction = (config) => { - switch (config.method) { - case 'GET': - case 'get': - if (typeof config.params !== 'object') config.params = {}; - config.params.role = 'interceptor'; - break; - case 'POST': - case 'post': - if (config.headers?.post['Content-Type'] === HttpContentType.urlencoded) { - const data = config.data; - const body: { [key: string]: string } = {}; - if (typeof data === 'string' && data.length) { - const list = data.split('&').map(v => v.split('=')); - for (const [key, value] of list) { - body[key] = value; - } - } else if (typeof data === 'object') { - for (const key in data) { - if (data.hasOwnProperty(key)) { - const element = data[key]; - body[key] = element; - } - } - } - body['role'] = 'interceptor'; - config.data = Object.entries(body).map(v => v.join('=')).join('&'); - } - break; - default: - break; - } - return config; - }; - - const interceptorService = new ServiceBuilder() - .setStandalone(true) - .setRequestInterceptors(requestInterceptor) - .setEndpoint(TEST_SERVER_ENDPOINT) - .build(InterceptorService); - - const response1 = await interceptorService.getParams(); - expect(response1.config.params.role).toEqual('interceptor'); - expect(response1.data.role).toEqual('interceptor'); - - const response2 = await interceptorService.createParams({ title: 'title', content: 'content' }); - expect(response2.data.role).toEqual('interceptor'); - }); - - test("Test Response Interceptors", async () => { - const standaloneId = 'im a interceptor'; - - const responseInterceptor: ResponseInterceptorFunction = (response) => { - response.config.standaloneId = standaloneId; - return response; - }; - - const userService = new ServiceBuilder() - .setStandalone(true) - .setResponseInterceptors(responseInterceptor) - .setEndpoint(TEST_SERVER_ENDPOINT) - .build(UserService); - - const response = await userService.getUsers(TOKEN); - expect(response.config.standaloneId).toEqual(standaloneId); - }); - - test("Test Interceptor Abstract Class", async () => { - class AddHeaderInterceptor extends RequestInterceptor { - - role = 'interceptor'; - - onFulfilled(config: AxiosRequestConfig) { - switch (config.method) { - case 'get': - case 'GET': - if (typeof config.headers?.get === 'object') { - config.headers.get['X-Role'] = this.role; - } - break; - - default: - break; - } - return config; - } - } - - const interceptorService = new ServiceBuilder() - .setStandalone(true) - .setRequestInterceptors(new AddHeaderInterceptor) - .setEndpoint(TEST_SERVER_ENDPOINT) - .build(InterceptorService); - - const response = await interceptorService.getHeader(); - expect(response.data.role).toEqual('interceptor'); - }); - - test("Test `@ResponseType` decorator.", async () => { - const fileService = new ServiceBuilder() - .setEndpoint(TEST_SERVER_ENDPOINT) - .build(FileService); - const response = await fileService.getFile("x-y-z"); - expect(response.config.responseType).toEqual("stream"); - }); - - test("Test `@Get` decorator and path is absolute URL.", async () => { - const service = new ServiceBuilder() - .setEndpoint(TEST_SERVER_ENDPOINT) - .build(UserService); - const response = await service.getUsersOther(TOKEN); - expect(response.config.method).toEqual("get"); - expect(response.config.url).toEqual(`${TEST_SERVER_ENDPOINT}/users`); - }); - - test("Test `@RequestTransformer` decorator.", async () => { - const service = new ServiceBuilder() - .setEndpoint(TEST_SERVER_ENDPOINT) - .build(TransformerService); - const response = await service.createSomething({ name: "ts-retrofit" }); - expect(response.config.data).toEqual('{"name":"ts-retrofit","foo":"foo"}'); - }); - - test("Test `@ResponseTransformer` decorator.", async () => { - const service = new ServiceBuilder() - .setEndpoint(TEST_SERVER_ENDPOINT) - .build(TransformerService); - const response = await service.getSomething(); - expect(response.data).toEqual({ foo: 'foo' }); - }); - - test("Test `setTimeout` method.", async () => { - const service = new ServiceBuilder() - .setEndpoint(TEST_SERVER_ENDPOINT) - .setTimeout(3000) - .build(TimeoutService); - await expect(service.sleep5000()).rejects.toThrow(/timeout/); - }); - - test("Test `@Timeout` decorator.", async () => { - const service = new ServiceBuilder() - .setEndpoint(TEST_SERVER_ENDPOINT) - .build(TimeoutService); - await expect(service.timeoutIn3000()).rejects.toThrow(/timeout/); - }); - - test("The timeout in `@Timeout` decorator should shield the value in `setTimeout` method.", async () => { - const service = new ServiceBuilder() - .setEndpoint(TEST_SERVER_ENDPOINT) - .setTimeout(3000) - .build(TimeoutService); - const response = await service.timeoutIn6000(); - expect(response.config.timeout).toEqual(6000); - expect(response.data).toEqual({}); - }); - - test("Test `@ResponseStatus` decorator.", async () => { - const service = new ServiceBuilder() - .setEndpoint(TEST_SERVER_ENDPOINT) - .build(ResponseStatusService); - expect(service.__meta__.getSomething.responseStatus).toEqual(200); - }); - - test("Test `@Config` decorator.", async () => { - const service = new ServiceBuilder() - .setEndpoint(TEST_SERVER_ENDPOINT) - .build(ConfigService); - const response = await service.getConfig(); - expect(response.config.maxRedirects).toEqual(1); - }); - - test("Test absolute URL.", async () => { - const service = new ServiceBuilder() - .setEndpoint(TEST_SERVER_ENDPOINT) - .build(AbsoluteURLService); - try { - const response = await service.getSomethingAbsolute(); - } catch (err) { - expect(err.config.url).toEqual("https://absolute-foobar.com"); - } - }); - - test("Test `ignoreBasePath` in HTTP method option.", async () => { - const service = new ServiceBuilder() - .setEndpoint(TEST_SERVER_ENDPOINT) - .build(HttpMethodOptionsService); - const response = await service.ping(); - expect(response.config.url).toEqual(`${TEST_SERVER_ENDPOINT}/ping`); - expect(response.data).toEqual({ result: "pong" }); - }); -}); diff --git a/tests/fixture/fixtures.convertTo.ts b/tests/fixture/fixtures.convertTo.ts new file mode 100644 index 0000000..d3925a1 --- /dev/null +++ b/tests/fixture/fixtures.convertTo.ts @@ -0,0 +1,45 @@ +import { ApiResponse, ApiResponseBody, BasePath, BaseService, ConvertTo, GET, Path } from "../../src"; +import { Post, PostAsClass, PostAsClassWithTransfromAndValidate, PostsApiService } from "./fixtures"; + +@BasePath(PostsApiService.BASE_PATH) +export class ConvertServiceInline extends BaseService { + @GET("/") + @ConvertTo(PostAsClass) + get(): ApiResponseBody {} + + @GET("/", { convertTo: PostAsClass }) + getConvertInMethod(): ApiResponseBody {} + + @GET("/") + getNoConvertTo(): ApiResponseBody {} + + @GET("/{id}") + @ConvertTo(PostAsClass) + getWithPath(@Path("id") id: number): ApiResponseBody {} + + @GET("/{id}", { convertTo: PostAsClass }) + getWithPathInMethod(@Path("id") id: number): ApiResponseBody {} + + @GET("/") + getToType(): ApiResponseBody {} +} + +@BasePath(PostsApiService.BASE_PATH) +export class ConvertToServiceRaw extends BaseService { + @GET("/") + @ConvertTo(PostAsClass) + get(): ApiResponse {} + + @GET("/") + getNoConvertTo(): ApiResponse {} + + @GET("/{id}") + @ConvertTo(PostAsClass) + getWithPath(@Path("id") id: number): ApiResponse {} + + @GET("/") + getToType(): ApiResponse {} + + @GET("/just-string", { convertTo: PostAsClassWithTransfromAndValidate }) + wrongConvertWhenReturnIsString(): ApiResponse {} +} diff --git a/tests/fixture/fixtures.formurlencoded.ts b/tests/fixture/fixtures.formurlencoded.ts new file mode 100644 index 0000000..1ded7b9 --- /dev/null +++ b/tests/fixture/fixtures.formurlencoded.ts @@ -0,0 +1,21 @@ +import { ApiResponse, BasePath, BaseService, Body, Field, FieldMap, FormUrlEncoded, POST } from "../../src"; +import { API_PREFIX, Post } from "./fixtures"; + +@BasePath(API_PREFIX) +export class FormUrlEncodedService extends BaseService { + @POST("/form-url-encoded") + @FormUrlEncoded + formUrlEncoded( + @Field("param1") param1: number, + @Field("param2") param2: string, + @Field("param3") param3: boolean, + ): ApiResponse {} + + @POST("/form-url-encoded") + @FormUrlEncoded + formUrlEncodedWithBody(@Body body: { param1: number; param2: string; param3: boolean }): ApiResponse {} + + @POST("/form-url-encoded") + @FormUrlEncoded + formUrlEncodedWithFieldMap(@FieldMap body: { param1: number; param2: string; param3: boolean }): ApiResponse {} +} diff --git a/tests/fixture/fixtures.multipart.ts b/tests/fixture/fixtures.multipart.ts new file mode 100644 index 0000000..26e80ec --- /dev/null +++ b/tests/fixture/fixtures.multipart.ts @@ -0,0 +1,21 @@ +import { BasePath, BaseService, GET, Multipart, Part, Path, POST, ResponseType, ApiResponse } from "../../src"; +import { PartDescriptor } from "../../src/constants"; +import { API_PREFIX } from "./fixtures"; + +@BasePath(API_PREFIX) +export class FileService extends BaseService { + @POST("/upload") + @Multipart + upload(@Part("bucket") bucket: PartDescriptor, @Part("file") file: PartDescriptor): ApiResponse {} + + @GET("/file") + @ResponseType("stream") + getFile(@Path("fileId") fileId: string): ApiResponse {} +} + +@BasePath(API_PREFIX) +export class MessagingService extends BaseService { + @POST("/sms") + @Multipart + createSMS(@Part("from") from: PartDescriptor, @Part("to") to: PartDescriptor): ApiResponse {} +} diff --git a/tests/fixture/fixtures.timeout.ts b/tests/fixture/fixtures.timeout.ts new file mode 100644 index 0000000..ddcd62e --- /dev/null +++ b/tests/fixture/fixtures.timeout.ts @@ -0,0 +1,16 @@ +import { BasePath, BaseService, GET, Timeout, ApiResponse } from "../../src"; +import { API_PREFIX } from "./fixtures"; + +@BasePath(API_PREFIX) +export class TimeoutService extends BaseService { + @GET("/sleep-5000") + sleep5000(): ApiResponse {} + + @GET("/sleep-5000") + @Timeout(3000) + timeoutIn3000(): ApiResponse {} + + @GET("/sleep-5000") + @Timeout(6000) + timeoutIn6000(): ApiResponse {} +} diff --git a/tests/fixture/fixtures.transformer.ts b/tests/fixture/fixtures.transformer.ts new file mode 100644 index 0000000..40ff115 --- /dev/null +++ b/tests/fixture/fixtures.transformer.ts @@ -0,0 +1,87 @@ +import { + BasePath, + BaseService, + Body, + GET, + POST, + RequestTransformer, + ResponseTransformer, + ApiResponse, +} from "../../src"; +import { Post, PostCreateDTO, PostsApiService } from "./fixtures"; + +@BasePath(PostsApiService.BASE_PATH) +export class RequestTransformerApiService extends BaseService { + @POST("/") + @RequestTransformer((data: Record) => { + data.title = "updated title1"; + return data; + }) + requestTransformer(@Body body: PostCreateDTO): ApiResponse {} + + @POST("/") + @RequestTransformer( + (data: Record) => { + data.title = "updated title1"; + return data; + }, + (data: Record) => { + data.title = "updated title2"; + return data; + }, + ) + twoTransformersAsArgument(@Body body: PostCreateDTO): ApiResponse {} + + @POST("/") + @RequestTransformer((data: PostCreateDTO) => { + data.title = "updated title1"; + return data; + }) + @POST("/") + @RequestTransformer((data: PostCreateDTO) => { + data.title = "updated title2"; + return data; + }) + twoTransformersAsDifferentDecorators(@Body body: PostCreateDTO): ApiResponse {} +} + +@BasePath(PostsApiService.BASE_PATH) +export class ResponseTransformerApiService extends BaseService { + @GET("/") + @ResponseTransformer((data: Record[], headers?: { [key: string]: unknown }) => { + data[0].title = "transformer"; + return data; + }) + array(): ApiResponse {} + + @POST("/") + @ResponseTransformer((data: Record, headers?: { [key: string]: unknown }) => { + data.title = "updated title2"; + return data; + }) + single(@Body body: PostCreateDTO): ApiResponse {} + + @POST("/") + @ResponseTransformer( + (data: Record, headers?: { [key: string]: unknown }) => { + data.title = "updated title1"; + return data; + }, + (data: Record, headers?: { [key: string]: unknown }) => { + data.title = "updated title2"; + return data; + }, + ) + twoTransformersAsArgument(@Body body: PostCreateDTO): ApiResponse {} + + @POST("/") + @ResponseTransformer((data: Record, headers?: { [key: string]: unknown }) => { + data.title = "updated title1"; + return data; + }) + @ResponseTransformer((data: Record, headers?: { [key: string]: unknown }) => { + data.title = "updated title2"; + return data; + }) + twoTransformersAsDifferentDecorators(@Body body: PostCreateDTO): ApiResponse {} +} diff --git a/tests/fixture/fixtures.ts b/tests/fixture/fixtures.ts new file mode 100644 index 0000000..ebf5dd3 --- /dev/null +++ b/tests/fixture/fixtures.ts @@ -0,0 +1,334 @@ +import { + ApiResponse, + ApiResponseBody, + BasePath, + BaseService, + Body, + Config, + DELETE, + Field, + FieldMap, + FormUrlEncoded, + GET, + HEAD, + Header, + HeaderMap, + Headers, + OPTIONS, + PATCH, + Path, + POST, + PUT, + Queries, + Query, + QueryMap, + ResponseStatus, +} from "../../src"; +import { JSONPLACEHOLDER_URL } from "../testHelpers"; +import { Type } from "class-transformer"; +import { IsNotEmpty } from "class-validator"; + +export const API_PREFIX = "/api/v1"; +export const TOKEN = "abcdef123456"; +export const TEST_HEADER = "TEST_HEADER"; + +export interface PostCreateDTO { + userId: number; + title: string; + body: string; +} + +export class PostAsClass { + id!: number; + userId!: number; + title!: string; + body!: string; + + methodInside() { + return this.id; + } +} + +export class PostAsClassWithTransfromAndValidate { + id = -1; + userId = -1; + title = ""; + @IsNotEmpty() + body = ""; + + @Type(() => Date) + date: Date = new Date(); +} + +export interface Post extends PostCreateDTO { + id: number; +} + +export interface SearchQuery { + title?: string; + body?: string; + userId?: number; +} + +export const posts: Post[] = [ + { + id: 1, + userId: 1, + body: "body1", + title: "title1", + }, + { + id: 2, + userId: 2, + body: "body2", + title: "title2", + }, +]; + +@BasePath(PostsApiService.BASE_PATH) +export class PostsApiService extends BaseService { + static BASE_PATH = "/posts"; + + static dto = { + body: "updatedBody", + title: "updatedTitle", + userId: 100, + }; + + @GET("/") + get(): ApiResponse {} + + @GET("/just-string") + getJustString(): ApiResponse {} + + @GET("/posts", { ignoreBasePath: true }) + getIgnoreBasePath(): ApiResponse {} + + @GET(`${JSONPLACEHOLDER_URL}${PostsApiService.BASE_PATH}`) + getAbsoluteUrl(): ApiResponse {} + + @GET("/{id}") + getWithPath(@Path("id") id: string): ApiResponse {} + + @POST("/") + post(@Body body: PostCreateDTO): ApiResponse {} + + @POST("/body-as-array") + bodyAsArray(@Body body: PostCreateDTO[]): ApiResponse {} + + @PUT("/{id}") + put(@Path("id") id: number, @Body body: PostCreateDTO): ApiResponse {} + + @PATCH("/{id}") + patch(@Path("id") id: number, @Body body: PostCreateDTO): ApiResponse {} + + @DELETE("/{id}") + delete(@Path("id") id: number): ApiResponse {} + + @HEAD("/{id}") + head(@Path("id") id: number): ApiResponse {} + + @OPTIONS("/{id}") + options(@Path("id") id: number): ApiResponse {} + + @POST("/") + @Headers({ + Header1: "Value1", + Header2: "Value2", + }) + headers(@Body body: PostCreateDTO): ApiResponse {} + + @GET("/") + header(@Header("Header") header: string): ApiResponse {} + + @GET("/") + headerMap(@HeaderMap headers: { [key: string]: unknown }): ApiResponse {} + + @GET("/") + @Queries({ + page: 1, + size: 20, + sort: "createdAt:desc", + }) + queries(): ApiResponse {} + + @GET("/") + query(@Query("userId") userId: number): ApiResponse {} + + @GET("/") + queryMap(@QueryMap query: SearchQuery): ApiResponse {} + + @POST("/") + @FormUrlEncoded + formUrlEncoded( + @Field("userId") userId: number, + @Field("title") title: string, + @Field("body") body: string, + ): ApiResponse {} + + @POST("/") + @FormUrlEncoded + formUrlEncodedWithBody(@Body body: PostCreateDTO): ApiResponse {} + + @POST("/") + @FormUrlEncoded + fieldMapUrlEncoded(@FieldMap body: PostCreateDTO): ApiResponse {} + + @POST("/") + fieldMap(@FieldMap body: PostCreateDTO): ApiResponse {} + + @POST("/") + field( + @Field("userId") userId: number, + @Field("title") title: string, + @Field("body") body: string, + ): ApiResponse {} + + @GET("/") + @ResponseStatus(200) + responseStatus(): ApiResponse {} + + @GET("/") + @Config({ + maxRedirects: 3, + }) + config(): ApiResponse {} + + @GET("/asdasda/sdasdasda/sdasd/asdkjajkldkasd", { ignoreBasePath: true }) + wrongUrl(): ApiResponse {} +} + +@BasePath(PostsApiService.BASE_PATH) +export class ResponseBodyPostsApiService extends BaseService { + @GET("/") + get(): ApiResponseBody {} + + @GET("/posts", { ignoreBasePath: true }) + getIgnoreBasePath(): ApiResponseBody {} + + @GET(`${JSONPLACEHOLDER_URL}${PostsApiService.BASE_PATH}`) + getAbsoluteUrl(): ApiResponseBody {} + + @GET("/{id}") + getWithPath(@Path("id") id: string): ApiResponseBody {} + + @POST("/") + post(@Body body: PostCreateDTO): ApiResponseBody {} + + @PUT("/{id}") + put(@Path("id") id: number, @Body body: PostCreateDTO): ApiResponseBody {} + + @PATCH("/{id}") + patch(@Path("id") id: number, @Body body: PostCreateDTO): ApiResponseBody {} + + @DELETE("/{id}") + delete(@Path("id") id: number): ApiResponseBody {} + + @HEAD("/{id}") + head(@Path("id") id: number): ApiResponseBody {} + + @OPTIONS("/{id}") + options(@Path("id") id: number): ApiResponseBody {} + + @POST("/") + @Headers({ + Header1: "Value1", + Header2: "Value2", + }) + headers(@Body body: PostCreateDTO): ApiResponseBody {} + + @GET("/") + header(@Header("Header") header: string): ApiResponseBody {} + + @GET("/") + headerMap(@HeaderMap headers: { [key: string]: unknown }): ApiResponseBody {} + + @GET("/") + @Queries({ + page: 1, + size: 20, + sort: "createdAt:desc", + }) + queries(): ApiResponseBody {} + + @GET("/") + query(@Query("userId") userId: number): ApiResponseBody {} + + @GET("/") + queryMap(@QueryMap query: SearchQuery): ApiResponseBody {} + + @POST("/") + @FormUrlEncoded + formUrlEncoded( + @Field("userId") userId: number, + @Field("title") title: string, + @Field("body") body: string, + ): ApiResponseBody {} + + @POST("/") + @FormUrlEncoded + formUrlEncodedWithBody(@Body body: PostCreateDTO): ApiResponseBody {} + + @POST("/") + @FormUrlEncoded + fieldMapUrlEncoded(@FieldMap body: PostCreateDTO): ApiResponseBody {} + + @POST("/") + fieldMap(@FieldMap body: PostCreateDTO): ApiResponseBody {} + + @POST("/") + field( + @Field("userId") userId: number, + @Field("title") title: string, + @Field("body") body: string, + ): ApiResponseBody {} + + @GET("/") + @ResponseStatus(200) + responseStatus(): ApiResponseBody {} + + @GET("/") + @Config({ + maxRedirects: 3, + }) + config(): ApiResponseBody {} + + @GET("/asdasda/sdasdasda/sdasd/asdkjajkldkasd", { ignoreBasePath: true }) + wrongUrl(): ApiResponseBody {} +} + +export class WithHeaderService extends BaseService { + @GET("/with-headers") + withHeaders(): ApiResponse {} + + @GET("/with-oauth") + withOauth(): ApiResponse {} +} + +export class ResponseBodyWithHeaderService extends BaseService { + @GET("/with-headers") + withHeaders(): ApiResponseBody {} + + @GET("/with-oauth") + withOauth(): ApiResponseBody {} +} + +export class ServiceWithoutBasePath extends BaseService { + @GET("/posts") + get(): ApiResponse {} +} + +export class ResponseBodyServiceWithoutBasePath extends BaseService { + @GET("/posts") + get(): ApiResponse {} +} + +@BasePath(PostsApiService.BASE_PATH) +export class WithMethodsService extends BaseService { + @GET("/") + get(): ApiResponse {} + + methodCallsGet() { + return this.get(); + } +} diff --git a/tests/fixture/fixtures.validate.ts b/tests/fixture/fixtures.validate.ts new file mode 100644 index 0000000..611c25b --- /dev/null +++ b/tests/fixture/fixtures.validate.ts @@ -0,0 +1,108 @@ +import { ApiResponse, BasePath, BaseService, GET, Path, ConvertTo, ApiResponseBody } from "../../src"; +import { PostsApiService } from "./fixtures"; +import { IsNegative, IsPositive, MinLength } from "class-validator"; + +export class ValidationPass { + @IsPositive() + id!: number; + + @MinLength(1) + body!: string; + + @IsPositive() + userId!: number; + + methodInside() { + return this.id; + } +} + +export class ValidationFailsOneField { + id!: number; + + @MinLength(100) + body!: string; + + userId!: number; + + methodInside() { + return this.id; + } +} + +export class ValidationFailsTwoFields { + id!: number; + + @MinLength(100) + body!: string; + + @IsNegative() + userId!: number; + + methodInside() { + return this.id; + } +} + +@BasePath(PostsApiService.BASE_PATH) +export class ValidationPassService extends BaseService { + @GET("/") + @ConvertTo(ValidationPass) + getAll(): ApiResponse {} + + @GET("/{id}") + @ConvertTo(ValidationPass) + single(@Path("id") id: number): ApiResponse {} +} + +@BasePath(PostsApiService.BASE_PATH) +export class ValidationPassServiceInlinedResponse extends BaseService { + @GET("/") + @ConvertTo(ValidationPass) + getAll(): ApiResponseBody {} + + @GET("/{id}") + @ConvertTo(ValidationPass) + single(@Path("id") id: number): ApiResponseBody {} +} + +@BasePath(PostsApiService.BASE_PATH) +export class ValidationFailService extends BaseService { + @GET("/not-found2222", { ignoreBasePath: true, convertTo: ValidationFailsOneField }) + wrongUrlAndOneField(): ApiResponse {} + + @GET("/") + @ConvertTo(ValidationFailsOneField) + array(): ApiResponse {} + + @GET("/") + @ConvertTo(ValidationFailsTwoFields) + arrayTwoFields(): ApiResponse {} + + @GET("/{id}") + @ConvertTo(ValidationFailsOneField) + singleOneField(@Path("id") id: number): ApiResponse {} + + @GET("/{id}") + @ConvertTo(ValidationFailsTwoFields) + singleTwoFields(@Path("id") id: number): ApiResponse {} +} + +@BasePath(PostsApiService.BASE_PATH) +export class ValidationFailServiceInlinedBody extends BaseService { + @GET("/") + @ConvertTo(ValidationFailsOneField) + array(): ApiResponseBody {} + + @GET("/") + @ConvertTo(ValidationFailsTwoFields) + arrayTwoFields(): ApiResponseBody {} + + @GET("/{id}") + @ConvertTo(ValidationFailsOneField) + singleOneField(@Path("id") id: number): ApiResponseBody {} + + @GET("/{id}") + @ConvertTo(ValidationFailsTwoFields) + singleTwoFields(@Path("id") id: number): ApiResponseBody {} +} diff --git a/tests/fixture/fixtures.wrong-cases.ts b/tests/fixture/fixtures.wrong-cases.ts new file mode 100644 index 0000000..5e302c9 --- /dev/null +++ b/tests/fixture/fixtures.wrong-cases.ts @@ -0,0 +1,121 @@ +import { + ApiResponse, + BasePath, + BaseService, + Body, + Config, + Field, + FieldMap, + FormUrlEncoded, + GET, + Header, + HeaderMap, + Headers, + Multipart, + Part, + Path, + POST, + Queries, + Query, + QueryMap, + ResponseStatus, +} from "../../src"; +import { API_PREFIX, Post, PostsApiService } from "./fixtures"; +import { PartDescriptor } from "../../src/constants"; + +export class WrongHeaderService extends BaseService { + @GET("/") + wrongHeaderMap(@HeaderMap headers: { [key: string]: unknown }): ApiResponse {} + + @GET("/") + wrongHeaderType(@Header("Header") header: unknown): ApiResponse {} + + @GET("/") + emptyHeaderKey(@Header("") header: unknown): ApiResponse {} +} + +@BasePath(PostsApiService.BASE_PATH) +export class WrongFieldService extends BaseService { + @POST("/") + wrongFieldMap(@FieldMap param: { [key: string]: unknown }): ApiResponse {} + + @POST("/") + wrongFieldMapType(@FieldMap param: string[]): ApiResponse {} + + @POST("/") + fieldMapWithBodyArray(@FieldMap param: { [key: string]: unknown }, @Body body: string[]): ApiResponse {} + + @POST("/") + emptyFieldKey(@Field("") param: unknown): ApiResponse {} + + @POST("/") + fieldWithBodyArray(@Field("p") param: unknown, @Body body: number[]): ApiResponse {} +} + +export class WrongQueryService extends BaseService { + @GET("/") + wrongQuery(@Query("userId") userId: unknown): ApiResponse {} + + @GET("/") + wrongQueryMap(@QueryMap query: unknown): ApiResponse {} + + @GET("/") + emptyQueryKey(@Query("") query: unknown): ApiResponse {} +} + +@BasePath(API_PREFIX) +export class WrongMultipartService extends BaseService { + @POST("/upload") + @Multipart + emptyPartKey(@Part("") bucket: PartDescriptor): ApiResponse {} + + @POST("/upload") + @Multipart + partAsIsNotPartDescriptor(@Part("from") from: string): ApiResponse {} + + @POST("/upload") + @Multipart + withBody(@Part("bucket") bucket: PartDescriptor, @Body body: number[]): ApiResponse {} +} + +export class NoHttpMethodService extends BaseService { + path(@Path("id") id: number): ApiResponse {} + + @Headers({ + Header1: "Value1", + Header2: "Value2", + }) + headers(): ApiResponse {} + + @Queries({ + page: 1, + size: 20, + sort: "createdAt:desc", + }) + queries(): ApiResponse {} + + @FormUrlEncoded + formUrlEncoded(): ApiResponse {} + + field(@Field("userId") userId: number): ApiResponse {} + + @ResponseStatus(200) + responseStatus(): ApiResponse {} + + @Config({ + maxRedirects: 3, + }) + config(): ApiResponse {} + + validMethodNoParams() { + return 100; + } + + validMethodWithOneParam(a: string) { + return a; + } + + validMethodWithTwoParams(a: string, b: string) { + return a + b; + } +} diff --git a/test/fixture/pic.png b/tests/fixture/pic.png similarity index 100% rename from test/fixture/pic.png rename to tests/fixture/pic.png diff --git a/tests/fixture/server.ts b/tests/fixture/server.ts new file mode 100644 index 0000000..6ace54d --- /dev/null +++ b/tests/fixture/server.ts @@ -0,0 +1,97 @@ +import express from "express"; +import bodyParser from "body-parser"; +import multer from "multer"; +import { posts, TEST_HEADER } from "./fixtures"; + +export const app = express(); + +const jsonParser = bodyParser.json(); +const upload = multer(); +app.use(bodyParser.urlencoded({ extended: false })); + +const sleep = async (milliseconds: number): Promise => { + return new Promise((resolve) => { + setTimeout(() => { + resolve(); + }, milliseconds); + }); +}; + +app.get("/posts/just-string", jsonParser, function (req, res) { + res.status(200).send("just string"); +}); + +app.post("/posts/body-as-array", jsonParser, function (req, res) { + res.status(201).json(req.body); +}); + +app.get("/posts/not-found", jsonParser, function (req, res) { + res.status(404).send({}); +}); + +app.get("/with-headers", jsonParser, function (req, res) { + res.status(200).send(req.header(TEST_HEADER)); +}); + +app.get("/with-oauth", jsonParser, function (req, res) { + res.status(200).send(req.header("Authorization")); +}); + +app.get("/posts", jsonParser, function (req, res) { + res.status(200).json(posts); +}); + +app.post("/posts", jsonParser, function (req, res) { + res.status(201).json(req.body); +}); + +app.get("/posts/:id", jsonParser, function (req, res) { + res.status(200).json(posts.find((p) => p.id === Number(req.params["id"]))); +}); + +app.put("/posts/:id", jsonParser, function (req, res) { + const found = posts.find((p) => p.id === Number(req.params["id"])); + res.status(200).json({ ...found, ...req.body }); +}); + +app.patch("/posts/:id", jsonParser, function (req, res) { + const found = posts.find((p) => p.id === Number(req.params["id"])); + res.status(200).json({ ...found, ...req.body }); +}); + +app.delete("/posts/:id", jsonParser, function (req, res) { + res.status(200).json(posts.find((p) => p.id === Number(req.params["id"]))); +}); + +app.head("/posts/:id", jsonParser, function (req, res) { + res.status(200).json(posts.find((p) => p.id === Number(req.params["id"]))); +}); +app.options("/posts/:id", jsonParser, function (req, res) { + res.status(204).json(posts.find((p) => p.id === Number(req.params["id"]))); +}); +/////////////////////////////////////////////////////////////////////////////////////////////////// + +app.post("/api/v1/form-url-encoded", jsonParser, function (req, res) { + res.status(200).json(req.body); +}); + +app.post("/api/v1/upload", upload.any(), function (req, res) { + res.status(200).json({}); +}); + +app.get("/api/v1/file", upload.any(), function (req, res) { + res.status(200).json({}); +}); + +app.post("/api/v1/sms", jsonParser, function (req, res) { + res.status(200).json({}); +}); + +app.get("/api/v1/sleep-5000", async function (req, res) { + await sleep(5000); + res.status(200).json({}); +}); + +app.get("/ping", async function (req, res) { + res.status(200).json({ result: "pong" }); +}); diff --git a/test/dataResolver.test.ts b/tests/test/dataResolver.test.ts similarity index 60% rename from test/dataResolver.test.ts rename to tests/test/dataResolver.test.ts index c1fd6d7..bddf34d 100644 --- a/test/dataResolver.test.ts +++ b/tests/test/dataResolver.test.ts @@ -1,24 +1,21 @@ import { - BaseDataResolver, FormUrlencodedResolver, MultiPartResolver, JsonResolver, TextXmlResolver, DataResolverFactory, -} from "../src/dataResolver"; + DataResolverFactory, + FormUrlencodedResolver, + JsonResolver, + MultiPartResolver, + TextXmlResolver, +} from "../../src/dataResolver"; import * as fs from "fs"; +import { CONTENT_TYPE, CONTENT_TYPE_HEADER } from "../../src/constants"; -describe("Test data resolver.", () => { - test("Test BaseDataResolver.", async () => { - const baseDataResolver = new BaseDataResolver(); - const t = () => { - baseDataResolver.resolve({}, {}); - }; - expect(t).toThrowError("Can not call this method in BaseDataResolver."); - }); - - test("Test FormUrlencodedResolver with flat object.", async () => { +describe("Data resolver.", () => { + test("FormUrlencodedResolver with flat object.", async () => { const formUrlencodedResolver = new FormUrlencodedResolver(); const headers = { - "content-type": "application/x-www-form-urlencoded", + [CONTENT_TYPE_HEADER]: CONTENT_TYPE.FORM_URL_ENCODED, }; const obj = { - foo: 'bar', + foo: "bar", }; const data = Object.create(obj); data.a = 1; @@ -29,10 +26,10 @@ describe("Test data resolver.", () => { expect(resolvedData).toEqual("a=1&b=hello&c=true&d=null"); }); - test("Test FormUrlencodedResolver with nested object.", async () => { + test("FormUrlencodedResolver with nested object.", async () => { const formUrlencodedResolver = new FormUrlencodedResolver(); const headers = { - "content-type": "application/x-www-form-urlencoded", + [CONTENT_TYPE_HEADER]: CONTENT_TYPE.FORM_URL_ENCODED, }; const data = { a: 1, @@ -45,16 +42,16 @@ describe("Test data resolver.", () => { expect(resolvedData).toEqual("a=1&b=hello&c=true&d=null&e=%5B%22foo%22%2C%22bar%22%5D"); }); - test("Test MultiPartResolver.", async () => { + test("MultiPartResolver.", async () => { const multiPartResolver = new MultiPartResolver(); const headers = { - "content-type": "multipart/form-data", + [CONTENT_TYPE_HEADER]: CONTENT_TYPE.MULTIPART_FORM_DATA, }; const bucket = { value: "test-bucket", }; const file = { - value: fs.readFileSync("test/fixture/pic.png"), + value: fs.readFileSync("tests/fixture/pic.png"), filename: "pic.png", }; const data = { @@ -62,20 +59,20 @@ describe("Test data resolver.", () => { file, }; const resolvedData = multiPartResolver.resolve(headers, data); - expect(resolvedData._streams).toContain("test-bucket"); + expect(resolvedData["_streams"]).toContain("test-bucket"); }); - test("Test JsonResolver.", async () => { + test("JsonResolver.", async () => { const jsonResolver = new JsonResolver(); const headers = { - "content-type": "application/json", + [CONTENT_TYPE_HEADER]: CONTENT_TYPE.APPLICATION_JSON, }; const data = { a: 1, b: "b", c: true, d: null, - e: [1,2,3], + e: [1, 2, 3], f: { f1: 1, f2: ["a", "b", "c"], @@ -85,10 +82,10 @@ describe("Test data resolver.", () => { expect(resolvedData).toStrictEqual(resolvedData); }); - test("Test TextXmlResolver.", async () => { + test("TextXmlResolver.", async () => { const textXmlResolver = new TextXmlResolver(); const headers = { - "content-type": "text/xml", + [CONTENT_TYPE_HEADER]: CONTENT_TYPE.XML, }; const xmlString = ` @@ -102,9 +99,8 @@ describe("Test data resolver.", () => { expect(resolvedData).toStrictEqual(xmlString); }); - test("Test DataResolverFactory.", async () => { - const dataResolverFactory = new DataResolverFactory(); - const dataResolver = dataResolverFactory.createDataResolver('application/user-defined-content-type'); + test("DataResolverFactory.", async () => { + const dataResolver = DataResolverFactory.createDataResolver("application/user-defined-content-type"); expect(dataResolver instanceof JsonResolver).toBeTruthy(); }); }); diff --git a/tests/test/decorators/convertTo.test.ts b/tests/test/decorators/convertTo.test.ts new file mode 100644 index 0000000..3d9793b --- /dev/null +++ b/tests/test/decorators/convertTo.test.ts @@ -0,0 +1,98 @@ +import { ErrorMessages, ServiceBuilder } from "../../../src"; +import { testServer, validateThrows, verifyRequest } from "../../testHelpers"; +import { ConvertServiceInline, ConvertToServiceRaw } from "../../fixture/fixtures.convertTo"; +import { PostAsClass, posts } from "../../fixture/fixtures"; + +describe("@ConvertTo", () => { + describe("AxiosResponse", () => { + let service: ConvertToServiceRaw; + + beforeAll(() => { + service = new ServiceBuilder() + .baseUrl(testServer.url) + .validateResponse() + .withRequestLogger({ showLogs: false, logLevel: "LOG" }) // to test logger + .saveRequestHistory() + .build(ConvertToServiceRaw); + }); + + test("@GET", async () => { + const response = await service.get(); + expect(response.data[0].methodInside()).toBe(1); + expect(response.data[1].methodInside()).toBe(2); + verifyRequest(response, "get"); + }); + + test("@GET - to type", async () => { + const response = await service.getToType(); + expect(response.data.length).toBe(posts.length); + verifyRequest(response, "get"); + }); + + test("@GET - single", async () => { + const response = await service.getWithPath(1); + expect(response.data.methodInside()).toBe(1); + verifyRequest(response, "get", "/posts/1"); + }); + + test("No ConvertTo", async () => { + const result = await service.getNoConvertTo(); + expect(result.data[0].methodInside).toBeUndefined(); + expect(result.data[1].methodInside).toBeUndefined(); + }); + + test("Wrong - Response is string", async () => { + await validateThrows( + () => service.wrongConvertWhenReturnIsString(), + (er) => { + const errorMessage = ErrorMessages.VALIDATION_NOT_OBJECT.replace("{}", "just string"); + expect(er.message).toBe(errorMessage); + }, + ); + }); + }); + + describe("Inline", () => { + let service: ConvertServiceInline; + + beforeAll(() => { + service = new ServiceBuilder() + .baseUrl(testServer.url) + .saveRequestHistory() + .inlineResponseBody() + .build(ConvertServiceInline); + }); + + test("@GET", async () => { + verifyGet(await service.get()); + }); + + test("@GET in method", async () => { + verifyGet(await service.getConvertInMethod()); + }); + + function verifyGet(response: PostAsClass[]) { + expect(response[0].methodInside()).toBe(1); + expect(response[1].methodInside()).toBe(2); + verifyRequest(service.__getLastRequest(), "get"); + } + + test("@GET - to type", async () => { + const response = await service.getToType(); + expect(response.length).toBe(posts.length); + verifyRequest(service.__getLastRequest(), "get"); + }); + + test("@GET - single", async () => { + const response = await service.getWithPath(1); + expect(response.methodInside()).toBe(1); + verifyRequest(service.__getLastRequest(), "get", "/posts/1"); + }); + + test("No ConvertTo", async () => { + const result = await service.getNoConvertTo(); + expect(result[0].methodInside).toBeUndefined(); + expect(result[1].methodInside).toBeUndefined(); + }); + }); +}); diff --git a/tests/test/decorators/decorators.test.ts b/tests/test/decorators/decorators.test.ts new file mode 100644 index 0000000..9dbc8e6 --- /dev/null +++ b/tests/test/decorators/decorators.test.ts @@ -0,0 +1,190 @@ +import { JSONPLACEHOLDER_URL, testServer, verifyRequest } from "../../testHelpers"; +import { ServiceBuilder } from "../../../src"; +import { posts, PostsApiService, ServiceWithoutBasePath, WithMethodsService } from "../../fixture/fixtures"; +import { CONTENT_TYPE, CONTENT_TYPE_HEADER } from "../../../src/constants"; +import { AxiosResponse } from "axios"; + +describe("Decorators", () => { + let service: PostsApiService; + + beforeAll(() => { + service = new ServiceBuilder().baseUrl(testServer.url).withRequestLogger().build(PostsApiService); + }); + + test("@BasePath", async () => { + const response = await service.get(); + expect(response.config.url).toEqual(postsUrl()); + }); + + test("@GET", async () => { + const response = await service.get(); + expect(response.data).toHaveLength(posts.length); + + verifyRequest(response, "get"); + }); + + test("@GET - return is just string", async () => { + const response = await service.getJustString(); + expect(response.data).toBe("just string"); + }); + + test("@GET - without base path", async () => { + const service = new ServiceBuilder().baseUrl(testServer.url).build(ServiceWithoutBasePath); + const response = await service.get(); + + expect(response.data).toHaveLength(posts.length); + + verifyRequest(response, "get", "/posts"); + }); + + test("@GET - ignore base path", async () => { + const response = await service.getIgnoreBasePath(); + expect(response.data).toHaveLength(posts.length); + + verifyRequest(response, "get", "/posts"); + }); + + test("@GET - Absolute url", async () => { + const service = new ServiceBuilder().baseUrl(JSONPLACEHOLDER_URL).build(PostsApiService); + const response = await service.getAbsoluteUrl(); + expect(response.data).toHaveLength(100); + verifyRequest(response, "get", "/posts"); + }); + + test("@Body as array", async () => { + const response = await service.bodyAsArray([PostsApiService.dto, PostsApiService.dto]); + verifyRequest(response, "post", "/posts/body-as-array", 201); + verifyBody(response, [PostsApiService.dto, PostsApiService.dto]); + }); + + test("@POST", async () => { + const response = await service.post(PostsApiService.dto); + + verifyRequest(response, "post", "/posts/", 201); + verifyBody(response, PostsApiService.dto); + }); + + test("@PUT", async () => { + const response = await service.put(1, PostsApiService.dto); + + verifyRequest(response, "put", "/posts/1", 200); + verifyBody(response, PostsApiService.dto); + }); + + test("@PATCH", async () => { + const response = await service.patch(1, PostsApiService.dto); + + verifyRequest(response, "patch", "/posts/1", 200); + verifyBody(response, PostsApiService.dto); + }); + + test("@DELETE", async () => { + const response = await service.delete(1); + verifyRequest(response, "delete", "/posts/1"); + }); + + test("@HEAD", async () => { + const response = await service.head(1); + verifyRequest(response, "head", "/posts/1"); + }); + + test("@OPTIONS", async () => { + const response = await service.options(1); + verifyRequest(response, "options", "/posts/1", 204); + }); + + test("@Headers", async () => { + const response = await service.headers(PostsApiService.dto); + expect(response.config.headers!["Header1"]).toBe("Value1"); + expect(response.config.headers!["Header2"]).toBe("Value2"); + verifyRequest(response, "post", "/posts/", 201); + }); + + test("@Header", async () => { + const response = await service.header("Value1"); + expect(response.config.headers!["Header"]).toBe("Value1"); + verifyRequest(response, "get"); + }); + + test("@HeaderMap", async () => { + const response = await service.headerMap({ h1: 1, h2: "v2", h3: true }); + expect(response.config.headers!["h1"]).toBe("1"); + expect(response.config.headers!["h2"]).toBe("v2"); + expect(response.config.headers!["h3"]).toBe("true"); + verifyRequest(response, "get"); + }); + + test("@Queries", async () => { + const response = await service.queries(); + expect(response.config.params).toMatchObject({ + page: 1, + size: 20, + sort: "createdAt:desc", + }); + }); + + test("@Query", async () => { + const response = await service.query(15); + expect(response.config.params.userId).toBe(15); + }); + + test("@ResponseStatus", async () => { + expect(service.__getServiceMetadata().getMetadata("responseStatus").responseStatus).toEqual(200); + }); + + test("@Config", async () => { + const response = await service.config(); + expect(response.config.maxRedirects).toEqual(3); + }); + + test("@Field", async () => { + const response = await service.field( + PostsApiService.dto.userId, + PostsApiService.dto.title, + PostsApiService.dto.body, + ); + + expect(response.config.headers![CONTENT_TYPE_HEADER]).toBe(CONTENT_TYPE.APPLICATION_JSON); + + verifyRequest(response, "post", "/posts/", 201); + verifyBody(response, PostsApiService.dto); + }); + + test("@FieldMap", async () => { + const response = await service.fieldMap(PostsApiService.dto); + + expect(response.config.headers![CONTENT_TYPE_HEADER]).toBe(CONTENT_TYPE.APPLICATION_JSON); + + verifyRequest(response, "post", "/posts/", 201); + verifyBody(response, PostsApiService.dto); + }); + + test("@QueryMap", async () => { + const response = await service.queryMap({ userId: 15, body: "b", title: "t" }); + expect(response.config.params.userId).toBe(15); + expect(response.config.params.body).toBe("b"); + expect(response.config.params.title).toBe("t"); + + verifyRequest(response, "get", "/posts/?userId=15&body=b&title=t"); + }); + + test("Methods that are not decorated should work", async () => { + const withMethodsService = new ServiceBuilder().baseUrl(testServer.url).build(WithMethodsService); + + const response = await withMethodsService.methodCallsGet(); + expect(response.data).toHaveLength(posts.length); + + verifyRequest(response, "get"); + }); + + function verifyBody(response: AxiosResponse, expectedRequestBody?: T) { + if (!expectedRequestBody) return; + + expect(JSON.parse(response.config.data)).toMatchObject(expectedRequestBody); + expect(response.data).toMatchObject(expectedRequestBody); + } + + function postsUrl() { + return `${testServer.url}${PostsApiService.BASE_PATH}/`; + } +}); diff --git a/tests/test/decorators/formurlencoded.test.ts b/tests/test/decorators/formurlencoded.test.ts new file mode 100644 index 0000000..c220d1e --- /dev/null +++ b/tests/test/decorators/formurlencoded.test.ts @@ -0,0 +1,48 @@ +import { ServiceBuilder } from "../../../src"; +import { testServer } from "../../testHelpers"; +import { CHARSET_UTF_8, CONTENT_TYPE, CONTENT_TYPE_HEADER } from "../../../src/constants"; +import { FormUrlEncodedService } from "../../fixture/fixtures.formurlencoded"; + +describe("Decorators - @FormUrlEncoded", () => { + let service: FormUrlEncodedService; + + beforeAll(() => { + service = new ServiceBuilder().baseUrl(testServer.url).build(FormUrlEncodedService); + }); + + const object = { + param1: 1, + param2: "a", + param3: true, + }; + + const objectFieldsAsString = { + param1: "1", + param2: "a", + param3: "true", + }; + + test("Primitive types", async () => { + const response = await service.formUrlEncoded(object.param1, object.param2, object.param3); + + expect(response.data).toMatchObject(objectFieldsAsString); + expect(response.config.headers![CONTENT_TYPE_HEADER]).toEqual(`${CONTENT_TYPE.FORM_URL_ENCODED};${CHARSET_UTF_8}`); + expect(response.config.data).toEqual(`param1=${object.param1}¶m2=${object.param2}¶m3=${object.param3}`); + }); + + test("With @Body", async () => { + const response = await service.formUrlEncodedWithBody(object); + + expect(response.data).toMatchObject(objectFieldsAsString); + expect(response.config.headers![CONTENT_TYPE_HEADER]).toEqual(`${CONTENT_TYPE.FORM_URL_ENCODED};${CHARSET_UTF_8}`); + expect(response.config.data).toEqual(`param1=${object.param1}¶m2=${object.param2}¶m3=${object.param3}`); + }); + + test("With @FieldMap", async () => { + const response = await service.formUrlEncodedWithFieldMap(object); + + expect(response.data).toMatchObject(objectFieldsAsString); + expect(response.config.headers![CONTENT_TYPE_HEADER]).toEqual(`${CONTENT_TYPE.FORM_URL_ENCODED};${CHARSET_UTF_8}`); + expect(response.config.data).toEqual(`param1=${object.param1}¶m2=${object.param2}¶m3=${object.param3}`); + }); +}); diff --git a/tests/test/decorators/inlined-body.test.ts b/tests/test/decorators/inlined-body.test.ts new file mode 100644 index 0000000..ba7fc4e --- /dev/null +++ b/tests/test/decorators/inlined-body.test.ts @@ -0,0 +1,198 @@ +import { AxiosResponse } from "axios"; +import { + Post, + posts, + PostsApiService, + ResponseBodyPostsApiService, + ServiceWithoutBasePath, +} from "../../fixture/fixtures"; +import { ServiceBuilder } from "../../../src"; +import { JSONPLACEHOLDER_URL, testServer, verifyRequest } from "../../testHelpers"; +import { CONTENT_TYPE, CONTENT_TYPE_HEADER } from "../../../src/constants"; + +describe("Decorators - inlined response", () => { + let service: ResponseBodyPostsApiService; + + beforeEach(() => { + service = new ServiceBuilder() + .saveRequestHistory() + .baseUrl(testServer.url) + .inlineResponseBody() + .withRequestLogger({ showLogs: true, logLevel: "LOG" }) // to test logger + .build(ResponseBodyPostsApiService); + }); + + test("__performRequest GET", async () => { + const request = await service.__performRequest("get"); + expect(request.data).toHaveLength(posts.length); + verifyRequest(request, "get"); + }); + + test("@BasePath", async () => { + await service.get(); + expect(service.__getLastRequest().config.url).toEqual(postsUrl()); + }); + + test("@GET", async () => { + const response = await service.get(); + expect(response).toHaveLength(posts.length); + + verifyRequest(service.__getLastRequest(), "get"); + }); + + test("@GET - without base path", async () => { + const service = new ServiceBuilder().baseUrl(testServer.url).build(ServiceWithoutBasePath); + const response = await service.get(); + + expect(response.data).toHaveLength(posts.length); + + verifyRequest(response, "get", "/posts"); + }); + + test("@GET - ignore base path", async () => { + const response = await service.getIgnoreBasePath(); + expect(response).toHaveLength(posts.length); + + verifyRequest(service.__getLastRequest(), "get", "/posts"); + }); + + test("@GET - Absolute url", async () => { + const service = new ServiceBuilder().baseUrl(JSONPLACEHOLDER_URL).build(PostsApiService); + const response = await service.getAbsoluteUrl(); + expect(response.data).toHaveLength(100); + verifyRequest(response, "get", "/posts"); + }); + + test("@POST", async () => { + const response = await service.post(PostsApiService.dto); + const lastRequest = service.__getLastRequest(); + + verifyRequest(lastRequest, "post", "/posts/", 201); + verifyInlinedBody(response, lastRequest, PostsApiService.dto); + }); + + test("@PUT", async () => { + const response = await service.put(1, PostsApiService.dto); + const lastRequest = service.__getLastRequest(); + + verifyRequest(lastRequest, "put", "/posts/1", 200); + verifyInlinedBody(response, lastRequest, PostsApiService.dto); + }); + + test("@PATCH", async () => { + const response = await service.patch(1, PostsApiService.dto); + const lastRequest = service.__getLastRequest(); + + verifyRequest(lastRequest, "patch", "/posts/1", 200); + verifyInlinedBody(response, lastRequest, PostsApiService.dto); + }); + + test("@DELETE", async () => { + await service.delete(1); + verifyRequest(service.__getLastRequest(), "delete", "/posts/1"); + }); + + test("@HEAD", async () => { + await service.head(1); + verifyRequest(service.__getLastRequest(), "head", "/posts/1"); + }); + + test("@OPTIONS", async () => { + await service.options(1); + verifyRequest(service.__getLastRequest(), "options", "/posts/1", 204); + }); + + test("@Headers", async () => { + await service.headers(PostsApiService.dto); + const lastRequest = service.__getLastRequest(); + expect(lastRequest.config.headers!["Header1"]).toBe("Value1"); + expect(lastRequest.config.headers!["Header2"]).toBe("Value2"); + verifyRequest(lastRequest, "post", "/posts/", 201); + }); + + test("@Header", async () => { + await service.header("Value1"); + const lastRequest = service.__getLastRequest(); + expect(lastRequest.config.headers!["Header"]).toBe("Value1"); + verifyRequest(lastRequest, "get"); + }); + + test("@HeaderMap", async () => { + await service.headerMap({ h1: 1, h2: "v2", h3: true }); + const lastRequest = service.__getLastRequest(); + expect(lastRequest.config.headers!["h1"]).toBe("1"); + expect(lastRequest.config.headers!["h2"]).toBe("v2"); + expect(lastRequest.config.headers!["h3"]).toBe("true"); + verifyRequest(lastRequest, "get"); + }); + + test("@Queries", async () => { + await service.queries(); + const lastRequest = service.__getLastRequest(); + expect(lastRequest.config.params).toMatchObject({ + page: 1, + size: 20, + sort: "createdAt:desc", + }); + }); + + test("@Query", async () => { + await service.query(15); + const lastRequest = service.__getLastRequest(); + expect(lastRequest.config.params.userId).toBe(15); + }); + + test("@ResponseStatus", async () => { + expect(service.__getServiceMetadata().getMetadata("responseStatus").responseStatus).toEqual(200); + }); + + test("@Config", async () => { + await service.config(); + expect(service.__getLastRequest().config.maxRedirects).toEqual(3); + }); + + test("@Field", async () => { + const response = await service.field( + PostsApiService.dto.userId, + PostsApiService.dto.title, + PostsApiService.dto.body, + ); + + const lastRequest = service.__getLastRequest(); + expect(lastRequest.config.headers![CONTENT_TYPE_HEADER]).toBe(CONTENT_TYPE.APPLICATION_JSON); + + verifyRequest(lastRequest, "post", "/posts/", 201); + verifyInlinedBody(response, lastRequest, PostsApiService.dto); + }); + + test("@FieldMap", async () => { + const response = await service.fieldMap(PostsApiService.dto); + const lastRequest = service.__getLastRequest(); + + expect(lastRequest.config.headers![CONTENT_TYPE_HEADER]).toBe(CONTENT_TYPE.APPLICATION_JSON); + + verifyRequest(lastRequest, "post", "/posts/", 201); + verifyInlinedBody(response, lastRequest, PostsApiService.dto); + }); + + test("@QueryMap", async () => { + await service.queryMap({ userId: 15, body: "b", title: "t" }); + const lastRequest = service.__getLastRequest(); + expect(lastRequest.config.params.userId).toBe(15); + expect(lastRequest.config.params.body).toBe("b"); + expect(lastRequest.config.params.title).toBe("t"); + + verifyRequest(lastRequest, "get", "/posts/?userId=15&body=b&title=t"); + }); + + function verifyInlinedBody(response: T, request: AxiosResponse, expectedRequestBody?: T) { + if (!expectedRequestBody) return; + + expect(JSON.parse(request.config.data)).toMatchObject(expectedRequestBody); + expect(response).toMatchObject(expectedRequestBody); + } + + function postsUrl() { + return `${testServer.url}${PostsApiService.BASE_PATH}/`; + } +}); diff --git a/tests/test/decorators/multipart.test.ts b/tests/test/decorators/multipart.test.ts new file mode 100644 index 0000000..7394393 --- /dev/null +++ b/tests/test/decorators/multipart.test.ts @@ -0,0 +1,34 @@ +import { ServiceBuilder } from "../../../src"; +import { testServer } from "../../testHelpers"; +import fs from "fs"; +import { CONTENT_TYPE, CONTENT_TYPE_HEADER } from "../../../src/constants"; +import { FileService, MessagingService } from "../../fixture/fixtures.multipart"; + +describe("Decorators - Multipart", () => { + test("@Multipart", async () => { + const fileService = new ServiceBuilder().baseUrl(testServer.url).build(FileService); + const bucket = { + value: "test-bucket", + }; + const file = { + value: fs.readFileSync("tests/fixture/pic.png"), + filename: "pic.png", + }; + const response = await fileService.upload(bucket, file); + expect(response.config.headers![CONTENT_TYPE_HEADER]).toContain(CONTENT_TYPE.MULTIPART_FORM_DATA); + }); + + test("@Multipart - test2", async () => { + const messagingService = new ServiceBuilder().baseUrl(testServer.url).build(MessagingService); + const from = { value: "+11111111" }; + const to = { value: ["+22222222", "+33333333"] }; + const response = await messagingService.createSMS(from, to); + expect(response.config.headers![CONTENT_TYPE_HEADER]).toContain(CONTENT_TYPE.MULTIPART_FORM_DATA); + }); + + test("@ResponseType", async () => { + const fileService = new ServiceBuilder().baseUrl(testServer.url).build(FileService); + const response = await fileService.getFile("x-y-z"); + expect(response.config.responseType).toEqual("stream"); + }); +}); diff --git a/tests/test/decorators/timeout.test.ts b/tests/test/decorators/timeout.test.ts new file mode 100644 index 0000000..bb8461d --- /dev/null +++ b/tests/test/decorators/timeout.test.ts @@ -0,0 +1,17 @@ +import { ServiceBuilder } from "../../../src"; +import { TimeoutService } from "../../fixture/fixtures.timeout"; +import { testServer } from "../../testHelpers"; + +describe("Decorators - timeout", () => { + test("@Timeout", async () => { + const service = new ServiceBuilder().baseUrl(testServer.url).build(TimeoutService); + await expect(service.timeoutIn3000()).rejects.toThrow(/timeout/); + }); + + test("The timeout in `@Timeout` decorator should shield the value in `setTimeout` method.", async () => { + const service = new ServiceBuilder().baseUrl(testServer.url).setTimeout(3000).build(TimeoutService); + const response = await service.timeoutIn6000(); + expect(response.config.timeout).toEqual(6000); + expect(response.data).toEqual({}); + }); +}); diff --git a/tests/test/decorators/validate.test.ts b/tests/test/decorators/validate.test.ts new file mode 100644 index 0000000..5c52e36 --- /dev/null +++ b/tests/test/decorators/validate.test.ts @@ -0,0 +1,163 @@ +import { ServiceBuilder, ValidationErrors } from "../../../src"; +import { testServer, validateThrows } from "../../testHelpers"; +import { + ValidationFailService, + ValidationFailServiceInlinedBody, + ValidationPassService, + ValidationPassServiceInlinedResponse, +} from "../../fixture/fixtures.validate"; +import { posts } from "../../fixture/fixtures"; + +describe("Validate", () => { + describe("Pass", () => { + describe("Raw response", () => { + let service: ValidationPassService; + + beforeAll(() => { + service = new ServiceBuilder().baseUrl(testServer.url).validateResponse().build(ValidationPassService); + }); + + test("Get all", async () => { + const result = await service.getAll(); + expect(result.data).toHaveLength(2); + expect(result.data[0].id).toBe(1); + expect(result.data[1].id).toBe(2); + }); + + test("Get single", async () => { + const result = await service.single(1); + expect(result.data.id).toBe(1); + }); + }); + + describe("Inlined response", () => { + let service: ValidationPassServiceInlinedResponse; + + beforeAll(() => { + service = new ServiceBuilder() + .baseUrl(testServer.url) + .inlineResponseBody() + .validateResponse() + .build(ValidationPassServiceInlinedResponse); + }); + + test("Get all", async () => { + const result = await service.getAll(); + expect(result).toHaveLength(2); + expect(result[0].id).toBe(1); + expect(result[1].id).toBe(2); + }); + + test("Get single", async () => { + const result = await service.single(1); + expect(result.id).toBe(1); + }); + }); + }); + + describe("Fail", () => { + describe("Raw response", () => { + let service: ValidationFailService; + + beforeAll(() => { + service = new ServiceBuilder().baseUrl(testServer.url).validateResponse().build(ValidationFailService); + }); + + test.each([ + ["Array", "1 field", validateSingleFieldInArray], + ["Array", "2 fields", validateTwoFieldsInArray], + ["Single", "1 field", validateSingleFieldIsInvalid], + ["Single", "2 fields", validateTwoFieldAreInvalid], + ])( + "[%s] - %s", + async ( + msg1: string, + msg2: string, + fn: (s: ValidationFailServiceInlinedBody | ValidationFailService) => void, + ) => { + await fn(service); + }, + ); + + test("Wrong url", async () => { + await validateThrows(service.wrongUrlAndOneField, (error) => { + expect(error.message).toContain("404"); + }); + }); + }); + + describe("Inlined body", () => { + let service: ValidationFailServiceInlinedBody; + + beforeAll(() => { + service = new ServiceBuilder() + .baseUrl(testServer.url) + .inlineResponseBody() + .validateResponse() + .build(ValidationFailServiceInlinedBody); + }); + + test.each([ + ["Array", "1 field", validateSingleFieldInArray], + ["Array", "2 fields", validateTwoFieldsInArray], + ["Single", "1 field", validateSingleFieldIsInvalid], + ["Single", "2 fields", validateTwoFieldAreInvalid], + ])( + "[%s] - %s", + async ( + msg1: string, + msg2: string, + fn: (s: ValidationFailServiceInlinedBody | ValidationFailService) => void, + ) => { + await fn(service); + }, + ); + }); + + async function validateTwoFieldsInArray(service: ValidationFailServiceInlinedBody | ValidationFailService) { + await validateThrows(service.arrayTwoFields, (er) => { + validateErrorsByTwoFields(posts.length, er, posts.length * 2); + }); + } + + function validateErrorsByTwoFields(len: number, er: ValidationErrors, expectedLength = len) { + expect(er.errors).toHaveLength(expectedLength); + + for (let i = 0; i < len - 1; i += 2) { + expect(er.errors[i].property).toBe("body"); + expect(er.errors[i + 1].property).toBe("userId"); + } + } + + async function validateSingleFieldInArray(service: ValidationFailServiceInlinedBody | ValidationFailService) { + await validateThrows(service.array, (er) => { + expect(er.errors).toHaveLength(posts.length); + expect(JSON.parse(er.response)).toMatchObject(posts); + er.errors.forEach((o) => { + expect(o.property).toBe("body"); + }); + }); + } + + async function validateSingleFieldIsInvalid(service: ValidationFailServiceInlinedBody | ValidationFailService) { + await validateThrows( + () => service.singleOneField(1), + (er) => { + expect(er.errors).toHaveLength(1); + er.errors.forEach((o) => { + expect(o.property).toBe("body"); + }); + }, + ); + } + + async function validateTwoFieldAreInvalid(service: ValidationFailServiceInlinedBody | ValidationFailService) { + await validateThrows( + () => service.singleTwoFields(1), + (er) => { + validateErrorsByTwoFields(posts.length, er); + }, + ); + } + }); +}); diff --git a/tests/test/decorators/with-common-header.test.ts b/tests/test/decorators/with-common-header.test.ts new file mode 100644 index 0000000..bfdd54e --- /dev/null +++ b/tests/test/decorators/with-common-header.test.ts @@ -0,0 +1,48 @@ +import { ResponseBodyWithHeaderService, TEST_HEADER, WithHeaderService } from "../../fixture/fixtures"; +import { ServiceBuilder } from "../../../src"; +import { testServer } from "../../testHelpers"; + +describe("Requests with header", () => { + describe("withOauth", () => { + test("Raw response", async () => { + const service = new ServiceBuilder().baseUrl(testServer.url).withOauth("321").build(WithHeaderService); + + const result = await service.withOauth(); + expect(result.data).toBe("Bearer 321"); + }); + + test("Inlined response", async () => { + const service = new ServiceBuilder() + .baseUrl(testServer.url) + .withOauth("321") + .inlineResponseBody() + .build(ResponseBodyWithHeaderService); + + const result = await service.withOauth(); + expect(result).toBe("Bearer 321"); + }); + }); + + describe("withRequestHeader", () => { + test("Raw response", async () => { + const service = new ServiceBuilder() + .baseUrl(testServer.url) + .withRequestHeader(TEST_HEADER, 123) + .build(WithHeaderService); + + const result = await service.withHeaders(); + expect(result.data).toBe(123); + }); + + test("Inlined response", async () => { + const service = new ServiceBuilder() + .baseUrl(testServer.url) + .withRequestHeader(TEST_HEADER, 123) + .inlineResponseBody() + .build(ResponseBodyWithHeaderService); + + const result = await service.withHeaders(); + expect(result).toBe(123); + }); + }); +}); diff --git a/tests/test/decorators/wrong-cases.test.ts b/tests/test/decorators/wrong-cases.test.ts new file mode 100644 index 0000000..a03d3ce --- /dev/null +++ b/tests/test/decorators/wrong-cases.test.ts @@ -0,0 +1,257 @@ +import { ErrorMessages, ServiceBuilder } from "../../../src"; +import { testServer } from "../../testHelpers"; +import { + NoHttpMethodService, + WrongFieldService, + WrongHeaderService, + WrongMultipartService, + WrongQueryService, +} from "../../fixture/fixtures.wrong-cases"; + +describe("Decorators - wrong cases", () => { + describe("Headers", () => { + let service: WrongHeaderService; + + beforeAll(() => { + service = new ServiceBuilder().baseUrl(testServer.url).build(WrongHeaderService); + }); + + describe("@HeaderMap", () => { + test("Empty header key", async () => { + await verifyErrorThrown(async () => { + await service.wrongHeaderMap({ + "": "hello", + }); + }, ErrorMessages.EMPTY_HEADER_KEY); + }); + + test("Wrong child property type", async () => { + await verifyErrorThrown(async () => { + await service.wrongHeaderMap({ + H1: "hello", + H2: { + I1: "asd", + }, + }); + }, ErrorMessages.WRONG_HEADERS_PROPERTY_TYPE); + }); + }); + + describe("@Header", () => { + test("Wrong property type", async () => { + await verifyErrorThrown(async () => { + await service.wrongHeaderType({ + a: "1", + b: 2, + }); + }, ErrorMessages.WRONG_HEADER_TYPE); + }); + + test("Empty header key", async () => { + await verifyErrorThrown(async () => { + await service.emptyHeaderKey(""); + }, ErrorMessages.EMPTY_HEADER_KEY); + }); + }); + }); + + describe("Fields", () => { + let service: WrongFieldService; + + beforeAll(() => { + service = new ServiceBuilder().baseUrl(testServer.url).build(WrongFieldService); + }); + + describe("@FieldMap", () => { + test("Empty field key", async () => { + await verifyErrorThrown(async () => { + await service.wrongFieldMap({ + "": "hello", + }); + }, ErrorMessages.EMPTY_FIELD_KEY); + }); + + test("Wrong FieldMap type", async () => { + await verifyErrorThrown(async () => { + await service.wrongFieldMapType(["1", "hello"]); + }, ErrorMessages.FIELD_MAP_PARAM_TYPE); + }); + + test("FieldMap with @Body as array", async () => { + await verifyErrorThrown(async () => { + await service.fieldMapWithBodyArray({ p1: "name" }, ["1", "hello"]); + }, ErrorMessages.FIELD_MAP_FOR_ARRAY_BODY); + }); + }); + + describe("@Field", () => { + test("Empty field key", async () => { + await verifyErrorThrown(async () => { + await service.emptyFieldKey(""); + }, ErrorMessages.EMPTY_FIELD_KEY); + }); + + test("Field with @Body as array", async () => { + await verifyErrorThrown(async () => { + await service.fieldWithBodyArray(1, [1, 2, 3]); + }, ErrorMessages.FIELD_WITH_ARRAY_BODY); + }); + }); + }); + + describe("Multipart", () => { + let service: WrongMultipartService; + const bucket = { + value: "test-bucket", + }; + + beforeAll(() => { + service = new ServiceBuilder().baseUrl(testServer.url).build(WrongMultipartService); + }); + + test("Empty part key", async () => { + await verifyErrorThrown(async () => { + await service.emptyPartKey(bucket); + }, ErrorMessages.EMPTY_PART_KEY); + }); + + test("Part is not type PartDescriptor", async () => { + await verifyErrorThrown(async () => { + await service.partAsIsNotPartDescriptor("hello"); + }, ErrorMessages.MULTIPART_PARAM_WRONG_TYPE); + }); + + test("Multipart with @Body as array", async () => { + await verifyErrorThrown(async () => { + await service.withBody(bucket, [1, 2, 3]); + }, ErrorMessages.MULTIPART_WITH_ARRAY_BODY); + }); + }); + + describe("Query params", () => { + let service: WrongQueryService; + + beforeAll(() => { + service = new ServiceBuilder().baseUrl(testServer.url).build(WrongQueryService); + }); + + describe("@QueryMap", () => { + test("Empty header key", async () => { + await verifyErrorThrown(async () => { + await service.wrongQueryMap({ + "": "hello", + }); + }, ErrorMessages.EMPTY_QUERY_KEY); + }); + + test("Wrong @QueryMap property type", async () => { + await verifyErrorThrown(async () => { + await service.wrongQueryMap({ + H1: "hello", + H2: { + I1: "asd", + }, + }); + }, ErrorMessages.WRONG_QUERY_MAP_PROPERTY_TYPE); + }); + }); + + describe("@Query", () => { + test("Wrong property type", async () => { + await verifyErrorThrown(async () => { + await service.wrongQuery({ + a: "1", + b: 2, + }); + }, ErrorMessages.WRONG_QUERY_TYPE); + }); + + test("Empty header key", async () => { + await verifyErrorThrown(async () => { + await service.emptyQueryKey(""); + }, ErrorMessages.EMPTY_QUERY_KEY); + }); + }); + }); + + describe("No Http decorator", () => { + let noHttpMethodService: NoHttpMethodService; + + beforeAll(() => { + noHttpMethodService = new ServiceBuilder().baseUrl(testServer.url).build(NoHttpMethodService); + }); + + describe("Works fine with not decorated methods", () => { + test("No params", async () => { + expect(await noHttpMethodService.validMethodNoParams()).toBe(100); + }); + test("1 param", async () => { + expect(await noHttpMethodService.validMethodWithOneParam("abc")).toBe("abc"); + }); + + test("2 params", async () => { + expect(await noHttpMethodService.validMethodWithTwoParams("abc", "cba")).toBe("abccba"); + }); + }); + + test("With @Path", async () => { + await verifyErrorThrown(async () => { + await noHttpMethodService.path(1); + }, ErrorMessages.NO_HTTP_METHOD); + }); + + test("With @Headers", async () => { + await verifyErrorThrown(async () => { + await noHttpMethodService.headers(); + }, ErrorMessages.NO_HTTP_METHOD); + }); + + test("With @Queries", async () => { + await verifyErrorThrown(async () => { + await noHttpMethodService.queries(); + }, ErrorMessages.NO_HTTP_METHOD); + }); + + test("With @FormUrlEncoded", async () => { + await verifyErrorThrown(async () => { + await noHttpMethodService.formUrlEncoded(); + }, ErrorMessages.NO_HTTP_METHOD); + }); + + test("With @Field", async () => { + await verifyErrorThrown(async () => { + await noHttpMethodService.field(12); + }, ErrorMessages.NO_HTTP_METHOD); + }); + + test("With @ResponseStatus", async () => { + await verifyErrorThrown(async () => { + await noHttpMethodService.responseStatus(); + }, ErrorMessages.NO_HTTP_METHOD); + }); + + test("With @Config", async () => { + await verifyErrorThrown(async () => { + await noHttpMethodService.config(); + }, ErrorMessages.NO_HTTP_METHOD); + }); + }); + + test("__getLastRequest - empty", async () => { + const anyService = new ServiceBuilder().baseUrl(testServer.url).build(NoHttpMethodService); + await verifyErrorThrown(async () => { + await anyService.__getLastRequest(); + }, ErrorMessages.__TEST_NO_REQUESTS_IN_HISTORY); + }); + + async function verifyErrorThrown(exec: () => void, err?: string) { + try { + await exec(); + } catch ({ message }) { + expect(message).toBe(err); + return; + } + + fail("No error"); + } +}); diff --git a/tests/test/interceptors/request-interceptors.test.ts b/tests/test/interceptors/request-interceptors.test.ts new file mode 100644 index 0000000..0386602 --- /dev/null +++ b/tests/test/interceptors/request-interceptors.test.ts @@ -0,0 +1,39 @@ +import { RequestInterceptor } from "../../../src"; +import { ServiceBuilder } from "../../../src"; +import { AxiosRequestConfig } from "axios"; +import { testServer } from "../../testHelpers"; +import { PostsApiService } from "../../fixture/fixtures"; + +describe("Request interceptors", () => { + const interceptedHeaderValue = `100`; + + test("RequestInterceptorFunction", async () => { + const interceptor = (config: AxiosRequestConfig) => { + config.headers!["INTERCEPTOR"] = interceptedHeaderValue; + return config; + }; + + await verifyInterceptor((b) => b.setRequestInterceptors(interceptor)); + }); + + test("RequestInterceptor class", async () => { + class Interceptor extends RequestInterceptor { + onFulfilled(config: AxiosRequestConfig) { + config.headers!["INTERCEPTOR"] = interceptedHeaderValue; + return config; + } + } + + await verifyInterceptor((b) => b.setRequestInterceptors(new Interceptor())); + }); + + async function verifyInterceptor(setInterceptor: (builder: ServiceBuilder) => void) { + const builder = new ServiceBuilder().baseUrl(testServer.url).withRequestLogger(); + setInterceptor(builder); + const service = builder.build(PostsApiService); + + const result = await service.get(); + + expect(result.config.headers!["INTERCEPTOR"]).toBe(interceptedHeaderValue); + } +}); diff --git a/tests/test/interceptors/response-interceptors.test.ts b/tests/test/interceptors/response-interceptors.test.ts new file mode 100644 index 0000000..b7053c2 --- /dev/null +++ b/tests/test/interceptors/response-interceptors.test.ts @@ -0,0 +1,92 @@ +import { ResponseInterceptor } from "../../../src"; +import { ServiceBuilder } from "../../../src"; +import { AxiosResponse } from "axios"; +import { testServer, validateThrows } from "../../testHelpers"; +import { PostsApiService } from "../../fixture/fixtures"; +import { DataType } from "../../../src/constants"; + +describe("Response interceptors", () => { + const interceptedHeaderValue = 100; + + test("ResponseInterceptorFunction", async () => { + const interceptor = (value: AxiosResponse) => { + value.data["INTERCEPTOR"] = interceptedHeaderValue; + return value; + }; + + await verifyInterceptor((b) => b.setResponseInterceptors(interceptor)); + }); + + test("ResponseInterceptor class", async () => { + class Interceptor extends ResponseInterceptor { + onFulfilled(value: AxiosResponse): AxiosResponse | Promise> { + value.data["INTERCEPTOR"] = interceptedHeaderValue; + return value; + } + } + + await verifyInterceptor((b) => b.setResponseInterceptors(new Interceptor())); + }); + + describe("onRejected", () => { + test("Override onRejected", async () => { + let calledRejected = false; + + class Interceptor> extends ResponseInterceptor { + onRejected(): void { + calledRejected = true; + } + + onFulfilled(value: AxiosResponse): AxiosResponse | Promise> { + return value; + } + } + + const interceptor = new Interceptor(); + const spy = jest.spyOn(interceptor, "onRejected"); + + const service = new ServiceBuilder() + .baseUrl(testServer.url) + .setResponseInterceptors(interceptor) + .setStandalone(true) + .build(PostsApiService); + + await service.wrongUrl(); + + expect(spy).toHaveBeenCalled(); + expect(calledRejected).toBeTruthy(); + }); + + test("No override", async () => { + class Interceptor> extends ResponseInterceptor { + onFulfilled(value: AxiosResponse): AxiosResponse | Promise> { + return value; + } + } + + const interceptor = new Interceptor(); + + const service = new ServiceBuilder() + .baseUrl(testServer.url) + .setStandalone(true) + .setResponseInterceptors(interceptor) + .build(PostsApiService); + + await validateThrows(service.wrongUrl, (error) => { + expect(error.message).toContain("404"); + }); + }); + }); + + async function verifyInterceptor(setInterceptor: (builder: ServiceBuilder) => void) { + const builder = new ServiceBuilder().baseUrl(testServer.url).setStandalone(true); + + setInterceptor(builder); + + const service = builder.build(PostsApiService); + + const result = await service.get(); + + expect(result.data["INTERCEPTOR"]).toBe(interceptedHeaderValue); + } +}); diff --git a/tests/test/metadata.test.ts b/tests/test/metadata.test.ts new file mode 100644 index 0000000..74d7030 --- /dev/null +++ b/tests/test/metadata.test.ts @@ -0,0 +1,24 @@ +import { ServiceBuilder } from "../../src"; +import { testServer } from "../testHelpers"; +import { PostsApiService } from "../fixture/fixtures"; + +describe("Metadata", () => { + let service: PostsApiService; + + beforeAll(() => { + service = new ServiceBuilder().baseUrl(testServer.url).build(PostsApiService); + }); + + test("Method not found", () => { + const methodName = "sadksadlasd"; + const t = () => { + service.__getServiceMetadata().getMetadata(methodName); + }; + expect(t).toThrowError(`Method ${methodName} does not exist`); + }); + + test("Method found", () => { + const metadata = service.__getServiceMetadata().getMetadata("getAbsoluteUrl"); + expect(metadata.httpMethod).toBe("GET"); + }); +}); diff --git a/tests/test/standalone.test.ts b/tests/test/standalone.test.ts new file mode 100644 index 0000000..299cda6 --- /dev/null +++ b/tests/test/standalone.test.ts @@ -0,0 +1,42 @@ +import { ServiceBuilder } from "../../src"; +import { testServer } from "../testHelpers"; +import { PostsApiService } from "../fixture/fixtures"; +import axios, { AxiosRequestConfig } from "axios"; + +describe("Standalone", () => { + test("With instance", async () => { + const serviceWithoutStandalone = new ServiceBuilder().baseUrl(testServer.url).build(PostsApiService); + const axiosInstance = axios.create(); + + axiosInstance.interceptors.response.use((value) => { + value.config["standaloneId"] = 101; + return value; + }); + + const serviceWithStandalone = new ServiceBuilder() + .baseUrl(testServer.url) + .setStandalone(axiosInstance) + .build(PostsApiService); + + expect((await serviceWithoutStandalone.get()).config["standaloneId"]).toBeUndefined(); + expect((await serviceWithStandalone.get()).config["standaloneId"]).toBe(101); + }); + + test("With boolean", async () => { + const serviceWithoutStandalone = new ServiceBuilder().baseUrl(testServer.url).build(PostsApiService); + + const interceptor = (config: AxiosRequestConfig) => { + config["standaloneId"] = 101; + return config; + }; + + const serviceWithStandalone = new ServiceBuilder() + .baseUrl(testServer.url) + .setStandalone(true) + .setRequestInterceptors(interceptor) + .build(PostsApiService); + + expect((await serviceWithoutStandalone.get()).config["standaloneId"]).toBeUndefined(); + expect((await serviceWithStandalone.get()).config["standaloneId"]).toBe(101); + }); +}); diff --git a/tests/test/transformers/request.transformer.test.ts b/tests/test/transformers/request.transformer.test.ts new file mode 100644 index 0000000..dd9689a --- /dev/null +++ b/tests/test/transformers/request.transformer.test.ts @@ -0,0 +1,45 @@ +import { ServiceBuilder } from "../../../src"; +import { testServer, verifyBody, verifyRequest } from "../../testHelpers"; +import { Post, PostCreateDTO, PostsApiService } from "../../fixture/fixtures"; +import { AxiosResponse } from "axios"; +import { RequestTransformerApiService } from "../../fixture/fixtures.transformer"; + +describe("Request transformer", () => { + let service: RequestTransformerApiService; + + beforeAll(() => { + service = new ServiceBuilder().baseUrl(testServer.url).withRequestLogger().build(RequestTransformerApiService); + }); + + test("Single", async () => { + const response = await service.requestTransformer(PostsApiService.dto); + + verify(response, { + ...PostsApiService.dto, + title: "updated title1", + }); + }); + + test("2 transformers (passed as arguments)", async () => { + const response = await service.twoTransformersAsArgument(PostsApiService.dto); + + verify(response, { + ...PostsApiService.dto, + title: "updated title2", + }); + }); + + test("2 transformers (different decorators)", async () => { + const response = await service.twoTransformersAsDifferentDecorators(PostsApiService.dto); + + verify(response, { + ...PostsApiService.dto, + title: "updated title2", + }); + }); + + function verify(response: AxiosResponse, expected: PostCreateDTO) { + verifyRequest(response, "post", "/posts/", 201); + verifyBody(response, expected, expected); + } +}); diff --git a/tests/test/transformers/response.transformer.test.ts b/tests/test/transformers/response.transformer.test.ts new file mode 100644 index 0000000..c2a3e59 --- /dev/null +++ b/tests/test/transformers/response.transformer.test.ts @@ -0,0 +1,57 @@ +import { ServiceBuilder } from "../../../src"; +import { testServer, verifyBody, verifyRequest } from "../../testHelpers"; +import { Post, PostCreateDTO, posts, PostsApiService } from "../../fixture/fixtures"; +import { ResponseTransformerApiService } from "../../fixture/fixtures.transformer"; +import { AxiosResponse } from "axios"; + +describe("Response transformer", () => { + let service: ResponseTransformerApiService; + + beforeAll(() => { + service = new ServiceBuilder().baseUrl(testServer.url).build(ResponseTransformerApiService); + }); + + test("1 transformer - array", async () => { + const { data } = await service.array(); + + expect(data).toHaveLength(posts.length); + + expect(data[0]).toMatchObject({ + ...posts[0], + title: "transformer", + }); + expect(data[1]).toMatchObject(posts[1]); + }); + + test("1 transformer", async () => { + const response = await service.single(PostsApiService.dto); + + verify(response, { + ...PostsApiService.dto, + title: "updated title2", + }); + }); + + test("2 transformers (passed as arguments)", async () => { + const response = await service.twoTransformersAsArgument(PostsApiService.dto); + + verify(response, { + ...PostsApiService.dto, + title: "updated title2", + }); + }); + + test("2 transformers (different decorators)", async () => { + const response = await service.twoTransformersAsDifferentDecorators(PostsApiService.dto); + + verify(response, { + ...PostsApiService.dto, + title: "updated title2", + }); + }); + + function verify(response: AxiosResponse, expected: PostCreateDTO) { + verifyRequest(response, "post", "/posts/", 201); + verifyBody(response, PostsApiService.dto, expected); + } +}); diff --git a/tests/testHelpers.ts b/tests/testHelpers.ts new file mode 100644 index 0000000..31a0200 --- /dev/null +++ b/tests/testHelpers.ts @@ -0,0 +1,51 @@ +import { AxiosResponse, Method } from "axios"; +import { AddressInfo } from "net"; +import { ApiResponse, ApiResponseBody } from "../src"; + +export const JSONPLACEHOLDER_URL = "https://jsonplaceholder.typicode.com"; +export const testServerUrl = (address: AddressInfo | string | null) => + `http://localhost:${(address as AddressInfo).port}`; + +export function verifyRequest(response: AxiosResponse, method: Method, path = "/posts/", status = 200) { + expect(response.request.method).toBe(method.toUpperCase()); + expect(response.request.path).toBe(path); + + expect(response.status).toEqual(status); + expect(response.config.method).toEqual(method.toLowerCase()); +} + +export function verifyBody( + response: AxiosResponse, + expectedRequestBody: T, + expectedResponseBody = expectedRequestBody, +) { + if (!expectedRequestBody) return; + + expect(response.config.data).toBe(JSON.stringify(expectedRequestBody)); + expect(response.data).toMatchObject(expectedResponseBody); +} + +export async function validateThrows( + fn: () => ApiResponse | ApiResponseBody, + catchChecks: (error: T) => void = () => { + // do nothing + }, +) { + try { + await fn(); + fail("Expected exception"); + } catch (e) { + catchChecks(e as T); + } +} + +// @TODO +describe.skip("TMP", () => { + test.skip("t", () => { + const a = 10; + }); +}); + +export const testServer = { + url: "", +}; diff --git a/tests/testSetupFile.ts b/tests/testSetupFile.ts new file mode 100644 index 0000000..9f4e60a --- /dev/null +++ b/tests/testSetupFile.ts @@ -0,0 +1,17 @@ +import "reflect-metadata"; +import http from "http"; +import { app } from "./fixture/server"; +import { testServer, testServerUrl } from "./testHelpers"; + +jest.setTimeout(60000); + +let server: http.Server; + +beforeAll(() => { + server = app.listen(0); + testServer.url = testServerUrl(server.address()); +}); + +afterAll(() => { + server.close(); +}); diff --git a/tsconfig.json b/tsconfig.json index 2b858c8..f0a9fc3 100644 --- a/tsconfig.json +++ b/tsconfig.json @@ -4,7 +4,12 @@ "esModuleInterop": true, "target": "es6", "module": "commonjs", - "lib": ["es2015", "es2016", "es2017", "dom"], + "lib": [ + "es2015", + "es2016", + "es2017", + "dom" + ], "suppressImplicitAnyIndexErrors": true, "noEmitOnError": true, "noImplicitReturns": true, @@ -15,8 +20,7 @@ "allowSyntheticDefaultImports": true, "experimentalDecorators": true, "emitDecoratorMetadata": true, - "outDir": "lib", - "declarationDir": "lib/types" + "outDir": "dist", }, "include": [ "src/**/*" @@ -25,4 +29,4 @@ "node_modules", "**/*.test.ts" ] -} +} \ No newline at end of file diff --git a/tslint.json b/tslint.json deleted file mode 100644 index ee1d3e6..0000000 --- a/tslint.json +++ /dev/null @@ -1,21 +0,0 @@ -{ - "defaultSeverity": "error", - "extends": [ - "tslint:recommended" - ], - "jsRules": {}, - "rules": { - "variable-name": [ - "ban-keywords", - "check-format", - "allow-leading-underscore", - "allow-pascal-case" - ], - "object-literal-sort-keys": false, - "max-classes-per-file": [true, 99], - "ban-types": [], - "ordered-imports": false, - "interface-name" : [true, "never-prefix"] - }, - "rulesDirectory": [] -}