From 3571eff89e78c86016c559dc4b32a6d66c5bcd51 Mon Sep 17 00:00:00 2001 From: Akinwale Samuel Date: Thu, 11 Apr 2019 10:14:36 +0100 Subject: [PATCH 1/5] 164798028-feature(search): add search filter for article --- package-lock.json | 406 +++++++++--------- server/controllers/index.js | 2 + .../controllers/search-article.controllers.js | 121 ++++++ server/routes/index.js | 2 + server/routes/search-articles.routes.js | 9 + tests/article-search.test.js | 22 + 6 files changed, 359 insertions(+), 203 deletions(-) create mode 100644 server/controllers/search-article.controllers.js create mode 100644 server/routes/search-articles.routes.js create mode 100644 tests/article-search.test.js diff --git a/package-lock.json b/package-lock.json index f944c1b..f397885 100644 --- a/package-lock.json +++ b/package-lock.json @@ -3136,24 +3136,24 @@ "dependencies": { "abbrev": { "version": "1.1.1", - "resolved": "https://registry.npmjs.org/abbrev/-/abbrev-1.1.1.tgz", + "resolved": false, "integrity": "sha512-nne9/IiQ/hzIhY6pdDnbBtz7DjPTKrY00P/zvPSm5pOFkl6xuGrGnXn/VtTNNfNtAfZ9/1RtehkszU9qcTii0Q==", "optional": true }, "ansi-regex": { "version": "2.1.1", - "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-2.1.1.tgz", + "resolved": false, "integrity": "sha1-w7M6te42DYbg5ijwRorn7yfWVN8=" }, "aproba": { "version": "1.2.0", - "resolved": "https://registry.npmjs.org/aproba/-/aproba-1.2.0.tgz", + "resolved": false, "integrity": "sha512-Y9J6ZjXtoYh8RnXVCMOU/ttDmk1aBjunq9vO0ta5x85WDQiQfUF9sIPBITdbiiIVcBo03Hi3jMxigBtsddlXRw==", "optional": true }, "are-we-there-yet": { "version": "1.1.5", - "resolved": "https://registry.npmjs.org/are-we-there-yet/-/are-we-there-yet-1.1.5.tgz", + "resolved": false, "integrity": "sha512-5hYdAkZlcG8tOLujVDTgCT+uPX0VnpAH28gWsLfzpXYm7wP6mp5Q/gYyR7YQ0cKVJcXJnl3j2kpBan13PtQf6w==", "optional": true, "requires": { @@ -3163,12 +3163,12 @@ }, "balanced-match": { "version": "1.0.0", - "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.0.tgz", + "resolved": false, "integrity": "sha1-ibTRmasr7kneFk6gK4nORi1xt2c=" }, "brace-expansion": { "version": "1.1.11", - "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz", + "resolved": false, "integrity": "sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==", "requires": { "balanced-match": "^1.0.0", @@ -3177,34 +3177,34 @@ }, "chownr": { "version": "1.1.1", - "resolved": "https://registry.npmjs.org/chownr/-/chownr-1.1.1.tgz", + "resolved": false, "integrity": "sha512-j38EvO5+LHX84jlo6h4UzmOwi0UgW61WRyPtJz4qaadK5eY3BTS5TY/S1Stc3Uk2lIM6TPevAlULiEJwie860g==", "optional": true }, "code-point-at": { "version": "1.1.0", - "resolved": "https://registry.npmjs.org/code-point-at/-/code-point-at-1.1.0.tgz", + "resolved": false, "integrity": "sha1-DQcLTQQ6W+ozovGkDi7bPZpMz3c=" }, "concat-map": { "version": "0.0.1", - "resolved": "https://registry.npmjs.org/concat-map/-/concat-map-0.0.1.tgz", + "resolved": false, "integrity": "sha1-2Klr13/Wjfd5OnMDajug1UBdR3s=" }, "console-control-strings": { "version": "1.1.0", - "resolved": "https://registry.npmjs.org/console-control-strings/-/console-control-strings-1.1.0.tgz", + "resolved": false, "integrity": "sha1-PXz0Rk22RG6mRL9LOVB/mFEAjo4=" }, "core-util-is": { "version": "1.0.2", - "resolved": "https://registry.npmjs.org/core-util-is/-/core-util-is-1.0.2.tgz", + "resolved": false, "integrity": "sha1-tf1UIgqivFq1eqtxQMlAdUUDwac=", "optional": true }, "debug": { "version": "2.6.9", - "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", + "resolved": false, "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==", "optional": true, "requires": { @@ -3213,25 +3213,25 @@ }, "deep-extend": { "version": "0.6.0", - "resolved": "https://registry.npmjs.org/deep-extend/-/deep-extend-0.6.0.tgz", + "resolved": false, "integrity": "sha512-LOHxIOaPYdHlJRtCQfDIVZtfw/ufM8+rVj649RIHzcm/vGwQRXFt6OPqIFWsm2XEMrNIEtWR64sY1LEKD2vAOA==", "optional": true }, "delegates": { "version": "1.0.0", - "resolved": "https://registry.npmjs.org/delegates/-/delegates-1.0.0.tgz", + "resolved": false, "integrity": "sha1-hMbhWbgZBP3KWaDvRM2HDTElD5o=", "optional": true }, "detect-libc": { "version": "1.0.3", - "resolved": "https://registry.npmjs.org/detect-libc/-/detect-libc-1.0.3.tgz", + "resolved": false, "integrity": "sha1-+hN8S9aY7fVc1c0CrFWfkaTEups=", "optional": true }, "fs-minipass": { "version": "1.2.5", - "resolved": "https://registry.npmjs.org/fs-minipass/-/fs-minipass-1.2.5.tgz", + "resolved": false, "integrity": "sha512-JhBl0skXjUPCFH7x6x61gQxrKyXsxB5gcgePLZCwfyCGGsTISMoIeObbrvVeP6Xmyaudw4TT43qV2Gz+iyd2oQ==", "optional": true, "requires": { @@ -3240,13 +3240,13 @@ }, "fs.realpath": { "version": "1.0.0", - "resolved": "https://registry.npmjs.org/fs.realpath/-/fs.realpath-1.0.0.tgz", + "resolved": false, "integrity": "sha1-FQStJSMVjKpA20onh8sBQRmU6k8=", "optional": true }, "gauge": { "version": "2.7.4", - "resolved": "https://registry.npmjs.org/gauge/-/gauge-2.7.4.tgz", + "resolved": false, "integrity": "sha1-LANAXHU4w51+s3sxcCLjJfsBi/c=", "optional": true, "requires": { @@ -3262,7 +3262,7 @@ }, "glob": { "version": "7.1.3", - "resolved": "https://registry.npmjs.org/glob/-/glob-7.1.3.tgz", + "resolved": false, "integrity": "sha512-vcfuiIxogLV4DlGBHIUOwI0IbrJ8HWPc4MU7HzviGeNho/UJDfi6B5p3sHeWIQ0KGIU0Jpxi5ZHxemQfLkkAwQ==", "optional": true, "requires": { @@ -3276,13 +3276,13 @@ }, "has-unicode": { "version": "2.0.1", - "resolved": "https://registry.npmjs.org/has-unicode/-/has-unicode-2.0.1.tgz", + "resolved": false, "integrity": "sha1-4Ob+aijPUROIVeCG0Wkedx3iqLk=", "optional": true }, "iconv-lite": { "version": "0.4.24", - "resolved": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.4.24.tgz", + "resolved": false, "integrity": "sha512-v3MXnZAcvnywkTUEZomIActle7RXXeedOR31wwl7VlyoXO4Qi9arvSenNQWne1TcRwhCL1HwLI21bEqdpj8/rA==", "optional": true, "requires": { @@ -3291,7 +3291,7 @@ }, "ignore-walk": { "version": "3.0.1", - "resolved": "https://registry.npmjs.org/ignore-walk/-/ignore-walk-3.0.1.tgz", + "resolved": false, "integrity": "sha512-DTVlMx3IYPe0/JJcYP7Gxg7ttZZu3IInhuEhbchuqneY9wWe5Ojy2mXLBaQFUQmo0AW2r3qG7m1mg86js+gnlQ==", "optional": true, "requires": { @@ -3300,7 +3300,7 @@ }, "inflight": { "version": "1.0.6", - "resolved": "https://registry.npmjs.org/inflight/-/inflight-1.0.6.tgz", + "resolved": false, "integrity": "sha1-Sb1jMdfQLQwJvJEKEHW6gWW1bfk=", "optional": true, "requires": { @@ -3310,18 +3310,18 @@ }, "inherits": { "version": "2.0.3", - "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.3.tgz", + "resolved": false, "integrity": "sha1-Yzwsg+PaQqUC9SRmAiSA9CCCYd4=" }, "ini": { "version": "1.3.5", - "resolved": "https://registry.npmjs.org/ini/-/ini-1.3.5.tgz", + "resolved": false, "integrity": "sha512-RZY5huIKCMRWDUqZlEi72f/lmXKMvuszcMBduliQ3nnWbx9X/ZBQO7DijMEYS9EhHBb2qacRUMtC7svLwe0lcw==", "optional": true }, "is-fullwidth-code-point": { "version": "1.0.0", - "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-1.0.0.tgz", + "resolved": false, "integrity": "sha1-754xOG8DGn8NZDr4L95QxFfvAMs=", "requires": { "number-is-nan": "^1.0.0" @@ -3329,13 +3329,13 @@ }, "isarray": { "version": "1.0.0", - "resolved": "https://registry.npmjs.org/isarray/-/isarray-1.0.0.tgz", + "resolved": false, "integrity": "sha1-u5NdSFgsuhaMBoNJV6VKPgcSTxE=", "optional": true }, "minimatch": { "version": "3.0.4", - "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.0.4.tgz", + "resolved": false, "integrity": "sha512-yJHVQEhyqPLUTgt9B83PXu6W3rx4MvvHvSUvToogpwoGDOUQ+yDrR0HRot+yOCdCO7u4hX3pWft6kWBBcqh0UA==", "requires": { "brace-expansion": "^1.1.7" @@ -3343,12 +3343,12 @@ }, "minimist": { "version": "0.0.8", - "resolved": "https://registry.npmjs.org/minimist/-/minimist-0.0.8.tgz", + "resolved": false, "integrity": "sha1-hX/Kv8M5fSYluCKCYuhqp6ARsF0=" }, "minipass": { "version": "2.3.5", - "resolved": "https://registry.npmjs.org/minipass/-/minipass-2.3.5.tgz", + "resolved": false, "integrity": "sha512-Gi1W4k059gyRbyVUZQ4mEqLm0YIUiGYfvxhF6SIlk3ui1WVxMTGfGdQ2SInh3PDrRTVvPKgULkpJtT4RH10+VA==", "requires": { "safe-buffer": "^5.1.2", @@ -3357,7 +3357,7 @@ }, "minizlib": { "version": "1.2.1", - "resolved": "https://registry.npmjs.org/minizlib/-/minizlib-1.2.1.tgz", + "resolved": false, "integrity": "sha512-7+4oTUOWKg7AuL3vloEWekXY2/D20cevzsrNT2kGWm+39J9hGTCBv8VI5Pm5lXZ/o3/mdR4f8rflAPhnQb8mPA==", "optional": true, "requires": { @@ -3366,7 +3366,7 @@ }, "mkdirp": { "version": "0.5.1", - "resolved": "https://registry.npmjs.org/mkdirp/-/mkdirp-0.5.1.tgz", + "resolved": false, "integrity": "sha1-MAV0OOrGz3+MR2fzhkjWaX11yQM=", "requires": { "minimist": "0.0.8" @@ -3374,13 +3374,13 @@ }, "ms": { "version": "2.0.0", - "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", + "resolved": false, "integrity": "sha1-VgiurfwAvmwpAd9fmGF4jeDVl8g=", "optional": true }, "needle": { "version": "2.2.4", - "resolved": "https://registry.npmjs.org/needle/-/needle-2.2.4.tgz", + "resolved": false, "integrity": "sha512-HyoqEb4wr/rsoaIDfTH2aVL9nWtQqba2/HvMv+++m8u0dz808MaagKILxtfeSN7QU7nvbQ79zk3vYOJp9zsNEA==", "optional": true, "requires": { @@ -3391,7 +3391,7 @@ }, "node-pre-gyp": { "version": "0.10.3", - "resolved": "https://registry.npmjs.org/node-pre-gyp/-/node-pre-gyp-0.10.3.tgz", + "resolved": false, "integrity": "sha512-d1xFs+C/IPS8Id0qPTZ4bUT8wWryfR/OzzAFxweG+uLN85oPzyo2Iw6bVlLQ/JOdgNonXLCoRyqDzDWq4iw72A==", "optional": true, "requires": { @@ -3409,7 +3409,7 @@ }, "nopt": { "version": "4.0.1", - "resolved": "https://registry.npmjs.org/nopt/-/nopt-4.0.1.tgz", + "resolved": false, "integrity": "sha1-0NRoWv1UFRk8jHUFYC0NF81kR00=", "optional": true, "requires": { @@ -3419,13 +3419,13 @@ }, "npm-bundled": { "version": "1.0.5", - "resolved": "https://registry.npmjs.org/npm-bundled/-/npm-bundled-1.0.5.tgz", + "resolved": false, "integrity": "sha512-m/e6jgWu8/v5niCUKQi9qQl8QdeEduFA96xHDDzFGqly0OOjI7c+60KM/2sppfnUU9JJagf+zs+yGhqSOFj71g==", "optional": true }, "npm-packlist": { "version": "1.2.0", - "resolved": "https://registry.npmjs.org/npm-packlist/-/npm-packlist-1.2.0.tgz", + "resolved": false, "integrity": "sha512-7Mni4Z8Xkx0/oegoqlcao/JpPCPEMtUvsmB0q7mgvlMinykJLSRTYuFqoQLYgGY8biuxIeiHO+QNJKbCfljewQ==", "optional": true, "requires": { @@ -3435,7 +3435,7 @@ }, "npmlog": { "version": "4.1.2", - "resolved": "https://registry.npmjs.org/npmlog/-/npmlog-4.1.2.tgz", + "resolved": false, "integrity": "sha512-2uUqazuKlTaSI/dC8AzicUck7+IrEaOnN/e0jd3Xtt1KcGpwx30v50mL7oPyr/h9bL3E4aZccVwpwP+5W9Vjkg==", "optional": true, "requires": { @@ -3447,18 +3447,18 @@ }, "number-is-nan": { "version": "1.0.1", - "resolved": "https://registry.npmjs.org/number-is-nan/-/number-is-nan-1.0.1.tgz", + "resolved": false, "integrity": "sha1-CXtgK1NCKlIsGvuHkDGDNpQaAR0=" }, "object-assign": { "version": "4.1.1", - "resolved": "https://registry.npmjs.org/object-assign/-/object-assign-4.1.1.tgz", + "resolved": false, "integrity": "sha1-IQmtx5ZYh8/AXLvUQsrIv7s2CGM=", "optional": true }, "once": { "version": "1.4.0", - "resolved": "https://registry.npmjs.org/once/-/once-1.4.0.tgz", + "resolved": false, "integrity": "sha1-WDsap3WWHUsROsF9nFC6753Xa9E=", "requires": { "wrappy": "1" @@ -3466,19 +3466,19 @@ }, "os-homedir": { "version": "1.0.2", - "resolved": "https://registry.npmjs.org/os-homedir/-/os-homedir-1.0.2.tgz", + "resolved": false, "integrity": "sha1-/7xJiDNuDoM94MFox+8VISGqf7M=", "optional": true }, "os-tmpdir": { "version": "1.0.2", - "resolved": "https://registry.npmjs.org/os-tmpdir/-/os-tmpdir-1.0.2.tgz", + "resolved": false, "integrity": "sha1-u+Z0BseaqFxc/sdm/lc0VV36EnQ=", "optional": true }, "osenv": { "version": "0.1.5", - "resolved": "https://registry.npmjs.org/osenv/-/osenv-0.1.5.tgz", + "resolved": false, "integrity": "sha512-0CWcCECdMVc2Rw3U5w9ZjqX6ga6ubk1xDVKxtBQPK7wis/0F2r9T6k4ydGYhecl7YUBxBVxhL5oisPsNxAPe2g==", "optional": true, "requires": { @@ -3488,19 +3488,19 @@ }, "path-is-absolute": { "version": "1.0.1", - "resolved": "https://registry.npmjs.org/path-is-absolute/-/path-is-absolute-1.0.1.tgz", + "resolved": false, "integrity": "sha1-F0uSaHNVNP+8es5r9TpanhtcX18=", "optional": true }, "process-nextick-args": { "version": "2.0.0", - "resolved": "https://registry.npmjs.org/process-nextick-args/-/process-nextick-args-2.0.0.tgz", + "resolved": false, "integrity": "sha512-MtEC1TqN0EU5nephaJ4rAtThHtC86dNN9qCuEhtshvpVBkAW5ZO7BASN9REnF9eoXGcRub+pFuKEpOHE+HbEMw==", "optional": true }, "rc": { "version": "1.2.8", - "resolved": "https://registry.npmjs.org/rc/-/rc-1.2.8.tgz", + "resolved": false, "integrity": "sha512-y3bGgqKj3QBdxLbLkomlohkvsA8gdAiUQlSBJnBhfn+BPxg4bc62d8TcBW15wavDfgexCgccckhcZvywyQYPOw==", "optional": true, "requires": { @@ -3512,7 +3512,7 @@ "dependencies": { "minimist": { "version": "1.2.0", - "resolved": "https://registry.npmjs.org/minimist/-/minimist-1.2.0.tgz", + "resolved": false, "integrity": "sha1-o1AIsg9BOD7sH7kU9M1d95omQoQ=", "optional": true } @@ -3520,7 +3520,7 @@ }, "readable-stream": { "version": "2.3.6", - "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-2.3.6.tgz", + "resolved": false, "integrity": "sha512-tQtKA9WIAhBF3+VLAseyMqZeBjW0AHJoxOtYqSUZNJxauErmLbVm2FW1y+J/YA9dUrAC39ITejlZWhVIwawkKw==", "optional": true, "requires": { @@ -3535,7 +3535,7 @@ }, "rimraf": { "version": "2.6.3", - "resolved": "https://registry.npmjs.org/rimraf/-/rimraf-2.6.3.tgz", + "resolved": false, "integrity": "sha512-mwqeW5XsA2qAejG46gYdENaxXjx9onRNCfn7L0duuP4hCuTIi/QO7PDK07KJfp1d+izWPrzEJDcSqBa0OZQriA==", "optional": true, "requires": { @@ -3544,42 +3544,42 @@ }, "safe-buffer": { "version": "5.1.2", - "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.1.2.tgz", + "resolved": false, "integrity": "sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g==" }, "safer-buffer": { "version": "2.1.2", - "resolved": "https://registry.npmjs.org/safer-buffer/-/safer-buffer-2.1.2.tgz", + "resolved": false, "integrity": "sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg==", "optional": true }, "sax": { "version": "1.2.4", - "resolved": "https://registry.npmjs.org/sax/-/sax-1.2.4.tgz", + "resolved": false, "integrity": "sha512-NqVDv9TpANUjFm0N8uM5GxL36UgKi9/atZw+x7YFnQ8ckwFGKrl4xX4yWtrey3UJm5nP1kUbnYgLopqWNSRhWw==", "optional": true }, "semver": { "version": "5.6.0", - "resolved": "https://registry.npmjs.org/semver/-/semver-5.6.0.tgz", + "resolved": false, "integrity": "sha512-RS9R6R35NYgQn++fkDWaOmqGoj4Ek9gGs+DPxNUZKuwE183xjJroKvyo1IzVFeXvUrvmALy6FWD5xrdJT25gMg==", "optional": true }, "set-blocking": { "version": "2.0.0", - "resolved": "https://registry.npmjs.org/set-blocking/-/set-blocking-2.0.0.tgz", + "resolved": false, "integrity": "sha1-BF+XgtARrppoA93TgrJDkrPYkPc=", "optional": true }, "signal-exit": { "version": "3.0.2", - "resolved": "https://registry.npmjs.org/signal-exit/-/signal-exit-3.0.2.tgz", + "resolved": false, "integrity": "sha1-tf3AjxKH6hF4Yo5BXiUTK3NkbG0=", "optional": true }, "string-width": { "version": "1.0.2", - "resolved": "https://registry.npmjs.org/string-width/-/string-width-1.0.2.tgz", + "resolved": false, "integrity": "sha1-EYvfW4zcUaKn5w0hHgfisLmxB9M=", "requires": { "code-point-at": "^1.0.0", @@ -3589,7 +3589,7 @@ }, "string_decoder": { "version": "1.1.1", - "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.1.1.tgz", + "resolved": false, "integrity": "sha512-n/ShnvDi6FHbbVfviro+WojiFzv+s8MPMHBczVePfUpDJLwoLT0ht1l4YwBCbi8pJAveEEdnkHyPyTP/mzRfwg==", "optional": true, "requires": { @@ -3598,7 +3598,7 @@ }, "strip-ansi": { "version": "3.0.1", - "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-3.0.1.tgz", + "resolved": false, "integrity": "sha1-ajhfuIU9lS1f8F0Oiq+UJ43GPc8=", "requires": { "ansi-regex": "^2.0.0" @@ -3606,13 +3606,13 @@ }, "strip-json-comments": { "version": "2.0.1", - "resolved": "https://registry.npmjs.org/strip-json-comments/-/strip-json-comments-2.0.1.tgz", + "resolved": false, "integrity": "sha1-PFMZQukIwml8DsNEhYwobHygpgo=", "optional": true }, "tar": { "version": "4.4.8", - "resolved": "https://registry.npmjs.org/tar/-/tar-4.4.8.tgz", + "resolved": false, "integrity": "sha512-LzHF64s5chPQQS0IYBn9IN5h3i98c12bo4NCO7e0sGM2llXQ3p2FGC5sdENN4cTW48O915Sh+x+EXx7XW96xYQ==", "optional": true, "requires": { @@ -3627,13 +3627,13 @@ }, "util-deprecate": { "version": "1.0.2", - "resolved": "https://registry.npmjs.org/util-deprecate/-/util-deprecate-1.0.2.tgz", + "resolved": false, "integrity": "sha1-RQ1Nyfpw3nMnYvvS1KKJgUGaDM8=", "optional": true }, "wide-align": { "version": "1.1.3", - "resolved": "https://registry.npmjs.org/wide-align/-/wide-align-1.1.3.tgz", + "resolved": false, "integrity": "sha512-QGkOQc8XL6Bt5PwnsExKBPuMKBxnGxWWW3fU55Xt4feHozMUhdUMaBCk290qpm/wG5u/RSKzwdAC4i51YigihA==", "optional": true, "requires": { @@ -3642,12 +3642,12 @@ }, "wrappy": { "version": "1.0.2", - "resolved": "https://registry.npmjs.org/wrappy/-/wrappy-1.0.2.tgz", + "resolved": false, "integrity": "sha1-tSQ9jz7BqjXxNkYFvA0QNuMKtp8=" }, "yallist": { "version": "3.0.3", - "resolved": "https://registry.npmjs.org/yallist/-/yallist-3.0.3.tgz", + "resolved": false, "integrity": "sha512-S+Zk8DEWE6oKpV+vI3qWkaK+jSbIK86pCwe2IF/xwIpQ8jEuxpw9NyaGjmp9+BoJv5FV2piqCDcoCtStppiq2A==" } } @@ -5549,13 +5549,13 @@ "dependencies": { "ansi-regex": { "version": "3.0.0", - "resolved": false, + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-3.0.0.tgz", "integrity": "sha1-7QMXwyIGT3lGbAKWa922Bas32Zg=", "dev": true }, "append-transform": { "version": "1.0.0", - "resolved": false, + "resolved": "https://registry.npmjs.org/append-transform/-/append-transform-1.0.0.tgz", "integrity": "sha512-P009oYkeHyU742iSZJzZZywj4QRJdnTWffaKuJQLablCZ1uz6/cW4yaRgcDaoQ+uwOxxnt0gRUcwfsNP2ri0gw==", "dev": true, "requires": { @@ -5564,19 +5564,19 @@ }, "archy": { "version": "1.0.0", - "resolved": false, + "resolved": "https://registry.npmjs.org/archy/-/archy-1.0.0.tgz", "integrity": "sha1-+cjBN1fMHde8N5rHeyxipcKGjEA=", "dev": true }, "arrify": { "version": "1.0.1", - "resolved": false, + "resolved": "https://registry.npmjs.org/arrify/-/arrify-1.0.1.tgz", "integrity": "sha1-iYUI2iIm84DfkEcoRWhJwVAaSw0=", "dev": true }, "async": { "version": "2.6.2", - "resolved": false, + "resolved": "https://registry.npmjs.org/async/-/async-2.6.2.tgz", "integrity": "sha512-H1qVYh1MYhEEFLsP97cVKqCGo7KfCyTt6uEWqsTBr9SO84oK9Uwbyd/yCW+6rKJLHksBNUVWZDAjfS+Ccx0Bbg==", "dev": true, "requires": { @@ -5585,13 +5585,13 @@ }, "balanced-match": { "version": "1.0.0", - "resolved": false, + "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.0.tgz", "integrity": "sha1-ibTRmasr7kneFk6gK4nORi1xt2c=", "dev": true }, "brace-expansion": { "version": "1.1.11", - "resolved": false, + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz", "integrity": "sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==", "dev": true, "requires": { @@ -5601,7 +5601,7 @@ }, "caching-transform": { "version": "3.0.1", - "resolved": false, + "resolved": "https://registry.npmjs.org/caching-transform/-/caching-transform-3.0.1.tgz", "integrity": "sha512-Y1KTLNwSPd4ljsDrFOtyXVmm7Gnk42yQitNq43AhE+cwUR/e4T+rmOHs1IPtzBg8066GBJfTOj1rQYFSWSsH2g==", "dev": true, "requires": { @@ -5613,13 +5613,13 @@ }, "camelcase": { "version": "5.0.0", - "resolved": false, + "resolved": "https://registry.npmjs.org/camelcase/-/camelcase-5.0.0.tgz", "integrity": "sha512-faqwZqnWxbxn+F1d399ygeamQNy3lPp/H9H6rNrqYh4FSVCtcY+3cub1MxA8o9mDd55mM8Aghuu/kuyYA6VTsA==", "dev": true }, "cliui": { "version": "4.1.0", - "resolved": false, + "resolved": "https://registry.npmjs.org/cliui/-/cliui-4.1.0.tgz", "integrity": "sha512-4FG+RSG9DL7uEwRUZXZn3SS34DiDPfzP0VOiEwtUWlE+AR2EIg+hSyvrIgUUfhdgR/UkAeW2QHgeP+hWrXs7jQ==", "dev": true, "requires": { @@ -5630,32 +5630,32 @@ }, "code-point-at": { "version": "1.1.0", - "resolved": false, + "resolved": "https://registry.npmjs.org/code-point-at/-/code-point-at-1.1.0.tgz", "integrity": "sha1-DQcLTQQ6W+ozovGkDi7bPZpMz3c=", "dev": true }, "commander": { "version": "2.17.1", - "resolved": false, + "resolved": "https://registry.npmjs.org/commander/-/commander-2.17.1.tgz", "integrity": "sha512-wPMUt6FnH2yzG95SA6mzjQOEKUU3aLaDEmzs1ti+1E9h+CsrZghRlqEM/EJ4KscsQVG8uNN4uVreUeT8+drlgg==", "dev": true, "optional": true }, "commondir": { "version": "1.0.1", - "resolved": false, + "resolved": "https://registry.npmjs.org/commondir/-/commondir-1.0.1.tgz", "integrity": "sha1-3dgA2gxmEnOTzKWVDqloo6rxJTs=", "dev": true }, "concat-map": { "version": "0.0.1", - "resolved": false, + "resolved": "https://registry.npmjs.org/concat-map/-/concat-map-0.0.1.tgz", "integrity": "sha1-2Klr13/Wjfd5OnMDajug1UBdR3s=", "dev": true }, "convert-source-map": { "version": "1.6.0", - "resolved": false, + "resolved": "https://registry.npmjs.org/convert-source-map/-/convert-source-map-1.6.0.tgz", "integrity": "sha512-eFu7XigvxdZ1ETfbgPBohgyQ/Z++C0eEhTor0qRwBw9unw+L0/6V8wkSuGgzdThkiS5lSpdptOQPD8Ak40a+7A==", "dev": true, "requires": { @@ -5664,7 +5664,7 @@ }, "cross-spawn": { "version": "4.0.2", - "resolved": false, + "resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-4.0.2.tgz", "integrity": "sha1-e5JHYhwjrf3ThWAEqCPL45dCTUE=", "dev": true, "requires": { @@ -5674,7 +5674,7 @@ }, "debug": { "version": "4.1.1", - "resolved": false, + "resolved": "https://registry.npmjs.org/debug/-/debug-4.1.1.tgz", "integrity": "sha512-pYAIzeRo8J6KPEaJ0VWOh5Pzkbw/RetuzehGM7QRRX5he4fPHx2rdKMB256ehJCkX+XRQm16eZLqLNS8RSZXZw==", "dev": true, "requires": { @@ -5683,13 +5683,13 @@ }, "decamelize": { "version": "1.2.0", - "resolved": false, + "resolved": "https://registry.npmjs.org/decamelize/-/decamelize-1.2.0.tgz", "integrity": "sha1-9lNNFRSCabIDUue+4m9QH5oZEpA=", "dev": true }, "default-require-extensions": { "version": "2.0.0", - "resolved": false, + "resolved": "https://registry.npmjs.org/default-require-extensions/-/default-require-extensions-2.0.0.tgz", "integrity": "sha1-9fj7sYp9bVCyH2QfZJ67Uiz+JPc=", "dev": true, "requires": { @@ -5698,7 +5698,7 @@ }, "end-of-stream": { "version": "1.4.1", - "resolved": false, + "resolved": "https://registry.npmjs.org/end-of-stream/-/end-of-stream-1.4.1.tgz", "integrity": "sha512-1MkrZNvWTKCaigbn+W15elq2BB/L22nqrSY5DKlo3X6+vclJm8Bb5djXJBmEX6fS3+zCh/F4VBK5Z2KxJt4s2Q==", "dev": true, "requires": { @@ -5707,7 +5707,7 @@ }, "error-ex": { "version": "1.3.2", - "resolved": false, + "resolved": "https://registry.npmjs.org/error-ex/-/error-ex-1.3.2.tgz", "integrity": "sha512-7dFHNmqeFSEt2ZBsCriorKnn3Z2pj+fd9kmI6QoWw4//DL+icEBfc0U7qJCisqrTsKTjw4fNFy2pW9OqStD84g==", "dev": true, "requires": { @@ -5716,13 +5716,13 @@ }, "es6-error": { "version": "4.1.1", - "resolved": false, + "resolved": "https://registry.npmjs.org/es6-error/-/es6-error-4.1.1.tgz", "integrity": "sha512-Um/+FxMr9CISWh0bi5Zv0iOD+4cFh5qLeks1qhAopKVAJw3drgKbKySikp7wGhDL0HPeaja0P5ULZrxLkniUVg==", "dev": true }, "execa": { "version": "1.0.0", - "resolved": false, + "resolved": "https://registry.npmjs.org/execa/-/execa-1.0.0.tgz", "integrity": "sha512-adbxcyWV46qiHyvSp50TKt05tB4tK3HcmF7/nxfAdhnox83seTDbwnaqKO4sXRy7roHAIFqJP/Rw/AuEbX61LA==", "dev": true, "requires": { @@ -5737,7 +5737,7 @@ "dependencies": { "cross-spawn": { "version": "6.0.5", - "resolved": false, + "resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-6.0.5.tgz", "integrity": "sha512-eTVLrBSt7fjbDygz805pMnstIs2VTBNkRm0qxZd+M7A5XDdxVRWO5MxGBXZhjY4cqLYLdtrGqRf8mBPmzwSpWQ==", "dev": true, "requires": { @@ -5752,7 +5752,7 @@ }, "find-cache-dir": { "version": "2.0.0", - "resolved": false, + "resolved": "https://registry.npmjs.org/find-cache-dir/-/find-cache-dir-2.0.0.tgz", "integrity": "sha512-LDUY6V1Xs5eFskUVYtIwatojt6+9xC9Chnlk/jYOOvn3FAFfSaWddxahDGyNHh0b2dMXa6YW2m0tk8TdVaXHlA==", "dev": true, "requires": { @@ -5763,7 +5763,7 @@ }, "find-up": { "version": "3.0.0", - "resolved": false, + "resolved": "https://registry.npmjs.org/find-up/-/find-up-3.0.0.tgz", "integrity": "sha512-1yD6RmLI1XBfxugvORwlck6f75tYL+iR0jqwsOrOxMZyGYqUuDhJ0l4AXdO1iX/FTs9cBAMEk1gWSEx1kSbylg==", "dev": true, "requires": { @@ -5772,7 +5772,7 @@ }, "foreground-child": { "version": "1.5.6", - "resolved": false, + "resolved": "https://registry.npmjs.org/foreground-child/-/foreground-child-1.5.6.tgz", "integrity": "sha1-T9ca0t/elnibmApcCilZN8svXOk=", "dev": true, "requires": { @@ -5782,19 +5782,19 @@ }, "fs.realpath": { "version": "1.0.0", - "resolved": false, + "resolved": "https://registry.npmjs.org/fs.realpath/-/fs.realpath-1.0.0.tgz", "integrity": "sha1-FQStJSMVjKpA20onh8sBQRmU6k8=", "dev": true }, "get-caller-file": { "version": "1.0.3", - "resolved": false, + "resolved": "https://registry.npmjs.org/get-caller-file/-/get-caller-file-1.0.3.tgz", "integrity": "sha512-3t6rVToeoZfYSGd8YoLFR2DJkiQrIiUrGcjvFX2mDw3bn6k2OtwHN0TNCLbBO+w8qTvimhDkv+LSscbJY1vE6w==", "dev": true }, "get-stream": { "version": "4.1.0", - "resolved": false, + "resolved": "https://registry.npmjs.org/get-stream/-/get-stream-4.1.0.tgz", "integrity": "sha512-GMat4EJ5161kIy2HevLlr4luNjBgvmj413KaQA7jt4V8B4RDsfpHk7WQ9GVqfYyyx8OS/L66Kox+rJRNklLK7w==", "dev": true, "requires": { @@ -5803,7 +5803,7 @@ }, "glob": { "version": "7.1.3", - "resolved": false, + "resolved": "https://registry.npmjs.org/glob/-/glob-7.1.3.tgz", "integrity": "sha512-vcfuiIxogLV4DlGBHIUOwI0IbrJ8HWPc4MU7HzviGeNho/UJDfi6B5p3sHeWIQ0KGIU0Jpxi5ZHxemQfLkkAwQ==", "dev": true, "requires": { @@ -5817,13 +5817,13 @@ }, "graceful-fs": { "version": "4.1.15", - "resolved": false, + "resolved": "https://registry.npmjs.org/graceful-fs/-/graceful-fs-4.1.15.tgz", "integrity": "sha512-6uHUhOPEBgQ24HM+r6b/QwWfZq+yiFcipKFrOFiBEnWdy5sdzYoi+pJeQaPI5qOLRFqWmAXUPQNsielzdLoecA==", "dev": true }, "handlebars": { "version": "4.1.0", - "resolved": false, + "resolved": "https://registry.npmjs.org/handlebars/-/handlebars-4.1.0.tgz", "integrity": "sha512-l2jRuU1NAWK6AW5qqcTATWQJvNPEwkM7NEKSiv/gqOsoSQbVoWyqVEY5GS+XPQ88zLNmqASRpzfdm8d79hJS+w==", "dev": true, "requires": { @@ -5835,7 +5835,7 @@ "dependencies": { "source-map": { "version": "0.6.1", - "resolved": false, + "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==", "dev": true } @@ -5843,13 +5843,13 @@ }, "has-flag": { "version": "3.0.0", - "resolved": false, + "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-3.0.0.tgz", "integrity": "sha1-tdRU3CGZriJWmfNGfloH87lVuv0=", "dev": true }, "hasha": { "version": "3.0.0", - "resolved": false, + "resolved": "https://registry.npmjs.org/hasha/-/hasha-3.0.0.tgz", "integrity": "sha1-UqMvq4Vp1BymmmH/GiFPjrfIvTk=", "dev": true, "requires": { @@ -5858,19 +5858,19 @@ }, "hosted-git-info": { "version": "2.7.1", - "resolved": false, + "resolved": "https://registry.npmjs.org/hosted-git-info/-/hosted-git-info-2.7.1.tgz", "integrity": "sha512-7T/BxH19zbcCTa8XkMlbK5lTo1WtgkFi3GvdWEyNuc4Vex7/9Dqbnpsf4JMydcfj9HCg4zUWFTL3Za6lapg5/w==", "dev": true }, "imurmurhash": { "version": "0.1.4", - "resolved": false, + "resolved": "https://registry.npmjs.org/imurmurhash/-/imurmurhash-0.1.4.tgz", "integrity": "sha1-khi5srkoojixPcT7a21XbyMUU+o=", "dev": true }, "inflight": { "version": "1.0.6", - "resolved": false, + "resolved": "https://registry.npmjs.org/inflight/-/inflight-1.0.6.tgz", "integrity": "sha1-Sb1jMdfQLQwJvJEKEHW6gWW1bfk=", "dev": true, "requires": { @@ -5880,49 +5880,49 @@ }, "inherits": { "version": "2.0.3", - "resolved": false, + "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.3.tgz", "integrity": "sha1-Yzwsg+PaQqUC9SRmAiSA9CCCYd4=", "dev": true }, "invert-kv": { "version": "2.0.0", - "resolved": false, + "resolved": "https://registry.npmjs.org/invert-kv/-/invert-kv-2.0.0.tgz", "integrity": "sha512-wPVv/y/QQ/Uiirj/vh3oP+1Ww+AWehmi1g5fFWGPF6IpCBCDVrhgHRMvrLfdYcwDh3QJbGXDW4JAuzxElLSqKA==", "dev": true }, "is-arrayish": { "version": "0.2.1", - "resolved": false, + "resolved": "https://registry.npmjs.org/is-arrayish/-/is-arrayish-0.2.1.tgz", "integrity": "sha1-d8mYQFJ6qOyxqLppe4BkWnqSap0=", "dev": true }, "is-fullwidth-code-point": { "version": "2.0.0", - "resolved": false, + "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-2.0.0.tgz", "integrity": "sha1-o7MKXE8ZkYMWeqq5O+764937ZU8=", "dev": true }, "is-stream": { "version": "1.1.0", - "resolved": false, + "resolved": "https://registry.npmjs.org/is-stream/-/is-stream-1.1.0.tgz", "integrity": "sha1-EtSj3U5o4Lec6428hBc66A2RykQ=", "dev": true }, "isexe": { "version": "2.0.0", - "resolved": false, + "resolved": "https://registry.npmjs.org/isexe/-/isexe-2.0.0.tgz", "integrity": "sha1-6PvzdNxVb/iUehDcsFctYz8s+hA=", "dev": true }, "istanbul-lib-coverage": { "version": "2.0.3", - "resolved": false, + "resolved": "https://registry.npmjs.org/istanbul-lib-coverage/-/istanbul-lib-coverage-2.0.3.tgz", "integrity": "sha512-dKWuzRGCs4G+67VfW9pBFFz2Jpi4vSp/k7zBcJ888ofV5Mi1g5CUML5GvMvV6u9Cjybftu+E8Cgp+k0dI1E5lw==", "dev": true }, "istanbul-lib-hook": { "version": "2.0.3", - "resolved": false, + "resolved": "https://registry.npmjs.org/istanbul-lib-hook/-/istanbul-lib-hook-2.0.3.tgz", "integrity": "sha512-CLmEqwEhuCYtGcpNVJjLV1DQyVnIqavMLFHV/DP+np/g3qvdxu3gsPqYoJMXm15sN84xOlckFB3VNvRbf5yEgA==", "dev": true, "requires": { @@ -5931,7 +5931,7 @@ }, "istanbul-lib-report": { "version": "2.0.4", - "resolved": false, + "resolved": "https://registry.npmjs.org/istanbul-lib-report/-/istanbul-lib-report-2.0.4.tgz", "integrity": "sha512-sOiLZLAWpA0+3b5w5/dq0cjm2rrNdAfHWaGhmn7XEFW6X++IV9Ohn+pnELAl9K3rfpaeBfbmH9JU5sejacdLeA==", "dev": true, "requires": { @@ -5942,7 +5942,7 @@ "dependencies": { "supports-color": { "version": "6.1.0", - "resolved": false, + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-6.1.0.tgz", "integrity": "sha512-qe1jfm1Mg7Nq/NSh6XE24gPXROEVsWHxC1LIx//XNlD9iw7YZQGjZNjYN7xGaEG6iKdA8EtNFW6R0gjnVXp+wQ==", "dev": true, "requires": { @@ -5953,7 +5953,7 @@ }, "istanbul-lib-source-maps": { "version": "3.0.2", - "resolved": false, + "resolved": "https://registry.npmjs.org/istanbul-lib-source-maps/-/istanbul-lib-source-maps-3.0.2.tgz", "integrity": "sha512-JX4v0CiKTGp9fZPmoxpu9YEkPbEqCqBbO3403VabKjH+NRXo72HafD5UgnjTEqHL2SAjaZK1XDuDOkn6I5QVfQ==", "dev": true, "requires": { @@ -5966,7 +5966,7 @@ "dependencies": { "source-map": { "version": "0.6.1", - "resolved": false, + "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==", "dev": true } @@ -5974,7 +5974,7 @@ }, "istanbul-reports": { "version": "2.1.1", - "resolved": false, + "resolved": "https://registry.npmjs.org/istanbul-reports/-/istanbul-reports-2.1.1.tgz", "integrity": "sha512-FzNahnidyEPBCI0HcufJoSEoKykesRlFcSzQqjH9x0+LC8tnnE/p/90PBLu8iZTxr8yYZNyTtiAujUqyN+CIxw==", "dev": true, "requires": { @@ -5983,13 +5983,13 @@ }, "json-parse-better-errors": { "version": "1.0.2", - "resolved": false, + "resolved": "https://registry.npmjs.org/json-parse-better-errors/-/json-parse-better-errors-1.0.2.tgz", "integrity": "sha512-mrqyZKfX5EhL7hvqcV6WG1yYjnjeuYDzDhhcAAUrq8Po85NBQBJP+ZDUT75qZQ98IkUoBqdkExkukOU7Ts2wrw==", "dev": true }, "lcid": { "version": "2.0.0", - "resolved": false, + "resolved": "https://registry.npmjs.org/lcid/-/lcid-2.0.0.tgz", "integrity": "sha512-avPEb8P8EGnwXKClwsNUgryVjllcRqtMYa49NTsbQagYuT1DcXnl1915oxWjoyGrXR6zH/Y0Zc96xWsPcoDKeA==", "dev": true, "requires": { @@ -5998,7 +5998,7 @@ }, "load-json-file": { "version": "4.0.0", - "resolved": false, + "resolved": "https://registry.npmjs.org/load-json-file/-/load-json-file-4.0.0.tgz", "integrity": "sha1-L19Fq5HjMhYjT9U62rZo607AmTs=", "dev": true, "requires": { @@ -6010,7 +6010,7 @@ }, "locate-path": { "version": "3.0.0", - "resolved": false, + "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-3.0.0.tgz", "integrity": "sha512-7AO748wWnIhNqAuaty2ZWHkQHRSNfPVIsPIfwEOWO22AmaoVrWavlOcMR5nzTLNYvp36X220/maaRsrec1G65A==", "dev": true, "requires": { @@ -6020,19 +6020,19 @@ }, "lodash": { "version": "4.17.11", - "resolved": false, + "resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.11.tgz", "integrity": "sha512-cQKh8igo5QUhZ7lg38DYWAxMvjSAKG0A8wGSVimP07SIUEK2UO+arSRKbRZWtelMtN5V0Hkwh5ryOto/SshYIg==", "dev": true }, "lodash.flattendeep": { "version": "4.4.0", - "resolved": false, + "resolved": "https://registry.npmjs.org/lodash.flattendeep/-/lodash.flattendeep-4.4.0.tgz", "integrity": "sha1-+wMJF/hqMTTlvJvsDWngAT3f7bI=", "dev": true }, "lru-cache": { "version": "4.1.5", - "resolved": false, + "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-4.1.5.tgz", "integrity": "sha512-sWZlbEP2OsHNkXrMl5GYk/jKk70MBng6UU4YI/qGDYbgf6YbP4EvmqISbXCoJiRKs+1bSpFHVgQxvJ17F2li5g==", "dev": true, "requires": { @@ -6042,7 +6042,7 @@ }, "make-dir": { "version": "1.3.0", - "resolved": false, + "resolved": "https://registry.npmjs.org/make-dir/-/make-dir-1.3.0.tgz", "integrity": "sha512-2w31R7SJtieJJnQtGc7RVL2StM2vGYVfqUOvUDxH6bC6aJTxPxTF0GnIgCyu7tjockiUWAYQRbxa7vKn34s5sQ==", "dev": true, "requires": { @@ -6051,7 +6051,7 @@ }, "map-age-cleaner": { "version": "0.1.3", - "resolved": false, + "resolved": "https://registry.npmjs.org/map-age-cleaner/-/map-age-cleaner-0.1.3.tgz", "integrity": "sha512-bJzx6nMoP6PDLPBFmg7+xRKeFZvFboMrGlxmNj9ClvX53KrmvM5bXFXEWjbz4cz1AFn+jWJ9z/DJSz7hrs0w3w==", "dev": true, "requires": { @@ -6060,7 +6060,7 @@ }, "mem": { "version": "4.1.0", - "resolved": false, + "resolved": "https://registry.npmjs.org/mem/-/mem-4.1.0.tgz", "integrity": "sha512-I5u6Q1x7wxO0kdOpYBB28xueHADYps5uty/zg936CiG8NTe5sJL8EjrCuLneuDW3PlMdZBGDIn8BirEVdovZvg==", "dev": true, "requires": { @@ -6071,7 +6071,7 @@ }, "merge-source-map": { "version": "1.1.0", - "resolved": false, + "resolved": "https://registry.npmjs.org/merge-source-map/-/merge-source-map-1.1.0.tgz", "integrity": "sha512-Qkcp7P2ygktpMPh2mCQZaf3jhN6D3Z/qVZHSdWvQ+2Ef5HgRAPBO57A77+ENm0CPx2+1Ce/MYKi3ymqdfuqibw==", "dev": true, "requires": { @@ -6080,7 +6080,7 @@ "dependencies": { "source-map": { "version": "0.6.1", - "resolved": false, + "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==", "dev": true } @@ -6088,13 +6088,13 @@ }, "mimic-fn": { "version": "1.2.0", - "resolved": false, + "resolved": "https://registry.npmjs.org/mimic-fn/-/mimic-fn-1.2.0.tgz", "integrity": "sha512-jf84uxzwiuiIVKiOLpfYk7N46TSy8ubTonmneY9vrpHNAnp0QBt2BxWV9dO3/j+BoVAb+a5G6YDPW3M5HOdMWQ==", "dev": true }, "minimatch": { "version": "3.0.4", - "resolved": false, + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.0.4.tgz", "integrity": "sha512-yJHVQEhyqPLUTgt9B83PXu6W3rx4MvvHvSUvToogpwoGDOUQ+yDrR0HRot+yOCdCO7u4hX3pWft6kWBBcqh0UA==", "dev": true, "requires": { @@ -6103,13 +6103,13 @@ }, "minimist": { "version": "0.0.10", - "resolved": false, + "resolved": "https://registry.npmjs.org/minimist/-/minimist-0.0.10.tgz", "integrity": "sha1-3j+YVD2/lggr5IrRoMfNqDYwHc8=", "dev": true }, "mkdirp": { "version": "0.5.1", - "resolved": false, + "resolved": "https://registry.npmjs.org/mkdirp/-/mkdirp-0.5.1.tgz", "integrity": "sha1-MAV0OOrGz3+MR2fzhkjWaX11yQM=", "dev": true, "requires": { @@ -6118,7 +6118,7 @@ "dependencies": { "minimist": { "version": "0.0.8", - "resolved": false, + "resolved": "https://registry.npmjs.org/minimist/-/minimist-0.0.8.tgz", "integrity": "sha1-hX/Kv8M5fSYluCKCYuhqp6ARsF0=", "dev": true } @@ -6126,19 +6126,19 @@ }, "ms": { "version": "2.1.1", - "resolved": false, + "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.1.tgz", "integrity": "sha512-tgp+dl5cGk28utYktBsrFqA7HKgrhgPsg6Z/EfhWI4gl1Hwq8B/GmY/0oXZ6nF8hDVesS/FpnYaD/kOWhYQvyg==", "dev": true }, "nice-try": { "version": "1.0.5", - "resolved": false, + "resolved": "https://registry.npmjs.org/nice-try/-/nice-try-1.0.5.tgz", "integrity": "sha512-1nh45deeb5olNY7eX82BkPO7SSxR5SSYJiPTrTdFUVYwAl8CKMA5N9PjTYkHiRjisVcxcQ1HXdLhx2qxxJzLNQ==", "dev": true }, "normalize-package-data": { "version": "2.5.0", - "resolved": false, + "resolved": "https://registry.npmjs.org/normalize-package-data/-/normalize-package-data-2.5.0.tgz", "integrity": "sha512-/5CMN3T0R4XTj4DcGaexo+roZSdSFW/0AOOTROrjxzCG1wrWXEsGbRKevjlIL+ZDE4sZlJr5ED4YW0yqmkK+eA==", "dev": true, "requires": { @@ -6150,7 +6150,7 @@ }, "npm-run-path": { "version": "2.0.2", - "resolved": false, + "resolved": "https://registry.npmjs.org/npm-run-path/-/npm-run-path-2.0.2.tgz", "integrity": "sha1-NakjLfo11wZ7TLLd8jV7GHFTbF8=", "dev": true, "requires": { @@ -6159,13 +6159,13 @@ }, "number-is-nan": { "version": "1.0.1", - "resolved": false, + "resolved": "https://registry.npmjs.org/number-is-nan/-/number-is-nan-1.0.1.tgz", "integrity": "sha1-CXtgK1NCKlIsGvuHkDGDNpQaAR0=", "dev": true }, "once": { "version": "1.4.0", - "resolved": false, + "resolved": "https://registry.npmjs.org/once/-/once-1.4.0.tgz", "integrity": "sha1-WDsap3WWHUsROsF9nFC6753Xa9E=", "dev": true, "requires": { @@ -6174,7 +6174,7 @@ }, "optimist": { "version": "0.6.1", - "resolved": false, + "resolved": "https://registry.npmjs.org/optimist/-/optimist-0.6.1.tgz", "integrity": "sha1-2j6nRob6IaGaERwybpDrFaAZZoY=", "dev": true, "requires": { @@ -6184,13 +6184,13 @@ }, "os-homedir": { "version": "1.0.2", - "resolved": false, + "resolved": "https://registry.npmjs.org/os-homedir/-/os-homedir-1.0.2.tgz", "integrity": "sha1-/7xJiDNuDoM94MFox+8VISGqf7M=", "dev": true }, "os-locale": { "version": "3.1.0", - "resolved": false, + "resolved": "https://registry.npmjs.org/os-locale/-/os-locale-3.1.0.tgz", "integrity": "sha512-Z8l3R4wYWM40/52Z+S265okfFj8Kt2cC2MKY+xNi3kFs+XGI7WXu/I309QQQYbRW4ijiZ+yxs9pqEhJh0DqW3Q==", "dev": true, "requires": { @@ -6201,25 +6201,25 @@ }, "p-defer": { "version": "1.0.0", - "resolved": false, + "resolved": "https://registry.npmjs.org/p-defer/-/p-defer-1.0.0.tgz", "integrity": "sha1-n26xgvbJqozXQwBKfU+WsZaw+ww=", "dev": true }, "p-finally": { "version": "1.0.0", - "resolved": false, + "resolved": "https://registry.npmjs.org/p-finally/-/p-finally-1.0.0.tgz", "integrity": "sha1-P7z7FbiZpEEjs0ttzBi3JDNqLK4=", "dev": true }, "p-is-promise": { "version": "2.0.0", - "resolved": false, + "resolved": "https://registry.npmjs.org/p-is-promise/-/p-is-promise-2.0.0.tgz", "integrity": "sha512-pzQPhYMCAgLAKPWD2jC3Se9fEfrD9npNos0y150EeqZll7akhEgGhTW/slB6lHku8AvYGiJ+YJ5hfHKePPgFWg==", "dev": true }, "p-limit": { "version": "2.1.0", - "resolved": false, + "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-2.1.0.tgz", "integrity": "sha512-NhURkNcrVB+8hNfLuysU8enY5xn2KXphsHBaC2YmRNTZRc7RWusw6apSpdEj3jo4CMb6W9nrF6tTnsJsJeyu6g==", "dev": true, "requires": { @@ -6228,7 +6228,7 @@ }, "p-locate": { "version": "3.0.0", - "resolved": false, + "resolved": "https://registry.npmjs.org/p-locate/-/p-locate-3.0.0.tgz", "integrity": "sha512-x+12w/To+4GFfgJhBEpiDcLozRJGegY+Ei7/z0tSLkMmxGZNybVMSfWj9aJn8Z5Fc7dBUNJOOVgPv2H7IwulSQ==", "dev": true, "requires": { @@ -6237,13 +6237,13 @@ }, "p-try": { "version": "2.0.0", - "resolved": false, + "resolved": "https://registry.npmjs.org/p-try/-/p-try-2.0.0.tgz", "integrity": "sha512-hMp0onDKIajHfIkdRk3P4CdCmErkYAxxDtP3Wx/4nZ3aGlau2VKh3mZpcuFkH27WQkL/3WBCPOktzA9ZOAnMQQ==", "dev": true }, "package-hash": { "version": "3.0.0", - "resolved": false, + "resolved": "https://registry.npmjs.org/package-hash/-/package-hash-3.0.0.tgz", "integrity": "sha512-lOtmukMDVvtkL84rJHI7dpTYq+0rli8N2wlnqUcBuDWCfVhRUfOmnR9SsoHFMLpACvEV60dX7rd0rFaYDZI+FA==", "dev": true, "requires": { @@ -6255,7 +6255,7 @@ }, "parse-json": { "version": "4.0.0", - "resolved": false, + "resolved": "https://registry.npmjs.org/parse-json/-/parse-json-4.0.0.tgz", "integrity": "sha1-vjX1Qlvh9/bHRxhPmKeIy5lHfuA=", "dev": true, "requires": { @@ -6265,31 +6265,31 @@ }, "path-exists": { "version": "3.0.0", - "resolved": false, + "resolved": "https://registry.npmjs.org/path-exists/-/path-exists-3.0.0.tgz", "integrity": "sha1-zg6+ql94yxiSXqfYENe1mwEP1RU=", "dev": true }, "path-is-absolute": { "version": "1.0.1", - "resolved": false, + "resolved": "https://registry.npmjs.org/path-is-absolute/-/path-is-absolute-1.0.1.tgz", "integrity": "sha1-F0uSaHNVNP+8es5r9TpanhtcX18=", "dev": true }, "path-key": { "version": "2.0.1", - "resolved": false, + "resolved": "https://registry.npmjs.org/path-key/-/path-key-2.0.1.tgz", "integrity": "sha1-QRyttXTFoUDTpLGRDUDYDMn0C0A=", "dev": true }, "path-parse": { "version": "1.0.6", - "resolved": false, + "resolved": "https://registry.npmjs.org/path-parse/-/path-parse-1.0.6.tgz", "integrity": "sha512-GSmOT2EbHrINBf9SR7CDELwlJ8AENk3Qn7OikK4nFYAu3Ote2+JYNVvkpAEQm3/TLNEJFD/xZJjzyxg3KBWOzw==", "dev": true }, "path-type": { "version": "3.0.0", - "resolved": false, + "resolved": "https://registry.npmjs.org/path-type/-/path-type-3.0.0.tgz", "integrity": "sha512-T2ZUsdZFHgA3u4e5PfPbjd7HDDpxPnQb5jN0SrDsjNSuVXHJqtwTnWqG0B1jZrgmJ/7lj1EmVIByWt1gxGkWvg==", "dev": true, "requires": { @@ -6298,13 +6298,13 @@ }, "pify": { "version": "3.0.0", - "resolved": false, + "resolved": "https://registry.npmjs.org/pify/-/pify-3.0.0.tgz", "integrity": "sha1-5aSs0sEB/fPZpNB/DbxNtJ3SgXY=", "dev": true }, "pkg-dir": { "version": "3.0.0", - "resolved": false, + "resolved": "https://registry.npmjs.org/pkg-dir/-/pkg-dir-3.0.0.tgz", "integrity": "sha512-/E57AYkoeQ25qkxMj5PBOVgF8Kiu/h7cYS30Z5+R7WaiCCBfLq58ZI/dSeaEKb9WVJV5n/03QwrN3IeWIFllvw==", "dev": true, "requires": { @@ -6313,13 +6313,13 @@ }, "pseudomap": { "version": "1.0.2", - "resolved": false, + "resolved": "https://registry.npmjs.org/pseudomap/-/pseudomap-1.0.2.tgz", "integrity": "sha1-8FKijacOYYkX7wqKw0wa5aaChrM=", "dev": true }, "pump": { "version": "3.0.0", - "resolved": false, + "resolved": "https://registry.npmjs.org/pump/-/pump-3.0.0.tgz", "integrity": "sha512-LwZy+p3SFs1Pytd/jYct4wpv49HiYCqd9Rlc5ZVdk0V+8Yzv6jR5Blk3TRmPL1ft69TxP0IMZGJ+WPFU2BFhww==", "dev": true, "requires": { @@ -6329,7 +6329,7 @@ }, "read-pkg": { "version": "3.0.0", - "resolved": false, + "resolved": "https://registry.npmjs.org/read-pkg/-/read-pkg-3.0.0.tgz", "integrity": "sha1-nLxoaXj+5l0WwA4rGcI3/Pbjg4k=", "dev": true, "requires": { @@ -6340,7 +6340,7 @@ }, "read-pkg-up": { "version": "4.0.0", - "resolved": false, + "resolved": "https://registry.npmjs.org/read-pkg-up/-/read-pkg-up-4.0.0.tgz", "integrity": "sha512-6etQSH7nJGsK0RbG/2TeDzZFa8shjQ1um+SwQQ5cwKy0dhSXdOncEhb1CPpvQG4h7FyOV6EB6YlV0yJvZQNAkA==", "dev": true, "requires": { @@ -6350,7 +6350,7 @@ }, "release-zalgo": { "version": "1.0.0", - "resolved": false, + "resolved": "https://registry.npmjs.org/release-zalgo/-/release-zalgo-1.0.0.tgz", "integrity": "sha1-CXALflB0Mpc5Mw5TXFqQ+2eFFzA=", "dev": true, "requires": { @@ -6359,19 +6359,19 @@ }, "require-directory": { "version": "2.1.1", - "resolved": false, + "resolved": "https://registry.npmjs.org/require-directory/-/require-directory-2.1.1.tgz", "integrity": "sha1-jGStX9MNqxyXbiNE/+f3kqam30I=", "dev": true }, "require-main-filename": { "version": "1.0.1", - "resolved": false, + "resolved": "https://registry.npmjs.org/require-main-filename/-/require-main-filename-1.0.1.tgz", "integrity": "sha1-l/cXtp1IeE9fUmpsWqj/3aBVpNE=", "dev": true }, "resolve": { "version": "1.10.0", - "resolved": false, + "resolved": "https://registry.npmjs.org/resolve/-/resolve-1.10.0.tgz", "integrity": "sha512-3sUr9aq5OfSg2S9pNtPA9hL1FVEAjvfOC4leW0SNf/mpnaakz2a9femSd6LqAww2RaFctwyf1lCqnTHuF1rxDg==", "dev": true, "requires": { @@ -6380,13 +6380,13 @@ }, "resolve-from": { "version": "4.0.0", - "resolved": false, + "resolved": "https://registry.npmjs.org/resolve-from/-/resolve-from-4.0.0.tgz", "integrity": "sha512-pb/MYmXstAkysRFx8piNI1tGFNQIFA3vkE3Gq4EuA1dF6gHp/+vgZqsCGJapvy8N3Q+4o7FwvquPJcnZ7RYy4g==", "dev": true }, "rimraf": { "version": "2.6.3", - "resolved": false, + "resolved": "https://registry.npmjs.org/rimraf/-/rimraf-2.6.3.tgz", "integrity": "sha512-mwqeW5XsA2qAejG46gYdENaxXjx9onRNCfn7L0duuP4hCuTIi/QO7PDK07KJfp1d+izWPrzEJDcSqBa0OZQriA==", "dev": true, "requires": { @@ -6395,25 +6395,25 @@ }, "safe-buffer": { "version": "5.1.2", - "resolved": false, + "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.1.2.tgz", "integrity": "sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g==", "dev": true }, "semver": { "version": "5.6.0", - "resolved": false, + "resolved": "https://registry.npmjs.org/semver/-/semver-5.6.0.tgz", "integrity": "sha512-RS9R6R35NYgQn++fkDWaOmqGoj4Ek9gGs+DPxNUZKuwE183xjJroKvyo1IzVFeXvUrvmALy6FWD5xrdJT25gMg==", "dev": true }, "set-blocking": { "version": "2.0.0", - "resolved": false, + "resolved": "https://registry.npmjs.org/set-blocking/-/set-blocking-2.0.0.tgz", "integrity": "sha1-BF+XgtARrppoA93TgrJDkrPYkPc=", "dev": true }, "shebang-command": { "version": "1.2.0", - "resolved": false, + "resolved": "https://registry.npmjs.org/shebang-command/-/shebang-command-1.2.0.tgz", "integrity": "sha1-RKrGW2lbAzmJaMOfNj/uXer98eo=", "dev": true, "requires": { @@ -6422,19 +6422,19 @@ }, "shebang-regex": { "version": "1.0.0", - "resolved": false, + "resolved": "https://registry.npmjs.org/shebang-regex/-/shebang-regex-1.0.0.tgz", "integrity": "sha1-2kL0l0DAtC2yypcoVxyxkMmO/qM=", "dev": true }, "signal-exit": { "version": "3.0.2", - "resolved": false, + "resolved": "https://registry.npmjs.org/signal-exit/-/signal-exit-3.0.2.tgz", "integrity": "sha1-tf3AjxKH6hF4Yo5BXiUTK3NkbG0=", "dev": true }, "spawn-wrap": { "version": "1.4.2", - "resolved": false, + "resolved": "https://registry.npmjs.org/spawn-wrap/-/spawn-wrap-1.4.2.tgz", "integrity": "sha512-vMwR3OmmDhnxCVxM8M+xO/FtIp6Ju/mNaDfCMMW7FDcLRTPFWUswec4LXJHTJE2hwTI9O0YBfygu4DalFl7Ylg==", "dev": true, "requires": { @@ -6448,7 +6448,7 @@ }, "spdx-correct": { "version": "3.1.0", - "resolved": false, + "resolved": "https://registry.npmjs.org/spdx-correct/-/spdx-correct-3.1.0.tgz", "integrity": "sha512-lr2EZCctC2BNR7j7WzJ2FpDznxky1sjfxvvYEyzxNyb6lZXHODmEoJeFu4JupYlkfha1KZpJyoqiJ7pgA1qq8Q==", "dev": true, "requires": { @@ -6458,13 +6458,13 @@ }, "spdx-exceptions": { "version": "2.2.0", - "resolved": false, + "resolved": "https://registry.npmjs.org/spdx-exceptions/-/spdx-exceptions-2.2.0.tgz", "integrity": "sha512-2XQACfElKi9SlVb1CYadKDXvoajPgBVPn/gOQLrTvHdElaVhr7ZEbqJaRnJLVNeaI4cMEAgVCeBMKF6MWRDCRA==", "dev": true }, "spdx-expression-parse": { "version": "3.0.0", - "resolved": false, + "resolved": "https://registry.npmjs.org/spdx-expression-parse/-/spdx-expression-parse-3.0.0.tgz", "integrity": "sha512-Yg6D3XpRD4kkOmTpdgbUiEJFKghJH03fiC1OPll5h/0sO6neh2jqRDVHOQ4o/LMea0tgCkbMgea5ip/e+MkWyg==", "dev": true, "requires": { @@ -6474,13 +6474,13 @@ }, "spdx-license-ids": { "version": "3.0.3", - "resolved": false, + "resolved": "https://registry.npmjs.org/spdx-license-ids/-/spdx-license-ids-3.0.3.tgz", "integrity": "sha512-uBIcIl3Ih6Phe3XHK1NqboJLdGfwr1UN3k6wSD1dZpmPsIkb8AGNbZYJ1fOBk834+Gxy8rpfDxrS6XLEMZMY2g==", "dev": true }, "string-width": { "version": "2.1.1", - "resolved": false, + "resolved": "https://registry.npmjs.org/string-width/-/string-width-2.1.1.tgz", "integrity": "sha512-nOqH59deCq9SRHlxq1Aw85Jnt4w6KvLKqWVik6oA9ZklXLNIOlqg4F2yrT1MVaTjAqvVwdfeZ7w7aCvJD7ugkw==", "dev": true, "requires": { @@ -6490,7 +6490,7 @@ }, "strip-ansi": { "version": "4.0.0", - "resolved": false, + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-4.0.0.tgz", "integrity": "sha1-qEeQIusaw2iocTibY1JixQXuNo8=", "dev": true, "requires": { @@ -6499,19 +6499,19 @@ }, "strip-bom": { "version": "3.0.0", - "resolved": false, + "resolved": "https://registry.npmjs.org/strip-bom/-/strip-bom-3.0.0.tgz", "integrity": "sha1-IzTBjpx1n3vdVv3vfprj1YjmjtM=", "dev": true }, "strip-eof": { "version": "1.0.0", - "resolved": false, + "resolved": "https://registry.npmjs.org/strip-eof/-/strip-eof-1.0.0.tgz", "integrity": "sha1-u0P/VZim6wXYm1n80SnJgzE2Br8=", "dev": true }, "test-exclude": { "version": "5.1.0", - "resolved": false, + "resolved": "https://registry.npmjs.org/test-exclude/-/test-exclude-5.1.0.tgz", "integrity": "sha512-gwf0S2fFsANC55fSeSqpb8BYk6w3FDvwZxfNjeF6FRgvFa43r+7wRiA/Q0IxoRU37wB/LE8IQ4221BsNucTaCA==", "dev": true, "requires": { @@ -6523,7 +6523,7 @@ }, "uglify-js": { "version": "3.4.9", - "resolved": false, + "resolved": "https://registry.npmjs.org/uglify-js/-/uglify-js-3.4.9.tgz", "integrity": "sha512-8CJsbKOtEbnJsTyv6LE6m6ZKniqMiFWmm9sRbopbkGs3gMPPfd3Fh8iIA4Ykv5MgaTbqHr4BaoGLJLZNhsrW1Q==", "dev": true, "optional": true, @@ -6534,7 +6534,7 @@ "dependencies": { "source-map": { "version": "0.6.1", - "resolved": false, + "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==", "dev": true, "optional": true @@ -6543,13 +6543,13 @@ }, "uuid": { "version": "3.3.2", - "resolved": false, + "resolved": "https://registry.npmjs.org/uuid/-/uuid-3.3.2.tgz", "integrity": "sha512-yXJmeNaw3DnnKAOKJE51sL/ZaYfWJRl1pK9dr19YFCu0ObS231AB1/LbqTKRAQ5kw8A90rA6fr4riOUpTZvQZA==", "dev": true }, "validate-npm-package-license": { "version": "3.0.4", - "resolved": false, + "resolved": "https://registry.npmjs.org/validate-npm-package-license/-/validate-npm-package-license-3.0.4.tgz", "integrity": "sha512-DpKm2Ui/xN7/HQKCtpZxoRWBhZ9Z0kqtygG8XCgNQ8ZlDnxuQmWhj566j8fN4Cu3/JmbhsDo7fcAJq4s9h27Ew==", "dev": true, "requires": { @@ -6559,7 +6559,7 @@ }, "which": { "version": "1.3.1", - "resolved": false, + "resolved": "https://registry.npmjs.org/which/-/which-1.3.1.tgz", "integrity": "sha512-HxJdYWq1MTIQbJ3nw0cqssHoTNU267KlrDuGZ1WYlxDStUtKUhOaJmh112/TZmHxxUfuJqPXSOm7tDyas0OSIQ==", "dev": true, "requires": { @@ -6568,19 +6568,19 @@ }, "which-module": { "version": "2.0.0", - "resolved": false, + "resolved": "https://registry.npmjs.org/which-module/-/which-module-2.0.0.tgz", "integrity": "sha1-2e8H3Od7mQK4o6j6SzHD4/fm6Ho=", "dev": true }, "wordwrap": { "version": "0.0.3", - "resolved": false, + "resolved": "https://registry.npmjs.org/wordwrap/-/wordwrap-0.0.3.tgz", "integrity": "sha1-o9XabNXAvAAI03I0u68b7WMFkQc=", "dev": true }, "wrap-ansi": { "version": "2.1.0", - "resolved": false, + "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-2.1.0.tgz", "integrity": "sha1-2Pw9KE3QV5T+hJc8rs3Rz4JP3YU=", "dev": true, "requires": { @@ -6590,13 +6590,13 @@ "dependencies": { "ansi-regex": { "version": "2.1.1", - "resolved": false, + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-2.1.1.tgz", "integrity": "sha1-w7M6te42DYbg5ijwRorn7yfWVN8=", "dev": true }, "is-fullwidth-code-point": { "version": "1.0.0", - "resolved": false, + "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-1.0.0.tgz", "integrity": "sha1-754xOG8DGn8NZDr4L95QxFfvAMs=", "dev": true, "requires": { @@ -6605,7 +6605,7 @@ }, "string-width": { "version": "1.0.2", - "resolved": false, + "resolved": "https://registry.npmjs.org/string-width/-/string-width-1.0.2.tgz", "integrity": "sha1-EYvfW4zcUaKn5w0hHgfisLmxB9M=", "dev": true, "requires": { @@ -6616,7 +6616,7 @@ }, "strip-ansi": { "version": "3.0.1", - "resolved": false, + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-3.0.1.tgz", "integrity": "sha1-ajhfuIU9lS1f8F0Oiq+UJ43GPc8=", "dev": true, "requires": { @@ -6627,13 +6627,13 @@ }, "wrappy": { "version": "1.0.2", - "resolved": false, + "resolved": "https://registry.npmjs.org/wrappy/-/wrappy-1.0.2.tgz", "integrity": "sha1-tSQ9jz7BqjXxNkYFvA0QNuMKtp8=", "dev": true }, "write-file-atomic": { "version": "2.4.2", - "resolved": false, + "resolved": "https://registry.npmjs.org/write-file-atomic/-/write-file-atomic-2.4.2.tgz", "integrity": "sha512-s0b6vB3xIVRLWywa6X9TOMA7k9zio0TMOsl9ZnDkliA/cfJlpHXAscj0gbHVJiTdIuAYpIyqS5GW91fqm6gG5g==", "dev": true, "requires": { @@ -6644,19 +6644,19 @@ }, "y18n": { "version": "4.0.0", - "resolved": false, + "resolved": "https://registry.npmjs.org/y18n/-/y18n-4.0.0.tgz", "integrity": "sha512-r9S/ZyXu/Xu9q1tYlpsLIsa3EeLXXk0VwlxqTcFRfg9EhMW+17kbt9G0NrgCmhGb5vT2hyhJZLfDGx+7+5Uj/w==", "dev": true }, "yallist": { "version": "2.1.2", - "resolved": false, + "resolved": "https://registry.npmjs.org/yallist/-/yallist-2.1.2.tgz", "integrity": "sha1-HBH5IY8HYImkfdUS+TxmmaaoHVI=", "dev": true }, "yargs": { "version": "12.0.5", - "resolved": false, + "resolved": "https://registry.npmjs.org/yargs/-/yargs-12.0.5.tgz", "integrity": "sha512-Lhz8TLaYnxq/2ObqHDql8dX8CJi97oHxrjUcYtzKbbykPtVW9WB+poxI+NM2UIzsMgNCZTIf0AQwsjK5yMAqZw==", "dev": true, "requires": { @@ -6676,7 +6676,7 @@ }, "yargs-parser": { "version": "11.1.1", - "resolved": false, + "resolved": "https://registry.npmjs.org/yargs-parser/-/yargs-parser-11.1.1.tgz", "integrity": "sha512-C6kB/WJDiaxONLJQnF8ccx9SEeoTTLek8RVbaOIsrAUS8VrBEXfmeSnCZxygc+XC2sNMBIwOOnfcxiynjHsVSQ==", "dev": true, "requires": { diff --git a/server/controllers/index.js b/server/controllers/index.js index 542b221..162e755 100644 --- a/server/controllers/index.js +++ b/server/controllers/index.js @@ -7,6 +7,7 @@ import ratingController from './rating.controller'; import ResetPasswordController from './reset-password.controllers'; import commentController from './comment.controller'; import getFollowersController from './get-followers.controllers'; +import searchArticles from './search-article.controllers'; export default { profileController, @@ -18,4 +19,5 @@ export default { ResetPasswordController, commentController, getFollowersController, + searchArticles, }; diff --git a/server/controllers/search-article.controllers.js b/server/controllers/search-article.controllers.js new file mode 100644 index 0000000..b2ca4b8 --- /dev/null +++ b/server/controllers/search-article.controllers.js @@ -0,0 +1,121 @@ +import sequelize from 'sequelize'; +import models from '../models'; +import serverError from '../helpers/server-error'; + +const { Article, User } = models; + +const searchArticles = async (req, res) => { + const authorSearchFilter = req.query.author; + const titleSearchFilter = req.query.title; + + if (authorSearchFilter && titleSearchFilter) { + try { + const filteredArticlesByAuthorAndTitle = await Article.findAll({ + where: { + user_id: authorSearchFilter, + title: titleSearchFilter, + }, + attributes: [ + 'slug', + 'title', + 'body', + 'createdAt', + 'updatedAt', + 'likes_count', + ], + include: [ + { + model: User, + where: { + id: authorSearchFilter, + }, + attributes: ['first_name', 'last_name'], + }, + ], + }); + return res.status(200).json({ + filteredArticlesByAuthorAndTitle, + }); + } catch (e) { + return res.status(500).json({ + errors: serverError(), + }); + } + } + + if (authorSearchFilter) { + try { + const seachFilter = sequelize.Op; + const filteredArticlesByAuthor = await User.findAll({ + where: { + first_name: { + [seachFilter.iLike]: `%${authorSearchFilter}%`, + }, + }, + attributes: ['first_name', 'last_name'], + include: [ + { + model: Article, + attributes: [ + 'slug', + 'title', + 'body', + 'createdAt', + 'updatedAt', + 'likes_count', + ], + }, + ], + }); + return res.status(200).json({ + filteredArticlesByAuthor, + }); + } catch (e) { + return res.status(500).json({ + errors: e, + }); + } + } + + if (titleSearchFilter) { + try { + const filteredArticlesByTitle = await Article.findAll({ + where: { + title: titleSearchFilter, + }, + attributes: [ + 'slug', + 'title', + 'body', + 'createdAt', + 'updatedAt', + 'likes_count', + ], + include: [ + { + model: User, + where: { + id: authorSearchFilter, + }, + attributes: ['first_name', 'last_name'], + }, + ], + }); + return res.status(200).json({ + filteredArticlesByTitle, + }); + } catch (e) { + return res.status(500).json({ + errors: serverError(), + }); + } + } + + return res.status(200).json({ + message: 'No search filter entered', + }); +}; + +const Articles = { searchArticles }; + +export default Articles; diff --git a/server/routes/index.js b/server/routes/index.js index 915d161..b188db6 100644 --- a/server/routes/index.js +++ b/server/routes/index.js @@ -10,6 +10,7 @@ import ratingRoute from './rating.routes'; import commentRoute from './comment.routes'; import followRoutes from './follow.routes'; import getFollowersRoute from './get-followers.routes'; +import searchArticles from './search-articles.routes'; const router = express.Router(); @@ -62,5 +63,6 @@ router.use(profileRoute); router.use(likeRoute); router.use(profileRoute); router.use(getFollowersRoute); +router.use(searchArticles); export default router; diff --git a/server/routes/search-articles.routes.js b/server/routes/search-articles.routes.js new file mode 100644 index 0000000..55b339b --- /dev/null +++ b/server/routes/search-articles.routes.js @@ -0,0 +1,9 @@ +import express from 'express'; + +import Articles from '../controllers/search-article.controllers'; + +const router = express.Router(); + +router.use('/search', Articles.searchArticles); + +export default router; diff --git a/tests/article-search.test.js b/tests/article-search.test.js new file mode 100644 index 0000000..14432a5 --- /dev/null +++ b/tests/article-search.test.js @@ -0,0 +1,22 @@ +import chai, { expect } from 'chai'; +import app from '../server/app'; + +describe('Display articles in pages', () => { + const authorName = '6517a6ea-662b-4eef-ab9f-20f89bd7099c'; + const tag = ''; + const articleTitle = ''; + it('should display articles based on the page number', done => { + chai + .request(app) + .get( + `/api/v1/articles/search?author=${authorName}&keyword=${tag}&title=${articleTitle}` + ) + .end((err, res) => { + const { articles } = res.body; + expect(res).to.have(200); + expect(articles).to.be.a('array'); + + done(); + }); + }); +}); From f761a37a1bac120b4ec3ab9997995d5e0f02fa6d Mon Sep 17 00:00:00 2001 From: Akinwale Samuel Date: Thu, 11 Apr 2019 17:13:27 +0100 Subject: [PATCH 2/5] 164798028-feature(search): add test cases --- .../controllers/search-article.controllers.js | 240 ++++++++++++++++-- server/models/keyword.js | 1 + tests/article-search.test.js | 97 ++++++- 3 files changed, 307 insertions(+), 31 deletions(-) diff --git a/server/controllers/search-article.controllers.js b/server/controllers/search-article.controllers.js index b2ca4b8..5b798fc 100644 --- a/server/controllers/search-article.controllers.js +++ b/server/controllers/search-article.controllers.js @@ -2,34 +2,92 @@ import sequelize from 'sequelize'; import models from '../models'; import serverError from '../helpers/server-error'; -const { Article, User } = models; +const { Article, User, Keyword } = models; const searchArticles = async (req, res) => { const authorSearchFilter = req.query.author; const titleSearchFilter = req.query.title; + const keywordSearchFilter = req.query.keyword; - if (authorSearchFilter && titleSearchFilter) { + if (keywordSearchFilter && authorSearchFilter && titleSearchFilter) { try { - const filteredArticlesByAuthorAndTitle = await Article.findAll({ + const searchFilter = sequelize.Op; + const filteredArticlesByKeyword = await Keyword.findAll({ where: { - user_id: authorSearchFilter, - title: titleSearchFilter, + keyword: { + [searchFilter.iLike]: `%${keywordSearchFilter}%`, + }, }, - attributes: [ - 'slug', - 'title', - 'body', - 'createdAt', - 'updatedAt', - 'likes_count', + attributes: ['keyword'], + include: [ + { + model: Article, + as: 'article', + where: { + title: { + [searchFilter.iLike]: `%${titleSearchFilter}%`, + }, + }, + attributes: [ + 'slug', + 'title', + 'body', + 'createdAt', + 'updatedAt', + 'likes_count', + ], + include: [ + { + model: User, + as: 'author', + where: { + first_name: { + [searchFilter.iLike]: `%${authorSearchFilter}%`, + }, + }, + attributes: ['first_name', 'last_name'], + }, + ], + }, ], + }); + return res.status(200).json({ + filteredArticlesByKeyword, + }); + } catch (e) { + return res.status(500).json({ + errors: serverError(), + }); + } + } + + if (authorSearchFilter && titleSearchFilter) { + try { + const searchFilter = sequelize.Op; + const filteredArticlesByAuthorAndTitle = await User.findAll({ + where: { + first_name: { + [searchFilter.iLike]: `%${authorSearchFilter}%`, + }, + }, + attributes: ['first_name', 'last_name'], include: [ { - model: User, + model: Article, + as: 'author', where: { - id: authorSearchFilter, + title: { + [searchFilter.iLike]: `%${titleSearchFilter}%`, + }, }, - attributes: ['first_name', 'last_name'], + attributes: [ + 'slug', + 'title', + 'body', + 'createdAt', + 'updatedAt', + 'likes_count', + ], }, ], }); @@ -43,19 +101,114 @@ const searchArticles = async (req, res) => { } } + if (keywordSearchFilter && authorSearchFilter) { + try { + const searchFilter = sequelize.Op; + const filteredArticlesByKeyword = await Keyword.findAll({ + where: { + keyword: { + [searchFilter.iLike]: `%${keywordSearchFilter}%`, + }, + }, + attributes: ['keyword'], + include: [ + { + model: Article, + as: 'article', + attributes: [ + 'slug', + 'title', + 'body', + 'createdAt', + 'updatedAt', + 'likes_count', + ], + include: [ + { + model: User, + as: 'author', + where: { + first_name: { + [searchFilter.iLike]: `%${authorSearchFilter}%`, + }, + }, + attributes: ['first_name', 'last_name'], + }, + ], + }, + ], + }); + return res.status(200).json({ + filteredArticlesByKeyword, + }); + } catch (e) { + return res.status(500).json({ + errors: serverError(), + }); + } + } + + if (keywordSearchFilter && titleSearchFilter) { + try { + const searchFilter = sequelize.Op; + const filteredArticlesByKeyword = await Keyword.findAll({ + where: { + keyword: { + [searchFilter.iLike]: `%${keywordSearchFilter}%`, + }, + }, + attributes: ['keyword'], + include: [ + { + model: Article, + as: 'article', + where: { + title: { + [searchFilter.iLike]: `%${titleSearchFilter}%`, + }, + }, + attributes: [ + 'slug', + 'title', + 'body', + 'createdAt', + 'updatedAt', + 'likes_count', + ], + include: [ + { + model: User, + as: 'author', + attributes: ['first_name', 'last_name'], + }, + ], + }, + ], + }); + return res.status(200).json({ + filteredArticlesByKeyword, + }); + } catch (e) { + return res.status(500).json({ + errors: serverError(), + }); + } + } + if (authorSearchFilter) { try { - const seachFilter = sequelize.Op; + const searchFilter = sequelize.Op; const filteredArticlesByAuthor = await User.findAll({ where: { first_name: { - [seachFilter.iLike]: `%${authorSearchFilter}%`, + [searchFilter.iLike]: `%${authorSearchFilter}%`, }, }, attributes: ['first_name', 'last_name'], include: [ { model: Article, + as: 'author', attributes: [ 'slug', 'title', @@ -72,16 +225,19 @@ const searchArticles = async (req, res) => { }); } catch (e) { return res.status(500).json({ - errors: e, + errors: serverError(), }); } } if (titleSearchFilter) { try { + const searchFilter = sequelize.Op; const filteredArticlesByTitle = await Article.findAll({ where: { - title: titleSearchFilter, + title: { + [searchFilter.iLike]: `%${titleSearchFilter}%`, + }, }, attributes: [ 'slug', @@ -94,9 +250,7 @@ const searchArticles = async (req, res) => { include: [ { model: User, - where: { - id: authorSearchFilter, - }, + as: 'author', attributes: ['first_name', 'last_name'], }, ], @@ -111,6 +265,48 @@ const searchArticles = async (req, res) => { } } + if (keywordSearchFilter) { + try { + const searchFilter = sequelize.Op; + const filteredArticlesByKeyword = await Keyword.findAll({ + where: { + keyword: { + [searchFilter.iLike]: `%${keywordSearchFilter}%`, + }, + }, + attributes: ['keyword'], + include: [ + { + model: Article, + as: 'article', + attributes: [ + 'slug', + 'title', + 'body', + 'createdAt', + 'updatedAt', + 'likes_count', + ], + include: [ + { + model: User, + as: 'author', + attributes: ['first_name', 'last_name'], + }, + ], + }, + ], + }); + return res.status(200).json({ + filteredArticlesByKeyword, + }); + } catch (e) { + return res.status(500).json({ + errors: serverError(), + }); + } + } + return res.status(200).json({ message: 'No search filter entered', }); diff --git a/server/models/keyword.js b/server/models/keyword.js index 9972c5b..dcb8b7a 100644 --- a/server/models/keyword.js +++ b/server/models/keyword.js @@ -19,6 +19,7 @@ module.exports = (sequelize, DataTypes) => { Keyword.associate = models => Keyword.belongsTo(models.Article, { foreignKey: 'article_id', + as: 'article', }); return Keyword; }; diff --git a/tests/article-search.test.js b/tests/article-search.test.js index 14432a5..51ffb6a 100644 --- a/tests/article-search.test.js +++ b/tests/article-search.test.js @@ -1,20 +1,99 @@ import chai, { expect } from 'chai'; import app from '../server/app'; -describe('Display articles in pages', () => { - const authorName = '6517a6ea-662b-4eef-ab9f-20f89bd7099c'; - const tag = ''; - const articleTitle = ''; - it('should display articles based on the page number', done => { +describe('Article Search', () => { + const authorName = 'a'; + const keyword = 'react'; + const articleTitle = 'Deep'; + it('Display articles by search filters: author, title and keyword', done => { chai .request(app) .get( - `/api/v1/articles/search?author=${authorName}&keyword=${tag}&title=${articleTitle}` + `/api/v1/search?author=${authorName}&keyword=${keyword}&title=${articleTitle}` ) .end((err, res) => { - const { articles } = res.body; - expect(res).to.have(200); - expect(articles).to.be.a('array'); + const article = res.body; + + expect(res.status).to.equal(200); + expect(article).to.be.a('object'); + + done(); + }); + }); + it('Display articles by search filters: author and title', done => { + chai + .request(app) + .get(`/api/v1/search?author=${authorName}&title=${articleTitle}`) + .end((err, res) => { + const articles = res.body; + + expect(res.status).to.equal(200); + expect(articles).to.be.a('object'); + + done(); + }); + }); + it('Display articles by search filters: author and keyword', done => { + chai + .request(app) + .get(`/api/v1/search?author=${authorName}&keyword=${keyword}`) + .end((err, res) => { + const articles = res.body; + + expect(res.status).to.equal(200); + expect(articles).to.be.a('object'); + + done(); + }); + }); + it('Display articles by search filters: keyword and title', done => { + chai + .request(app) + .get(`/api/v1/search?keyword=${keyword}&title=${articleTitle}`) + .end((err, res) => { + const articles = res.body; + + expect(res.status).to.equal(200); + expect(articles).to.be.a('object'); + + done(); + }); + }); + it('Display articles by search filter: author', done => { + chai + .request(app) + .get(`/api/v1/search?author=${authorName}`) + .end((err, res) => { + const articles = res.body; + + expect(res.status).to.equal(200); + expect(articles).to.be.a('object'); + + done(); + }); + }); + it('Display articles by search filter: keyword', done => { + chai + .request(app) + .get(`/api/v1/search?keyword=${keyword}`) + .end((err, res) => { + const articles = res.body; + + expect(res.status).to.equal(200); + expect(articles).to.be.a('object'); + + done(); + }); + }); + it('Display articles by search filter: title', done => { + chai + .request(app) + .get(`/api/v1/search?title=${articleTitle}`) + .end((err, res) => { + const articles = res.body; + + expect(res.status).to.equal(200); + expect(articles).to.be.a('object'); done(); }); From 3541f0657d9315c5cd8f687c151ff8802f21110c Mon Sep 17 00:00:00 2001 From: Akinwale Samuel Date: Fri, 12 Apr 2019 18:53:29 +0100 Subject: [PATCH 3/5] 164798028-feature(search): refactor code --- .../controllers/search-article.controllers.js | 347 +++--------------- tests/article-search.test.js | 85 +---- 2 files changed, 62 insertions(+), 370 deletions(-) diff --git a/server/controllers/search-article.controllers.js b/server/controllers/search-article.controllers.js index 5b798fc..f28903b 100644 --- a/server/controllers/search-article.controllers.js +++ b/server/controllers/search-article.controllers.js @@ -5,311 +5,72 @@ import serverError from '../helpers/server-error'; const { Article, User, Keyword } = models; const searchArticles = async (req, res) => { - const authorSearchFilter = req.query.author; - const titleSearchFilter = req.query.title; - const keywordSearchFilter = req.query.keyword; - - if (keywordSearchFilter && authorSearchFilter && titleSearchFilter) { - try { - const searchFilter = sequelize.Op; - const filteredArticlesByKeyword = await Keyword.findAll({ - where: { - keyword: { - [searchFilter.iLike]: `%${keywordSearchFilter}%`, - }, + try { + if (!Object.keys(req.query).length) { + return res.status(400).json({ + errors: { + body: ['No input provided'], }, - attributes: ['keyword'], - include: [ - { - model: Article, - as: 'article', - where: { - title: { - [searchFilter.iLike]: `%${titleSearchFilter}%`, - }, - }, - attributes: [ - 'slug', - 'title', - 'body', - 'createdAt', - 'updatedAt', - 'likes_count', - ], - include: [ - { - model: User, - as: 'author', - where: { - first_name: { - [searchFilter.iLike]: `%${authorSearchFilter}%`, - }, - }, - attributes: ['first_name', 'last_name'], - }, - ], - }, - ], - }); - return res.status(200).json({ - filteredArticlesByKeyword, - }); - } catch (e) { - return res.status(500).json({ - errors: serverError(), }); } - } - - if (authorSearchFilter && titleSearchFilter) { - try { - const searchFilter = sequelize.Op; - const filteredArticlesByAuthorAndTitle = await User.findAll({ - where: { - first_name: { - [searchFilter.iLike]: `%${authorSearchFilter}%`, - }, + const searchFilter = req.query.search; + const articles = Article.findAll({ + where: { + title: { + [sequelize.Op.iLike]: `%${searchFilter}%`, }, - attributes: ['first_name', 'last_name'], - include: [ - { - model: Article, - as: 'author', - where: { - title: { - [searchFilter.iLike]: `%${titleSearchFilter}%`, - }, - }, - attributes: [ - 'slug', - 'title', - 'body', - 'createdAt', - 'updatedAt', - 'likes_count', - ], - }, - ], - }); - return res.status(200).json({ - filteredArticlesByAuthorAndTitle, - }); - } catch (e) { - return res.status(500).json({ - errors: serverError(), - }); - } - } - - if (keywordSearchFilter && authorSearchFilter) { - try { - const searchFilter = sequelize.Op; - const filteredArticlesByKeyword = await Keyword.findAll({ - where: { - keyword: { - [searchFilter.iLike]: `%${keywordSearchFilter}%`, - }, + }, + attributes: [ + 'slug', + 'title', + 'body', + 'createdAt', + 'updatedAt', + 'likes_count', + ], + include: [ + { + model: User, + as: 'author', + attributes: ['first_name', 'last_name'], }, - attributes: ['keyword'], - include: [ - { - model: Article, - as: 'article', - attributes: [ - 'slug', - 'title', - 'body', - 'createdAt', - 'updatedAt', - 'likes_count', - ], - include: [ - { - model: User, - as: 'author', - where: { - first_name: { - [searchFilter.iLike]: `%${authorSearchFilter}%`, - }, - }, - attributes: ['first_name', 'last_name'], - }, - ], - }, - ], - }); - return res.status(200).json({ - filteredArticlesByKeyword, - }); - } catch (e) { - return res.status(500).json({ - errors: serverError(), - }); - } - } + ], + }); - if (keywordSearchFilter && titleSearchFilter) { - try { - const searchFilter = sequelize.Op; - const filteredArticlesByKeyword = await Keyword.findAll({ - where: { - keyword: { - [searchFilter.iLike]: `%${keywordSearchFilter}%`, - }, + const keywords = Keyword.findAll({ + where: { + keyword: { + [sequelize.Op.iLike]: `%${searchFilter}%`, }, - attributes: ['keyword'], - include: [ - { - model: Article, - as: 'article', - where: { - title: { - [searchFilter.iLike]: `%${titleSearchFilter}%`, - }, - }, - attributes: [ - 'slug', - 'title', - 'body', - 'createdAt', - 'updatedAt', - 'likes_count', - ], - include: [ - { - model: User, - as: 'author', - attributes: ['first_name', 'last_name'], - }, - ], - }, - ], - }); - return res.status(200).json({ - filteredArticlesByKeyword, - }); - } catch (e) { - return res.status(500).json({ - errors: serverError(), - }); - } - } + }, + attributes: ['keyword'], + }); - if (authorSearchFilter) { - try { - const searchFilter = sequelize.Op; - const filteredArticlesByAuthor = await User.findAll({ - where: { - first_name: { - [searchFilter.iLike]: `%${authorSearchFilter}%`, - }, + const authors = User.findAll({ + where: { + first_name: { + [sequelize.Op.iLike]: `%${searchFilter}%`, }, - attributes: ['first_name', 'last_name'], - include: [ - { - model: Article, - as: 'author', - attributes: [ - 'slug', - 'title', - 'body', - 'createdAt', - 'updatedAt', - 'likes_count', - ], - }, - ], - }); - return res.status(200).json({ - filteredArticlesByAuthor, - }); - } catch (e) { - return res.status(500).json({ - errors: serverError(), - }); - } - } + }, + attributes: ['first_name', 'last_name'], + }); - if (titleSearchFilter) { - try { - const searchFilter = sequelize.Op; - const filteredArticlesByTitle = await Article.findAll({ - where: { - title: { - [searchFilter.iLike]: `%${titleSearchFilter}%`, - }, - }, - attributes: [ - 'slug', - 'title', - 'body', - 'createdAt', - 'updatedAt', - 'likes_count', - ], - include: [ - { - model: User, - as: 'author', - attributes: ['first_name', 'last_name'], - }, - ], - }); - return res.status(200).json({ - filteredArticlesByTitle, - }); - } catch (e) { - return res.status(500).json({ - errors: serverError(), - }); - } - } + const [articleFilter, keywordFilter, authorFilter] = await Promise.all([ + articles, + keywords, + authors, + ]); - if (keywordSearchFilter) { - try { - const searchFilter = sequelize.Op; - const filteredArticlesByKeyword = await Keyword.findAll({ - where: { - keyword: { - [searchFilter.iLike]: `%${keywordSearchFilter}%`, - }, - }, - attributes: ['keyword'], - include: [ - { - model: Article, - as: 'article', - attributes: [ - 'slug', - 'title', - 'body', - 'createdAt', - 'updatedAt', - 'likes_count', - ], - include: [ - { - model: User, - as: 'author', - attributes: ['first_name', 'last_name'], - }, - ], - }, - ], - }); - return res.status(200).json({ - filteredArticlesByKeyword, - }); - } catch (e) { - return res.status(500).json({ - errors: serverError(), - }); - } + return res.status(200).json({ + articleFilter, + keywordFilter, + authorFilter, + }); + } catch (e) { + return res.status(500).json({ + errors: serverError(), + }); } - - return res.status(200).json({ - message: 'No search filter entered', - }); }; const Articles = { searchArticles }; diff --git a/tests/article-search.test.js b/tests/article-search.test.js index 51ffb6a..02f8817 100644 --- a/tests/article-search.test.js +++ b/tests/article-search.test.js @@ -2,15 +2,11 @@ import chai, { expect } from 'chai'; import app from '../server/app'; describe('Article Search', () => { - const authorName = 'a'; - const keyword = 'react'; - const articleTitle = 'Deep'; - it('Display articles by search filters: author, title and keyword', done => { + const searchFilter = 'a'; + it('Display articles by search filter', done => { chai .request(app) - .get( - `/api/v1/search?author=${authorName}&keyword=${keyword}&title=${articleTitle}` - ) + .get(`/api/v1/search?search=${searchFilter}`) .end((err, res) => { const article = res.body; @@ -20,80 +16,15 @@ describe('Article Search', () => { done(); }); }); - it('Display articles by search filters: author and title', done => { + it('Display articles by search filter: no empty query', done => { chai .request(app) - .get(`/api/v1/search?author=${authorName}&title=${articleTitle}`) + .get(`/api/v1/search`) .end((err, res) => { - const articles = res.body; - - expect(res.status).to.equal(200); - expect(articles).to.be.a('object'); - - done(); - }); - }); - it('Display articles by search filters: author and keyword', done => { - chai - .request(app) - .get(`/api/v1/search?author=${authorName}&keyword=${keyword}`) - .end((err, res) => { - const articles = res.body; - - expect(res.status).to.equal(200); - expect(articles).to.be.a('object'); - - done(); - }); - }); - it('Display articles by search filters: keyword and title', done => { - chai - .request(app) - .get(`/api/v1/search?keyword=${keyword}&title=${articleTitle}`) - .end((err, res) => { - const articles = res.body; - - expect(res.status).to.equal(200); - expect(articles).to.be.a('object'); - - done(); - }); - }); - it('Display articles by search filter: author', done => { - chai - .request(app) - .get(`/api/v1/search?author=${authorName}`) - .end((err, res) => { - const articles = res.body; - - expect(res.status).to.equal(200); - expect(articles).to.be.a('object'); - - done(); - }); - }); - it('Display articles by search filter: keyword', done => { - chai - .request(app) - .get(`/api/v1/search?keyword=${keyword}`) - .end((err, res) => { - const articles = res.body; - - expect(res.status).to.equal(200); - expect(articles).to.be.a('object'); - - done(); - }); - }); - it('Display articles by search filter: title', done => { - chai - .request(app) - .get(`/api/v1/search?title=${articleTitle}`) - .end((err, res) => { - const articles = res.body; + const article = res.body; - expect(res.status).to.equal(200); - expect(articles).to.be.a('object'); + expect(res.status).to.equal(400); + expect(article).to.be.a('object'); done(); }); From d050422e51d174bc1f42dea5da9f10558da1640b Mon Sep 17 00:00:00 2001 From: Akinwale Samuel Date: Mon, 15 Apr 2019 10:34:40 +0100 Subject: [PATCH 4/5] 164798028-feature(search): add table indexes to model definition --- server/models/article.js | 113 +++++++++++++++-------------- server/models/keyword.js | 43 ++++++----- server/models/user.js | 149 +++++++++++++++++++++------------------ 3 files changed, 169 insertions(+), 136 deletions(-) diff --git a/server/models/article.js b/server/models/article.js index d7c8b7f..7303efe 100644 --- a/server/models/article.js +++ b/server/models/article.js @@ -1,56 +1,67 @@ module.exports = (sequelize, DataTypes) => { - const Article = sequelize.define('Article', { - id: { - allowNull: false, - primaryKey: true, - type: DataTypes.UUID, - defaultValue: DataTypes.UUIDV4, - unique: true, + const Article = sequelize.define( + 'Article', + { + id: { + allowNull: false, + primaryKey: true, + type: DataTypes.UUID, + defaultValue: DataTypes.UUIDV4, + unique: true, + }, + user_id: { + type: DataTypes.UUID, + allowNull: false, + }, + title: { + type: DataTypes.STRING, + allowNull: false, + }, + slug: { + type: DataTypes.STRING, + unique: true, + }, + abstract: { + type: DataTypes.STRING, + }, + body: { + type: DataTypes.STRING, + }, + category: { + type: DataTypes.STRING, + }, + image_url: { + type: DataTypes.STRING, + }, + bookmark_count: { + type: DataTypes.INTEGER, + defaultValue: 0, + }, + likes_count: { + type: DataTypes.INTEGER, + defaultValue: 0, + }, + is_reported: { + type: DataTypes.BOOLEAN, + defaultValue: false, + }, + is_draft: { + type: DataTypes.BOOLEAN, + defaultValue: false, + }, + reading_time: { + type: DataTypes.INTEGER, + }, }, - user_id: { - type: DataTypes.UUID, - allowNull: false, - }, - title: { - type: DataTypes.STRING, - allowNull: false, - }, - slug: { - type: DataTypes.STRING, - unique: true, - }, - abstract: { - type: DataTypes.STRING, - }, - body: { - type: DataTypes.STRING, - }, - category: { - type: DataTypes.STRING, - }, - image_url: { - type: DataTypes.STRING, - }, - bookmark_count: { - type: DataTypes.INTEGER, - defaultValue: 0, - }, - likes_count: { - type: DataTypes.INTEGER, - defaultValue: 0, - }, - is_reported: { - type: DataTypes.BOOLEAN, - defaultValue: false, - }, - is_draft: { - type: DataTypes.BOOLEAN, - defaultValue: false, - }, - reading_time: { - type: DataTypes.INTEGER, - }, - }); + { + indexes: [ + { + unique: true, + fields: ['title'], + }, + ], + } + ); Article.associate = models => Article.belongsTo(models.User, { foreignKey: 'user_id', diff --git a/server/models/keyword.js b/server/models/keyword.js index dcb8b7a..25c40b9 100644 --- a/server/models/keyword.js +++ b/server/models/keyword.js @@ -1,21 +1,32 @@ module.exports = (sequelize, DataTypes) => { - const Keyword = sequelize.define('Keyword', { - id: { - allowNull: false, - primaryKey: true, - type: DataTypes.UUID, - defaultValue: DataTypes.UUIDV4, - unique: true, + const Keyword = sequelize.define( + 'Keyword', + { + id: { + allowNull: false, + primaryKey: true, + type: DataTypes.UUID, + defaultValue: DataTypes.UUIDV4, + unique: true, + }, + article_id: { + type: DataTypes.UUID, + allowNull: false, + }, + keyword: { + type: DataTypes.STRING, + allowNull: false, + }, }, - article_id: { - type: DataTypes.UUID, - allowNull: false, - }, - keyword: { - type: DataTypes.STRING, - allowNull: false, - }, - }); + { + indexes: [ + { + unique: true, + fields: ['keyword'], + }, + ], + } + ); Keyword.associate = models => Keyword.belongsTo(models.Article, { foreignKey: 'article_id', diff --git a/server/models/user.js b/server/models/user.js index 2abf6ce..615b879 100644 --- a/server/models/user.js +++ b/server/models/user.js @@ -1,78 +1,89 @@ import authHelpers from '../helpers/auth'; module.exports = (sequelize, DataTypes) => { - const User = sequelize.define('User', { - id: { - allowNull: false, - primaryKey: true, - type: DataTypes.UUID, - defaultValue: DataTypes.UUIDV4, - unique: true, - }, - first_name: { - type: DataTypes.STRING, - allowNull: false, - }, - last_name: { - type: DataTypes.STRING, - allowNull: false, - }, - title: { - type: DataTypes.STRING, - }, - phone_number: { - type: DataTypes.STRING, - unique: true, - }, - email: { - type: DataTypes.STRING, - allowNull: false, - unique: true, - }, - bio: { - type: DataTypes.TEXT, - }, - password: { - type: DataTypes.STRING, - allowNull: false, - validate: { - len: { - args: 8, - msg: 'password length must be at least 8 characters long', + const User = sequelize.define( + 'User', + { + id: { + allowNull: false, + primaryKey: true, + type: DataTypes.UUID, + defaultValue: DataTypes.UUIDV4, + unique: true, + }, + first_name: { + type: DataTypes.STRING, + allowNull: false, + }, + last_name: { + type: DataTypes.STRING, + allowNull: false, + }, + title: { + type: DataTypes.STRING, + }, + phone_number: { + type: DataTypes.STRING, + unique: true, + }, + email: { + type: DataTypes.STRING, + allowNull: false, + unique: true, + }, + bio: { + type: DataTypes.TEXT, + }, + password: { + type: DataTypes.STRING, + allowNull: false, + validate: { + len: { + args: 8, + msg: 'password length must be at least 8 characters long', + }, }, }, + is_activated: { + type: DataTypes.BOOLEAN, + defaultValue: false, + }, + image_url: { + type: DataTypes.STRING, + }, + is_admin: { + type: DataTypes.BOOLEAN, + defaultValue: false, + }, + is_reviewer: { + type: DataTypes.BOOLEAN, + defaultValue: false, + }, + is_reported: { + type: DataTypes.BOOLEAN, + defaultValue: false, + }, + is_notified: { + type: DataTypes.BOOLEAN, + defaultValue: true, + }, + research_field: { + type: DataTypes.STRING, + }, + social: { + type: DataTypes.ENUM('facebook', 'twitter', 'google', 'local'), + allowNull: true, + }, }, - is_activated: { - type: DataTypes.BOOLEAN, - defaultValue: false, - }, - image_url: { - type: DataTypes.STRING, - }, - is_admin: { - type: DataTypes.BOOLEAN, - defaultValue: false, - }, - is_reviewer: { - type: DataTypes.BOOLEAN, - defaultValue: false, - }, - is_reported: { - type: DataTypes.BOOLEAN, - defaultValue: false, - }, - is_notified: { - type: DataTypes.BOOLEAN, - defaultValue: true, - }, - research_field: { - type: DataTypes.STRING, - }, - social: { - type: DataTypes.ENUM('facebook', 'twitter', 'google', 'local'), - allowNull: true, - }, - }); + { + indexes: [ + { + unique: true, + fields: ['first_name', 'last_name'], + }, + ], + } + ); User.beforeCreate(user => { user.password = authHelpers.hashPassword(user.password); }); From 91a61f55477591c249b8058396a20b5aee48a73a Mon Sep 17 00:00:00 2001 From: Akinwale Samuel Date: Mon, 15 Apr 2019 12:31:23 +0100 Subject: [PATCH 5/5] 164798028-feature(search): add more test cases --- .../controllers/search-article.controllers.js | 30 +++++++++++++- tests/article-search.test.js | 41 ++++++++++++++++--- 2 files changed, 64 insertions(+), 7 deletions(-) diff --git a/server/controllers/search-article.controllers.js b/server/controllers/search-article.controllers.js index f28903b..0f74bd0 100644 --- a/server/controllers/search-article.controllers.js +++ b/server/controllers/search-article.controllers.js @@ -9,7 +9,7 @@ const searchArticles = async (req, res) => { if (!Object.keys(req.query).length) { return res.status(400).json({ errors: { - body: ['No input provided'], + body: ['No search query provided'], }, }); } @@ -44,6 +44,20 @@ const searchArticles = async (req, res) => { }, }, attributes: ['keyword'], + include: [ + { + model: Article, + as: 'article', + attributes: [ + 'slug', + 'title', + 'body', + 'createdAt', + 'updatedAt', + 'likes_count', + ], + }, + ], }); const authors = User.findAll({ @@ -53,6 +67,20 @@ const searchArticles = async (req, res) => { }, }, attributes: ['first_name', 'last_name'], + include: [ + { + model: Article, + as: 'author', + attributes: [ + 'slug', + 'title', + 'body', + 'createdAt', + 'updatedAt', + 'likes_count', + ], + }, + ], }); const [articleFilter, keywordFilter, authorFilter] = await Promise.all([ diff --git a/tests/article-search.test.js b/tests/article-search.test.js index 02f8817..7842938 100644 --- a/tests/article-search.test.js +++ b/tests/article-search.test.js @@ -2,29 +2,58 @@ import chai, { expect } from 'chai'; import app from '../server/app'; describe('Article Search', () => { - const searchFilter = 'a'; + const articleSearchFilter = 'chemical'; + const authorSearchFilter = 'a'; + const keywordSearchFilter = 'react'; it('Display articles by search filter', done => { chai .request(app) - .get(`/api/v1/search?search=${searchFilter}`) + .get(`/api/v1/search?search=${articleSearchFilter}`) .end((err, res) => { - const article = res.body; + const { articleFilter } = res.body; + expect(res.status).to.equal(200); + expect(articleFilter).to.be.an('array'); + expect(articleFilter[0].title).to.be.equal('Chemical Properties'); + expect(articleFilter[0].author.first_name).to.be.equal('Ameachi'); + done(); + }); + }); + it('Display author by search filter', done => { + chai + .request(app) + .get(`/api/v1/search?search=${authorSearchFilter}`) + .end((err, res) => { + const { authorFilter } = res.body; expect(res.status).to.equal(200); - expect(article).to.be.a('object'); + expect(authorFilter).to.be.an('array'); + expect(authorFilter[0].first_name).to.be.equal('Anayo'); done(); }); }); - it('Display articles by search filter: no empty query', done => { + it('Display keyword by search filter', done => { + chai + .request(app) + .get(`/api/v1/search?search=${keywordSearchFilter}`) + .end((err, res) => { + const { keywordFilter } = res.body; + expect(res.status).to.equal(200); + expect(keywordFilter).to.be.an('array'); + expect(keywordFilter[0].keyword).to.be.equal('react'); + + done(); + }); + }); + it('Display error message if no query string is passed', done => { chai .request(app) .get(`/api/v1/search`) .end((err, res) => { const article = res.body; - expect(res.status).to.equal(400); expect(article).to.be.a('object'); + expect(article.errors.body[0]).to.be.equal('No search query provided'); done(); });