diff --git a/.env.dist b/.env.dist index 9e9a88b..8b9c3db 100644 --- a/.env.dist +++ b/.env.dist @@ -1,4 +1,5 @@ DB_PATH=./data/database.db +JSON_DB_PATH=./data/clubs.json API_FOOTBALL_DATA= SESSION_DB_PATH=./data/session.db SESSION_SECRET=secreto por default (que puede tener espacios y caracteres no alfanuméricos) diff --git a/README.md b/README.md index 5ecdb2a..dfd7367 100644 --- a/README.md +++ b/README.md @@ -4,6 +4,8 @@ Un CRUD/ABM (Create, Retrieve, Update, Delete ó Alta, Baja, Modificación) de c ## Diagrama + + ## Cómo instalar y correr este proyecto El proyecto se instala con `npm install` @@ -29,9 +31,6 @@ Adaptado de https://softwareontheroad.com/ideal-nodejs-project-structure/ | Ruta | explicación | | -------------------------------- | ----------------------------------------------------------------------------------------------------------------------------- | -| data | contiene las bases de datos de SQLite | -| data/database.db | base de datos principal del proyecto | -| data/session.db | base de datos para guardar las sesiones de nuestro proyecto | | public | contiene los archivos estáticos que va a servir el navegador, acá se guardan las imágenes subidas | | src | contiene toda nuestra aplicación | | src/app.js | punto de entrada de nuestra aplicación | @@ -52,10 +51,6 @@ Adaptado de https://softwareontheroad.com/ideal-nodejs-project-structure/ | src/module/club/view | archivos de presentación (interfaz) que se procesarán del lado del servidor (SSR, server side rendering) | | src/module/club/module.js | archivo de entrada a este módulo que lo inicializa | -## Creando modelos nuevos - -Si se crea un modelo de Sequelize nuevo, recordar cargarlo en el archivo `src/cli/init.db.js` para que la sincronización de la base de datos incluya el nuevo modelo. - ## Configuración del IDE El IDE debe soportar Prettier + ESLint, como por ejemplo (vscode)[https://blog.echobind.com/integrating-prettier-eslint-airbnb-style-guide-in-vscode-47f07b5d7d6a] diff --git a/clubes_crud.jpg b/clubes_crud.jpg deleted file mode 100644 index aa0b1d6..0000000 Binary files a/clubes_crud.jpg and /dev/null differ diff --git a/crud_clubes_simple.png b/crud_clubes_simple.png new file mode 100644 index 0000000..6e3b649 Binary files /dev/null and b/crud_clubes_simple.png differ diff --git a/package-lock.json b/package-lock.json index d4fde6e..d6a30dd 100644 --- a/package-lock.json +++ b/package-lock.json @@ -440,6 +440,14 @@ "tough-cookie": "~2.5.0", "tunnel-agent": "^0.6.0", "uuid": "^3.3.2" + }, + "dependencies": { + "uuid": { + "version": "3.4.0", + "resolved": "https://registry.npmjs.org/uuid/-/uuid-3.4.0.tgz", + "integrity": "sha512-HjSDRw6gZE5JMggctHBcjVak08+KEVhSIiDzFnT9S9aegmp85S/bReBVTb4QTFaRNptJ9kuYaNhnbNEOkbKb/A==", + "dev": true + } } }, "@cypress/xvfb": { @@ -1132,7 +1140,8 @@ "@types/node": { "version": "14.0.14", "resolved": "https://registry.npmjs.org/@types/node/-/node-14.0.14.tgz", - "integrity": "sha512-syUgf67ZQpaJj01/tRTknkMNoBBLWJOBODF0Zm4NrXmiSuxjymFrxnTu1QVYRubhVkRcZLYZG8STTwJRdVm/WQ==" + "integrity": "sha512-syUgf67ZQpaJj01/tRTknkMNoBBLWJOBODF0Zm4NrXmiSuxjymFrxnTu1QVYRubhVkRcZLYZG8STTwJRdVm/WQ==", + "dev": true }, "@types/normalize-package-data": { "version": "2.4.0", @@ -1228,7 +1237,8 @@ "abbrev": { "version": "1.1.1", "resolved": "https://registry.npmjs.org/abbrev/-/abbrev-1.1.1.tgz", - "integrity": "sha512-nne9/IiQ/hzIhY6pdDnbBtz7DjPTKrY00P/zvPSm5pOFkl6xuGrGnXn/VtTNNfNtAfZ9/1RtehkszU9qcTii0Q==" + "integrity": "sha512-nne9/IiQ/hzIhY6pdDnbBtz7DjPTKrY00P/zvPSm5pOFkl6xuGrGnXn/VtTNNfNtAfZ9/1RtehkszU9qcTii0Q==", + "dev": true }, "accepts": { "version": "1.3.7", @@ -1271,6 +1281,7 @@ "version": "6.12.3", "resolved": "https://registry.npmjs.org/ajv/-/ajv-6.12.3.tgz", "integrity": "sha512-4K0cK3L1hsqk9xIb2z9vs/XU+PGJZ9PNpJRDS9YLzmNdX6jmVPfamLvTJr0aDAusnHyCHO6MjzlkAsgtqp9teA==", + "dev": true, "requires": { "fast-deep-equal": "^3.1.1", "fast-json-stable-stringify": "^2.0.0", @@ -1344,11 +1355,6 @@ "integrity": "sha512-/FQM1EDkTsf63Ub2C6O7GuYFDsSXUwsaZDurV0np41ocwq0jthUAYCmhBX9f+KwlaCgIuWyr/4WlUQUBfKfZog==", "dev": true }, - "any-promise": { - "version": "1.3.0", - "resolved": "https://registry.npmjs.org/any-promise/-/any-promise-1.3.0.tgz", - "integrity": "sha1-q8av7tzqUugJzcA3au0845Y10X8=" - }, "anymatch": { "version": "3.1.1", "resolved": "https://registry.npmjs.org/anymatch/-/anymatch-3.1.1.tgz", @@ -1410,11 +1416,6 @@ "integrity": "sha1-45sJrqne+Gao8gbiiK9jkZuuOcQ=", "dev": true }, - "array-filter": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/array-filter/-/array-filter-1.0.0.tgz", - "integrity": "sha1-uveeYubvTCpMC4MSMtr/7CUfnYM=" - }, "array-flatten": { "version": "1.1.1", "resolved": "https://registry.npmjs.org/array-flatten/-/array-flatten-1.1.1.tgz", @@ -1456,6 +1457,7 @@ "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" } @@ -1463,7 +1465,8 @@ "assert-plus": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/assert-plus/-/assert-plus-1.0.0.tgz", - "integrity": "sha1-8S4PPF13sLHN2RRpQuTpbB5N1SU=" + "integrity": "sha1-8S4PPF13sLHN2RRpQuTpbB5N1SU=", + "dev": true }, "assign-symbols": { "version": "1.0.0", @@ -1486,7 +1489,8 @@ "asynckit": { "version": "0.4.0", "resolved": "https://registry.npmjs.org/asynckit/-/asynckit-0.4.0.tgz", - "integrity": "sha1-x57Zf380y48robyXkLzDZkdLS3k=" + "integrity": "sha1-x57Zf380y48robyXkLzDZkdLS3k=", + "dev": true }, "atob": { "version": "2.1.2", @@ -1494,23 +1498,17 @@ "integrity": "sha512-Wm6ukoaOGJi/73p/cl2GvLjTI5JM1k/O14isD73YML8StrH/7/lRFgmg8nICZgD3bZZvjwCGxtMOD3wWNAu8cg==", "dev": true }, - "available-typed-arrays": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/available-typed-arrays/-/available-typed-arrays-1.0.2.tgz", - "integrity": "sha512-XWX3OX8Onv97LMk/ftVyBibpGwY5a8SmuxZPzeOxqmuEqUCOM9ZE+uIaD1VNJ5QnvU2UQusvmKbuM1FR8QWGfQ==", - "requires": { - "array-filter": "^1.0.0" - } - }, "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=" + "integrity": "sha1-tG6JCTSpWR8tL2+G1+ap8bP+dqg=", + "dev": true }, "aws4": { "version": "1.10.0", "resolved": "https://registry.npmjs.org/aws4/-/aws4-1.10.0.tgz", - "integrity": "sha512-3YDiu347mtVtjpyV3u5kVqQLP242c06zwDOgpeRnybmXlYYsLbtTrUBUm8i8srONt+FWobl5aibnU1030PeeuA==" + "integrity": "sha512-3YDiu347mtVtjpyV3u5kVqQLP242c06zwDOgpeRnybmXlYYsLbtTrUBUm8i8srONt+FWobl5aibnU1030PeeuA==", + "dev": true }, "axios": { "version": "0.19.2", @@ -1630,7 +1628,8 @@ "balanced-match": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.0.tgz", - "integrity": "sha1-ibTRmasr7kneFk6gK4nORi1xt2c=" + "integrity": "sha1-ibTRmasr7kneFk6gK4nORi1xt2c=", + "dev": true }, "base": { "version": "0.11.2", @@ -1687,26 +1686,63 @@ } } }, + "base64-js": { + "version": "1.3.1", + "resolved": "https://registry.npmjs.org/base64-js/-/base64-js-1.3.1.tgz", + "integrity": "sha512-mLQ4i2QO1ytvGWFWmcngKO//JXAQueZvwEKtjgQFM4jIK0kU+ytMfplL8j+n5mspOfjHwoAg+9yhb7BwAHm36g==" + }, "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" } }, + "better-sqlite3": { + "version": "7.1.0", + "resolved": "https://registry.npmjs.org/better-sqlite3/-/better-sqlite3-7.1.0.tgz", + "integrity": "sha512-FV/snQ8F/kyqhdxsevzbojVtMowDWOfe1A5N3lYu1KJwoho2t7JgITmdlSc7DkOh3Zq65I+ZyeNWXQrkLEDFTg==", + "requires": { + "bindings": "^1.5.0", + "prebuild-install": "^5.3.3", + "tar": "4.4.10" + } + }, "binary-extensions": { "version": "2.1.0", "resolved": "https://registry.npmjs.org/binary-extensions/-/binary-extensions-2.1.0.tgz", "integrity": "sha512-1Yj8h9Q+QDF5FzhMs/c9+6UntbD5MkRfRwac8DoEm9ZfUBZ7tZ55YcGVAzEe4bXsdQHEk+s9S5wsOKVdZrw0tQ==" }, - "block-stream": { - "version": "0.0.9", - "resolved": "https://registry.npmjs.org/block-stream/-/block-stream-0.0.9.tgz", - "integrity": "sha1-E+v+d4oDIFz+A3UUgeu0szAMEmo=", - "optional": true, + "bindings": { + "version": "1.5.0", + "resolved": "https://registry.npmjs.org/bindings/-/bindings-1.5.0.tgz", + "integrity": "sha512-p2q/t/mhvuOj/UeLlV6566GD/guowlr0hHxClI0W9m7MWYkL1F0hLo+0Aexs9HSPCtR1SXQ0TD3MMKrXZajbiQ==", + "requires": { + "file-uri-to-path": "1.0.0" + } + }, + "bl": { + "version": "4.0.2", + "resolved": "https://registry.npmjs.org/bl/-/bl-4.0.2.tgz", + "integrity": "sha512-j4OH8f6Qg2bGuWfRiltT2HYGx0e1QcBTrK9KAHNMwMZdQnDZFk0ZSYIpADjYCB3U12nicC5tVJwSIhwOWjb4RQ==", "requires": { - "inherits": "~2.0.0" + "buffer": "^5.5.0", + "inherits": "^2.0.4", + "readable-stream": "^3.4.0" + }, + "dependencies": { + "readable-stream": { + "version": "3.6.0", + "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-3.6.0.tgz", + "integrity": "sha512-BViHy7LKeTz4oNnkcLJ+lVSL6vpiFeX6/d3oSH8zCW7UxP2onchk+vTGB143xuFjHS3deTgkKoXXymXqymiIdA==", + "requires": { + "inherits": "^2.0.3", + "string_decoder": "^1.1.1", + "util-deprecate": "^1.0.1" + } + } } }, "bluebird": { @@ -1841,6 +1877,7 @@ "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" @@ -1869,6 +1906,15 @@ "node-int64": "^0.4.0" } }, + "buffer": { + "version": "5.6.0", + "resolved": "https://registry.npmjs.org/buffer/-/buffer-5.6.0.tgz", + "integrity": "sha512-/gDYp/UtU0eA1ys8bOs9J6a+E/KWIY+DZ+Q2WESNUA0jFRsJOc0SNUO6xJ5SGA1xueg3NL65W6s+NY5l9cunuw==", + "requires": { + "base64-js": "^1.0.2", + "ieee754": "^1.1.4" + } + }, "buffer-crc32": { "version": "0.2.13", "resolved": "https://registry.npmjs.org/buffer-crc32/-/buffer-crc32-0.2.13.tgz", @@ -1996,7 +2042,8 @@ "caseless": { "version": "0.12.0", "resolved": "https://registry.npmjs.org/caseless/-/caseless-0.12.0.tgz", - "integrity": "sha1-G2gcIf+EAzyCZUMJBolCDRhxUdw=" + "integrity": "sha1-G2gcIf+EAzyCZUMJBolCDRhxUdw=", + "dev": true }, "chalk": { "version": "2.4.2", @@ -2311,6 +2358,7 @@ "version": "1.0.8", "resolved": "https://registry.npmjs.org/combined-stream/-/combined-stream-1.0.8.tgz", "integrity": "sha512-FQN4MRfuJeHf7cBbBMJFXhKSDq+2kAArBlmRBvcvFE5BB1HZKXtSFASDhdlz9zOYwxh8lDdnvmMOe/+5cdoEdg==", + "dev": true, "requires": { "delayed-stream": "~1.0.0" } @@ -2336,7 +2384,8 @@ "concat-map": { "version": "0.0.1", "resolved": "https://registry.npmjs.org/concat-map/-/concat-map-0.0.1.tgz", - "integrity": "sha1-2Klr13/Wjfd5OnMDajug1UBdR3s=" + "integrity": "sha1-2Klr13/Wjfd5OnMDajug1UBdR3s=", + "dev": true }, "concat-stream": { "version": "1.6.2", @@ -2369,15 +2418,6 @@ "integrity": "sha512-KbS1Y0jMtyPgIxjO7ZzMAuUpAKMt1SzCL9fsrKsX6b0zJPTaT0SiSPmewwVZg9UAO83HVIlEhZF84LIjZ0lmAw==", "dev": true }, - "connect-session-sequelize": { - "version": "7.0.1", - "resolved": "https://registry.npmjs.org/connect-session-sequelize/-/connect-session-sequelize-7.0.1.tgz", - "integrity": "sha512-EDsHbhewpVigA+ZQtCKSNAnLmSp2/Nm6gUXmxUPzU7uAIbqThcZeDBO94GHimJvLN4UBe49yxeuZ9uFfGuXpzw==", - "requires": { - "debug": "^4.1.1", - "deep-equal": "^2.0.3" - } - }, "console-control-strings": { "version": "1.1.0", "resolved": "https://registry.npmjs.org/console-control-strings/-/console-control-strings-1.1.0.tgz", @@ -2538,6 +2578,7 @@ "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" } @@ -2563,6 +2604,7 @@ "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" } @@ -2585,32 +2627,12 @@ "integrity": "sha1-6zkTMzRYd1y4TNGh+uBiEGu4dUU=", "dev": true }, - "deep-equal": { - "version": "2.0.3", - "resolved": "https://registry.npmjs.org/deep-equal/-/deep-equal-2.0.3.tgz", - "integrity": "sha512-Spqdl4H+ky45I9ByyJtXteOm9CaIrPmnIPmOhrkKGNYWeDgCvJ8jNYVCTjChxW4FqGuZnLHADc8EKRMX6+CgvA==", + "decompress-response": { + "version": "4.2.1", + "resolved": "https://registry.npmjs.org/decompress-response/-/decompress-response-4.2.1.tgz", + "integrity": "sha512-jOSne2qbyE+/r8G1VU+G/82LBs2Fs4LAsTiLSHOCOMZQl2OKZ6i8i4IyHemTe+/yIXOtTcRQMzPcgyhoFlqPkw==", "requires": { - "es-abstract": "^1.17.5", - "es-get-iterator": "^1.1.0", - "is-arguments": "^1.0.4", - "is-date-object": "^1.0.2", - "is-regex": "^1.0.5", - "isarray": "^2.0.5", - "object-is": "^1.1.2", - "object-keys": "^1.1.1", - "object.assign": "^4.1.0", - "regexp.prototype.flags": "^1.3.0", - "side-channel": "^1.0.2", - "which-boxed-primitive": "^1.0.1", - "which-collection": "^1.0.1", - "which-typed-array": "^1.1.2" - }, - "dependencies": { - "isarray": { - "version": "2.0.5", - "resolved": "https://registry.npmjs.org/isarray/-/isarray-2.0.5.tgz", - "integrity": "sha512-xHjhDr3cNBK0BzdUJSPXZntQUx/mwMS5Rw4A7lPJ90XGAO6ISP/ePDNuo0vhqOZU+UD5JoodwCAAoZQd3FeAKw==" - } + "mimic-response": "^2.0.0" } }, "deep-extend": { @@ -2640,6 +2662,7 @@ "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" } @@ -2688,7 +2711,8 @@ "delayed-stream": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/delayed-stream/-/delayed-stream-1.0.0.tgz", - "integrity": "sha1-3zrhmayt+31ECqrgsp4icrJOxhk=" + "integrity": "sha1-3zrhmayt+31ECqrgsp4icrJOxhk=", + "dev": true }, "delegates": { "version": "1.0.0", @@ -2794,11 +2818,6 @@ "resolved": "https://registry.npmjs.org/dotenv/-/dotenv-8.2.0.tgz", "integrity": "sha512-8sJ78ElpbDJBHNeBzUbUVLsqKdccaa/BXF1uPTw3GrvQTBgrQrtObr2mUrE38vzYd8cEv+m/JBfDLioYcfXoaw==" }, - "dottie": { - "version": "2.0.2", - "resolved": "https://registry.npmjs.org/dottie/-/dottie-2.0.2.tgz", - "integrity": "sha512-fmrwR04lsniq/uSr8yikThDTrM7epXHBAAjH9TbeH3rEA8tdCO7mRzB9hdmdGyJCxF8KERo9CITcm3kGuoyMhg==" - }, "duplexer3": { "version": "0.1.4", "resolved": "https://registry.npmjs.org/duplexer3/-/duplexer3-0.1.4.tgz", @@ -2809,6 +2828,7 @@ "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" @@ -2840,7 +2860,6 @@ "version": "1.4.4", "resolved": "https://registry.npmjs.org/end-of-stream/-/end-of-stream-1.4.4.tgz", "integrity": "sha512-+uw1inIHVPQoaVuHzRyXd21icM+cnt4CzD5rW+NC1wjOUSTOs+Te7FOv7AhN7vS9x/oIyhLP5PR1H+phQAHu5Q==", - "dev": true, "requires": { "once": "^1.4.0" } @@ -2858,6 +2877,7 @@ "version": "1.17.6", "resolved": "https://registry.npmjs.org/es-abstract/-/es-abstract-1.17.6.tgz", "integrity": "sha512-Fr89bON3WFyUi5EvAeI48QTWX0AyekGgLA8H+c+7fbfCkJwRWRMLd8CQedNEyJuoYYhmtEqY92pgte1FAhBlhw==", + "dev": true, "requires": { "es-to-primitive": "^1.2.1", "function-bind": "^1.1.1", @@ -2872,31 +2892,11 @@ "string.prototype.trimstart": "^1.0.1" } }, - "es-get-iterator": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/es-get-iterator/-/es-get-iterator-1.1.0.tgz", - "integrity": "sha512-UfrmHuWQlNMTs35e1ypnvikg6jCz3SK8v8ImvmDsh36fCVUR1MqoFDiyn0/k52C8NqO3YsO8Oe0azeesNuqSsQ==", - "requires": { - "es-abstract": "^1.17.4", - "has-symbols": "^1.0.1", - "is-arguments": "^1.0.4", - "is-map": "^2.0.1", - "is-set": "^2.0.1", - "is-string": "^1.0.5", - "isarray": "^2.0.5" - }, - "dependencies": { - "isarray": { - "version": "2.0.5", - "resolved": "https://registry.npmjs.org/isarray/-/isarray-2.0.5.tgz", - "integrity": "sha512-xHjhDr3cNBK0BzdUJSPXZntQUx/mwMS5Rw4A7lPJ90XGAO6ISP/ePDNuo0vhqOZU+UD5JoodwCAAoZQd3FeAKw==" - } - } - }, "es-to-primitive": { "version": "1.2.1", "resolved": "https://registry.npmjs.org/es-to-primitive/-/es-to-primitive-1.2.1.tgz", "integrity": "sha512-QCOllgZJtaUo9miYBcLChTUaHNjJF3PYs1VidD7AwiEj1kYxKeQTctLAezAOH5ZKRH0g2IgPn6KwB4IT8iRpvA==", + "dev": true, "requires": { "is-callable": "^1.1.4", "is-date-object": "^1.0.1", @@ -3581,6 +3581,11 @@ } } }, + "expand-template": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/expand-template/-/expand-template-2.0.3.tgz", + "integrity": "sha512-XYfuKMvj4O35f/pOXLObndIRvyQ+/+6AhODh+OKWj9S9498pHHn/IMszH+gt0fBCRWMNfk1ZSp5x3AifmnI2vg==" + }, "expect": { "version": "26.1.0", "resolved": "https://registry.npmjs.org/expect/-/expect-26.1.0.tgz", @@ -3727,7 +3732,8 @@ "extend": { "version": "3.0.2", "resolved": "https://registry.npmjs.org/extend/-/extend-3.0.2.tgz", - "integrity": "sha512-fjquC59cD7CyW6urNXK0FBufkZcoiGG80wTuPujX590cB5Ttln20E2UB4S/WARVqhXffZl2LNgS+gQdPIIim/g==" + "integrity": "sha512-fjquC59cD7CyW6urNXK0FBufkZcoiGG80wTuPujX590cB5Ttln20E2UB4S/WARVqhXffZl2LNgS+gQdPIIim/g==", + "dev": true }, "extend-shallow": { "version": "3.0.2", @@ -3869,12 +3875,14 @@ "extsprintf": { "version": "1.3.0", "resolved": "https://registry.npmjs.org/extsprintf/-/extsprintf-1.3.0.tgz", - "integrity": "sha1-lpGEQOMEGnpBT4xS48V06zw+HgU=" + "integrity": "sha1-lpGEQOMEGnpBT4xS48V06zw+HgU=", + "dev": true }, "fast-deep-equal": { "version": "3.1.3", "resolved": "https://registry.npmjs.org/fast-deep-equal/-/fast-deep-equal-3.1.3.tgz", - "integrity": "sha512-f3qQ9oQy9j2AhBe/H9VC91wLmKBCCU/gDOnKNAYG5hswO7BLKj09Hc5HYNz9cGI++xlpDCIgDaitVs03ATR84Q==" + "integrity": "sha512-f3qQ9oQy9j2AhBe/H9VC91wLmKBCCU/gDOnKNAYG5hswO7BLKj09Hc5HYNz9cGI++xlpDCIgDaitVs03ATR84Q==", + "dev": true }, "fast-diff": { "version": "1.2.0", @@ -3885,7 +3893,8 @@ "fast-json-stable-stringify": { "version": "2.1.0", "resolved": "https://registry.npmjs.org/fast-json-stable-stringify/-/fast-json-stable-stringify-2.1.0.tgz", - "integrity": "sha512-lhd/wF+Lk98HZoTCtlVraHtfh5XYijIjalXck7saUtuanSDyLMxnHhSXEDJqHxD7msR8D0uCmqlkwjCV8xvwHw==" + "integrity": "sha512-lhd/wF+Lk98HZoTCtlVraHtfh5XYijIjalXck7saUtuanSDyLMxnHhSXEDJqHxD7msR8D0uCmqlkwjCV8xvwHw==", + "dev": true }, "fast-levenshtein": { "version": "2.0.6", @@ -3930,6 +3939,11 @@ "flat-cache": "^2.0.1" } }, + "file-uri-to-path": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/file-uri-to-path/-/file-uri-to-path-1.0.0.tgz", + "integrity": "sha512-0Zt+s3L7Vf1biwWZ29aARiVYLx7iMGnEUl9x33fbB/j3jR81u/O2LbqK+Bm1CDSNDKVtJ/YjwY7TUd5SkeLQLw==" + }, "fill-range": { "version": "7.0.1", "resolved": "https://registry.npmjs.org/fill-range/-/fill-range-7.0.1.tgz", @@ -4034,20 +4048,17 @@ "integrity": "sha1-gQaNKVqBQuwKxybG4iAMMPttXoA=", "dev": true }, - "foreach": { - "version": "2.0.5", - "resolved": "https://registry.npmjs.org/foreach/-/foreach-2.0.5.tgz", - "integrity": "sha1-C+4AUBiusmDQo6865ljdATbsG5k=" - }, "forever-agent": { "version": "0.6.1", "resolved": "https://registry.npmjs.org/forever-agent/-/forever-agent-0.6.1.tgz", - "integrity": "sha1-+8cfDEGt6zf5bFd60e1C2P2sypE=" + "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", @@ -4073,6 +4084,11 @@ "resolved": "https://registry.npmjs.org/fresh/-/fresh-0.5.2.tgz", "integrity": "sha1-PYyt2Q2XZWn6g1qx+OSyOhBWBac=" }, + "fs-constants": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/fs-constants/-/fs-constants-1.0.0.tgz", + "integrity": "sha512-y6OAwoSIf7FyjMIv94u+b5rdheZEjzR63GTyZJm5qh4Bi+2YgwLCcI/fPFZkL5PSixOt6ZNKm+w+Hfp/Bciwow==" + }, "fs-extra": { "version": "8.1.0", "resolved": "https://registry.npmjs.org/fs-extra/-/fs-extra-8.1.0.tgz", @@ -4095,7 +4111,8 @@ "fs.realpath": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/fs.realpath/-/fs.realpath-1.0.0.tgz", - "integrity": "sha1-FQStJSMVjKpA20onh8sBQRmU6k8=" + "integrity": "sha1-FQStJSMVjKpA20onh8sBQRmU6k8=", + "dev": true }, "fsevents": { "version": "2.1.3", @@ -4103,22 +4120,11 @@ "integrity": "sha512-Auw9a4AxqWpa9GUfj370BMPzzyncfBABW8Mab7BGWBYDj4Isgq+cDKtx0i6u9jcX9pQDnswsaaOTgTmA5pEjuQ==", "optional": true }, - "fstream": { - "version": "1.0.12", - "resolved": "https://registry.npmjs.org/fstream/-/fstream-1.0.12.tgz", - "integrity": "sha512-WvJ193OHa0GHPEL+AycEJgxvBEwyfRkN1vhjca23OaPVMCaLCXTd5qAu82AjTcgP1UJmytkOKb63Ypde7raDIg==", - "optional": true, - "requires": { - "graceful-fs": "^4.1.2", - "inherits": "~2.0.0", - "mkdirp": ">=0.5 0", - "rimraf": "2" - } - }, "function-bind": { "version": "1.1.1", "resolved": "https://registry.npmjs.org/function-bind/-/function-bind-1.1.1.tgz", - "integrity": "sha512-yIovAzMX49sF8Yl58fSCWJ5svSLuaibPxXQJFLmBObTuCr0Mf1KiPopGM9NiFjiYBCbfaa2Fh6breQ6ANVTI0A==" + "integrity": "sha512-yIovAzMX49sF8Yl58fSCWJ5svSLuaibPxXQJFLmBObTuCr0Mf1KiPopGM9NiFjiYBCbfaa2Fh6breQ6ANVTI0A==", + "dev": true }, "functional-red-black-tree": { "version": "1.0.1", @@ -4213,14 +4219,21 @@ "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" } }, + "github-from-package": { + "version": "0.0.0", + "resolved": "https://registry.npmjs.org/github-from-package/-/github-from-package-0.0.0.tgz", + "integrity": "sha1-l/tdlr/eiXMxPyDoKI75oWf6ZM4=" + }, "glob": { "version": "7.1.6", "resolved": "https://registry.npmjs.org/glob/-/glob-7.1.6.tgz", "integrity": "sha512-LwaxwyZ72Lk7vZINtNNrywX0ZuLyStrdDtabefZKAY5ZGJhVtgdznluResxNmPitE0SAO+O26sWTHeKSI2wMBA==", + "dev": true, "requires": { "fs.realpath": "^1.0.0", "inflight": "^1.0.4", @@ -4292,7 +4305,8 @@ "graceful-fs": { "version": "4.2.4", "resolved": "https://registry.npmjs.org/graceful-fs/-/graceful-fs-4.2.4.tgz", - "integrity": "sha512-WjKPNJF79dtJAVniUlGGWHYGz2jWxT6VhN/4m1NdkbZ2nOsEF+cI1Edgql5zCRhs/VsQYRvrXctxktVXZUkixw==" + "integrity": "sha512-WjKPNJF79dtJAVniUlGGWHYGz2jWxT6VhN/4m1NdkbZ2nOsEF+cI1Edgql5zCRhs/VsQYRvrXctxktVXZUkixw==", + "dev": true }, "growly": { "version": "1.3.0", @@ -4304,12 +4318,14 @@ "har-schema": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/har-schema/-/har-schema-2.0.0.tgz", - "integrity": "sha1-qUwiJOvKwEeCoNkDVSHyRzW37JI=" + "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" @@ -4319,6 +4335,7 @@ "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" } @@ -4341,7 +4358,8 @@ "has-symbols": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/has-symbols/-/has-symbols-1.0.1.tgz", - "integrity": "sha512-PLcsoqu++dmEIZB+6totNFKq/7Do+Z0u4oT0zKOJNl3lYK6vGwwu2hjHs+68OEZbTjiUE9bgOABXbP/GvrS0Kg==" + "integrity": "sha512-PLcsoqu++dmEIZB+6totNFKq/7Do+Z0u4oT0zKOJNl3lYK6vGwwu2hjHs+68OEZbTjiUE9bgOABXbP/GvrS0Kg==", + "dev": true }, "has-unicode": { "version": "2.0.1", @@ -4456,6 +4474,7 @@ "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", @@ -4476,6 +4495,11 @@ "safer-buffer": ">= 2.1.2 < 3" } }, + "ieee754": { + "version": "1.1.13", + "resolved": "https://registry.npmjs.org/ieee754/-/ieee754-1.1.13.tgz", + "integrity": "sha512-4vf7I2LYV/HaWerSo3XmlMkp5eZ83i+/CDluXi/IGTs/O1sejBNhTtnxzmRZfvOUqj7lZjqHkeTvpgSFDlWZTg==" + }, "ignore": { "version": "4.0.6", "resolved": "https://registry.npmjs.org/ignore/-/ignore-4.0.6.tgz", @@ -4488,14 +4512,6 @@ "integrity": "sha1-SMptcvbGo68Aqa1K5odr44ieKwk=", "dev": true }, - "ignore-walk": { - "version": "3.0.3", - "resolved": "https://registry.npmjs.org/ignore-walk/-/ignore-walk-3.0.3.tgz", - "integrity": "sha512-m7o6xuOaT1aqheYHKf8W6J5pYH85ZI9w077erOzLje3JsB1gkafkAhHHY19dqjulgIZHFm32Cp5uNZgcQqdJKw==", - "requires": { - "minimatch": "^3.0.4" - } - }, "import-fresh": { "version": "3.2.1", "resolved": "https://registry.npmjs.org/import-fresh/-/import-fresh-3.2.1.tgz", @@ -4542,15 +4558,11 @@ "integrity": "sha1-Sl/W0nzDMvN+VBmlBNu4NxBckok=", "dev": true }, - "inflection": { - "version": "1.12.0", - "resolved": "https://registry.npmjs.org/inflection/-/inflection-1.12.0.tgz", - "integrity": "sha1-ogCTVlbW9fa8TcdQLhrstwMihBY=" - }, "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" @@ -4745,22 +4757,12 @@ } } }, - "is-arguments": { - "version": "1.0.4", - "resolved": "https://registry.npmjs.org/is-arguments/-/is-arguments-1.0.4.tgz", - "integrity": "sha512-xPh0Rmt8NE65sNzvyUmWgI1tz3mKq74lGA0mL8LYZcoIzKOzDh6HmrYm3d18k60nHerC8A9Km8kYu87zfSFnLA==" - }, "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-bigint": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/is-bigint/-/is-bigint-1.0.0.tgz", - "integrity": "sha512-t5mGUXC/xRheCK431ylNiSkGGpBp8bHENBcENTkDT6ppwPzEVxNGZRvgvmOEfbWkFhA7D2GEuE2mmQTr78sl2g==" - }, "is-binary-path": { "version": "2.1.0", "resolved": "https://registry.npmjs.org/is-binary-path/-/is-binary-path-2.1.0.tgz", @@ -4769,11 +4771,6 @@ "binary-extensions": "^2.0.0" } }, - "is-boolean-object": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/is-boolean-object/-/is-boolean-object-1.0.1.tgz", - "integrity": "sha512-TqZuVwa/sppcrhUCAYkGBk7w0yxfQQnxq28fjkO53tnK9FQXmdwz2JS5+GjsWQ6RByES1K40nI+yDic5c9/aAQ==" - }, "is-buffer": { "version": "1.1.6", "resolved": "https://registry.npmjs.org/is-buffer/-/is-buffer-1.1.6.tgz", @@ -4783,7 +4780,8 @@ "is-callable": { "version": "1.2.0", "resolved": "https://registry.npmjs.org/is-callable/-/is-callable-1.2.0.tgz", - "integrity": "sha512-pyVD9AaGLxtg6srb2Ng6ynWJqkHU9bEM087AKck0w8QwDarTfNcpIYoU8x8Hv2Icm8u6kFJM18Dag8lyqGkviw==" + "integrity": "sha512-pyVD9AaGLxtg6srb2Ng6ynWJqkHU9bEM087AKck0w8QwDarTfNcpIYoU8x8Hv2Icm8u6kFJM18Dag8lyqGkviw==", + "dev": true }, "is-ci": { "version": "2.0.0", @@ -4817,7 +4815,8 @@ "is-date-object": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/is-date-object/-/is-date-object-1.0.2.tgz", - "integrity": "sha512-USlDT524woQ08aoZFzh3/Z6ch9Y/EWXEHQ/AaRN0SkKq4t2Jw2R2339tSXmwuVoY7LLlBCbOIlx2myP/L5zk0g==" + "integrity": "sha512-USlDT524woQ08aoZFzh3/Z6ch9Y/EWXEHQ/AaRN0SkKq4t2Jw2R2339tSXmwuVoY7LLlBCbOIlx2myP/L5zk0g==", + "dev": true }, "is-descriptor": { "version": "0.1.6", @@ -4885,11 +4884,6 @@ "is-path-inside": "^3.0.1" } }, - "is-map": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/is-map/-/is-map-2.0.1.tgz", - "integrity": "sha512-T/S49scO8plUiAOA2DBTBG3JHpn1yiw0kRp6dgiZ0v2/6twi5eiB0rHtHFH9ZIrvlWc6+4O+m4zg5+Z833aXgw==" - }, "is-npm": { "version": "4.0.0", "resolved": "https://registry.npmjs.org/is-npm/-/is-npm-4.0.0.tgz", @@ -4901,11 +4895,6 @@ "resolved": "https://registry.npmjs.org/is-number/-/is-number-7.0.0.tgz", "integrity": "sha512-41Cifkg6e8TylSpdtTpeLVMqvSBEVzTttHvERD741+pnZ8ANv0004MRL43QKPDlK9cGvNp6NZWZUBlbGXYxxng==" }, - "is-number-object": { - "version": "1.0.4", - "resolved": "https://registry.npmjs.org/is-number-object/-/is-number-object-1.0.4.tgz", - "integrity": "sha512-zohwelOAur+5uXtk8O3GPQ1eAcu4ZX3UwxQhUlfFFMNpUd83gXgjbhJh6HmB6LUNV/ieOLQuDwJO3dWJosUeMw==" - }, "is-obj": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/is-obj/-/is-obj-2.0.0.tgz", @@ -4952,15 +4941,11 @@ "version": "1.1.0", "resolved": "https://registry.npmjs.org/is-regex/-/is-regex-1.1.0.tgz", "integrity": "sha512-iI97M8KTWID2la5uYXlkbSDQIg4F6o1sYboZKKTDpnDQMLtUL86zxhgDet3Q2SriaYsyGqZ6Mn2SjbRKeLHdqw==", + "dev": true, "requires": { "has-symbols": "^1.0.1" } }, - "is-set": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/is-set/-/is-set-2.0.1.tgz", - "integrity": "sha512-eJEzOtVyenDs1TMzSQ3kU3K+E0GUS9sno+F0OBT97xsgcJsF9nXMBtkT9/kut5JEpM7oL7X/0qxR17K3mcwIAA==" - }, "is-stream": { "version": "1.1.0", "resolved": "https://registry.npmjs.org/is-stream/-/is-stream-1.1.0.tgz", @@ -4970,41 +4955,23 @@ "is-string": { "version": "1.0.5", "resolved": "https://registry.npmjs.org/is-string/-/is-string-1.0.5.tgz", - "integrity": "sha512-buY6VNRjhQMiF1qWDouloZlQbRhDPCebwxSjxMjxgemYT46YMd2NR0/H+fBhEfWX4A/w9TBJ+ol+okqJKFE6vQ==" + "integrity": "sha512-buY6VNRjhQMiF1qWDouloZlQbRhDPCebwxSjxMjxgemYT46YMd2NR0/H+fBhEfWX4A/w9TBJ+ol+okqJKFE6vQ==", + "dev": true }, "is-symbol": { "version": "1.0.3", "resolved": "https://registry.npmjs.org/is-symbol/-/is-symbol-1.0.3.tgz", "integrity": "sha512-OwijhaRSgqvhm/0ZdAcXNZt9lYdKFpcRDT5ULUuYXPoT794UNOdU+gpT6Rzo7b4V2HUl/op6GqY894AZwv9faQ==", + "dev": true, "requires": { "has-symbols": "^1.0.1" } }, - "is-typed-array": { - "version": "1.1.3", - "resolved": "https://registry.npmjs.org/is-typed-array/-/is-typed-array-1.1.3.tgz", - "integrity": "sha512-BSYUBOK/HJibQ30wWkWold5txYwMUXQct9YHAQJr8fSwvZoiglcqB0pd7vEN23+Tsi9IUEjztdOSzl4qLVYGTQ==", - "requires": { - "available-typed-arrays": "^1.0.0", - "es-abstract": "^1.17.4", - "foreach": "^2.0.5", - "has-symbols": "^1.0.1" - } - }, "is-typedarray": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/is-typedarray/-/is-typedarray-1.0.0.tgz", - "integrity": "sha1-5HnICFjfDBsR3dppQPlgEfzaSpo=" - }, - "is-weakmap": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/is-weakmap/-/is-weakmap-2.0.1.tgz", - "integrity": "sha512-NSBR4kH5oVj1Uwvv970ruUkCV7O1mzgVFO4/rev2cLRda9Tm9HrL70ZPut4rOHgY0FNrUu9BCbXA2sdQ+x0chA==" - }, - "is-weakset": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/is-weakset/-/is-weakset-2.0.1.tgz", - "integrity": "sha512-pi4vhbhVHGLxohUw7PhGsueT4vRGFoXhP7+RGN0jKIv9+8PWYCQTqtADngrxOm2g46hoH0+g8uZZBzMrvVGDmw==" + "integrity": "sha1-5HnICFjfDBsR3dppQPlgEfzaSpo=", + "dev": true }, "is-windows": { "version": "1.0.2", @@ -5036,7 +5003,8 @@ "isexe": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/isexe/-/isexe-2.0.0.tgz", - "integrity": "sha1-6PvzdNxVb/iUehDcsFctYz8s+hA=" + "integrity": "sha1-6PvzdNxVb/iUehDcsFctYz8s+hA=", + "dev": true }, "isobject": { "version": "3.0.1", @@ -5047,7 +5015,8 @@ "isstream": { "version": "0.1.2", "resolved": "https://registry.npmjs.org/isstream/-/isstream-0.1.2.tgz", - "integrity": "sha1-R+Y/evVa+m+S4VAOaQ64uFKcCZo=" + "integrity": "sha1-R+Y/evVa+m+S4VAOaQ64uFKcCZo=", + "dev": true }, "istanbul-lib-coverage": { "version": "3.0.0", @@ -6193,7 +6162,8 @@ "jsbn": { "version": "0.1.1", "resolved": "https://registry.npmjs.org/jsbn/-/jsbn-0.1.1.tgz", - "integrity": "sha1-peZUwuWi3rXyAdls77yoDA7y9RM=" + "integrity": "sha1-peZUwuWi3rXyAdls77yoDA7y9RM=", + "dev": true }, "jsdom": { "version": "16.3.0", @@ -6263,12 +6233,14 @@ "json-schema": { "version": "0.2.3", "resolved": "https://registry.npmjs.org/json-schema/-/json-schema-0.2.3.tgz", - "integrity": "sha1-tIDIkuWaLwWVTOcnvT8qTogvnhM=" + "integrity": "sha1-tIDIkuWaLwWVTOcnvT8qTogvnhM=", + "dev": true }, "json-schema-traverse": { "version": "0.4.1", "resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-0.4.1.tgz", - "integrity": "sha512-xbbCH5dCYU5T8LcEhhuh7HJ88HXuW3qsI3Y0zOZFKfZEHcpWiHU/Jxzk629Brsab/mMiHQti9wMP+845RPe3Vg==" + "integrity": "sha512-xbbCH5dCYU5T8LcEhhuh7HJ88HXuW3qsI3Y0zOZFKfZEHcpWiHU/Jxzk629Brsab/mMiHQti9wMP+845RPe3Vg==", + "dev": true }, "json-stable-stringify-without-jsonify": { "version": "1.0.1", @@ -6279,7 +6251,8 @@ "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=" + "integrity": "sha1-Epai1Y/UXxmg9s4B1lcB4sc1tus=", + "dev": true }, "json5": { "version": "2.1.3", @@ -6303,6 +6276,7 @@ "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", @@ -6529,7 +6503,8 @@ "lodash": { "version": "4.17.19", "resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.19.tgz", - "integrity": "sha512-JNvd8XER9GQX0v2qJgsaN/mzFCNA5BRe/j8JN9d+tWyGLSodKQHKFicdwNYzWwI3wjRnaKPsGj1XkBjx/F96DQ==" + "integrity": "sha512-JNvd8XER9GQX0v2qJgsaN/mzFCNA5BRe/j8JN9d+tWyGLSodKQHKFicdwNYzWwI3wjRnaKPsGj1XkBjx/F96DQ==", + "dev": true }, "lodash.once": { "version": "4.1.1", @@ -6695,10 +6670,16 @@ "integrity": "sha512-jf84uxzwiuiIVKiOLpfYk7N46TSy8ubTonmneY9vrpHNAnp0QBt2BxWV9dO3/j+BoVAb+a5G6YDPW3M5HOdMWQ==", "dev": true }, + "mimic-response": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/mimic-response/-/mimic-response-2.1.0.tgz", + "integrity": "sha512-wXqjST+SLt7R009ySCglWBCFpjUygmCIfD790/kVbiGmUgfYGuB14PiTd5DwVxSV4NcYHjzMkoj5LjQZwTQLEA==" + }, "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" } @@ -6754,23 +6735,22 @@ "minimist": "^1.2.5" } }, + "mkdirp-classic": { + "version": "0.5.3", + "resolved": "https://registry.npmjs.org/mkdirp-classic/-/mkdirp-classic-0.5.3.tgz", + "integrity": "sha512-gKLcREMhtuZRwRAfqP3RFW+TK4JqApVBtOIftVgjuABpAtpxhPGaDcfvbhNvD0B8iD1oUr/txX35NjcaY6Ns/A==" + }, "moment": { "version": "2.26.0", "resolved": "https://registry.npmjs.org/moment/-/moment-2.26.0.tgz", - "integrity": "sha512-oIixUO+OamkUkwjhAVE18rAMfRJNsNe/Stid/gwHSOfHrOtw9EhAY2AHvdKZ/k/MggcYELFCJz/Sn2pL8b8JMw==" - }, - "moment-timezone": { - "version": "0.5.31", - "resolved": "https://registry.npmjs.org/moment-timezone/-/moment-timezone-0.5.31.tgz", - "integrity": "sha512-+GgHNg8xRhMXfEbv81iDtrVeTcWt0kWmTEY1XQK14dICTXnWJnT0dxdlPspwqF3keKMVPXwayEsk1DI0AA/jdA==", - "requires": { - "moment": ">= 2.9.0" - } + "integrity": "sha512-oIixUO+OamkUkwjhAVE18rAMfRJNsNe/Stid/gwHSOfHrOtw9EhAY2AHvdKZ/k/MggcYELFCJz/Sn2pL8b8JMw==", + "dev": true }, "ms": { "version": "2.1.2", "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz", - "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==" + "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==", + "dev": true }, "multer": { "version": "1.4.2", @@ -6812,32 +6792,17 @@ "to-regex": "^3.0.1" } }, + "napi-build-utils": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/napi-build-utils/-/napi-build-utils-1.0.2.tgz", + "integrity": "sha512-ONmRUqK7zj7DWX0D9ADe03wbwOBZxNAfF20PlGfCWQcD3+/MakShIHrMqx9YwPTfxDdF1zLeL+RGZiR9kGMLdg==" + }, "natural-compare": { "version": "1.4.0", "resolved": "https://registry.npmjs.org/natural-compare/-/natural-compare-1.4.0.tgz", "integrity": "sha1-Sr6/7tdUHywnrPspvbvRXI1bpPc=", "dev": true }, - "needle": { - "version": "2.5.0", - "resolved": "https://registry.npmjs.org/needle/-/needle-2.5.0.tgz", - "integrity": "sha512-o/qITSDR0JCyCKEQ1/1bnUXMmznxabbwi/Y4WwJElf+evwJNFNwIDMCCt5IigFVxgeGBJESLohGtIS9gEzo1fA==", - "requires": { - "debug": "^3.2.6", - "iconv-lite": "^0.4.4", - "sax": "^1.2.4" - }, - "dependencies": { - "debug": { - "version": "3.2.6", - "resolved": "https://registry.npmjs.org/debug/-/debug-3.2.6.tgz", - "integrity": "sha512-mel+jf7nrtEl5Pn1Qx46zARXKDpBbvzezse7p7LqINmdoIk8PYP5SySaxEmYv6TZ0JyEKA1hsCId6DIhgITtWQ==", - "requires": { - "ms": "^2.1.1" - } - } - } - }, "negotiator": { "version": "0.6.2", "resolved": "https://registry.npmjs.org/negotiator/-/negotiator-0.6.2.tgz", @@ -6849,57 +6814,12 @@ "integrity": "sha512-1nh45deeb5olNY7eX82BkPO7SSxR5SSYJiPTrTdFUVYwAl8CKMA5N9PjTYkHiRjisVcxcQ1HXdLhx2qxxJzLNQ==", "dev": true }, - "node-addon-api": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/node-addon-api/-/node-addon-api-2.0.0.tgz", - "integrity": "sha512-ASCL5U13as7HhOExbT6OlWJJUV/lLzL2voOSP1UVehpRD8FbSrSDjfScK/KwAvVTI5AS6r4VwbOMlIqtvRidnA==" - }, - "node-gyp": { - "version": "3.8.0", - "resolved": "https://registry.npmjs.org/node-gyp/-/node-gyp-3.8.0.tgz", - "integrity": "sha512-3g8lYefrRRzvGeSowdJKAKyks8oUpLEd/DyPV4eMhVlhJ0aNaZqIrNUIPuEWWTAoPqyFkfGrM67MC69baqn6vA==", - "optional": true, + "node-abi": { + "version": "2.18.0", + "resolved": "https://registry.npmjs.org/node-abi/-/node-abi-2.18.0.tgz", + "integrity": "sha512-yi05ZoiuNNEbyT/xXfSySZE+yVnQW6fxPZuFbLyS1s6b5Kw3HzV2PHOM4XR+nsjzkHxByK+2Wg+yCQbe35l8dw==", "requires": { - "fstream": "^1.0.0", - "glob": "^7.0.3", - "graceful-fs": "^4.1.2", - "mkdirp": "^0.5.0", - "nopt": "2 || 3", - "npmlog": "0 || 1 || 2 || 3 || 4", - "osenv": "0", - "request": "^2.87.0", - "rimraf": "2", - "semver": "~5.3.0", - "tar": "^2.0.0", - "which": "1" - }, - "dependencies": { - "nopt": { - "version": "3.0.6", - "resolved": "https://registry.npmjs.org/nopt/-/nopt-3.0.6.tgz", - "integrity": "sha1-xkZdvwirzU2zWTF/eaxopkayj/k=", - "optional": true, - "requires": { - "abbrev": "1" - } - }, - "semver": { - "version": "5.3.0", - "resolved": "https://registry.npmjs.org/semver/-/semver-5.3.0.tgz", - "integrity": "sha1-myzl094C0XxgEq0yaqa00M9U+U8=", - "optional": true - }, - "tar": { - "version": "2.2.2", - "resolved": "https://registry.npmjs.org/tar/-/tar-2.2.2.tgz", - "integrity": "sha512-FCEhQ/4rE1zYv9rYXJw/msRqsnmlje5jHP6huWeBZ704jUTy02c5AZyWujpMR1ax6mVw9NyJMfuK2CMDWVIfgA==", - "optional": true, - "requires": { - "block-stream": "*", - "fstream": "^1.0.12", - "inherits": "2" - } - } + "semver": "^5.4.1" } }, "node-int64": { @@ -6955,34 +6875,6 @@ } } }, - "node-pre-gyp": { - "version": "0.11.0", - "resolved": "https://registry.npmjs.org/node-pre-gyp/-/node-pre-gyp-0.11.0.tgz", - "integrity": "sha512-TwWAOZb0j7e9eGaf9esRx3ZcLaE5tQ2lvYy1pb5IAaG1a2e2Kv5Lms1Y4hpj+ciXJRofIxxlt5haeQ/2ANeE0Q==", - "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" - }, - "dependencies": { - "nopt": { - "version": "4.0.3", - "resolved": "https://registry.npmjs.org/nopt/-/nopt-4.0.3.tgz", - "integrity": "sha512-CvaGwVMztSMJLOeXPrez7fyfObdZqNUK1cPAEzLHrTybIua9pMdmmPR5YwtfNftIOMv3DPUhFaxsZMNTQO20Kg==", - "requires": { - "abbrev": "1", - "osenv": "^0.1.4" - } - } - } - }, "nodemon": { "version": "2.0.4", "resolved": "https://registry.npmjs.org/nodemon/-/nodemon-2.0.4.tgz", @@ -7021,6 +6913,11 @@ } } }, + "noop-logger": { + "version": "0.1.1", + "resolved": "https://registry.npmjs.org/noop-logger/-/noop-logger-0.1.1.tgz", + "integrity": "sha1-lKKxYzxPExdVMAfYlm/Q6EG2pMI=" + }, "nopt": { "version": "1.0.10", "resolved": "https://registry.npmjs.org/nopt/-/nopt-1.0.10.tgz", @@ -7053,29 +6950,6 @@ "integrity": "sha512-2s47yzUxdexf1OhyRi4Em83iQk0aPvwTddtFz4hnSSw9dCEsLEGf6SwIO8ss/19S9iBb5sJaOuTvTGDeZI00BQ==", "dev": true }, - "npm-bundled": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/npm-bundled/-/npm-bundled-1.1.1.tgz", - "integrity": "sha512-gqkfgGePhTpAEgUsGEgcq1rqPXA+tv/aVBlgEzfXwA1yiUJF7xtEt3CtVwOjNYQOVknDk0F20w58Fnm3EtG0fA==", - "requires": { - "npm-normalize-package-bin": "^1.0.1" - } - }, - "npm-normalize-package-bin": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/npm-normalize-package-bin/-/npm-normalize-package-bin-1.0.1.tgz", - "integrity": "sha512-EPfafl6JL5/rU+ot6P3gRSCpPDW5VmIzX959Ob1+ySFUuuYHWHekXpwdUZcKP5C+DS4GEtdJluwBjnsNDl+fSA==" - }, - "npm-packlist": { - "version": "1.4.8", - "resolved": "https://registry.npmjs.org/npm-packlist/-/npm-packlist-1.4.8.tgz", - "integrity": "sha512-5+AZgwru5IevF5ZdnFglB5wNlHG1AOOuw28WhUq8/8emhBmLv6jX5by4WJCh7lW0uSYZYS6DXqIsyZVIXRZU9A==", - "requires": { - "ignore-walk": "^3.0.1", - "npm-bundled": "^1.0.1", - "npm-normalize-package-bin": "^1.0.1" - } - }, "npm-run-path": { "version": "2.0.2", "resolved": "https://registry.npmjs.org/npm-run-path/-/npm-run-path-2.0.2.tgz", @@ -7128,7 +7002,8 @@ "oauth-sign": { "version": "0.9.0", "resolved": "https://registry.npmjs.org/oauth-sign/-/oauth-sign-0.9.0.tgz", - "integrity": "sha512-fexhUFFPTGV8ybAtSIGbV6gOkSv8UtRbDBnAyLQw4QPKkgNlsH2ByPGtMUqdWkos6YCRmAqViwgZrJc/mRDzZQ==" + "integrity": "sha512-fexhUFFPTGV8ybAtSIGbV6gOkSv8UtRbDBnAyLQw4QPKkgNlsH2ByPGtMUqdWkos6YCRmAqViwgZrJc/mRDzZQ==", + "dev": true }, "object-assign": { "version": "4.1.1", @@ -7169,21 +7044,14 @@ "object-inspect": { "version": "1.8.0", "resolved": "https://registry.npmjs.org/object-inspect/-/object-inspect-1.8.0.tgz", - "integrity": "sha512-jLdtEOB112fORuypAyl/50VRVIBIdVQOSUUGQHzJ4xBSbit81zRarz7GThkEFZy1RceYrWYcPcBFPQwHyAc1gA==" - }, - "object-is": { - "version": "1.1.2", - "resolved": "https://registry.npmjs.org/object-is/-/object-is-1.1.2.tgz", - "integrity": "sha512-5lHCz+0uufF6wZ7CRFWJN3hp8Jqblpgve06U5CMQ3f//6iDjPr2PEo9MWCjEssDsa+UZEL4PkFpr+BMop6aKzQ==", - "requires": { - "define-properties": "^1.1.3", - "es-abstract": "^1.17.5" - } + "integrity": "sha512-jLdtEOB112fORuypAyl/50VRVIBIdVQOSUUGQHzJ4xBSbit81zRarz7GThkEFZy1RceYrWYcPcBFPQwHyAc1gA==", + "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==" + "integrity": "sha512-NuAESUOUMrlIXOfHKzD6bpPu3tYt3xvjNdRIQ+FeT0lNb4K8WR70CaDxhuNguS2XG+GjkyMwOzsN5ZktImfhLA==", + "dev": true }, "object-visit": { "version": "1.0.1", @@ -7198,6 +7066,7 @@ "version": "4.1.0", "resolved": "https://registry.npmjs.org/object.assign/-/object.assign-4.1.0.tgz", "integrity": "sha512-exHJeq6kBKj58mqGyTQ9DFvrZC/eR6OwxzoM9YRoGBqrXYonaFyGiFMuc9VZrXf7DarreEwMpurG3dd+CNyW5w==", + "dev": true, "requires": { "define-properties": "^1.1.2", "function-bind": "^1.1.1", @@ -7278,24 +7147,11 @@ "word-wrap": "~1.2.3" } }, - "os-homedir": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/os-homedir/-/os-homedir-1.0.2.tgz", - "integrity": "sha1-/7xJiDNuDoM94MFox+8VISGqf7M=" - }, "os-tmpdir": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/os-tmpdir/-/os-tmpdir-1.0.2.tgz", - "integrity": "sha1-u+Z0BseaqFxc/sdm/lc0VV36EnQ=" - }, - "osenv": { - "version": "0.1.5", - "resolved": "https://registry.npmjs.org/osenv/-/osenv-0.1.5.tgz", - "integrity": "sha512-0CWcCECdMVc2Rw3U5w9ZjqX6ga6ubk1xDVKxtBQPK7wis/0F2r9T6k4ydGYhecl7YUBxBVxhL5oisPsNxAPe2g==", - "requires": { - "os-homedir": "^1.0.0", - "os-tmpdir": "^1.0.0" - } + "integrity": "sha1-u+Z0BseaqFxc/sdm/lc0VV36EnQ=", + "dev": true }, "ospath": { "version": "1.2.2", @@ -7418,7 +7274,8 @@ "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=" + "integrity": "sha1-F0uSaHNVNP+8es5r9TpanhtcX18=", + "dev": true }, "path-key": { "version": "2.0.1", @@ -7455,7 +7312,8 @@ "performance-now": { "version": "2.1.0", "resolved": "https://registry.npmjs.org/performance-now/-/performance-now-2.1.0.tgz", - "integrity": "sha1-Ywn04OX6kT7BxpMHrjZLSzd8nns=" + "integrity": "sha1-Ywn04OX6kT7BxpMHrjZLSzd8nns=", + "dev": true }, "picomatch": { "version": "2.2.2", @@ -7492,6 +7350,28 @@ "integrity": "sha1-AerA/jta9xoqbAL+q7jB/vfgDqs=", "dev": true }, + "prebuild-install": { + "version": "5.3.5", + "resolved": "https://registry.npmjs.org/prebuild-install/-/prebuild-install-5.3.5.tgz", + "integrity": "sha512-YmMO7dph9CYKi5IR/BzjOJlRzpxGGVo1EsLSUZ0mt/Mq0HWZIHOKHHcHdT69yG54C9m6i45GpItwRHpk0Py7Uw==", + "requires": { + "detect-libc": "^1.0.3", + "expand-template": "^2.0.3", + "github-from-package": "0.0.0", + "minimist": "^1.2.3", + "mkdirp": "^0.5.1", + "napi-build-utils": "^1.0.1", + "node-abi": "^2.7.0", + "noop-logger": "^0.1.1", + "npmlog": "^4.0.1", + "pump": "^3.0.0", + "rc": "^1.2.7", + "simple-get": "^3.0.3", + "tar-fs": "^2.0.0", + "tunnel-agent": "^0.6.0", + "which-pm-runs": "^1.0.0" + } + }, "prelude-ls": { "version": "1.1.2", "resolved": "https://registry.npmjs.org/prelude-ls/-/prelude-ls-1.1.2.tgz", @@ -7603,7 +7483,8 @@ "psl": { "version": "1.8.0", "resolved": "https://registry.npmjs.org/psl/-/psl-1.8.0.tgz", - "integrity": "sha512-RIdOzyoavK+hA18OGGWDqUTsCLhtA7IcZ/6NCs4fFJaHBDab+pDDmDIByWFRQJq2Cd7r1OoQxBGKOaztq+hjIQ==" + "integrity": "sha512-RIdOzyoavK+hA18OGGWDqUTsCLhtA7IcZ/6NCs4fFJaHBDab+pDDmDIByWFRQJq2Cd7r1OoQxBGKOaztq+hjIQ==", + "dev": true }, "pstree.remy": { "version": "1.1.8", @@ -7615,7 +7496,6 @@ "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" @@ -7624,7 +7504,8 @@ "punycode": { "version": "2.1.1", "resolved": "https://registry.npmjs.org/punycode/-/punycode-2.1.1.tgz", - "integrity": "sha512-XRsRjdf+j5ml+y/6GKHPZbrF/8p2Yga0JPtdqTIY2Xe5ohJPD9saDJJLPvp9+NSBprVvevdXZybnj2cv8OEd0A==" + "integrity": "sha512-XRsRjdf+j5ml+y/6GKHPZbrF/8p2Yga0JPtdqTIY2Xe5ohJPD9saDJJLPvp9+NSBprVvevdXZybnj2cv8OEd0A==", + "dev": true }, "pupa": { "version": "2.0.1", @@ -7638,7 +7519,8 @@ "qs": { "version": "6.5.2", "resolved": "https://registry.npmjs.org/qs/-/qs-6.5.2.tgz", - "integrity": "sha512-N5ZAX4/LxJmF+7wN74pUD6qAh9/wnvdQcjq9TZjevvXzSUo7bfmw91saqMjzGS2xq91/odN2dW/WOl7qQHNDGA==" + "integrity": "sha512-N5ZAX4/LxJmF+7wN74pUD6qAh9/wnvdQcjq9TZjevvXzSUo7bfmw91saqMjzGS2xq91/odN2dW/WOl7qQHNDGA==", + "dev": true }, "querystring": { "version": "0.2.0", @@ -7760,15 +7642,6 @@ "safe-regex": "^1.1.0" } }, - "regexp.prototype.flags": { - "version": "1.3.0", - "resolved": "https://registry.npmjs.org/regexp.prototype.flags/-/regexp.prototype.flags-1.3.0.tgz", - "integrity": "sha512-2+Q0C5g951OlYlJz6yu5/M33IcsESLlLfsyIaLJaG4FA2r4yP8MvVMJUUP/fVBkSpbbbZlS5gynbEWLipiiXiQ==", - "requires": { - "define-properties": "^1.1.3", - "es-abstract": "^1.17.0-next.1" - } - }, "regexpp": { "version": "3.1.0", "resolved": "https://registry.npmjs.org/regexpp/-/regexpp-3.1.0.tgz", @@ -7815,6 +7688,7 @@ "version": "2.88.2", "resolved": "https://registry.npmjs.org/request/-/request-2.88.2.tgz", "integrity": "sha512-MsvtOrfG9ZcrOwAW+Qi+F6HbD0CWXEh9ou77uOb7FM2WPhwT7smM833PzanhJLsgXjN89Ir6V2PczXNnMpwKhw==", + "dev": true, "requires": { "aws-sign2": "~0.7.0", "aws4": "^1.8.0", @@ -7836,6 +7710,14 @@ "tough-cookie": "~2.5.0", "tunnel-agent": "^0.6.0", "uuid": "^3.3.2" + }, + "dependencies": { + "uuid": { + "version": "3.4.0", + "resolved": "https://registry.npmjs.org/uuid/-/uuid-3.4.0.tgz", + "integrity": "sha512-HjSDRw6gZE5JMggctHBcjVak08+KEVhSIiDzFnT9S9aegmp85S/bReBVTb4QTFaRNptJ9kuYaNhnbNEOkbKb/A==", + "dev": true + } } }, "request-progress": { @@ -7934,18 +7816,11 @@ "integrity": "sha512-TTlYpa+OL+vMMNG24xSlQGEJ3B/RzEfUlLct7b5G/ytav+wPrplCpVMFuwzXbkecJrb6IYo1iFb0S9v37754mg==", "dev": true }, - "retry-as-promised": { - "version": "3.2.0", - "resolved": "https://registry.npmjs.org/retry-as-promised/-/retry-as-promised-3.2.0.tgz", - "integrity": "sha512-CybGs60B7oYU/qSQ6kuaFmRd9sTZ6oXSc0toqePvV74Ac6/IFZSI1ReFQmtCN+uvW1Mtqdwpvt/LGOiCBAY2Mg==", - "requires": { - "any-promise": "^1.3.0" - } - }, "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" } @@ -8136,11 +8011,6 @@ } } }, - "sax": { - "version": "1.2.4", - "resolved": "https://registry.npmjs.org/sax/-/sax-1.2.4.tgz", - "integrity": "sha512-NqVDv9TpANUjFm0N8uM5GxL36UgKi9/atZw+x7YFnQ8ckwFGKrl4xX4yWtrey3UJm5nP1kUbnYgLopqWNSRhWw==" - }, "saxes": { "version": "5.0.1", "resolved": "https://registry.npmjs.org/saxes/-/saxes-5.0.1.tgz", @@ -8214,43 +8084,6 @@ } } }, - "sequelize": { - "version": "6.3.3", - "resolved": "https://registry.npmjs.org/sequelize/-/sequelize-6.3.3.tgz", - "integrity": "sha512-WO/b1ehjSFKlBCHzwZoaPhoW3WyXXy9x74yPrOP8NpE67wzbv0dIucDO4a+THLVyl3lnv3nFMZdJRdkUgb/ZAw==", - "requires": { - "debug": "^4.1.1", - "dottie": "^2.0.0", - "inflection": "1.12.0", - "lodash": "^4.17.15", - "moment": "^2.26.0", - "moment-timezone": "^0.5.31", - "retry-as-promised": "^3.2.0", - "semver": "^7.3.2", - "sequelize-pool": "^6.0.0", - "toposort-class": "^1.0.1", - "uuid": "^8.1.0", - "validator": "^10.11.0", - "wkx": "^0.5.0" - }, - "dependencies": { - "semver": { - "version": "7.3.2", - "resolved": "https://registry.npmjs.org/semver/-/semver-7.3.2.tgz", - "integrity": "sha512-OrOb32TeeambH6UrhtShmF7CRDqhL6/5XpPNp2DuRH6+9QLw/orhp72j87v8Qa1ScDkvrrBNpZcDejAirJmfXQ==" - }, - "uuid": { - "version": "8.2.0", - "resolved": "https://registry.npmjs.org/uuid/-/uuid-8.2.0.tgz", - "integrity": "sha512-CYpGiFTUrmI6OBMkAdjSDM0k5h8SkkiTP4WAjQgDgNB1S3Ou9VBEvr6q0Kv2H1mMk7IWfxYGpMH5sd5AvcIV2Q==" - } - } - }, - "sequelize-pool": { - "version": "6.1.0", - "resolved": "https://registry.npmjs.org/sequelize-pool/-/sequelize-pool-6.1.0.tgz", - "integrity": "sha512-4YwEw3ZgK/tY/so+GfnSgXkdwIJJ1I32uZJztIEgZeAO6HMgj64OzySbWLgxj+tXhZCJnzRfkY9gINw8Ft8ZMg==" - }, "serve-static": { "version": "1.14.1", "resolved": "https://registry.npmjs.org/serve-static/-/serve-static-1.14.1.tgz", @@ -8317,20 +8150,26 @@ "dev": true, "optional": true }, - "side-channel": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/side-channel/-/side-channel-1.0.2.tgz", - "integrity": "sha512-7rL9YlPHg7Ancea1S96Pa8/QWb4BtXL/TZvS6B8XFetGBeuhAsfmUspK6DokBeZ64+Kj9TCNRD/30pVz1BvQNA==", - "requires": { - "es-abstract": "^1.17.0-next.1", - "object-inspect": "^1.7.0" - } - }, "signal-exit": { "version": "3.0.3", "resolved": "https://registry.npmjs.org/signal-exit/-/signal-exit-3.0.3.tgz", "integrity": "sha512-VUJ49FC8U1OxwZLxIbTTrDvLnf/6TDgxZcK8wxR8zs13xpx7xbG60ndBlhNrFi2EMuFRoeDoJO7wthSLq42EjA==" }, + "simple-concat": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/simple-concat/-/simple-concat-1.0.1.tgz", + "integrity": "sha512-cSFtAPtRhljv69IK0hTVZQ+OfE9nePi/rtJmw5UjHeVyVroEqJXP1sFztKUy1qU+xvz3u/sfYJLa947b7nAN2Q==" + }, + "simple-get": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/simple-get/-/simple-get-3.1.0.tgz", + "integrity": "sha512-bCR6cP+aTdScaQCnQKbPKtJOKDp/hj9EDLJo3Nw4y1QksqaovlW/bnptB6/c1e+qmNIDHRK+oXFDdEqBT8WzUA==", + "requires": { + "decompress-response": "^4.2.0", + "once": "^1.3.1", + "simple-concat": "^1.0.0" + } + }, "sisteransi": { "version": "1.0.5", "resolved": "https://registry.npmjs.org/sisteransi/-/sisteransi-1.0.5.tgz", @@ -8559,20 +8398,11 @@ "integrity": "sha1-BOaSb2YolTVPPdAVIDYzuFcpfiw=", "dev": true }, - "sqlite3": { - "version": "5.0.0", - "resolved": "https://registry.npmjs.org/sqlite3/-/sqlite3-5.0.0.tgz", - "integrity": "sha512-rjvqHFUaSGnzxDy2AHCwhHy6Zp6MNJzCPGYju4kD8yi6bze4d1/zMTg6C7JI49b7/EM7jKMTvyfN/4ylBKdwfw==", - "requires": { - "node-addon-api": "2.0.0", - "node-gyp": "3.x", - "node-pre-gyp": "^0.11.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", @@ -8694,6 +8524,7 @@ "version": "1.0.1", "resolved": "https://registry.npmjs.org/string.prototype.trimend/-/string.prototype.trimend-1.0.1.tgz", "integrity": "sha512-LRPxFUaTtpqYsTeNKaFOw3R4bxIzWOnbQ837QfBylo8jIxtcbK/A/sMV7Q+OAV/vWo+7s25pOE10KYSjaSO06g==", + "dev": true, "requires": { "define-properties": "^1.1.3", "es-abstract": "^1.17.5" @@ -8703,6 +8534,7 @@ "version": "1.0.1", "resolved": "https://registry.npmjs.org/string.prototype.trimstart/-/string.prototype.trimstart-1.0.1.tgz", "integrity": "sha512-XxZn+QpvrBI1FOcg6dIpxUPgWCPuNXvMD72aaRaUQv1eD4e/Qy8i/hFTe0BUmD60p/QA6bh1avmuPTfNjqVWRw==", + "dev": true, "requires": { "define-properties": "^1.1.3", "es-abstract": "^1.17.5" @@ -8881,6 +8713,41 @@ "yallist": "^3.0.3" } }, + "tar-fs": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/tar-fs/-/tar-fs-2.1.0.tgz", + "integrity": "sha512-9uW5iDvrIMCVpvasdFHW0wJPez0K4JnMZtsuIeDI7HyMGJNxmDZDOCQROr7lXyS+iL/QMpj07qcjGYTSdRFXUg==", + "requires": { + "chownr": "^1.1.1", + "mkdirp-classic": "^0.5.2", + "pump": "^3.0.0", + "tar-stream": "^2.0.0" + } + }, + "tar-stream": { + "version": "2.1.3", + "resolved": "https://registry.npmjs.org/tar-stream/-/tar-stream-2.1.3.tgz", + "integrity": "sha512-Z9yri56Dih8IaK8gncVPx4Wqt86NDmQTSh49XLZgjWpGZL9GK9HKParS2scqHCC4w6X9Gh2jwaU45V47XTKwVA==", + "requires": { + "bl": "^4.0.1", + "end-of-stream": "^1.4.1", + "fs-constants": "^1.0.0", + "inherits": "^2.0.3", + "readable-stream": "^3.1.1" + }, + "dependencies": { + "readable-stream": { + "version": "3.6.0", + "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-3.6.0.tgz", + "integrity": "sha512-BViHy7LKeTz4oNnkcLJ+lVSL6vpiFeX6/d3oSH8zCW7UxP2onchk+vTGB143xuFjHS3deTgkKoXXymXqymiIdA==", + "requires": { + "inherits": "^2.0.3", + "string_decoder": "^1.1.1", + "util-deprecate": "^1.0.1" + } + } + } + }, "term-size": { "version": "2.2.0", "resolved": "https://registry.npmjs.org/term-size/-/term-size-2.2.0.tgz", @@ -9021,11 +8888,6 @@ "resolved": "https://registry.npmjs.org/toidentifier/-/toidentifier-1.0.0.tgz", "integrity": "sha512-yaOH/Pk/VEhBWWTlhI+qXxDFXlejDGcQipMlyxda9nthulaxLZUNcUqFxokp0vcYnvteJln5FNQDRrxj3YcbVw==" }, - "toposort-class": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/toposort-class/-/toposort-class-1.0.1.tgz", - "integrity": "sha1-f/0feMi+KMO6Rc1OGj9e4ZO9mYg=" - }, "touch": { "version": "3.1.0", "resolved": "https://registry.npmjs.org/touch/-/touch-3.1.0.tgz", @@ -9039,6 +8901,7 @@ "version": "2.5.0", "resolved": "https://registry.npmjs.org/tough-cookie/-/tough-cookie-2.5.0.tgz", "integrity": "sha512-nlLsUzgm1kfLXSXfRZMc1KLAugd4hqJHDTvc2hDIwS3mZAfMEuMbc03SujMF+GEcpaX/qboeycw6iO8JwVv2+g==", + "dev": true, "requires": { "psl": "^1.1.28", "punycode": "^2.1.1" @@ -9108,7 +8971,8 @@ "tweetnacl": { "version": "0.14.5", "resolved": "https://registry.npmjs.org/tweetnacl/-/tweetnacl-0.14.5.tgz", - "integrity": "sha1-WuaBd/GS1EViadEIr6k/+HQ/T2Q=" + "integrity": "sha1-WuaBd/GS1EViadEIr6k/+HQ/T2Q=", + "dev": true }, "type-check": { "version": "0.3.2", @@ -9328,6 +9192,7 @@ "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" } @@ -9381,11 +9246,6 @@ "resolved": "https://registry.npmjs.org/utils-merge/-/utils-merge-1.0.1.tgz", "integrity": "sha1-n5VxD1CiZ5R7LMwSR0HBAoQn5xM=" }, - "uuid": { - "version": "3.4.0", - "resolved": "https://registry.npmjs.org/uuid/-/uuid-3.4.0.tgz", - "integrity": "sha512-HjSDRw6gZE5JMggctHBcjVak08+KEVhSIiDzFnT9S9aegmp85S/bReBVTb4QTFaRNptJ9kuYaNhnbNEOkbKb/A==" - }, "v8-compile-cache": { "version": "2.1.1", "resolved": "https://registry.npmjs.org/v8-compile-cache/-/v8-compile-cache-2.1.1.tgz", @@ -9421,11 +9281,6 @@ "spdx-expression-parse": "^3.0.0" } }, - "validator": { - "version": "10.11.0", - "resolved": "https://registry.npmjs.org/validator/-/validator-10.11.0.tgz", - "integrity": "sha512-X/p3UZerAIsbBfN/IwahhYaBbY68EN/UQBWHtsbXGT5bfrH/p4NQzUCG1kF/rtKaNpnJ7jAu6NGTdSNtyNIXMw==" - }, "vary": { "version": "1.1.2", "resolved": "https://registry.npmjs.org/vary/-/vary-1.1.2.tgz", @@ -9435,6 +9290,7 @@ "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", @@ -9512,51 +9368,21 @@ "version": "1.3.1", "resolved": "https://registry.npmjs.org/which/-/which-1.3.1.tgz", "integrity": "sha512-HxJdYWq1MTIQbJ3nw0cqssHoTNU267KlrDuGZ1WYlxDStUtKUhOaJmh112/TZmHxxUfuJqPXSOm7tDyas0OSIQ==", + "dev": true, "requires": { "isexe": "^2.0.0" } }, - "which-boxed-primitive": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/which-boxed-primitive/-/which-boxed-primitive-1.0.1.tgz", - "integrity": "sha512-7BT4TwISdDGBgaemWU0N0OU7FeAEJ9Oo2P1PHRm/FCWoEi2VLWC9b6xvxAA3C/NMpxg3HXVgi0sMmGbNUbNepQ==", - "requires": { - "is-bigint": "^1.0.0", - "is-boolean-object": "^1.0.0", - "is-number-object": "^1.0.3", - "is-string": "^1.0.4", - "is-symbol": "^1.0.2" - } - }, - "which-collection": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/which-collection/-/which-collection-1.0.1.tgz", - "integrity": "sha512-W8xeTUwaln8i3K/cY1nGXzdnVZlidBcagyNFtBdD5kxnb4TvGKR7FfSIS3mYpwWS1QUCutfKz8IY8RjftB0+1A==", - "requires": { - "is-map": "^2.0.1", - "is-set": "^2.0.1", - "is-weakmap": "^2.0.1", - "is-weakset": "^2.0.1" - } - }, "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 }, - "which-typed-array": { - "version": "1.1.2", - "resolved": "https://registry.npmjs.org/which-typed-array/-/which-typed-array-1.1.2.tgz", - "integrity": "sha512-KT6okrd1tE6JdZAy3o2VhMoYPh3+J6EMZLyrxBQsZflI1QCZIxMrIYLkosd8Twf+YfknVIHmYQPgJt238p8dnQ==", - "requires": { - "available-typed-arrays": "^1.0.2", - "es-abstract": "^1.17.5", - "foreach": "^2.0.5", - "function-bind": "^1.1.1", - "has-symbols": "^1.0.1", - "is-typed-array": "^1.1.3" - } + "which-pm-runs": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/which-pm-runs/-/which-pm-runs-1.0.0.tgz", + "integrity": "sha1-Zws6+8VS4LVd9rd4DKdGFfI60cs=" }, "wide-align": { "version": "1.1.3", @@ -9609,14 +9435,6 @@ } } }, - "wkx": { - "version": "0.5.0", - "resolved": "https://registry.npmjs.org/wkx/-/wkx-0.5.0.tgz", - "integrity": "sha512-Xng/d4Ichh8uN4l0FToV/258EjMGU9MGcA0HV2d9B/ZpZB3lqQm7nkOdZdm5GhKtLLhAE7PiVQwN4eN+2YJJUg==", - "requires": { - "@types/node": "*" - } - }, "word-wrap": { "version": "1.2.3", "resolved": "https://registry.npmjs.org/word-wrap/-/word-wrap-1.2.3.tgz", diff --git a/package.json b/package.json index 62db138..36aae5e 100644 --- a/package.json +++ b/package.json @@ -5,8 +5,7 @@ "main": "index.js", "scripts": { "start": "node src/app.js", - "schema:sync": "node src/cli/init.db.js", - "dev": "npm run schema:sync && nodemon -e 'js,njk,html' src/app.js", + "dev": "nodemon -e 'js,njk,html' src/app.js", "test": "jest --coverage", "test:dev": "jest --watch" }, @@ -35,14 +34,12 @@ }, "dependencies": { "axios": "^0.19.2", - "connect-session-sequelize": "^7.0.1", + "better-sqlite3": "^7.1.0", "dotenv": "^8.2.0", "express": "^4.17.1", "express-session": "^1.17.1", "multer": "^1.4.2", "nunjucks": "^3.2.1", - "rsdi": "^1.0.5", - "sequelize": "^6.3.3", - "sqlite3": "^5.0.0" + "rsdi": "^1.0.5" } } diff --git a/src/app.js b/src/app.js index 450ce8a..228415e 100644 --- a/src/app.js +++ b/src/app.js @@ -4,7 +4,6 @@ const nunjucks = require('nunjucks'); const configureDependencyInjection = require('./config/di'); const { init: initClubModule } = require('./module/club/module'); -const { init: initAreaModule } = require('./module/area/module'); const app = express(); const port = process.env.PORT || 3000; @@ -22,7 +21,6 @@ const container = configureDependencyInjection(app); app.use(container.get('Session')); initClubModule(app, container); -initAreaModule(app, container); /** * @type {import('./module/club/controller/clubController')} controller; diff --git a/src/cli/init.db.js b/src/cli/init.db.js deleted file mode 100644 index 4baa161..0000000 --- a/src/cli/init.db.js +++ /dev/null @@ -1,22 +0,0 @@ -require('dotenv').config(); -const express = require('express'); -const configureDependencyInjection = require('../config/di'); - -const app = express(); -const container = configureDependencyInjection(app); - -/** - * @type {import('sequelize').Sequelize} mainDb - */ -const mainDb = container.get('Sequelize'); - -container.get('AreaModel'); -container.get('ClubModel'); - -mainDb.sync(); - -/** - * @type {import('sequelize').Sequelize} sessionDb - */ -const sessionDb = container.get('SessionSequelize'); -sessionDb.sync(); diff --git a/src/config/associations.js b/src/config/associations.js deleted file mode 100644 index 19c602e..0000000 --- a/src/config/associations.js +++ /dev/null @@ -1,6 +0,0 @@ -/** - * @param {import('sequelize').Sequelize} sequelizeInstance - */ -module.exports = async function setupAssociations(ClubModel, AreaModel) { - ClubModel.belongsTo(AreaModel, { foreignKey: 'area_id' }); -}; diff --git a/src/config/di.js b/src/config/di.js index 49e115f..d675adc 100644 --- a/src/config/di.js +++ b/src/config/di.js @@ -1,55 +1,22 @@ // configure DI container const path = require('path'); const { default: DIContainer, object, get, factory } = require('rsdi'); -const { Sequelize } = require('sequelize'); const multer = require('multer'); +const Sqlite3Database = require('better-sqlite3'); const session = require('express-session'); -const SequelizeStore = require('connect-session-sequelize')(session.Store); -const { ClubController, ClubService, ClubRepository, ClubModel } = require('../module/club/module'); -const { AreaController, AreaService, AreaRepository, AreaModel } = require('../module/area/module'); +const { ClubController, ClubService, ClubRepository } = require('../module/club/module'); -const setupSequelizeModelAssociations = require('./associations'); - -function configureMainSequelizeDatabase() { - const sequelize = new Sequelize({ - dialect: 'sqlite', - storage: process.env.DB_PATH, - }); - return sequelize; -} - -function configureSessionSequelizeDatabase() { - const sequelize = new Sequelize({ - dialect: 'sqlite', - storage: process.env.SESSION_DB_PATH, +function configureMainDatabaseAdapter() { + return new Sqlite3Database(process.env.DB_PATH, { + verbose: console.log, }); - return sequelize; -} - -/** - * @param {DIContainer} container - */ -function configureClubModel(container) { - return ClubModel.setup(container.get('Sequelize')); -} - -/** - * @param {DIContainer} container - */ -function configureAreaModel(container) { - return AreaModel.setup(container.get('Sequelize')); } -/** - * @param {DIContainer} container - */ -function configureSession(container) { +function configureSession() { const ONE_WEEK_IN_SECONDS = 604800000; - const sequelize = container.get('SessionSequelize'); const sessionOptions = { - store: new SequelizeStore({ db: sequelize }), secret: process.env.SESSION_SECRET, resave: false, saveUninitialized: false, @@ -78,8 +45,7 @@ function configureMulter() { */ function addCommonDefinitions(container) { container.addDefinitions({ - Sequelize: factory(configureMainSequelizeDatabase), - SessionSequelize: factory(configureSessionSequelizeDatabase), + MainDatabaseAdapter: factory(configureMainDatabaseAdapter), Session: factory(configureSession), Multer: factory(configureMulter), }); @@ -90,34 +56,15 @@ function addCommonDefinitions(container) { */ function addClubModuleDefinitions(container) { container.addDefinitions({ - ClubController: object(ClubController).construct( - get('Multer'), - get('ClubService'), - get('AreaService') - ), + ClubController: object(ClubController).construct(get('Multer'), get('ClubService')), ClubService: object(ClubService).construct(get('ClubRepository')), - ClubRepository: object(ClubRepository).construct(get('ClubModel'), get('AreaModel')), - ClubModel: factory(configureClubModel), - }); -} - -/** - * @param {DIContainer} container - */ -function addAreaModuleDefinitions(container) { - container.addDefinitions({ - AreaController: object(AreaController).construct(get('AreaService')), - AreaService: object(AreaService).construct(get('AreaRepository')), - AreaRepository: object(AreaRepository).construct(get('AreaModel')), - AreaModel: factory(configureAreaModel), + ClubRepository: object(ClubRepository).construct(get('MainDatabaseAdapter')), }); } module.exports = function configureDI() { const container = new DIContainer(); addCommonDefinitions(container); - addAreaModuleDefinitions(container); addClubModuleDefinitions(container); - setupSequelizeModelAssociations(container.get('ClubModel'), container.get('AreaModel')); return container; }; diff --git a/src/config/setup.sql b/src/config/setup.sql new file mode 100644 index 0000000..3952cf7 --- /dev/null +++ b/src/config/setup.sql @@ -0,0 +1,17 @@ +DROP TABLE IF EXISTS clubes; +CREATE TABLE clubes ( + id INTEGER PRIMARY KEY AUTOINCREMENT, + `name` TEXT NOT NULL, + short_name TEXT NOT NULL, + tla TEXT NOT NULL, + crest_url TEXT NOT NULL, + `address` TEXT NOT NULL, + phone TEXT NOT NULL, + website TEXT NOT NULL, + email TEXT NOT NULL, + founded TEXT NOT NULL, + club_colors TEXT NOT NULL, + venue TEXT NOT NULL, + created_at DATE DEFAULT (datetime('now', 'localtime')) NOT NULL, + updated_at DATE DEFAULT (datetime('now', 'localtime')) NOT NULL +); diff --git a/src/module/area/controller/areaController.js b/src/module/area/controller/areaController.js deleted file mode 100644 index 9a79e45..0000000 --- a/src/module/area/controller/areaController.js +++ /dev/null @@ -1,104 +0,0 @@ -const fromDataToEntity = require('../mapper/areaMapper'); -const AreaIdNotDefinedError = require('./error/areaIdNotDefinedError'); -const AbstractController = require('../../abstractController'); - -module.exports = class AreaController extends AbstractController { - /** - * @param {import('../service/areaService')} areaService - */ - constructor(areaService) { - super(); - this.areaService = areaService; - } - - /** - * @param {import('express').Application} app - */ - configureRoutes(app) { - const ROUTE = '/area'; - - // Nota: el `bind` es necesario porque estamos atando el callback a una función miembro de esta clase - // y no a la clase en si. - // Al hacer `bind` nos aseguramos que "this" dentro de `create` sea el controlador. - app.get(`${ROUTE}/create`, this.create.bind(this)); - app.get(`${ROUTE}`, this.index.bind(this)); - app.get(`${ROUTE}/view/:id`, this.view.bind(this)); - app.post(`${ROUTE}/save`, this.save.bind(this)); - app.get(`${ROUTE}/delete/:id`, this.delete.bind(this)); - } - - /** - * @param {import('express').Request} req - * @param {import('express').Response} res - */ - async index(req, res) { - const areas = await this.areaService.getAll(); - const { errors, messages } = req.session; - res.render('area/view/index.html', { data: { areas }, messages, errors }); - req.session.errors = []; - req.session.messages = []; - } - - /** - * @param {import('express').Request} req - * @param {import('express').Response} res - */ - async create(req, res) { - res.render('area/view/form.html'); - } - - /** - * @param {import('express').Request} req - * @param {import('express').Response} res - */ - async view(req, res) { - const { id } = req.params; - if (!id) { - throw new AreaIdNotDefinedError(); - } - - try { - const area = await this.areaService.getById(id); - res.render('area/view/form.html', { data: { area } }); - } catch (e) { - req.session.errors = [e.message]; - res.redirect('/area'); - } - } - - /** - * @param {import('express').Request} req - * @param {import('express').Response} res - */ - async save(req, res) { - try { - const area = fromDataToEntity(req.body); - const savedArea = await this.areaService.save(area); - if (area.id) { - req.session.messages = [`El area con id ${area.id} se actualizó exitosamente`]; - } else { - req.session.messages = [`Se creó el area con id ${savedArea.id} (${savedArea.name})`]; - } - res.redirect('/area'); - } catch (e) { - req.session.errors = [e.message]; - res.redirect('/area'); - } - } - - /** - * @param {import('express').Request} req - * @param {import('express').Response} res - */ - async delete(req, res) { - try { - const { id } = req.params; - const area = await this.areaService.getById(id); - await this.areaService.delete(area); - req.session.messages = [`Se eliminó el area ID: ${id} (${area.name})`]; - } catch (e) { - req.session.errors = [e.message]; - } - res.redirect('/area'); - } -}; diff --git a/src/module/area/controller/error/areaIdNotDefinedError.js b/src/module/area/controller/error/areaIdNotDefinedError.js deleted file mode 100644 index 58c3e8c..0000000 --- a/src/module/area/controller/error/areaIdNotDefinedError.js +++ /dev/null @@ -1 +0,0 @@ -module.exports = class AreaIdNotDefinedError extends Error {}; diff --git a/src/module/area/entity/area.js b/src/module/area/entity/area.js deleted file mode 100644 index 2ffda7a..0000000 --- a/src/module/area/entity/area.js +++ /dev/null @@ -1,6 +0,0 @@ -module.exports = class Area { - constructor({ id, name }) { - this.id = id; - this.name = name; - } -}; diff --git a/src/module/area/mapper/areaMapper.js b/src/module/area/mapper/areaMapper.js deleted file mode 100644 index abd6558..0000000 --- a/src/module/area/mapper/areaMapper.js +++ /dev/null @@ -1,5 +0,0 @@ -const Area = require('../entity/area'); - -module.exports = function fromDataToEntity({ id, name }) { - return new Area({ id, name }); -}; diff --git a/src/module/area/module.js b/src/module/area/module.js deleted file mode 100644 index 7dd49ad..0000000 --- a/src/module/area/module.js +++ /dev/null @@ -1,24 +0,0 @@ -const AreaController = require('./controller/areaController'); -const AreaRepository = require('./repository/sqlite/areaRepository'); -const AreaService = require('./service/areaService'); -const AreaModel = require('./repository/sqlite/areaModel'); - -/** - * @param {import('express').Application} app - * @param {import('rsdi').IDIContainer} container - */ -function init(app, container) { - /** - * @type {AreaController} controller; - */ - const controller = container.get('AreaController'); - controller.configureRoutes(app); -} - -module.exports = { - init, - AreaController, - AreaService, - AreaRepository, - AreaModel, -}; diff --git a/src/module/area/repository/abstractAreaRepository.js b/src/module/area/repository/abstractAreaRepository.js deleted file mode 100644 index 82e95bf..0000000 --- a/src/module/area/repository/abstractAreaRepository.js +++ /dev/null @@ -1,35 +0,0 @@ -/* eslint-disable no-empty-function */ -/* eslint-disable no-unused-vars */ -const AbstractAreaRepositoryError = require('./error/abstractAreaRepositoryError'); - -module.exports = class AbstractClubRepository { - constructor() { - if (new.target === AbstractClubRepository) { - throw new AbstractAreaRepositoryError( - 'No se puede instanciar el repositorio de áreas abstracto.' - ); - } - } - - /** - * @param {import('../entity/area')} area - * @returns {Promise} - */ - async save(club) {} - - /** - * @param {Number} id - */ - async delete(id) {} - - /** - * @param {Number} id - * @returns {Promise} - */ - async getById(id) {} - - /** - * @returns {Promise>} - */ - async getAll() {} -}; diff --git a/src/module/area/repository/error/abstractAreaRepositoryError.js b/src/module/area/repository/error/abstractAreaRepositoryError.js deleted file mode 100644 index 4929a27..0000000 --- a/src/module/area/repository/error/abstractAreaRepositoryError.js +++ /dev/null @@ -1 +0,0 @@ -module.exports = class AbstractAreaRepositoryError extends Error {}; diff --git a/src/module/area/repository/error/areaIdNotDefinedError.js b/src/module/area/repository/error/areaIdNotDefinedError.js deleted file mode 100644 index 58c3e8c..0000000 --- a/src/module/area/repository/error/areaIdNotDefinedError.js +++ /dev/null @@ -1 +0,0 @@ -module.exports = class AreaIdNotDefinedError extends Error {}; diff --git a/src/module/area/repository/error/areaNotFoundError.js b/src/module/area/repository/error/areaNotFoundError.js deleted file mode 100644 index 993b9b3..0000000 --- a/src/module/area/repository/error/areaNotFoundError.js +++ /dev/null @@ -1 +0,0 @@ -module.exports = class AreaNotFoundError extends Error {}; diff --git a/src/module/area/repository/sqlite/areaMapper.js b/src/module/area/repository/sqlite/areaMapper.js deleted file mode 100644 index cb9f176..0000000 --- a/src/module/area/repository/sqlite/areaMapper.js +++ /dev/null @@ -1,11 +0,0 @@ -const Area = require('../../entity/area'); - -module.exports = { - /** - * @param {import('./areaModel')} model - * @returns {import('../../entity/area')} - */ - fromModelToEntity(model) { - return new Area(model.toJSON()); - }, -}; diff --git a/src/module/area/repository/sqlite/areaModel.js b/src/module/area/repository/sqlite/areaModel.js deleted file mode 100644 index 1b99cb5..0000000 --- a/src/module/area/repository/sqlite/areaModel.js +++ /dev/null @@ -1,38 +0,0 @@ -const { Sequelize, Model, DataTypes } = require('sequelize'); - -module.exports = class AreaModel extends Model { - /** - * @param {import('sequelize').Sequelize} sequelizeInstance - * @returns {typeof AreaModel} - */ - static setup(sequelizeInstance) { - AreaModel.init( - { - id: { - type: DataTypes.INTEGER, - allowNull: false, - primaryKey: true, - autoIncrement: true, - unique: true, - }, - name: { - type: DataTypes.STRING, - }, - lastUpdated: { - type: DataTypes.DATE, - defaultValue: Sequelize.NOW, - }, - createdAt: { - type: DataTypes.DATE, - defaultValue: Sequelize.NOW, - }, - }, - { - sequelize: sequelizeInstance, - modelName: 'Area', - timestamps: false, - } - ); - return AreaModel; - } -}; diff --git a/src/module/area/repository/sqlite/areaRepository.js b/src/module/area/repository/sqlite/areaRepository.js deleted file mode 100644 index 612cb33..0000000 --- a/src/module/area/repository/sqlite/areaRepository.js +++ /dev/null @@ -1,62 +0,0 @@ -const { fromModelToEntity } = require('./areaMapper'); -const AbstractAreaRepository = require('../abstractAreaRepository'); -const AreaNotFoundError = require('../error/areaNotFoundError'); -const AreaIdNotDefinedError = require('../error/areaIdNotDefinedError'); - -module.exports = class AreaRepository extends AbstractAreaRepository { - /** - * @param {typeof import('./areaModel')} areaModel - */ - constructor(areaModel) { - super(); - this.areaModel = areaModel; - } - - /** - * @param {import('../../entity/area')} area - * @returns {Promise} - */ - async save(area) { - let areaModel; - if (!area.id) { - areaModel = await this.areaModel.create(area); - } else { - areaModel = await this.areaModel.build(area, { isNewRecord: false }).save(); - } - return fromModelToEntity(areaModel); - } - - /** - * @param {import('../../entity/area')} area - * @returns {Boolean} devuelve true si se borró algo, false si no se borró nada. - */ - async delete(area) { - if (!area || !area.id) { - throw new AreaIdNotDefinedError(); - } - - return Boolean(await this.areaModel.destroy({ where: { id: area.id } })); - } - - /** - * @param {Number} id - * @returns {Promise} - */ - async getById(id) { - const areaModel = await this.areaModel.findOne({ where: { id } }); - - if (!areaModel) { - throw new AreaNotFoundError(`No se encontró área con id ${id}`); - } - - return fromModelToEntity(areaModel); - } - - /** - * @return {Promise>} - */ - async getAll() { - const areas = await this.areaModel.findAll(); - return areas.map(fromModelToEntity); - } -}; diff --git a/src/module/area/service/areaService.js b/src/module/area/service/areaService.js deleted file mode 100644 index f74cb87..0000000 --- a/src/module/area/service/areaService.js +++ /dev/null @@ -1,51 +0,0 @@ -/** - * @typedef {import('../repository/abstractAreaRepository')} AbstractAreaRepository - */ - -const AreaNotDefinedError = require('./error/areaNotDefinedError'); -const AreaIdNotDefinedError = require('./error/areaIdNotDefinedError'); -const Area = require('../entity/area'); - -module.exports = class Service { - /** - * - * @param {AbstractAreaRepository} areaRepository - */ - constructor(areaRepository) { - this.areaRepository = areaRepository; - } - - /** - * @param {Area} area - */ - async save(area) { - if (area === undefined) { - throw new AreaNotDefinedError(); - } - - return this.areaRepository.save(area); - } - - /** - * @param {Area} area - */ - async delete(area) { - if (!(area instanceof Area)) { - throw new AreaNotDefinedError(); - } - - return this.areaRepository.delete(area); - } - - async getById(id) { - if (id === undefined) { - throw new AreaIdNotDefinedError(); - } - - return this.areaRepository.getById(id); - } - - async getAll() { - return this.areaRepository.getAll(); - } -}; diff --git a/src/module/area/service/error/areaIdNotDefinedError.js b/src/module/area/service/error/areaIdNotDefinedError.js deleted file mode 100644 index 58c3e8c..0000000 --- a/src/module/area/service/error/areaIdNotDefinedError.js +++ /dev/null @@ -1 +0,0 @@ -module.exports = class AreaIdNotDefinedError extends Error {}; diff --git a/src/module/area/service/error/areaNotDefinedError.js b/src/module/area/service/error/areaNotDefinedError.js deleted file mode 100644 index 8bbbdf6..0000000 --- a/src/module/area/service/error/areaNotDefinedError.js +++ /dev/null @@ -1 +0,0 @@ -module.exports = class AreaNotDefinedError extends Error {}; diff --git a/src/module/area/view/form.html b/src/module/area/view/form.html deleted file mode 100644 index bdb9d05..0000000 --- a/src/module/area/view/form.html +++ /dev/null @@ -1,34 +0,0 @@ -{% extends 'view/layout/base.html' %} - -{% block body %} -{% set area = data.area %} - -
-
-

