From 67b3e5e94120e3f0e4913d87f6316802e9f48f44 Mon Sep 17 00:00:00 2001 From: Luiz Filho Date: Wed, 18 Sep 2019 21:34:33 -0300 Subject: [PATCH 01/65] added .gitignore --- .gitignore | 1 + README.md | 56 ------------------------------------------------------ 2 files changed, 1 insertion(+), 56 deletions(-) create mode 100644 .gitignore diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..b512c09 --- /dev/null +++ b/.gitignore @@ -0,0 +1 @@ +node_modules \ No newline at end of file diff --git a/README.md b/README.md index 5e836c1..e69de29 100644 --- a/README.md +++ b/README.md @@ -1,56 +0,0 @@ -Desafio Back-end - Grupo Fleury -==== - -## Descrição: - -O Grupo Fleury deseja disponibilizar uma api restfull para realização de agendamentos para seus clientes, -para tal o usuário precisará ter um cadastro de cliente em nossa base de dados, -selecionar um exame e informar data e hora desejado. - -## Regras de Negócio - -- Cliente precisa estar cadastrado em base de dados para realizar o agendamento -- Caso o cliente não exista em base, deverá ser feito o cadastro antecipadamente. -- Não será possível realizar agendamento de mais de 2 pacientes para o mesmo exame na mesma data e hora, esse valor de 2 deverá ser parametrizado. -- O cadastro de cliente deverá ter os campos: Nome, CPF e Data de Nascimento -- Não poderá ser cadastrado mais de um cliente para o mesmo CPF -- A lista de exames disponíveis para agendamento deverá ser consumida do endpoint ( http://www.mocky.io/v2/5d681ede33000054e7e65c3f). - -## Features -- Deverá haver um endpoint para listagem dos exames disponíveis para agendamento, exibindo apenas nome do exame e id -- Deverá haver um endpoint para criação de um cliente -- Deverá haver um endpoint para atualização de um cliente -- Deverá haver um endpoint para exclusão de um cliente -- Deverá haver um endpoint para busca de um cliente baseado no seu cpf -- Deverá haver um endpoint para listagem de todos os clientes cadastrados - -- Deverá haver um endpoint para listagem dos agendamentos de um cliente por cpf, deverá conter o valor total (soma dos valores dos exames selecionados para o agendamento) -- Deverá haver um endpoint para edição de um agendamento realizado, apenas dia e hora poderão ser editados -- Deverá haver um endpoint para exclusão de um agendamento realizado - -## Requisitos - -- A API deverá ter um swagger -- Teste unitário -- Utilizar uma estrutura de dados a sua escolha para simular a base de dados em memória -- Para vaga de Back-end NodeJS utilizar Typecript, para Vaga de .net utilizar .net core 2.x -- Aplicação deverá conter um Readme contendo instruções de como realizar o build e rodar a Aplicação - - -## Diferencial -- No readme separe uma sessão para explicar a arquitetura da api -- Tenha em mente conceitos de SOLID e clean architecture -- Docker -- Esteira de CI/CD no github (exemplo Travis CI) - -## Como submeter? - -Deverá ser enviado um PULL REQUEST com o seu teste. - -### Como funciona? - -- Fork deste repositório -- Clonar a partir do repositório que foi criada na sua conta -- Procure fazer o máximo de commits com todas as suas decisões -- Abra um Pull Request para este repositório - From 613f5fd54151f833a4a41328ce12a2b4c640df30 Mon Sep 17 00:00:00 2001 From: Luiz Filho Date: Wed, 18 Sep 2019 21:49:02 -0300 Subject: [PATCH 02/65] added package.json --- package.json | 19 +++++++++++++++++++ 1 file changed, 19 insertions(+) create mode 100644 package.json diff --git a/package.json b/package.json new file mode 100644 index 0000000..2d125e9 --- /dev/null +++ b/package.json @@ -0,0 +1,19 @@ +{ + "name": "desafio-backend", + "version": "1.0.0", + "description": "Desafio Backend em NodeJS", + "main": "server.js", + "scripts": { + + }, + "repository": { + "type": "git", + "url": "git+https://github.com/LUIZFH/desafio-backend.git" + }, + "author": "Luiz Filho", + "license": "ISC", + "bugs": { + "url": "https://github.com/LUIZFH/desafio-backend/issues" + }, + "homepage": "https://github.com/LUIZFH/desafio-backend#readme" +} From dcd6843fced24be66a6c1544ad094f2a93f023a1 Mon Sep 17 00:00:00 2001 From: Luiz Filho Date: Wed, 18 Sep 2019 22:01:33 -0300 Subject: [PATCH 03/65] initial ts configuration --- .gitignore | 3 ++- package-lock.json | 14 +++++++++++ package.json | 7 ++++-- tsconfig.json | 63 +++++++++++++++++++++++++++++++++++++++++++++++ 4 files changed, 84 insertions(+), 3 deletions(-) create mode 100644 package-lock.json create mode 100644 tsconfig.json diff --git a/.gitignore b/.gitignore index b512c09..b7dab5e 100644 --- a/.gitignore +++ b/.gitignore @@ -1 +1,2 @@ -node_modules \ No newline at end of file +node_modules +build \ No newline at end of file diff --git a/package-lock.json b/package-lock.json new file mode 100644 index 0000000..fb837c7 --- /dev/null +++ b/package-lock.json @@ -0,0 +1,14 @@ +{ + "name": "desafio-backend", + "version": "1.0.0", + "lockfileVersion": 1, + "requires": true, + "dependencies": { + "typescript": { + "version": "3.6.3", + "resolved": "https://registry.npmjs.org/typescript/-/typescript-3.6.3.tgz", + "integrity": "sha512-N7bceJL1CtRQ2RiG0AQME13ksR7DiuQh/QehubYcghzv20tnh+MQnQIuJddTmsbqYj+dztchykemz0zFzlvdQw==", + "dev": true + } + } +} diff --git a/package.json b/package.json index 2d125e9..917772e 100644 --- a/package.json +++ b/package.json @@ -4,7 +4,7 @@ "description": "Desafio Backend em NodeJS", "main": "server.js", "scripts": { - + "tsc":"tsc" }, "repository": { "type": "git", @@ -15,5 +15,8 @@ "bugs": { "url": "https://github.com/LUIZFH/desafio-backend/issues" }, - "homepage": "https://github.com/LUIZFH/desafio-backend#readme" + "homepage": "https://github.com/LUIZFH/desafio-backend#readme", + "devDependencies": { + "typescript": "^3.6.3" + } } diff --git a/tsconfig.json b/tsconfig.json new file mode 100644 index 0000000..dd93202 --- /dev/null +++ b/tsconfig.json @@ -0,0 +1,63 @@ +{ + "compilerOptions": { + /* Basic Options */ + // "incremental": true, /* Enable incremental compilation */ + "target": "es5", /* Specify ECMAScript target version: 'ES3' (default), 'ES5', 'ES2015', 'ES2016', 'ES2017', 'ES2018', 'ES2019' or 'ESNEXT'. */ + "module": "commonjs", /* Specify module code generation: 'none', 'commonjs', 'amd', 'system', 'umd', 'es2015', or 'ESNext'. */ + // "lib": [], /* Specify library files to be included in the compilation. */ + // "allowJs": true, /* Allow javascript files to be compiled. */ + // "checkJs": true, /* Report errors in .js files. */ + // "jsx": "preserve", /* Specify JSX code generation: 'preserve', 'react-native', or 'react'. */ + // "declaration": true, /* Generates corresponding '.d.ts' file. */ + // "declarationMap": true, /* Generates a sourcemap for each corresponding '.d.ts' file. */ + // "sourceMap": true, /* Generates corresponding '.map' file. */ + // "outFile": "./", /* Concatenate and emit output to single file. */ + "outDir": "./build", /* Redirect output structure to the directory. */ + // "rootDir": "./", /* Specify the root directory of input files. Use to control the output directory structure with --outDir. */ + // "composite": true, /* Enable project compilation */ + // "tsBuildInfoFile": "./", /* Specify file to store incremental compilation information */ + // "removeComments": true, /* Do not emit comments to output. */ + // "noEmit": true, /* Do not emit outputs. */ + // "importHelpers": true, /* Import emit helpers from 'tslib'. */ + // "downlevelIteration": true, /* Provide full support for iterables in 'for-of', spread, and destructuring when targeting 'ES5' or 'ES3'. */ + // "isolatedModules": true, /* Transpile each file as a separate module (similar to 'ts.transpileModule'). */ + + /* Strict Type-Checking Options */ + "strict": true, /* Enable all strict type-checking options. */ + // "noImplicitAny": true, /* Raise error on expressions and declarations with an implied 'any' type. */ + // "strictNullChecks": true, /* Enable strict null checks. */ + // "strictFunctionTypes": true, /* Enable strict checking of function types. */ + // "strictBindCallApply": true, /* Enable strict 'bind', 'call', and 'apply' methods on functions. */ + // "strictPropertyInitialization": true, /* Enable strict checking of property initialization in classes. */ + // "noImplicitThis": true, /* Raise error on 'this' expressions with an implied 'any' type. */ + // "alwaysStrict": true, /* Parse in strict mode and emit "use strict" for each source file. */ + + /* Additional Checks */ + // "noUnusedLocals": true, /* Report errors on unused locals. */ + // "noUnusedParameters": true, /* Report errors on unused parameters. */ + // "noImplicitReturns": true, /* Report error when not all code paths in function return a value. */ + // "noFallthroughCasesInSwitch": true, /* Report errors for fallthrough cases in switch statement. */ + + /* Module Resolution Options */ + // "moduleResolution": "node", /* Specify module resolution strategy: 'node' (Node.js) or 'classic' (TypeScript pre-1.6). */ + // "baseUrl": "./", /* Base directory to resolve non-absolute module names. */ + // "paths": {}, /* A series of entries which re-map imports to lookup locations relative to the 'baseUrl'. */ + // "rootDirs": [], /* List of root folders whose combined content represents the structure of the project at runtime. */ + // "typeRoots": [], /* List of folders to include type definitions from. */ + // "types": [], /* Type declaration files to be included in compilation. */ + // "allowSyntheticDefaultImports": true, /* Allow default imports from modules with no default export. This does not affect code emit, just typechecking. */ + "esModuleInterop": true /* Enables emit interoperability between CommonJS and ES Modules via creation of namespace objects for all imports. Implies 'allowSyntheticDefaultImports'. */ + // "preserveSymlinks": true, /* Do not resolve the real path of symlinks. */ + // "allowUmdGlobalAccess": true, /* Allow accessing UMD globals from modules. */ + + /* Source Map Options */ + // "sourceRoot": "", /* Specify the location where debugger should locate TypeScript files instead of source locations. */ + // "mapRoot": "", /* Specify the location where debugger should locate map files instead of generated locations. */ + // "inlineSourceMap": true, /* Emit a single file with source maps instead of having a separate file. */ + // "inlineSources": true, /* Emit the source alongside the sourcemaps within a single file; requires '--inlineSourceMap' or '--sourceMap' to be set. */ + + /* Experimental Options */ + // "experimentalDecorators": true, /* Enables experimental support for ES7 decorators. */ + // "emitDecoratorMetadata": true, /* Enables experimental support for emitting type metadata for decorators. */ + } +} From a3494f6bb189839757e7733e6b2c585a4c9f22b8 Mon Sep 17 00:00:00 2001 From: Luiz Filho Date: Wed, 18 Sep 2019 22:18:00 -0300 Subject: [PATCH 04/65] first route to test initial config --- package-lock.json | 68 +++++++++++++++++++++++++++++++++++++++++++++++ package.json | 3 ++- src/server.ts | 11 ++++++++ 3 files changed, 81 insertions(+), 1 deletion(-) create mode 100644 src/server.ts diff --git a/package-lock.json b/package-lock.json index fb837c7..4f3d45c 100644 --- a/package-lock.json +++ b/package-lock.json @@ -4,6 +4,74 @@ "lockfileVersion": 1, "requires": true, "dependencies": { + "@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/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/node": { + "version": "12.7.5", + "resolved": "https://registry.npmjs.org/@types/node/-/node-12.7.5.tgz", + "integrity": "sha512-9fq4jZVhPNW8r+UYKnxF1e2HkDWOWKM5bC2/7c9wPV835I0aOrVbS/Hw/pWPk2uKrNXQqg9Z959Kz+IYDd5p3w==", + "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": "*" + } + }, "typescript": { "version": "3.6.3", "resolved": "https://registry.npmjs.org/typescript/-/typescript-3.6.3.tgz", diff --git a/package.json b/package.json index 917772e..eb30a81 100644 --- a/package.json +++ b/package.json @@ -4,7 +4,7 @@ "description": "Desafio Backend em NodeJS", "main": "server.js", "scripts": { - "tsc":"tsc" + "tsc": "tsc" }, "repository": { "type": "git", @@ -17,6 +17,7 @@ }, "homepage": "https://github.com/LUIZFH/desafio-backend#readme", "devDependencies": { + "@types/express": "^4.17.1", "typescript": "^3.6.3" } } diff --git a/src/server.ts b/src/server.ts new file mode 100644 index 0000000..e4ec078 --- /dev/null +++ b/src/server.ts @@ -0,0 +1,11 @@ +import express from 'express' + +const server: express.Application = express() + +server.get('/', (request, response) => { + response.send({ message: 'Welcome to my challenge'}) +}) + +server.listen(4446, () => { + console.log(`Server is running! Welcome!`) +}) \ No newline at end of file From ed59baeb4ed538089a9b98ed5e248132795c70b0 Mon Sep 17 00:00:00 2001 From: Luiz Filho Date: Wed, 18 Sep 2019 22:56:14 -0300 Subject: [PATCH 05/65] nodemon setup --- package-lock.json | 3528 +++++++++++++++++++++++++++++++++++++++++++++ package.json | 8 +- 2 files changed, 3535 insertions(+), 1 deletion(-) diff --git a/package-lock.json b/package-lock.json index 4f3d45c..fbc8887 100644 --- a/package-lock.json +++ b/package-lock.json @@ -72,11 +72,3539 @@ "@types/mime": "*" } }, + "@types/strip-bom": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/@types/strip-bom/-/strip-bom-3.0.0.tgz", + "integrity": "sha1-FKjsOVbC6B7bdSB5CuzyHCkK69I=", + "dev": true + }, + "@types/strip-json-comments": { + "version": "0.0.30", + "resolved": "https://registry.npmjs.org/@types/strip-json-comments/-/strip-json-comments-0.0.30.tgz", + "integrity": "sha512-7NQmHra/JILCd1QqpSzl8+mJRc8ZHz3uDm8YV1Ks9IhK0epEiTw8aIErbvH9PI+6XbqhyIQy3462nEsn7UVzjQ==", + "dev": true + }, + "abbrev": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/abbrev/-/abbrev-1.1.1.tgz", + "integrity": "sha512-nne9/IiQ/hzIhY6pdDnbBtz7DjPTKrY00P/zvPSm5pOFkl6xuGrGnXn/VtTNNfNtAfZ9/1RtehkszU9qcTii0Q==", + "dev": true + }, + "accepts": { + "version": "1.3.7", + "resolved": "https://registry.npmjs.org/accepts/-/accepts-1.3.7.tgz", + "integrity": "sha512-Il80Qs2WjYlJIBNzNkK6KYqlVMTbZLXgHx2oT0pU/fjRHyEp+PEfEPY0R3WCwAGVOtauxh1hOxNgIf5bv7dQpA==", + "requires": { + "mime-types": "~2.1.24", + "negotiator": "0.6.2" + } + }, + "ansi-align": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/ansi-align/-/ansi-align-2.0.0.tgz", + "integrity": "sha1-w2rsy6VjuJzrVW82kPCx2eNUf38=", + "dev": true, + "requires": { + "string-width": "^2.0.0" + } + }, + "ansi-regex": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-3.0.0.tgz", + "integrity": "sha1-7QMXwyIGT3lGbAKWa922Bas32Zg=", + "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" + }, + "dependencies": { + "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" + } + } + } + }, + "arg": { + "version": "4.1.1", + "resolved": "https://registry.npmjs.org/arg/-/arg-4.1.1.tgz", + "integrity": "sha512-SlmP3fEA88MBv0PypnXZ8ZfJhwmDeIE3SP71j37AiXQBXYosPV0x6uISAaHYSlSVhmHOVkomen0tbGk6Anlebw==", + "dev": true + }, + "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-find-index": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/array-find-index/-/array-find-index-1.0.2.tgz", + "integrity": "sha1-3wEKoSh+Fku9pvlyOwqWoexBh6E=", + "dev": true + }, + "array-flatten": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/array-flatten/-/array-flatten-1.1.1.tgz", + "integrity": "sha1-ml9pkFGx5wczKPKgCJaLZOopVdI=" + }, + "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 + }, + "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 + }, + "async-each": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/async-each/-/async-each-1.0.3.tgz", + "integrity": "sha512-z/WhQ5FPySLdvREByI2vZiTWwCnF0moMJ1hK9YQwDTHKh6I7/uSckMetoRGb5UBZPC1z0jlw+n/XCgjeH7y1AQ==", + "dev": true + }, + "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 + }, + "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" + } + } + } + }, + "binary-extensions": { + "version": "1.13.1", + "resolved": "https://registry.npmjs.org/binary-extensions/-/binary-extensions-1.13.1.tgz", + "integrity": "sha512-Un7MIEDdUC5gNpcGDV97op1Ywk748MpHcFTHoYs6qnj1Z3j7I53VG3nwZhKzoBZmbdRNnb6WRdFlwl7tSDuZGw==", + "dev": true + }, + "body-parser": { + "version": "1.19.0", + "resolved": "https://registry.npmjs.org/body-parser/-/body-parser-1.19.0.tgz", + "integrity": "sha512-dhEPs72UPbDnAQJ9ZKMNTP6ptJaionhP5cBb541nXPlW60Jepo9RV/a4fX4XWW9CuFNK22krhrj1+rgzifNCsw==", + "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==", + "requires": { + "ms": "2.0.0" + } + } + } + }, + "boxen": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/boxen/-/boxen-1.3.0.tgz", + "integrity": "sha512-TNPjfTr432qx7yOjQyaXm3dSR0MH9vXp7eT1BFSl/C51g+EFnOR9hTg1IreahGBmDNCehscshe45f+C1TBZbLw==", + "dev": true, + "requires": { + "ansi-align": "^2.0.0", + "camelcase": "^4.0.0", + "chalk": "^2.0.1", + "cli-boxes": "^1.0.0", + "string-width": "^2.0.0", + "term-size": "^1.2.0", + "widest-line": "^2.0.0" + } + }, + "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" + } + } + } + }, + "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 + }, + "bytes": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/bytes/-/bytes-3.1.0.tgz", + "integrity": "sha512-zauLjrfCG+xvoyaqLoV8bLVXXNGC4JqlxFCutSDWA6fJrTo2ZuvLYTqZ7aHBLZSMOopbzwv8f+wZcVzfVTI2Dg==" + }, + "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" + } + }, + "camelcase": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/camelcase/-/camelcase-4.1.0.tgz", + "integrity": "sha1-1UVjW+HjPFQmScaRc+Xeas+uNN0=", + "dev": true + }, + "camelcase-keys": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/camelcase-keys/-/camelcase-keys-2.1.0.tgz", + "integrity": "sha1-MIvur/3ygRkFHvodkyITyRuPkuc=", + "dev": true, + "requires": { + "camelcase": "^2.0.0", + "map-obj": "^1.0.0" + }, + "dependencies": { + "camelcase": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/camelcase/-/camelcase-2.1.1.tgz", + "integrity": "sha1-fB0W1nmhu+WcoCys7PsBHiAfWh8=", + "dev": true + } + } + }, + "capture-stack-trace": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/capture-stack-trace/-/capture-stack-trace-1.0.1.tgz", + "integrity": "sha512-mYQLZnx5Qt1JgB1WEiMCf2647plpGeQ2NMR/5L0HNZzGQo4fuSPnK+wjfPnKZV0aiJDgzmWqqkV/g7JD+DW0qw==", + "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" + } + }, + "chokidar": { + "version": "2.1.8", + "resolved": "https://registry.npmjs.org/chokidar/-/chokidar-2.1.8.tgz", + "integrity": "sha512-ZmZUazfOzf0Nve7duiCKD23PFSCs4JPoYyccjUFF3aQkQadqBhfzhjkwBH2mNOG9cTBwhamM37EIsIkZw3nRgg==", + "dev": true, + "requires": { + "anymatch": "^2.0.0", + "async-each": "^1.0.1", + "braces": "^2.3.2", + "fsevents": "^1.2.7", + "glob-parent": "^3.1.0", + "inherits": "^2.0.3", + "is-binary-path": "^1.0.0", + "is-glob": "^4.0.0", + "normalize-path": "^3.0.0", + "path-is-absolute": "^1.0.0", + "readdirp": "^2.2.1", + "upath": "^1.1.1" + } + }, + "ci-info": { + "version": "1.6.0", + "resolved": "https://registry.npmjs.org/ci-info/-/ci-info-1.6.0.tgz", + "integrity": "sha512-vsGdkwSCDpWmP80ncATX7iea5DWQemg1UgCW5J8tqjU3lYw4FBYuj89J0CTVomA7BEfvSZd84GmHko+MxFQU2A==", + "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" + } + } + } + }, + "cli-boxes": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/cli-boxes/-/cli-boxes-1.0.0.tgz", + "integrity": "sha1-T6kXw+WclKAEzWH47lCdplFocUM=", + "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 + }, + "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 + }, + "configstore": { + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/configstore/-/configstore-3.1.2.tgz", + "integrity": "sha512-vtv5HtGjcYUgFrXc6Kx747B83MRRVS5R1VTEQoXvuP+kMI+if6uywV0nDGoiydJRy4yk7h9od5Og0kxx4zUXmw==", + "dev": true, + "requires": { + "dot-prop": "^4.1.0", + "graceful-fs": "^4.1.2", + "make-dir": "^1.0.0", + "unique-string": "^1.0.0", + "write-file-atomic": "^2.0.0", + "xdg-basedir": "^3.0.0" + } + }, + "content-disposition": { + "version": "0.5.3", + "resolved": "https://registry.npmjs.org/content-disposition/-/content-disposition-0.5.3.tgz", + "integrity": "sha512-ExO0774ikEObIAEV9kDo50o+79VCUdEB6n6lzKgGwupcVeRlhrj3qGAfwq8G6uBJjkqLrhT0qEYFcWng8z1z0g==", + "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==" + }, + "cookie": { + "version": "0.4.0", + "resolved": "https://registry.npmjs.org/cookie/-/cookie-0.4.0.tgz", + "integrity": "sha512-+Hp8fLp57wnUSt0tY0tHEXh4voZRDnoIrZPqlo3DPiI4y9lwg/jqx+1Om94/W6ZaPDOUbnjOt/99w66zk+l1Xg==" + }, + "cookie-signature": { + "version": "1.0.6", + "resolved": "https://registry.npmjs.org/cookie-signature/-/cookie-signature-1.0.6.tgz", + "integrity": "sha1-4wOogrNCzD7oylE6eZmXNNqzriw=" + }, + "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 + }, + "create-error-class": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/create-error-class/-/create-error-class-3.0.2.tgz", + "integrity": "sha1-Br56vvlHo/FKMP1hBnHUAbyot7Y=", + "dev": true, + "requires": { + "capture-stack-trace": "^1.0.0" + } + }, + "cross-spawn": { + "version": "5.1.0", + "resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-5.1.0.tgz", + "integrity": "sha1-6L0O/uWPz/b4+UUQoKVUu/ojVEk=", + "dev": true, + "requires": { + "lru-cache": "^4.0.1", + "shebang-command": "^1.2.0", + "which": "^1.2.9" + } + }, + "crypto-random-string": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/crypto-random-string/-/crypto-random-string-1.0.0.tgz", + "integrity": "sha1-ojD2T1aDEOFJgAmUB5DsmVRbyn4=", + "dev": true + }, + "currently-unhandled": { + "version": "0.4.1", + "resolved": "https://registry.npmjs.org/currently-unhandled/-/currently-unhandled-0.4.1.tgz", + "integrity": "sha1-mI3zP+qxke95mmE2nddsF635V+o=", + "dev": true, + "requires": { + "array-find-index": "^1.0.1" + } + }, + "dateformat": { + "version": "1.0.12", + "resolved": "https://registry.npmjs.org/dateformat/-/dateformat-1.0.12.tgz", + "integrity": "sha1-nxJLZ1lMk3/3BpMuSmQsyo27/uk=", + "dev": true, + "requires": { + "get-stdin": "^4.0.1", + "meow": "^3.3.0" + } + }, + "debounce": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/debounce/-/debounce-1.2.0.tgz", + "integrity": "sha512-mYtLl1xfZLi1m4RtQYlZgJUNQjl4ZxVnHzIR8nLLgi4q1YT8o/WM+MK/f8yfcc9s5Ir5zRaPZyZU6xs1Syoocg==", + "dev": true + }, + "debug": { + "version": "3.2.6", + "resolved": "https://registry.npmjs.org/debug/-/debug-3.2.6.tgz", + "integrity": "sha512-mel+jf7nrtEl5Pn1Qx46zARXKDpBbvzezse7p7LqINmdoIk8PYP5SySaxEmYv6TZ0JyEKA1hsCId6DIhgITtWQ==", + "dev": true, + "requires": { + "ms": "^2.1.1" + }, + "dependencies": { + "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 + } + } + }, + "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-extend": { + "version": "0.6.0", + "resolved": "https://registry.npmjs.org/deep-extend/-/deep-extend-0.6.0.tgz", + "integrity": "sha512-LOHxIOaPYdHlJRtCQfDIVZtfw/ufM8+rVj649RIHzcm/vGwQRXFt6OPqIFWsm2XEMrNIEtWR64sY1LEKD2vAOA==", + "dev": true + }, + "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" + } + } + } + }, + "depd": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/depd/-/depd-1.1.2.tgz", + "integrity": "sha1-m81S4UwJd2PnSbJ0xDRu0uVgtak=" + }, + "destroy": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/destroy/-/destroy-1.0.4.tgz", + "integrity": "sha1-l4hXRCxEdJ5CBmE+N5RiBYJqvYA=" + }, + "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 + }, + "dot-prop": { + "version": "4.2.0", + "resolved": "https://registry.npmjs.org/dot-prop/-/dot-prop-4.2.0.tgz", + "integrity": "sha512-tUMXrxlExSW6U2EXiiKGSBVdYgtV8qlHL+C10TsW4PURY/ic+eaysnSkwB4kA/mBlCyy/IKDJ+Lc3wbWeaXtuQ==", + "dev": true, + "requires": { + "is-obj": "^1.0.0" + } + }, + "duplexer3": { + "version": "0.1.4", + "resolved": "https://registry.npmjs.org/duplexer3/-/duplexer3-0.1.4.tgz", + "integrity": "sha1-7gHdHKwO08vH/b6jfcCo8c4ALOI=", + "dev": true + }, + "dynamic-dedupe": { + "version": "0.3.0", + "resolved": "https://registry.npmjs.org/dynamic-dedupe/-/dynamic-dedupe-0.3.0.tgz", + "integrity": "sha1-BuRMIj9eTpTXjvnbI6ZRXOL5YqE=", + "dev": true, + "requires": { + "xtend": "^4.0.0" + } + }, + "ee-first": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/ee-first/-/ee-first-1.1.1.tgz", + "integrity": "sha1-WQxhFWsK4vTwJVcyoViyZrxWsh0=" + }, + "encodeurl": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/encodeurl/-/encodeurl-1.0.2.tgz", + "integrity": "sha1-rT/0yG7C0CkyL1oCw6mmBslbP1k=" + }, + "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" + } + }, + "escape-html": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/escape-html/-/escape-html-1.0.3.tgz", + "integrity": "sha1-Aljq5NPQwJdN4cFpGI7wBR0dGYg=" + }, + "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 + }, + "etag": { + "version": "1.8.1", + "resolved": "https://registry.npmjs.org/etag/-/etag-1.8.1.tgz", + "integrity": "sha1-Qa4u62XvpiJorr/qg6x9eSmbCIc=" + }, + "execa": { + "version": "0.7.0", + "resolved": "https://registry.npmjs.org/execa/-/execa-0.7.0.tgz", + "integrity": "sha1-lEvs00zEHuMqY6n68nrVpl/Fl3c=", + "dev": true, + "requires": { + "cross-spawn": "^5.0.1", + "get-stream": "^3.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" + } + }, + "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" + } + } + } + }, + "express": { + "version": "4.17.1", + "resolved": "https://registry.npmjs.org/express/-/express-4.17.1.tgz", + "integrity": "sha512-mHJ9O79RqluphRrcw2X/GTh3k9tVv8YcoyY4Kkh4WDMUYKRZUq0h1o0w2rrrxBqM7VoeUVqgb27xlEMXTnYt4g==", + "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==", + "requires": { + "ms": "2.0.0" + } + } + } + }, + "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" + } + } + } + }, + "filewatcher": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/filewatcher/-/filewatcher-3.0.1.tgz", + "integrity": "sha1-9KGVc1Xdr0Q8zXiolfPVXiPIoDQ=", + "dev": true, + "requires": { + "debounce": "^1.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==", + "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==", + "requires": { + "ms": "2.0.0" + } + } + } + }, + "find-up": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/find-up/-/find-up-1.1.2.tgz", + "integrity": "sha1-ay6YIrGizgpgq2TWEOzK1TyyTQ8=", + "dev": true, + "requires": { + "path-exists": "^2.0.0", + "pinkie-promise": "^2.0.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 + }, + "forwarded": { + "version": "0.1.2", + "resolved": "https://registry.npmjs.org/forwarded/-/forwarded-0.1.2.tgz", + "integrity": "sha1-mMI9qxF1ZXuMBXPozszZGw/xjIQ=" + }, + "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=" + }, + "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 + } + } + }, + "get-stdin": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/get-stdin/-/get-stdin-4.0.1.tgz", + "integrity": "sha1-uWjGsKBDhDJJAui/Gl3zJXmkUP4=", + "dev": true + }, + "get-stream": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/get-stream/-/get-stream-3.0.0.tgz", + "integrity": "sha1-jpQ9E1jcN1VQVOy+LtsFqhdO3hQ=", + "dev": true + }, + "get-value": { + "version": "2.0.6", + "resolved": "https://registry.npmjs.org/get-value/-/get-value-2.0.6.tgz", + "integrity": "sha1-3BXKHGcjh8p2vTesCjlbogQqLCg=", + "dev": true + }, + "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" + } + }, + "glob-parent": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-3.1.0.tgz", + "integrity": "sha1-nmr2KZ2NO9K9QEMIMr0RPfkGxa4=", + "dev": true, + "requires": { + "is-glob": "^3.1.0", + "path-dirname": "^1.0.0" + }, + "dependencies": { + "is-glob": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/is-glob/-/is-glob-3.1.0.tgz", + "integrity": "sha1-e6WuJCF4BKxwcHuWkiVnSGzD6Eo=", + "dev": true, + "requires": { + "is-extglob": "^2.1.0" + } + } + } + }, + "global-dirs": { + "version": "0.1.1", + "resolved": "https://registry.npmjs.org/global-dirs/-/global-dirs-0.1.1.tgz", + "integrity": "sha1-sxnA3UYH81PzvpzKTHL8FIxJ9EU=", + "dev": true, + "requires": { + "ini": "^1.3.4" + } + }, + "got": { + "version": "6.7.1", + "resolved": "https://registry.npmjs.org/got/-/got-6.7.1.tgz", + "integrity": "sha1-JAzQV4WpoY5WHcG0S0HHY+8ejbA=", + "dev": true, + "requires": { + "create-error-class": "^3.0.0", + "duplexer3": "^0.1.4", + "get-stream": "^3.0.0", + "is-redirect": "^1.0.0", + "is-retry-allowed": "^1.0.0", + "is-stream": "^1.0.0", + "lowercase-keys": "^1.0.0", + "safe-buffer": "^5.0.1", + "timed-out": "^4.0.0", + "unzip-response": "^2.0.1", + "url-parse-lax": "^1.0.0" + } + }, + "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 + }, + "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-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": { + "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 + }, + "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==", + "requires": { + "depd": "~1.1.2", + "inherits": "2.0.3", + "setprototypeof": "1.1.1", + "statuses": ">= 1.5.0 < 2", + "toidentifier": "1.0.0" + }, + "dependencies": { + "inherits": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.3.tgz", + "integrity": "sha1-Yzwsg+PaQqUC9SRmAiSA9CCCYd4=" + } + } + }, + "iconv-lite": { + "version": "0.4.24", + "resolved": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.4.24.tgz", + "integrity": "sha512-v3MXnZAcvnywkTUEZomIActle7RXXeedOR31wwl7VlyoXO4Qi9arvSenNQWne1TcRwhCL1HwLI21bEqdpj8/rA==", + "requires": { + "safer-buffer": ">= 2.1.2 < 3" + } + }, + "ignore-by-default": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/ignore-by-default/-/ignore-by-default-1.0.1.tgz", + "integrity": "sha1-SMptcvbGo68Aqa1K5odr44ieKwk=", + "dev": true + }, + "import-lazy": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/import-lazy/-/import-lazy-2.1.0.tgz", + "integrity": "sha1-BWmOPUXIjo1+nZLLBYTnfwlvPkM=", + "dev": true + }, + "imurmurhash": { + "version": "0.1.4", + "resolved": "https://registry.npmjs.org/imurmurhash/-/imurmurhash-0.1.4.tgz", + "integrity": "sha1-khi5srkoojixPcT7a21XbyMUU+o=", + "dev": true + }, + "indent-string": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/indent-string/-/indent-string-2.1.0.tgz", + "integrity": "sha1-ji1INIdCEhtKghi3oTfppSBJ3IA=", + "dev": true, + "requires": { + "repeating": "^2.0.0" + } + }, + "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.4", + "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.4.tgz", + "integrity": "sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==", + "dev": true + }, + "ini": { + "version": "1.3.5", + "resolved": "https://registry.npmjs.org/ini/-/ini-1.3.5.tgz", + "integrity": "sha512-RZY5huIKCMRWDUqZlEi72f/lmXKMvuszcMBduliQ3nnWbx9X/ZBQO7DijMEYS9EhHBb2qacRUMtC7svLwe0lcw==", + "dev": true + }, + "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==" + }, + "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": { + "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-binary-path": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/is-binary-path/-/is-binary-path-1.0.1.tgz", + "integrity": "sha1-dfFmQrSA8YenEcgUFh/TpKdlWJg=", + "dev": true, + "requires": { + "binary-extensions": "^1.0.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 + }, + "is-ci": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/is-ci/-/is-ci-1.2.1.tgz", + "integrity": "sha512-s6tfsaQaQi3JNciBH6shVqEDvhGut0SUXr31ag8Pd8BBbVVlcGfWhpPmEOoM6RJ5TFhbypvf5yyRw/VXW1IiWg==", + "dev": true, + "requires": { + "ci-info": "^1.5.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": { + "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-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-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-extglob": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/is-extglob/-/is-extglob-2.1.1.tgz", + "integrity": "sha1-qIwCU1eR8C7TfHahueqXc8gz+MI=", + "dev": true + }, + "is-finite": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/is-finite/-/is-finite-1.0.2.tgz", + "integrity": "sha1-zGZ3aVYCvlUO8R6LSqYwU0K20Ko=", + "dev": true, + "requires": { + "number-is-nan": "^1.0.0" + } + }, + "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-glob": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/is-glob/-/is-glob-4.0.1.tgz", + "integrity": "sha512-5G0tKtBTFImOqDnLB2hG6Bp2qcKEFduo4tZu9MT/H6NQv/ghhy30o55ufafxJ/LdH79LLs2Kfrn85TLKyA7BUg==", + "dev": true, + "requires": { + "is-extglob": "^2.1.1" + } + }, + "is-installed-globally": { + "version": "0.1.0", + "resolved": "https://registry.npmjs.org/is-installed-globally/-/is-installed-globally-0.1.0.tgz", + "integrity": "sha1-Df2Y9akRFxbdU13aZJL2e/PSWoA=", + "dev": true, + "requires": { + "global-dirs": "^0.1.0", + "is-path-inside": "^1.0.0" + } + }, + "is-npm": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/is-npm/-/is-npm-1.0.0.tgz", + "integrity": "sha1-8vtjpl5JBbQGyGBydloaTceTufQ=", + "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": { + "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-obj": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/is-obj/-/is-obj-1.0.1.tgz", + "integrity": "sha1-PkcprB9f3gJc19g6iW2rn09n2w8=", + "dev": true + }, + "is-path-inside": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/is-path-inside/-/is-path-inside-1.0.1.tgz", + "integrity": "sha1-jvW33lBDej/cprToZe96pVy0gDY=", + "dev": true, + "requires": { + "path-is-inside": "^1.0.1" + } + }, + "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-redirect": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/is-redirect/-/is-redirect-1.0.0.tgz", + "integrity": "sha1-HQPd7VO9jbDzDCbk+V02/HyH3CQ=", + "dev": true + }, + "is-retry-allowed": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/is-retry-allowed/-/is-retry-allowed-1.2.0.tgz", + "integrity": "sha512-RUbUeKwvm3XG2VYamhJL1xFktgjvPzL0Hq8C+6yrWIswDy3BIXGqCxhxkc30N9jqK311gVU137K8Ei55/zVJRg==", + "dev": true + }, + "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-utf8": { + "version": "0.2.1", + "resolved": "https://registry.npmjs.org/is-utf8/-/is-utf8-0.2.1.tgz", + "integrity": "sha1-Sw2hRCEE0bM2NA6AeX6GXPOffXI=", + "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 + }, + "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 + }, + "latest-version": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/latest-version/-/latest-version-3.1.0.tgz", + "integrity": "sha1-ogU4P+oyKzO1rjsYq+4NwvNW7hU=", + "dev": true, + "requires": { + "package-json": "^4.0.0" + } + }, + "load-json-file": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/load-json-file/-/load-json-file-1.1.0.tgz", + "integrity": "sha1-lWkFcI1YtLq0wiYbBPWfMcmTdMA=", + "dev": true, + "requires": { + "graceful-fs": "^4.1.2", + "parse-json": "^2.2.0", + "pify": "^2.0.0", + "pinkie-promise": "^2.0.0", + "strip-bom": "^2.0.0" + }, + "dependencies": { + "pify": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/pify/-/pify-2.3.0.tgz", + "integrity": "sha1-7RQaasBDqEnqWISY59yosVMw6Qw=", + "dev": true + } + } + }, + "loud-rejection": { + "version": "1.6.0", + "resolved": "https://registry.npmjs.org/loud-rejection/-/loud-rejection-1.6.0.tgz", + "integrity": "sha1-W0b4AUft7leIcPCG0Eghz5mOVR8=", + "dev": true, + "requires": { + "currently-unhandled": "^0.4.1", + "signal-exit": "^3.0.0" + } + }, + "lowercase-keys": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/lowercase-keys/-/lowercase-keys-1.0.1.tgz", + "integrity": "sha512-G2Lj61tXDnVFFOi8VZds+SoQjtQC3dgokKdDG2mTm1tx4m50NUHBOZSBwQQHyy0V12A0JTG4icfZQH+xPyh8VA==", + "dev": true + }, + "lru-cache": { + "version": "4.1.5", + "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-4.1.5.tgz", + "integrity": "sha512-sWZlbEP2OsHNkXrMl5GYk/jKk70MBng6UU4YI/qGDYbgf6YbP4EvmqISbXCoJiRKs+1bSpFHVgQxvJ17F2li5g==", + "dev": true, + "requires": { + "pseudomap": "^1.0.2", + "yallist": "^2.1.2" + } + }, + "make-dir": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/make-dir/-/make-dir-1.3.0.tgz", + "integrity": "sha512-2w31R7SJtieJJnQtGc7RVL2StM2vGYVfqUOvUDxH6bC6aJTxPxTF0GnIgCyu7tjockiUWAYQRbxa7vKn34s5sQ==", + "dev": true, + "requires": { + "pify": "^3.0.0" + } + }, + "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 + }, + "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-obj": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/map-obj/-/map-obj-1.0.1.tgz", + "integrity": "sha1-2TPOuSBdgr3PSIb2dCvcK03qFG0=", + "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=" + }, + "meow": { + "version": "3.7.0", + "resolved": "https://registry.npmjs.org/meow/-/meow-3.7.0.tgz", + "integrity": "sha1-cstmi0JSKCkKu/qFaJJYcwioAfs=", + "dev": true, + "requires": { + "camelcase-keys": "^2.0.0", + "decamelize": "^1.1.2", + "loud-rejection": "^1.0.0", + "map-obj": "^1.0.1", + "minimist": "^1.1.3", + "normalize-package-data": "^2.3.4", + "object-assign": "^4.0.1", + "read-pkg-up": "^1.0.1", + "redent": "^1.0.0", + "trim-newlines": "^1.0.0" + } + }, + "merge-descriptors": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/merge-descriptors/-/merge-descriptors-1.0.1.tgz", + "integrity": "sha1-sAqqVW3YtEVoFQ7J0blT8/kMu2E=" + }, + "methods": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/methods/-/methods-1.1.2.tgz", + "integrity": "sha1-VSmk1nZUE07cxSZmVoNbD4Ua/O4=" + }, + "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==" + }, + "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=" + }, + "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" + } + }, + "negotiator": { + "version": "0.6.2", + "resolved": "https://registry.npmjs.org/negotiator/-/negotiator-0.6.2.tgz", + "integrity": "sha512-hZXc7K2e+PgeI1eDBe/10Ard4ekbfrrqG8Ep+8Jmf4JID2bNg7NvCPOZN+kfF574pFQI7mum2AUqDidoKqcTOw==" + }, + "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" + } + }, + "nodemon": { + "version": "1.19.2", + "resolved": "https://registry.npmjs.org/nodemon/-/nodemon-1.19.2.tgz", + "integrity": "sha512-hRLYaw5Ihyw9zK7NF+9EUzVyS6Cvgc14yh8CAYr38tPxJa6UrOxwAQ351GwrgoanHCF0FalQFn6w5eoX/LGdJw==", + "dev": true, + "requires": { + "chokidar": "^2.1.5", + "debug": "^3.1.0", + "ignore-by-default": "^1.0.1", + "minimatch": "^3.0.4", + "pstree.remy": "^1.1.6", + "semver": "^5.5.0", + "supports-color": "^5.2.0", + "touch": "^3.1.0", + "undefsafe": "^2.0.2", + "update-notifier": "^2.5.0" + } + }, + "nopt": { + "version": "1.0.10", + "resolved": "https://registry.npmjs.org/nopt/-/nopt-1.0.10.tgz", + "integrity": "sha1-bd0hvSoxQXuScn3Vhfim83YI6+4=", + "dev": true, + "requires": { + "abbrev": "1" + } + }, + "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": "3.0.0", + "resolved": "https://registry.npmjs.org/normalize-path/-/normalize-path-3.0.0.tgz", + "integrity": "sha512-6eZs5Ls3WtCisHWp9S2GUy8dqkpGi4BVSz3GaqiE6ezub0512ESztXUwUB6C6IKbQkY2Pnb/mD4WYojCRwcwLA==", + "dev": true + }, + "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" + } + }, + "number-is-nan": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/number-is-nan/-/number-is-nan-1.0.1.tgz", + "integrity": "sha1-CXtgK1NCKlIsGvuHkDGDNpQaAR0=", + "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" + } + }, + "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-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.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=", + "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" + } + }, + "p-finally": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/p-finally/-/p-finally-1.0.0.tgz", + "integrity": "sha1-P7z7FbiZpEEjs0ttzBi3JDNqLK4=", + "dev": true + }, + "package-json": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/package-json/-/package-json-4.0.1.tgz", + "integrity": "sha1-iGmgQBJTZhxMTKPabCEh7VVfXu0=", + "dev": true, + "requires": { + "got": "^6.7.1", + "registry-auth-token": "^3.0.1", + "registry-url": "^3.0.3", + "semver": "^5.1.0" + } + }, + "parse-json": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/parse-json/-/parse-json-2.2.0.tgz", + "integrity": "sha1-9ID0BDTvgHQfhGkJn43qGPVaTck=", + "dev": true, + "requires": { + "error-ex": "^1.2.0" + } + }, + "parseurl": { + "version": "1.3.3", + "resolved": "https://registry.npmjs.org/parseurl/-/parseurl-1.3.3.tgz", + "integrity": "sha512-CiyeOxFT/JZyN5m0z9PfXw4SCBJ6Sygz1Dpl0wqjlhDEGGBP1GnsUVEL0p63hoG1fcj3fHynXi9NYO4nWOL+qQ==" + }, + "pascalcase": { + "version": "0.1.1", + "resolved": "https://registry.npmjs.org/pascalcase/-/pascalcase-0.1.1.tgz", + "integrity": "sha1-s2PlXoAGym/iF4TS2yK9FdeRfxQ=", + "dev": true + }, + "path-dirname": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/path-dirname/-/path-dirname-1.0.2.tgz", + "integrity": "sha1-zDPSTVJeCZpTiMAzbG4yuRYGCeA=", + "dev": true + }, + "path-exists": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/path-exists/-/path-exists-2.1.0.tgz", + "integrity": "sha1-D+tsZPD8UY2adU3V77YscCJ2H0s=", + "dev": true, + "requires": { + "pinkie-promise": "^2.0.0" + } + }, + "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-is-inside": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/path-is-inside/-/path-is-inside-1.0.2.tgz", + "integrity": "sha1-NlQX3t5EQw0cEa9hAn+s8HS9/FM=", + "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=" + }, + "path-type": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/path-type/-/path-type-1.1.0.tgz", + "integrity": "sha1-WcRPfuSR2nBNpBXaWkBwuk+P5EE=", + "dev": true, + "requires": { + "graceful-fs": "^4.1.2", + "pify": "^2.0.0", + "pinkie-promise": "^2.0.0" + }, + "dependencies": { + "pify": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/pify/-/pify-2.3.0.tgz", + "integrity": "sha1-7RQaasBDqEnqWISY59yosVMw6Qw=", + "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 + }, + "pinkie": { + "version": "2.0.4", + "resolved": "https://registry.npmjs.org/pinkie/-/pinkie-2.0.4.tgz", + "integrity": "sha1-clVrgM+g1IqXToDnckjoDtT3+HA=", + "dev": true + }, + "pinkie-promise": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/pinkie-promise/-/pinkie-promise-2.0.1.tgz", + "integrity": "sha1-ITXW36ejWMBprJsXh3YogihFD/o=", + "dev": true, + "requires": { + "pinkie": "^2.0.0" + } + }, + "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 + }, + "prepend-http": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/prepend-http/-/prepend-http-1.0.4.tgz", + "integrity": "sha1-1PRWKwzjaW5BrFLQ4ALlemNdxtw=", + "dev": true + }, + "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 + }, + "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==", + "requires": { + "forwarded": "~0.1.2", + "ipaddr.js": "1.9.0" + } + }, + "pseudomap": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/pseudomap/-/pseudomap-1.0.2.tgz", + "integrity": "sha1-8FKijacOYYkX7wqKw0wa5aaChrM=", + "dev": true + }, + "pstree.remy": { + "version": "1.1.7", + "resolved": "https://registry.npmjs.org/pstree.remy/-/pstree.remy-1.1.7.tgz", + "integrity": "sha512-xsMgrUwRpuGskEzBFkH8NmTimbZ5PcPup0LA8JJkHIm2IMUbQcpo3yeLNWVrufEYjh8YwtSVh0xz6UeWc5Oh5A==", + "dev": true + }, + "qs": { + "version": "6.7.0", + "resolved": "https://registry.npmjs.org/qs/-/qs-6.7.0.tgz", + "integrity": "sha512-VCdBRNFTX1fyE7Nb6FYoURo/SPe62QCaAyzJvUjwRaIsc+NePBEniHlvxFmmX56+HZphIGtV0XeCirBtpDrTyQ==" + }, + "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==" + }, + "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==", + "requires": { + "bytes": "3.1.0", + "http-errors": "1.7.2", + "iconv-lite": "0.4.24", + "unpipe": "1.0.0" + } + }, + "rc": { + "version": "1.2.8", + "resolved": "https://registry.npmjs.org/rc/-/rc-1.2.8.tgz", + "integrity": "sha512-y3bGgqKj3QBdxLbLkomlohkvsA8gdAiUQlSBJnBhfn+BPxg4bc62d8TcBW15wavDfgexCgccckhcZvywyQYPOw==", + "dev": true, + "requires": { + "deep-extend": "^0.6.0", + "ini": "~1.3.0", + "minimist": "^1.2.0", + "strip-json-comments": "~2.0.1" + } + }, + "read-pkg": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/read-pkg/-/read-pkg-1.1.0.tgz", + "integrity": "sha1-9f+qXs0pyzHAR0vKfXVra7KePyg=", + "dev": true, + "requires": { + "load-json-file": "^1.0.0", + "normalize-package-data": "^2.3.2", + "path-type": "^1.0.0" + } + }, + "read-pkg-up": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/read-pkg-up/-/read-pkg-up-1.0.1.tgz", + "integrity": "sha1-nWPBMnbAZZGNV/ACpX9AobZD+wI=", + "dev": true, + "requires": { + "find-up": "^1.0.0", + "read-pkg": "^1.0.0" + } + }, + "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" + } + }, + "readdirp": { + "version": "2.2.1", + "resolved": "https://registry.npmjs.org/readdirp/-/readdirp-2.2.1.tgz", + "integrity": "sha512-1JU/8q+VgFZyxwrJ+SVIOsh+KywWGpds3NTqikiKpDMZWScmAYyKIgqkO+ARvNWJfXeXR1zxz7aHF4u4CyH6vQ==", + "dev": true, + "requires": { + "graceful-fs": "^4.1.11", + "micromatch": "^3.1.10", + "readable-stream": "^2.0.2" + } + }, + "redent": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/redent/-/redent-1.0.0.tgz", + "integrity": "sha1-z5Fqsf1fHxbfsggi3W7H9zDCr94=", + "dev": true, + "requires": { + "indent-string": "^2.1.0", + "strip-indent": "^1.0.1" + } + }, + "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" + } + }, + "registry-auth-token": { + "version": "3.4.0", + "resolved": "https://registry.npmjs.org/registry-auth-token/-/registry-auth-token-3.4.0.tgz", + "integrity": "sha512-4LM6Fw8eBQdwMYcES4yTnn2TqIasbXuwDx3um+QRs7S55aMKCBKBxvPXl2RiUjHwuJLTyYfxSpmfSAjQpcuP+A==", + "dev": true, + "requires": { + "rc": "^1.1.6", + "safe-buffer": "^5.0.1" + } + }, + "registry-url": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/registry-url/-/registry-url-3.1.0.tgz", + "integrity": "sha1-PU74cPc93h138M+aOBQyRE4XSUI=", + "dev": true, + "requires": { + "rc": "^1.0.1" + } + }, + "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 + }, + "repeating": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/repeating/-/repeating-2.0.1.tgz", + "integrity": "sha1-UhTFOpJtNVJwdSf7q0FdvAjQbdo=", + "dev": true, + "requires": { + "is-finite": "^1.0.0" + } + }, + "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-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" + } + }, + "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==" + }, + "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==" + }, + "semver": { + "version": "5.7.1", + "resolved": "https://registry.npmjs.org/semver/-/semver-5.7.1.tgz", + "integrity": "sha512-sauaDf/PZdVgrLTNYHRtpXa1iRiKcaebiKQ1BJdpQlWH2lCvexQdX55snPFyK7QzpudqbCI0qXFfOasHdyNDGQ==", + "dev": true + }, + "semver-diff": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/semver-diff/-/semver-diff-2.1.0.tgz", + "integrity": "sha1-S7uEN8jTfksM8aaP1ybsbWRdbTY=", + "dev": true, + "requires": { + "semver": "^5.0.3" + } + }, + "send": { + "version": "0.17.1", + "resolved": "https://registry.npmjs.org/send/-/send-0.17.1.tgz", + "integrity": "sha512-BsVKsiGcQMFwT8UxypobUKyv7irCNRHk1T0G680vk88yf6LBByGcZJOTJCrTP2xVN6yI+XjPJcNuE3V4fT9sAg==", + "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==", + "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=" + } + } + }, + "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==" + } + } + }, + "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==", + "requires": { + "encodeurl": "~1.0.2", + "escape-html": "~1.0.3", + "parseurl": "~1.3.3", + "send": "0.17.1" + } + }, + "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==" + }, + "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 + }, + "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" + } + } + } + }, + "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": { + "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.5.7", + "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.5.7.tgz", + "integrity": "sha1-igOdLRAh0i0eoUyA2OpGi6LvP8w=", + "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" + }, + "dependencies": { + "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-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" + } + }, + "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=" + }, + "string-width": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/string-width/-/string-width-2.1.1.tgz", + "integrity": "sha512-nOqH59deCq9SRHlxq1Aw85Jnt4w6KvLKqWVik6oA9ZklXLNIOlqg4F2yrT1MVaTjAqvVwdfeZ7w7aCvJD7ugkw==", + "dev": true, + "requires": { + "is-fullwidth-code-point": "^2.0.0", + "strip-ansi": "^4.0.0" + } + }, + "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" + } + }, + "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" + } + }, + "strip-bom": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/strip-bom/-/strip-bom-2.0.0.tgz", + "integrity": "sha1-YhmoVhZSBJHzV4i9vxRHqZx+aw4=", + "dev": true, + "requires": { + "is-utf8": "^0.2.0" + } + }, + "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 + }, + "strip-indent": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/strip-indent/-/strip-indent-1.0.1.tgz", + "integrity": "sha1-DHlipq3vp7vUrDZkYKY4VSrhoKI=", + "dev": true, + "requires": { + "get-stdin": "^4.0.1" + } + }, + "strip-json-comments": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/strip-json-comments/-/strip-json-comments-2.0.1.tgz", + "integrity": "sha1-PFMZQukIwml8DsNEhYwobHygpgo=", + "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" + } + }, + "term-size": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/term-size/-/term-size-1.2.0.tgz", + "integrity": "sha1-RYuDiH8oj8Vtb/+/rSYuJmOO+mk=", + "dev": true, + "requires": { + "execa": "^0.7.0" + } + }, + "timed-out": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/timed-out/-/timed-out-4.0.1.tgz", + "integrity": "sha1-8y6srFoXW+ol1/q1Zas+2HQe9W8=", + "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": { + "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==" + }, + "touch": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/touch/-/touch-3.1.0.tgz", + "integrity": "sha512-WBx8Uy5TLtOSRtIq+M03/sKDrXCLHxwDcquSP2c43Le03/9serjQBIztjRz6FkJez9D/hleyAXTBGLwwZUw9lA==", + "dev": true, + "requires": { + "nopt": "~1.0.10" + } + }, + "tree-kill": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/tree-kill/-/tree-kill-1.2.1.tgz", + "integrity": "sha512-4hjqbObwlh2dLyW4tcz0Ymw0ggoaVDMveUB9w8kFSQScdRLo0gxO9J7WFcUBo+W3C1TLdFIEwNOWebgZZ0RH9Q==", + "dev": true + }, + "trim-newlines": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/trim-newlines/-/trim-newlines-1.0.0.tgz", + "integrity": "sha1-WIeWa7WCpFA6QetST301ARgVphM=", + "dev": true + }, + "ts-node": { + "version": "8.4.1", + "resolved": "https://registry.npmjs.org/ts-node/-/ts-node-8.4.1.tgz", + "integrity": "sha512-5LpRN+mTiCs7lI5EtbXmF/HfMeCjzt7DH9CZwtkr6SywStrNQC723wG+aOWFiLNn7zT3kD/RnFqi3ZUfr4l5Qw==", + "dev": true, + "requires": { + "arg": "^4.1.0", + "diff": "^4.0.1", + "make-error": "^1.1.1", + "source-map-support": "^0.5.6", + "yn": "^3.0.0" + } + }, + "ts-node-dev": { + "version": "1.0.0-pre.42", + "resolved": "https://registry.npmjs.org/ts-node-dev/-/ts-node-dev-1.0.0-pre.42.tgz", + "integrity": "sha512-1jrTjDu6SpBCkRYuBsBIND6hPO3FBP8+XdovchYp7Fi95pIpG0AmpVY+Xk4cmYTogd1sB4g0dQU98U1l0lHPtg==", + "dev": true, + "requires": { + "dateformat": "~1.0.4-1.2.3", + "dynamic-dedupe": "^0.3.0", + "filewatcher": "~3.0.0", + "minimist": "^1.1.3", + "mkdirp": "^0.5.1", + "node-notifier": "^5.4.0", + "resolve": "^1.0.0", + "rimraf": "^2.6.1", + "source-map-support": "^0.5.12", + "tree-kill": "^1.2.1", + "ts-node": "*", + "tsconfig": "^7.0.0" + } + }, + "tsconfig": { + "version": "7.0.0", + "resolved": "https://registry.npmjs.org/tsconfig/-/tsconfig-7.0.0.tgz", + "integrity": "sha512-vZXmzPrL+EmC4T/4rVlT2jNVMWCi/O4DIiSj3UHg1OE5kCKbk4mfrXc6dZksLgRM/TZlKnousKH9bbTazUWRRw==", + "dev": true, + "requires": { + "@types/strip-bom": "^3.0.0", + "@types/strip-json-comments": "0.0.30", + "strip-bom": "^3.0.0", + "strip-json-comments": "^2.0.0" + }, + "dependencies": { + "strip-bom": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/strip-bom/-/strip-bom-3.0.0.tgz", + "integrity": "sha1-IzTBjpx1n3vdVv3vfprj1YjmjtM=", + "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==", + "requires": { + "media-typer": "0.3.0", + "mime-types": "~2.1.24" + } + }, "typescript": { "version": "3.6.3", "resolved": "https://registry.npmjs.org/typescript/-/typescript-3.6.3.tgz", "integrity": "sha512-N7bceJL1CtRQ2RiG0AQME13ksR7DiuQh/QehubYcghzv20tnh+MQnQIuJddTmsbqYj+dztchykemz0zFzlvdQw==", "dev": true + }, + "undefsafe": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/undefsafe/-/undefsafe-2.0.2.tgz", + "integrity": "sha1-Il9rngM3Zj4Njnz9aG/Cg2zKznY=", + "dev": true, + "requires": { + "debug": "^2.2.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" + } + } + } + }, + "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" + } + }, + "unique-string": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/unique-string/-/unique-string-1.0.0.tgz", + "integrity": "sha1-nhBXzKhRq7kzmPizOuGHuZyuwRo=", + "dev": true, + "requires": { + "crypto-random-string": "^1.0.0" + } + }, + "unpipe": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/unpipe/-/unpipe-1.0.0.tgz", + "integrity": "sha1-sr9O6FFKrmFltIF4KdIbLvSZBOw=" + }, + "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 + } + } + }, + "unzip-response": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/unzip-response/-/unzip-response-2.0.1.tgz", + "integrity": "sha1-0vD3N9FrBhXnKmk17QQhRXLVb5c=", + "dev": true + }, + "upath": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/upath/-/upath-1.2.0.tgz", + "integrity": "sha512-aZwGpamFO61g3OlfT7OQCHqhGnW43ieH9WZeP7QxN/G/jS4jfqUkZxoryvJgVPEcrl5NL/ggHsSmLMHuH64Lhg==", + "dev": true + }, + "update-notifier": { + "version": "2.5.0", + "resolved": "https://registry.npmjs.org/update-notifier/-/update-notifier-2.5.0.tgz", + "integrity": "sha512-gwMdhgJHGuj/+wHJJs9e6PcCszpxR1b236igrOkUofGhqJuG+amlIKwApH1IW1WWl7ovZxsX49lMBWLxSdm5Dw==", + "dev": true, + "requires": { + "boxen": "^1.2.1", + "chalk": "^2.0.1", + "configstore": "^3.0.0", + "import-lazy": "^2.1.0", + "is-ci": "^1.0.10", + "is-installed-globally": "^0.1.0", + "is-npm": "^1.0.0", + "latest-version": "^3.0.0", + "semver-diff": "^2.0.0", + "xdg-basedir": "^3.0.0" + } + }, + "urix": { + "version": "0.1.0", + "resolved": "https://registry.npmjs.org/urix/-/urix-0.1.0.tgz", + "integrity": "sha1-2pN/emLiH+wf0Y1Js1wpNQZ6bHI=", + "dev": true + }, + "url-parse-lax": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/url-parse-lax/-/url-parse-lax-1.0.0.tgz", + "integrity": "sha1-evjzA2Rem9eaJy56FKxovAYJ2nM=", + "dev": true, + "requires": { + "prepend-http": "^1.0.1" + } + }, + "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 + }, + "utils-merge": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/utils-merge/-/utils-merge-1.0.1.tgz", + "integrity": "sha1-n5VxD1CiZ5R7LMwSR0HBAoQn5xM=" + }, + "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=" + }, + "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" + } + }, + "widest-line": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/widest-line/-/widest-line-2.0.1.tgz", + "integrity": "sha512-Ba5m9/Fa4Xt9eb2ELXt77JxVDV8w7qQrH0zS/TWSJdLyAwQjWoOzpzj5lwVftDz6n/EOu3tNACS84v509qwnJA==", + "dev": true, + "requires": { + "string-width": "^2.1.1" + } + }, + "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.3", + "resolved": "https://registry.npmjs.org/write-file-atomic/-/write-file-atomic-2.4.3.tgz", + "integrity": "sha512-GaETH5wwsX+GcnzhPgKcKjJ6M2Cq3/iZp1WyY/X1CSqrW+jVNM9Y7D8EC2sM4ZG/V8wZlSniJnCKWPmBYAucRQ==", + "dev": true, + "requires": { + "graceful-fs": "^4.1.11", + "imurmurhash": "^0.1.4", + "signal-exit": "^3.0.2" + } + }, + "xdg-basedir": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/xdg-basedir/-/xdg-basedir-3.0.0.tgz", + "integrity": "sha1-SWsswQnsqNus/i3HK2A8F8WHCtQ=", + "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 + }, + "yallist": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/yallist/-/yallist-2.1.2.tgz", + "integrity": "sha1-HBH5IY8HYImkfdUS+TxmmaaoHVI=", + "dev": true + }, + "yn": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/yn/-/yn-3.1.1.tgz", + "integrity": "sha512-Ux4ygGWsu2c7isFWe8Yu1YluJmqVhxqK2cLXNQA5AcC3QfbGNpM7fu0Y8b/z16pXLnFxZYvWhd3fhBY9DLmC6Q==", + "dev": true } } } diff --git a/package.json b/package.json index eb30a81..73aaa62 100644 --- a/package.json +++ b/package.json @@ -4,7 +4,8 @@ "description": "Desafio Backend em NodeJS", "main": "server.js", "scripts": { - "tsc": "tsc" + "tsc": "tsc", + "dev": "nodemon src/server.ts" }, "repository": { "type": "git", @@ -18,6 +19,11 @@ "homepage": "https://github.com/LUIZFH/desafio-backend#readme", "devDependencies": { "@types/express": "^4.17.1", + "nodemon": "^1.19.2", + "ts-node-dev": "^1.0.0-pre.42", "typescript": "^3.6.3" + }, + "dependencies": { + "express": "^4.17.1" } } From 4a8652f7465eb69d677657426aeb7db8ad1a8de3 Mon Sep 17 00:00:00 2001 From: Luiz Filho Date: Wed, 18 Sep 2019 23:43:48 -0300 Subject: [PATCH 06/65] add initial config swagger openapi specification --- package-lock.json | 36 +++++++++++++++++++++++++----------- package.json | 4 +++- src/server.ts | 4 ++++ swagger.json | 8 ++++++++ tsconfig.json | 1 + 5 files changed, 41 insertions(+), 12 deletions(-) create mode 100644 swagger.json diff --git a/package-lock.json b/package-lock.json index fbc8887..4f68a63 100644 --- a/package-lock.json +++ b/package-lock.json @@ -8,7 +8,6 @@ "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": "*" @@ -18,7 +17,6 @@ "version": "3.4.32", "resolved": "https://registry.npmjs.org/@types/connect/-/connect-3.4.32.tgz", "integrity": "sha512-4r8qa0quOvh7lGD0pre62CAb1oni1OO6ecJLGCezTmhQ8Fz50Arx9RUszryR8KlgK6avuSXvviL6yWyViQABOg==", - "dev": true, "requires": { "@types/node": "*" } @@ -27,7 +25,6 @@ "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": "*", @@ -38,7 +35,6 @@ "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": "*" @@ -47,26 +43,22 @@ "@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 + "integrity": "sha512-FwI9gX75FgVBJ7ywgnq/P7tw+/o1GUbtP0KzbtusLigAOgIgNISRK0ZPl4qertvXSIE8YbsVJueQ90cDt9YYyw==" }, "@types/node": { "version": "12.7.5", "resolved": "https://registry.npmjs.org/@types/node/-/node-12.7.5.tgz", - "integrity": "sha512-9fq4jZVhPNW8r+UYKnxF1e2HkDWOWKM5bC2/7c9wPV835I0aOrVbS/Hw/pWPk2uKrNXQqg9Z959Kz+IYDd5p3w==", - "dev": true + "integrity": "sha512-9fq4jZVhPNW8r+UYKnxF1e2HkDWOWKM5bC2/7c9wPV835I0aOrVbS/Hw/pWPk2uKrNXQqg9Z959Kz+IYDd5p3w==" }, "@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 + "integrity": "sha512-ewFXqrQHlFsgc09MK5jP5iR7vumV/BYayNC6PgJO2LPe8vrnNFyjQjSppfEngITi0qvfKtzFvgKymGheFM9UOA==" }, "@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": "*" @@ -84,6 +76,15 @@ "integrity": "sha512-7NQmHra/JILCd1QqpSzl8+mJRc8ZHz3uDm8YV1Ks9IhK0epEiTw8aIErbvH9PI+6XbqhyIQy3462nEsn7UVzjQ==", "dev": true }, + "@types/swagger-ui-express": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/@types/swagger-ui-express/-/swagger-ui-express-3.0.1.tgz", + "integrity": "sha512-AHIIs9tUDimRAKvmHHBXxNfavjcvZuGgu/iXaSVpBk+C6EO/H1PUBIq4l5opFXLbV+hBuVbYnpycbobhSoMjTA==", + "requires": { + "@types/express": "*", + "@types/serve-static": "*" + } + }, "abbrev": { "version": "1.1.1", "resolved": "https://registry.npmjs.org/abbrev/-/abbrev-1.1.1.tgz", @@ -3233,6 +3234,19 @@ "has-flag": "^3.0.0" } }, + "swagger-ui-dist": { + "version": "3.23.10", + "resolved": "https://registry.npmjs.org/swagger-ui-dist/-/swagger-ui-dist-3.23.10.tgz", + "integrity": "sha512-lK9oNNb9HAz2HJIg6+cYZszbYC/0CTm0nWi0XX2AjEbVgu43smbW2/h5zn7yAjYstPJBaYXkt5g6ABRpO/Ncfg==" + }, + "swagger-ui-express": { + "version": "4.1.1", + "resolved": "https://registry.npmjs.org/swagger-ui-express/-/swagger-ui-express-4.1.1.tgz", + "integrity": "sha512-PDt7A4JZYszP2/AcnsYj24u1RwVRV3/8LvCZSL6EcxKq918OBhS1e7NHqS+2woBHi0zn8HjeiJVxXDBKVxgwYw==", + "requires": { + "swagger-ui-dist": "^3.18.1" + } + }, "term-size": { "version": "1.2.0", "resolved": "https://registry.npmjs.org/term-size/-/term-size-1.2.0.tgz", diff --git a/package.json b/package.json index 73aaa62..9765fb4 100644 --- a/package.json +++ b/package.json @@ -24,6 +24,8 @@ "typescript": "^3.6.3" }, "dependencies": { - "express": "^4.17.1" + "@types/swagger-ui-express": "^3.0.1", + "express": "^4.17.1", + "swagger-ui-express": "^4.1.1" } } diff --git a/src/server.ts b/src/server.ts index e4ec078..3d8196c 100644 --- a/src/server.ts +++ b/src/server.ts @@ -1,4 +1,6 @@ import express from 'express' +import swaggerUi from 'swagger-ui-express' +import * as swaggerDocumentat from '../swagger.json' const server: express.Application = express() @@ -6,6 +8,8 @@ server.get('/', (request, response) => { response.send({ message: 'Welcome to my challenge'}) }) +server.use('/swagger', swaggerUi.serve, swaggerUi.setup(swaggerDocumentat)) + server.listen(4446, () => { console.log(`Server is running! Welcome!`) }) \ No newline at end of file diff --git a/swagger.json b/swagger.json new file mode 100644 index 0000000..65be1db --- /dev/null +++ b/swagger.json @@ -0,0 +1,8 @@ +{ + "openapi": "3.0.0", + "info": { + "version": "1.0.0", + "title": "Backend challenge NodeJS Luiz Filho", + "description": "Patient Registration and Appointment Scheduling API" + } +} \ No newline at end of file diff --git a/tsconfig.json b/tsconfig.json index dd93202..bdd4f39 100644 --- a/tsconfig.json +++ b/tsconfig.json @@ -4,6 +4,7 @@ // "incremental": true, /* Enable incremental compilation */ "target": "es5", /* Specify ECMAScript target version: 'ES3' (default), 'ES5', 'ES2015', 'ES2016', 'ES2017', 'ES2018', 'ES2019' or 'ESNEXT'. */ "module": "commonjs", /* Specify module code generation: 'none', 'commonjs', 'amd', 'system', 'umd', 'es2015', or 'ESNext'. */ + "resolveJsonModule": true, // "lib": [], /* Specify library files to be included in the compilation. */ // "allowJs": true, /* Allow javascript files to be compiled. */ // "checkJs": true, /* Report errors in .js files. */ From b2d7951443d78ccf456ef497da82f6430bb24710 Mon Sep 17 00:00:00 2001 From: Luiz Filho Date: Thu, 19 Sep 2019 00:37:47 -0300 Subject: [PATCH 07/65] initial docker and docker compose config --- .dockerignore | 2 ++ .gitignore | 1 + Dockerfile | 12 ++++++++++++ docker-compose.yml | 7 +++++++ 4 files changed, 22 insertions(+) create mode 100644 .dockerignore create mode 100644 Dockerfile create mode 100644 docker-compose.yml diff --git a/.dockerignore b/.dockerignore new file mode 100644 index 0000000..25c8fdb --- /dev/null +++ b/.dockerignore @@ -0,0 +1,2 @@ +node_modules +package-lock.json \ No newline at end of file diff --git a/.gitignore b/.gitignore index b7dab5e..a049075 100644 --- a/.gitignore +++ b/.gitignore @@ -1,2 +1,3 @@ node_modules +package-lock.json build \ No newline at end of file diff --git a/Dockerfile b/Dockerfile new file mode 100644 index 0000000..b10a8af --- /dev/null +++ b/Dockerfile @@ -0,0 +1,12 @@ +FROM node:alpine + +RUN mkdir -p /var/www/api +WORKDIR /var/www/api + +COPY package.json ./ +RUN npm install +COPY . ./ + +EXPOSE 4446 + +CMD ["npm", "run", "dev"] \ No newline at end of file diff --git a/docker-compose.yml b/docker-compose.yml new file mode 100644 index 0000000..bdd8d31 --- /dev/null +++ b/docker-compose.yml @@ -0,0 +1,7 @@ +version: "3" + +services: + api: + build: . + ports: + - "4446:4446" \ No newline at end of file From 924173bd33d9332c695bd3601180b80c98cb71f2 Mon Sep 17 00:00:00 2001 From: Luiz Filho Date: Thu, 19 Sep 2019 01:09:38 -0300 Subject: [PATCH 08/65] refactor: created app class to server --- src/app.ts | 21 +++++++++++++++++++++ src/server.ts | 16 ++-------------- 2 files changed, 23 insertions(+), 14 deletions(-) create mode 100644 src/app.ts diff --git a/src/app.ts b/src/app.ts new file mode 100644 index 0000000..36979a5 --- /dev/null +++ b/src/app.ts @@ -0,0 +1,21 @@ +import express from 'express' +import swaggerUi from 'swagger-ui-express' +import * as swaggerDocument from '../swagger.json' + +class App { + private express: express.Application + + public constructor () { + this.express = express() + this.swagger() + } + + private swagger (): void { + this.express.use('/documentation', swaggerUi.serve, swaggerUi.setup(swaggerDocument)) + } + + public start(port: number): void { + this.express.listen(port) + } +} +export default new App() \ No newline at end of file diff --git a/src/server.ts b/src/server.ts index 3d8196c..a0f4baa 100644 --- a/src/server.ts +++ b/src/server.ts @@ -1,15 +1,3 @@ -import express from 'express' -import swaggerUi from 'swagger-ui-express' -import * as swaggerDocumentat from '../swagger.json' +import App from './app' -const server: express.Application = express() - -server.get('/', (request, response) => { - response.send({ message: 'Welcome to my challenge'}) -}) - -server.use('/swagger', swaggerUi.serve, swaggerUi.setup(swaggerDocumentat)) - -server.listen(4446, () => { - console.log(`Server is running! Welcome!`) -}) \ No newline at end of file +App.start(4446) \ No newline at end of file From bd6b2598eb9106620789fd91a0b2eab2a1e81768 Mon Sep 17 00:00:00 2001 From: Luiz Filho Date: Fri, 20 Sep 2019 00:17:25 -0300 Subject: [PATCH 09/65] added routes file for separation of responsablitities --- src/app.ts | 6 ++++++ src/routes/index.ts | 9 +++++++++ 2 files changed, 15 insertions(+) create mode 100644 src/routes/index.ts diff --git a/src/app.ts b/src/app.ts index 36979a5..6ab37d5 100644 --- a/src/app.ts +++ b/src/app.ts @@ -1,5 +1,6 @@ import express from 'express' import swaggerUi from 'swagger-ui-express' +import routes from './routes' import * as swaggerDocument from '../swagger.json' class App { @@ -7,9 +8,14 @@ class App { public constructor () { this.express = express() + this.routes() this.swagger() } + private routes (): void { + this.express.use(routes) + } + private swagger (): void { this.express.use('/documentation', swaggerUi.serve, swaggerUi.setup(swaggerDocument)) } diff --git a/src/routes/index.ts b/src/routes/index.ts new file mode 100644 index 0000000..4efcb60 --- /dev/null +++ b/src/routes/index.ts @@ -0,0 +1,9 @@ +import { Router } from 'express' + +const routes = Router() + +routes.get('/', (request, response) => { + response.send({ message: 'Welcome' }) +}) + +export default routes \ No newline at end of file From 5a09e41fb6d1afb746fe61da0dbf7767efc84de6 Mon Sep 17 00:00:00 2001 From: Luiz Filho Date: Fri, 20 Sep 2019 00:37:40 -0300 Subject: [PATCH 10/65] added route test swagger --- swagger.json | 27 +++++++++++++++++++++++++++ 1 file changed, 27 insertions(+) diff --git a/swagger.json b/swagger.json index 65be1db..d570a30 100644 --- a/swagger.json +++ b/swagger.json @@ -4,5 +4,32 @@ "version": "1.0.0", "title": "Backend challenge NodeJS Luiz Filho", "description": "Patient Registration and Appointment Scheduling API" + }, + "tags": [ + { + "name": "Challenge Backend NodeJS - Scheduling Exams", + "description": "API for scheduling exams and patient registration." + } + ], + "consumes": [ + "application/json" + ], + "produces": [ + "application/json" + ], + "paths": { + "/": { + "get": { + "tags": [ + "Welcome" + ], + "summary": "Default route", + "responses": { + "200": { + "description": "OK" + } + } + } + } } } \ No newline at end of file From 09f1636d385e27e3b3cf26cd5ec3d375f055fd02 Mon Sep 17 00:00:00 2001 From: Luiz Filho Date: Fri, 20 Sep 2019 01:14:10 -0300 Subject: [PATCH 11/65] initial config jest for test --- jest.config.js | 8 ++++++++ package.json | 6 +++++- src/services/index.spec.ts | 3 +++ src/services/index.ts | 0 tsconfig.json | 4 +++- 5 files changed, 19 insertions(+), 2 deletions(-) create mode 100644 jest.config.js create mode 100644 src/services/index.spec.ts create mode 100644 src/services/index.ts diff --git a/jest.config.js b/jest.config.js new file mode 100644 index 0000000..5e2696f --- /dev/null +++ b/jest.config.js @@ -0,0 +1,8 @@ +module.exports = { + roots: ['/src'], + transform: { + '^.+\\.tsx?$': 'ts-jest', + }, + testRegex: '(/__tests__/.*|(\\.|/)(test|spec))\\.tsx?$', + moduleFileExtensions: ['ts', 'tsx', 'js', 'jsx', 'json', 'node'], +} \ No newline at end of file diff --git a/package.json b/package.json index 9765fb4..811732b 100644 --- a/package.json +++ b/package.json @@ -5,7 +5,8 @@ "main": "server.js", "scripts": { "tsc": "tsc", - "dev": "nodemon src/server.ts" + "dev": "nodemon src/server.ts", + "test": "jest" }, "repository": { "type": "git", @@ -19,7 +20,10 @@ "homepage": "https://github.com/LUIZFH/desafio-backend#readme", "devDependencies": { "@types/express": "^4.17.1", + "@types/jest": "^24.0.18", + "jest": "^24.9.0", "nodemon": "^1.19.2", + "ts-jest": "^24.1.0", "ts-node-dev": "^1.0.0-pre.42", "typescript": "^3.6.3" }, diff --git a/src/services/index.spec.ts b/src/services/index.spec.ts new file mode 100644 index 0000000..5eded20 --- /dev/null +++ b/src/services/index.spec.ts @@ -0,0 +1,3 @@ +test('should return true', () => { + expect(true).toBe(true) +}) \ No newline at end of file diff --git a/src/services/index.ts b/src/services/index.ts new file mode 100644 index 0000000..e69de29 diff --git a/tsconfig.json b/tsconfig.json index bdd4f39..f0a1af9 100644 --- a/tsconfig.json +++ b/tsconfig.json @@ -60,5 +60,7 @@ /* Experimental Options */ // "experimentalDecorators": true, /* Enables experimental support for ES7 decorators. */ // "emitDecoratorMetadata": true, /* Enables experimental support for emitting type metadata for decorators. */ - } + }, + "include": ["src/**/*"], + "exclude": ["node_modules", "**/*.spec.ts"] } From f18c7435f044ac08957b2310e3ca56c7f79ebf89 Mon Sep 17 00:00:00 2001 From: Luiz Filho Date: Fri, 20 Sep 2019 02:53:49 -0300 Subject: [PATCH 12/65] added call for exams api and its unit test --- jest.config.js | 2 +- package.json | 1 + src/services/exams.ts | 11 +++++++++++ tests/unit/exam/service.spec.ts | 24 ++++++++++++++++++++++++ 4 files changed, 37 insertions(+), 1 deletion(-) create mode 100644 src/services/exams.ts create mode 100644 tests/unit/exam/service.spec.ts diff --git a/jest.config.js b/jest.config.js index 5e2696f..6da78a8 100644 --- a/jest.config.js +++ b/jest.config.js @@ -1,5 +1,5 @@ module.exports = { - roots: ['/src'], + roots: ['/src', '/tests'], transform: { '^.+\\.tsx?$': 'ts-jest', }, diff --git a/package.json b/package.json index 811732b..836b625 100644 --- a/package.json +++ b/package.json @@ -29,6 +29,7 @@ }, "dependencies": { "@types/swagger-ui-express": "^3.0.1", + "axios": "^0.19.0", "express": "^4.17.1", "swagger-ui-express": "^4.1.1" } diff --git a/src/services/exams.ts b/src/services/exams.ts new file mode 100644 index 0000000..4305ad1 --- /dev/null +++ b/src/services/exams.ts @@ -0,0 +1,11 @@ +import axios from 'axios' + +class ExamsService { + static list() { + return axios.get('http://www.mocky.io/v2/5d681ede33000054e7e65c3f').then( (response: any) => { + return response.data.map( ({ id, name }: { id: Number, name: String}) => ({ id, name })) + }) + } +} + +export default ExamsService \ No newline at end of file diff --git a/tests/unit/exam/service.spec.ts b/tests/unit/exam/service.spec.ts new file mode 100644 index 0000000..3891299 --- /dev/null +++ b/tests/unit/exam/service.spec.ts @@ -0,0 +1,24 @@ +import axios from 'axios' +import ExamsService from '../../../src/services/exams' + +jest.mock('axios') +const mockedAxios = axios as jest.Mocked + +test('should return exam list', () => { + const exams = [ + { id: 1, name: 'Raio-x', value: 30.44 }, + { id: 2, name: 'Ultrassonografia', value: 46.21 }, + { id: 3, name: 'Endoscopia', value: 44.31 } + ] + + const expected = [ + { id: 1, name: 'Raio-x' }, + { id: 2, name: 'Ultrassonografia' }, + { id: 3, name: 'Endoscopia' } + ] + + mockedAxios.get.mockResolvedValue({ data: exams }) + + return ExamsService.list().then( data => expect(data).toEqual(expected)) + +}) From 6b0e5dcbdf8f0a42802632e5df78c9372f46938d Mon Sep 17 00:00:00 2001 From: Luiz Filho Date: Fri, 20 Sep 2019 03:48:23 -0300 Subject: [PATCH 13/65] refactor exam service --- src/services/exams.ts | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/src/services/exams.ts b/src/services/exams.ts index 4305ad1..6d1ab94 100644 --- a/src/services/exams.ts +++ b/src/services/exams.ts @@ -1,10 +1,9 @@ import axios from 'axios' class ExamsService { - static list() { - return axios.get('http://www.mocky.io/v2/5d681ede33000054e7e65c3f').then( (response: any) => { - return response.data.map( ({ id, name }: { id: Number, name: String}) => ({ id, name })) - }) + static async list(): Promise { + let response = await axios.get('http://www.mocky.io/v2/5d681ede33000054e7e65c3f') + return response.data.map( ({ id, name }: { id: Number, name: String}) => ({ id, name })) } } From 6bf708a53779504ba4a1c90cca945c46279300b3 Mon Sep 17 00:00:00 2001 From: Luiz Filho Date: Fri, 20 Sep 2019 03:51:44 -0300 Subject: [PATCH 14/65] renamed service request external api --- src/services/{exams.ts => apiExams.ts} | 4 ++-- tests/unit/exam/service.spec.ts | 4 ++-- 2 files changed, 4 insertions(+), 4 deletions(-) rename src/services/{exams.ts => apiExams.ts} (83%) diff --git a/src/services/exams.ts b/src/services/apiExams.ts similarity index 83% rename from src/services/exams.ts rename to src/services/apiExams.ts index 6d1ab94..cb28a8d 100644 --- a/src/services/exams.ts +++ b/src/services/apiExams.ts @@ -1,10 +1,10 @@ import axios from 'axios' -class ExamsService { +class ApiExamsService { static async list(): Promise { let response = await axios.get('http://www.mocky.io/v2/5d681ede33000054e7e65c3f') return response.data.map( ({ id, name }: { id: Number, name: String}) => ({ id, name })) } } -export default ExamsService \ No newline at end of file +export default ApiExamsService \ No newline at end of file diff --git a/tests/unit/exam/service.spec.ts b/tests/unit/exam/service.spec.ts index 3891299..74db382 100644 --- a/tests/unit/exam/service.spec.ts +++ b/tests/unit/exam/service.spec.ts @@ -1,5 +1,5 @@ import axios from 'axios' -import ExamsService from '../../../src/services/exams' +import ApiExamsService from '../../../src/services/apiExams' jest.mock('axios') const mockedAxios = axios as jest.Mocked @@ -19,6 +19,6 @@ test('should return exam list', () => { mockedAxios.get.mockResolvedValue({ data: exams }) - return ExamsService.list().then( data => expect(data).toEqual(expected)) + return ApiExamsService.list().then( data => expect(data).toEqual(expected)) }) From f371eb52ebb17f9f8c89fb7080864a0d12dc0cde Mon Sep 17 00:00:00 2001 From: Luiz Filho Date: Sat, 21 Sep 2019 12:14:39 -0300 Subject: [PATCH 15/65] replace of axios with request --- package.json | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/package.json b/package.json index 836b625..ca897bd 100644 --- a/package.json +++ b/package.json @@ -28,9 +28,10 @@ "typescript": "^3.6.3" }, "dependencies": { + "@types/request-promise-native": "^1.0.16", "@types/swagger-ui-express": "^3.0.1", - "axios": "^0.19.0", "express": "^4.17.1", + "request-promise-native": "^1.0.7", "swagger-ui-express": "^4.1.1" } } From 13267424ced66de39dcbd8621006498a7aa5e5ec Mon Sep 17 00:00:00 2001 From: Luiz Filho Date: Sat, 21 Sep 2019 12:16:31 -0300 Subject: [PATCH 16/65] exam listing route completed --- src/app.ts | 2 +- src/helpers/formatter.ts | 7 +++++++ src/http/controllers/examController.ts | 13 +++++++++++++ src/http/controllers/index.ts | 1 + src/routes/exam.ts | 8 ++++++++ src/routes/index.ts | 10 +--------- src/services/apiExams.ts | 7 +++---- 7 files changed, 34 insertions(+), 14 deletions(-) create mode 100644 src/helpers/formatter.ts create mode 100644 src/http/controllers/examController.ts create mode 100644 src/http/controllers/index.ts create mode 100644 src/routes/exam.ts diff --git a/src/app.ts b/src/app.ts index 6ab37d5..8dac438 100644 --- a/src/app.ts +++ b/src/app.ts @@ -1,6 +1,6 @@ import express from 'express' import swaggerUi from 'swagger-ui-express' -import routes from './routes' +import routes from './routes/exam' import * as swaggerDocument from '../swagger.json' class App { diff --git a/src/helpers/formatter.ts b/src/helpers/formatter.ts new file mode 100644 index 0000000..60bbc59 --- /dev/null +++ b/src/helpers/formatter.ts @@ -0,0 +1,7 @@ +class Formatter { + public static extractFields(data: []) { + return data.map(({ id, name }: { id: Number, name: String}) => ({ id, name })) + } +} + +export default Formatter \ No newline at end of file diff --git a/src/http/controllers/examController.ts b/src/http/controllers/examController.ts new file mode 100644 index 0000000..0f6859e --- /dev/null +++ b/src/http/controllers/examController.ts @@ -0,0 +1,13 @@ +import { Request, Response } from 'express' +import apiExam from '../../services/apiExams' +import formatter from '../../helpers/formatter' + +class ExamController { + public async list(request: Request, response: Response): Promise { + const exams = await apiExam.list() + const responseFormatted = formatter.extractFields(JSON.parse(exams.toString()).exams) + return response.send(responseFormatted) + } +} + +export default new ExamController() \ No newline at end of file diff --git a/src/http/controllers/index.ts b/src/http/controllers/index.ts new file mode 100644 index 0000000..e98aaf6 --- /dev/null +++ b/src/http/controllers/index.ts @@ -0,0 +1 @@ +export * from './examController' diff --git a/src/routes/exam.ts b/src/routes/exam.ts new file mode 100644 index 0000000..b9a61b5 --- /dev/null +++ b/src/routes/exam.ts @@ -0,0 +1,8 @@ +import { Router } from 'express' + +const routes = Router() +import ExamController from '../http/controllers/examController' + +routes.get('/exams', ExamController.list) + +export default routes \ No newline at end of file diff --git a/src/routes/index.ts b/src/routes/index.ts index 4efcb60..a3250fc 100644 --- a/src/routes/index.ts +++ b/src/routes/index.ts @@ -1,9 +1 @@ -import { Router } from 'express' - -const routes = Router() - -routes.get('/', (request, response) => { - response.send({ message: 'Welcome' }) -}) - -export default routes \ No newline at end of file +export * from './exam' \ No newline at end of file diff --git a/src/services/apiExams.ts b/src/services/apiExams.ts index cb28a8d..c90836f 100644 --- a/src/services/apiExams.ts +++ b/src/services/apiExams.ts @@ -1,9 +1,8 @@ -import axios from 'axios' +import request from 'request-promise-native' class ApiExamsService { - static async list(): Promise { - let response = await axios.get('http://www.mocky.io/v2/5d681ede33000054e7e65c3f') - return response.data.map( ({ id, name }: { id: Number, name: String}) => ({ id, name })) + static async list(): Promise { + return await request.get('http://www.mocky.io/v2/5d681ede33000054e7e65c3f') } } From 06ce7a5798f64f8d7e2a798b1f40512115712264 Mon Sep 17 00:00:00 2001 From: Luiz Filho Date: Sat, 21 Sep 2019 13:22:39 -0300 Subject: [PATCH 17/65] add simulated database in memory --- data/db.ts | 29 +++++++++++++++++++++++++++++ 1 file changed, 29 insertions(+) create mode 100644 data/db.ts diff --git a/data/db.ts b/data/db.ts new file mode 100644 index 0000000..e5d600c --- /dev/null +++ b/data/db.ts @@ -0,0 +1,29 @@ +class DB { + private static collection: DB + private static customer: Array + private static schedule: Array + + private constructor() { + DB.customer = [] + DB.schedule = [] + } + + public static connection(): Object { + if (!DB.collection) { + DB.collection = new DB() + } + return DB.collection + } + + public addCustomer(data: any) { + DB.customer.push(data) + return DB.customer.find( item => item.cpf === data.cpf) + } + + public addSchedule(data: any) { + DB.schedule.push(data) + return DB.schedule.find( item => item.cpf == data.cpf ) + } +} + +export default DB \ No newline at end of file From f2c825c6647a33afe2caa389fbab64cb8f125cc4 Mon Sep 17 00:00:00 2001 From: Luiz Filho Date: Sat, 21 Sep 2019 14:06:14 -0300 Subject: [PATCH 18/65] unit test database connection --- data/db.ts | 14 +++++++++----- tests/unit/exam/service.spec.ts | 14 ++++++++++++++ 2 files changed, 23 insertions(+), 5 deletions(-) diff --git a/data/db.ts b/data/db.ts index e5d600c..67c9276 100644 --- a/data/db.ts +++ b/data/db.ts @@ -1,5 +1,5 @@ class DB { - private static collection: DB + private static instance: DB private static customer: Array private static schedule: Array @@ -8,11 +8,15 @@ class DB { DB.schedule = [] } - public static connection(): Object { - if (!DB.collection) { - DB.collection = new DB() + public static connection(): DB { + if (!DB.instance) { + DB.instance = new DB() } - return DB.collection + return DB.instance + } + + public getCustomer(cpf: String) { + return DB.customer.find( item => item.cpf === cpf) } public addCustomer(data: any) { diff --git a/tests/unit/exam/service.spec.ts b/tests/unit/exam/service.spec.ts index 74db382..25d0233 100644 --- a/tests/unit/exam/service.spec.ts +++ b/tests/unit/exam/service.spec.ts @@ -1,5 +1,6 @@ import axios from 'axios' import ApiExamsService from '../../../src/services/apiExams' +import database from '../../../data/db' jest.mock('axios') const mockedAxios = axios as jest.Mocked @@ -22,3 +23,16 @@ test('should return exam list', () => { return ApiExamsService.list().then( data => expect(data).toEqual(expected)) }) + +test('should save a client to the database', () => { + const connection = database.connection() + const customer = { + name: 'Luiz Filho', + cpf: '383383383-44' + } + + const customerStored = connection.addCustomer(customer) + const otherConnection = database.connection() + const searched = otherConnection.getCustomer(customer.cpf) + expect(customer).toEqual(searched) +}) From 58d76671ec18534bc66e7da1eea2d339fb5430a6 Mon Sep 17 00:00:00 2001 From: Luiz Filho Date: Sat, 21 Sep 2019 14:09:27 -0300 Subject: [PATCH 19/65] division unit test files --- tests/unit/exam/{service.spec.ts => api.spec.ts} | 16 +--------------- tests/unit/exam/database.spec.ts | 14 ++++++++++++++ 2 files changed, 15 insertions(+), 15 deletions(-) rename tests/unit/exam/{service.spec.ts => api.spec.ts} (60%) create mode 100644 tests/unit/exam/database.spec.ts diff --git a/tests/unit/exam/service.spec.ts b/tests/unit/exam/api.spec.ts similarity index 60% rename from tests/unit/exam/service.spec.ts rename to tests/unit/exam/api.spec.ts index 25d0233..e2b7d37 100644 --- a/tests/unit/exam/service.spec.ts +++ b/tests/unit/exam/api.spec.ts @@ -1,6 +1,5 @@ import axios from 'axios' import ApiExamsService from '../../../src/services/apiExams' -import database from '../../../data/db' jest.mock('axios') const mockedAxios = axios as jest.Mocked @@ -22,17 +21,4 @@ test('should return exam list', () => { return ApiExamsService.list().then( data => expect(data).toEqual(expected)) -}) - -test('should save a client to the database', () => { - const connection = database.connection() - const customer = { - name: 'Luiz Filho', - cpf: '383383383-44' - } - - const customerStored = connection.addCustomer(customer) - const otherConnection = database.connection() - const searched = otherConnection.getCustomer(customer.cpf) - expect(customer).toEqual(searched) -}) +}) \ No newline at end of file diff --git a/tests/unit/exam/database.spec.ts b/tests/unit/exam/database.spec.ts new file mode 100644 index 0000000..55e6767 --- /dev/null +++ b/tests/unit/exam/database.spec.ts @@ -0,0 +1,14 @@ +import database from '../../../data/db' + +test('should save a client to the database', () => { + const connection = database.connection() + const customer = { + name: 'Luiz Filho', + cpf: '383383383-44' + } + + const customerStored = connection.addCustomer(customer) + const otherConnection = database.connection() + const searched = otherConnection.getCustomer(customer.cpf) + expect(customer).toEqual(searched) +}) From cdae307d9feafc0c81db081a04fd96d44a680ccb Mon Sep 17 00:00:00 2001 From: Luiz Filho Date: Sat, 21 Sep 2019 14:10:39 -0300 Subject: [PATCH 20/65] adjustoment unit test database --- tests/unit/exam/database.spec.ts | 1 + 1 file changed, 1 insertion(+) diff --git a/tests/unit/exam/database.spec.ts b/tests/unit/exam/database.spec.ts index 55e6767..cd9334b 100644 --- a/tests/unit/exam/database.spec.ts +++ b/tests/unit/exam/database.spec.ts @@ -11,4 +11,5 @@ test('should save a client to the database', () => { const otherConnection = database.connection() const searched = otherConnection.getCustomer(customer.cpf) expect(customer).toEqual(searched) + expect(customerStored).toEqual(searched) }) From 42b8e74aabb424230b118c161f55453fa82908ad Mon Sep 17 00:00:00 2001 From: Luiz Filho Date: Sat, 21 Sep 2019 14:27:27 -0300 Subject: [PATCH 21/65] added service to save customer and unit test --- src/services/customer.ts | 15 +++++++++++++++ tests/unit/exam/customer.spec.ts | 13 +++++++++++++ 2 files changed, 28 insertions(+) create mode 100644 src/services/customer.ts create mode 100644 tests/unit/exam/customer.spec.ts diff --git a/src/services/customer.ts b/src/services/customer.ts new file mode 100644 index 0000000..ab952c1 --- /dev/null +++ b/src/services/customer.ts @@ -0,0 +1,15 @@ +import DB from '../../data/db' + +class CustomerService { + private connection: DB + + public constructor () { + this.connection = DB.connection() + } + + public save(data:Object) { + return this.connection.addCustomer(data) + } +} + +export default CustomerService \ No newline at end of file diff --git a/tests/unit/exam/customer.spec.ts b/tests/unit/exam/customer.spec.ts new file mode 100644 index 0000000..bd98771 --- /dev/null +++ b/tests/unit/exam/customer.spec.ts @@ -0,0 +1,13 @@ +import CustomerService from '../../../src/services/customer' + + +test('should save a client to the database by service', () => { + const customer = { + name: 'Luiz Filho', + cpf: '464444466-44' + } + const service = new CustomerService() + const customerStored = service.save(customer) + + expect(customer).toEqual(customerStored) +}) \ No newline at end of file From e74281a413313f6a373a44772eb1ed8fefb86093 Mon Sep 17 00:00:00 2001 From: Luiz Filho Date: Sat, 21 Sep 2019 15:29:37 -0300 Subject: [PATCH 22/65] added customer save route --- src/app.ts | 10 ++++++++-- src/http/controllers/customerController.ts | 18 ++++++++++++++++++ src/http/controllers/index.ts | 1 + src/routes/customer.ts | 8 ++++++++ src/routes/exam.ts | 6 +++--- src/routes/index.ts | 3 ++- 6 files changed, 40 insertions(+), 6 deletions(-) create mode 100644 src/http/controllers/customerController.ts create mode 100644 src/routes/customer.ts diff --git a/src/app.ts b/src/app.ts index 8dac438..5465489 100644 --- a/src/app.ts +++ b/src/app.ts @@ -1,6 +1,6 @@ import express from 'express' import swaggerUi from 'swagger-ui-express' -import routes from './routes/exam' +import { CustomerRoutes, ExamRoutes } from './routes/index' import * as swaggerDocument from '../swagger.json' class App { @@ -8,12 +8,18 @@ class App { public constructor () { this.express = express() + this.middlwares() this.routes() this.swagger() } private routes (): void { - this.express.use(routes) + this.express.use(CustomerRoutes) + this.express.use(ExamRoutes) + } + + private middlwares (): void { + this.express.use(express.json()) } private swagger (): void { diff --git a/src/http/controllers/customerController.ts b/src/http/controllers/customerController.ts new file mode 100644 index 0000000..6574b6f --- /dev/null +++ b/src/http/controllers/customerController.ts @@ -0,0 +1,18 @@ +import { Request, Response } from 'express' +import CustomerService from '../../services/customer' + +class CustomerController { + private service: CustomerService + + public constructor () { + this.service = new CustomerService() + this.save = this.save.bind(this) + } + + public save(request: Request, response: Response) { + const result = this.service.save(request.body) + response.send(result) + } +} + +export default CustomerController \ No newline at end of file diff --git a/src/http/controllers/index.ts b/src/http/controllers/index.ts index e98aaf6..98ceca2 100644 --- a/src/http/controllers/index.ts +++ b/src/http/controllers/index.ts @@ -1 +1,2 @@ export * from './examController' +export * from './customerController' diff --git a/src/routes/customer.ts b/src/routes/customer.ts new file mode 100644 index 0000000..959753d --- /dev/null +++ b/src/routes/customer.ts @@ -0,0 +1,8 @@ +import { Router } from 'express' +import CustomerController from '../http/controllers/customerController' + +const CustomerRoutes = Router() +const controller = new CustomerController() +CustomerRoutes.post('/customers', controller.save) + +export { CustomerRoutes } \ No newline at end of file diff --git a/src/routes/exam.ts b/src/routes/exam.ts index b9a61b5..b14f2a1 100644 --- a/src/routes/exam.ts +++ b/src/routes/exam.ts @@ -1,8 +1,8 @@ import { Router } from 'express' -const routes = Router() +const ExamRoutes = Router() import ExamController from '../http/controllers/examController' -routes.get('/exams', ExamController.list) +ExamRoutes.get('/exams', ExamController.list) -export default routes \ No newline at end of file +export { ExamRoutes } \ No newline at end of file diff --git a/src/routes/index.ts b/src/routes/index.ts index a3250fc..1cef95b 100644 --- a/src/routes/index.ts +++ b/src/routes/index.ts @@ -1 +1,2 @@ -export * from './exam' \ No newline at end of file +export * from './exam' +export * from './customer' \ No newline at end of file From 696f23993150d371d41ef0ccf1cc86f86ed5d48c Mon Sep 17 00:00:00 2001 From: Luiz Filho Date: Sat, 21 Sep 2019 16:04:36 -0300 Subject: [PATCH 23/65] handling for cpf already exists unit test --- data/db.ts | 4 ++-- src/http/controllers/customerController.ts | 3 +++ src/services/customer.ts | 2 +- src/services/index.spec.ts | 3 --- tests/unit/exam/customer.spec.ts | 21 +++++++++++++++++++-- 5 files changed, 25 insertions(+), 8 deletions(-) delete mode 100644 src/services/index.spec.ts diff --git a/data/db.ts b/data/db.ts index 67c9276..26e0e13 100644 --- a/data/db.ts +++ b/data/db.ts @@ -20,8 +20,8 @@ class DB { } public addCustomer(data: any) { - DB.customer.push(data) - return DB.customer.find( item => item.cpf === data.cpf) + !DB.customer.find(item => item.cpf === data.cpf) ? DB.customer.push(data) : null + return DB.customer.find( item => item.cpf === data.cpf && item.name === data.name) || null } public addSchedule(data: any) { diff --git a/src/http/controllers/customerController.ts b/src/http/controllers/customerController.ts index 6574b6f..d34fb30 100644 --- a/src/http/controllers/customerController.ts +++ b/src/http/controllers/customerController.ts @@ -11,6 +11,9 @@ class CustomerController { public save(request: Request, response: Response) { const result = this.service.save(request.body) + if (!result) { + response.status(409) + } response.send(result) } } diff --git a/src/services/customer.ts b/src/services/customer.ts index ab952c1..9b5775a 100644 --- a/src/services/customer.ts +++ b/src/services/customer.ts @@ -7,7 +7,7 @@ class CustomerService { this.connection = DB.connection() } - public save(data:Object) { + public save(data: any) { return this.connection.addCustomer(data) } } diff --git a/src/services/index.spec.ts b/src/services/index.spec.ts deleted file mode 100644 index 5eded20..0000000 --- a/src/services/index.spec.ts +++ /dev/null @@ -1,3 +0,0 @@ -test('should return true', () => { - expect(true).toBe(true) -}) \ No newline at end of file diff --git a/tests/unit/exam/customer.spec.ts b/tests/unit/exam/customer.spec.ts index bd98771..211e756 100644 --- a/tests/unit/exam/customer.spec.ts +++ b/tests/unit/exam/customer.spec.ts @@ -2,12 +2,29 @@ import CustomerService from '../../../src/services/customer' test('should save a client to the database by service', () => { + const customer = { name: 'Luiz Filho', cpf: '464444466-44' } + const service = new CustomerService() const customerStored = service.save(customer) - expect(customer).toEqual(customerStored) -}) \ No newline at end of file +}) + +test('should return null and not save a client', () => { + + const customer = { + name: 'Luiz Filho', + cpf: '464444466-44' + } + + const service = new CustomerService() + service.save(customer) + + const otherService = new CustomerService() + const responseOtherService = otherService.save({ ...customer, name: 'João' }) + + expect(responseOtherService).toEqual(null) +}) From 3439ec13f38317ba672fc808313a16b335626877 Mon Sep 17 00:00:00 2001 From: Luiz Filho Date: Sat, 21 Sep 2019 16:28:15 -0300 Subject: [PATCH 24/65] adjustment response db and save route --- data/db.ts | 10 ++++++++-- src/http/controllers/customerController.ts | 7 ++++--- tests/unit/exam/customer.spec.ts | 4 ++-- tests/unit/exam/database.spec.ts | 2 +- 4 files changed, 15 insertions(+), 8 deletions(-) diff --git a/data/db.ts b/data/db.ts index 26e0e13..c4bd7bc 100644 --- a/data/db.ts +++ b/data/db.ts @@ -20,8 +20,14 @@ class DB { } public addCustomer(data: any) { - !DB.customer.find(item => item.cpf === data.cpf) ? DB.customer.push(data) : null - return DB.customer.find( item => item.cpf === data.cpf && item.name === data.name) || null + + let result = !DB.customer.find(item => item.cpf === data.cpf) ? DB.customer.push(data) : null + + return { + success: result ? true: false, + data: DB.customer.find( item => item.cpf === data.cpf && item.name === data.name) || null, + message: result ? 'item successfully saved' : 'item already exists' + } } public addSchedule(data: any) { diff --git a/src/http/controllers/customerController.ts b/src/http/controllers/customerController.ts index d34fb30..22359d5 100644 --- a/src/http/controllers/customerController.ts +++ b/src/http/controllers/customerController.ts @@ -10,11 +10,12 @@ class CustomerController { } public save(request: Request, response: Response) { - const result = this.service.save(request.body) - if (!result) { + const customer = this.service.save(request.body) + + if (!customer.success) { response.status(409) } - response.send(result) + response.send(customer) } } diff --git a/tests/unit/exam/customer.spec.ts b/tests/unit/exam/customer.spec.ts index 211e756..6212996 100644 --- a/tests/unit/exam/customer.spec.ts +++ b/tests/unit/exam/customer.spec.ts @@ -10,7 +10,7 @@ test('should save a client to the database by service', () => { const service = new CustomerService() const customerStored = service.save(customer) - expect(customer).toEqual(customerStored) + expect(customer).toEqual(customerStored.data) }) test('should return null and not save a client', () => { @@ -26,5 +26,5 @@ test('should return null and not save a client', () => { const otherService = new CustomerService() const responseOtherService = otherService.save({ ...customer, name: 'João' }) - expect(responseOtherService).toEqual(null) + expect(responseOtherService.success).toEqual(false) }) diff --git a/tests/unit/exam/database.spec.ts b/tests/unit/exam/database.spec.ts index cd9334b..e0a8482 100644 --- a/tests/unit/exam/database.spec.ts +++ b/tests/unit/exam/database.spec.ts @@ -11,5 +11,5 @@ test('should save a client to the database', () => { const otherConnection = database.connection() const searched = otherConnection.getCustomer(customer.cpf) expect(customer).toEqual(searched) - expect(customerStored).toEqual(searched) + expect(customerStored.data).toEqual(searched) }) From d2bc07adceeb994b048e1b56498a755d510eb14b Mon Sep 17 00:00:00 2001 From: Luiz Filho Date: Sat, 21 Sep 2019 17:13:21 -0300 Subject: [PATCH 25/65] added service and unit test update customer --- data/db.ts | 13 ++++++++++++ src/services/customer.ts | 4 ++++ tests/unit/exam/customer.spec.ts | 34 ++++++++++++++++++++++++++++++-- 3 files changed, 49 insertions(+), 2 deletions(-) diff --git a/data/db.ts b/data/db.ts index c4bd7bc..3afa94d 100644 --- a/data/db.ts +++ b/data/db.ts @@ -30,6 +30,19 @@ class DB { } } + public updateCustomer(data: any) { + let customerIndex = DB.customer.findIndex( item => item.cpf === data.cpf ) + if (customerIndex > -1) { + DB.customer[customerIndex] = data + } + + return { + success: customerIndex > -1 ? true: false, + data: DB.customer.find( item => item.cpf === data.cpf ) || null, + message: customerIndex > -1 ? 'item successfully saved' : 'item already exists' + } + } + public addSchedule(data: any) { DB.schedule.push(data) return DB.schedule.find( item => item.cpf == data.cpf ) diff --git a/src/services/customer.ts b/src/services/customer.ts index 9b5775a..5c093e1 100644 --- a/src/services/customer.ts +++ b/src/services/customer.ts @@ -10,6 +10,10 @@ class CustomerService { public save(data: any) { return this.connection.addCustomer(data) } + + public update(data: {cpf: String, name: String}): any { + return this.connection.updateCustomer(data) + } } export default CustomerService \ No newline at end of file diff --git a/tests/unit/exam/customer.spec.ts b/tests/unit/exam/customer.spec.ts index 6212996..41c9240 100644 --- a/tests/unit/exam/customer.spec.ts +++ b/tests/unit/exam/customer.spec.ts @@ -1,7 +1,7 @@ import CustomerService from '../../../src/services/customer' -test('should save a client to the database by service', () => { +test('should save a customer to the database by service', () => { const customer = { name: 'Luiz Filho', @@ -13,7 +13,7 @@ test('should save a client to the database by service', () => { expect(customer).toEqual(customerStored.data) }) -test('should return null and not save a client', () => { +test('should not save a customer', () => { const customer = { name: 'Luiz Filho', @@ -28,3 +28,33 @@ test('should return null and not save a client', () => { expect(responseOtherService.success).toEqual(false) }) + +test('should update a customer to the database by service', () => { + + let customer = { + name: 'Luiz Filho', + cpf: '464444466-44' + } + + const service = new CustomerService() + service.save(customer) + customer = { ...customer, name: 'João Pereira'} + const customerUpdated = service.update(customer) + + expect(customerUpdated.data).toEqual(customer) +}) + +test('should not update a customer', () => { + + let customer = { + name: 'Luiz Filho', + cpf: '464444466-44' + } + + const service = new CustomerService() + service.save(customer) + customer = { cpf: '464444466-46', name: 'João Pereira'} + const customerUpdated = service.update(customer) + + expect(customerUpdated.success).toEqual(false) +}) From 5f1fee544d5d5d856db65c370ee4de34419942ea Mon Sep 17 00:00:00 2001 From: Luiz Filho Date: Sat, 21 Sep 2019 17:22:24 -0300 Subject: [PATCH 26/65] added route update customer --- data/db.ts | 2 +- src/http/controllers/customerController.ts | 10 ++++++++++ src/routes/customer.ts | 1 + 3 files changed, 12 insertions(+), 1 deletion(-) diff --git a/data/db.ts b/data/db.ts index 3afa94d..a4a5a1d 100644 --- a/data/db.ts +++ b/data/db.ts @@ -39,7 +39,7 @@ class DB { return { success: customerIndex > -1 ? true: false, data: DB.customer.find( item => item.cpf === data.cpf ) || null, - message: customerIndex > -1 ? 'item successfully saved' : 'item already exists' + message: customerIndex > -1 ? 'item successfully updated' : 'item not found' } } diff --git a/src/http/controllers/customerController.ts b/src/http/controllers/customerController.ts index 22359d5..673542f 100644 --- a/src/http/controllers/customerController.ts +++ b/src/http/controllers/customerController.ts @@ -7,6 +7,7 @@ class CustomerController { public constructor () { this.service = new CustomerService() this.save = this.save.bind(this) + this.update = this.update.bind(this) } public save(request: Request, response: Response) { @@ -17,6 +18,15 @@ class CustomerController { } response.send(customer) } + + public update(request: Request, response: Response) { + const customer = this.service.update(request.body) + + if (!customer.success) { + response.status(404) + } + response.send(customer) + } } export default CustomerController \ No newline at end of file diff --git a/src/routes/customer.ts b/src/routes/customer.ts index 959753d..5ee87b2 100644 --- a/src/routes/customer.ts +++ b/src/routes/customer.ts @@ -4,5 +4,6 @@ import CustomerController from '../http/controllers/customerController' const CustomerRoutes = Router() const controller = new CustomerController() CustomerRoutes.post('/customers', controller.save) +CustomerRoutes.put('/customers', controller.update) export { CustomerRoutes } \ No newline at end of file From 318bf9f4d9a57f77b2b8dfc5418940b783526c56 Mon Sep 17 00:00:00 2001 From: Luiz Filho Date: Sat, 21 Sep 2019 17:56:41 -0300 Subject: [PATCH 27/65] added remove route customer --- data/db.ts | 15 +++++-- src/http/controllers/customerController.ts | 10 +++++ src/routes/customer.ts | 1 + src/services/customer.ts | 4 ++ tests/unit/exam/customer.spec.ts | 47 ++++++++++++++++++---- 5 files changed, 66 insertions(+), 11 deletions(-) diff --git a/data/db.ts b/data/db.ts index a4a5a1d..a5f8e4f 100644 --- a/data/db.ts +++ b/data/db.ts @@ -43,9 +43,18 @@ class DB { } } - public addSchedule(data: any) { - DB.schedule.push(data) - return DB.schedule.find( item => item.cpf == data.cpf ) + public removeCustomer(cpf: String): any { + let customer = DB.customer.find( item => item.cpf === cpf ) + console.log(customer) + if (customer) { + DB.customer = DB.customer.filter( item => item.cpf !== cpf) + } + + return { + success: customer ? true: false, + data: customer || null, + message: customer ? 'item successfully removed' : 'item not found' + } } } diff --git a/src/http/controllers/customerController.ts b/src/http/controllers/customerController.ts index 673542f..56be8e0 100644 --- a/src/http/controllers/customerController.ts +++ b/src/http/controllers/customerController.ts @@ -8,6 +8,7 @@ class CustomerController { this.service = new CustomerService() this.save = this.save.bind(this) this.update = this.update.bind(this) + this.remove = this.remove.bind(this) } public save(request: Request, response: Response) { @@ -27,6 +28,15 @@ class CustomerController { } response.send(customer) } + + public remove(request: Request, response: Response) { + const customer = this.service.remove(request.params.cpf) + + if (!customer.success) { + response.status(404) + } + response.send(customer) + } } export default CustomerController \ No newline at end of file diff --git a/src/routes/customer.ts b/src/routes/customer.ts index 5ee87b2..831b6f5 100644 --- a/src/routes/customer.ts +++ b/src/routes/customer.ts @@ -5,5 +5,6 @@ const CustomerRoutes = Router() const controller = new CustomerController() CustomerRoutes.post('/customers', controller.save) CustomerRoutes.put('/customers', controller.update) +CustomerRoutes.delete('/customers/:cpf', controller.remove) export { CustomerRoutes } \ No newline at end of file diff --git a/src/services/customer.ts b/src/services/customer.ts index 5c093e1..1ecfe3f 100644 --- a/src/services/customer.ts +++ b/src/services/customer.ts @@ -14,6 +14,10 @@ class CustomerService { public update(data: {cpf: String, name: String}): any { return this.connection.updateCustomer(data) } + + public remove(cpf: String): any { + return this.connection.removeCustomer(cpf) + } } export default CustomerService \ No newline at end of file diff --git a/tests/unit/exam/customer.spec.ts b/tests/unit/exam/customer.spec.ts index 41c9240..bcf0e7f 100644 --- a/tests/unit/exam/customer.spec.ts +++ b/tests/unit/exam/customer.spec.ts @@ -1,4 +1,5 @@ import CustomerService from '../../../src/services/customer' +import { cursorTo } from 'readline' test('should save a customer to the database by service', () => { @@ -16,15 +17,15 @@ test('should save a customer to the database by service', () => { test('should not save a customer', () => { const customer = { - name: 'Luiz Filho', - cpf: '464444466-44' + name: 'Luiz Carlos', + cpf: '888555333-44' } const service = new CustomerService() service.save(customer) const otherService = new CustomerService() - const responseOtherService = otherService.save({ ...customer, name: 'João' }) + const responseOtherService = otherService.save({ ...customer, name: 'João Silva' }) expect(responseOtherService.success).toEqual(false) }) @@ -32,13 +33,13 @@ test('should not save a customer', () => { test('should update a customer to the database by service', () => { let customer = { - name: 'Luiz Filho', - cpf: '464444466-44' + name: 'Nathalia Souza', + cpf: '961965000-44' } const service = new CustomerService() service.save(customer) - customer = { ...customer, name: 'João Pereira'} + customer = { ...customer, name: 'Geisiane Pereira'} const customerUpdated = service.update(customer) expect(customerUpdated.data).toEqual(customer) @@ -47,14 +48,44 @@ test('should update a customer to the database by service', () => { test('should not update a customer', () => { let customer = { - name: 'Luiz Filho', + name: 'Hamilton Vicente', cpf: '464444466-44' } const service = new CustomerService() service.save(customer) - customer = { cpf: '464444466-46', name: 'João Pereira'} + customer = { cpf: '333161615-46', name: 'João Rodrigues'} const customerUpdated = service.update(customer) expect(customerUpdated.success).toEqual(false) }) + +test('should remove a customer to the database by service', () => { + + let customer = { + name: 'Fernanda Pereira', + cpf: '464999966-44' + } + + const service = new CustomerService() + service.save(customer) + const customerRemoved = service.remove(customer.cpf) + + expect(customerRemoved.success).toEqual(true) + expect(customerRemoved.data).toEqual(customer) +}) + +test('should not delete a customer', () => { + + let customer = { + name: 'Luiz Filho', + cpf: '464444466-44' + } + + const service = new CustomerService() + service.save(customer) + customer = { ...customer, cpf: '111222333-44' } + const customerRemoved = service.remove(customer.cpf) + + expect(customerRemoved.success).toEqual(false) +}) From ed11fa225faf510737f53f5fd1c56f8b52e8f188 Mon Sep 17 00:00:00 2001 From: Luiz Filho Date: Sat, 21 Sep 2019 18:33:27 -0300 Subject: [PATCH 28/65] added service find customer by cpf and unit test --- data/db.ts | 11 ++++++++--- src/services/customer.ts | 4 ++++ tests/unit/exam/customer.spec.ts | 31 +++++++++++++++++++++++++++++++ tests/unit/exam/database.spec.ts | 6 +++--- 4 files changed, 46 insertions(+), 6 deletions(-) diff --git a/data/db.ts b/data/db.ts index a5f8e4f..9d09728 100644 --- a/data/db.ts +++ b/data/db.ts @@ -15,8 +15,13 @@ class DB { return DB.instance } - public getCustomer(cpf: String) { - return DB.customer.find( item => item.cpf === cpf) + public findCustomer(cpf: String) { + const customer = DB.customer.find( item => item.cpf === cpf) + return { + success: customer ? true: false, + data: customer || null, + message: customer ? 'item successfully find' : 'item not found' + } } public addCustomer(data: any) { @@ -45,7 +50,7 @@ class DB { public removeCustomer(cpf: String): any { let customer = DB.customer.find( item => item.cpf === cpf ) - console.log(customer) + if (customer) { DB.customer = DB.customer.filter( item => item.cpf !== cpf) } diff --git a/src/services/customer.ts b/src/services/customer.ts index 1ecfe3f..bbe0d60 100644 --- a/src/services/customer.ts +++ b/src/services/customer.ts @@ -18,6 +18,10 @@ class CustomerService { public remove(cpf: String): any { return this.connection.removeCustomer(cpf) } + + public find(cpf: String): any { + return this.connection.findCustomer(cpf) + } } export default CustomerService \ No newline at end of file diff --git a/tests/unit/exam/customer.spec.ts b/tests/unit/exam/customer.spec.ts index bcf0e7f..336f5eb 100644 --- a/tests/unit/exam/customer.spec.ts +++ b/tests/unit/exam/customer.spec.ts @@ -89,3 +89,34 @@ test('should not delete a customer', () => { expect(customerRemoved.success).toEqual(false) }) + +test('should be returned a customer by cpf', () => { + + const customer = { + name: 'Giovanni Santos', + cpf: '101010101-10' + } + + const service = new CustomerService() + service.save(customer) + const customerSeached = service.find(customer.cpf) + + expect(customerSeached.success).toEqual(true) + expect(customerSeached.data).toEqual(customer) +}) + +test('should not return a customer by cpf', () => { + + const customer = { + name: 'Giovanni Santos', + cpf: '101010101-10' + } + + const service = new CustomerService() + service.save(customer) + customer.cpf = '121121121-12' + const customerSeached = service.find(customer.cpf) + + expect(customerSeached.success).toEqual(false) + expect(customerSeached.data).toEqual(null) +}) diff --git a/tests/unit/exam/database.spec.ts b/tests/unit/exam/database.spec.ts index e0a8482..e81405e 100644 --- a/tests/unit/exam/database.spec.ts +++ b/tests/unit/exam/database.spec.ts @@ -9,7 +9,7 @@ test('should save a client to the database', () => { const customerStored = connection.addCustomer(customer) const otherConnection = database.connection() - const searched = otherConnection.getCustomer(customer.cpf) - expect(customer).toEqual(searched) - expect(customerStored.data).toEqual(searched) + const searched = otherConnection.findCustomer(customer.cpf) + expect(customer).toEqual(searched.data) + expect(customerStored.data).toEqual(searched.data) }) From 789c024a6e5f5e912d7f87a5ecff7e8fca194dcc Mon Sep 17 00:00:00 2001 From: Luiz Filho Date: Sat, 21 Sep 2019 18:43:52 -0300 Subject: [PATCH 29/65] added customer find route --- src/http/controllers/customerController.ts | 10 ++++++++++ src/routes/customer.ts | 1 + 2 files changed, 11 insertions(+) diff --git a/src/http/controllers/customerController.ts b/src/http/controllers/customerController.ts index 56be8e0..47555af 100644 --- a/src/http/controllers/customerController.ts +++ b/src/http/controllers/customerController.ts @@ -9,6 +9,7 @@ class CustomerController { this.save = this.save.bind(this) this.update = this.update.bind(this) this.remove = this.remove.bind(this) + this.find = this.find.bind(this) } public save(request: Request, response: Response) { @@ -32,6 +33,15 @@ class CustomerController { public remove(request: Request, response: Response) { const customer = this.service.remove(request.params.cpf) + if (!customer.success) { + response.status(409) + } + response.send(customer) + } + + public find(request: Request, response: Response) { + const customer = this.service.find(request.params.cpf) + if (!customer.success) { response.status(404) } diff --git a/src/routes/customer.ts b/src/routes/customer.ts index 831b6f5..80d268c 100644 --- a/src/routes/customer.ts +++ b/src/routes/customer.ts @@ -6,5 +6,6 @@ const controller = new CustomerController() CustomerRoutes.post('/customers', controller.save) CustomerRoutes.put('/customers', controller.update) CustomerRoutes.delete('/customers/:cpf', controller.remove) +CustomerRoutes.get('/customers/:cpf', controller.find) export { CustomerRoutes } \ No newline at end of file From f8b969ef537391fab7bd99c4ccec514124c16169 Mon Sep 17 00:00:00 2001 From: Luiz Filho Date: Sat, 21 Sep 2019 19:55:43 -0300 Subject: [PATCH 30/65] added list route --- data/db.ts | 37 +++++++++++++++++++++++++------------ package.json | 2 ++ src/services/customer.ts | 6 +++++- 3 files changed, 32 insertions(+), 13 deletions(-) diff --git a/data/db.ts b/data/db.ts index 9d09728..b61a60c 100644 --- a/data/db.ts +++ b/data/db.ts @@ -1,11 +1,11 @@ class DB { private static instance: DB - private static customer: Array - private static schedule: Array + private static customers: Array + private static schedules: Array private constructor() { - DB.customer = [] - DB.schedule = [] + DB.customers = [] + DB.schedules = [] } public static connection(): DB { @@ -16,7 +16,7 @@ class DB { } public findCustomer(cpf: String) { - const customer = DB.customer.find( item => item.cpf === cpf) + const customer = DB.customers.find( item => item.cpf === cpf) return { success: customer ? true: false, data: customer || null, @@ -26,33 +26,33 @@ class DB { public addCustomer(data: any) { - let result = !DB.customer.find(item => item.cpf === data.cpf) ? DB.customer.push(data) : null + let result = !DB.customers.find(item => item.cpf === data.cpf) ? DB.customers.push({...data}) : null return { success: result ? true: false, - data: DB.customer.find( item => item.cpf === data.cpf && item.name === data.name) || null, + data: DB.customers.find( item => item.cpf === data.cpf && item.name === data.name) || null, message: result ? 'item successfully saved' : 'item already exists' } } public updateCustomer(data: any) { - let customerIndex = DB.customer.findIndex( item => item.cpf === data.cpf ) + let customerIndex = DB.customers.findIndex( item => item.cpf === data.cpf ) if (customerIndex > -1) { - DB.customer[customerIndex] = data + DB.customers[customerIndex] = { ...data } } return { success: customerIndex > -1 ? true: false, - data: DB.customer.find( item => item.cpf === data.cpf ) || null, + data: DB.customers.find( item => item.cpf === data.cpf ) || null, message: customerIndex > -1 ? 'item successfully updated' : 'item not found' } } public removeCustomer(cpf: String): any { - let customer = DB.customer.find( item => item.cpf === cpf ) + let customer = DB.customers.find( item => item.cpf === cpf ) if (customer) { - DB.customer = DB.customer.filter( item => item.cpf !== cpf) + DB.customers = DB.customers.filter( item => item.cpf !== cpf) } return { @@ -61,6 +61,19 @@ class DB { message: customer ? 'item successfully removed' : 'item not found' } } + + public listCustomer() { + const customers = DB.customers + return { + success: customers ? true: false, + data: customers || null, + message: customers ? 'items successfully removed' : 'items not found' + } + } + + public static resetForUnitTest() { + DB.instance = new DB() + } } export default DB \ No newline at end of file diff --git a/package.json b/package.json index ca897bd..b52bdb9 100644 --- a/package.json +++ b/package.json @@ -28,9 +28,11 @@ "typescript": "^3.6.3" }, "dependencies": { + "@types/faker": "^4.1.5", "@types/request-promise-native": "^1.0.16", "@types/swagger-ui-express": "^3.0.1", "express": "^4.17.1", + "faker": "^4.1.0", "request-promise-native": "^1.0.7", "swagger-ui-express": "^4.1.1" } diff --git a/src/services/customer.ts b/src/services/customer.ts index bbe0d60..bd5b9e7 100644 --- a/src/services/customer.ts +++ b/src/services/customer.ts @@ -11,7 +11,7 @@ class CustomerService { return this.connection.addCustomer(data) } - public update(data: {cpf: String, name: String}): any { + public update(data: any): any { return this.connection.updateCustomer(data) } @@ -22,6 +22,10 @@ class CustomerService { public find(cpf: String): any { return this.connection.findCustomer(cpf) } + + public list() { + return this.connection.listCustomer() + } } export default CustomerService \ No newline at end of file From 196be4598ac72aefc046eaf10fc4a9d5481f1c19 Mon Sep 17 00:00:00 2001 From: Luiz Filho Date: Sat, 21 Sep 2019 19:57:41 -0300 Subject: [PATCH 31/65] refactor customer unit test --- tests/unit/exam/customer.spec.ts | 119 ++++++++++++++----------------- 1 file changed, 52 insertions(+), 67 deletions(-) diff --git a/tests/unit/exam/customer.spec.ts b/tests/unit/exam/customer.spec.ts index 336f5eb..5939388 100644 --- a/tests/unit/exam/customer.spec.ts +++ b/tests/unit/exam/customer.spec.ts @@ -1,122 +1,107 @@ +import DB from '../../../data/db' import CustomerService from '../../../src/services/customer' -import { cursorTo } from 'readline' +import Faker from 'faker' +import { copyFileSync } from 'fs' +import { getDefaultWatermarks } from 'istanbul-lib-report' +const getCpf = () => Faker.random.number({ 'min': 100000000,'max': 999999999 }) + '-' + Faker.random.number({ 'min': 10, 'max': 99 }) -test('should save a customer to the database by service', () => { - - const customer = { - name: 'Luiz Filho', - cpf: '464444466-44' +const fullName = () => Faker.name.firstName + ' ' + Faker.name.lastName + +const getDate = () => Faker.date.between('1920-01-01', '2019-09-01') + +let customer = { + cpf: '', + name: '', + dateOfBirth: new Date() +} +let service = new CustomerService() + +beforeEach(() => { + DB.resetForUnitTest() + customer = { + name: fullName(), + cpf: getCpf(), + dateOfBirth: getDate() } +}) - const service = new CustomerService() +test('should save a customer to the database by service', () => { const customerStored = service.save(customer) expect(customer).toEqual(customerStored.data) }) test('should not save a customer', () => { - - const customer = { - name: 'Luiz Carlos', - cpf: '888555333-44' - } - - const service = new CustomerService() service.save(customer) - const otherService = new CustomerService() - const responseOtherService = otherService.save({ ...customer, name: 'João Silva' }) - + const responseOtherService = otherService.save({ ...customer, name: fullName() }) expect(responseOtherService.success).toEqual(false) }) test('should update a customer to the database by service', () => { - - let customer = { - name: 'Nathalia Souza', - cpf: '961965000-44' - } - - const service = new CustomerService() service.save(customer) - customer = { ...customer, name: 'Geisiane Pereira'} + customer = { ...customer, name: Faker.name.firstName + ' ' + fullName() } const customerUpdated = service.update(customer) - expect(customerUpdated.data).toEqual(customer) }) test('should not update a customer', () => { - - let customer = { - name: 'Hamilton Vicente', - cpf: '464444466-44' - } - - const service = new CustomerService() service.save(customer) - customer = { cpf: '333161615-46', name: 'João Rodrigues'} + customer = { + cpf: getCpf(), + name: fullName(), + dateOfBirth: getDate() + } const customerUpdated = service.update(customer) - expect(customerUpdated.success).toEqual(false) }) test('should remove a customer to the database by service', () => { - - let customer = { - name: 'Fernanda Pereira', - cpf: '464999966-44' - } - - const service = new CustomerService() service.save(customer) const customerRemoved = service.remove(customer.cpf) - expect(customerRemoved.success).toEqual(true) expect(customerRemoved.data).toEqual(customer) }) test('should not delete a customer', () => { - - let customer = { - name: 'Luiz Filho', - cpf: '464444466-44' - } - - const service = new CustomerService() service.save(customer) - customer = { ...customer, cpf: '111222333-44' } + customer = { + ...customer, + cpf: getCpf() + } const customerRemoved = service.remove(customer.cpf) expect(customerRemoved.success).toEqual(false) }) test('should be returned a customer by cpf', () => { - - const customer = { - name: 'Giovanni Santos', - cpf: '101010101-10' - } - - const service = new CustomerService() service.save(customer) const customerSeached = service.find(customer.cpf) - expect(customerSeached.success).toEqual(true) expect(customerSeached.data).toEqual(customer) }) test('should not return a customer by cpf', () => { - - const customer = { - name: 'Giovanni Santos', - cpf: '101010101-10' - } - - const service = new CustomerService() service.save(customer) - customer.cpf = '121121121-12' + customer.cpf = getCpf() const customerSeached = service.find(customer.cpf) expect(customerSeached.success).toEqual(false) expect(customerSeached.data).toEqual(null) }) + +test('should returned all customers', () => { + const service = new CustomerService() + for(let index = 0; index < 10; index++) { + let customer = { + cpf: getCpf(), + name: fullName() + } + + service.save(customer) + } + + let customers = service.list() + expect(customers.data.length).toEqual(10) + +}) From cb40a6cd302bf21af9b5f5850cfd176ecb138c9b Mon Sep 17 00:00:00 2001 From: Luiz Filho Date: Sat, 21 Sep 2019 20:01:38 -0300 Subject: [PATCH 32/65] rename dir inut test customer --- .../unit/{exam => customer}/customer.spec.ts | 0 .../unit/{exam => customer}/database.spec.ts | 0 tests/unit/exam/api.spec.ts | 24 ------------------- 3 files changed, 24 deletions(-) rename tests/unit/{exam => customer}/customer.spec.ts (100%) rename tests/unit/{exam => customer}/database.spec.ts (100%) delete mode 100644 tests/unit/exam/api.spec.ts diff --git a/tests/unit/exam/customer.spec.ts b/tests/unit/customer/customer.spec.ts similarity index 100% rename from tests/unit/exam/customer.spec.ts rename to tests/unit/customer/customer.spec.ts diff --git a/tests/unit/exam/database.spec.ts b/tests/unit/customer/database.spec.ts similarity index 100% rename from tests/unit/exam/database.spec.ts rename to tests/unit/customer/database.spec.ts diff --git a/tests/unit/exam/api.spec.ts b/tests/unit/exam/api.spec.ts deleted file mode 100644 index e2b7d37..0000000 --- a/tests/unit/exam/api.spec.ts +++ /dev/null @@ -1,24 +0,0 @@ -import axios from 'axios' -import ApiExamsService from '../../../src/services/apiExams' - -jest.mock('axios') -const mockedAxios = axios as jest.Mocked - -test('should return exam list', () => { - const exams = [ - { id: 1, name: 'Raio-x', value: 30.44 }, - { id: 2, name: 'Ultrassonografia', value: 46.21 }, - { id: 3, name: 'Endoscopia', value: 44.31 } - ] - - const expected = [ - { id: 1, name: 'Raio-x' }, - { id: 2, name: 'Ultrassonografia' }, - { id: 3, name: 'Endoscopia' } - ] - - mockedAxios.get.mockResolvedValue({ data: exams }) - - return ApiExamsService.list().then( data => expect(data).toEqual(expected)) - -}) \ No newline at end of file From 5d1261fa74a16d5029f99d7dd23be425d18fbb9c Mon Sep 17 00:00:00 2001 From: Luiz Filho Date: Sat, 21 Sep 2019 20:14:17 -0300 Subject: [PATCH 33/65] added utils for unit test file --- tests/unit/customer/customer.spec.ts | 12 ++---------- tests/unit/utils/dataGenerate.ts | 13 +++++++++++++ 2 files changed, 15 insertions(+), 10 deletions(-) create mode 100644 tests/unit/utils/dataGenerate.ts diff --git a/tests/unit/customer/customer.spec.ts b/tests/unit/customer/customer.spec.ts index 5939388..798b68f 100644 --- a/tests/unit/customer/customer.spec.ts +++ b/tests/unit/customer/customer.spec.ts @@ -1,14 +1,6 @@ import DB from '../../../data/db' import CustomerService from '../../../src/services/customer' -import Faker from 'faker' -import { copyFileSync } from 'fs' -import { getDefaultWatermarks } from 'istanbul-lib-report' - -const getCpf = () => Faker.random.number({ 'min': 100000000,'max': 999999999 }) + '-' + Faker.random.number({ 'min': 10, 'max': 99 }) - -const fullName = () => Faker.name.firstName + ' ' + Faker.name.lastName - -const getDate = () => Faker.date.between('1920-01-01', '2019-09-01') +import { getCpf, fullName, getDate } from '../utils/dataGenerate' let customer = { cpf: '', @@ -40,7 +32,7 @@ test('should not save a customer', () => { test('should update a customer to the database by service', () => { service.save(customer) - customer = { ...customer, name: Faker.name.firstName + ' ' + fullName() } + customer = { ...customer, name: fullName() } const customerUpdated = service.update(customer) expect(customerUpdated.data).toEqual(customer) }) diff --git a/tests/unit/utils/dataGenerate.ts b/tests/unit/utils/dataGenerate.ts new file mode 100644 index 0000000..60190ae --- /dev/null +++ b/tests/unit/utils/dataGenerate.ts @@ -0,0 +1,13 @@ +import Faker from 'faker' + +const getCpf = () => Faker.random.number({ 'min': 100000000,'max': 999999999 }) + '-' + Faker.random.number({ 'min': 10, 'max': 99 }) + +const fullName = () => Faker.name.firstName + ' ' + Faker.name.lastName + +const getDate = () => Faker.date.between('1920-01-01', '2019-09-01') + +export { + getCpf, + fullName, + getDate +} \ No newline at end of file From 18e65bb5c50a541082f74912d9149d19d99002d3 Mon Sep 17 00:00:00 2001 From: Luiz Filho Date: Sat, 21 Sep 2019 21:24:44 -0300 Subject: [PATCH 34/65] refactor exam list --- src/http/controllers/examController.ts | 15 ++++++++++----- src/providers/exams.ts | 11 +++++++++++ src/services/exam.ts | 14 ++++++++++++++ 3 files changed, 35 insertions(+), 5 deletions(-) create mode 100644 src/providers/exams.ts create mode 100644 src/services/exam.ts diff --git a/src/http/controllers/examController.ts b/src/http/controllers/examController.ts index 0f6859e..9dc99cf 100644 --- a/src/http/controllers/examController.ts +++ b/src/http/controllers/examController.ts @@ -1,12 +1,17 @@ import { Request, Response } from 'express' -import apiExam from '../../services/apiExams' -import formatter from '../../helpers/formatter' +import ExamsService from '../../services/exam' class ExamController { + + private service: ExamsService + + public constructor () { + this.service = new ExamsService() + this.list = this.list.bind(this) + } public async list(request: Request, response: Response): Promise { - const exams = await apiExam.list() - const responseFormatted = formatter.extractFields(JSON.parse(exams.toString()).exams) - return response.send(responseFormatted) + const exams = await this.service.list() + return response.send(exams) } } diff --git a/src/providers/exams.ts b/src/providers/exams.ts new file mode 100644 index 0000000..c6c0c46 --- /dev/null +++ b/src/providers/exams.ts @@ -0,0 +1,11 @@ +import request from 'request-promise-native' +import formatter from '../helpers/formatter' + +class ExamProvider { + static async list(): Promise { + let exams = await request.get('http://www.mocky.io/v2/5d681ede33000054e7e65c3f') + return formatter.extractFields(JSON.parse(exams.toString()).exams) + } +} + +export default ExamProvider \ No newline at end of file diff --git a/src/services/exam.ts b/src/services/exam.ts new file mode 100644 index 0000000..5298d99 --- /dev/null +++ b/src/services/exam.ts @@ -0,0 +1,14 @@ +import ExamProvider from '../providers/exams' + +class ExamsService { + + public list() { + return ExamProvider.list() + } + + public get(id: Number) { + const exams = this.list() + } +} + +export default ExamsService \ No newline at end of file From ffd2500c2571f9cee0c4cfa6ed8eb6b84de67b8a Mon Sep 17 00:00:00 2001 From: Luiz Filho Date: Sun, 22 Sep 2019 00:35:19 -0300 Subject: [PATCH 35/65] fixed unity test external api --- tests/unit/customer/api.spec.ts | 20 ++++++++++++++++++++ 1 file changed, 20 insertions(+) create mode 100644 tests/unit/customer/api.spec.ts diff --git a/tests/unit/customer/api.spec.ts b/tests/unit/customer/api.spec.ts new file mode 100644 index 0000000..d7f16fb --- /dev/null +++ b/tests/unit/customer/api.spec.ts @@ -0,0 +1,20 @@ +import request from 'request-promise-native' +import ExamProvider from '../../../src/providers/exams' + +jest.mock('request-promise-native') +const mockedAxios = request as jest.Mocked + +test('should return exam list', async () => { + const exams = '{"exams": [{"id":"1","name":"17 soro","value":35.60},{"id":"2","name":"Acidificação Urinária","value":84.90},{"id":"3","name":"Ácido Ascórbico, plasma","value":99.90}]}' + + const expected = [ + { id: "1", name: '17 soro' }, + { id: "2", name: 'Acidificação Urinária' }, + { id: "3", name: 'Ácido Ascórbico, plasma' } + ] + + mockedAxios.get.mockResolvedValue(exams) + let response = await ExamProvider.list() + expect(response).toEqual(expected) +}) + From 2667e28bf3c0d13a616d92d37340fd6f2286cecc Mon Sep 17 00:00:00 2001 From: Luiz Filho Date: Sun, 22 Sep 2019 01:09:00 -0300 Subject: [PATCH 36/65] added unit test schedule exam --- tests/unit/exam/schedule.spec.ts | 56 ++++++++++++++++++++++++++++++++ tests/unit/utils/dataGenerate.ts | 8 ++++- 2 files changed, 63 insertions(+), 1 deletion(-) create mode 100644 tests/unit/exam/schedule.spec.ts diff --git a/tests/unit/exam/schedule.spec.ts b/tests/unit/exam/schedule.spec.ts new file mode 100644 index 0000000..99df4de --- /dev/null +++ b/tests/unit/exam/schedule.spec.ts @@ -0,0 +1,56 @@ +import request from 'request-promise-native' +import DB from '../../../data/db' +import { fullName, getCpf, getDate, getFutureDate, getExamsMock } from '../utils/dataGenerate' +import ScheduleService from '../../../src/services/schedule' + +jest.mock('request-promise-native') +const mockedAxios = request as jest.Mocked + +let customer = { + cpf: '', + name: '', + dateOfBirth: new Date() +} + +let scheduleService = new ScheduleService() +const examsMock = getExamsMock() + +describe('Scheduling exam', () => { + + beforeEach( async () => { + + DB.resetForUnitTest() + + let customerData = { + name: fullName(), + cpf: getCpf(), + dateOfBirth: getDate() + } + + let connection = DB.connection() + customer = connection.addCustomer(customerData).data + mockedAxios.get.mockResolvedValue(examsMock) + }) + + it('should be scheduled an exam for a patient enrolled in the database', async () => { + const data = { + examId: (Math.floor(Math.random() * 3) + 1).toString(), + cpf: customer.cpf, + date: getFutureDate() + } + mockedAxios.get.mockResolvedValue(examsMock) + let examResult = await scheduleService.save(data) + expect(examResult).toEqual(data) + }) + + it('should not be scheduled an exam for the wrong exam id', async () => { + const data = { + examId: '11', + cpf: customer.cpf, + date: getFutureDate() + } + mockedAxios.get.mockResolvedValue(examsMock) + let examResult = await scheduleService.save(data) + expect(examResult).toEqual(null) + }) +}) diff --git a/tests/unit/utils/dataGenerate.ts b/tests/unit/utils/dataGenerate.ts index 60190ae..ef42390 100644 --- a/tests/unit/utils/dataGenerate.ts +++ b/tests/unit/utils/dataGenerate.ts @@ -6,8 +6,14 @@ const fullName = () => Faker.name.firstName + ' ' + Faker.name.lastName const getDate = () => Faker.date.between('1920-01-01', '2019-09-01') +const getFutureDate = () => Faker.date.between(new Date(), '2020-12-31') + +const getExamsMock = () => '{"exams": [{"id":"1","name":"17 soro","value":35.60},{"id":"2","name":"Acidificação Urinária","value":84.90},{"id":"3","name":"Ácido Ascórbico, plasma","value":99.90}]}' + export { getCpf, fullName, - getDate + getDate, + getFutureDate, + getExamsMock } \ No newline at end of file From 611986a6544c71e56723d18b509078d4b83b1148 Mon Sep 17 00:00:00 2001 From: Luiz Filho Date: Sun, 22 Sep 2019 01:58:27 -0300 Subject: [PATCH 37/65] added unit test when same time --- data/db.ts | 9 +++++++++ package.json | 1 + src/providers/exams.ts | 2 +- src/services/schedule.ts | 32 ++++++++++++++++++++++++++++++++ tests/unit/exam/schedule.spec.ts | 20 ++++++++++++++++++-- tests/unit/utils/dataGenerate.ts | 2 +- 6 files changed, 62 insertions(+), 4 deletions(-) create mode 100644 src/services/schedule.ts diff --git a/data/db.ts b/data/db.ts index b61a60c..b80c428 100644 --- a/data/db.ts +++ b/data/db.ts @@ -74,6 +74,15 @@ class DB { public static resetForUnitTest() { DB.instance = new DB() } + + public schedule(data: any): any { + DB.schedules.push({...data}) + return DB.schedules.find( item => item.cpf == data.cpf && item.examId === data.examId) + } + + public getByScheduleByDate( examId: String, date: any ) { + return DB.schedules.find( item => item.examId === examId && item.date === date) + } } export default DB \ No newline at end of file diff --git a/package.json b/package.json index b52bdb9..5726b5e 100644 --- a/package.json +++ b/package.json @@ -33,6 +33,7 @@ "@types/swagger-ui-express": "^3.0.1", "express": "^4.17.1", "faker": "^4.1.0", + "moment": "^2.24.0", "request-promise-native": "^1.0.7", "swagger-ui-express": "^4.1.1" } diff --git a/src/providers/exams.ts b/src/providers/exams.ts index c6c0c46..05005e7 100644 --- a/src/providers/exams.ts +++ b/src/providers/exams.ts @@ -2,7 +2,7 @@ import request from 'request-promise-native' import formatter from '../helpers/formatter' class ExamProvider { - static async list(): Promise { + static async list(): Promise { let exams = await request.get('http://www.mocky.io/v2/5d681ede33000054e7e65c3f') return formatter.extractFields(JSON.parse(exams.toString()).exams) } diff --git a/src/services/schedule.ts b/src/services/schedule.ts new file mode 100644 index 0000000..de21c63 --- /dev/null +++ b/src/services/schedule.ts @@ -0,0 +1,32 @@ +import DB from '../../data/db' +import ExamService from './exam' +import CustomerService from './customer' +import moment from 'moment' + +class ScheduleService { + private connection: DB + private exam: ExamService + private customer: CustomerService + + public constructor () { + this.connection = DB.connection() + this.exam = new ExamService() + this.customer = new CustomerService() + } + + public async save(data: any) { + let exam = await this.exam.get(data.examId) + let customer = await this.customer.find(data.cpf) + if (exam && customer.success) { + const alreadyScheduled = this.connection.getByScheduleByDate(data.examId, data.date) + if (!alreadyScheduled) { + data = { ...data, date: moment(data.date).format() } + return this.connection.schedule(data) + } + } + return null + } + +} + +export default ScheduleService \ No newline at end of file diff --git a/tests/unit/exam/schedule.spec.ts b/tests/unit/exam/schedule.spec.ts index 99df4de..5d18224 100644 --- a/tests/unit/exam/schedule.spec.ts +++ b/tests/unit/exam/schedule.spec.ts @@ -2,6 +2,7 @@ import request from 'request-promise-native' import DB from '../../../data/db' import { fullName, getCpf, getDate, getFutureDate, getExamsMock } from '../utils/dataGenerate' import ScheduleService from '../../../src/services/schedule' +import moment from 'moment' jest.mock('request-promise-native') const mockedAxios = request as jest.Mocked @@ -26,7 +27,6 @@ describe('Scheduling exam', () => { cpf: getCpf(), dateOfBirth: getDate() } - let connection = DB.connection() customer = connection.addCustomer(customerData).data mockedAxios.get.mockResolvedValue(examsMock) @@ -36,7 +36,7 @@ describe('Scheduling exam', () => { const data = { examId: (Math.floor(Math.random() * 3) + 1).toString(), cpf: customer.cpf, - date: getFutureDate() + date: moment(getFutureDate()).format() } mockedAxios.get.mockResolvedValue(examsMock) let examResult = await scheduleService.save(data) @@ -53,4 +53,20 @@ describe('Scheduling exam', () => { let examResult = await scheduleService.save(data) expect(examResult).toEqual(null) }) + + it('should not schedule a busy time', async () => { + const data = { + examId: (Math.floor(Math.random() * 3) + 1).toString(), + cpf: customer.cpf, + date: moment(getFutureDate()).format() + } + mockedAxios.get.mockResolvedValue(examsMock) + let examResult = await scheduleService.save(data) + let connectionToSameTime = DB.connection() + + let otherCustomer = connectionToSameTime.addCustomer({ ...customer, cpf: getCpf() }).data + + let otherExamSameTime = await scheduleService.save({ otherCustomer }) + expect(otherExamSameTime).toEqual(null) + }) }) diff --git a/tests/unit/utils/dataGenerate.ts b/tests/unit/utils/dataGenerate.ts index ef42390..0759a00 100644 --- a/tests/unit/utils/dataGenerate.ts +++ b/tests/unit/utils/dataGenerate.ts @@ -2,7 +2,7 @@ import Faker from 'faker' const getCpf = () => Faker.random.number({ 'min': 100000000,'max': 999999999 }) + '-' + Faker.random.number({ 'min': 10, 'max': 99 }) -const fullName = () => Faker.name.firstName + ' ' + Faker.name.lastName +const fullName = () => Faker.name.firstName() + ' ' + Faker.name.lastName() const getDate = () => Faker.date.between('1920-01-01', '2019-09-01') From 3c0dabbafb382f73a9dcfb81d070ea4eebb17218 Mon Sep 17 00:00:00 2001 From: Luiz Filho Date: Sun, 22 Sep 2019 03:15:14 -0300 Subject: [PATCH 38/65] added schedule route --- data/db.ts | 2 +- src/http/controllers/examController.ts | 9 ++++++- src/http/controllers/scheduleController.ts | 29 ++++++++++++++++++++++ src/routes/exam.ts | 1 + src/routes/schedule.ts | 8 ++++++ src/services/exam.ts | 5 ++-- src/services/schedule.ts | 7 +++--- 7 files changed, 54 insertions(+), 7 deletions(-) create mode 100644 src/http/controllers/scheduleController.ts create mode 100644 src/routes/schedule.ts diff --git a/data/db.ts b/data/db.ts index b80c428..918d801 100644 --- a/data/db.ts +++ b/data/db.ts @@ -81,7 +81,7 @@ class DB { } public getByScheduleByDate( examId: String, date: any ) { - return DB.schedules.find( item => item.examId === examId && item.date === date) + return !!DB.schedules.find( item => item.examId === examId && item.date === date ) } } diff --git a/src/http/controllers/examController.ts b/src/http/controllers/examController.ts index 9dc99cf..4536ee9 100644 --- a/src/http/controllers/examController.ts +++ b/src/http/controllers/examController.ts @@ -2,17 +2,24 @@ import { Request, Response } from 'express' import ExamsService from '../../services/exam' class ExamController { - + private service: ExamsService public constructor () { this.service = new ExamsService() this.list = this.list.bind(this) + this.get = this.get.bind(this) } + public async list(request: Request, response: Response): Promise { const exams = await this.service.list() return response.send(exams) } + + public async get(request: Request, response: Response): Promise { + const exam = await this.service.get(request.params.id) + return response.send(exam) + } } export default new ExamController() \ No newline at end of file diff --git a/src/http/controllers/scheduleController.ts b/src/http/controllers/scheduleController.ts new file mode 100644 index 0000000..6d7131a --- /dev/null +++ b/src/http/controllers/scheduleController.ts @@ -0,0 +1,29 @@ +import { Request, Response } from 'express' +import ScheduleService from '../../services/schedule' + +class ScheduleController { + + private service: ScheduleService + + public constructor () { + this.service = new ScheduleService() + this.schedule = this.schedule.bind(this) + } + + public async schedule(request: Request, response: Response): Promise { + const result = await this.service.save(request.body) + if(!!result) { + response.status(409) + } + + return response.send( + { + data: result, + success: !!result ? true : false, + message: !!result ? 'Successful Scheduling' : 'Schedule failed' + } + ) + } +} + +export default new ScheduleController() \ No newline at end of file diff --git a/src/routes/exam.ts b/src/routes/exam.ts index b14f2a1..253d742 100644 --- a/src/routes/exam.ts +++ b/src/routes/exam.ts @@ -4,5 +4,6 @@ const ExamRoutes = Router() import ExamController from '../http/controllers/examController' ExamRoutes.get('/exams', ExamController.list) +ExamRoutes.get('/exams/:id', ExamController.get) export { ExamRoutes } \ No newline at end of file diff --git a/src/routes/schedule.ts b/src/routes/schedule.ts new file mode 100644 index 0000000..7ec8a1a --- /dev/null +++ b/src/routes/schedule.ts @@ -0,0 +1,8 @@ +import { Router } from 'express' + +const ScheduleRoute = Router() +import ScheduleController from '../http/controllers/scheduleController' + +ScheduleRoute.post('/schedules', ScheduleController.schedule) + +export { ScheduleRoute } \ No newline at end of file diff --git a/src/services/exam.ts b/src/services/exam.ts index 5298d99..d38f659 100644 --- a/src/services/exam.ts +++ b/src/services/exam.ts @@ -6,8 +6,9 @@ class ExamsService { return ExamProvider.list() } - public get(id: Number) { - const exams = this.list() + public async get(id: any): Promise { + const exams = await this.list() + return exams.find( (item: any) => item.id === id) } } diff --git a/src/services/schedule.ts b/src/services/schedule.ts index de21c63..9260dc0 100644 --- a/src/services/schedule.ts +++ b/src/services/schedule.ts @@ -15,13 +15,14 @@ class ScheduleService { } public async save(data: any) { - let exam = await this.exam.get(data.examId) + let exam = await this.exam.get(data.examId.toString()) let customer = await this.customer.find(data.cpf) if (exam && customer.success) { - const alreadyScheduled = this.connection.getByScheduleByDate(data.examId, data.date) + let formattedDate = moment(data.date).format() + const alreadyScheduled = this.connection.getByScheduleByDate(data.examId.toString(), formattedDate) if (!alreadyScheduled) { data = { ...data, date: moment(data.date).format() } - return this.connection.schedule(data) + return this.connection.schedule({ ...data, examId: data.examId.toString() }) } } return null From d1b2f1fe4f12e44429efc72e45d6f38c8c460cb3 Mon Sep 17 00:00:00 2001 From: Luiz Filho Date: Sun, 22 Sep 2019 03:15:35 -0300 Subject: [PATCH 39/65] adjustment unit test --- tests/unit/exam/schedule.spec.ts | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/tests/unit/exam/schedule.spec.ts b/tests/unit/exam/schedule.spec.ts index 5d18224..e7acc60 100644 --- a/tests/unit/exam/schedule.spec.ts +++ b/tests/unit/exam/schedule.spec.ts @@ -61,12 +61,12 @@ describe('Scheduling exam', () => { date: moment(getFutureDate()).format() } mockedAxios.get.mockResolvedValue(examsMock) - let examResult = await scheduleService.save(data) + await scheduleService.save(data) let connectionToSameTime = DB.connection() let otherCustomer = connectionToSameTime.addCustomer({ ...customer, cpf: getCpf() }).data - let otherExamSameTime = await scheduleService.save({ otherCustomer }) + let otherExamSameTime = await scheduleService.save({ ...data, cpf: otherCustomer.cpf }) expect(otherExamSameTime).toEqual(null) }) }) From 2c2f7677814ae999c3310cb00c46b99415aabb3d Mon Sep 17 00:00:00 2001 From: Luiz Filho Date: Sun, 22 Sep 2019 03:16:30 -0300 Subject: [PATCH 40/65] adjustment route schedule --- src/app.ts | 3 ++- src/routes/index.ts | 3 ++- src/services/apiExams.ts | 9 --------- 3 files changed, 4 insertions(+), 11 deletions(-) delete mode 100644 src/services/apiExams.ts diff --git a/src/app.ts b/src/app.ts index 5465489..83d5930 100644 --- a/src/app.ts +++ b/src/app.ts @@ -1,6 +1,6 @@ import express from 'express' import swaggerUi from 'swagger-ui-express' -import { CustomerRoutes, ExamRoutes } from './routes/index' +import { CustomerRoutes, ExamRoutes, ScheduleRoute } from './routes/index' import * as swaggerDocument from '../swagger.json' class App { @@ -16,6 +16,7 @@ class App { private routes (): void { this.express.use(CustomerRoutes) this.express.use(ExamRoutes) + this.express.use(ScheduleRoute) } private middlwares (): void { diff --git a/src/routes/index.ts b/src/routes/index.ts index 1cef95b..b461b59 100644 --- a/src/routes/index.ts +++ b/src/routes/index.ts @@ -1,2 +1,3 @@ export * from './exam' -export * from './customer' \ No newline at end of file +export * from './customer' +export * from './schedule' \ No newline at end of file diff --git a/src/services/apiExams.ts b/src/services/apiExams.ts deleted file mode 100644 index c90836f..0000000 --- a/src/services/apiExams.ts +++ /dev/null @@ -1,9 +0,0 @@ -import request from 'request-promise-native' - -class ApiExamsService { - static async list(): Promise { - return await request.get('http://www.mocky.io/v2/5d681ede33000054e7e65c3f') - } -} - -export default ApiExamsService \ No newline at end of file From 95ebfab976efc55ec2801444f859716f9dc79735 Mon Sep 17 00:00:00 2001 From: Luiz Filho Date: Sun, 22 Sep 2019 04:08:52 -0300 Subject: [PATCH 41/65] added service for get exam bu cpf and sum price and unit test --- data/db.ts | 6 +++++- src/providers/exams.ts | 6 ++++++ src/services/exam.ts | 3 +-- src/services/schedule.ts | 10 ++++++++++ tests/unit/exam/schedule.spec.ts | 18 ++++++++++++++++++ 5 files changed, 40 insertions(+), 3 deletions(-) diff --git a/data/db.ts b/data/db.ts index 918d801..4ee9651 100644 --- a/data/db.ts +++ b/data/db.ts @@ -83,6 +83,10 @@ class DB { public getByScheduleByDate( examId: String, date: any ) { return !!DB.schedules.find( item => item.examId === examId && item.date === date ) } -} + + public getScheduleByCpf(cpf: String) { + return DB.schedules.filter(item => item.cpf === cpf) + } + } export default DB \ No newline at end of file diff --git a/src/providers/exams.ts b/src/providers/exams.ts index 05005e7..e530a91 100644 --- a/src/providers/exams.ts +++ b/src/providers/exams.ts @@ -6,6 +6,12 @@ class ExamProvider { let exams = await request.get('http://www.mocky.io/v2/5d681ede33000054e7e65c3f') return formatter.extractFields(JSON.parse(exams.toString()).exams) } + + static async byId(id: String): Promise { + let exams = await request.get('http://www.mocky.io/v2/5d681ede33000054e7e65c3f') + let formatted = JSON.parse(exams.toString()).exams + return formatted.find( (item: any) => item.id === id) + } } export default ExamProvider \ No newline at end of file diff --git a/src/services/exam.ts b/src/services/exam.ts index d38f659..752e196 100644 --- a/src/services/exam.ts +++ b/src/services/exam.ts @@ -7,8 +7,7 @@ class ExamsService { } public async get(id: any): Promise { - const exams = await this.list() - return exams.find( (item: any) => item.id === id) + return await ExamProvider.byId(id) } } diff --git a/src/services/schedule.ts b/src/services/schedule.ts index 9260dc0..4840c75 100644 --- a/src/services/schedule.ts +++ b/src/services/schedule.ts @@ -21,6 +21,7 @@ class ScheduleService { let formattedDate = moment(data.date).format() const alreadyScheduled = this.connection.getByScheduleByDate(data.examId.toString(), formattedDate) if (!alreadyScheduled) { + data.price = exam.value data = { ...data, date: moment(data.date).format() } return this.connection.schedule({ ...data, examId: data.examId.toString() }) } @@ -28,6 +29,15 @@ class ScheduleService { return null } + public listByCpf(cpf: String) { + const result = this.connection.getScheduleByCpf(cpf) + let pricesSum = 0 + if (!!result) { + pricesSum = result.reduce( (sum, currentPrice) => sum + currentPrice.price, 0) + } + return { ...result, total: pricesSum } + } + } export default ScheduleService \ No newline at end of file diff --git a/tests/unit/exam/schedule.spec.ts b/tests/unit/exam/schedule.spec.ts index e7acc60..c3134cd 100644 --- a/tests/unit/exam/schedule.spec.ts +++ b/tests/unit/exam/schedule.spec.ts @@ -69,4 +69,22 @@ describe('Scheduling exam', () => { let otherExamSameTime = await scheduleService.save({ ...data, cpf: otherCustomer.cpf }) expect(otherExamSameTime).toEqual(null) }) + + it('should return exams by cpf and calculate the total value', async () => { + + mockedAxios.get.mockResolvedValue(examsMock) + let sum = 0 + for(let index = 0; index < 10; index++) { + + const data = { + examId: (Math.floor(Math.random() * 3) + 1).toString(), + cpf: customer.cpf, + date: moment(getFutureDate()).format() + } + let saved = await scheduleService.save(data) + sum += saved.price + } + let scheduleByCpf = scheduleService.listByCpf(customer.cpf) + expect(scheduleByCpf.total).toEqual(sum) + }) }) From 83d34ba1f370b7c74d23f060e835d76362a616cb Mon Sep 17 00:00:00 2001 From: Luiz Filho Date: Sun, 22 Sep 2019 05:22:51 -0300 Subject: [PATCH 42/65] added id schedule --- data/db.ts | 3 ++- src/http/controllers/scheduleController.ts | 15 ++++++++++++++- src/routes/schedule.ts | 1 + src/services/schedule.ts | 9 +++++---- tests/unit/exam/schedule.spec.ts | 3 ++- 5 files changed, 24 insertions(+), 7 deletions(-) diff --git a/data/db.ts b/data/db.ts index 4ee9651..755f84f 100644 --- a/data/db.ts +++ b/data/db.ts @@ -76,7 +76,8 @@ class DB { } public schedule(data: any): any { - DB.schedules.push({...data}) + let id = DB.schedules.length + 1 + DB.schedules.push({ ...data, id }) return DB.schedules.find( item => item.cpf == data.cpf && item.examId === data.examId) } diff --git a/src/http/controllers/scheduleController.ts b/src/http/controllers/scheduleController.ts index 6d7131a..a438e0b 100644 --- a/src/http/controllers/scheduleController.ts +++ b/src/http/controllers/scheduleController.ts @@ -8,11 +8,12 @@ class ScheduleController { public constructor () { this.service = new ScheduleService() this.schedule = this.schedule.bind(this) + this.get = this.get.bind(this) } public async schedule(request: Request, response: Response): Promise { const result = await this.service.save(request.body) - if(!!result) { + if(!result) { response.status(409) } @@ -24,6 +25,18 @@ class ScheduleController { } ) } + + public async get(request: Request, response: Response): Promise { + const result = await this.service.listByCpf(request.params.cpf) + if (!result) { + response.status(409) + } + return response.send({ + data: result ? result : null, + success: result ? true : false, + message: result ? 'data found successfully' : 'data search failed' + }) + } } export default new ScheduleController() \ No newline at end of file diff --git a/src/routes/schedule.ts b/src/routes/schedule.ts index 7ec8a1a..cb38a4a 100644 --- a/src/routes/schedule.ts +++ b/src/routes/schedule.ts @@ -4,5 +4,6 @@ const ScheduleRoute = Router() import ScheduleController from '../http/controllers/scheduleController' ScheduleRoute.post('/schedules', ScheduleController.schedule) +ScheduleRoute.get('/schedules/:cpf', ScheduleController.get) export { ScheduleRoute } \ No newline at end of file diff --git a/src/services/schedule.ts b/src/services/schedule.ts index 4840c75..e0be521 100644 --- a/src/services/schedule.ts +++ b/src/services/schedule.ts @@ -30,12 +30,13 @@ class ScheduleService { } public listByCpf(cpf: String) { - const result = this.connection.getScheduleByCpf(cpf) + let result: any = this.connection.getScheduleByCpf(cpf) let pricesSum = 0 - if (!!result) { - pricesSum = result.reduce( (sum, currentPrice) => sum + currentPrice.price, 0) + if (result) { + pricesSum = result.reduce( (sum: Number, currentPrice: any) => sum + currentPrice.price, 0) + result = { result, total: pricesSum } } - return { ...result, total: pricesSum } + return result } } diff --git a/tests/unit/exam/schedule.spec.ts b/tests/unit/exam/schedule.spec.ts index c3134cd..b1e1abd 100644 --- a/tests/unit/exam/schedule.spec.ts +++ b/tests/unit/exam/schedule.spec.ts @@ -40,7 +40,8 @@ describe('Scheduling exam', () => { } mockedAxios.get.mockResolvedValue(examsMock) let examResult = await scheduleService.save(data) - expect(examResult).toEqual(data) + const { id, ...received } = examResult + expect(received).toEqual(data) }) it('should not be scheduled an exam for the wrong exam id', async () => { From 580db5d6b2d6936d1b39ed90033100f53630daa7 Mon Sep 17 00:00:00 2001 From: Luiz Filho Date: Sun, 22 Sep 2019 05:41:40 -0300 Subject: [PATCH 43/65] added test unit and service for edit schedule --- data/db.ts | 13 +++++++++++++ src/services/schedule.ts | 5 +++++ tests/unit/exam/schedule.spec.ts | 17 +++++++++++++++++ 3 files changed, 35 insertions(+) diff --git a/data/db.ts b/data/db.ts index 755f84f..b2800e1 100644 --- a/data/db.ts +++ b/data/db.ts @@ -81,6 +81,19 @@ class DB { return DB.schedules.find( item => item.cpf == data.cpf && item.examId === data.examId) } + public updateSchedule(id: any, date: any): any { + let scheduleIndex = DB.schedules.findIndex( item => item.id === id ) + if (scheduleIndex > -1) { + DB.schedules[scheduleIndex] = { ...DB.schedules[scheduleIndex] , date: date} + } + + return { + success: scheduleIndex > -1 ? true: false, + data: DB.schedules.find( item => item.id === id ) || null, + message: scheduleIndex > -1 ? 'item successfully updated' : 'item not found' + } + } + public getByScheduleByDate( examId: String, date: any ) { return !!DB.schedules.find( item => item.examId === examId && item.date === date ) } diff --git a/src/services/schedule.ts b/src/services/schedule.ts index e0be521..f6adbdc 100644 --- a/src/services/schedule.ts +++ b/src/services/schedule.ts @@ -39,6 +39,11 @@ class ScheduleService { return result } + public async update(id: any, date: any) { + let formattedDate = moment(date).format() + return this.connection.updateSchedule(id, formattedDate) + } + } export default ScheduleService \ No newline at end of file diff --git a/tests/unit/exam/schedule.spec.ts b/tests/unit/exam/schedule.spec.ts index b1e1abd..5693dbd 100644 --- a/tests/unit/exam/schedule.spec.ts +++ b/tests/unit/exam/schedule.spec.ts @@ -88,4 +88,21 @@ describe('Scheduling exam', () => { let scheduleByCpf = scheduleService.listByCpf(customer.cpf) expect(scheduleByCpf.total).toEqual(sum) }) + + it('should edit a schedule by id', async () => { + const data = { + examId: (Math.floor(Math.random() * 3) + 1).toString(), + cpf: customer.cpf, + date: moment(getFutureDate()).format() + } + mockedAxios.get.mockResolvedValue(examsMock) + let examResult = await scheduleService.save(data) + const { id } = examResult + + const newDate = moment(getFutureDate()).format() + + let updatedSchedule = await scheduleService.update(id, newDate) + + expect(updatedSchedule.data.date).toEqual(newDate) + }) }) From 831ba87c1c657ac434f717e392b2c68b1c286a83 Mon Sep 17 00:00:00 2001 From: Luiz Filho Date: Sun, 22 Sep 2019 06:14:09 -0300 Subject: [PATCH 44/65] added route update schedule --- data/db.ts | 4 ++-- src/http/controllers/scheduleController.ts | 10 ++++++++++ src/routes/schedule.ts | 1 + src/services/schedule.ts | 2 +- 4 files changed, 14 insertions(+), 3 deletions(-) diff --git a/data/db.ts b/data/db.ts index b2800e1..38fa210 100644 --- a/data/db.ts +++ b/data/db.ts @@ -81,8 +81,8 @@ class DB { return DB.schedules.find( item => item.cpf == data.cpf && item.examId === data.examId) } - public updateSchedule(id: any, date: any): any { - let scheduleIndex = DB.schedules.findIndex( item => item.id === id ) + public updateSchedule(id: Number, date: any): any { + let scheduleIndex = DB.schedules.findIndex( item => item.id === id) if (scheduleIndex > -1) { DB.schedules[scheduleIndex] = { ...DB.schedules[scheduleIndex] , date: date} } diff --git a/src/http/controllers/scheduleController.ts b/src/http/controllers/scheduleController.ts index a438e0b..0270a6d 100644 --- a/src/http/controllers/scheduleController.ts +++ b/src/http/controllers/scheduleController.ts @@ -8,6 +8,7 @@ class ScheduleController { public constructor () { this.service = new ScheduleService() this.schedule = this.schedule.bind(this) + this.update = this.update.bind(this) this.get = this.get.bind(this) } @@ -26,6 +27,15 @@ class ScheduleController { ) } + public async update(request: Request, response: Response): Promise { + const result = await this.service.update(parseInt(request.params.id), request.body.date) + if(!result) { + response.status(409) + } + + return response.send(result) + } + public async get(request: Request, response: Response): Promise { const result = await this.service.listByCpf(request.params.cpf) if (!result) { diff --git a/src/routes/schedule.ts b/src/routes/schedule.ts index cb38a4a..a626313 100644 --- a/src/routes/schedule.ts +++ b/src/routes/schedule.ts @@ -4,6 +4,7 @@ const ScheduleRoute = Router() import ScheduleController from '../http/controllers/scheduleController' ScheduleRoute.post('/schedules', ScheduleController.schedule) +ScheduleRoute.put('/schedules/:id', ScheduleController.update) ScheduleRoute.get('/schedules/:cpf', ScheduleController.get) export { ScheduleRoute } \ No newline at end of file diff --git a/src/services/schedule.ts b/src/services/schedule.ts index f6adbdc..4fdb138 100644 --- a/src/services/schedule.ts +++ b/src/services/schedule.ts @@ -39,7 +39,7 @@ class ScheduleService { return result } - public async update(id: any, date: any) { + public async update(id: Number, date: any) { let formattedDate = moment(date).format() return this.connection.updateSchedule(id, formattedDate) } From 76ea7981c501a22344b0510af20b938c3e505f16 Mon Sep 17 00:00:00 2001 From: Luiz Filho Date: Sun, 22 Sep 2019 06:25:43 -0300 Subject: [PATCH 45/65] added service delete schedule and unit test --- data/db.ts | 14 ++++++++++++++ src/services/schedule.ts | 3 +++ tests/unit/exam/schedule.spec.ts | 15 +++++++++++++++ 3 files changed, 32 insertions(+) diff --git a/data/db.ts b/data/db.ts index 38fa210..a9a19a1 100644 --- a/data/db.ts +++ b/data/db.ts @@ -101,6 +101,20 @@ class DB { public getScheduleByCpf(cpf: String) { return DB.schedules.filter(item => item.cpf === cpf) } + + public removeSchedule(id: Number): any { + let schedule = DB.schedules.find( item => item.id === id ) + + if (schedule) { + DB.schedules = DB.schedules.filter( item => item.id !== id) + } + + return { + success: schedule ? true: false, + data: schedule || null, + message: schedule ? 'item successfully removed' : 'item not found' + } + } } export default DB \ No newline at end of file diff --git a/src/services/schedule.ts b/src/services/schedule.ts index 4fdb138..95f3dcc 100644 --- a/src/services/schedule.ts +++ b/src/services/schedule.ts @@ -44,6 +44,9 @@ class ScheduleService { return this.connection.updateSchedule(id, formattedDate) } + public async remove(id: Number) { + return this.connection.removeSchedule(id) + } } export default ScheduleService \ No newline at end of file diff --git a/tests/unit/exam/schedule.spec.ts b/tests/unit/exam/schedule.spec.ts index 5693dbd..c99a6b3 100644 --- a/tests/unit/exam/schedule.spec.ts +++ b/tests/unit/exam/schedule.spec.ts @@ -105,4 +105,19 @@ describe('Scheduling exam', () => { expect(updatedSchedule.data.date).toEqual(newDate) }) + + it('should remove a schedue by id', async () => { + const data = { + examId: (Math.floor(Math.random() * 3) + 1).toString(), + cpf: customer.cpf, + date: moment(getFutureDate()).format() + } + mockedAxios.get.mockResolvedValue(examsMock) + let examResult = await scheduleService.save(data) + const { id } = examResult + + let removed = await scheduleService.remove(id) + + expect(removed.data).toEqual(examResult) + }) }) From 48291c14797a37d0be52d78505e6fa46405f7507 Mon Sep 17 00:00:00 2001 From: Luiz Filho Date: Sun, 22 Sep 2019 06:35:00 -0300 Subject: [PATCH 46/65] added route remove schedule --- src/http/controllers/scheduleController.ts | 17 +++++++++++++---- src/routes/schedule.ts | 1 + 2 files changed, 14 insertions(+), 4 deletions(-) diff --git a/src/http/controllers/scheduleController.ts b/src/http/controllers/scheduleController.ts index 0270a6d..0aab8f4 100644 --- a/src/http/controllers/scheduleController.ts +++ b/src/http/controllers/scheduleController.ts @@ -10,6 +10,7 @@ class ScheduleController { this.schedule = this.schedule.bind(this) this.update = this.update.bind(this) this.get = this.get.bind(this) + this.remove = this.remove.bind(this) } public async schedule(request: Request, response: Response): Promise { @@ -38,15 +39,23 @@ class ScheduleController { public async get(request: Request, response: Response): Promise { const result = await this.service.listByCpf(request.params.cpf) - if (!result) { + if (!result.length) { response.status(409) } return response.send({ - data: result ? result : null, - success: result ? true : false, - message: result ? 'data found successfully' : 'data search failed' + data: result.length ? result : null, + success: result.length ? true : false, + message: result.length ? 'data found successfully' : 'data search failed' }) } + + public async remove(request: Request, response: Response): Promise { + const result = await this.service.remove(parseInt(request.params.id)) + if (!result) { + response.status(409) + } + return response.send(result) + } } export default new ScheduleController() \ No newline at end of file diff --git a/src/routes/schedule.ts b/src/routes/schedule.ts index a626313..70e1e08 100644 --- a/src/routes/schedule.ts +++ b/src/routes/schedule.ts @@ -6,5 +6,6 @@ import ScheduleController from '../http/controllers/scheduleController' ScheduleRoute.post('/schedules', ScheduleController.schedule) ScheduleRoute.put('/schedules/:id', ScheduleController.update) ScheduleRoute.get('/schedules/:cpf', ScheduleController.get) +ScheduleRoute.delete('/schedules/:id', ScheduleController.remove) export { ScheduleRoute } \ No newline at end of file From 6a471fca8caa461a26e78c8023ecd3b175ab4353 Mon Sep 17 00:00:00 2001 From: Luiz Filho Date: Sun, 22 Sep 2019 07:27:51 -0300 Subject: [PATCH 47/65] added interface and other types --- src/helpers/formatter.ts | 6 ++++-- src/http/controllers/customerController.ts | 8 ++++---- src/models/customer.ts | 7 +++++++ src/models/exam.ts | 5 +++++ src/models/schedule.ts | 7 +++++++ src/providers/exams.ts | 3 ++- src/services/customer.ts | 7 ++++--- src/services/exam.ts | 5 +++-- src/services/schedule.ts | 6 ++++-- 9 files changed, 40 insertions(+), 14 deletions(-) create mode 100644 src/models/customer.ts create mode 100644 src/models/exam.ts create mode 100644 src/models/schedule.ts diff --git a/src/helpers/formatter.ts b/src/helpers/formatter.ts index 60bbc59..eebfc07 100644 --- a/src/helpers/formatter.ts +++ b/src/helpers/formatter.ts @@ -1,6 +1,8 @@ +import { Exam } from "../models/exam"; + class Formatter { - public static extractFields(data: []) { - return data.map(({ id, name }: { id: Number, name: String}) => ({ id, name })) + public static extractFields(data: Exam[]): Exam[] { + return data.map(({ id, name }: Exam) => ({ id, name })) } } diff --git a/src/http/controllers/customerController.ts b/src/http/controllers/customerController.ts index 47555af..e908728 100644 --- a/src/http/controllers/customerController.ts +++ b/src/http/controllers/customerController.ts @@ -12,7 +12,7 @@ class CustomerController { this.find = this.find.bind(this) } - public save(request: Request, response: Response) { + public save(request: Request, response: Response): void { const customer = this.service.save(request.body) if (!customer.success) { @@ -21,7 +21,7 @@ class CustomerController { response.send(customer) } - public update(request: Request, response: Response) { + public update(request: Request, response: Response): void { const customer = this.service.update(request.body) if (!customer.success) { @@ -30,7 +30,7 @@ class CustomerController { response.send(customer) } - public remove(request: Request, response: Response) { + public remove(request: Request, response: Response): void { const customer = this.service.remove(request.params.cpf) if (!customer.success) { @@ -39,7 +39,7 @@ class CustomerController { response.send(customer) } - public find(request: Request, response: Response) { + public find(request: Request, response: Response): void { const customer = this.service.find(request.params.cpf) if (!customer.success) { diff --git a/src/models/customer.ts b/src/models/customer.ts new file mode 100644 index 0000000..6b7cc28 --- /dev/null +++ b/src/models/customer.ts @@ -0,0 +1,7 @@ +import * as moment from "moment" + +export interface Customer { + name: String + cpf: String + dateOfBirth: moment.Moment +} \ No newline at end of file diff --git a/src/models/exam.ts b/src/models/exam.ts new file mode 100644 index 0000000..7cd6ac2 --- /dev/null +++ b/src/models/exam.ts @@ -0,0 +1,5 @@ +export interface Exam { + id?: String + name: String + value?: Number +} \ No newline at end of file diff --git a/src/models/schedule.ts b/src/models/schedule.ts new file mode 100644 index 0000000..a3472fc --- /dev/null +++ b/src/models/schedule.ts @@ -0,0 +1,7 @@ +export interface Schedule { + id: Number + examId: String + cpf: String + date?: string + price?: Number +} \ No newline at end of file diff --git a/src/providers/exams.ts b/src/providers/exams.ts index e530a91..409087e 100644 --- a/src/providers/exams.ts +++ b/src/providers/exams.ts @@ -1,8 +1,9 @@ import request from 'request-promise-native' import formatter from '../helpers/formatter' +import { Exam } from '../models/exam' class ExamProvider { - static async list(): Promise { + static async list(): Promise { let exams = await request.get('http://www.mocky.io/v2/5d681ede33000054e7e65c3f') return formatter.extractFields(JSON.parse(exams.toString()).exams) } diff --git a/src/services/customer.ts b/src/services/customer.ts index bd5b9e7..ee9e2bf 100644 --- a/src/services/customer.ts +++ b/src/services/customer.ts @@ -1,4 +1,5 @@ import DB from '../../data/db' +import { Customer } from '../models/customer' class CustomerService { private connection: DB @@ -7,11 +8,11 @@ class CustomerService { this.connection = DB.connection() } - public save(data: any) { + public save(data: Customer) { return this.connection.addCustomer(data) } - public update(data: any): any { + public update(data: Customer): any { return this.connection.updateCustomer(data) } @@ -23,7 +24,7 @@ class CustomerService { return this.connection.findCustomer(cpf) } - public list() { + public list(): any { return this.connection.listCustomer() } } diff --git a/src/services/exam.ts b/src/services/exam.ts index 752e196..8016609 100644 --- a/src/services/exam.ts +++ b/src/services/exam.ts @@ -1,12 +1,13 @@ +import { Exam } from '../models/exam' import ExamProvider from '../providers/exams' class ExamsService { - public list() { + public list(): any { return ExamProvider.list() } - public async get(id: any): Promise { + public async get(id: String): Promise { return await ExamProvider.byId(id) } } diff --git a/src/services/schedule.ts b/src/services/schedule.ts index 95f3dcc..7f28530 100644 --- a/src/services/schedule.ts +++ b/src/services/schedule.ts @@ -2,6 +2,7 @@ import DB from '../../data/db' import ExamService from './exam' import CustomerService from './customer' import moment from 'moment' +import { Schedule } from '../models/schedule' class ScheduleService { private connection: DB @@ -14,7 +15,7 @@ class ScheduleService { this.customer = new CustomerService() } - public async save(data: any) { + public async save(data: Schedule) { let exam = await this.exam.get(data.examId.toString()) let customer = await this.customer.find(data.cpf) if (exam && customer.success) { @@ -22,7 +23,8 @@ class ScheduleService { const alreadyScheduled = this.connection.getByScheduleByDate(data.examId.toString(), formattedDate) if (!alreadyScheduled) { data.price = exam.value - data = { ...data, date: moment(data.date).format() } + formattedDate = moment(data.date).format() + data = { ...data, date: formattedDate } return this.connection.schedule({ ...data, examId: data.examId.toString() }) } } From e1370e3801e1353c38da5f4c923fcd291f0b9ce0 Mon Sep 17 00:00:00 2001 From: Luiz Filho Date: Sun, 22 Sep 2019 07:45:56 -0300 Subject: [PATCH 48/65] fixed route scedule by cpf --- src/http/controllers/scheduleController.ts | 8 ++++---- src/services/schedule.ts | 10 +++++----- 2 files changed, 9 insertions(+), 9 deletions(-) diff --git a/src/http/controllers/scheduleController.ts b/src/http/controllers/scheduleController.ts index 0aab8f4..eb2efbb 100644 --- a/src/http/controllers/scheduleController.ts +++ b/src/http/controllers/scheduleController.ts @@ -39,13 +39,13 @@ class ScheduleController { public async get(request: Request, response: Response): Promise { const result = await this.service.listByCpf(request.params.cpf) - if (!result.length) { + if (!result.schedules.length) { response.status(409) } return response.send({ - data: result.length ? result : null, - success: result.length ? true : false, - message: result.length ? 'data found successfully' : 'data search failed' + data: result.schedules.length ? result : null, + success: result.schedules.length ? true : false, + message: result.schedules.length ? 'data found successfully' : 'data search failed' }) } diff --git a/src/services/schedule.ts b/src/services/schedule.ts index 7f28530..842a6d0 100644 --- a/src/services/schedule.ts +++ b/src/services/schedule.ts @@ -32,13 +32,13 @@ class ScheduleService { } public listByCpf(cpf: String) { - let result: any = this.connection.getScheduleByCpf(cpf) + let schedules: any = this.connection.getScheduleByCpf(cpf) let pricesSum = 0 - if (result) { - pricesSum = result.reduce( (sum: Number, currentPrice: any) => sum + currentPrice.price, 0) - result = { result, total: pricesSum } + if (schedules) { + pricesSum = schedules.reduce( (sum: Number, currentPrice: any) => sum + currentPrice.price, 0) + schedules = { schedules, total: pricesSum } } - return result + return schedules } public async update(id: Number, date: any) { From 1021db780fc7d44757efc67bcdae34d53737c019 Mon Sep 17 00:00:00 2001 From: Luiz Filho Date: Sun, 22 Sep 2019 10:31:31 -0300 Subject: [PATCH 49/65] refactor with all routes --- data/db.ts | 12 ++++++------ package.json | 1 - src/http/controllers/customerController.ts | 4 ++-- src/http/controllers/examController.ts | 8 ++++---- src/http/controllers/index.ts | 1 + src/http/controllers/scheduleController.ts | 4 ++-- src/models/customer.ts | 8 +++----- src/models/exam.ts | 6 +++--- src/models/schedule.ts | 8 ++++---- src/providers/exams.ts | 2 +- src/routes/customer.ts | 2 +- src/routes/exam.ts | 7 ++++--- src/routes/schedule.ts | 11 ++++++----- src/services/customer.ts | 6 +++--- src/services/exam.ts | 6 +++--- src/services/index.ts | 3 +++ src/services/schedule.ts | 21 ++++++++++----------- tests/unit/customer/customer.spec.ts | 4 ++-- tests/unit/exam/schedule.spec.ts | 18 +++++++----------- tests/unit/utils/dataGenerate.ts | 4 ++-- 20 files changed, 67 insertions(+), 69 deletions(-) diff --git a/data/db.ts b/data/db.ts index a9a19a1..ed89652 100644 --- a/data/db.ts +++ b/data/db.ts @@ -15,7 +15,7 @@ class DB { return DB.instance } - public findCustomer(cpf: String) { + public findCustomer(cpf: string) { const customer = DB.customers.find( item => item.cpf === cpf) return { success: customer ? true: false, @@ -48,7 +48,7 @@ class DB { } } - public removeCustomer(cpf: String): any { + public removeCustomer(cpf: string): any { let customer = DB.customers.find( item => item.cpf === cpf ) if (customer) { @@ -81,7 +81,7 @@ class DB { return DB.schedules.find( item => item.cpf == data.cpf && item.examId === data.examId) } - public updateSchedule(id: Number, date: any): any { + public updateSchedule(id: number, date: any): any { let scheduleIndex = DB.schedules.findIndex( item => item.id === id) if (scheduleIndex > -1) { DB.schedules[scheduleIndex] = { ...DB.schedules[scheduleIndex] , date: date} @@ -94,15 +94,15 @@ class DB { } } - public getByScheduleByDate( examId: String, date: any ) { + public getByScheduleByDate( examId: string, date: any ) { return !!DB.schedules.find( item => item.examId === examId && item.date === date ) } - public getScheduleByCpf(cpf: String) { + public getScheduleByCpf(cpf: string) { return DB.schedules.filter(item => item.cpf === cpf) } - public removeSchedule(id: Number): any { + public removeSchedule(id: number): any { let schedule = DB.schedules.find( item => item.id === id ) if (schedule) { diff --git a/package.json b/package.json index 5726b5e..b52bdb9 100644 --- a/package.json +++ b/package.json @@ -33,7 +33,6 @@ "@types/swagger-ui-express": "^3.0.1", "express": "^4.17.1", "faker": "^4.1.0", - "moment": "^2.24.0", "request-promise-native": "^1.0.7", "swagger-ui-express": "^4.1.1" } diff --git a/src/http/controllers/customerController.ts b/src/http/controllers/customerController.ts index e908728..06c2406 100644 --- a/src/http/controllers/customerController.ts +++ b/src/http/controllers/customerController.ts @@ -1,5 +1,5 @@ import { Request, Response } from 'express' -import CustomerService from '../../services/customer' +import { CustomerService } from '../../services/index' class CustomerController { private service: CustomerService @@ -49,4 +49,4 @@ class CustomerController { } } -export default CustomerController \ No newline at end of file +export { CustomerController } \ No newline at end of file diff --git a/src/http/controllers/examController.ts b/src/http/controllers/examController.ts index 4536ee9..221e9b4 100644 --- a/src/http/controllers/examController.ts +++ b/src/http/controllers/examController.ts @@ -1,12 +1,12 @@ import { Request, Response } from 'express' -import ExamsService from '../../services/exam' +import { ExamService } from '../../services/index' class ExamController { - private service: ExamsService + private service: ExamService public constructor () { - this.service = new ExamsService() + this.service = new ExamService() this.list = this.list.bind(this) this.get = this.get.bind(this) } @@ -22,4 +22,4 @@ class ExamController { } } -export default new ExamController() \ No newline at end of file +export { ExamController } \ No newline at end of file diff --git a/src/http/controllers/index.ts b/src/http/controllers/index.ts index 98ceca2..e5f9c12 100644 --- a/src/http/controllers/index.ts +++ b/src/http/controllers/index.ts @@ -1,2 +1,3 @@ export * from './examController' export * from './customerController' +export * from './scheduleController' diff --git a/src/http/controllers/scheduleController.ts b/src/http/controllers/scheduleController.ts index eb2efbb..569ef14 100644 --- a/src/http/controllers/scheduleController.ts +++ b/src/http/controllers/scheduleController.ts @@ -1,5 +1,5 @@ import { Request, Response } from 'express' -import ScheduleService from '../../services/schedule' +import { ScheduleService } from '../../services/index' class ScheduleController { @@ -58,4 +58,4 @@ class ScheduleController { } } -export default new ScheduleController() \ No newline at end of file +export { ScheduleController } \ No newline at end of file diff --git a/src/models/customer.ts b/src/models/customer.ts index 6b7cc28..a189d6c 100644 --- a/src/models/customer.ts +++ b/src/models/customer.ts @@ -1,7 +1,5 @@ -import * as moment from "moment" - export interface Customer { - name: String - cpf: String - dateOfBirth: moment.Moment + name?: string + cpf?: string + dateOfBirth?: string } \ No newline at end of file diff --git a/src/models/exam.ts b/src/models/exam.ts index 7cd6ac2..3456333 100644 --- a/src/models/exam.ts +++ b/src/models/exam.ts @@ -1,5 +1,5 @@ export interface Exam { - id?: String - name: String - value?: Number + id?: string + name: string + value?: number } \ No newline at end of file diff --git a/src/models/schedule.ts b/src/models/schedule.ts index a3472fc..8900b41 100644 --- a/src/models/schedule.ts +++ b/src/models/schedule.ts @@ -1,7 +1,7 @@ export interface Schedule { - id: Number - examId: String - cpf: String + id?: number + examId: string + cpf: string date?: string - price?: Number + price?: number } \ No newline at end of file diff --git a/src/providers/exams.ts b/src/providers/exams.ts index 409087e..19a6e22 100644 --- a/src/providers/exams.ts +++ b/src/providers/exams.ts @@ -8,7 +8,7 @@ class ExamProvider { return formatter.extractFields(JSON.parse(exams.toString()).exams) } - static async byId(id: String): Promise { + static async byId(id: string): Promise { let exams = await request.get('http://www.mocky.io/v2/5d681ede33000054e7e65c3f') let formatted = JSON.parse(exams.toString()).exams return formatted.find( (item: any) => item.id === id) diff --git a/src/routes/customer.ts b/src/routes/customer.ts index 80d268c..42d50b9 100644 --- a/src/routes/customer.ts +++ b/src/routes/customer.ts @@ -1,5 +1,5 @@ import { Router } from 'express' -import CustomerController from '../http/controllers/customerController' +import { CustomerController } from '../http/controllers/index' const CustomerRoutes = Router() const controller = new CustomerController() diff --git a/src/routes/exam.ts b/src/routes/exam.ts index 253d742..b29608e 100644 --- a/src/routes/exam.ts +++ b/src/routes/exam.ts @@ -1,9 +1,10 @@ import { Router } from 'express' const ExamRoutes = Router() -import ExamController from '../http/controllers/examController' +import { ExamController } from '../http/controllers/examController' +const examController = new ExamController() -ExamRoutes.get('/exams', ExamController.list) -ExamRoutes.get('/exams/:id', ExamController.get) +ExamRoutes.get('/exams', examController.list) +ExamRoutes.get('/exams/:id', examController.get) export { ExamRoutes } \ No newline at end of file diff --git a/src/routes/schedule.ts b/src/routes/schedule.ts index 70e1e08..e3324c8 100644 --- a/src/routes/schedule.ts +++ b/src/routes/schedule.ts @@ -1,11 +1,12 @@ import { Router } from 'express' const ScheduleRoute = Router() -import ScheduleController from '../http/controllers/scheduleController' +import { ScheduleController } from '../http/controllers/scheduleController' +const scheduleController = new ScheduleController -ScheduleRoute.post('/schedules', ScheduleController.schedule) -ScheduleRoute.put('/schedules/:id', ScheduleController.update) -ScheduleRoute.get('/schedules/:cpf', ScheduleController.get) -ScheduleRoute.delete('/schedules/:id', ScheduleController.remove) +ScheduleRoute.post('/schedules', scheduleController.schedule) +ScheduleRoute.put('/schedules/:id', scheduleController.update) +ScheduleRoute.get('/schedules/:cpf', scheduleController.get) +ScheduleRoute.delete('/schedules/:id', scheduleController.remove) export { ScheduleRoute } \ No newline at end of file diff --git a/src/services/customer.ts b/src/services/customer.ts index ee9e2bf..3eb57b1 100644 --- a/src/services/customer.ts +++ b/src/services/customer.ts @@ -16,11 +16,11 @@ class CustomerService { return this.connection.updateCustomer(data) } - public remove(cpf: String): any { + public remove(cpf: string): any { return this.connection.removeCustomer(cpf) } - public find(cpf: String): any { + public find(cpf: string): any { return this.connection.findCustomer(cpf) } @@ -29,4 +29,4 @@ class CustomerService { } } -export default CustomerService \ No newline at end of file +export { CustomerService } \ No newline at end of file diff --git a/src/services/exam.ts b/src/services/exam.ts index 8016609..1d63d4e 100644 --- a/src/services/exam.ts +++ b/src/services/exam.ts @@ -1,15 +1,15 @@ import { Exam } from '../models/exam' import ExamProvider from '../providers/exams' -class ExamsService { +class ExamService { public list(): any { return ExamProvider.list() } - public async get(id: String): Promise { + public async get(id: string): Promise { return await ExamProvider.byId(id) } } -export default ExamsService \ No newline at end of file +export { ExamService } \ No newline at end of file diff --git a/src/services/index.ts b/src/services/index.ts index e69de29..3417390 100644 --- a/src/services/index.ts +++ b/src/services/index.ts @@ -0,0 +1,3 @@ +export * from './customer' +export * from './exam' +export * from './schedule' \ No newline at end of file diff --git a/src/services/schedule.ts b/src/services/schedule.ts index 842a6d0..40e13c2 100644 --- a/src/services/schedule.ts +++ b/src/services/schedule.ts @@ -1,7 +1,6 @@ import DB from '../../data/db' -import ExamService from './exam' -import CustomerService from './customer' -import moment from 'moment' +import { ExamService } from './index' +import { CustomerService } from './index' import { Schedule } from '../models/schedule' class ScheduleService { @@ -19,11 +18,11 @@ class ScheduleService { let exam = await this.exam.get(data.examId.toString()) let customer = await this.customer.find(data.cpf) if (exam && customer.success) { - let formattedDate = moment(data.date).format() + let formattedDate = data.date const alreadyScheduled = this.connection.getByScheduleByDate(data.examId.toString(), formattedDate) if (!alreadyScheduled) { data.price = exam.value - formattedDate = moment(data.date).format() + formattedDate = data.date data = { ...data, date: formattedDate } return this.connection.schedule({ ...data, examId: data.examId.toString() }) } @@ -31,24 +30,24 @@ class ScheduleService { return null } - public listByCpf(cpf: String) { + public listByCpf(cpf: string) { let schedules: any = this.connection.getScheduleByCpf(cpf) let pricesSum = 0 if (schedules) { - pricesSum = schedules.reduce( (sum: Number, currentPrice: any) => sum + currentPrice.price, 0) + pricesSum = schedules.reduce( (sum: number, currentPrice: any) => sum + currentPrice.price, 0) schedules = { schedules, total: pricesSum } } return schedules } - public async update(id: Number, date: any) { - let formattedDate = moment(date).format() + public async update(id: number, date: any) { + let formattedDate = date return this.connection.updateSchedule(id, formattedDate) } - public async remove(id: Number) { + public async remove(id: number) { return this.connection.removeSchedule(id) } } -export default ScheduleService \ No newline at end of file +export { ScheduleService } \ No newline at end of file diff --git a/tests/unit/customer/customer.spec.ts b/tests/unit/customer/customer.spec.ts index 798b68f..d20f664 100644 --- a/tests/unit/customer/customer.spec.ts +++ b/tests/unit/customer/customer.spec.ts @@ -1,11 +1,11 @@ import DB from '../../../data/db' -import CustomerService from '../../../src/services/customer' +import { CustomerService } from '../../../src/services/index' import { getCpf, fullName, getDate } from '../utils/dataGenerate' let customer = { cpf: '', name: '', - dateOfBirth: new Date() + dateOfBirth: '' } let service = new CustomerService() diff --git a/tests/unit/exam/schedule.spec.ts b/tests/unit/exam/schedule.spec.ts index c99a6b3..4ad9acf 100644 --- a/tests/unit/exam/schedule.spec.ts +++ b/tests/unit/exam/schedule.spec.ts @@ -1,8 +1,7 @@ import request from 'request-promise-native' import DB from '../../../data/db' import { fullName, getCpf, getDate, getFutureDate, getExamsMock } from '../utils/dataGenerate' -import ScheduleService from '../../../src/services/schedule' -import moment from 'moment' +import { ScheduleService } from '../../../src/services/index' jest.mock('request-promise-native') const mockedAxios = request as jest.Mocked @@ -36,7 +35,7 @@ describe('Scheduling exam', () => { const data = { examId: (Math.floor(Math.random() * 3) + 1).toString(), cpf: customer.cpf, - date: moment(getFutureDate()).format() + date: getFutureDate() } mockedAxios.get.mockResolvedValue(examsMock) let examResult = await scheduleService.save(data) @@ -59,7 +58,7 @@ describe('Scheduling exam', () => { const data = { examId: (Math.floor(Math.random() * 3) + 1).toString(), cpf: customer.cpf, - date: moment(getFutureDate()).format() + date: getFutureDate() } mockedAxios.get.mockResolvedValue(examsMock) await scheduleService.save(data) @@ -80,7 +79,7 @@ describe('Scheduling exam', () => { const data = { examId: (Math.floor(Math.random() * 3) + 1).toString(), cpf: customer.cpf, - date: moment(getFutureDate()).format() + date: getFutureDate() } let saved = await scheduleService.save(data) sum += saved.price @@ -93,16 +92,13 @@ describe('Scheduling exam', () => { const data = { examId: (Math.floor(Math.random() * 3) + 1).toString(), cpf: customer.cpf, - date: moment(getFutureDate()).format() + date: getFutureDate() } mockedAxios.get.mockResolvedValue(examsMock) let examResult = await scheduleService.save(data) const { id } = examResult - - const newDate = moment(getFutureDate()).format() - + const newDate = getFutureDate() let updatedSchedule = await scheduleService.update(id, newDate) - expect(updatedSchedule.data.date).toEqual(newDate) }) @@ -110,7 +106,7 @@ describe('Scheduling exam', () => { const data = { examId: (Math.floor(Math.random() * 3) + 1).toString(), cpf: customer.cpf, - date: moment(getFutureDate()).format() + date: getFutureDate() } mockedAxios.get.mockResolvedValue(examsMock) let examResult = await scheduleService.save(data) diff --git a/tests/unit/utils/dataGenerate.ts b/tests/unit/utils/dataGenerate.ts index 0759a00..95da096 100644 --- a/tests/unit/utils/dataGenerate.ts +++ b/tests/unit/utils/dataGenerate.ts @@ -4,9 +4,9 @@ const getCpf = () => Faker.random.number({ 'min': 100000000,'max': 999999999 }) const fullName = () => Faker.name.firstName() + ' ' + Faker.name.lastName() -const getDate = () => Faker.date.between('1920-01-01', '2019-09-01') +const getDate = () => Faker.date.between('1920-01-01', '2019-09-01').toString() -const getFutureDate = () => Faker.date.between(new Date(), '2020-12-31') +const getFutureDate = () => new Date(+(new Date()) - Math.floor(Math.random()*10000000000)).toString() const getExamsMock = () => '{"exams": [{"id":"1","name":"17 soro","value":35.60},{"id":"2","name":"Acidificação Urinária","value":84.90},{"id":"3","name":"Ácido Ascórbico, plasma","value":99.90}]}' From 30c76ccc7e025248ed17ffb5b3c5341a92d5ca34 Mon Sep 17 00:00:00 2001 From: Luiz Filho Date: Sun, 22 Sep 2019 10:35:07 -0300 Subject: [PATCH 50/65] added package-lock --- .gitignore | 1 - package-lock.json | 3143 ++++++++++++++++++++++++++++++++++++++++++++- 2 files changed, 3106 insertions(+), 38 deletions(-) diff --git a/.gitignore b/.gitignore index a049075..b7dab5e 100644 --- a/.gitignore +++ b/.gitignore @@ -1,3 +1,2 @@ node_modules -package-lock.json build \ No newline at end of file diff --git a/package-lock.json b/package-lock.json index 4f68a63..82f4e60 100644 --- a/package-lock.json +++ b/package-lock.json @@ -4,6 +4,466 @@ "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.0", + "resolved": "https://registry.npmjs.org/@babel/core/-/core-7.6.0.tgz", + "integrity": "sha512-FuRhDRtsd6IptKpHXAa+4WPZYY2ZzgowkbLBecEDDSje1X/apG7jQM33or3NdOmjXBKWGOg4JmSiRfUfuTtHXw==", + "dev": true, + "requires": { + "@babel/code-frame": "^7.5.5", + "@babel/generator": "^7.6.0", + "@babel/helpers": "^7.6.0", + "@babel/parser": "^7.6.0", + "@babel/template": "^7.6.0", + "@babel/traverse": "^7.6.0", + "@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 + } + } + }, + "@babel/generator": { + "version": "7.6.0", + "resolved": "https://registry.npmjs.org/@babel/generator/-/generator-7.6.0.tgz", + "integrity": "sha512-Ms8Mo7YBdMMn1BYuNtKuP/z0TgEIhbcyB8HVR6PPNYp4P61lMsABiS4A3VG1qznjXVCf3r+fVHhm4efTYVsySA==", + "dev": true, + "requires": { + "@babel/types": "^7.6.0", + "jsesc": "^2.5.1", + "lodash": "^4.17.13", + "source-map": "^0.5.0", + "trim-right": "^1.0.1" + } + }, + "@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.0", + "resolved": "https://registry.npmjs.org/@babel/helpers/-/helpers-7.6.0.tgz", + "integrity": "sha512-W9kao7OBleOjfXtFGgArGRX6eCP0UEcA2ZWEWNkJdRZnHhW4eEbeswbG3EwaRsnQUAEGWYgMq1HsIXuNNNy2eQ==", + "dev": true, + "requires": { + "@babel/template": "^7.6.0", + "@babel/traverse": "^7.6.0", + "@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.0", + "resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.6.0.tgz", + "integrity": "sha512-+o2q111WEx4srBs7L9eJmcwi655eD8sXniLqMB93TBK9GrNzGrxDWSjiqz2hLU0Ha8MTXFIP0yd9fNdP+m43ZQ==", + "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.0", + "resolved": "https://registry.npmjs.org/@babel/traverse/-/traverse-7.6.0.tgz", + "integrity": "sha512-93t52SaOBgml/xY74lsmt7xOR4ufYvhb5c5qiM6lu4J/dWGMAfAh6eKw4PjLes6DI6nQgearoxnFJk60YchpvQ==", + "dev": true, + "requires": { + "@babel/code-frame": "^7.5.5", + "@babel/generator": "^7.6.0", + "@babel/helper-function-name": "^7.1.0", + "@babel/helper-split-export-declaration": "^7.4.4", + "@babel/parser": "^7.6.0", + "@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" + }, + "dependencies": { + "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 + }, + "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" + } + } + } + }, + "@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" + }, + "dependencies": { + "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 + } + } + }, + "@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" + }, + "dependencies": { + "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 + } + } + }, + "@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" + }, + "dependencies": { + "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 + }, + "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" + } + } + } + }, + "@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" + } + }, + "@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.0.2", + "resolved": "https://registry.npmjs.org/@types/babel__generator/-/babel__generator-7.0.2.tgz", + "integrity": "sha512-NHcOfab3Zw4q5sEE2COkpfXjoE7o+PmqD9DQW4koUT3roNxwziUdXGnRndMat/LJNUtePwn1TlP4do3uoe3KZQ==", + "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", @@ -13,6 +473,11 @@ "@types/node": "*" } }, + "@types/caseless": { + "version": "0.12.2", + "resolved": "https://registry.npmjs.org/@types/caseless/-/caseless-0.12.2.tgz", + "integrity": "sha512-6ckxMjBBD8URvjB6J3NcnuAn5Pkl7t3TizAg+xdlzzQGSPSmBcXf8KoIH0ua/i+tio+ZRUHEXp0HEmvaR4kt0w==" + }, "@types/connect": { "version": "3.4.32", "resolved": "https://registry.npmjs.org/@types/connect/-/connect-3.4.32.tgz", @@ -40,6 +505,51 @@ "@types/range-parser": "*" } }, + "@types/faker": { + "version": "4.1.5", + "resolved": "https://registry.npmjs.org/@types/faker/-/faker-4.1.5.tgz", + "integrity": "sha512-YSDqoBEWYGdNk53xSkkb6REaUaVSlIjxIAGjj/nbLzlZOit7kUU+nA2zC2qQkIVO4MQ+3zl4Sz7aw+kbpHHHUQ==" + }, + "@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", @@ -55,6 +565,37 @@ "resolved": "https://registry.npmjs.org/@types/range-parser/-/range-parser-1.2.3.tgz", "integrity": "sha512-ewFXqrQHlFsgc09MK5jP5iR7vumV/BYayNC6PgJO2LPe8vrnNFyjQjSppfEngITi0qvfKtzFvgKymGheFM9UOA==" }, + "@types/request": { + "version": "2.48.3", + "resolved": "https://registry.npmjs.org/@types/request/-/request-2.48.3.tgz", + "integrity": "sha512-3Wo2jNYwqgXcIz/rrq18AdOZUQB8cQ34CXZo+LUwPJNpvRAL86+Kc2wwI8mqpz9Cr1V+enIox5v+WZhy/p3h8w==", + "requires": { + "@types/caseless": "*", + "@types/node": "*", + "@types/tough-cookie": "*", + "form-data": "^2.5.0" + }, + "dependencies": { + "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" + } + } + } + }, + "@types/request-promise-native": { + "version": "1.0.16", + "resolved": "https://registry.npmjs.org/@types/request-promise-native/-/request-promise-native-1.0.16.tgz", + "integrity": "sha512-gbLf6cg1XGBU8BObOgs5VkCQo5JFz2GstgZjyE4FRbig/jiCEdiynu2fCzJlw3qYPuoj59spKnvuRLN4PsMvhA==", + "requires": { + "@types/request": "*" + } + }, "@types/serve-static": { "version": "1.13.3", "resolved": "https://registry.npmjs.org/@types/serve-static/-/serve-static-1.13.3.tgz", @@ -64,6 +605,12 @@ "@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/strip-bom": { "version": "3.0.0", "resolved": "https://registry.npmjs.org/@types/strip-bom/-/strip-bom-3.0.0.tgz", @@ -85,6 +632,32 @@ "@types/serve-static": "*" } }, + "@types/tough-cookie": { + "version": "2.3.5", + "resolved": "https://registry.npmjs.org/@types/tough-cookie/-/tough-cookie-2.3.5.tgz", + "integrity": "sha512-SCcK7mvGi3+ZNz833RRjFIxrn4gI1PPR3NtuIS+6vMkvmsGjosqTJwRt5bAEFLRz+wtJMWv8+uOnZf2hi2QXTg==" + }, + "@types/yargs": { + "version": "13.0.2", + "resolved": "https://registry.npmjs.org/@types/yargs/-/yargs-13.0.2.tgz", + "integrity": "sha512-lwwgizwk/bIIU+3ELORkyuOgDjCh7zuWDFqRtPPhhVgq9N1F7CvLNKg1TX4f2duwtKQ0p044Au9r1PLIXHrIzQ==", + "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.1", + "resolved": "https://registry.npmjs.org/abab/-/abab-2.0.1.tgz", + "integrity": "sha512-1zSbbCuoIjafKZ3mblY5ikvAb0ODUbqBnFuUb7f6uLeQhhGJ0vEV4ntmtxKLT2WgXCO94E07BjunsIw1jOMPZw==", + "dev": true + }, "abbrev": { "version": "1.1.1", "resolved": "https://registry.npmjs.org/abbrev/-/abbrev-1.1.1.tgz", @@ -100,6 +673,48 @@ "negotiator": "0.6.2" } }, + "acorn": { + "version": "5.7.3", + "resolved": "https://registry.npmjs.org/acorn/-/acorn-5.7.3.tgz", + "integrity": "sha512-T/zvzYRfbVojPWahDsE5evJdHb3oJoQfFbsrKM7w5Zcs++Tr257tia3BmMP8XYVjp1S9RZXQMh7gao96BlqZOw==", + "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.3.0", + "resolved": "https://registry.npmjs.org/acorn/-/acorn-6.3.0.tgz", + "integrity": "sha512-/czfa8BwS88b9gWQVhc8eknunSA2DoJpJyTQkhheIf5E48u1N0R4q/YxxsAeqRrmK9TQ/uYfgLDfZo91UlANIA==", + "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-align": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/ansi-align/-/ansi-align-2.0.0.tgz", @@ -109,6 +724,12 @@ "string-width": "^2.0.0" } }, + "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": "3.0.0", "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-3.0.0.tgz", @@ -169,6 +790,12 @@ "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-find-index": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/array-find-index/-/array-find-index-1.0.2.tgz", @@ -186,10 +813,31 @@ "integrity": "sha1-qJS3XUvE9s1nnvMkSp/Y9Gri1Cg=", "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=", + "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-each": { @@ -198,12 +846,92 @@ "integrity": "sha512-z/WhQ5FPySLdvREByI2vZiTWwCnF0moMJ1hK9YQwDTHKh6I7/uSckMetoRGb5UBZPC1z0jlw+n/XCgjeH7y1AQ==", "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 + }, + "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" + }, + "dependencies": { + "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" + } + } + } + }, + "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", @@ -265,6 +993,15 @@ } } }, + "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" + } + }, "binary-extensions": { "version": "1.13.1", "resolved": "https://registry.npmjs.org/binary-extensions/-/binary-extensions-1.13.1.tgz", @@ -352,6 +1089,47 @@ } } }, + "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", @@ -380,6 +1158,12 @@ "unset-value": "^1.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": "4.1.0", "resolved": "https://registry.npmjs.org/camelcase/-/camelcase-4.1.0.tgz", @@ -404,12 +1188,27 @@ } } }, + "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" + } + }, "capture-stack-trace": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/capture-stack-trace/-/capture-stack-trace-1.0.1.tgz", "integrity": "sha512-mYQLZnx5Qt1JgB1WEiMCf2647plpGeQ2NMR/5L0HNZzGQo4fuSPnK+wjfPnKZV0aiJDgzmWqqkV/g7JD+DW0qw==", "dev": true }, + "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", @@ -476,6 +1275,51 @@ "integrity": "sha1-T6kXw+WclKAEzWH47lCdplFocUM=", "dev": true }, + "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" + }, + "dependencies": { + "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 + }, + "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" + } + }, + "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" + } + } + } + }, + "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", @@ -501,6 +1345,21 @@ "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, + "optional": true + }, "component-emitter": { "version": "1.3.0", "resolved": "https://registry.npmjs.org/component-emitter/-/component-emitter-1.3.0.tgz", @@ -540,6 +1399,15 @@ "resolved": "https://registry.npmjs.org/content-type/-/content-type-1.0.4.tgz", "integrity": "sha512-hIP3EEPs8tB9AT1L+NUqtwOAps4mk2Zob89MWXMHjHWg9milF/j4osnnQLXBCBFBk/tvIG/tUc9mOUJiPBhPXA==" }, + "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", @@ -588,6 +1456,21 @@ "integrity": "sha1-ojD2T1aDEOFJgAmUB5DsmVRbyn4=", "dev": true }, + "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" + } + }, "currently-unhandled": { "version": "0.4.1", "resolved": "https://registry.npmjs.org/currently-unhandled/-/currently-unhandled-0.4.1.tgz", @@ -597,6 +1480,39 @@ "array-find-index": "^1.0.1" } }, + "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" + } + } + } + }, "dateformat": { "version": "1.0.12", "resolved": "https://registry.npmjs.org/dateformat/-/dateformat-1.0.12.tgz", @@ -648,6 +1564,21 @@ "integrity": "sha512-LOHxIOaPYdHlJRtCQfDIVZtfw/ufM8+rVj649RIHzcm/vGwQRXFt6OPqIFWsm2XEMrNIEtWR64sY1LEKD2vAOA==", "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", @@ -689,6 +1620,11 @@ } } }, + "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", @@ -699,12 +1635,33 @@ "resolved": "https://registry.npmjs.org/destroy/-/destroy-1.0.4.tgz", "integrity": "sha1-l4hXRCxEdJ5CBmE+N5RiBYJqvYA=" }, + "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 + }, "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" + } + }, "dot-prop": { "version": "4.2.0", "resolved": "https://registry.npmjs.org/dot-prop/-/dot-prop-4.2.0.tgz", @@ -729,16 +1686,41 @@ "xtend": "^4.0.0" } }, + "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=" }, + "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=" }, + "end-of-stream": { + "version": "1.4.1", + "resolved": "https://registry.npmjs.org/end-of-stream/-/end-of-stream-1.4.1.tgz", + "integrity": "sha512-1MkrZNvWTKCaigbn+W15elq2BB/L22nqrSY5DKlo3X6+vclJm8Bb5djXJBmEX6fS3+zCh/F4VBK5Z2KxJt4s2Q==", + "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", @@ -748,6 +1730,35 @@ "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", @@ -759,11 +1770,57 @@ "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" + }, + "dependencies": { + "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, + "optional": true + } + } + }, + "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=" }, + "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": "0.7.0", "resolved": "https://registry.npmjs.org/execa/-/execa-0.7.0.tgz", @@ -779,6 +1836,12 @@ "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", @@ -823,6 +1886,20 @@ } } }, + "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", @@ -870,6 +1947,12 @@ } } }, + "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", @@ -956,6 +2039,44 @@ } } }, + "extsprintf": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/extsprintf/-/extsprintf-1.3.0.tgz", + "integrity": "sha1-lpGEQOMEGnpBT4xS48V06zw+HgU=", + "dev": true + }, + "faker": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/faker/-/faker-4.1.0.tgz", + "integrity": "sha1-HkW7vsxndLPBlfrSg1EJxtdIzD8=" + }, + "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" + } + }, "filewatcher": { "version": "3.0.1", "resolved": "https://registry.npmjs.org/filewatcher/-/filewatcher-3.0.1.tgz", @@ -1028,6 +2149,23 @@ "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.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" + } + }, "forwarded": { "version": "0.1.2", "resolved": "https://registry.npmjs.org/forwarded/-/forwarded-0.1.2.tgz", @@ -1601,6 +2739,18 @@ } } }, + "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": "4.0.1", "resolved": "https://registry.npmjs.org/get-stdin/-/get-stdin-4.0.1.tgz", @@ -1619,6 +2769,15 @@ "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", @@ -1663,6 +2822,12 @@ "ini": "^1.3.4" } }, + "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 + }, "got": { "version": "6.7.1", "resolved": "https://registry.npmjs.org/got/-/got-6.7.1.tgz", @@ -1694,15 +2859,66 @@ "integrity": "sha1-8QdIy+dq+WS3yWyTxrzCivEgwIE=", "dev": true }, - "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-value": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/has-value/-/has-value-1.0.0.tgz", + "handlebars": { + "version": "4.2.0", + "resolved": "https://registry.npmjs.org/handlebars/-/handlebars-4.2.0.tgz", + "integrity": "sha512-Kb4xn5Qh1cxAKvQnzNWZ512DhABzyFNmsaJf3OAkWNa4NkaqWcNI8Tao8Tasi0/F4JD9oyG0YxuFyvyR57d+Gw==", + "dev": true, + "requires": { + "neo-async": "^2.6.0", + "optimist": "^0.6.1", + "source-map": "^0.6.1", + "uglify-js": "^3.1.4" + }, + "dependencies": { + "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 + } + } + }, + "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": { @@ -1738,6 +2954,15 @@ "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", @@ -1757,6 +2982,17 @@ } } }, + "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" + } + }, "iconv-lite": { "version": "0.4.24", "resolved": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.4.24.tgz", @@ -1777,6 +3013,16 @@ "integrity": "sha1-BWmOPUXIjo1+nZLLBYTnfwlvPkM=", "dev": true }, + "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", @@ -1814,6 +3060,15 @@ "integrity": "sha512-RZY5huIKCMRWDUqZlEi72f/lmXKMvuszcMBduliQ3nnWbx9X/ZBQO7DijMEYS9EhHBb2qacRUMtC7svLwe0lcw==", "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", @@ -1860,6 +3115,12 @@ "integrity": "sha512-NcdALwpXkTm5Zvvbk7owOUSvVvBKDgKP5/ewfXEznmQFfs4ZRmanOeKBTjRVjka3QFoN6XJ+9F3USqfHqTaU5w==", "dev": true }, + "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": "1.2.1", "resolved": "https://registry.npmjs.org/is-ci/-/is-ci-1.2.1.tgz", @@ -1889,6 +3150,12 @@ } } }, + "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", @@ -1935,6 +3202,12 @@ "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-glob": { "version": "4.0.1", "resolved": "https://registry.npmjs.org/is-glob/-/is-glob-4.0.1.tgz", @@ -2010,6 +3283,15 @@ "integrity": "sha1-HQPd7VO9jbDzDCbk+V02/HyH3CQ=", "dev": true }, + "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-retry-allowed": { "version": "1.2.0", "resolved": "https://registry.npmjs.org/is-retry-allowed/-/is-retry-allowed-1.2.0.tgz", @@ -2022,48 +3304,819 @@ "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-utf8": { "version": "0.2.1", "resolved": "https://registry.npmjs.org/is-utf8/-/is-utf8-0.2.1.tgz", "integrity": "sha1-Sw2hRCEE0bM2NA6AeX6GXPOffXI=", "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==", + "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": { + "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" + } + }, + "pify": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/pify/-/pify-4.0.1.tgz", + "integrity": "sha512-uB80kBFb/tfd68bVleG9T5GGsGPjJrLAUpR5PZIrhBnIaRTQRjqdJSsIKkOP6OAIFbj7GOrcudc5pNjZ+geV2g==", + "dev": true + }, + "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" + } + }, + "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" + } + }, + "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 + }, + "pify": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/pify/-/pify-4.0.1.tgz", + "integrity": "sha512-uB80kBFb/tfd68bVleG9T5GGsGPjJrLAUpR5PZIrhBnIaRTQRjqdJSsIKkOP6OAIFbj7GOrcudc5pNjZ+geV2g==", + "dev": true + }, + "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 + } + } + }, + "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": { + "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 + }, + "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" + } + }, + "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" + }, + "dependencies": { + "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" + } + }, + "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" + } + }, + "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" + } + } + } + }, + "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" + }, + "dependencies": { + "strip-bom": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/strip-bom/-/strip-bom-3.0.0.tgz", + "integrity": "sha1-IzTBjpx1n3vdVv3vfprj1YjmjtM=", + "dev": true + } + } + }, + "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" + }, + "dependencies": { + "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 + }, + "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" + } + }, + "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 + } + } + }, + "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" + }, + "dependencies": { + "camelcase": { + "version": "5.3.1", + "resolved": "https://registry.npmjs.org/camelcase/-/camelcase-5.3.1.tgz", + "integrity": "sha512-L28STB170nwWS63UjtlEOE3dldQApaJXZkOI1uMFfzf3rRuPegHaHesyee+YxQ+W6SvRDQV6UrdOdRiR153wJg==", + "dev": true + } + } + }, + "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 + }, + "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 }, - "is-wsl": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/is-wsl/-/is-wsl-1.1.0.tgz", - "integrity": "sha1-HxbkqiKwTRM2tmGIpmrzxgDDpm0=", + "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 }, - "isarray": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/isarray/-/isarray-1.0.0.tgz", - "integrity": "sha1-u5NdSFgsuhaMBoNJV6VKPgcSTxE=", + "json-schema": { + "version": "0.2.3", + "resolved": "https://registry.npmjs.org/json-schema/-/json-schema-0.2.3.tgz", + "integrity": "sha1-tIDIkuWaLwWVTOcnvT8qTogvnhM=", "dev": true }, - "isexe": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/isexe/-/isexe-2.0.0.tgz", - "integrity": "sha1-6PvzdNxVb/iUehDcsFctYz8s+hA=", + "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 }, - "isobject": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/isobject/-/isobject-3.0.1.tgz", - "integrity": "sha1-TkMekrEalzFjaqH5yNHMvP2reN8=", + "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 + }, "latest-version": { "version": "3.1.0", "resolved": "https://registry.npmjs.org/latest-version/-/latest-version-3.1.0.tgz", @@ -2073,6 +4126,28 @@ "package-json": "^4.0.0" } }, + "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" + } + }, "load-json-file": { "version": "1.1.0", "resolved": "https://registry.npmjs.org/load-json-file/-/load-json-file-1.1.0.tgz", @@ -2094,6 +4169,50 @@ } } }, + "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" + }, + "dependencies": { + "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 + } + } + }, + "lodash": { + "version": "4.17.15", + "resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.15.tgz", + "integrity": "sha512-8xOcRHvCjnocdS5cpwXQXVzmmh5e5+saE2QGoeQmbKmRS6J3VQppPOIt0MnmE+4xlZoumy0GPG0D0MVIQbNA1A==" + }, + "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" + } + }, "loud-rejection": { "version": "1.6.0", "resolved": "https://registry.npmjs.org/loud-rejection/-/loud-rejection-1.6.0.tgz", @@ -2135,6 +4254,15 @@ "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", @@ -2184,6 +4312,12 @@ "resolved": "https://registry.npmjs.org/merge-descriptors/-/merge-descriptors-1.0.1.tgz", "integrity": "sha1-sAqqVW3YtEVoFQ7J0blT8/kMu2E=" }, + "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", @@ -2312,11 +4446,41 @@ "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==" }, + "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", @@ -2390,6 +4554,18 @@ "integrity": "sha1-CXtgK1NCKlIsGvuHkDGDNpQaAR0=", "dev": true }, + "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", @@ -2427,6 +4603,18 @@ } } }, + "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", @@ -2436,6 +4624,16 @@ "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", @@ -2462,12 +4660,91 @@ "wrappy": "1" } }, + "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 + }, "package-json": { "version": "4.0.1", "resolved": "https://registry.npmjs.org/package-json/-/package-json-4.0.1.tgz", @@ -2489,6 +4766,12 @@ "error-ex": "^1.2.0" } }, + "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", @@ -2563,6 +4846,12 @@ } } }, + "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", @@ -2584,24 +4873,95 @@ "pinkie": "^2.0.0" } }, + "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" + }, + "dependencies": { + "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" + } + } + } + }, + "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 + }, "prepend-http": { "version": "1.0.4", "resolved": "https://registry.npmjs.org/prepend-http/-/prepend-http-1.0.4.tgz", "integrity": "sha1-1PRWKwzjaW5BrFLQ4ALlemNdxtw=", "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" + }, + "dependencies": { + "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 + } + } + }, "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", @@ -2617,12 +4977,32 @@ "integrity": "sha1-8FKijacOYYkX7wqKw0wa5aaChrM=", "dev": true }, + "psl": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/psl/-/psl-1.4.0.tgz", + "integrity": "sha512-HZzqCGPecFLyoRj5HLfuDSKYTJkAfB5thKBIkRHtGjWwY7p1dAyveIbXIq4tO0KYfDF2tHqPUgY9SDnGm00uFw==" + }, "pstree.remy": { "version": "1.1.7", "resolved": "https://registry.npmjs.org/pstree.remy/-/pstree.remy-1.1.7.tgz", "integrity": "sha512-xsMgrUwRpuGskEzBFkH8NmTimbZ5PcPup0LA8JJkHIm2IMUbQcpo3yeLNWVrufEYjh8YwtSVh0xz6UeWc5Oh5A==", "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==" + }, "qs": { "version": "6.7.0", "resolved": "https://registry.npmjs.org/qs/-/qs-6.7.0.tgz", @@ -2656,6 +5036,12 @@ "strip-json-comments": "~2.0.1" } }, + "react-is": { + "version": "16.9.0", + "resolved": "https://registry.npmjs.org/react-is/-/react-is-16.9.0.tgz", + "integrity": "sha512-tJBzzzIgnnRfEm046qRcURvwQnZVXmuCbscxUO5RWrGTXpon2d4c8mI0D8WE6ydVIm29JiLB6+RslkIvym9Rjw==", + "dev": true + }, "read-pkg": { "version": "1.1.0", "resolved": "https://registry.npmjs.org/read-pkg/-/read-pkg-1.1.0.tgz", @@ -2703,6 +5089,15 @@ "readable-stream": "^2.0.2" } }, + "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" + } + }, "redent": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/redent/-/redent-1.0.0.tgz", @@ -2769,6 +5164,88 @@ "is-finite": "^1.0.0" } }, + "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": { + "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==", + "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==", + "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", @@ -2778,6 +5255,21 @@ "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", @@ -2799,6 +5291,12 @@ "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 + }, "safe-buffer": { "version": "5.1.2", "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.1.2.tgz", @@ -2813,10 +5311,72 @@ "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==" + "safer-buffer": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/safer-buffer/-/safer-buffer-2.1.2.tgz", + "integrity": "sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg==" + }, + "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" + }, + "dependencies": { + "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" + } + }, + "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" + } + }, + "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" + } + } + } + }, + "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", @@ -2886,6 +5446,12 @@ "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", @@ -2941,6 +5507,18 @@ "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", @@ -3141,6 +5719,29 @@ "extend-shallow": "^3.0.0" } }, + "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", @@ -3167,6 +5768,21 @@ "resolved": "https://registry.npmjs.org/statuses/-/statuses-1.5.0.tgz", "integrity": "sha1-Fhx9rBd2Wf2YEfQ3cfqZOBR4Yow=" }, + "stealthy-require": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/stealthy-require/-/stealthy-require-1.1.1.tgz", + "integrity": "sha1-NbCYdbT/SfJqd35QmzCQoyJr8ks=" + }, + "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" + } + }, "string-width": { "version": "2.1.1", "resolved": "https://registry.npmjs.org/string-width/-/string-width-2.1.1.tgz", @@ -3177,6 +5793,26 @@ "strip-ansi": "^4.0.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": "1.1.1", "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.1.1.tgz", @@ -3247,6 +5883,12 @@ "swagger-ui-dist": "^3.18.1" } }, + "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 + }, "term-size": { "version": "1.2.0", "resolved": "https://registry.npmjs.org/term-size/-/term-size-1.2.0.tgz", @@ -3256,12 +5898,111 @@ "execa": "^0.7.0" } }, + "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" + }, + "dependencies": { + "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" + } + }, + "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" + } + }, + "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" + } + }, + "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" + } + }, + "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" + } + }, + "strip-bom": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/strip-bom/-/strip-bom-3.0.0.tgz", + "integrity": "sha1-IzTBjpx1n3vdVv3vfprj1YjmjtM=", + "dev": true + } + } + }, + "throat": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/throat/-/throat-4.1.0.tgz", + "integrity": "sha1-iQN8vJLFarGJJua6TLsgDhVnKmo=", + "dev": true + }, "timed-out": { "version": "4.0.1", "resolved": "https://registry.npmjs.org/timed-out/-/timed-out-4.0.1.tgz", "integrity": "sha1-8y6srFoXW+ol1/q1Zas+2HQe9W8=", "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", @@ -3318,6 +6059,24 @@ "nopt": "~1.0.10" } }, + "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==", + "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" + } + }, "tree-kill": { "version": "1.2.1", "resolved": "https://registry.npmjs.org/tree-kill/-/tree-kill-1.2.1.tgz", @@ -3330,6 +6089,41 @@ "integrity": "sha1-WIeWa7WCpFA6QetST301ARgVphM=", "dev": true }, + "trim-right": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/trim-right/-/trim-right-1.0.1.tgz", + "integrity": "sha1-yy4SAwZ+DI3h9hQJS5/kVwTqYAM=", + "dev": true + }, + "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": { + "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" + } + } + } + }, "ts-node": { "version": "8.4.1", "resolved": "https://registry.npmjs.org/ts-node/-/ts-node-8.4.1.tgz", @@ -3383,6 +6177,30 @@ } } }, + "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-is": { "version": "1.6.18", "resolved": "https://registry.npmjs.org/type-is/-/type-is-1.6.18.tgz", @@ -3398,6 +6216,26 @@ "integrity": "sha512-N7bceJL1CtRQ2RiG0AQME13ksR7DiuQh/QehubYcghzv20tnh+MQnQIuJddTmsbqYj+dztchykemz0zFzlvdQw==", "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" + }, + "dependencies": { + "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, + "optional": true + } + } + }, "undefsafe": { "version": "2.0.2", "resolved": "https://registry.npmjs.org/undefsafe/-/undefsafe-2.0.2.tgz", @@ -3514,6 +6352,15 @@ "xdg-basedir": "^3.0.0" } }, + "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", @@ -3541,11 +6388,27 @@ "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=" }, + "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", @@ -3561,6 +6424,67 @@ "resolved": "https://registry.npmjs.org/vary/-/vary-1.1.2.tgz", "integrity": "sha1-IpnwLG3tMNSllhsLn3RSShj2NPw=" }, + "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", @@ -3570,6 +6494,12 @@ "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 + }, "widest-line": { "version": "2.0.1", "resolved": "https://registry.npmjs.org/widest-line/-/widest-line-2.0.1.tgz", @@ -3579,6 +6509,51 @@ "string-width": "^2.1.1" } }, + "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" + }, + "dependencies": { + "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 + }, + "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" + } + }, + "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" + } + } + } + }, "wrappy": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/wrappy/-/wrappy-1.0.2.tgz", @@ -3596,24 +6571,118 @@ "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" + } + }, "xdg-basedir": { "version": "3.0.0", "resolved": "https://registry.npmjs.org/xdg-basedir/-/xdg-basedir-3.0.0.tgz", "integrity": "sha1-SWsswQnsqNus/i3HK2A8F8WHCtQ=", "dev": true }, + "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 + }, "yallist": { "version": "2.1.2", "resolved": "https://registry.npmjs.org/yallist/-/yallist-2.1.2.tgz", "integrity": "sha1-HBH5IY8HYImkfdUS+TxmmaaoHVI=", "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" + }, + "dependencies": { + "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 + }, + "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" + } + }, + "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" + } + }, + "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" + } + } + } + }, + "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" + }, + "dependencies": { + "camelcase": { + "version": "5.3.1", + "resolved": "https://registry.npmjs.org/camelcase/-/camelcase-5.3.1.tgz", + "integrity": "sha512-L28STB170nwWS63UjtlEOE3dldQApaJXZkOI1uMFfzf3rRuPegHaHesyee+YxQ+W6SvRDQV6UrdOdRiR153wJg==", + "dev": true + } + } + }, "yn": { "version": "3.1.1", "resolved": "https://registry.npmjs.org/yn/-/yn-3.1.1.tgz", From e499fa1c4f944afdb94b4591e7196ea5134d0a5c Mon Sep 17 00:00:00 2001 From: Luiz Filho Date: Sun, 22 Sep 2019 11:40:47 -0300 Subject: [PATCH 51/65] swagger increments inital --- swagger.json | 87 ++++++++++++++++++++++++++++++++++++++++++++++++++-- 1 file changed, 84 insertions(+), 3 deletions(-) diff --git a/swagger.json b/swagger.json index d570a30..11353a2 100644 --- a/swagger.json +++ b/swagger.json @@ -18,15 +18,96 @@ "application/json" ], "paths": { - "/": { + "/customers/{cpf}": { "get": { "tags": [ - "Welcome" + "Customer" ], "summary": "Default route", + "parameters": [ + { + "in": "path", + "name": "cpf", + "required": true, + "description": "Customer CPF", + "schema": { + "$ref": "#/definitions/cpf" + } + } + ], + "responses": { + "200": { + "description": "OK", + "schema": { + "$ref": "#/definitions/Customers" + } + } + } + } + }, + "/customers": { + "post": { + "tags": [ + "Customer" + ], + "summary": "Create a new customer", + "requestBody": { + "description": "Customer Object", + "required": true, + "content": { + "application/json": { + "schema": { + "$ref": "#/definitions/Customer" + } + } + } + }, + "produces": [ + "application/json" + ], "responses": { "200": { - "description": "OK" + "description": "OK", + "schema": { + "$ref": "#/definitions/Customer" + } + }, + "400": { + "description": "Failed. Bad post data." + } + } + } + } + }, + "definitions": { + "cpf": { + "properties": { + "string": { + "type": "string" + } + } + }, + "Customer": { + "type": "object", + "properties": { + "name": { + "type": "string" + }, + "cpf": { + "type": "string" + }, + "dataOfBirth": { + "type": "string" + } + } + }, + "Customers": { + "type": "object", + "properties": { + "customers": { + "type": "object", + "additionalProperties": { + "$ref": "#/definitions/Customer" } } } From d5145a4eca944233c9469e9ae546d2865fe64591 Mon Sep 17 00:00:00 2001 From: Luiz Filho Date: Sun, 22 Sep 2019 14:08:56 -0300 Subject: [PATCH 52/65] config env files --- env/local.env | 4 ++++ env/production.env | 4 ++++ env/staging.env | 4 ++++ env/test.env | 2 ++ package-lock.json | 13 +++++++++++++ package.json | 4 +++- src/app.ts | 1 + src/config/init.ts | 4 ++++ src/config/unit-test.ts | 4 ++++ 9 files changed, 39 insertions(+), 1 deletion(-) create mode 100644 env/local.env create mode 100644 env/production.env create mode 100644 env/staging.env create mode 100644 env/test.env create mode 100644 src/config/init.ts create mode 100644 src/config/unit-test.ts diff --git a/env/local.env b/env/local.env new file mode 100644 index 0000000..a15904f --- /dev/null +++ b/env/local.env @@ -0,0 +1,4 @@ +NODE_ENV=local +HOST=localhost +PORT=4446 +MAX_BY_TIME=2 \ No newline at end of file diff --git a/env/production.env b/env/production.env new file mode 100644 index 0000000..1a5bb64 --- /dev/null +++ b/env/production.env @@ -0,0 +1,4 @@ +NODE_ENV=production +HOST=localhost +PORT=80 +MAX_BY_TIME=2 \ No newline at end of file diff --git a/env/staging.env b/env/staging.env new file mode 100644 index 0000000..02c26b3 --- /dev/null +++ b/env/staging.env @@ -0,0 +1,4 @@ +NODE_ENV=staging +HOST=localhost +PORT=80 +MAX_BY_TIME=2 \ No newline at end of file diff --git a/env/test.env b/env/test.env new file mode 100644 index 0000000..5174436 --- /dev/null +++ b/env/test.env @@ -0,0 +1,2 @@ +NODE_ENV= +MAX_BY_TIME=2 \ No newline at end of file diff --git a/package-lock.json b/package-lock.json index 82f4e60..73f7827 100644 --- a/package-lock.json +++ b/package-lock.json @@ -486,6 +486,14 @@ "@types/node": "*" } }, + "@types/dotenv": { + "version": "6.1.1", + "resolved": "https://registry.npmjs.org/@types/dotenv/-/dotenv-6.1.1.tgz", + "integrity": "sha512-ftQl3DtBvqHl9L16tpqqzA4YzCSXZfi7g8cQceTz5rOlYtk/IZbFjAv3mLOQlNIgOaylCQWQoBdDQHPgEBJPHg==", + "requires": { + "@types/node": "*" + } + }, "@types/express": { "version": "4.17.1", "resolved": "https://registry.npmjs.org/@types/express/-/express-4.17.1.tgz", @@ -1671,6 +1679,11 @@ "is-obj": "^1.0.0" } }, + "dotenv": { + "version": "8.1.0", + "resolved": "https://registry.npmjs.org/dotenv/-/dotenv-8.1.0.tgz", + "integrity": "sha512-GUE3gqcDCaMltj2++g6bRQ5rBJWtkWTmqmD0fo1RnnMuUqHNCt2oTPeDnS9n6fKYvlhn7AeBkb38lymBtWBQdA==" + }, "duplexer3": { "version": "0.1.4", "resolved": "https://registry.npmjs.org/duplexer3/-/duplexer3-0.1.4.tgz", diff --git a/package.json b/package.json index b52bdb9..1dbbc2a 100644 --- a/package.json +++ b/package.json @@ -6,7 +6,7 @@ "scripts": { "tsc": "tsc", "dev": "nodemon src/server.ts", - "test": "jest" + "test": "jest --setupFiles ./src/config/unit-test.ts" }, "repository": { "type": "git", @@ -28,9 +28,11 @@ "typescript": "^3.6.3" }, "dependencies": { + "@types/dotenv": "^6.1.1", "@types/faker": "^4.1.5", "@types/request-promise-native": "^1.0.16", "@types/swagger-ui-express": "^3.0.1", + "dotenv": "^8.1.0", "express": "^4.17.1", "faker": "^4.1.0", "request-promise-native": "^1.0.7", diff --git a/src/app.ts b/src/app.ts index 83d5930..a12768c 100644 --- a/src/app.ts +++ b/src/app.ts @@ -1,3 +1,4 @@ +import './config/init' import express from 'express' import swaggerUi from 'swagger-ui-express' import { CustomerRoutes, ExamRoutes, ScheduleRoute } from './routes/index' diff --git a/src/config/init.ts b/src/config/init.ts new file mode 100644 index 0000000..65e292f --- /dev/null +++ b/src/config/init.ts @@ -0,0 +1,4 @@ +import { resolve } from 'path' +import { config } from 'dotenv' + +config({ path: resolve(__dirname, '../../env/' + (process.env.NODE_ENV || 'local') + '.env') }) \ No newline at end of file diff --git a/src/config/unit-test.ts b/src/config/unit-test.ts new file mode 100644 index 0000000..872bd6c --- /dev/null +++ b/src/config/unit-test.ts @@ -0,0 +1,4 @@ +import { resolve } from 'path' +import { config } from 'dotenv' + +config({ path: resolve(__dirname, '../../env/test.env') }) \ No newline at end of file From 1662cedd394d391ec168c99e6d3f536a86d1aec9 Mon Sep 17 00:00:00 2001 From: Luiz Filho Date: Sun, 22 Sep 2019 14:09:37 -0300 Subject: [PATCH 53/65] adjustment to work default max 2 customer by time in same exam --- data/db.ts | 2 +- src/services/schedule.ts | 15 +++++++++++++-- tests/unit/exam/schedule.spec.ts | 9 ++++++--- 3 files changed, 20 insertions(+), 6 deletions(-) diff --git a/data/db.ts b/data/db.ts index ed89652..049ad55 100644 --- a/data/db.ts +++ b/data/db.ts @@ -95,7 +95,7 @@ class DB { } public getByScheduleByDate( examId: string, date: any ) { - return !!DB.schedules.find( item => item.examId === examId && item.date === date ) + return DB.schedules.filter( item => item.examId === examId && item.date === date ) } public getScheduleByCpf(cpf: string) { diff --git a/src/services/schedule.ts b/src/services/schedule.ts index 40e13c2..dde3589 100644 --- a/src/services/schedule.ts +++ b/src/services/schedule.ts @@ -9,34 +9,45 @@ class ScheduleService { private customer: CustomerService public constructor () { + this.connection = DB.connection() this.exam = new ExamService() this.customer = new CustomerService() } public async save(data: Schedule) { + let exam = await this.exam.get(data.examId.toString()) let customer = await this.customer.find(data.cpf) + if (exam && customer.success) { + let formattedDate = data.date - const alreadyScheduled = this.connection.getByScheduleByDate(data.examId.toString(), formattedDate) - if (!alreadyScheduled) { + + const customersAtThisTime = this.connection.getByScheduleByDate(data.examId.toString(), formattedDate) + let maxByTime = process.env.MAX_BY_TIME || 2 + + if (customersAtThisTime.length < maxByTime) { data.price = exam.value formattedDate = data.date data = { ...data, date: formattedDate } return this.connection.schedule({ ...data, examId: data.examId.toString() }) } } + return null } public listByCpf(cpf: string) { + let schedules: any = this.connection.getScheduleByCpf(cpf) let pricesSum = 0 + if (schedules) { pricesSum = schedules.reduce( (sum: number, currentPrice: any) => sum + currentPrice.price, 0) schedules = { schedules, total: pricesSum } } + return schedules } diff --git a/tests/unit/exam/schedule.spec.ts b/tests/unit/exam/schedule.spec.ts index 4ad9acf..4b1f2c6 100644 --- a/tests/unit/exam/schedule.spec.ts +++ b/tests/unit/exam/schedule.spec.ts @@ -63,11 +63,14 @@ describe('Scheduling exam', () => { mockedAxios.get.mockResolvedValue(examsMock) await scheduleService.save(data) let connectionToSameTime = DB.connection() + let secondCustomer = connectionToSameTime.addCustomer({ ...customer, cpf: getCpf() }).data - let otherCustomer = connectionToSameTime.addCustomer({ ...customer, cpf: getCpf() }).data + await scheduleService.save({ ...data, cpf: secondCustomer.cpf }) - let otherExamSameTime = await scheduleService.save({ ...data, cpf: otherCustomer.cpf }) - expect(otherExamSameTime).toEqual(null) + let thirdCustomer = connectionToSameTime.addCustomer({ ...customer, cpf: getCpf() }).data + + const thirdSchedule = await scheduleService.save({ ...data, cpf: thirdCustomer.cpf }) + expect(thirdSchedule).toEqual(null) }) it('should return exams by cpf and calculate the total value', async () => { From 66020a3d76fc925c588aea288b5acb59ac5dd97d Mon Sep 17 00:00:00 2001 From: Luiz Filho Date: Sun, 22 Sep 2019 14:44:15 -0300 Subject: [PATCH 54/65] add travis and adjustment --- .travis.yml | 6 ++++++ data/db.ts | 8 ++++---- src/services/customer.ts | 4 ++-- tests/unit/customer/customer.spec.ts | 4 ++-- tests/unit/exam/schedule.spec.ts | 2 +- 5 files changed, 15 insertions(+), 9 deletions(-) create mode 100644 .travis.yml diff --git a/.travis.yml b/.travis.yml new file mode 100644 index 0000000..d55a5f2 --- /dev/null +++ b/.travis.yml @@ -0,0 +1,6 @@ +language: node_js +node_js: + - "stable" +cache: + directories: + - "node_modules" \ No newline at end of file diff --git a/data/db.ts b/data/db.ts index 049ad55..f86509a 100644 --- a/data/db.ts +++ b/data/db.ts @@ -35,15 +35,15 @@ class DB { } } - public updateCustomer(data: any) { - let customerIndex = DB.customers.findIndex( item => item.cpf === data.cpf ) + public updateCustomer(cpf: string, data: any) { + let customerIndex = DB.customers.findIndex( item => item.cpf === cpf ) if (customerIndex > -1) { - DB.customers[customerIndex] = { ...data } + DB.customers[customerIndex] = { ...data, cpf } } return { success: customerIndex > -1 ? true: false, - data: DB.customers.find( item => item.cpf === data.cpf ) || null, + data: DB.customers.find( item => item.cpf === cpf ) || null, message: customerIndex > -1 ? 'item successfully updated' : 'item not found' } } diff --git a/src/services/customer.ts b/src/services/customer.ts index 3eb57b1..2c7ea09 100644 --- a/src/services/customer.ts +++ b/src/services/customer.ts @@ -12,8 +12,8 @@ class CustomerService { return this.connection.addCustomer(data) } - public update(data: Customer): any { - return this.connection.updateCustomer(data) + public update(cpf: string, data: Customer): any { + return this.connection.updateCustomer(cpf, data) } public remove(cpf: string): any { diff --git a/tests/unit/customer/customer.spec.ts b/tests/unit/customer/customer.spec.ts index d20f664..bb62454 100644 --- a/tests/unit/customer/customer.spec.ts +++ b/tests/unit/customer/customer.spec.ts @@ -33,7 +33,7 @@ test('should not save a customer', () => { test('should update a customer to the database by service', () => { service.save(customer) customer = { ...customer, name: fullName() } - const customerUpdated = service.update(customer) + const customerUpdated = service.update(customer.cpf, customer) expect(customerUpdated.data).toEqual(customer) }) @@ -44,7 +44,7 @@ test('should not update a customer', () => { name: fullName(), dateOfBirth: getDate() } - const customerUpdated = service.update(customer) + const customerUpdated = service.update(customer.cpf, customer) expect(customerUpdated.success).toEqual(false) }) diff --git a/tests/unit/exam/schedule.spec.ts b/tests/unit/exam/schedule.spec.ts index 4b1f2c6..94a5482 100644 --- a/tests/unit/exam/schedule.spec.ts +++ b/tests/unit/exam/schedule.spec.ts @@ -64,10 +64,10 @@ describe('Scheduling exam', () => { await scheduleService.save(data) let connectionToSameTime = DB.connection() let secondCustomer = connectionToSameTime.addCustomer({ ...customer, cpf: getCpf() }).data + let thirdCustomer = connectionToSameTime.addCustomer({ ...customer, cpf: getCpf() }).data await scheduleService.save({ ...data, cpf: secondCustomer.cpf }) - let thirdCustomer = connectionToSameTime.addCustomer({ ...customer, cpf: getCpf() }).data const thirdSchedule = await scheduleService.save({ ...data, cpf: thirdCustomer.cpf }) expect(thirdSchedule).toEqual(null) From 4a35d9d4c88d85fcbe0b80978486db1f42ca1b7a Mon Sep 17 00:00:00 2001 From: Luiz Filho Date: Sun, 22 Sep 2019 17:07:39 -0300 Subject: [PATCH 55/65] swagger complete --- swagger.json | 299 +++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 299 insertions(+) diff --git a/swagger.json b/swagger.json index 11353a2..631df46 100644 --- a/swagger.json +++ b/swagger.json @@ -43,6 +43,76 @@ } } } + }, + "put": { + "summary": "Update Customer with given CPF", + "tags": [ + "Customer" + ], + "requestBody": { + "description": "Customer Object", + "required": true, + "content": { + "application/json": { + "schema": { + "$ref": "#/definitions/Customer" + } + } + } + }, + "parameters": [ + { + "in": "path", + "name": "cpf", + "required": true, + "description": "Customer with new values of properties", + "schema": { + "$ref": "#/definitions/cpf" + } + } + ], + "responses": { + "200": { + "description": "OK", + "schema": { + "$ref": "#/definitions/Customer" + } + }, + "400": { + "description": "Failed. Bad post data." + }, + "404": { + "description": "Failed. Customer not found." + } + } + }, + "delete": { + "summary": "Delete Customer with given CPF", + "tags": [ + "Customer" + ], + "parameters": [ + { + "in": "path", + "name": "cpf", + "required": true, + "description": "Delete Customer with id", + "schema": { + "$ref": "#/definitions/cpf" + } + } + ], + "responses": { + "200": { + "description": "OK", + "schema": { + "$ref": "#/definitions/cpf" + } + }, + "404": { + "description": "Failed. Customer not found." + } + } } }, "/customers": { @@ -77,9 +147,191 @@ } } } + }, + "/schedules/{id}": { + "put": { + "summary": "Update Schedule with given id", + "tags": [ + "Schedule" + ], + "requestBody": { + "description": "Schedule Object", + "required": true, + "content": { + "application/json": { + "schema": { + "$ref": "#/definitions/Schedule" + } + } + } + }, + "parameters": [ + { + "in": "path", + "name": "id", + "required": true, + "description": "Schedule with new values of properties", + "schema": { + "$ref": "#/definitions/id" + } + } + ], + "responses": { + "200": { + "description": "OK", + "schema": { + "$ref": "#/definitions/Schedule" + } + }, + "400": { + "description": "Failed. Bad post data." + }, + "404": { + "description": "Failed. Schedule not found." + } + } + }, + "delete": { + "summary": "Delete Schedule with given id", + "tags": [ + "Schedule" + ], + "parameters": [ + { + "in": "path", + "name": "id", + "required": true, + "description": "Delete Schedule with id", + "schema": { + "$ref": "#/definitions/id" + } + } + ], + "responses": { + "200": { + "description": "OK", + "schema": { + "$ref": "#/definitions/id" + } + }, + "404": { + "description": "Failed. Schedule not found." + } + } + } + }, + "/schedules/{cpf}": { + "get": { + "tags": [ + "Schedule" + ], + "summary": "Default route", + "parameters": [ + { + "in": "path", + "name": "cpf", + "required": true, + "description": "Customer cpf", + "schema": { + "$ref": "#/definitions/cpf" + } + } + ], + "responses": { + "200": { + "description": "OK", + "schema": { + "$ref": "#/definitions/Schedule" + } + } + } + } + }, + "/schedules": { + "post": { + "tags": [ + "Schedule" + ], + "summary": "Create a new Schedule", + "requestBody": { + "description": "Schedule Object", + "required": true, + "content": { + "application/json": { + "schema": { + "$ref": "#/definitions/Schedule" + } + } + } + }, + "produces": [ + "application/json" + ], + "responses": { + "200": { + "description": "OK", + "schema": { + "$ref": "#/definitions/Schedule" + } + }, + "400": { + "description": "Failed. Bad post data." + } + } + } + }, + "/exams": { + "get": { + "tags": [ + "Exam" + ], + "summary": "Default route", + "responses": { + "200": { + "description": "OK", + "schema": { + "$ref": "#/definitions/Exams" + } + } + } + } + }, + "/exams/{id}": { + "get": { + "tags": [ + "Exam" + ], + "summary": "Default route", + "parameters": [ + { + "in": "path", + "name": "id", + "required": true, + "description": "Exam id", + "schema": { + "$ref": "#/definitions/id" + } + } + ], + "responses": { + "200": { + "description": "OK", + "schema": { + "$ref": "#/definitions/Exam" + } + } + } + } } }, "definitions": { + "id": { + "properties": { + "integer": { + "type": "integer" + } + } + }, "cpf": { "properties": { "string": { @@ -111,6 +363,53 @@ } } } + }, + "Schedule": { + "type": "object", + "properties": { + "examId": { + "type": "string" + }, + "cpf": { + "type": "string" + }, + "date": { + "type": "string" + } + } + }, + "Schedulers": { + "type": "object", + "properties": { + "schedulers": { + "type": "object", + "additionalProperties": { + "$ref": "#/definitions/Schedule" + } + } + } + }, + "Exam": { + "type": "object", + "properties": { + "id": { + "type": "string" + }, + "name": { + "type": "string" + } + } + }, + "Exams": { + "type": "object", + "properties": { + "exams": { + "type": "object", + "additionalProperties": { + "$ref": "#/definitions/Exam" + } + } + } } } } \ No newline at end of file From 158279cd9dcb75e182506e5af9a3dbd88bea579b Mon Sep 17 00:00:00 2001 From: Luiz Filho Date: Sun, 22 Sep 2019 17:17:01 -0300 Subject: [PATCH 56/65] added doc with request postman --- .../challenge-backend.postman_collection.json | 353 ++++++++++++++++++ 1 file changed, 353 insertions(+) create mode 100644 docs/challenge-backend.postman_collection.json diff --git a/docs/challenge-backend.postman_collection.json b/docs/challenge-backend.postman_collection.json new file mode 100644 index 0000000..e02689c --- /dev/null +++ b/docs/challenge-backend.postman_collection.json @@ -0,0 +1,353 @@ +{ + "info": { + "_postman_id": "86948c1b-d6af-4383-bd11-212d5a3661b1", + "name": "challenge-backend", + "schema": "https://schema.getpostman.com/json/collection/v2.1.0/collection.json" + }, + "item": [ + { + "name": "schedule", + "item": [ + { + "name": "schedule", + "request": { + "method": "POST", + "header": [ + { + "key": "Content-Type", + "name": "Content-Type", + "type": "text", + "value": "application/json" + } + ], + "body": { + "mode": "raw", + "raw": "{\n\t\"examId\": 4,\n\t\"cpf\": \"11122233349\",\n\t\"date\": \"2019/12/12 08:04:00\"\n}" + }, + "url": { + "raw": "http://localhost:4446/schedules", + "protocol": "http", + "host": [ + "localhost" + ], + "port": "4446", + "path": [ + "schedules" + ] + }, + "description": "Welcome route test" + }, + "response": [] + }, + { + "name": "update schedule", + "request": { + "method": "PUT", + "header": [ + { + "key": "Content-Type", + "name": "Content-Type", + "type": "text", + "value": "application/json" + } + ], + "body": { + "mode": "raw", + "raw": "{\n\t\"date\": \"2019/12/13 08:04:00\"\n}" + }, + "url": { + "raw": "http://localhost:4446/schedules/1", + "protocol": "http", + "host": [ + "localhost" + ], + "port": "4446", + "path": [ + "schedules", + "1" + ] + }, + "description": "Welcome route test" + }, + "response": [] + }, + { + "name": "getbycpf", + "request": { + "method": "GET", + "header": [ + { + "key": "Content-Type", + "name": "Content-Type", + "type": "text", + "value": "application/json" + } + ], + "body": { + "mode": "raw", + "raw": "" + }, + "url": { + "raw": "http://localhost:4446/schedules/11122233349", + "protocol": "http", + "host": [ + "localhost" + ], + "port": "4446", + "path": [ + "schedules", + "11122233349" + ] + }, + "description": "Welcome route test" + }, + "response": [] + }, + { + "name": "remove schedule", + "request": { + "method": "DELETE", + "header": [ + { + "key": "Content-Type", + "name": "Content-Type", + "type": "text", + "value": "application/json" + } + ], + "body": { + "mode": "raw", + "raw": "{\n\t\"examId\": 3,\n\t\"cpf\": \"33309812324\",\n\t\"date\": \"2019/12/12 08:04:00\"\n}" + }, + "url": { + "raw": "http://localhost:4446/schedules/2", + "protocol": "http", + "host": [ + "localhost" + ], + "port": "4446", + "path": [ + "schedules", + "2" + ] + }, + "description": "Welcome route test" + }, + "response": [] + } + ] + }, + { + "name": "exam", + "item": [ + { + "name": "exam-list", + "request": { + "method": "GET", + "header": [], + "body": { + "mode": "raw", + "raw": "" + }, + "url": { + "raw": "http://localhost:4446/exams", + "protocol": "http", + "host": [ + "localhost" + ], + "port": "4446", + "path": [ + "exams" + ] + }, + "description": "Welcome route test" + }, + "response": [] + }, + { + "name": "exam by id", + "request": { + "method": "GET", + "header": [], + "body": { + "mode": "raw", + "raw": "" + }, + "url": { + "raw": "http://localhost:4446/exams/2", + "protocol": "http", + "host": [ + "localhost" + ], + "port": "4446", + "path": [ + "exams", + "2" + ] + }, + "description": "Welcome route test" + }, + "response": [] + }, + { + "name": "mock-api", + "request": { + "method": "GET", + "header": [], + "body": { + "mode": "raw", + "raw": "" + }, + "url": { + "raw": "http://www.mocky.io/v2/5d681ede33000054e7e65c3f", + "protocol": "http", + "host": [ + "www", + "mocky", + "io" + ], + "path": [ + "v2", + "5d681ede33000054e7e65c3f" + ] + }, + "description": "Welcome route test" + }, + "response": [] + } + ] + }, + { + "name": "customer", + "item": [ + { + "name": "save customer", + "request": { + "method": "POST", + "header": [ + { + "key": "Content-Type", + "name": "Content-Type", + "value": "application/json", + "type": "text" + } + ], + "body": { + "mode": "raw", + "raw": "{\n\t\"name\":\"Roberta Dias\",\n\t\"cpf\":\"11122233349\",\n\t\"dateOfBirth\": \"17/02/1980\"\n}" + }, + "url": { + "raw": "http://localhost:4446/customers", + "protocol": "http", + "host": [ + "localhost" + ], + "port": "4446", + "path": [ + "customers" + ] + }, + "description": "Welcome route test" + }, + "response": [] + }, + { + "name": "update customer", + "request": { + "method": "PUT", + "header": [ + { + "key": "Content-Type", + "name": "Content-Type", + "type": "text", + "value": "application/json" + } + ], + "body": { + "mode": "raw", + "raw": "{\n\t\"name\":\"Fernanda Pereira\",\n\t\"dateOfBirth\": \"17/02/1992\"\n}" + }, + "url": { + "raw": "http://localhost:4446/customers/11122233349", + "protocol": "http", + "host": [ + "localhost" + ], + "port": "4446", + "path": [ + "customers", + "11122233349" + ] + }, + "description": "Welcome route test" + }, + "response": [] + }, + { + "name": "remove customer", + "request": { + "method": "DELETE", + "header": [ + { + "key": "Content-Type", + "name": "Content-Type", + "type": "text", + "value": "application/json" + } + ], + "body": { + "mode": "raw", + "raw": "" + }, + "url": { + "raw": "http://localhost:4446/customers/11122233349", + "protocol": "http", + "host": [ + "localhost" + ], + "port": "4446", + "path": [ + "customers", + "11122233349" + ] + }, + "description": "Welcome route test" + }, + "response": [] + }, + { + "name": "find customer", + "request": { + "method": "GET", + "header": [ + { + "key": "Content-Type", + "name": "Content-Type", + "type": "text", + "value": "application/json" + } + ], + "body": { + "mode": "raw", + "raw": "" + }, + "url": { + "raw": "http://localhost:4446/customers/11122233345", + "protocol": "http", + "host": [ + "localhost" + ], + "port": "4446", + "path": [ + "customers", + "11122233345" + ] + }, + "description": "Welcome route test" + }, + "response": [] + } + ] + } + ] +} \ No newline at end of file From ddfb54daf8caaf0e106556ae9370d8347946e183 Mon Sep 17 00:00:00 2001 From: Luiz Filho Date: Sun, 22 Sep 2019 17:26:30 -0300 Subject: [PATCH 57/65] added middlewares layer to complete the architecture --- src/http/middlewares/index.js | 0 1 file changed, 0 insertions(+), 0 deletions(-) create mode 100644 src/http/middlewares/index.js diff --git a/src/http/middlewares/index.js b/src/http/middlewares/index.js new file mode 100644 index 0000000..e69de29 From 5067b5bde071885849f95eee4f219cb406435864 Mon Sep 17 00:00:00 2001 From: Luiz Filho Date: Sun, 22 Sep 2019 20:43:10 -0300 Subject: [PATCH 58/65] updated config docker-compose --- docker-compose.yml | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/docker-compose.yml b/docker-compose.yml index bdd8d31..dd4438e 100644 --- a/docker-compose.yml +++ b/docker-compose.yml @@ -3,5 +3,9 @@ version: "3" services: api: build: . + env_file: + - ./env/local.env ports: - - "4446:4446" \ No newline at end of file + - "4446:4446" + environment: + - NODE_ENV=local \ No newline at end of file From ca277f822569eef1a26477ed971d8fdd72d6969c Mon Sep 17 00:00:00 2001 From: Luiz Filho Date: Sun, 22 Sep 2019 20:43:41 -0300 Subject: [PATCH 59/65] updated unit test sintaxe --- tests/unit/customer/api.spec.ts | 26 ++--- tests/unit/customer/customer.spec.ts | 150 ++++++++++++++------------- tests/unit/customer/database.spec.ts | 25 ++--- tests/unit/exam/schedule.spec.ts | 43 ++++---- 4 files changed, 131 insertions(+), 113 deletions(-) diff --git a/tests/unit/customer/api.spec.ts b/tests/unit/customer/api.spec.ts index d7f16fb..82ca172 100644 --- a/tests/unit/customer/api.spec.ts +++ b/tests/unit/customer/api.spec.ts @@ -4,17 +4,19 @@ import ExamProvider from '../../../src/providers/exams' jest.mock('request-promise-native') const mockedAxios = request as jest.Mocked -test('should return exam list', async () => { - const exams = '{"exams": [{"id":"1","name":"17 soro","value":35.60},{"id":"2","name":"Acidificação Urinária","value":84.90},{"id":"3","name":"Ácido Ascórbico, plasma","value":99.90}]}' +describe('mock api', () => { + it('should return exam list', async () => { + const exams = '{"exams": [{"id":"1","name":"17 soro","value":35.60},{"id":"2","name":"Acidificação Urinária","value":84.90},{"id":"3","name":"Ácido Ascórbico, plasma","value":99.90}]}' + + const expected = [ + { id: "1", name: '17 soro' }, + { id: "2", name: 'Acidificação Urinária' }, + { id: "3", name: 'Ácido Ascórbico, plasma' } + ] - const expected = [ - { id: "1", name: '17 soro' }, - { id: "2", name: 'Acidificação Urinária' }, - { id: "3", name: 'Ácido Ascórbico, plasma' } - ] - - mockedAxios.get.mockResolvedValue(exams) - let response = await ExamProvider.list() - expect(response).toEqual(expected) -}) + mockedAxios.get.mockResolvedValue(exams) + let response = await ExamProvider.list() + expect(response).toEqual(expected) + }) +}) diff --git a/tests/unit/customer/customer.spec.ts b/tests/unit/customer/customer.spec.ts index bb62454..7e099af 100644 --- a/tests/unit/customer/customer.spec.ts +++ b/tests/unit/customer/customer.spec.ts @@ -18,82 +18,90 @@ beforeEach(() => { } }) -test('should save a customer to the database by service', () => { - const customerStored = service.save(customer) - expect(customer).toEqual(customerStored.data) -}) - -test('should not save a customer', () => { - service.save(customer) - const otherService = new CustomerService() - const responseOtherService = otherService.save({ ...customer, name: fullName() }) - expect(responseOtherService.success).toEqual(false) -}) - -test('should update a customer to the database by service', () => { - service.save(customer) - customer = { ...customer, name: fullName() } - const customerUpdated = service.update(customer.cpf, customer) - expect(customerUpdated.data).toEqual(customer) -}) - -test('should not update a customer', () => { - service.save(customer) - customer = { - cpf: getCpf(), - name: fullName(), - dateOfBirth: getDate() - } - const customerUpdated = service.update(customer.cpf, customer) - expect(customerUpdated.success).toEqual(false) -}) - -test('should remove a customer to the database by service', () => { - service.save(customer) - const customerRemoved = service.remove(customer.cpf) - expect(customerRemoved.success).toEqual(true) - expect(customerRemoved.data).toEqual(customer) -}) - -test('should not delete a customer', () => { - service.save(customer) - customer = { - ...customer, - cpf: getCpf() - } - const customerRemoved = service.remove(customer.cpf) - - expect(customerRemoved.success).toEqual(false) -}) - -test('should be returned a customer by cpf', () => { - service.save(customer) - const customerSeached = service.find(customer.cpf) - expect(customerSeached.success).toEqual(true) - expect(customerSeached.data).toEqual(customer) -}) - -test('should not return a customer by cpf', () => { - service.save(customer) - customer.cpf = getCpf() - const customerSeached = service.find(customer.cpf) - - expect(customerSeached.success).toEqual(false) - expect(customerSeached.data).toEqual(null) +describe('Customer save', () => { + it('should save a customer to the database by service', () => { + const customerStored = service.save(customer) + expect(customer).toEqual(customerStored.data) + }) + + it('should not save a customer', () => { + service.save(customer) + const otherService = new CustomerService() + const responseOtherService = otherService.save({ ...customer, name: fullName() }) + expect(responseOtherService.success).toEqual(false) + }) }) -test('should returned all customers', () => { - const service = new CustomerService() - for(let index = 0; index < 10; index++) { - let customer = { +describe('Customer update', () => { + it('should update a customer to the database by service', () => { + service.save(customer) + customer = { ...customer, name: fullName() } + const customerUpdated = service.update(customer.cpf, customer) + expect(customerUpdated.data).toEqual(customer) + }) + + it('should not update a customer', () => { + service.save(customer) + customer = { cpf: getCpf(), - name: fullName() + name: fullName(), + dateOfBirth: getDate() } + const customerUpdated = service.update(customer.cpf, customer) + expect(customerUpdated.success).toEqual(false) + }) +}) +describe('Customer remove', () => { + it('should remove a customer to the database by service', () => { service.save(customer) - } - - let customers = service.list() - expect(customers.data.length).toEqual(10) + const customerRemoved = service.remove(customer.cpf) + expect(customerRemoved.success).toEqual(true) + expect(customerRemoved.data).toEqual(customer) + }) + + it('should not delete a customer', () => { + service.save(customer) + customer = { + ...customer, + cpf: getCpf() + } + const customerRemoved = service.remove(customer.cpf) + + expect(customerRemoved.success).toEqual(false) + }) +}) +describe('Customer read', () => { + it('should be returned a customer by cpf', () => { + service.save(customer) + const customerSeached = service.find(customer.cpf) + expect(customerSeached.success).toEqual(true) + expect(customerSeached.data).toEqual(customer) + }) + + it('should not return a customer by cpf', () => { + service.save(customer) + customer.cpf = getCpf() + const customerSeached = service.find(customer.cpf) + + expect(customerSeached.success).toEqual(false) + expect(customerSeached.data).toEqual(null) + }) + + it('should returned all customers', () => { + const service = new CustomerService() + for(let index = 0; index < 10; index++) { + let customer = { + cpf: getCpf(), + name: fullName() + } + + service.save(customer) + } + + let customers = service.list() + expect(customers.data.length).toEqual(10) + }) }) + diff --git a/tests/unit/customer/database.spec.ts b/tests/unit/customer/database.spec.ts index e81405e..71b9883 100644 --- a/tests/unit/customer/database.spec.ts +++ b/tests/unit/customer/database.spec.ts @@ -1,15 +1,16 @@ import database from '../../../data/db' -test('should save a client to the database', () => { - const connection = database.connection() - const customer = { - name: 'Luiz Filho', - cpf: '383383383-44' - } - - const customerStored = connection.addCustomer(customer) - const otherConnection = database.connection() - const searched = otherConnection.findCustomer(customer.cpf) - expect(customer).toEqual(searched.data) - expect(customerStored.data).toEqual(searched.data) +describe('database im memory', () => { + it('should save a client to the database', () => { + const connection = database.connection() + const customer = { + name: 'Luiz Filho', + cpf: '383383383-44' + } + const customerStored = connection.addCustomer(customer) + const otherConnection = database.connection() + const searched = otherConnection.findCustomer(customer.cpf) + expect(customer).toEqual(searched.data) + expect(customerStored.data).toEqual(searched.data) + }) }) diff --git a/tests/unit/exam/schedule.spec.ts b/tests/unit/exam/schedule.spec.ts index 94a5482..5c0a815 100644 --- a/tests/unit/exam/schedule.spec.ts +++ b/tests/unit/exam/schedule.spec.ts @@ -15,22 +15,22 @@ let customer = { let scheduleService = new ScheduleService() const examsMock = getExamsMock() -describe('Scheduling exam', () => { - - beforeEach( async () => { +beforeEach( async () => { + + DB.resetForUnitTest() + + let customerData = { + name: fullName(), + cpf: getCpf(), + dateOfBirth: getDate() + } + let connection = DB.connection() + customer = connection.addCustomer(customerData).data + mockedAxios.get.mockResolvedValue(examsMock) +}) - DB.resetForUnitTest() +describe('Schedule save', () => { - let customerData = { - name: fullName(), - cpf: getCpf(), - dateOfBirth: getDate() - } - let connection = DB.connection() - customer = connection.addCustomer(customerData).data - mockedAxios.get.mockResolvedValue(examsMock) - }) - it('should be scheduled an exam for a patient enrolled in the database', async () => { const data = { examId: (Math.floor(Math.random() * 3) + 1).toString(), @@ -72,13 +72,15 @@ describe('Scheduling exam', () => { const thirdSchedule = await scheduleService.save({ ...data, cpf: thirdCustomer.cpf }) expect(thirdSchedule).toEqual(null) }) +}) +describe('Schedule read', () => { it('should return exams by cpf and calculate the total value', async () => { - + mockedAxios.get.mockResolvedValue(examsMock) let sum = 0 for(let index = 0; index < 10; index++) { - + const data = { examId: (Math.floor(Math.random() * 3) + 1).toString(), cpf: customer.cpf, @@ -90,7 +92,9 @@ describe('Scheduling exam', () => { let scheduleByCpf = scheduleService.listByCpf(customer.cpf) expect(scheduleByCpf.total).toEqual(sum) }) +}) +describe('Schedule edit', () => { it('should edit a schedule by id', async () => { const data = { examId: (Math.floor(Math.random() * 3) + 1).toString(), @@ -104,7 +108,9 @@ describe('Scheduling exam', () => { let updatedSchedule = await scheduleService.update(id, newDate) expect(updatedSchedule.data.date).toEqual(newDate) }) +}) +describe('Schedule remove', () => { it('should remove a schedue by id', async () => { const data = { examId: (Math.floor(Math.random() * 3) + 1).toString(), @@ -114,9 +120,10 @@ describe('Scheduling exam', () => { mockedAxios.get.mockResolvedValue(examsMock) let examResult = await scheduleService.save(data) const { id } = examResult - + let removed = await scheduleService.remove(id) - + expect(removed.data).toEqual(examResult) }) }) + From c815dde822c104aea3423eb443b23515896e3df5 Mon Sep 17 00:00:00 2001 From: Luiz Filho Date: Sun, 22 Sep 2019 20:44:11 -0300 Subject: [PATCH 60/65] updated singleton DB --- data/db.ts | 18 +++++++++++------- 1 file changed, 11 insertions(+), 7 deletions(-) diff --git a/data/db.ts b/data/db.ts index f86509a..5adfd99 100644 --- a/data/db.ts +++ b/data/db.ts @@ -1,4 +1,5 @@ class DB { + private static instance: DB private static customers: Array private static schedules: Array @@ -12,11 +13,13 @@ class DB { if (!DB.instance) { DB.instance = new DB() } + return DB.instance } public findCustomer(cpf: string) { const customer = DB.customers.find( item => item.cpf === cpf) + return { success: customer ? true: false, data: customer || null, @@ -25,7 +28,6 @@ class DB { } public addCustomer(data: any) { - let result = !DB.customers.find(item => item.cpf === data.cpf) ? DB.customers.push({...data}) : null return { @@ -37,6 +39,7 @@ class DB { public updateCustomer(cpf: string, data: any) { let customerIndex = DB.customers.findIndex( item => item.cpf === cpf ) + if (customerIndex > -1) { DB.customers[customerIndex] = { ...data, cpf } } @@ -71,11 +74,7 @@ class DB { } } - public static resetForUnitTest() { - DB.instance = new DB() - } - - public schedule(data: any): any { + public createSchedule(data: any): any { let id = DB.schedules.length + 1 DB.schedules.push({ ...data, id }) return DB.schedules.find( item => item.cpf == data.cpf && item.examId === data.examId) @@ -83,6 +82,7 @@ class DB { public updateSchedule(id: number, date: any): any { let scheduleIndex = DB.schedules.findIndex( item => item.id === id) + if (scheduleIndex > -1) { DB.schedules[scheduleIndex] = { ...DB.schedules[scheduleIndex] , date: date} } @@ -98,7 +98,7 @@ class DB { return DB.schedules.filter( item => item.examId === examId && item.date === date ) } - public getScheduleByCpf(cpf: string) { + public getScheduleByCpf(cpf: string): any { return DB.schedules.filter(item => item.cpf === cpf) } @@ -115,6 +115,10 @@ class DB { message: schedule ? 'item successfully removed' : 'item not found' } } + + public static resetForUnitTest(): void { + DB.instance = new DB() + } } export default DB \ No newline at end of file From 00fb9af226fc3c319d1bb259c05d66f8b4c66eb8 Mon Sep 17 00:00:00 2001 From: Luiz Filho Date: Sun, 22 Sep 2019 20:45:11 -0300 Subject: [PATCH 61/65] updated declaration variables --- src/config/urls.ts | 0 src/http/controllers/customerController.ts | 2 +- src/providers/exams.ts | 6 +++--- src/routes/customer.ts | 2 +- src/server.ts | 4 ++-- src/services/schedule.ts | 10 +++++----- 6 files changed, 12 insertions(+), 12 deletions(-) create mode 100644 src/config/urls.ts diff --git a/src/config/urls.ts b/src/config/urls.ts new file mode 100644 index 0000000..e69de29 diff --git a/src/http/controllers/customerController.ts b/src/http/controllers/customerController.ts index 06c2406..124a464 100644 --- a/src/http/controllers/customerController.ts +++ b/src/http/controllers/customerController.ts @@ -22,7 +22,7 @@ class CustomerController { } public update(request: Request, response: Response): void { - const customer = this.service.update(request.body) + const customer = this.service.update(request.params.cpf, request.body) if (!customer.success) { response.status(404) diff --git a/src/providers/exams.ts b/src/providers/exams.ts index 19a6e22..6a1dc94 100644 --- a/src/providers/exams.ts +++ b/src/providers/exams.ts @@ -4,13 +4,13 @@ import { Exam } from '../models/exam' class ExamProvider { static async list(): Promise { - let exams = await request.get('http://www.mocky.io/v2/5d681ede33000054e7e65c3f') + const exams = await request.get('http://www.mocky.io/v2/5d681ede33000054e7e65c3f') return formatter.extractFields(JSON.parse(exams.toString()).exams) } static async byId(id: string): Promise { - let exams = await request.get('http://www.mocky.io/v2/5d681ede33000054e7e65c3f') - let formatted = JSON.parse(exams.toString()).exams + const exams = await request.get('http://www.mocky.io/v2/5d681ede33000054e7e65c3f') + const formatted = JSON.parse(exams.toString()).exams return formatted.find( (item: any) => item.id === id) } } diff --git a/src/routes/customer.ts b/src/routes/customer.ts index 42d50b9..b49a191 100644 --- a/src/routes/customer.ts +++ b/src/routes/customer.ts @@ -4,7 +4,7 @@ import { CustomerController } from '../http/controllers/index' const CustomerRoutes = Router() const controller = new CustomerController() CustomerRoutes.post('/customers', controller.save) -CustomerRoutes.put('/customers', controller.update) +CustomerRoutes.put('/customers/:cpf', controller.update) CustomerRoutes.delete('/customers/:cpf', controller.remove) CustomerRoutes.get('/customers/:cpf', controller.find) diff --git a/src/server.ts b/src/server.ts index a0f4baa..954f1bc 100644 --- a/src/server.ts +++ b/src/server.ts @@ -1,3 +1,3 @@ import App from './app' - -App.start(4446) \ No newline at end of file +const port = parseInt(process.env.PORT) || 4446 +App.start(port) \ No newline at end of file diff --git a/src/services/schedule.ts b/src/services/schedule.ts index dde3589..e5a91e2 100644 --- a/src/services/schedule.ts +++ b/src/services/schedule.ts @@ -17,21 +17,21 @@ class ScheduleService { public async save(data: Schedule) { - let exam = await this.exam.get(data.examId.toString()) - let customer = await this.customer.find(data.cpf) + const exam = await this.exam.get(data.examId.toString()) + const customer = await this.customer.find(data.cpf) if (exam && customer.success) { let formattedDate = data.date const customersAtThisTime = this.connection.getByScheduleByDate(data.examId.toString(), formattedDate) - let maxByTime = process.env.MAX_BY_TIME || 2 + const maxByTime = process.env.MAX_BY_TIME || 2 if (customersAtThisTime.length < maxByTime) { data.price = exam.value formattedDate = data.date data = { ...data, date: formattedDate } - return this.connection.schedule({ ...data, examId: data.examId.toString() }) + return this.connection.createSchedule({ ...data, examId: data.examId.toString() }) } } @@ -52,7 +52,7 @@ class ScheduleService { } public async update(id: number, date: any) { - let formattedDate = date + const formattedDate = date return this.connection.updateSchedule(id, formattedDate) } From 76ee039100804a110c82766518b550a7bd0a787b Mon Sep 17 00:00:00 2001 From: Luiz Filho Date: Sun, 22 Sep 2019 22:29:31 -0300 Subject: [PATCH 62/65] added README.md --- README.md | 183 ++++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 183 insertions(+) diff --git a/README.md b/README.md index e69de29..00ddd36 100644 --- a/README.md +++ b/README.md @@ -0,0 +1,183 @@ +Desafio Back-end NodeJS - Grupo Fleury - Luiz Filho + +==== + + + +## Para executar a aplicação: + + + +- Deverá ter o **docker** e o **docker-compose** instalados na máquina host + +- Clonar o repositório no github + +- Acessar a pasta da aplicação no host local + +- Para ter a aplicação executando dentro de um container, executar o seguinte comando: + +> **docker-compose up -d --build** + +- Para manter o terminal preso enquanto executa, rodar: + +> **docker-compose up --build** + + + +- Opcionalmente, para executar localmente, sem container, deve-se executar os seguintes comandos: + +> **npm install** + +> **npm run dev** + + + +- Apos isso, a API estará disponível para ser consumida. As rotas disponível estão no **Swagger**, que está executando em: + +> **http://localhost:4446/documentation** + + + +- Para auxiliar, no diretório raiz do projeto tem um diretório **./docs**, que contém um arquivo **challenge-backend.postman_collection.json** com uma collection do postman. Basta importá-lo no **Postman** para ter as rotas prontas para consumir todos os endpoints da API. + + +## Para executar os testes unitaŕios: + +- Ter o NodeJS instalado na máquina host + +- Executar os comandos abaixo: +> **npm install** + +> **npm run test** + + +## Requisições usadas para desenvolver e testar: + +Na pasta, **./docs**, na raiz do projeto, tem um arquivo **challenge-backend.postman_collection,json**. + +Esse arquivo deve ser importado no Postman. Com isso, terá acesso a todas as requests para teste e uso da API. + + + +## Regras de Negócio + + +- "Não é possível agendar mais de 2 pacientes para o mesmo exame na mesma data e hora" + +> **Isso está parametrizado via variavel de ambiente, sendo o default, 2.** + + +## Features + +- Deverá haver um endpoint para listagem dos exames disponíveis para agendamento, exibindo apenas nome do exame e id : *GET /exams* + +- Deverá haver um endpoint para criação de um cliente : *POST /customers* + +- Deverá haver um endpoint para atualização de um cliente : *PUT /customers* + +- Deverá haver um endpoint para exclusão de um cliente : *DELETE /customers* + +- Deverá haver um endpoint para busca de um cliente baseado no seu cpf : *GET /customers/{cpf}* + +- Deverá haver um endpoint para listagem de todos os clientes cadastrados : *GET /customers* + + +- Deverá haver um endpoint para listagem dos agendamentos de um cliente por cpf, deverá conter o valor total (soma dos valores dos exames selecionados para o agendamento) : *GET /schedules/{cpf}* + +- Deverá haver um endpoint para edição de um agendamento realizado, apenas dia e hora poderão ser editados : *PUT /schedules/{id}* + +- Deverá haver um endpoint para exclusão de um agendamento realizado : *DELETE /schedules/{id}* + + +## Requisitos + + +- O **swagger** está disponível em **http://{domain}:4446/documentation** + +- Os testes unitários cobrem os Serviços *(.src/services)* da aplicação. Eles foram divididos em subpastas com base nas entidades do domínio. Os testes estão na **./tests/unit**. Foi usado o **Jest**. + +- Foi criado um objeto *Singleton* em **./data/db** para simular a base de dados em memória, fazendo uso desse *Design Pattern* para gerenciar o estado dos dados. + +- O superset **Typescript** foi utilizado no desenvolvimento. + + +## Diferencial + +- Tenha em mente conceitos de **SOLID** e **clean architecture** + +- **Docker** e **docker compose** + +- Esteira de CI/CD no github: **Travis CI** foi usado para execução dos testes unitários após o push. + +## Arquitetura + +O servidor da Api foi baseado no framework Web **Express**. A configuração e inicialização do Express está no **./src/app**. + +As configurações de servidor e registros de *rotas*, *middlwares* e do *Swagger* ficam no arquivo **./src/app**. Ao final, é exportada uma instância de um servidor. + +No **./src/server** esse servidor é importado e iniciado, sendo um ouvinte na **porta** **4446**. + +Os arquivos de variaveis de ambiente estão em **./env/***. O parâmetro do número máximo de agendamentos no mesmo horário, está no arquivo env. + +Para resolver a questão da simulação do banco de dados em memória, foi criado um *Singleton* em **./data/db**. O objeto *Singleton* é usado por toda a aplicação, abstraindo o acesso aos dados. + +Todo o *domínio/coleções/tabelas* foram estruturado na mesma instancia do objeto *Singleton*, sendo as todas as entidades representadas pelos atributos desse objeto. Essas entidades são acessadas via métodos. Resumindo, essa estrutura foi pensada para facilitar o acesso aos dados, tanto com a aplicação em execucução quanto para execução dos testes unitários. + +As collections do postman, usadas para desenvolvimento e testes, estão na pasta ./docs. + +Os testes unitários estão em **./tests/unit**. Esse subdiretório *unit* foi criado com a intenção de separar de outros tipos de testes que possam surgir com o andamento do projeto, como testes de integração e *end to end*, por exemplo. + +Dentro de **./tests/unit**, os testes foram dividos pensando no domínio, sendo separado em três diretórios: **customer**, **exam** e **schedule**. Os testes cobrem a camada de serviço, sendo o acesso a dados mockado. A chamada a API externa dos exames também foi coberta por teste, sendo a mockado o pacote usado para fazer a requisição. O **TDD** foi aplicado. + +O principal diretório da aplicação, onde o domínio foi dividido, pensando em níveis de abstração, é o **./src**. A aplicação foi dividida em *Layers* baseadas em abstração. Conforme a aplicação evolui, tendendo a crescer em tamanho e complexidade, podem ser criadas subcamadas com uma divisão baseadas em recursos. Essa abordagem de divisão por recursos é usada em por outros framework web para APIs. O **Express** "sugere" a divisão usada aqui. + +O diretório **./src/http** contém todas as partes para abstrair a manipulação de requisições e respostas para dos clients da API. Essa camada conta com subcamadas, que visam dividar as responsabilidades, deixando-as bem definidas e simples de visualizar. Compoem essa camada os *controllers* e os *middlewares*. Observando que, para este escopo/domínio, não foi implementada nenhum *middlware*. Somente, foram usados *middlwares* nativos do **Express**, que estão configuros e registrados no arquivo de servidor **./src/app**. + +Na camada de *controllers*, temos uma divisão por recursos. + +- **customerController**: responsável por tratar requisições para o domínio de Clientes/Pacientes. + +- **examController**: responsável pelo tratamento de requisições para o domínio de Exames. + +- **scheduleController**: trata das interações com o domínio de Agendamento de Exames + + + +O arquivo de **./src/http/controllers/index** é usado para centralizar o acesso aos *controllers*. Todos os *controllers* são importados nesse arquivo, que é importado por quem desejar acessar algums dos *controllers*. + + + +O diretório de **./src/routes** segue a mesma divisão por recursos dos *controllers*. Um arquivo **index** também foi usado para centralizar o acesso a elas por parte do servidor. Existe um arquivo de rota para cada *controller*. + +As responsabilidades dos arquivos de rotas são: + +> mapeamento dos controllers para seus domínios + +> além de disponiblizar os verbos http que estão disponíves para os recursos. + +A camada **./src/providers** foi criada para a interação com a API externa. Nesse diretório tem um único provider Exam. Nele está uma classe para a interação com a API externa. Essa classe possui métodos estáticos para obtenção do conteúdo, visto que é uma classe exclusiva para isso, foi feita a opção por deixar os métodos no escopo de classe, não necessitando do acesso a dados por operações com os objetos. Nessa camada podem ser colocadas classes e/ou funções para interação com pacotes de terceiros, containeres para injeção de dependencia, entre outros. + +Na camada de serviço **./src/services** ficam os arquivos que interagem com o banco de dados e com os providers, por exemplo. Essa camada, também, é divida por arquivos separando os recursos. Um **index** é usado para centralizar o acesso. + +O tratamento do dado que é enviado na requisição e retornado na resposta é tratado nessa camada, se for uma regra de negócio. Formatação, procurou-se deixar para **helpers** e para a camada mais alta na abstração, os *controllers*. + +*Middlewares* poderiam ser usados para interceptar as requisições e as respostas, porém, pelo fato do domínio ser relativamente pequeno, optou-se por adicionar campos nesse fluxo simples. + +Uma "camada" de **helpers** foi adicionada. Ela poderia não ser uma camada e ficar fora de src, porém, como todo o domínio está em src, optou-se por mantê-la aqui. Essa camada pode seracessada por qualquer parte do sistema, desde que, faça sentido tal uso. Esse **helper **é usado para formatar a resposta da API externa. Optou-se por dividir essa responsabilidade para deixar o provider mais simples e fácil de manter. + + + +A camada de models fica com as interfaces das entidades do negócio. Nela, foram criados arquivos diferentes para cada entidade do domínio, isso para "tipagem" dos objetos trafegados entre as camadas. + +Conforme a aplicação cresce, o nível de abstração pode ser elevado, criando interfaces de mais alto nível, e também pode-se trabalhar num nível masi baixo, criando subtipos, dando granularidade, tratando os dados de maneira mas especifica. +Pesa na balança a complexidade versus o controle mais fino dos dados. + +Um diretório com as configurações para load das variáveis de ambiente também está em **./src/config**. + +Há, na raiz do projeto, um **Dockerfile** para setup do **container docker** para rodar o **NodeJS**. Para a execução do container, foi usado o **docker-compose**. Aqui, é apenas um container para subir, porém, caso seja necessário outros serviços para criar um ecossistema maior, facilitará a adição de outros containeres. + +**Travis** foi configurado para executar os testes unitários após o *push*. + + + +O **Swagger** executa em **http://{HOST}:4446/documentation**. \ No newline at end of file From 419b7451d5ac8713c309cf19c7ab69451bd60a48 Mon Sep 17 00:00:00 2001 From: Luiz Filho Date: Sun, 22 Sep 2019 22:35:15 -0300 Subject: [PATCH 63/65] added selo travis --- README.md | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/README.md b/README.md index 00ddd36..0dbc04b 100644 --- a/README.md +++ b/README.md @@ -1,4 +1,7 @@ -Desafio Back-end NodeJS - Grupo Fleury - Luiz Filho +[![Build Status](https://travis-ci.org/LUIZFH/desafio-backend.svg?branch=master)](https://travis-ci.org/LUIZFH/desafio-backend) + +==== +Desafio Back-end NodeJS - Grupo Fleury - Luiz Filho ==== From ac7cdef5e5d26d56572b1d9890ad55d449fc8d86 Mon Sep 17 00:00:00 2001 From: Luiz Filho Date: Sun, 22 Sep 2019 22:36:14 -0300 Subject: [PATCH 64/65] updated format README.md --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 0dbc04b..4a819db 100644 --- a/README.md +++ b/README.md @@ -1,6 +1,6 @@ [![Build Status](https://travis-ci.org/LUIZFH/desafio-backend.svg?branch=master)](https://travis-ci.org/LUIZFH/desafio-backend) -==== + Desafio Back-end NodeJS - Grupo Fleury - Luiz Filho ==== From 5613b1de7026b951ab7300b346bd0db60248e2c0 Mon Sep 17 00:00:00 2001 From: Luiz Filho Date: Thu, 24 Oct 2019 21:22:15 -0300 Subject: [PATCH 65/65] Update README.md --- README.md | 185 ------------------------------------------------------ 1 file changed, 185 deletions(-) diff --git a/README.md b/README.md index 4a819db..8b13789 100644 --- a/README.md +++ b/README.md @@ -1,186 +1 @@ -[![Build Status](https://travis-ci.org/LUIZFH/desafio-backend.svg?branch=master)](https://travis-ci.org/LUIZFH/desafio-backend) - -Desafio Back-end NodeJS - Grupo Fleury - Luiz Filho - -==== - - - -## Para executar a aplicação: - - - -- Deverá ter o **docker** e o **docker-compose** instalados na máquina host - -- Clonar o repositório no github - -- Acessar a pasta da aplicação no host local - -- Para ter a aplicação executando dentro de um container, executar o seguinte comando: - -> **docker-compose up -d --build** - -- Para manter o terminal preso enquanto executa, rodar: - -> **docker-compose up --build** - - - -- Opcionalmente, para executar localmente, sem container, deve-se executar os seguintes comandos: - -> **npm install** - -> **npm run dev** - - - -- Apos isso, a API estará disponível para ser consumida. As rotas disponível estão no **Swagger**, que está executando em: - -> **http://localhost:4446/documentation** - - - -- Para auxiliar, no diretório raiz do projeto tem um diretório **./docs**, que contém um arquivo **challenge-backend.postman_collection.json** com uma collection do postman. Basta importá-lo no **Postman** para ter as rotas prontas para consumir todos os endpoints da API. - - -## Para executar os testes unitaŕios: - -- Ter o NodeJS instalado na máquina host - -- Executar os comandos abaixo: -> **npm install** - -> **npm run test** - - -## Requisições usadas para desenvolver e testar: - -Na pasta, **./docs**, na raiz do projeto, tem um arquivo **challenge-backend.postman_collection,json**. - -Esse arquivo deve ser importado no Postman. Com isso, terá acesso a todas as requests para teste e uso da API. - - - -## Regras de Negócio - - -- "Não é possível agendar mais de 2 pacientes para o mesmo exame na mesma data e hora" - -> **Isso está parametrizado via variavel de ambiente, sendo o default, 2.** - - -## Features - -- Deverá haver um endpoint para listagem dos exames disponíveis para agendamento, exibindo apenas nome do exame e id : *GET /exams* - -- Deverá haver um endpoint para criação de um cliente : *POST /customers* - -- Deverá haver um endpoint para atualização de um cliente : *PUT /customers* - -- Deverá haver um endpoint para exclusão de um cliente : *DELETE /customers* - -- Deverá haver um endpoint para busca de um cliente baseado no seu cpf : *GET /customers/{cpf}* - -- Deverá haver um endpoint para listagem de todos os clientes cadastrados : *GET /customers* - - -- Deverá haver um endpoint para listagem dos agendamentos de um cliente por cpf, deverá conter o valor total (soma dos valores dos exames selecionados para o agendamento) : *GET /schedules/{cpf}* - -- Deverá haver um endpoint para edição de um agendamento realizado, apenas dia e hora poderão ser editados : *PUT /schedules/{id}* - -- Deverá haver um endpoint para exclusão de um agendamento realizado : *DELETE /schedules/{id}* - - -## Requisitos - - -- O **swagger** está disponível em **http://{domain}:4446/documentation** - -- Os testes unitários cobrem os Serviços *(.src/services)* da aplicação. Eles foram divididos em subpastas com base nas entidades do domínio. Os testes estão na **./tests/unit**. Foi usado o **Jest**. - -- Foi criado um objeto *Singleton* em **./data/db** para simular a base de dados em memória, fazendo uso desse *Design Pattern* para gerenciar o estado dos dados. - -- O superset **Typescript** foi utilizado no desenvolvimento. - - -## Diferencial - -- Tenha em mente conceitos de **SOLID** e **clean architecture** - -- **Docker** e **docker compose** - -- Esteira de CI/CD no github: **Travis CI** foi usado para execução dos testes unitários após o push. - -## Arquitetura - -O servidor da Api foi baseado no framework Web **Express**. A configuração e inicialização do Express está no **./src/app**. - -As configurações de servidor e registros de *rotas*, *middlwares* e do *Swagger* ficam no arquivo **./src/app**. Ao final, é exportada uma instância de um servidor. - -No **./src/server** esse servidor é importado e iniciado, sendo um ouvinte na **porta** **4446**. - -Os arquivos de variaveis de ambiente estão em **./env/***. O parâmetro do número máximo de agendamentos no mesmo horário, está no arquivo env. - -Para resolver a questão da simulação do banco de dados em memória, foi criado um *Singleton* em **./data/db**. O objeto *Singleton* é usado por toda a aplicação, abstraindo o acesso aos dados. - -Todo o *domínio/coleções/tabelas* foram estruturado na mesma instancia do objeto *Singleton*, sendo as todas as entidades representadas pelos atributos desse objeto. Essas entidades são acessadas via métodos. Resumindo, essa estrutura foi pensada para facilitar o acesso aos dados, tanto com a aplicação em execucução quanto para execução dos testes unitários. - -As collections do postman, usadas para desenvolvimento e testes, estão na pasta ./docs. - -Os testes unitários estão em **./tests/unit**. Esse subdiretório *unit* foi criado com a intenção de separar de outros tipos de testes que possam surgir com o andamento do projeto, como testes de integração e *end to end*, por exemplo. - -Dentro de **./tests/unit**, os testes foram dividos pensando no domínio, sendo separado em três diretórios: **customer**, **exam** e **schedule**. Os testes cobrem a camada de serviço, sendo o acesso a dados mockado. A chamada a API externa dos exames também foi coberta por teste, sendo a mockado o pacote usado para fazer a requisição. O **TDD** foi aplicado. - -O principal diretório da aplicação, onde o domínio foi dividido, pensando em níveis de abstração, é o **./src**. A aplicação foi dividida em *Layers* baseadas em abstração. Conforme a aplicação evolui, tendendo a crescer em tamanho e complexidade, podem ser criadas subcamadas com uma divisão baseadas em recursos. Essa abordagem de divisão por recursos é usada em por outros framework web para APIs. O **Express** "sugere" a divisão usada aqui. - -O diretório **./src/http** contém todas as partes para abstrair a manipulação de requisições e respostas para dos clients da API. Essa camada conta com subcamadas, que visam dividar as responsabilidades, deixando-as bem definidas e simples de visualizar. Compoem essa camada os *controllers* e os *middlewares*. Observando que, para este escopo/domínio, não foi implementada nenhum *middlware*. Somente, foram usados *middlwares* nativos do **Express**, que estão configuros e registrados no arquivo de servidor **./src/app**. - -Na camada de *controllers*, temos uma divisão por recursos. - -- **customerController**: responsável por tratar requisições para o domínio de Clientes/Pacientes. - -- **examController**: responsável pelo tratamento de requisições para o domínio de Exames. - -- **scheduleController**: trata das interações com o domínio de Agendamento de Exames - - - -O arquivo de **./src/http/controllers/index** é usado para centralizar o acesso aos *controllers*. Todos os *controllers* são importados nesse arquivo, que é importado por quem desejar acessar algums dos *controllers*. - - - -O diretório de **./src/routes** segue a mesma divisão por recursos dos *controllers*. Um arquivo **index** também foi usado para centralizar o acesso a elas por parte do servidor. Existe um arquivo de rota para cada *controller*. - -As responsabilidades dos arquivos de rotas são: - -> mapeamento dos controllers para seus domínios - -> além de disponiblizar os verbos http que estão disponíves para os recursos. - -A camada **./src/providers** foi criada para a interação com a API externa. Nesse diretório tem um único provider Exam. Nele está uma classe para a interação com a API externa. Essa classe possui métodos estáticos para obtenção do conteúdo, visto que é uma classe exclusiva para isso, foi feita a opção por deixar os métodos no escopo de classe, não necessitando do acesso a dados por operações com os objetos. Nessa camada podem ser colocadas classes e/ou funções para interação com pacotes de terceiros, containeres para injeção de dependencia, entre outros. - -Na camada de serviço **./src/services** ficam os arquivos que interagem com o banco de dados e com os providers, por exemplo. Essa camada, também, é divida por arquivos separando os recursos. Um **index** é usado para centralizar o acesso. - -O tratamento do dado que é enviado na requisição e retornado na resposta é tratado nessa camada, se for uma regra de negócio. Formatação, procurou-se deixar para **helpers** e para a camada mais alta na abstração, os *controllers*. - -*Middlewares* poderiam ser usados para interceptar as requisições e as respostas, porém, pelo fato do domínio ser relativamente pequeno, optou-se por adicionar campos nesse fluxo simples. - -Uma "camada" de **helpers** foi adicionada. Ela poderia não ser uma camada e ficar fora de src, porém, como todo o domínio está em src, optou-se por mantê-la aqui. Essa camada pode seracessada por qualquer parte do sistema, desde que, faça sentido tal uso. Esse **helper **é usado para formatar a resposta da API externa. Optou-se por dividir essa responsabilidade para deixar o provider mais simples e fácil de manter. - - - -A camada de models fica com as interfaces das entidades do negócio. Nela, foram criados arquivos diferentes para cada entidade do domínio, isso para "tipagem" dos objetos trafegados entre as camadas. - -Conforme a aplicação cresce, o nível de abstração pode ser elevado, criando interfaces de mais alto nível, e também pode-se trabalhar num nível masi baixo, criando subtipos, dando granularidade, tratando os dados de maneira mas especifica. -Pesa na balança a complexidade versus o controle mais fino dos dados. - -Um diretório com as configurações para load das variáveis de ambiente também está em **./src/config**. - -Há, na raiz do projeto, um **Dockerfile** para setup do **container docker** para rodar o **NodeJS**. Para a execução do container, foi usado o **docker-compose**. Aqui, é apenas um container para subir, porém, caso seja necessário outros serviços para criar um ecossistema maior, facilitará a adição de outros containeres. - -**Travis** foi configurado para executar os testes unitários após o *push*. - - - -O **Swagger** executa em **http://{HOST}:4446/documentation**. \ No newline at end of file