- {{"Editando area ID: " + area.id if area.id else "Nuevo area"}} -

-
-
- Cancelar -
-
- -
- -
- - -
- -
- - - - -
-
- -
-
-{% endblock %} diff --git a/src/module/area/view/index.html b/src/module/area/view/index.html deleted file mode 100644 index 958ddfa..0000000 --- a/src/module/area/view/index.html +++ /dev/null @@ -1,73 +0,0 @@ -{% extends 'view/layout/base.html' %} - -{% block body %} -

Índice de áreas

- -{% for error in errors %} - -
- {{error}} -
-{% endfor %} - -{% for message in messages %} -
- {{message}} -
- -{% endfor %} - - -
- - - - - - - - - - - - - - - - {% for area in data.areas %} - - - - - - - - {% endfor %} - -
IDNombreEditarEliminar
- -
{{area.id}}{{area.name}} - editar - - - eliminar - -
-
-{% endblock %} - -{% block footerScripts %} - -{% endblock %} diff --git a/src/module/club/controller/__tests__/club.test.js b/src/module/club/controller/__tests__/club.test.js index ad4709d..f1c7c78 100644 --- a/src/module/club/controller/__tests__/club.test.js +++ b/src/module/club/controller/__tests__/club.test.js @@ -1,14 +1,17 @@ const ClubController = require('../clubController'); const Club = require('../../entity/club'); -const Area = require('../../../area/entity/area'); +const ClubIdNotDefinedError = require('../error/clubIdNotDefinedError'); +const uploadMiddleware = { + single: jest.fn(), +}; const serviceMock = { save: jest.fn(), delete: jest.fn(() => Promise.resolve(true)), getById: jest.fn(() => Promise.resolve({})), getAll: jest.fn(() => Promise.resolve([])), }; -const controller = new ClubController({}, serviceMock, serviceMock); +const controller = new ClubController(uploadMiddleware, serviceMock); test('Index renderea index.html', async () => { const renderMock = jest.fn(); @@ -23,34 +26,18 @@ test('Index renderea index.html', async () => { }); }); -test('Create muestra un error si no hay áreas en el sistema', async () => { - const mockRes = { redirect: jest.fn() }; - const mockReq = { session: {} }; - await controller.create(mockReq, mockRes); - expect(mockRes.redirect).toHaveBeenCalledTimes(1); - expect(mockReq.session.errors).toEqual(['Para crear un club, primero debe crear un área']); -}); - test('Create renderea form.html', async () => { const renderMock = jest.fn(); - const mockAreasData = [new Area({ id: 1, name: 'Argentina' })]; - serviceMock.getAll.mockImplementationOnce(() => mockAreasData); await controller.create({}, { render: renderMock }); expect(renderMock).toHaveBeenCalledTimes(1); - expect(renderMock).toHaveBeenCalledWith('club/view/form.html', { - data: { areas: mockAreasData }, - }); + expect(renderMock).toHaveBeenCalledWith('club/view/form.html'); }); -test('Save llama al servicio con el body y redirecciona a /club', async () => { +test('Save edita un club cuando hay un id presente', async () => { const redirectMock = jest.fn(); const FAKE_CREST_URL = 'ejemplo/escudo.png'; const bodyMock = new Club({ - Area: { - id: NaN, - name: undefined, - }, address: undefined, clubColors: undefined, crestUrl: 'ejemplo/escudo.png', @@ -76,6 +63,35 @@ test('Save llama al servicio con el body y redirecciona a /club', async () => { expect(redirectMock).toHaveBeenCalledWith('/club'); }); +test('Save crea un club cuando no hay id', async () => { + serviceMock.save.mockReset(); + const redirectMock = jest.fn(); + const FAKE_CREST_URL = 'ejemplo/escudo.png'; + const bodyMock = new Club({ + address: undefined, + clubColors: undefined, + crestUrl: 'ejemplo/escudo.png', + email: undefined, + founded: undefined, + name: undefined, + phone: undefined, + shortName: undefined, + tla: undefined, + venue: undefined, + website: undefined, + }); + + await controller.save( + { body: bodyMock, file: { path: FAKE_CREST_URL }, session: {} }, + { redirect: redirectMock } + ); + + expect(serviceMock.save).toHaveBeenCalledTimes(1); + expect(serviceMock.save).toHaveBeenCalledWith(bodyMock); + expect(redirectMock).toHaveBeenCalledTimes(1); + expect(redirectMock).toHaveBeenCalledWith('/club'); +}); + test('Delete llama al servicio con el id del body y redirecciona a /club', async () => { const FAKE_CLUB = new Club({ id: 1 }); serviceMock.getById.mockImplementationOnce(() => Promise.resolve(FAKE_CLUB)); @@ -88,3 +104,78 @@ test('Delete llama al servicio con el id del body y redirecciona a /club', async expect(redirectMock).toHaveBeenCalledTimes(1); expect(redirectMock).toHaveBeenCalledWith('/club'); }); + +test('Configura las rutas adecuadas', () => { + const app = { + get: jest.fn(), + post: jest.fn(), + }; + controller.configureRoutes(app); +}); + +test('View sin id da un error', async () => { + expect(controller.view({ params: {} })).rejects.toThrowError(ClubIdNotDefinedError); +}); + +test('View obtiene el id del club y lo renderea', async () => { + const MOCK_ID = 1; + const renderMock = jest.fn(); + serviceMock.getById.mockImplementationOnce(() => { + return {}; + }); + await controller.view({ params: { id: MOCK_ID } }, { render: renderMock }); + expect(serviceMock.getById).toHaveBeenCalledWith(MOCK_ID); + expect(renderMock).toHaveBeenCalledWith('club/view/form.html', { data: { club: {} } }); +}); + +test('View, cuando hay alguna excepción, seta errores en la sesión y redirecciona a club', async () => { + serviceMock.getById.mockImplementationOnce(() => { + throw Error('ejemplo'); + }); + + const redirectMock = jest.fn(); + const req = { params: { id: 1 }, session: { errors: {} } }; + await controller.view(req, { redirect: redirectMock }); + + expect(redirectMock).toHaveBeenCalledTimes(1); + expect(req.session.errors).not.toEqual([]); +}); + +test('Save, cuando hay alguna excepción, setea errores en la sesión y redirecciona a club', async () => { + serviceMock.getById.mockImplementationOnce(() => { + throw Error('ejemplo'); + }); + + const redirectMock = jest.fn(); + const req = { params: { id: 1 }, session: { errors: {} } }; + await controller.save(req, { redirect: redirectMock }); + + expect(redirectMock).toHaveBeenCalledTimes(1); + expect(req.session.errors).not.toEqual([]); +}); + +test('Save, cuando hay alguna excepción, setea errores en la sesión y redirecciona a club', async () => { + serviceMock.save.mockImplementationOnce(() => { + throw Error('ejemplo'); + }); + + const redirectMock = jest.fn(); + const req = { params: { id: 1 }, session: { errors: {} } }; + await controller.save(req, { redirect: redirectMock }); + + expect(redirectMock).toHaveBeenCalledTimes(1); + expect(req.session.errors).not.toEqual([]); +}); + +test('Delete, cuando hay alguna excepción, setea errores en la sesión y redirecciona a club', async () => { + serviceMock.delete.mockImplementationOnce(() => { + throw Error('ejemplo'); + }); + + const redirectMock = jest.fn(); + const req = { params: { id: 1 }, session: { errors: {} } }; + await controller.delete(req, { redirect: redirectMock }); + + expect(redirectMock).toHaveBeenCalledTimes(1); + expect(req.session.errors).not.toEqual([]); +}); diff --git a/src/module/club/controller/clubController.js b/src/module/club/controller/clubController.js index ace016c..3d5a9e3 100644 --- a/src/module/club/controller/clubController.js +++ b/src/module/club/controller/clubController.js @@ -5,14 +5,12 @@ const AbstractController = require('../../abstractController'); module.exports = class ClubController extends AbstractController { /** * @param {import('../service/clubService')} clubService - * @param {import('../../area/service/areaService')} areaService */ - constructor(uploadMiddleware, clubService, areaService) { + constructor(uploadMiddleware, clubService) { super(); this.ROUTE_BASE = '/club'; this.uploadMiddleware = uploadMiddleware; this.clubService = clubService; - this.areaService = areaService; } /** @@ -48,14 +46,7 @@ module.exports = class ClubController extends AbstractController { * @param {import('express').Response} res */ async create(req, res) { - const areas = await this.areaService.getAll(); - - if (areas.length > 0) { - res.render('club/view/form.html', { data: { areas } }); - } else { - req.session.errors = ['Para crear un club, primero debe crear un área']; - res.redirect(this.ROUTE_BASE); - } + res.render('club/view/form.html'); } /** @@ -70,10 +61,9 @@ module.exports = class ClubController extends AbstractController { try { const club = await this.clubService.getById(id); - const areas = await this.areaService.getAll(); - res.render('club/view/form.html', { data: { club, areas } }); + res.render('club/view/form.html', { data: { club } }); } catch (e) { - req.session.errors = [e.message]; + req.session.errors = [e.message, e.stack]; res.redirect('/club'); } } @@ -97,7 +87,7 @@ module.exports = class ClubController extends AbstractController { } res.redirect('/club'); } catch (e) { - req.session.errors = [e.message]; + req.session.errors = [e.message, e.stack]; res.redirect('/club'); } } @@ -113,7 +103,7 @@ module.exports = class ClubController extends AbstractController { await this.clubService.delete(club); req.session.messages = [`Se eliminó el club ID: ${id} (${club.name})`]; } catch (e) { - req.session.errors = [e.message]; + req.session.errors = [e.message, e.stack]; } res.redirect('/club'); } diff --git a/src/module/club/entity/club.js b/src/module/club/entity/club.js index 4049464..45b0b62 100644 --- a/src/module/club/entity/club.js +++ b/src/module/club/entity/club.js @@ -12,7 +12,6 @@ module.exports = class Club { founded, clubColors, venue, - Area, }) { this.id = id; this.name = name; @@ -26,9 +25,5 @@ module.exports = class Club { this.founded = founded; this.clubColors = clubColors; this.venue = venue; - /** - * @type {import('../../area/entity/area');} this.Area - */ - this.Area = Area; } }; diff --git a/src/module/club/mapper/clubMapper.js b/src/module/club/mapper/clubMapper.js index 3a0d4f9..88b09ce 100644 --- a/src/module/club/mapper/clubMapper.js +++ b/src/module/club/mapper/clubMapper.js @@ -1,10 +1,4 @@ -// map from Controller to Entity -// map from Entity to Controller -// map from Entity to Model -// map from Model to Entity - const Club = require('../entity/club'); -const Area = require('../../area/entity/area'); /** * @@ -24,11 +18,44 @@ function fromDataToEntity({ founded, 'club-colors': clubColors, venue, - // eslint-disable-next-line camelcase - area_id, }) { return new Club({ - id: Number(id), + id, + name, + shortName, + tla, + crestUrl, + address, + phone, + website, + email, + founded, + clubColors, + venue, + }); +} + +/** + * + * @param {Object} formData + * @returns Club + */ +function fromDbToEntity({ + id, + name, + short_name: shortName, + tla, + crest_url: crestUrl, + address, + phone, + website, + email, + founded, + club_colors: clubColors, + venue, +}) { + return new Club({ + id, name, shortName, tla, @@ -40,10 +67,10 @@ function fromDataToEntity({ founded, clubColors, venue, - Area: new Area({ id: Number(area_id) }), }); } module.exports = { fromDataToEntity, + fromDbToEntity, }; diff --git a/src/module/club/module.js b/src/module/club/module.js index e694cef..548c6af 100644 --- a/src/module/club/module.js +++ b/src/module/club/module.js @@ -1,7 +1,6 @@ const ClubController = require('./controller/clubController'); const ClubRepository = require('./repository/sqlite/clubRepository'); const ClubService = require('./service/clubService'); -const ClubModel = require('./repository/sqlite/clubModel'); /** * @param {import('express').Application} app @@ -20,5 +19,4 @@ module.exports = { ClubController, ClubService, ClubRepository, - ClubModel, }; diff --git a/src/module/club/repository/__tests__/abstractClubRepository.test.js b/src/module/club/repository/__tests__/abstractClubRepository.test.js index ebb7313..dca344b 100644 --- a/src/module/club/repository/__tests__/abstractClubRepository.test.js +++ b/src/module/club/repository/__tests__/abstractClubRepository.test.js @@ -1,5 +1,8 @@ +/* eslint max-classes-per-file: "off" */ + const AbstractClubRepository = require('../abstractClubRepository'); const AbstractClubRepositoryError = require('../error/abstractClubRepositoryError'); +const MethodNotImplementedError = require('../error/methodNotImplementedError'); test('No se puede instanciar un repositorio abstracto', () => { let repoInstance; @@ -18,3 +21,13 @@ test('Se puede instanciar un repositorio concreto que herede del repositorio abs expect(respositoryInstance).toBeInstanceOf(ConcreteRepository); expect(respositoryInstance).toBeInstanceOf(AbstractClubRepository); }); + +test('Llamar a métodos base sin implementación concreta da error', () => { + const ConcreteRepository = class extends AbstractClubRepository {}; + const respositoryInstance = new ConcreteRepository(); + + expect(() => respositoryInstance.save()).rejects.toThrowError(MethodNotImplementedError); + expect(() => respositoryInstance.delete()).rejects.toThrowError(MethodNotImplementedError); + expect(() => respositoryInstance.getAll()).rejects.toThrowError(MethodNotImplementedError); + expect(() => respositoryInstance.getById()).rejects.toThrowError(MethodNotImplementedError); +}); diff --git a/src/module/club/repository/abstractClubRepository.js b/src/module/club/repository/abstractClubRepository.js index 5e5bc86..263ad16 100644 --- a/src/module/club/repository/abstractClubRepository.js +++ b/src/module/club/repository/abstractClubRepository.js @@ -1,6 +1,7 @@ /* eslint-disable no-empty-function */ /* eslint-disable no-unused-vars */ const AbstractClubRepositoryError = require('./error/abstractClubRepositoryError'); +const MethodNotImplementedError = require('./error/methodNotImplementedError'); module.exports = class AbstractClubRepository { constructor() { @@ -15,21 +16,29 @@ module.exports = class AbstractClubRepository { * @param {import('../entity/club')} club * @returns {import('../entity/club')} */ - async save(club) {} + async save(club) { + throw new MethodNotImplementedError(); + } /** * @param {Number} id */ - async delete(id) {} + async delete(id) { + throw new MethodNotImplementedError(); + } /** * @param {Number} id * @returns {import('../entity/club')} */ - async getById(id) {} + async getById(id) { + throw new MethodNotImplementedError(); + } /** * @returns {Array} */ - async getAll() {} + async getAll() { + throw new MethodNotImplementedError(); + } }; diff --git a/src/module/club/repository/error/methodNotImplementedError.js b/src/module/club/repository/error/methodNotImplementedError.js new file mode 100644 index 0000000..f132e77 --- /dev/null +++ b/src/module/club/repository/error/methodNotImplementedError.js @@ -0,0 +1 @@ +module.exports = class MethodNotImplementedError extends Error {}; diff --git a/src/module/club/repository/sqlite/__test__/clubMapper.test.js b/src/module/club/repository/sqlite/__test__/clubMapper.test.js deleted file mode 100644 index 632223c..0000000 --- a/src/module/club/repository/sqlite/__test__/clubMapper.test.js +++ /dev/null @@ -1,12 +0,0 @@ -const { fromModelToEntity } = require('../clubMapper'); -const ClubEntity = require('../../../entity/club'); - -test('Convierte un modelo a una entidad del dominio', () => { - expect( - fromModelToEntity({ - toJSON() { - return {}; - }, - }) - ).toBeInstanceOf(ClubEntity); -}); diff --git a/src/module/club/repository/sqlite/__test__/clubModel.test.js b/src/module/club/repository/sqlite/__test__/clubModel.test.js deleted file mode 100644 index b454221..0000000 --- a/src/module/club/repository/sqlite/__test__/clubModel.test.js +++ /dev/null @@ -1,13 +0,0 @@ -const Sequelize = require('sequelize'); -const ClubModel = require('../clubModel'); - -const sequelizeInstance = new Sequelize('sqlite::memory'); - -test('Después de hacerle un setup a Club Model y sincronizar el modelo, la tabla Clubs existe ', async () => { - const TEST_ID = 1; - ClubModel.setup(sequelizeInstance); - await ClubModel.sync({ force: true }); - await ClubModel.create({ id: 1 }); - const club = await ClubModel.findOne({ where: { id: TEST_ID } }); - expect(club.id).toEqual(TEST_ID); -}); diff --git a/src/module/club/repository/sqlite/__test__/clubRepository.test.js b/src/module/club/repository/sqlite/__test__/clubRepository.test.js deleted file mode 100644 index 00865c7..0000000 --- a/src/module/club/repository/sqlite/__test__/clubRepository.test.js +++ /dev/null @@ -1,81 +0,0 @@ -const { Sequelize } = require('sequelize'); -const ClubRepository = require('../clubRepository'); -const ClubModel = require('../clubModel'); -const AreaModel = require('../../../../area/repository/sqlite/areaModel'); -const ClubEntity = require('../../../entity/club'); -const ClubNotFoundError = require('../../error/clubNotFoundError'); -const ClubIdNotDefinedError = require('../../error/clubIdNotDefinedError'); - -const sequelizeInstance = new Sequelize('sqlite::memory'); - -/** - * @type ClubRepository - */ -let repository; - -const sampleClub = new ClubEntity({ - name: 'Arsenal FC', - shortName: 'Arsenal', - tla: 'ARS', - crestUrl: 'https://upload.wikimedia.org/wikipedia/en/5/53/Arsenal_FC.svg', - address: '75 Drayton Park London N5 1BU', - phone: '+44 (020) 76195003', - website: 'http://www.arsenal.com', - email: 'info@arsenal.co.uk', - founded: 1886, - clubColors: 'Red / White', - venue: 'Emirates Stadium', - lastUpdated: '2020-05-14T02:41:34Z', - Area: { id: 1 }, -}); - -beforeAll(() => { - const club = ClubModel.setup(sequelizeInstance); - const area = AreaModel.setup(sequelizeInstance); - club.belongsTo(area); - - repository = new ClubRepository(club, area); -}); - -beforeEach(async (done) => { - await sequelizeInstance.sync({ force: true }); - done(); -}); - -test('Crea un equipo cuando la entidad no tiene id', async () => { - const NEW_AUTOGENERATED_ID = 1; - const newClub = await repository.save(sampleClub); - expect(newClub.id).toEqual(NEW_AUTOGENERATED_ID); -}); - -test('Actualiza un equipo cuando la entidad tiene un id', async () => { - const NEW_AUTOGENERATED_ID = 1; - const newClub = await repository.save(sampleClub); - expect(newClub.id).toEqual(NEW_AUTOGENERATED_ID); - - newClub.name = 'Independiente'; - console.log(newClub); - const modifiedClub = await repository.save(newClub); - expect(modifiedClub.id).toEqual(NEW_AUTOGENERATED_ID); - expect(modifiedClub.name).toEqual('Independiente'); -}); - -test('Borrar un equipo existente devuelve true', async () => { - const NEW_AUTOGENERATED_ID = 1; - const newClub = await repository.save(sampleClub); - expect(newClub.id).toEqual(NEW_AUTOGENERATED_ID); - await expect(repository.delete(newClub)).resolves.toEqual(true); - await expect(repository.getById(NEW_AUTOGENERATED_ID)).rejects.toThrow(ClubNotFoundError); -}); - -test('Borrar un equipo sin parámetros da error', async () => { - await expect(repository.delete()).rejects.toThrow(ClubIdNotDefinedError); -}); - -test('Borrar un equipo sin id da error', async () => { - await expect(repository.delete({})).rejects.toThrow(ClubIdNotDefinedError); -}); - -test('Borrar un equipo con id inexistente devuelve false', async () => { - await expect(repository.delete({ id: 1 })).resolves.toEqual(false); -}); diff --git a/src/module/club/repository/sqlite/__tests__/clubRepository.test.js b/src/module/club/repository/sqlite/__tests__/clubRepository.test.js new file mode 100644 index 0000000..ae5e360 --- /dev/null +++ b/src/module/club/repository/sqlite/__tests__/clubRepository.test.js @@ -0,0 +1,200 @@ +const Sqlite3Database = require('better-sqlite3'); +const fs = require('fs'); +const ClubRepository = require('../clubRepository'); +const Club = require('../../../entity/club'); +const ClubNotFoundError = require('../../error/clubNotFoundError'); +const ClubIdNotDefinedError = require('../../error/clubIdNotDefinedError'); + +let mockDb; + +beforeEach(() => { + mockDb = new Sqlite3Database(':memory:'); + const migration = fs.readFileSync('./src/config/setup.sql', 'utf-8'); + mockDb.exec(migration); +}); + +test('Guardar un club nuevo genera un id', () => { + const repository = new ClubRepository(mockDb); + const club = repository.save( + new Club({ + name: 'name', + tla: 'tla', + shortName: 'shortName', + address: 'address', + clubColors: 'clubColors', + crestUrl: 'cres.url', + email: 'e@mail.com', + founded: 'founded', + phone: 'phone', + venue: 'venue', + website: 'website', + }) + ); + + expect(club.id).toEqual(1); +}); + +test('Guardar un club existente actualiza los valores', () => { + const repository = new ClubRepository(mockDb); + let club = repository.save( + new Club({ + name: 'name', + tla: 'tla', + shortName: 'shortName', + address: 'address', + clubColors: 'clubColors', + crestUrl: 'cres.url', + email: 'e@mail.com', + founded: 'founded', + phone: 'phone', + venue: 'venue', + website: 'website', + }) + ); + + expect(club.id).toEqual(1); + + club = repository.save( + new Club({ + id: 1, + name: 'name actualizado', + tla: 'tla', + shortName: 'shortName', + address: 'address', + clubColors: 'clubColors', + crestUrl: 'cres.url', + email: 'e@mail.com', + founded: 'founded', + phone: 'phone', + venue: 'venue', + website: 'website', + }) + ); + + expect(club.id).toEqual(1); + expect(club.name).toEqual('name actualizado'); +}); + +test('Guardar un club con id que no existe da error', () => { + const repository = new ClubRepository(mockDb); + + expect(() => { + repository.save( + new Club({ + id: 1, + name: 'name actualizado', + tla: 'tla', + shortName: 'shortName', + address: 'address', + clubColors: 'clubColors', + crestUrl: 'cres.url', + email: 'e@mail.com', + founded: 'founded', + phone: 'phone', + venue: 'venue', + website: 'website', + }) + ); + }).toThrowError(ClubNotFoundError); +}); + +test('Buscar un club con id que no existe da error', () => { + const repository = new ClubRepository(mockDb); + expect(() => { + repository.getById(1); + }).toThrowError(ClubNotFoundError); +}); + +test('Buscar un club por id devuelve el club adecuado', () => { + const repository = new ClubRepository(mockDb); + const nuevoClub = repository.save( + new Club({ + name: 'name', + tla: 'tla', + shortName: 'shortName', + address: 'address', + clubColors: 'clubColors', + crestUrl: 'cres.url', + email: 'e@mail.com', + founded: 'founded', + phone: 'phone', + venue: 'venue', + website: 'website', + }) + ); + + expect(nuevoClub.id).toEqual(1); + + const club = repository.getById(nuevoClub.id); + expect(club).toEqual(nuevoClub); +}); + +test('Eliminar club elimina un club existente', () => { + const repository = new ClubRepository(mockDb); + const nuevoClub = repository.save( + new Club({ + name: 'name', + tla: 'tla', + shortName: 'shortName', + address: 'address', + clubColors: 'clubColors', + crestUrl: 'cres.url', + email: 'e@mail.com', + founded: 'founded', + phone: 'phone', + venue: 'venue', + website: 'website', + }) + ); + + expect(nuevoClub.id).toEqual(1); + expect(repository.delete(nuevoClub)).toBe(true); + expect(() => { + repository.getById(1); + }).toThrow(ClubNotFoundError); +}); + +test('Eliminar club sin un id da error', () => { + const repository = new ClubRepository(mockDb); + expect(() => { + repository.delete({}); + }).toThrow(ClubIdNotDefinedError); +}); + +test('Otener todos los clubes devuelve un array de entidad Club', () => { + const repository = new ClubRepository(mockDb); + expect(repository.getAll()).toEqual([]); + + const nuevoClub1 = repository.save( + new Club({ + name: 'name', + tla: 'tla', + shortName: 'shortName', + address: 'address', + clubColors: 'clubColors', + crestUrl: 'cres.url', + email: 'e@mail.com', + founded: 'founded', + phone: 'phone', + venue: 'venue', + website: 'website', + }) + ); + + const nuevoClub2 = repository.save( + new Club({ + name: 'name', + tla: 'tla', + shortName: 'shortName', + address: 'address', + clubColors: 'clubColors', + crestUrl: 'cres.url', + email: 'e@mail.com', + founded: 'founded', + phone: 'phone', + venue: 'venue', + website: 'website', + }) + ); + expect(repository.getAll()).toEqual([nuevoClub1, nuevoClub2]); +}); diff --git a/src/module/club/repository/sqlite/clubMapper.js b/src/module/club/repository/sqlite/clubMapper.js deleted file mode 100644 index 8c41528..0000000 --- a/src/module/club/repository/sqlite/clubMapper.js +++ /dev/null @@ -1,11 +0,0 @@ -const Club = require('../../entity/club'); - -module.exports = { - /** - * @param {import('./clubModel')} model - * @returns {import('../../entity/club')} - */ - fromModelToEntity(model) { - return new Club(model.toJSON()); - }, -}; diff --git a/src/module/club/repository/sqlite/clubModel.js b/src/module/club/repository/sqlite/clubModel.js deleted file mode 100644 index 252ff98..0000000 --- a/src/module/club/repository/sqlite/clubModel.js +++ /dev/null @@ -1,68 +0,0 @@ -const { Sequelize, Model, DataTypes } = require('sequelize'); - -module.exports = class ClubModel extends Model { - /** - * @param {import('sequelize').Sequelize} sequelizeInstance - * @returns {typeof ClubModel} - */ - static setup(sequelizeInstance) { - ClubModel.init( - { - id: { - type: DataTypes.INTEGER, - allowNull: false, - primaryKey: true, - autoIncrement: true, - unique: true, - }, - name: { - type: DataTypes.STRING, - }, - shortName: { - type: DataTypes.STRING, - }, - tla: { - type: DataTypes.STRING, - }, - crestUrl: { - type: DataTypes.STRING, - }, - address: { - type: DataTypes.STRING, - }, - phone: { - type: DataTypes.STRING, - }, - website: { - type: DataTypes.STRING, - }, - email: { - type: DataTypes.STRING, - }, - founded: { - type: DataTypes.INTEGER, - }, - clubColors: { - type: DataTypes.STRING, - }, - venue: { - type: DataTypes.STRING, - }, - lastUpdated: { - type: DataTypes.DATE, - defaultValue: Sequelize.NOW, - }, - createdAt: { - type: DataTypes.DATE, - defaultValue: Sequelize.NOW, - }, - }, - { - sequelize: sequelizeInstance, - modelName: 'Club', - timestamps: false, - } - ); - return ClubModel; - } -}; diff --git a/src/module/club/repository/sqlite/clubRepository.js b/src/module/club/repository/sqlite/clubRepository.js index 5f20da9..9a7f25b 100644 --- a/src/module/club/repository/sqlite/clubRepository.js +++ b/src/module/club/repository/sqlite/clubRepository.js @@ -1,68 +1,165 @@ -const { fromModelToEntity } = require('./clubMapper'); const AbstractClubRepository = require('../abstractClubRepository'); const ClubNotFoundError = require('../error/clubNotFoundError'); const ClubIdNotDefinedError = require('../error/clubIdNotDefinedError'); +const { fromDbToEntity } = require('../../mapper/clubMapper'); module.exports = class ClubRepository extends AbstractClubRepository { /** - * @param {typeof import('./clubModel')} clubModel - * * @param {typeof import('../../../area/repository/sqlite/areaModel')} areaModel + * @param {import('better-sqlite3').Database} databaseAdapter */ - constructor(clubModel, areaModel) { + constructor(databaseAdapter) { super(); - this.clubModel = clubModel; - this.areaModel = areaModel; + this.databaseAdapter = databaseAdapter; } /** * @param {import('../../entity/club')} club - * @returns {Promise} + * @returns {import('../../entity/club')} */ - async save(club) { - let clubModel; + save(club) { + let id; + const isUpdate = club.id; + if (isUpdate) { + id = club.id; + const statement = this.databaseAdapter.prepare(` + UPDATE clubes SET + ${club.crestUrl ? `crest_url = ?,` : ''} + name = ?, + short_name = ?, + tla = ?, + address = ?, + phone = ?, + website = ?, + email = ?, + founded = ?, + club_colors = ?, + venue = ? + WHERE id = ? + `); - const buildOptions = { isNewRecord: !club.id, include: this.areaModel }; - clubModel = this.clubModel.build(club, buildOptions); - clubModel.setDataValue('area_id', club.Area.id); - clubModel = await clubModel.save(); + const params = [ + club.name, + club.shortName, + club.tla, + club.address, + club.phone, + club.website, + club.email, + club.founded, + club.clubColors, + club.venue, + club.id, + ]; - return fromModelToEntity(clubModel); + if (club.crestUrl) { + params.unshift(club.crestUrl); + } + + statement.run(params); + } else { + const statement = this.databaseAdapter.prepare(` + INSERT INTO clubes( + name, + short_name, + tla, + crest_url, + address, + phone, + website, + email, + founded, + club_colors, + venue + ) VALUES(?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?) + `); + + const result = statement.run( + club.name, + club.shortName, + club.tla, + club.crestUrl, + club.address, + club.phone, + club.website, + club.email, + club.founded, + club.clubColors, + club.venue + ); + + id = result.lastInsertRowid; + } + + return this.getById(id); } /** * @param {import('../../entity/club')} club * @returns {Boolean} devuelve true si se borró algo, false si no se borró nada. */ - async delete(club) { + delete(club) { if (!club || !club.id) { - throw new ClubIdNotDefinedError(); + throw new ClubIdNotDefinedError('El ID del club no está definido'); } - return Boolean(await this.clubModel.destroy({ where: { id: club.id } })); + this.databaseAdapter.prepare('DELETE FROM clubes WHERE id = ?').run(club.id); + + return true; } /** * @param {Number} id - * @returns {Promise} + * @returns {import('../../entity/club')} */ - async getById(id) { - const clubModel = await this.clubModel.findOne({ - where: { id }, - include: this.areaModel, - }); + getById(id) { + const club = this.databaseAdapter + .prepare( + `SELECT + id, + name, + short_name, + tla, + crest_url, + address, + phone, + website, + email, + founded, + club_colors, + venue + FROM clubes wHERE id = ?` + ) + .get(id); - if (!clubModel) { - throw new ClubNotFoundError(`No se encontró club con id ${id}`); + if (club === undefined) { + throw new ClubNotFoundError(`No se encontró el club con ID: ${id}`); } - return fromModelToEntity(clubModel); + return fromDbToEntity(club); } /** - * @return {Promise>} + * @return {Array} */ - async getAll() { - const clubs = await this.clubModel.findAll(); - return clubs.map(fromModelToEntity); + getAll() { + const clubes = this.databaseAdapter + .prepare( + `SELECT + id, + name, + short_name, + tla, + crest_url, + address, + phone, + website, + email, + founded, + club_colors, + venue + FROM clubes` + ) + .all(); + return clubes.map((clubData) => fromDbToEntity(clubData)); } }; diff --git a/src/module/club/service/error/clubIdNotDefinedError.js b/src/module/club/service/error/clubIdNotDefinedError.js index 58c3e8c..8d7bc4f 100644 --- a/src/module/club/service/error/clubIdNotDefinedError.js +++ b/src/module/club/service/error/clubIdNotDefinedError.js @@ -1 +1 @@ -module.exports = class AreaIdNotDefinedError extends Error {}; +module.exports = class ClubIdNotDefinedError extends Error {}; diff --git a/src/module/club/view/form.html b/src/module/club/view/form.html index 14c88da..4aadf4e 100644 --- a/src/module/club/view/form.html +++ b/src/module/club/view/form.html @@ -2,7 +2,6 @@ {% block body %} {% set club = data.club %} -{% set areas = data.areas %}
@@ -63,23 +62,6 @@

-
- -
-
- -
- - - -
-
-
diff --git a/src/module/view/layout/base.html b/src/module/view/layout/base.html index b20b2b7..738dffa 100644 --- a/src/module/view/layout/base.html +++ b/src/module/view/layout/base.html @@ -45,21 +45,6 @@

CRUD Clubes

- -