├── .eslintignore ├── .eslintrc ├── .gitignore ├── .npmignore ├── LICENSE ├── README.md ├── index.js ├── package-lock.json ├── package.json ├── src ├── application.js ├── feathers.js ├── helpers.js ├── index.js ├── mixins │ ├── event.js │ ├── index.js │ ├── normalizer.js │ └── promise.js ├── proxy-service.js ├── route.js └── service.js └── yarn.lock /.eslintignore: -------------------------------------------------------------------------------- 1 | node_modules/** 2 | lib/** 3 | test/** 4 | -------------------------------------------------------------------------------- /.eslintrc: -------------------------------------------------------------------------------- 1 | { 2 | "extends": "eslint:recommended", 3 | "parser": "babel-eslint", 4 | "parserOptions": { 5 | "ecmaVersion": 6, 6 | "sourceType": "module", 7 | "ecmaFeatures": { 8 | "impliedStrict": true 9 | } 10 | }, 11 | "rules": { 12 | "semi": ["error", "always"], 13 | "eqeqeq": ["off", "smart"], 14 | "no-console": "off", 15 | "no-unused-vars": "off", 16 | "indent": ["error", 2, { "SwitchCase": 1 }], 17 | "space-before-function-paren": ["error", "always"] 18 | }, 19 | "env": { 20 | "es6": true, 21 | "node": true, 22 | "mocha": true, 23 | "mongo": true 24 | }, 25 | "plugins": [ 26 | "promise" 27 | ] 28 | } -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | # Logs 2 | logs 3 | *.log 4 | 5 | # Runtime data 6 | pids 7 | *.pid 8 | *.seed 9 | 10 | # Directory for instrumented libs generated by jscoverage/JSCover 11 | lib-cov 12 | 13 | # Coverage directory used by tools like istanbul 14 | coverage 15 | 16 | # Grunt intermediate storage (http://gruntjs.com/creating-plugins#storing-task-files) 17 | .grunt 18 | 19 | # Compiled binary addons (http://nodejs.org/api/addons.html) 20 | build/Release 21 | 22 | # Dependency directory 23 | # Commenting this out is preferred by some people, see 24 | # https://www.npmjs.org/doc/misc/npm-faq.html#should-i-check-my-node_modules-folder-into-git- 25 | node_modules 26 | 27 | # Users Environment Variables 28 | .lock-wscript 29 | .DS_store 30 | 31 | # The compiled/babelified modules 32 | lib/ 33 | -------------------------------------------------------------------------------- /.npmignore: -------------------------------------------------------------------------------- 1 | .editorconfig 2 | .travis.yml 3 | .istanbul.yml 4 | .babelrc 5 | .idea/ 6 | .vscode/ 7 | .github/ 8 | coverage/ 9 | test/ 10 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2017 MostlyJS 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | MostlyJS with Feathers 2 | ====================== 3 | 4 | [![Build Status](https://travis-ci.org/mostlyjs/mostly-feathers.svg)](https://travis-ci.org/mostlyjs/mostly-feathers) 5 | 6 | This module provides quick ways to create [MostlyJS](https://github.com/MostlyJS/mostly-node) microservices with [Feathers](https://feathersjs.com/). 7 | 8 | # Documentation 9 | 10 | Please see the [documentation site](https://mostlyjs.github.io). 11 | 12 | # Usage 13 | 14 | ## Installation 15 | 16 | ```bash 17 | npm install mostly-feathers --save 18 | ``` 19 | 20 | ## Quick Example 21 | 22 | Convert your Feathers APIs into microservices is easy enough. 23 | 24 | Your existing Feathers code 25 | ```javascript 26 | // service.js 27 | const memory = require('feathers-memory'); 28 | 29 | module.exports = function() { 30 | const app = this; 31 | 32 | // initialize service 33 | const service = new memory(); 34 | app.use('dummies', service); 35 | } 36 | ``` 37 | 38 | Wrapping it as standalone server 39 | ```javascript 40 | const nats = require('nats'); 41 | const mostly = require('mostly-node'); 42 | const feathers = require('mostly-feathers'); 43 | const service = require('./service'); 44 | 45 | const trans = new mostly(nats.connect()); 46 | trans.ready(() => { 47 | var app = feathers(trans) 48 | .configure(service); 49 | }); 50 | ``` 51 | 52 | That's all, the service will register itself with NATS and can be called remotely. 53 | 54 | ## RESTful Gateway 55 | 56 | To expose the service as RESTful api, you need only setup a simple express gateway server using [mostly-feathers-rest](https://github.com/MostlyJS/mostly-feathers-rest) 57 | 58 | # License 59 | 60 | MIT -------------------------------------------------------------------------------- /index.js: -------------------------------------------------------------------------------- 1 | module.exports = require('./src/index'); -------------------------------------------------------------------------------- /package-lock.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "mostly-feathers", 3 | "version": "1.1.1", 4 | "lockfileVersion": 1, 5 | "requires": true, 6 | "dependencies": { 7 | "@babel/code-frame": { 8 | "version": "7.0.0-beta.44", 9 | "resolved": "http://registry.npm.taobao.org/@babel/code-frame/download/@babel/code-frame-7.0.0-beta.44.tgz", 10 | "integrity": "sha1-KgJkM2jegJFhYr5whlyXd08629k=", 11 | "dev": true, 12 | "requires": { 13 | "@babel/highlight": "7.0.0-beta.44" 14 | } 15 | }, 16 | "@babel/generator": { 17 | "version": "7.0.0-beta.44", 18 | "resolved": "http://registry.npm.taobao.org/@babel/generator/download/@babel/generator-7.0.0-beta.44.tgz", 19 | "integrity": "sha1-x+Z7m1KEr89pswm1DX038+UDPUI=", 20 | "dev": true, 21 | "requires": { 22 | "@babel/types": "7.0.0-beta.44", 23 | "jsesc": "^2.5.1", 24 | "lodash": "^4.2.0", 25 | "source-map": "^0.5.0", 26 | "trim-right": "^1.0.1" 27 | } 28 | }, 29 | "@babel/helper-function-name": { 30 | "version": "7.0.0-beta.44", 31 | "resolved": "http://registry.npm.taobao.org/@babel/helper-function-name/download/@babel/helper-function-name-7.0.0-beta.44.tgz", 32 | "integrity": "sha1-4YVSqq4iMRAKbkheA4VLw1MtRN0=", 33 | "dev": true, 34 | "requires": { 35 | "@babel/helper-get-function-arity": "7.0.0-beta.44", 36 | "@babel/template": "7.0.0-beta.44", 37 | "@babel/types": "7.0.0-beta.44" 38 | } 39 | }, 40 | "@babel/helper-get-function-arity": { 41 | "version": "7.0.0-beta.44", 42 | "resolved": "http://registry.npm.taobao.org/@babel/helper-get-function-arity/download/@babel/helper-get-function-arity-7.0.0-beta.44.tgz", 43 | "integrity": "sha1-0Dym3SufewseazLFbHKDYUDbOhU=", 44 | "dev": true, 45 | "requires": { 46 | "@babel/types": "7.0.0-beta.44" 47 | } 48 | }, 49 | "@babel/helper-split-export-declaration": { 50 | "version": "7.0.0-beta.44", 51 | "resolved": "http://registry.npm.taobao.org/@babel/helper-split-export-declaration/download/@babel/helper-split-export-declaration-7.0.0-beta.44.tgz", 52 | "integrity": "sha1-wLNRc14PvLOCLIrY205YOwXr2dw=", 53 | "dev": true, 54 | "requires": { 55 | "@babel/types": "7.0.0-beta.44" 56 | } 57 | }, 58 | "@babel/highlight": { 59 | "version": "7.0.0-beta.44", 60 | "resolved": "http://registry.npm.taobao.org/@babel/highlight/download/@babel/highlight-7.0.0-beta.44.tgz", 61 | "integrity": "sha1-GMlM5UORaoBVPtzc9oGJCyAHR9U=", 62 | "dev": true, 63 | "requires": { 64 | "chalk": "^2.0.0", 65 | "esutils": "^2.0.2", 66 | "js-tokens": "^3.0.0" 67 | } 68 | }, 69 | "@babel/template": { 70 | "version": "7.0.0-beta.44", 71 | "resolved": "http://registry.npm.taobao.org/@babel/template/download/@babel/template-7.0.0-beta.44.tgz", 72 | "integrity": "sha1-+IMvT9zuXVm/UV5ZX8UQbFKbOU8=", 73 | "dev": true, 74 | "requires": { 75 | "@babel/code-frame": "7.0.0-beta.44", 76 | "@babel/types": "7.0.0-beta.44", 77 | "babylon": "7.0.0-beta.44", 78 | "lodash": "^4.2.0" 79 | } 80 | }, 81 | "@babel/traverse": { 82 | "version": "7.0.0-beta.44", 83 | "resolved": "http://registry.npm.taobao.org/@babel/traverse/download/@babel/traverse-7.0.0-beta.44.tgz", 84 | "integrity": "sha1-qXCixFR3rRgBfi5GWgYG/u4NKWY=", 85 | "dev": true, 86 | "requires": { 87 | "@babel/code-frame": "7.0.0-beta.44", 88 | "@babel/generator": "7.0.0-beta.44", 89 | "@babel/helper-function-name": "7.0.0-beta.44", 90 | "@babel/helper-split-export-declaration": "7.0.0-beta.44", 91 | "@babel/types": "7.0.0-beta.44", 92 | "babylon": "7.0.0-beta.44", 93 | "debug": "^3.1.0", 94 | "globals": "^11.1.0", 95 | "invariant": "^2.2.0", 96 | "lodash": "^4.2.0" 97 | }, 98 | "dependencies": { 99 | "debug": { 100 | "version": "3.1.0", 101 | "resolved": "http://registry.npm.taobao.org/debug/download/debug-3.1.0.tgz", 102 | "integrity": "sha1-W7WgZyYotkFJVmuhaBnmFRjGcmE=", 103 | "dev": true, 104 | "requires": { 105 | "ms": "2.0.0" 106 | } 107 | } 108 | } 109 | }, 110 | "@babel/types": { 111 | "version": "7.0.0-beta.44", 112 | "resolved": "http://registry.npm.taobao.org/@babel/types/download/@babel/types-7.0.0-beta.44.tgz", 113 | "integrity": "sha1-axsWRZH3fewKA0KsqZXy0Eazp1c=", 114 | "dev": true, 115 | "requires": { 116 | "esutils": "^2.0.2", 117 | "lodash": "^4.2.0", 118 | "to-fast-properties": "^2.0.0" 119 | } 120 | }, 121 | "align-text": { 122 | "version": "0.1.4", 123 | "resolved": "https://registry.npmjs.org/align-text/-/align-text-0.1.4.tgz", 124 | "integrity": "sha1-DNkKVhCT810KmSVsIrcGlDP60Rc=", 125 | "dev": true, 126 | "optional": true, 127 | "requires": { 128 | "kind-of": "^3.0.2", 129 | "longest": "^1.0.1", 130 | "repeat-string": "^1.5.2" 131 | }, 132 | "dependencies": { 133 | "kind-of": { 134 | "version": "3.2.2", 135 | "resolved": "http://registry.npm.taobao.org/kind-of/download/kind-of-3.2.2.tgz", 136 | "integrity": "sha1-MeohpzS6ubuw8yRm2JOupR5KPGQ=", 137 | "dev": true, 138 | "optional": true, 139 | "requires": { 140 | "is-buffer": "^1.1.5" 141 | } 142 | } 143 | } 144 | }, 145 | "amdefine": { 146 | "version": "1.0.1", 147 | "resolved": "https://registry.npmjs.org/amdefine/-/amdefine-1.0.1.tgz", 148 | "integrity": "sha1-SlKCrBZHKek2Gbz9OtFR+BfOkfU=", 149 | "dev": true 150 | }, 151 | "ansi-styles": { 152 | "version": "3.2.1", 153 | "resolved": "http://registry.npm.taobao.org/ansi-styles/download/ansi-styles-3.2.1.tgz", 154 | "integrity": "sha1-QfuyAkPlCxK+DwS43tvwdSDOhB0=", 155 | "dev": true, 156 | "requires": { 157 | "color-convert": "^1.9.0" 158 | } 159 | }, 160 | "argparse": { 161 | "version": "1.0.10", 162 | "resolved": "http://registry.npm.taobao.org/argparse/download/argparse-1.0.10.tgz", 163 | "integrity": "sha1-vNZ5HqWuCXJeF+WtmIE0zUCz2RE=", 164 | "dev": true, 165 | "requires": { 166 | "sprintf-js": "~1.0.2" 167 | } 168 | }, 169 | "async": { 170 | "version": "1.5.2", 171 | "resolved": "https://registry.npmjs.org/async/-/async-1.5.2.tgz", 172 | "integrity": "sha1-7GphrlZIDAw8skHJVhjiCJL5Zyo=", 173 | "dev": true 174 | }, 175 | "babel-eslint": { 176 | "version": "8.2.6", 177 | "resolved": "http://registry.npm.taobao.org/babel-eslint/download/babel-eslint-8.2.6.tgz", 178 | "integrity": "sha1-YnDQxzIFYoBnwPeuFpOp55es79k=", 179 | "dev": true, 180 | "requires": { 181 | "@babel/code-frame": "7.0.0-beta.44", 182 | "@babel/traverse": "7.0.0-beta.44", 183 | "@babel/types": "7.0.0-beta.44", 184 | "babylon": "7.0.0-beta.44", 185 | "eslint-scope": "3.7.1", 186 | "eslint-visitor-keys": "^1.0.0" 187 | } 188 | }, 189 | "babylon": { 190 | "version": "7.0.0-beta.44", 191 | "resolved": "http://registry.npm.taobao.org/babylon/download/babylon-7.0.0-beta.44.tgz", 192 | "integrity": "sha1-iRWeFebjDFCW4i1zjYwK+KDoyh0=", 193 | "dev": true 194 | }, 195 | "balanced-match": { 196 | "version": "1.0.0", 197 | "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.0.tgz", 198 | "integrity": "sha1-ibTRmasr7kneFk6gK4nORi1xt2c=", 199 | "dev": true 200 | }, 201 | "brace-expansion": { 202 | "version": "1.1.11", 203 | "resolved": "http://registry.npm.taobao.org/brace-expansion/download/brace-expansion-1.1.11.tgz", 204 | "integrity": "sha1-PH/L9SnYcibz0vUrlm/1Jx60Qd0=", 205 | "dev": true, 206 | "requires": { 207 | "balanced-match": "^1.0.0", 208 | "concat-map": "0.0.1" 209 | } 210 | }, 211 | "browser-stdout": { 212 | "version": "1.3.0", 213 | "resolved": "https://registry.npmjs.org/browser-stdout/-/browser-stdout-1.3.0.tgz", 214 | "integrity": "sha1-81HTKWnTL6XXpVZxVCY9korjvR8=", 215 | "dev": true 216 | }, 217 | "camelcase": { 218 | "version": "1.2.1", 219 | "resolved": "https://registry.npmjs.org/camelcase/-/camelcase-1.2.1.tgz", 220 | "integrity": "sha1-m7UwTS4LVmmLLHWLCKPqqdqlijk=", 221 | "dev": true, 222 | "optional": true 223 | }, 224 | "center-align": { 225 | "version": "0.1.3", 226 | "resolved": "https://registry.npmjs.org/center-align/-/center-align-0.1.3.tgz", 227 | "integrity": "sha1-qg0yYptu6XIgBBHL1EYckHvCt60=", 228 | "dev": true, 229 | "optional": true, 230 | "requires": { 231 | "align-text": "^0.1.3", 232 | "lazy-cache": "^1.0.3" 233 | } 234 | }, 235 | "chalk": { 236 | "version": "2.4.1", 237 | "resolved": "http://registry.npm.taobao.org/chalk/download/chalk-2.4.1.tgz", 238 | "integrity": "sha1-GMSasWoDe26wFSzIPjRxM4IVtm4=", 239 | "dev": true, 240 | "requires": { 241 | "ansi-styles": "^3.2.1", 242 | "escape-string-regexp": "^1.0.5", 243 | "supports-color": "^5.3.0" 244 | } 245 | }, 246 | "cliui": { 247 | "version": "2.1.0", 248 | "resolved": "https://registry.npmjs.org/cliui/-/cliui-2.1.0.tgz", 249 | "integrity": "sha1-S0dXYP+AJkx2LDoXGQMukcf+oNE=", 250 | "dev": true, 251 | "optional": true, 252 | "requires": { 253 | "center-align": "^0.1.1", 254 | "right-align": "^0.1.1", 255 | "wordwrap": "0.0.2" 256 | }, 257 | "dependencies": { 258 | "wordwrap": { 259 | "version": "0.0.2", 260 | "resolved": "https://registry.npmjs.org/wordwrap/-/wordwrap-0.0.2.tgz", 261 | "integrity": "sha1-t5Zpu0LstAn4PVg8rVLKF+qhZD8=", 262 | "dev": true, 263 | "optional": true 264 | } 265 | } 266 | }, 267 | "color-convert": { 268 | "version": "1.9.2", 269 | "resolved": "http://registry.npm.taobao.org/color-convert/download/color-convert-1.9.2.tgz", 270 | "integrity": "sha1-SYgbj7pn3xKpa98/VsCqueeRMUc=", 271 | "dev": true, 272 | "requires": { 273 | "color-name": "1.1.1" 274 | } 275 | }, 276 | "color-name": { 277 | "version": "1.1.1", 278 | "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.1.tgz", 279 | "integrity": "sha1-SxQVMEz1ACjqgWQ2Q72C6gWANok=", 280 | "dev": true 281 | }, 282 | "commander": { 283 | "version": "2.9.0", 284 | "resolved": "https://registry.npmjs.org/commander/-/commander-2.9.0.tgz", 285 | "integrity": "sha1-nJkJQXbhIkDLItbFFGCYQA/g99Q=", 286 | "dev": true, 287 | "requires": { 288 | "graceful-readlink": ">= 1.0.0" 289 | } 290 | }, 291 | "concat-map": { 292 | "version": "0.0.1", 293 | "resolved": "https://registry.npmjs.org/concat-map/-/concat-map-0.0.1.tgz", 294 | "integrity": "sha1-2Klr13/Wjfd5OnMDajug1UBdR3s=", 295 | "dev": true 296 | }, 297 | "debug": { 298 | "version": "2.6.9", 299 | "resolved": "http://registry.npm.taobao.org/debug/download/debug-2.6.9.tgz", 300 | "integrity": "sha1-XRKFFd8TT/Mn6QpMk/Tgd6U2NB8=", 301 | "requires": { 302 | "ms": "2.0.0" 303 | } 304 | }, 305 | "decamelize": { 306 | "version": "1.2.0", 307 | "resolved": "https://registry.npmjs.org/decamelize/-/decamelize-1.2.0.tgz", 308 | "integrity": "sha1-9lNNFRSCabIDUue+4m9QH5oZEpA=", 309 | "dev": true, 310 | "optional": true 311 | }, 312 | "deep-is": { 313 | "version": "0.1.3", 314 | "resolved": "https://registry.npmjs.org/deep-is/-/deep-is-0.1.3.tgz", 315 | "integrity": "sha1-s2nW+128E+7PUk+RsHD+7cNXzzQ=", 316 | "dev": true 317 | }, 318 | "diff": { 319 | "version": "3.2.0", 320 | "resolved": "https://registry.npmjs.org/diff/-/diff-3.2.0.tgz", 321 | "integrity": "sha1-yc45Okt8vQsFinJck98pkCeGj/k=", 322 | "dev": true 323 | }, 324 | "escape-string-regexp": { 325 | "version": "1.0.5", 326 | "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-1.0.5.tgz", 327 | "integrity": "sha1-G2HAViGQqN/2rjuyzwIAyhMLhtQ=", 328 | "dev": true 329 | }, 330 | "escodegen": { 331 | "version": "1.8.1", 332 | "resolved": "https://registry.npmjs.org/escodegen/-/escodegen-1.8.1.tgz", 333 | "integrity": "sha1-WltTr0aTEQvrsIZ6o0MN07cKEBg=", 334 | "dev": true, 335 | "requires": { 336 | "esprima": "^2.7.1", 337 | "estraverse": "^1.9.1", 338 | "esutils": "^2.0.2", 339 | "optionator": "^0.8.1", 340 | "source-map": "~0.2.0" 341 | }, 342 | "dependencies": { 343 | "esprima": { 344 | "version": "2.7.3", 345 | "resolved": "http://registry.npm.taobao.org/esprima/download/esprima-2.7.3.tgz", 346 | "integrity": "sha1-luO3DVd59q1JzQMmc9HDEnZ7pYE=", 347 | "dev": true 348 | }, 349 | "estraverse": { 350 | "version": "1.9.3", 351 | "resolved": "https://registry.npmjs.org/estraverse/-/estraverse-1.9.3.tgz", 352 | "integrity": "sha1-r2fy3JIlgkFZUJJgkaQAXSnJu0Q=", 353 | "dev": true 354 | }, 355 | "source-map": { 356 | "version": "0.2.0", 357 | "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.2.0.tgz", 358 | "integrity": "sha1-2rc/vPwrqBm03gO9b26qSBZLP50=", 359 | "dev": true, 360 | "optional": true, 361 | "requires": { 362 | "amdefine": ">=0.0.4" 363 | } 364 | } 365 | } 366 | }, 367 | "eslint-if-supported": { 368 | "version": "1.0.1", 369 | "resolved": "https://registry.npmjs.org/eslint-if-supported/-/eslint-if-supported-1.0.1.tgz", 370 | "integrity": "sha1-wqZYOxNKLU2Djq417kuLyNN+hW4=", 371 | "dev": true 372 | }, 373 | "eslint-plugin-promise": { 374 | "version": "3.8.0", 375 | "resolved": "http://registry.npm.taobao.org/eslint-plugin-promise/download/eslint-plugin-promise-3.8.0.tgz", 376 | "integrity": "sha1-ZevyeoRePB6db2pWIt3TgBaUtiE=", 377 | "dev": true 378 | }, 379 | "eslint-scope": { 380 | "version": "3.7.1", 381 | "resolved": "https://registry.npmjs.org/eslint-scope/-/eslint-scope-3.7.1.tgz", 382 | "integrity": "sha1-PWPD7f2gLgbgGkUq2IyqzHzctug=", 383 | "dev": true, 384 | "requires": { 385 | "esrecurse": "^4.1.0", 386 | "estraverse": "^4.1.1" 387 | } 388 | }, 389 | "eslint-visitor-keys": { 390 | "version": "1.0.0", 391 | "resolved": "http://registry.npm.taobao.org/eslint-visitor-keys/download/eslint-visitor-keys-1.0.0.tgz", 392 | "integrity": "sha1-PzGA+y4pEBdxastMnW1bXDSmqB0=", 393 | "dev": true 394 | }, 395 | "esprima": { 396 | "version": "4.0.1", 397 | "resolved": "http://registry.npm.taobao.org/esprima/download/esprima-4.0.1.tgz", 398 | "integrity": "sha1-E7BM2z5sXRnfkatph6hpVhmwqnE=", 399 | "dev": true 400 | }, 401 | "esrecurse": { 402 | "version": "4.2.1", 403 | "resolved": "http://registry.npm.taobao.org/esrecurse/download/esrecurse-4.2.1.tgz", 404 | "integrity": "sha1-AHo7n9vCs7uH5IeeoZyS/b05Qs8=", 405 | "dev": true, 406 | "requires": { 407 | "estraverse": "^4.1.0" 408 | } 409 | }, 410 | "estraverse": { 411 | "version": "4.2.0", 412 | "resolved": "https://registry.npmjs.org/estraverse/-/estraverse-4.2.0.tgz", 413 | "integrity": "sha1-De4/7TH81GlhjOc0IJn8GvoL2xM=", 414 | "dev": true 415 | }, 416 | "esutils": { 417 | "version": "2.0.2", 418 | "resolved": "https://registry.npmjs.org/esutils/-/esutils-2.0.2.tgz", 419 | "integrity": "sha1-Cr9PHKpbyx96nYrMbepPqqBLrJs=", 420 | "dev": true 421 | }, 422 | "fast-levenshtein": { 423 | "version": "2.0.6", 424 | "resolved": "https://registry.npmjs.org/fast-levenshtein/-/fast-levenshtein-2.0.6.tgz", 425 | "integrity": "sha1-PYpcZog6FqMMqGQ+hR8Zuqd5eRc=", 426 | "dev": true 427 | }, 428 | "feathers-commons": { 429 | "version": "0.8.7", 430 | "resolved": "https://registry.npmjs.org/feathers-commons/-/feathers-commons-0.8.7.tgz", 431 | "integrity": "sha1-EcbyW1N3RamD6NYVUtfbiTLVN4I=" 432 | }, 433 | "fs.realpath": { 434 | "version": "1.0.0", 435 | "resolved": "https://registry.npmjs.org/fs.realpath/-/fs.realpath-1.0.0.tgz", 436 | "integrity": "sha1-FQStJSMVjKpA20onh8sBQRmU6k8=", 437 | "dev": true 438 | }, 439 | "globals": { 440 | "version": "11.7.0", 441 | "resolved": "http://registry.npm.taobao.org/globals/download/globals-11.7.0.tgz", 442 | "integrity": "sha1-pYP6pDBVsayncZFL9oJY4vwSVnM=", 443 | "dev": true 444 | }, 445 | "graceful-readlink": { 446 | "version": "1.0.1", 447 | "resolved": "https://registry.npmjs.org/graceful-readlink/-/graceful-readlink-1.0.1.tgz", 448 | "integrity": "sha1-TK+tdrxi8C+gObL5Tpo906ORpyU=", 449 | "dev": true 450 | }, 451 | "growl": { 452 | "version": "1.9.2", 453 | "resolved": "https://registry.npmjs.org/growl/-/growl-1.9.2.tgz", 454 | "integrity": "sha1-Dqd0NxXbjY3ixe3hd14bRayFwC8=", 455 | "dev": true 456 | }, 457 | "handlebars": { 458 | "version": "4.0.11", 459 | "resolved": "https://registry.npmjs.org/handlebars/-/handlebars-4.0.11.tgz", 460 | "integrity": "sha1-Ywo13+ApS8KB7a5v/F0yn8eYLcw=", 461 | "dev": true, 462 | "requires": { 463 | "async": "^1.4.0", 464 | "optimist": "^0.6.1", 465 | "source-map": "^0.4.4", 466 | "uglify-js": "^2.6" 467 | }, 468 | "dependencies": { 469 | "source-map": { 470 | "version": "0.4.4", 471 | "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.4.4.tgz", 472 | "integrity": "sha1-66T12pwNyZneaAMti092FzZSA2s=", 473 | "dev": true, 474 | "requires": { 475 | "amdefine": ">=0.0.4" 476 | } 477 | } 478 | } 479 | }, 480 | "has-flag": { 481 | "version": "3.0.0", 482 | "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-3.0.0.tgz", 483 | "integrity": "sha1-tdRU3CGZriJWmfNGfloH87lVuv0=", 484 | "dev": true 485 | }, 486 | "he": { 487 | "version": "1.1.1", 488 | "resolved": "https://registry.npmjs.org/he/-/he-1.1.1.tgz", 489 | "integrity": "sha1-k0EP0hsAlzUVH4howvJx80J+I/0=", 490 | "dev": true 491 | }, 492 | "inflight": { 493 | "version": "1.0.6", 494 | "resolved": "https://registry.npmjs.org/inflight/-/inflight-1.0.6.tgz", 495 | "integrity": "sha1-Sb1jMdfQLQwJvJEKEHW6gWW1bfk=", 496 | "dev": true, 497 | "requires": { 498 | "once": "^1.3.0", 499 | "wrappy": "1" 500 | } 501 | }, 502 | "inherits": { 503 | "version": "2.0.3", 504 | "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.3.tgz", 505 | "integrity": "sha1-Yzwsg+PaQqUC9SRmAiSA9CCCYd4=", 506 | "dev": true 507 | }, 508 | "invariant": { 509 | "version": "2.2.4", 510 | "resolved": "http://registry.npm.taobao.org/invariant/download/invariant-2.2.4.tgz", 511 | "integrity": "sha1-YQ88ksk1nOHbYW5TgAjSP/NRWOY=", 512 | "dev": true, 513 | "requires": { 514 | "loose-envify": "^1.0.0" 515 | } 516 | }, 517 | "is-buffer": { 518 | "version": "1.1.6", 519 | "resolved": "http://registry.npm.taobao.org/is-buffer/download/is-buffer-1.1.6.tgz", 520 | "integrity": "sha1-76ouqdqg16suoTqXsritUf776L4=", 521 | "dev": true, 522 | "optional": true 523 | }, 524 | "isarray": { 525 | "version": "0.0.1", 526 | "resolved": "https://registry.npmjs.org/isarray/-/isarray-0.0.1.tgz", 527 | "integrity": "sha1-ihis/Kmo9Bd+Cav8YDiTmwXR7t8=" 528 | }, 529 | "isexe": { 530 | "version": "2.0.0", 531 | "resolved": "https://registry.npmjs.org/isexe/-/isexe-2.0.0.tgz", 532 | "integrity": "sha1-6PvzdNxVb/iUehDcsFctYz8s+hA=", 533 | "dev": true 534 | }, 535 | "istanbul": { 536 | "version": "0.4.5", 537 | "resolved": "https://registry.npmjs.org/istanbul/-/istanbul-0.4.5.tgz", 538 | "integrity": "sha1-ZcfXPUxNqE1POsMQuRj7C4Azczs=", 539 | "dev": true, 540 | "requires": { 541 | "abbrev": "1.0.x", 542 | "async": "1.x", 543 | "escodegen": "1.8.x", 544 | "esprima": "2.7.x", 545 | "glob": "^5.0.15", 546 | "handlebars": "^4.0.1", 547 | "js-yaml": "3.x", 548 | "mkdirp": "0.5.x", 549 | "nopt": "3.x", 550 | "once": "1.x", 551 | "resolve": "1.1.x", 552 | "supports-color": "^3.1.0", 553 | "which": "^1.1.1", 554 | "wordwrap": "^1.0.0" 555 | }, 556 | "dependencies": { 557 | "abbrev": { 558 | "version": "1.0.9", 559 | "resolved": "http://registry.npm.taobao.org/abbrev/download/abbrev-1.0.9.tgz", 560 | "integrity": "sha1-kbR5JYinc4wl813W9jdSovh3YTU=", 561 | "dev": true 562 | }, 563 | "esprima": { 564 | "version": "2.7.3", 565 | "resolved": "http://registry.npm.taobao.org/esprima/download/esprima-2.7.3.tgz", 566 | "integrity": "sha1-luO3DVd59q1JzQMmc9HDEnZ7pYE=", 567 | "dev": true 568 | }, 569 | "glob": { 570 | "version": "5.0.15", 571 | "resolved": "http://registry.npm.taobao.org/glob/download/glob-5.0.15.tgz", 572 | "integrity": "sha1-G8k2ueAvSmA/zCIuz3Yz0wuLk7E=", 573 | "dev": true, 574 | "requires": { 575 | "inflight": "^1.0.4", 576 | "inherits": "2", 577 | "minimatch": "2 || 3", 578 | "once": "^1.3.0", 579 | "path-is-absolute": "^1.0.0" 580 | } 581 | }, 582 | "has-flag": { 583 | "version": "1.0.0", 584 | "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-1.0.0.tgz", 585 | "integrity": "sha1-nZ55MWXOAXoA8AQYxD+UKnsdEfo=", 586 | "dev": true 587 | }, 588 | "nopt": { 589 | "version": "3.0.6", 590 | "resolved": "http://registry.npm.taobao.org/nopt/download/nopt-3.0.6.tgz", 591 | "integrity": "sha1-xkZdvwirzU2zWTF/eaxopkayj/k=", 592 | "dev": true, 593 | "requires": { 594 | "abbrev": "1" 595 | } 596 | }, 597 | "resolve": { 598 | "version": "1.1.7", 599 | "resolved": "http://registry.npm.taobao.org/resolve/download/resolve-1.1.7.tgz", 600 | "integrity": "sha1-IDEU2CrSxe2ejgQRs5ModeiJ6Xs=", 601 | "dev": true 602 | }, 603 | "supports-color": { 604 | "version": "3.2.3", 605 | "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-3.2.3.tgz", 606 | "integrity": "sha1-ZawFBLOVQXHYpklGsq48u4pfVPY=", 607 | "dev": true, 608 | "requires": { 609 | "has-flag": "^1.0.0" 610 | } 611 | } 612 | } 613 | }, 614 | "js-tokens": { 615 | "version": "3.0.2", 616 | "resolved": "https://registry.npmjs.org/js-tokens/-/js-tokens-3.0.2.tgz", 617 | "integrity": "sha1-mGbfOVECEw449/mWvOtlRDIJwls=", 618 | "dev": true 619 | }, 620 | "js-yaml": { 621 | "version": "3.12.0", 622 | "resolved": "http://registry.npm.taobao.org/js-yaml/download/js-yaml-3.12.0.tgz", 623 | "integrity": "sha1-6u1lbsg0TxD1J8a/obbiJE3hZ9E=", 624 | "dev": true, 625 | "requires": { 626 | "argparse": "^1.0.7", 627 | "esprima": "^4.0.0" 628 | } 629 | }, 630 | "jsesc": { 631 | "version": "2.5.1", 632 | "resolved": "https://registry.npmjs.org/jsesc/-/jsesc-2.5.1.tgz", 633 | "integrity": "sha1-5CGiqOINawgZ3yiQj3glJrlt0f4=", 634 | "dev": true 635 | }, 636 | "json3": { 637 | "version": "3.3.2", 638 | "resolved": "https://registry.npmjs.org/json3/-/json3-3.3.2.tgz", 639 | "integrity": "sha1-PAQ0dD35Pi9cQq7nsZvLSDV19OE=", 640 | "dev": true 641 | }, 642 | "lazy-cache": { 643 | "version": "1.0.4", 644 | "resolved": "https://registry.npmjs.org/lazy-cache/-/lazy-cache-1.0.4.tgz", 645 | "integrity": "sha1-odePw6UEdMuAhF07O24dpJpEbo4=", 646 | "dev": true, 647 | "optional": true 648 | }, 649 | "levn": { 650 | "version": "0.3.0", 651 | "resolved": "https://registry.npmjs.org/levn/-/levn-0.3.0.tgz", 652 | "integrity": "sha1-OwmSTt+fCDwEkP3UwLxEIeBHZO4=", 653 | "dev": true, 654 | "requires": { 655 | "prelude-ls": "~1.1.2", 656 | "type-check": "~0.3.2" 657 | } 658 | }, 659 | "lodash": { 660 | "version": "4.17.10", 661 | "resolved": "http://registry.npm.taobao.org/lodash/download/lodash-4.17.10.tgz", 662 | "integrity": "sha1-G3eTz3JZ6jj7NmHU04syYK+K5Oc=", 663 | "dev": true 664 | }, 665 | "lodash._baseassign": { 666 | "version": "3.2.0", 667 | "resolved": "https://registry.npmjs.org/lodash._baseassign/-/lodash._baseassign-3.2.0.tgz", 668 | "integrity": "sha1-jDigmVAPIVrQnlnxci/QxSv+Ck4=", 669 | "dev": true, 670 | "requires": { 671 | "lodash._basecopy": "^3.0.0", 672 | "lodash.keys": "^3.0.0" 673 | } 674 | }, 675 | "lodash._basecopy": { 676 | "version": "3.0.1", 677 | "resolved": "https://registry.npmjs.org/lodash._basecopy/-/lodash._basecopy-3.0.1.tgz", 678 | "integrity": "sha1-jaDmqHbPNEwK2KVIghEd08XHyjY=", 679 | "dev": true 680 | }, 681 | "lodash._basecreate": { 682 | "version": "3.0.3", 683 | "resolved": "https://registry.npmjs.org/lodash._basecreate/-/lodash._basecreate-3.0.3.tgz", 684 | "integrity": "sha1-G8ZhYU2qf8MRt9A78WgGoCE8+CE=", 685 | "dev": true 686 | }, 687 | "lodash._getnative": { 688 | "version": "3.9.1", 689 | "resolved": "https://registry.npmjs.org/lodash._getnative/-/lodash._getnative-3.9.1.tgz", 690 | "integrity": "sha1-VwvH3t5G1hzc3mh9ZdPuy6o6r/U=", 691 | "dev": true 692 | }, 693 | "lodash._isiterateecall": { 694 | "version": "3.0.9", 695 | "resolved": "https://registry.npmjs.org/lodash._isiterateecall/-/lodash._isiterateecall-3.0.9.tgz", 696 | "integrity": "sha1-UgOte6Ql+uhCRg5pbbnPPmqsBXw=", 697 | "dev": true 698 | }, 699 | "lodash.create": { 700 | "version": "3.1.1", 701 | "resolved": "https://registry.npmjs.org/lodash.create/-/lodash.create-3.1.1.tgz", 702 | "integrity": "sha1-1/KEnw29p+BGgruM1yqwIkYd6+c=", 703 | "dev": true, 704 | "requires": { 705 | "lodash._baseassign": "^3.0.0", 706 | "lodash._basecreate": "^3.0.0", 707 | "lodash._isiterateecall": "^3.0.0" 708 | } 709 | }, 710 | "lodash.isarguments": { 711 | "version": "3.1.0", 712 | "resolved": "https://registry.npmjs.org/lodash.isarguments/-/lodash.isarguments-3.1.0.tgz", 713 | "integrity": "sha1-L1c9hcaiQon/AGY7SRwdM4/zRYo=", 714 | "dev": true 715 | }, 716 | "lodash.isarray": { 717 | "version": "3.0.4", 718 | "resolved": "https://registry.npmjs.org/lodash.isarray/-/lodash.isarray-3.0.4.tgz", 719 | "integrity": "sha1-eeTriMNqgSKvhvhEqpvNhRtfu1U=", 720 | "dev": true 721 | }, 722 | "lodash.keys": { 723 | "version": "3.1.2", 724 | "resolved": "https://registry.npmjs.org/lodash.keys/-/lodash.keys-3.1.2.tgz", 725 | "integrity": "sha1-TbwEcrFWvlCgsoaFXRvQsMZWCYo=", 726 | "dev": true, 727 | "requires": { 728 | "lodash._getnative": "^3.0.0", 729 | "lodash.isarguments": "^3.0.0", 730 | "lodash.isarray": "^3.0.0" 731 | } 732 | }, 733 | "longest": { 734 | "version": "1.0.1", 735 | "resolved": "https://registry.npmjs.org/longest/-/longest-1.0.1.tgz", 736 | "integrity": "sha1-MKCy2jj3N3DoKUoNIuZiXtd9AJc=", 737 | "dev": true, 738 | "optional": true 739 | }, 740 | "loose-envify": { 741 | "version": "1.4.0", 742 | "resolved": "http://registry.npm.taobao.org/loose-envify/download/loose-envify-1.4.0.tgz", 743 | "integrity": "sha1-ce5R+nvkyuwaY4OffmgtgTLTDK8=", 744 | "dev": true, 745 | "requires": { 746 | "js-tokens": "^3.0.0 || ^4.0.0" 747 | } 748 | }, 749 | "minimatch": { 750 | "version": "2.0.10", 751 | "resolved": "http://registry.npm.taobao.org/minimatch/download/minimatch-2.0.10.tgz", 752 | "integrity": "sha1-jQh8OcazjAAbl/ynzm0OHoCvusc=", 753 | "dev": true, 754 | "requires": { 755 | "brace-expansion": "^1.0.0" 756 | } 757 | }, 758 | "mkdirp": { 759 | "version": "0.5.1", 760 | "resolved": "https://registry.npmjs.org/mkdirp/-/mkdirp-0.5.1.tgz", 761 | "integrity": "sha1-MAV0OOrGz3+MR2fzhkjWaX11yQM=", 762 | "dev": true, 763 | "requires": { 764 | "minimist": "0.0.8" 765 | }, 766 | "dependencies": { 767 | "minimist": { 768 | "version": "0.0.8", 769 | "resolved": "https://registry.npmjs.org/minimist/-/minimist-0.0.8.tgz", 770 | "integrity": "sha1-hX/Kv8M5fSYluCKCYuhqp6ARsF0=", 771 | "dev": true 772 | } 773 | } 774 | }, 775 | "mocha": { 776 | "version": "3.5.3", 777 | "resolved": "http://registry.npm.taobao.org/mocha/download/mocha-3.5.3.tgz", 778 | "integrity": "sha1-HgSA/jbS2lhY0etqzDhBiybqog0=", 779 | "dev": true, 780 | "requires": { 781 | "browser-stdout": "1.3.0", 782 | "commander": "2.9.0", 783 | "debug": "2.6.8", 784 | "diff": "3.2.0", 785 | "escape-string-regexp": "1.0.5", 786 | "glob": "7.1.1", 787 | "growl": "1.9.2", 788 | "he": "1.1.1", 789 | "json3": "3.3.2", 790 | "lodash.create": "3.1.1", 791 | "mkdirp": "0.5.1", 792 | "supports-color": "3.1.2" 793 | }, 794 | "dependencies": { 795 | "debug": { 796 | "version": "2.6.8", 797 | "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.8.tgz", 798 | "integrity": "sha1-5zFTHKLt4n0YgiJCfaF4IdaP9Pw=", 799 | "dev": true, 800 | "requires": { 801 | "ms": "2.0.0" 802 | } 803 | }, 804 | "glob": { 805 | "version": "7.1.1", 806 | "resolved": "https://registry.npmjs.org/glob/-/glob-7.1.1.tgz", 807 | "integrity": "sha1-gFIR3wT6rxxjo2ADBs31reULLsg=", 808 | "dev": true, 809 | "requires": { 810 | "fs.realpath": "^1.0.0", 811 | "inflight": "^1.0.4", 812 | "inherits": "2", 813 | "minimatch": "^3.0.2", 814 | "once": "^1.3.0", 815 | "path-is-absolute": "^1.0.0" 816 | } 817 | }, 818 | "has-flag": { 819 | "version": "1.0.0", 820 | "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-1.0.0.tgz", 821 | "integrity": "sha1-nZ55MWXOAXoA8AQYxD+UKnsdEfo=", 822 | "dev": true 823 | }, 824 | "minimatch": { 825 | "version": "3.0.4", 826 | "resolved": "http://registry.npm.taobao.org/minimatch/download/minimatch-3.0.4.tgz", 827 | "integrity": "sha1-UWbihkV/AzBgZL5Ul+jbsMPTIIM=", 828 | "dev": true, 829 | "requires": { 830 | "brace-expansion": "^1.1.7" 831 | } 832 | }, 833 | "supports-color": { 834 | "version": "3.1.2", 835 | "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-3.1.2.tgz", 836 | "integrity": "sha1-cqJiiU2dQIuVbKBf83su2KbiotU=", 837 | "dev": true, 838 | "requires": { 839 | "has-flag": "^1.0.0" 840 | } 841 | } 842 | } 843 | }, 844 | "ms": { 845 | "version": "2.0.0", 846 | "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", 847 | "integrity": "sha1-VgiurfwAvmwpAd9fmGF4jeDVl8g=" 848 | }, 849 | "once": { 850 | "version": "1.3.3", 851 | "resolved": "http://registry.npm.taobao.org/once/download/once-1.3.3.tgz", 852 | "integrity": "sha1-suJhVXzkwxTsgwTz+oJmPkKXyiA=", 853 | "dev": true, 854 | "requires": { 855 | "wrappy": "1" 856 | } 857 | }, 858 | "optimist": { 859 | "version": "0.6.1", 860 | "resolved": "https://registry.npmjs.org/optimist/-/optimist-0.6.1.tgz", 861 | "integrity": "sha1-2j6nRob6IaGaERwybpDrFaAZZoY=", 862 | "dev": true, 863 | "requires": { 864 | "minimist": "~0.0.1", 865 | "wordwrap": "~0.0.2" 866 | }, 867 | "dependencies": { 868 | "minimist": { 869 | "version": "0.0.10", 870 | "resolved": "http://registry.npm.taobao.org/minimist/download/minimist-0.0.10.tgz", 871 | "integrity": "sha1-3j+YVD2/lggr5IrRoMfNqDYwHc8=", 872 | "dev": true 873 | }, 874 | "wordwrap": { 875 | "version": "0.0.3", 876 | "resolved": "https://registry.npmjs.org/wordwrap/-/wordwrap-0.0.3.tgz", 877 | "integrity": "sha1-o9XabNXAvAAI03I0u68b7WMFkQc=", 878 | "dev": true 879 | } 880 | } 881 | }, 882 | "optionator": { 883 | "version": "0.8.2", 884 | "resolved": "https://registry.npmjs.org/optionator/-/optionator-0.8.2.tgz", 885 | "integrity": "sha1-NkxeQJ0/TWMB1sC0wFu6UBgK62Q=", 886 | "dev": true, 887 | "requires": { 888 | "deep-is": "~0.1.3", 889 | "fast-levenshtein": "~2.0.4", 890 | "levn": "~0.3.0", 891 | "prelude-ls": "~1.1.2", 892 | "type-check": "~0.3.2", 893 | "wordwrap": "~1.0.0" 894 | } 895 | }, 896 | "path-is-absolute": { 897 | "version": "1.0.1", 898 | "resolved": "https://registry.npmjs.org/path-is-absolute/-/path-is-absolute-1.0.1.tgz", 899 | "integrity": "sha1-F0uSaHNVNP+8es5r9TpanhtcX18=", 900 | "dev": true 901 | }, 902 | "path-to-regexp": { 903 | "version": "1.7.0", 904 | "resolved": "https://registry.npmjs.org/path-to-regexp/-/path-to-regexp-1.7.0.tgz", 905 | "integrity": "sha1-Wf3g9DW62suhA6hOnTvGTpa5k30=", 906 | "requires": { 907 | "isarray": "0.0.1" 908 | } 909 | }, 910 | "prelude-ls": { 911 | "version": "1.1.2", 912 | "resolved": "https://registry.npmjs.org/prelude-ls/-/prelude-ls-1.1.2.tgz", 913 | "integrity": "sha1-IZMqVJ9eUv/ZqCf1cOBL5iqX2lQ=", 914 | "dev": true 915 | }, 916 | "repeat-string": { 917 | "version": "1.6.1", 918 | "resolved": "https://registry.npmjs.org/repeat-string/-/repeat-string-1.6.1.tgz", 919 | "integrity": "sha1-jcrkcOHIirwtYA//Sndihtp15jc=", 920 | "dev": true, 921 | "optional": true 922 | }, 923 | "right-align": { 924 | "version": "0.1.3", 925 | "resolved": "https://registry.npmjs.org/right-align/-/right-align-0.1.3.tgz", 926 | "integrity": "sha1-YTObci/mo1FWiSENJOFMlhSGE+8=", 927 | "dev": true, 928 | "optional": true, 929 | "requires": { 930 | "align-text": "^0.1.1" 931 | } 932 | }, 933 | "rubberduck": { 934 | "version": "1.1.1", 935 | "resolved": "https://registry.npmjs.org/rubberduck/-/rubberduck-1.1.1.tgz", 936 | "integrity": "sha1-zSzaS4ZxeBNer8mVpxOE9fdD2wI=" 937 | }, 938 | "source-map": { 939 | "version": "0.5.7", 940 | "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.5.7.tgz", 941 | "integrity": "sha1-igOdLRAh0i0eoUyA2OpGi6LvP8w=", 942 | "dev": true 943 | }, 944 | "sprintf-js": { 945 | "version": "1.0.3", 946 | "resolved": "https://registry.npmjs.org/sprintf-js/-/sprintf-js-1.0.3.tgz", 947 | "integrity": "sha1-BOaSb2YolTVPPdAVIDYzuFcpfiw=", 948 | "dev": true 949 | }, 950 | "supports-color": { 951 | "version": "5.4.0", 952 | "resolved": "http://registry.npm.taobao.org/supports-color/download/supports-color-5.4.0.tgz", 953 | "integrity": "sha1-HGszdALCE3YF7+GfEP7DkPb6q1Q=", 954 | "dev": true, 955 | "requires": { 956 | "has-flag": "^3.0.0" 957 | } 958 | }, 959 | "to-fast-properties": { 960 | "version": "2.0.0", 961 | "resolved": "https://registry.npmjs.org/to-fast-properties/-/to-fast-properties-2.0.0.tgz", 962 | "integrity": "sha1-3F5pjL0HkmW8c+A3doGk5Og/YW4=", 963 | "dev": true 964 | }, 965 | "trim-right": { 966 | "version": "1.0.1", 967 | "resolved": "https://registry.npmjs.org/trim-right/-/trim-right-1.0.1.tgz", 968 | "integrity": "sha1-yy4SAwZ+DI3h9hQJS5/kVwTqYAM=", 969 | "dev": true 970 | }, 971 | "type-check": { 972 | "version": "0.3.2", 973 | "resolved": "https://registry.npmjs.org/type-check/-/type-check-0.3.2.tgz", 974 | "integrity": "sha1-WITKtRLPHTVeP7eE8wgEsrUg23I=", 975 | "dev": true, 976 | "requires": { 977 | "prelude-ls": "~1.1.2" 978 | } 979 | }, 980 | "uberproto": { 981 | "version": "1.2.0", 982 | "resolved": "https://registry.npmjs.org/uberproto/-/uberproto-1.2.0.tgz", 983 | "integrity": "sha1-YdTqsCT5CcTm6lK+hnxIlKS+63Y=" 984 | }, 985 | "uglify-js": { 986 | "version": "2.8.29", 987 | "resolved": "https://registry.npmjs.org/uglify-js/-/uglify-js-2.8.29.tgz", 988 | "integrity": "sha1-KcVzMUgFe7Th913zW3qcty5qWd0=", 989 | "dev": true, 990 | "optional": true, 991 | "requires": { 992 | "source-map": "~0.5.1", 993 | "uglify-to-browserify": "~1.0.0", 994 | "yargs": "~3.10.0" 995 | } 996 | }, 997 | "uglify-to-browserify": { 998 | "version": "1.0.2", 999 | "resolved": "https://registry.npmjs.org/uglify-to-browserify/-/uglify-to-browserify-1.0.2.tgz", 1000 | "integrity": "sha1-bgkk1r2mta/jSeOabWMoUKD4grc=", 1001 | "dev": true, 1002 | "optional": true 1003 | }, 1004 | "which": { 1005 | "version": "1.3.1", 1006 | "resolved": "http://registry.npm.taobao.org/which/download/which-1.3.1.tgz", 1007 | "integrity": "sha1-pFBD1U9YBTFtqNYvn1CRjT2nCwo=", 1008 | "dev": true, 1009 | "requires": { 1010 | "isexe": "^2.0.0" 1011 | } 1012 | }, 1013 | "window-size": { 1014 | "version": "0.1.0", 1015 | "resolved": "https://registry.npmjs.org/window-size/-/window-size-0.1.0.tgz", 1016 | "integrity": "sha1-VDjNLqk7IC76Ohn+iIeu58lPnJ0=", 1017 | "dev": true, 1018 | "optional": true 1019 | }, 1020 | "wordwrap": { 1021 | "version": "1.0.0", 1022 | "resolved": "https://registry.npmjs.org/wordwrap/-/wordwrap-1.0.0.tgz", 1023 | "integrity": "sha1-J1hIEIkUVqQXHI0CJkQa3pDLyus=", 1024 | "dev": true 1025 | }, 1026 | "wrappy": { 1027 | "version": "1.0.2", 1028 | "resolved": "https://registry.npmjs.org/wrappy/-/wrappy-1.0.2.tgz", 1029 | "integrity": "sha1-tSQ9jz7BqjXxNkYFvA0QNuMKtp8=", 1030 | "dev": true 1031 | }, 1032 | "yargs": { 1033 | "version": "3.10.0", 1034 | "resolved": "https://registry.npmjs.org/yargs/-/yargs-3.10.0.tgz", 1035 | "integrity": "sha1-9+572FfdfB0tOMDnTvvWgdFDH9E=", 1036 | "dev": true, 1037 | "optional": true, 1038 | "requires": { 1039 | "camelcase": "^1.0.2", 1040 | "cliui": "^2.1.0", 1041 | "decamelize": "^1.0.0", 1042 | "window-size": "0.1.0" 1043 | } 1044 | } 1045 | } 1046 | } 1047 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "mostly-feathers", 3 | "version": "1.1.1", 4 | "description": "MostlyJS microservice integration with feathers", 5 | "author": { 6 | "name": "mostly", 7 | "email": "hello@playingio.com", 8 | "url": "https://mostlyjs.github.com" 9 | }, 10 | "license": "MIT", 11 | "main": "index.js", 12 | "scripts": { 13 | "publish": "git push origin --tags && git push origin", 14 | "release:patch": "npm version patch && npm publish", 15 | "release:minor": "npm version minor && npm publish", 16 | "release:major": "npm version major && npm publish", 17 | "lint": "eslint-if-supported semistandard --fix", 18 | "mocha": "mocha --opts mocha.opts", 19 | "coverage": "istanbul cover node_modules/mocha/bin/_mocha -- --opts mocha.opts", 20 | "test": "npm run lint && npm run coverage" 21 | }, 22 | "homepage": "https://github.com/MostlyJS/mostly-feathers#readme", 23 | "repository": { 24 | "type": "git", 25 | "url": "git+https://github.com/MostlyJS/mostly-feathers.git" 26 | }, 27 | "bugs": { 28 | "url": "https://github.com/MostlyJS/mostly-feathers/issues" 29 | }, 30 | "dependencies": { 31 | "debug": "^2.6.6", 32 | "feathers-commons": "^0.8.7", 33 | "path-to-regexp": "^1.7.0", 34 | "rubberduck": "^1.1.1", 35 | "uberproto": "^1.2.0" 36 | }, 37 | "devDependencies": { 38 | "babel-eslint": "^8.2.2", 39 | "eslint-if-supported": "^1.0.1", 40 | "eslint-plugin-promise": "^3.5.0", 41 | "istanbul": "^0.4.5", 42 | "mocha": "^3.3.0" 43 | } 44 | } 45 | -------------------------------------------------------------------------------- /src/application.js: -------------------------------------------------------------------------------- 1 | const assert = require('assert'); 2 | const makeDebug = require('debug'); 3 | const { stripSlashes } = require('feathers-commons'); 4 | const fp = require('mostly-func'); 5 | const Uberproto = require('uberproto'); 6 | const util = require('util'); 7 | 8 | const route = require('./route'); 9 | const mixins = require('./mixins/index'); 10 | const ProxyService = require('./proxy-service'); 11 | 12 | const debug = makeDebug('mostly:feathers:application'); 13 | const timeDebug = (process.env.DEBUG || '').indexOf('mostly:*') >= 0; 14 | const timeTag = ' Microservices application started'; 15 | 16 | const methods = ['find', 'get', 'create', 'update', 'patch', 'remove']; 17 | 18 | const Proto = Uberproto.extend({ 19 | create: null 20 | }); 21 | 22 | // Adapts an express style handler to uroute 23 | function adapt (fn) { 24 | return function adapter (ctx){ 25 | return Promise.resolve(fn(ctx, ctx.response, ctx.next)).then(x => { 26 | return x === undefined && fn.length < 3? false : x; 27 | }); 28 | }; 29 | } 30 | 31 | // simplified version of `extend` that does not do deep cloning, but does 32 | // accept an optional array of key names to skip as it's first argument. 33 | function extend () { 34 | var args = [].splice.call(arguments, []), except, out = args.shift(); 35 | if (Array.isArray(out)) { 36 | except = out; 37 | out = args.shift(); 38 | } 39 | for (var i=0,src; i fn.call(this, protoService)); 120 | 121 | if (typeof protoService._setup === 'function') { 122 | protoService._setup(this, location); 123 | } 124 | 125 | // Register the service 126 | for (const method of this.methods) { 127 | if (protoService[method]) { 128 | this.trans.add({ 129 | topic: `${this.domain}.${location}`, 130 | cmd: method 131 | }, (req, cb) => { 132 | debug(`service '${protoService.name}.${req.cmd}' called`, { topic: req.topic, cmd: req.cmd }); 133 | debug(`service '${protoService.name}.${req.cmd}' params`, req.params && { query: JSON.stringify(req.params.query) }), 134 | debug(`service '${protoService.name}.${req.cmd}' params`, req.params && { provider: req.params.provider }), 135 | debug(`service '${protoService.name}.${req.cmd}' params`, req.params && { user: req.params.user && req.params.user.id }), 136 | 137 | route.match(this.routes, extend(['host'], 138 | { path: '', feathers: {} }, req, { response: null })); 139 | 140 | // let action = req.params.action; 141 | // if (action) { 142 | // if (!protoService[action] || !fp.isFunction(protoService[action])) { 143 | // return cb(new Error(`No such action \'${action}\' found in service \'${protoService.name}\'`)); 144 | // } 145 | // } else { 146 | // action = req.cmd; 147 | // } 148 | const tag = ` mostly:feathers:application service '${protoService.name}.${req.cmd}' time used`; 149 | if (timeDebug) console.time(tag); 150 | protoService[req.cmd].apply(protoService, [].concat(req.args, req.params)) 151 | .then(data => { 152 | debug(`service '${protoService.name}.${req.cmd}' response`, data && { 153 | size: JSON.stringify(data).length 154 | }); 155 | if (timeDebug) console.timeEnd(tag); 156 | return cb(null, data); 157 | }) 158 | .catch(err => { 159 | debug(`service '${protoService.name}.${req.cmd}' response`, { 160 | error: err 161 | }); 162 | // remove context in errors from feathers to nats 163 | delete err.hook; 164 | delete err.model; 165 | return cb(err); 166 | }); 167 | }); 168 | } 169 | } 170 | 171 | // If we ran setup already, set this service up explicitly 172 | if (this._isSetup && typeof protoService.setup === 'function') { 173 | debug(`Setting up service for \`${location}\``); 174 | protoService.setup(this, location); 175 | } 176 | 177 | return (this.services[location] = protoService); 178 | }, 179 | 180 | use (location) { 181 | let service; 182 | let middleware = Array.from(arguments) 183 | .slice(1) 184 | .reduce(function (middleware, arg) { 185 | if (typeof arg === 'function') { 186 | middleware[service? 'after' : 'before'].push(arg); 187 | } else if (!service) { 188 | service = arg; 189 | } else { 190 | throw new Error('invalid arg passed to app.use'); 191 | } 192 | return middleware; 193 | }, { 194 | before: [], 195 | after: [] 196 | }); 197 | 198 | const hasMethod = methods => methods.some(name => 199 | (service && typeof service[name] === 'function') 200 | ); 201 | 202 | const handler = (path, fn) => { 203 | if (!fn) { 204 | fn = path; 205 | path = undefined; 206 | if (!fn) return; 207 | } 208 | if (fn.routes) { // fn is a sub-app 209 | if (!path) path = '/'; 210 | fn.mountpath = path; 211 | fn.parent = this; 212 | this.routes.children.push(route(path, { __handler: fn }, fn.routes.children)); 213 | fn.emit('mount', this); 214 | } else { 215 | if (!path) path = fn.length >= 3? '*' : '/'; 216 | this.routes.children.push(route(path, { __handler: fn }, adapt(fn))); 217 | } 218 | }; 219 | 220 | // Check for service (any object with at least one service method) 221 | if (hasMethod(['handle', 'set']) || !hasMethod(this.methods.concat('setup'))) { 222 | debug('middleware handler', arguments); 223 | return handler.apply(this, arguments); 224 | } 225 | 226 | // Any arguments left over are other middleware that we want to pass to the providers 227 | this.service(location, service, { middleware }); 228 | 229 | return this; 230 | }, 231 | 232 | setup () { 233 | // Setup each service (pass the app so that they can look up other services etc.) 234 | Object.keys(this.services).forEach(path => { 235 | const service = this.services[path]; 236 | 237 | debug(`Setting up service for \`${path}\``); 238 | if (typeof service.setup === 'function') { 239 | service.setup(this, path); 240 | } 241 | }); 242 | 243 | this._isSetup = true; 244 | 245 | return this; 246 | }, 247 | 248 | configure (fn) { 249 | fn && fn.call(this, this); 250 | return this; 251 | }, 252 | 253 | start () { 254 | this.setup(); 255 | if (timeDebug) { 256 | console.log('\n============ APPLICATION STARTED ============'); 257 | console.timeEnd(timeTag); 258 | console.log('==================================================\n'); 259 | } 260 | return this; 261 | } 262 | }; 263 | -------------------------------------------------------------------------------- /src/feathers.js: -------------------------------------------------------------------------------- 1 | const app = require('./application'); 2 | 3 | /** 4 | * Create a Feathers application. 5 | * 6 | * @return {Function} 7 | * @api public 8 | */ 9 | module.exports = function createApplication (trans, domain) { 10 | app.init(trans, domain); 11 | return app; 12 | }; 13 | -------------------------------------------------------------------------------- /src/helpers.js: -------------------------------------------------------------------------------- 1 | const fp = require('mostly-func'); 2 | 3 | const defaultMethods = ['find', 'get', 'create', 'update', 'patch', 'remove']; 4 | 5 | /** 6 | * check if name is a service method 7 | */ 8 | const isAction = (service, name, params) => { 9 | const action = params && (params.action || (params.query && params.query.$action)) || name; 10 | return (fp.isFunction(service[action]) && defaultMethods.indexOf(action) < 0); 11 | }; 12 | 13 | module.exports = { 14 | defaultMethods, 15 | isAction 16 | }; 17 | -------------------------------------------------------------------------------- /src/index.js: -------------------------------------------------------------------------------- 1 | const feathers = require('./feathers'); 2 | const ProxyService = require('./proxy-service'); 3 | const Service = require('./service'); 4 | const { defaultMethods, isAction } = require('./helpers'); 5 | 6 | const version = require('../package.json').version; 7 | 8 | module.exports = function createApplication (...args) { 9 | return feathers(...args); 10 | }; 11 | 12 | module.exports.ProxyService = ProxyService; 13 | module.exports.Service = Service; 14 | module.exports.version = version; 15 | module.exports.defaultMethods = defaultMethods; 16 | module.exports.isAction = isAction; 17 | -------------------------------------------------------------------------------- /src/mixins/event.js: -------------------------------------------------------------------------------- 1 | const rubberduck = require('rubberduck'); 2 | const { EventEmitter } = require('events'); 3 | const { hooks } = require('feathers-commons'); 4 | 5 | const hookObject = hooks.hookObject; 6 | const eventMappings = { 7 | create: 'created', 8 | update: 'updated', 9 | remove: 'removed', 10 | patch: 'patched' 11 | }; 12 | 13 | function upperCase (name) { 14 | return name.charAt(0).toUpperCase() + name.substring(1); 15 | } 16 | 17 | module.exports = function (service) { 18 | const app = this; 19 | const isEmitter = typeof service.on === 'function' && 20 | typeof service.emit === 'function'; 21 | const emitter = service._rubberDuck = rubberduck.emitter(service); 22 | 23 | if (typeof service.mixin === 'function' && !isEmitter) { 24 | service.mixin(EventEmitter.prototype); 25 | } 26 | 27 | service._serviceEvents = Array.isArray(service.events)? service.events.slice() : []; 28 | 29 | // Pass the Rubberduck error event through 30 | // TODO deal with error events properly 31 | emitter.on('error', function (errors) { 32 | service.emit('serviceError', errors[0]); 33 | }); 34 | 35 | Object.keys(eventMappings).forEach(method => { 36 | const event = eventMappings[method]; 37 | const alreadyEmits = service._serviceEvents.indexOf(event) !== -1; 38 | 39 | if (typeof service[method] === 'function' && !alreadyEmits) { 40 | // The Rubberduck event name (e.g. afterCreate, afterUpdate or afterDestroy) 41 | var eventName = `after${upperCase(method)}`; 42 | service._serviceEvents.push(event); 43 | // Punch the given method 44 | emitter.punch(method, -1); 45 | // Pass the event and error event through 46 | emitter.on(eventName, function (results, args) { 47 | if (!results[0]) { // callback without error 48 | const hook = hookObject(method, 'after', args); 49 | const data = Array.isArray(results[1])? results[1] : [ results[1] ]; 50 | 51 | hook.app = app; 52 | data.forEach(current => service.emit(event, current, hook)); 53 | } else { 54 | service.emit('serviceError', results[0]); 55 | } 56 | }); 57 | } 58 | }); 59 | }; -------------------------------------------------------------------------------- /src/mixins/index.js: -------------------------------------------------------------------------------- 1 | const promise = require('./promise'); 2 | const event = require('./event'); 3 | const normalizer = require('./normalizer'); 4 | 5 | module.exports = function () { 6 | const mixins = [promise, event, normalizer]; 7 | 8 | // Override push to make sure that normalize is always the last 9 | mixins.push = function () { 10 | const args = [this.length - 1, 0].concat(Array.from(arguments)); 11 | this.splice.apply(this, args); 12 | return this.length; 13 | }; 14 | 15 | return mixins; 16 | }; -------------------------------------------------------------------------------- /src/mixins/normalizer.js: -------------------------------------------------------------------------------- 1 | const { getArguments } = require('feathers-commons'); 2 | 3 | module.exports = function (service) { 4 | if (typeof service.mixin === 'function') { 5 | const mixin = {}; 6 | 7 | this.methods.forEach(method => { 8 | if (typeof service[method] === 'function') { 9 | mixin[method] = function () { 10 | return this._super.apply(this, getArguments(method, arguments)); 11 | }; 12 | } 13 | }); 14 | 15 | service.mixin(mixin); 16 | } 17 | }; 18 | -------------------------------------------------------------------------------- /src/mixins/promise.js: -------------------------------------------------------------------------------- 1 | function isPromise (result) { 2 | return typeof result !== 'undefined' && 3 | typeof result.then === 'function'; 4 | } 5 | 6 | function wrapper () { 7 | const result = this._super.apply(this, arguments); 8 | const callback = arguments[arguments.length - 1]; 9 | 10 | if (typeof callback === 'function' && isPromise(result)) { 11 | result.then(data => callback(null, data), error => callback(error)); 12 | } 13 | return result; 14 | } 15 | 16 | module.exports = function (service) { 17 | if (typeof service.mixin === 'function') { 18 | const mixin = {}; 19 | 20 | this.methods.forEach(method => { 21 | if (typeof service[method] === 'function') { 22 | mixin[method] = wrapper; 23 | } 24 | }); 25 | 26 | service.mixin(mixin); 27 | } 28 | }; -------------------------------------------------------------------------------- /src/proxy-service.js: -------------------------------------------------------------------------------- 1 | const makeDebug = require('debug'); 2 | const { stripSlashes } = require('feathers-commons'); 3 | 4 | const debug = makeDebug('mostly:feathers:proxy-service'); 5 | 6 | class ProxyService { 7 | constructor (settings = { id: '_id'}) { 8 | this.id = settings.id || '_id'; 9 | this.name = stripSlashes(settings.name); 10 | this.domain = stripSlashes(settings.domain || 'feathers'); 11 | this.trans = settings.trans; 12 | } 13 | 14 | request (options = {}) { 15 | return new Promise((resolve, reject) => { 16 | let pattern = { 17 | topic: `${this.domain}.${this.name}`, 18 | cmd: options.method, 19 | args: options.args, 20 | params: options.params, 21 | path: '', 22 | feathers: {} 23 | }; 24 | debug(`proxy service '${pattern.topic}.${pattern.cmd}' request`, 25 | { query: JSON.stringify(pattern.params.query) } 26 | ); 27 | this.trans.act(pattern, (err, data) => { 28 | debug(`proxy service '${pattern.topic}.${pattern.cmd}' response`, { 29 | error: err, 30 | size: data? JSON.stringify(data).length : 0 31 | }); 32 | if (err) return reject(err.cause || err); 33 | resolve(data); 34 | }); 35 | }); 36 | } 37 | 38 | find (params = {}) { 39 | return this.request({ 40 | method: 'find', 41 | args: [], 42 | params: params 43 | }); 44 | } 45 | 46 | get (id, params = {}) { 47 | if (typeof id === 'undefined') { 48 | return Promise.reject(new Error(`id for 'get' can not be undefined`)); 49 | } 50 | 51 | return this.request({ 52 | method: 'get', 53 | args: [id], 54 | params: params 55 | }); 56 | } 57 | 58 | create (body, params = {}) { 59 | return this.request({ 60 | method: 'create', 61 | args: [body], 62 | params: params 63 | }); 64 | } 65 | 66 | update (id, body, params = {}) { 67 | if (typeof id === 'undefined') { 68 | return Promise.reject(new Error(`id for 'update' can not be undefined, only 'null' when updating multiple entries`)); 69 | } 70 | 71 | return this.request({ 72 | method: 'update', 73 | args: [id, body], 74 | params: params 75 | }); 76 | } 77 | 78 | patch (id, body, params = {}) { 79 | if (typeof id === 'undefined') { 80 | return Promise.reject(new Error(`id for 'patch' can not be undefined, only 'null' when updating multiple entries`)); 81 | } 82 | 83 | return this.request({ 84 | method: 'patch', 85 | args: [id, body], 86 | params: params 87 | }); 88 | } 89 | 90 | remove (id, params = {}) { 91 | if (typeof id === 'undefined') { 92 | return Promise.reject(new Error(`id for 'remove' can not be undefined, only 'null' when removing multiple entries`)); 93 | } 94 | 95 | return this.request({ 96 | method: 'remove', 97 | args: [id], 98 | params: params 99 | }); 100 | } 101 | 102 | /** 103 | * proxy to action method 104 | * syntax sugar for calling from other services 105 | */ 106 | action (action) { 107 | return { 108 | find: (params = {}) => { 109 | params.action = action; 110 | return this.find(params); 111 | }, 112 | 113 | get: (id, params = {}) => { 114 | params.action = action; 115 | return this.get(id, params); 116 | }, 117 | 118 | create: (data, params = {}) => { 119 | params.action = action; 120 | return this.create(data, params); 121 | }, 122 | 123 | update: (id, data, params = {}) => { 124 | params.action = action; 125 | return this.update(id, data, params); 126 | }, 127 | 128 | patch: (id, data, params = {}) => { 129 | params.action = action; 130 | return this.patch(id, data, params); 131 | }, 132 | 133 | remove: (id, params = {}) => { 134 | params.action = action; 135 | return this.remove(id, params); 136 | } 137 | }; 138 | } 139 | } 140 | 141 | module.exports = ProxyService; -------------------------------------------------------------------------------- /src/route.js: -------------------------------------------------------------------------------- 1 | const makeDebug = require('debug'); 2 | const pathToRegExp = require('path-to-regexp'); 3 | 4 | const debug = makeDebug('mostly:feathers:route'); 5 | 6 | function route () { 7 | var args = Array.prototype.slice.call(arguments), 8 | next = args.shift(), 9 | path, ctx = {}, action, children; 10 | 11 | if (typeof next == 'string' || next instanceof String) { 12 | path = next.toString(); 13 | next = args.shift(); 14 | } 15 | if (typeof next == 'object' && (!Array.isArray(next))) { 16 | ctx = next; 17 | next = args.shift(); 18 | } 19 | if (typeof next == 'function') { 20 | action = next; 21 | next = args.shift(); 22 | } 23 | if (typeof next == 'object' && (Array.isArray(next))) { 24 | children = next; 25 | next = null; 26 | } else if (next) { 27 | children = [next]; 28 | } 29 | if (args.length) { 30 | children = (children || []).concat(args); 31 | } 32 | var result = path? extend({}, ctx, { path }) : extend({}, ctx); 33 | if (!result.path) { 34 | result.path = '/'; 35 | } 36 | if (typeof action == 'function') { 37 | result.action = action; 38 | } else if (children) { 39 | result.action = function next (ctx) { 40 | return ctx.next(); 41 | }; 42 | } 43 | if (typeof children == 'object') { 44 | result.children = children; 45 | } 46 | return result; 47 | } 48 | 49 | function match (routes, ctx) { 50 | debug('match', ctx.path); 51 | var context = typeof ctx === 'string' || ctx instanceof String? { path: ctx } : ctx; 52 | var root = Array.isArray(routes)? { path: '/', children: routes } : routes; 53 | var errorRoute = root.children && root.children.filter(x => x.path === '/error')[0]; 54 | var match = matchRoute(root, '', context.path); 55 | var result, value, done = false; 56 | 57 | context.next = function () { 58 | var promise = Promise.resolve(); 59 | var next = match.next(); 60 | value = next.value; 61 | done = next.done; 62 | if (!done && value && value.route.action) { 63 | var newCtx = extend({}, context, next.value); 64 | try { 65 | promise = Promise.resolve(value.route.action(newCtx, newCtx.params)); 66 | } catch(err) { 67 | promise = Promise.reject(err); 68 | } 69 | if (errorRoute) { 70 | promise = promise.catch(err => { 71 | err.status = err.status || 500; 72 | newCtx.error = err; 73 | return errorRoute.action(newCtx, newCtx.params); 74 | }); 75 | } 76 | } 77 | return promise; 78 | }; 79 | 80 | context.end = function (data) { 81 | result = data; 82 | done = true; 83 | }; 84 | 85 | function run () { 86 | return context.next().then(function (r){ 87 | if (r !== undefined) { 88 | result = r; 89 | done = true; 90 | } 91 | if (done) return result; 92 | return run(); 93 | }); 94 | } 95 | 96 | return run().then(function (r){ 97 | if (r === undefined && errorRoute) { 98 | context.error = new Error('Not found'); 99 | context.error.status = 404; 100 | return errorRoute.action(context, {}); 101 | } 102 | return r; 103 | }); 104 | } 105 | 106 | 107 | function matchRoute (route, baseUrl, path) { 108 | var match, childMatches, childIdx = 0; 109 | // simulate a generator function by returning an object with a `next` method 110 | return { 111 | next: function (){ 112 | if (!route.children) { 113 | if (! match) { 114 | match = matchPath(true, route.path, path); 115 | if (match) { 116 | return { 117 | done: false, 118 | value: { 119 | route:route, 120 | baseUrl:baseUrl, 121 | path: match.path, 122 | params: match.params 123 | } 124 | }; 125 | } 126 | } 127 | return { done: true, value: undefined }; 128 | } 129 | 130 | if (route.children) { 131 | if (!match) { 132 | match = matchPath(false, route.path, path); 133 | if (match) { 134 | return { 135 | done: false, 136 | value: { 137 | route:route, 138 | baseUrl:baseUrl, 139 | path: match.path, 140 | params: match.params, 141 | } 142 | }; 143 | } 144 | } 145 | while (childIdx < route.children.length) { 146 | if (!childMatches) { 147 | var childRoute = route.children[childIdx]; 148 | var newPath = path.substr(match.path.length); 149 | childMatches = matchRoute(childRoute, 150 | baseUrl + (match.path === '/'? '' : match.path), 151 | newPath.indexOf('/') === 0? newPath : '/' + newPath 152 | ); 153 | } 154 | var childMatch = childMatches.next(); 155 | if (childMatch.done) { 156 | childIdx++; 157 | childMatches = null; 158 | } 159 | else { 160 | return { 161 | done: false, 162 | value: childMatch.value 163 | }; 164 | } 165 | } 166 | return { done: true, value: undefined }; 167 | } 168 | } 169 | }; 170 | } 171 | 172 | var cache = {}; 173 | 174 | function matchPath (end, routePath, urlPath) { 175 | var key = routePath + '|' + end; 176 | var regexp = cache[key]; 177 | if (!regexp) { 178 | var keys = []; 179 | regexp = { pattern: pathToRegExp(routePath, keys, { end:end }), keys:keys }; 180 | cache[key] = regexp; 181 | } 182 | var m = regexp.pattern.exec(urlPath); 183 | if (!m) return null; 184 | var params = {}, path = m.shift(); 185 | for (var i = 0; i < m.length; i++) { 186 | params[regexp.keys[i].name] = m[i] !== undefined? decode(m[i]) : undefined; 187 | } 188 | return { path: path === ''? '/' : path, params:params }; 189 | } 190 | 191 | function decode (val) { 192 | return typeof val !== 'string'? val : decodeURIComponent(val); 193 | } 194 | 195 | function extend (out) { 196 | for (var src, i=1; i this.create(current, params), data)); 45 | } 46 | 47 | debug('service %s create %j', this.name, data); 48 | return this._create(data, params); 49 | } 50 | 51 | update (id, data, params) { 52 | params = { query: {}, ...params }; 53 | 54 | if (this._isAction(id, params)) { 55 | return this._action('update', id, data, params); 56 | } 57 | debug('service %s update %j', this.name, id, data); 58 | return this._update(id, data, params); 59 | } 60 | 61 | patch (id, data, params) { 62 | params = { query: {}, ...params }; 63 | 64 | if (this._isAction(id, params)) { 65 | return this._action('patch', id, data, params); 66 | } 67 | debug('service %s patch %j', this.name, id, data); 68 | return this._patch(id, data, params); 69 | } 70 | 71 | remove (id, params) { 72 | params = { query: {}, ...params }; 73 | 74 | if (this._isAction(id, params)) { 75 | return this._action('remove', id, null, params); 76 | } 77 | debug('service %s remove %j', this.name, id); 78 | return this._remove(id, params); 79 | } 80 | 81 | /** 82 | * proxy to action method 83 | * syntax sugar for calling from other services, do not call them by super 84 | */ 85 | action (action) { 86 | assert(action, 'action is not provided'); 87 | return { 88 | get: async (params = {}) => { 89 | params.action = action; 90 | return this.get(null, params); 91 | }, 92 | 93 | create: async (data, params = {}) => { 94 | params.action = action; 95 | return this.patch(null, data, params); 96 | }, 97 | 98 | update: async (id, data, params = {}) => { 99 | params.action = action; 100 | return this.update(id, data, params); 101 | }, 102 | 103 | patch: async (id, data, params = {}) => { 104 | params.action = action; 105 | return this.patch(id, data, params); 106 | }, 107 | 108 | remove: async (id, params = {}) => { 109 | params.action = action; 110 | return this.remove(id, params); 111 | } 112 | }; 113 | } 114 | 115 | /** 116 | * check if name is a service method 117 | */ 118 | _isAction (id, params) { 119 | return isAction(this, id, params); 120 | } 121 | 122 | /** 123 | * Proxy to a action service 124 | */ 125 | async _action (method, id, data, params) { 126 | const action = params && (params.action || (params.query && params.query.$action)) || id; 127 | assert(action, 'action is not provided'); 128 | 129 | if (!fp.isFunction(this[action]) || defaultMethods.indexOf(action) >= 0) { 130 | throw new Error(`Not implemented **${method}** action: ${action}`); 131 | } 132 | params = fp.dissoc('action', fp.dissocPath(['query', '$action'], params)); 133 | debug('service %s %s action %s id %j => %j', this.name, method, action, id, data); 134 | 135 | switch (method) { 136 | case 'get': return this[action].call(this, params); 137 | case 'create': return this[action].call(this, null, data, params); 138 | case 'update': return this[action].call(this, id, data, params); 139 | case 'patch': return this[action].call(this, id, data, params); 140 | case 'remove': return this[action].call(this, id, params); 141 | default: throw new Error(`Invalid method ${method}`); 142 | } 143 | } 144 | 145 | _find (params) { throw new Error('Not implemented'); } 146 | _get (id, params) { throw new Error('Not implemented'); } 147 | _create (data, params) { throw new Error('Not implemented'); } 148 | _update (id, data, params) { throw new Error('Not implemented'); } 149 | _patch (id, data, params) { throw new Error('Not implemented'); } 150 | _remove (id, params) { throw new Error('Not implemented'); } 151 | } 152 | 153 | module.exports = Service; -------------------------------------------------------------------------------- /yarn.lock: -------------------------------------------------------------------------------- 1 | # THIS IS AN AUTOGENERATED FILE. DO NOT EDIT THIS FILE DIRECTLY. 2 | # yarn lockfile v1 3 | 4 | 5 | "@babel/code-frame@7.0.0-beta.44": 6 | version "7.0.0-beta.44" 7 | resolved "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.0.0-beta.44.tgz#2a02643368de80916162be70865c97774f3adbd9" 8 | dependencies: 9 | "@babel/highlight" "7.0.0-beta.44" 10 | 11 | "@babel/generator@7.0.0-beta.44": 12 | version "7.0.0-beta.44" 13 | resolved "https://registry.npmjs.org/@babel/generator/-/generator-7.0.0-beta.44.tgz#c7e67b9b5284afcf69b309b50d7d37f3e5033d42" 14 | dependencies: 15 | "@babel/types" "7.0.0-beta.44" 16 | jsesc "^2.5.1" 17 | lodash "^4.2.0" 18 | source-map "^0.5.0" 19 | trim-right "^1.0.1" 20 | 21 | "@babel/helper-function-name@7.0.0-beta.44": 22 | version "7.0.0-beta.44" 23 | resolved "https://registry.npmjs.org/@babel/helper-function-name/-/helper-function-name-7.0.0-beta.44.tgz#e18552aaae2231100a6e485e03854bc3532d44dd" 24 | dependencies: 25 | "@babel/helper-get-function-arity" "7.0.0-beta.44" 26 | "@babel/template" "7.0.0-beta.44" 27 | "@babel/types" "7.0.0-beta.44" 28 | 29 | "@babel/helper-get-function-arity@7.0.0-beta.44": 30 | version "7.0.0-beta.44" 31 | resolved "https://registry.npmjs.org/@babel/helper-get-function-arity/-/helper-get-function-arity-7.0.0-beta.44.tgz#d03ca6dd2b9f7b0b1e6b32c56c72836140db3a15" 32 | dependencies: 33 | "@babel/types" "7.0.0-beta.44" 34 | 35 | "@babel/helper-split-export-declaration@7.0.0-beta.44": 36 | version "7.0.0-beta.44" 37 | resolved "https://registry.npmjs.org/@babel/helper-split-export-declaration/-/helper-split-export-declaration-7.0.0-beta.44.tgz#c0b351735e0fbcb3822c8ad8db4e583b05ebd9dc" 38 | dependencies: 39 | "@babel/types" "7.0.0-beta.44" 40 | 41 | "@babel/highlight@7.0.0-beta.44": 42 | version "7.0.0-beta.44" 43 | resolved "https://registry.npmjs.org/@babel/highlight/-/highlight-7.0.0-beta.44.tgz#18c94ce543916a80553edcdcf681890b200747d5" 44 | dependencies: 45 | chalk "^2.0.0" 46 | esutils "^2.0.2" 47 | js-tokens "^3.0.0" 48 | 49 | "@babel/template@7.0.0-beta.44": 50 | version "7.0.0-beta.44" 51 | resolved "https://registry.npmjs.org/@babel/template/-/template-7.0.0-beta.44.tgz#f8832f4fdcee5d59bf515e595fc5106c529b394f" 52 | dependencies: 53 | "@babel/code-frame" "7.0.0-beta.44" 54 | "@babel/types" "7.0.0-beta.44" 55 | babylon "7.0.0-beta.44" 56 | lodash "^4.2.0" 57 | 58 | "@babel/traverse@7.0.0-beta.44": 59 | version "7.0.0-beta.44" 60 | resolved "https://registry.npmjs.org/@babel/traverse/-/traverse-7.0.0-beta.44.tgz#a970a2c45477ad18017e2e465a0606feee0d2966" 61 | dependencies: 62 | "@babel/code-frame" "7.0.0-beta.44" 63 | "@babel/generator" "7.0.0-beta.44" 64 | "@babel/helper-function-name" "7.0.0-beta.44" 65 | "@babel/helper-split-export-declaration" "7.0.0-beta.44" 66 | "@babel/types" "7.0.0-beta.44" 67 | babylon "7.0.0-beta.44" 68 | debug "^3.1.0" 69 | globals "^11.1.0" 70 | invariant "^2.2.0" 71 | lodash "^4.2.0" 72 | 73 | "@babel/types@7.0.0-beta.44": 74 | version "7.0.0-beta.44" 75 | resolved "https://registry.npmjs.org/@babel/types/-/types-7.0.0-beta.44.tgz#6b1b164591f77dec0a0342aca995f2d046b3a757" 76 | dependencies: 77 | esutils "^2.0.2" 78 | lodash "^4.2.0" 79 | to-fast-properties "^2.0.0" 80 | 81 | abbrev@1: 82 | version "1.1.1" 83 | resolved "https://registry.npmjs.org/abbrev/-/abbrev-1.1.1.tgz#f8f2c887ad10bf67f634f005b6987fed3179aac8" 84 | 85 | abbrev@1.0.x: 86 | version "1.0.9" 87 | resolved "https://registry.npmjs.org/abbrev/-/abbrev-1.0.9.tgz#91b4792588a7738c25f35dd6f63752a2f8776135" 88 | 89 | align-text@^0.1.1, align-text@^0.1.3: 90 | version "0.1.4" 91 | resolved "https://registry.npmjs.org/align-text/-/align-text-0.1.4.tgz#0cd90a561093f35d0a99256c22b7069433fad117" 92 | dependencies: 93 | kind-of "^3.0.2" 94 | longest "^1.0.1" 95 | repeat-string "^1.5.2" 96 | 97 | amdefine@>=0.0.4: 98 | version "1.0.1" 99 | resolved "https://registry.npmjs.org/amdefine/-/amdefine-1.0.1.tgz#4a5282ac164729e93619bcfd3ad151f817ce91f5" 100 | 101 | ansi-styles@^3.2.1: 102 | version "3.2.1" 103 | resolved "https://registry.npmjs.org/ansi-styles/-/ansi-styles-3.2.1.tgz#41fbb20243e50b12be0f04b8dedbf07520ce841d" 104 | dependencies: 105 | color-convert "^1.9.0" 106 | 107 | argparse@^1.0.7: 108 | version "1.0.10" 109 | resolved "https://registry.npmjs.org/argparse/-/argparse-1.0.10.tgz#bcd6791ea5ae09725e17e5ad988134cd40b3d911" 110 | dependencies: 111 | sprintf-js "~1.0.2" 112 | 113 | async@1.x, async@^1.4.0: 114 | version "1.5.2" 115 | resolved "https://registry.npmjs.org/async/-/async-1.5.2.tgz#ec6a61ae56480c0c3cb241c95618e20892f9672a" 116 | 117 | babel-eslint@^8.2.2: 118 | version "8.2.6" 119 | resolved "https://registry.npmjs.org/babel-eslint/-/babel-eslint-8.2.6.tgz#6270d0c73205628067c0f7ae1693a9e797acefd9" 120 | dependencies: 121 | "@babel/code-frame" "7.0.0-beta.44" 122 | "@babel/traverse" "7.0.0-beta.44" 123 | "@babel/types" "7.0.0-beta.44" 124 | babylon "7.0.0-beta.44" 125 | eslint-scope "3.7.1" 126 | eslint-visitor-keys "^1.0.0" 127 | 128 | babylon@7.0.0-beta.44: 129 | version "7.0.0-beta.44" 130 | resolved "https://registry.npmjs.org/babylon/-/babylon-7.0.0-beta.44.tgz#89159e15e6e30c5096e22d738d8c0af8a0e8ca1d" 131 | 132 | balanced-match@^1.0.0: 133 | version "1.0.0" 134 | resolved "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.0.tgz#89b4d199ab2bee49de164ea02b89ce462d71b767" 135 | 136 | brace-expansion@^1.1.7: 137 | version "1.1.11" 138 | resolved "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz#3c7fcbf529d87226f3d2f52b966ff5271eb441dd" 139 | dependencies: 140 | balanced-match "^1.0.0" 141 | concat-map "0.0.1" 142 | 143 | browser-stdout@1.3.0: 144 | version "1.3.0" 145 | resolved "https://registry.npmjs.org/browser-stdout/-/browser-stdout-1.3.0.tgz#f351d32969d32fa5d7a5567154263d928ae3bd1f" 146 | 147 | camelcase@^1.0.2: 148 | version "1.2.1" 149 | resolved "https://registry.npmjs.org/camelcase/-/camelcase-1.2.1.tgz#9bb5304d2e0b56698b2c758b08a3eaa9daa58a39" 150 | 151 | center-align@^0.1.1: 152 | version "0.1.3" 153 | resolved "https://registry.npmjs.org/center-align/-/center-align-0.1.3.tgz#aa0d32629b6ee972200411cbd4461c907bc2b7ad" 154 | dependencies: 155 | align-text "^0.1.3" 156 | lazy-cache "^1.0.3" 157 | 158 | chalk@^2.0.0: 159 | version "2.4.1" 160 | resolved "https://registry.npmjs.org/chalk/-/chalk-2.4.1.tgz#18c49ab16a037b6eb0152cc83e3471338215b66e" 161 | dependencies: 162 | ansi-styles "^3.2.1" 163 | escape-string-regexp "^1.0.5" 164 | supports-color "^5.3.0" 165 | 166 | cliui@^2.1.0: 167 | version "2.1.0" 168 | resolved "https://registry.npmjs.org/cliui/-/cliui-2.1.0.tgz#4b475760ff80264c762c3a1719032e91c7fea0d1" 169 | dependencies: 170 | center-align "^0.1.1" 171 | right-align "^0.1.1" 172 | wordwrap "0.0.2" 173 | 174 | color-convert@^1.9.0: 175 | version "1.9.2" 176 | resolved "https://registry.npmjs.org/color-convert/-/color-convert-1.9.2.tgz#49881b8fba67df12a96bdf3f56c0aab9e7913147" 177 | dependencies: 178 | color-name "1.1.1" 179 | 180 | color-name@1.1.1: 181 | version "1.1.1" 182 | resolved "https://registry.npmjs.org/color-name/-/color-name-1.1.1.tgz#4b1415304cf50028ea81643643bd82ea05803689" 183 | 184 | commander@2.9.0: 185 | version "2.9.0" 186 | resolved "https://registry.npmjs.org/commander/-/commander-2.9.0.tgz#9c99094176e12240cb22d6c5146098400fe0f7d4" 187 | dependencies: 188 | graceful-readlink ">= 1.0.0" 189 | 190 | concat-map@0.0.1: 191 | version "0.0.1" 192 | resolved "https://registry.npmjs.org/concat-map/-/concat-map-0.0.1.tgz#d8a96bd77fd68df7793a73036a3ba0d5405d477b" 193 | 194 | debug@2.6.8: 195 | version "2.6.8" 196 | resolved "https://registry.npmjs.org/debug/-/debug-2.6.8.tgz#e731531ca2ede27d188222427da17821d68ff4fc" 197 | dependencies: 198 | ms "2.0.0" 199 | 200 | debug@^2.6.6: 201 | version "2.6.9" 202 | resolved "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz#5d128515df134ff327e90a4c93f4e077a536341f" 203 | dependencies: 204 | ms "2.0.0" 205 | 206 | debug@^3.1.0: 207 | version "3.1.0" 208 | resolved "https://registry.npmjs.org/debug/-/debug-3.1.0.tgz#5bb5a0672628b64149566ba16819e61518c67261" 209 | dependencies: 210 | ms "2.0.0" 211 | 212 | decamelize@^1.0.0: 213 | version "1.2.0" 214 | resolved "https://registry.npmjs.org/decamelize/-/decamelize-1.2.0.tgz#f6534d15148269b20352e7bee26f501f9a191290" 215 | 216 | deep-is@~0.1.3: 217 | version "0.1.3" 218 | resolved "https://registry.npmjs.org/deep-is/-/deep-is-0.1.3.tgz#b369d6fb5dbc13eecf524f91b070feedc357cf34" 219 | 220 | diff@3.2.0: 221 | version "3.2.0" 222 | resolved "https://registry.npmjs.org/diff/-/diff-3.2.0.tgz#c9ce393a4b7cbd0b058a725c93df299027868ff9" 223 | 224 | escape-string-regexp@1.0.5, escape-string-regexp@^1.0.5: 225 | version "1.0.5" 226 | resolved "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-1.0.5.tgz#1b61c0562190a8dff6ae3bb2cf0200ca130b86d4" 227 | 228 | escodegen@1.8.x: 229 | version "1.8.1" 230 | resolved "https://registry.npmjs.org/escodegen/-/escodegen-1.8.1.tgz#5a5b53af4693110bebb0867aa3430dd3b70a1018" 231 | dependencies: 232 | esprima "^2.7.1" 233 | estraverse "^1.9.1" 234 | esutils "^2.0.2" 235 | optionator "^0.8.1" 236 | optionalDependencies: 237 | source-map "~0.2.0" 238 | 239 | eslint-if-supported@^1.0.1: 240 | version "1.0.1" 241 | resolved "https://registry.npmjs.org/eslint-if-supported/-/eslint-if-supported-1.0.1.tgz#c2a6583b134a2d4d838eae35ee4b8bc8d37e856e" 242 | 243 | eslint-plugin-promise@^3.5.0: 244 | version "3.8.0" 245 | resolved "https://registry.npmjs.org/eslint-plugin-promise/-/eslint-plugin-promise-3.8.0.tgz#65ebf27a845e3c1e9d6f6a5622ddd3801694b621" 246 | 247 | eslint-scope@3.7.1: 248 | version "3.7.1" 249 | resolved "https://registry.npmjs.org/eslint-scope/-/eslint-scope-3.7.1.tgz#3d63c3edfda02e06e01a452ad88caacc7cdcb6e8" 250 | dependencies: 251 | esrecurse "^4.1.0" 252 | estraverse "^4.1.1" 253 | 254 | eslint-visitor-keys@^1.0.0: 255 | version "1.0.0" 256 | resolved "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-1.0.0.tgz#3f3180fb2e291017716acb4c9d6d5b5c34a6a81d" 257 | 258 | esprima@2.7.x, esprima@^2.7.1: 259 | version "2.7.3" 260 | resolved "https://registry.npmjs.org/esprima/-/esprima-2.7.3.tgz#96e3b70d5779f6ad49cd032673d1c312767ba581" 261 | 262 | esprima@^4.0.0: 263 | version "4.0.1" 264 | resolved "https://registry.npmjs.org/esprima/-/esprima-4.0.1.tgz#13b04cdb3e6c5d19df91ab6987a8695619b0aa71" 265 | 266 | esrecurse@^4.1.0: 267 | version "4.2.1" 268 | resolved "https://registry.npmjs.org/esrecurse/-/esrecurse-4.2.1.tgz#007a3b9fdbc2b3bb87e4879ea19c92fdbd3942cf" 269 | dependencies: 270 | estraverse "^4.1.0" 271 | 272 | estraverse@^1.9.1: 273 | version "1.9.3" 274 | resolved "https://registry.npmjs.org/estraverse/-/estraverse-1.9.3.tgz#af67f2dc922582415950926091a4005d29c9bb44" 275 | 276 | estraverse@^4.1.0, estraverse@^4.1.1: 277 | version "4.2.0" 278 | resolved "https://registry.npmjs.org/estraverse/-/estraverse-4.2.0.tgz#0dee3fed31fcd469618ce7342099fc1afa0bdb13" 279 | 280 | esutils@^2.0.2: 281 | version "2.0.2" 282 | resolved "https://registry.npmjs.org/esutils/-/esutils-2.0.2.tgz#0abf4f1caa5bcb1f7a9d8acc6dea4faaa04bac9b" 283 | 284 | fast-levenshtein@~2.0.4: 285 | version "2.0.6" 286 | resolved "https://registry.npmjs.org/fast-levenshtein/-/fast-levenshtein-2.0.6.tgz#3d8a5c66883a16a30ca8643e851f19baa7797917" 287 | 288 | feathers-commons@^0.8.7: 289 | version "0.8.7" 290 | resolved "https://registry.npmjs.org/feathers-commons/-/feathers-commons-0.8.7.tgz#11c6f25b537745a983e8d61552d7db8932d53782" 291 | 292 | fs.realpath@^1.0.0: 293 | version "1.0.0" 294 | resolved "https://registry.npmjs.org/fs.realpath/-/fs.realpath-1.0.0.tgz#1504ad2523158caa40db4a2787cb01411994ea4f" 295 | 296 | glob@7.1.1: 297 | version "7.1.1" 298 | resolved "https://registry.npmjs.org/glob/-/glob-7.1.1.tgz#805211df04faaf1c63a3600306cdf5ade50b2ec8" 299 | dependencies: 300 | fs.realpath "^1.0.0" 301 | inflight "^1.0.4" 302 | inherits "2" 303 | minimatch "^3.0.2" 304 | once "^1.3.0" 305 | path-is-absolute "^1.0.0" 306 | 307 | glob@^5.0.15: 308 | version "5.0.15" 309 | resolved "https://registry.npmjs.org/glob/-/glob-5.0.15.tgz#1bc936b9e02f4a603fcc222ecf7633d30b8b93b1" 310 | dependencies: 311 | inflight "^1.0.4" 312 | inherits "2" 313 | minimatch "2 || 3" 314 | once "^1.3.0" 315 | path-is-absolute "^1.0.0" 316 | 317 | globals@^11.1.0: 318 | version "11.7.0" 319 | resolved "https://registry.npmjs.org/globals/-/globals-11.7.0.tgz#a583faa43055b1aca771914bf68258e2fc125673" 320 | 321 | "graceful-readlink@>= 1.0.0": 322 | version "1.0.1" 323 | resolved "https://registry.npmjs.org/graceful-readlink/-/graceful-readlink-1.0.1.tgz#4cafad76bc62f02fa039b2f94e9a3dd3a391a725" 324 | 325 | growl@1.9.2: 326 | version "1.9.2" 327 | resolved "https://registry.npmjs.org/growl/-/growl-1.9.2.tgz#0ea7743715db8d8de2c5ede1775e1b45ac85c02f" 328 | 329 | handlebars@^4.0.1: 330 | version "4.0.11" 331 | resolved "https://registry.npmjs.org/handlebars/-/handlebars-4.0.11.tgz#630a35dfe0294bc281edae6ffc5d329fc7982dcc" 332 | dependencies: 333 | async "^1.4.0" 334 | optimist "^0.6.1" 335 | source-map "^0.4.4" 336 | optionalDependencies: 337 | uglify-js "^2.6" 338 | 339 | has-flag@^1.0.0: 340 | version "1.0.0" 341 | resolved "https://registry.npmjs.org/has-flag/-/has-flag-1.0.0.tgz#9d9e793165ce017a00f00418c43f942a7b1d11fa" 342 | 343 | has-flag@^3.0.0: 344 | version "3.0.0" 345 | resolved "https://registry.npmjs.org/has-flag/-/has-flag-3.0.0.tgz#b5d454dc2199ae225699f3467e5a07f3b955bafd" 346 | 347 | he@1.1.1: 348 | version "1.1.1" 349 | resolved "https://registry.npmjs.org/he/-/he-1.1.1.tgz#93410fd21b009735151f8868c2f271f3427e23fd" 350 | 351 | inflight@^1.0.4: 352 | version "1.0.6" 353 | resolved "https://registry.npmjs.org/inflight/-/inflight-1.0.6.tgz#49bd6331d7d02d0c09bc910a1075ba8165b56df9" 354 | dependencies: 355 | once "^1.3.0" 356 | wrappy "1" 357 | 358 | inherits@2: 359 | version "2.0.3" 360 | resolved "https://registry.npmjs.org/inherits/-/inherits-2.0.3.tgz#633c2c83e3da42a502f52466022480f4208261de" 361 | 362 | invariant@^2.2.0: 363 | version "2.2.4" 364 | resolved "https://registry.npmjs.org/invariant/-/invariant-2.2.4.tgz#610f3c92c9359ce1db616e538008d23ff35158e6" 365 | dependencies: 366 | loose-envify "^1.0.0" 367 | 368 | is-buffer@^1.1.5: 369 | version "1.1.6" 370 | resolved "https://registry.npmjs.org/is-buffer/-/is-buffer-1.1.6.tgz#efaa2ea9daa0d7ab2ea13a97b2b8ad51fefbe8be" 371 | 372 | isarray@0.0.1: 373 | version "0.0.1" 374 | resolved "https://registry.npmjs.org/isarray/-/isarray-0.0.1.tgz#8a18acfca9a8f4177e09abfc6038939b05d1eedf" 375 | 376 | isexe@^2.0.0: 377 | version "2.0.0" 378 | resolved "https://registry.npmjs.org/isexe/-/isexe-2.0.0.tgz#e8fbf374dc556ff8947a10dcb0572d633f2cfa10" 379 | 380 | istanbul@^0.4.5: 381 | version "0.4.5" 382 | resolved "https://registry.npmjs.org/istanbul/-/istanbul-0.4.5.tgz#65c7d73d4c4da84d4f3ac310b918fb0b8033733b" 383 | dependencies: 384 | abbrev "1.0.x" 385 | async "1.x" 386 | escodegen "1.8.x" 387 | esprima "2.7.x" 388 | glob "^5.0.15" 389 | handlebars "^4.0.1" 390 | js-yaml "3.x" 391 | mkdirp "0.5.x" 392 | nopt "3.x" 393 | once "1.x" 394 | resolve "1.1.x" 395 | supports-color "^3.1.0" 396 | which "^1.1.1" 397 | wordwrap "^1.0.0" 398 | 399 | js-tokens@^3.0.0: 400 | version "3.0.2" 401 | resolved "https://registry.npmjs.org/js-tokens/-/js-tokens-3.0.2.tgz#9866df395102130e38f7f996bceb65443209c25b" 402 | 403 | "js-tokens@^3.0.0 || ^4.0.0": 404 | version "4.0.0" 405 | resolved "https://registry.npmjs.org/js-tokens/-/js-tokens-4.0.0.tgz#19203fb59991df98e3a287050d4647cdeaf32499" 406 | 407 | js-yaml@3.x: 408 | version "3.12.0" 409 | resolved "https://registry.npmjs.org/js-yaml/-/js-yaml-3.12.0.tgz#eaed656ec8344f10f527c6bfa1b6e2244de167d1" 410 | dependencies: 411 | argparse "^1.0.7" 412 | esprima "^4.0.0" 413 | 414 | jsesc@^2.5.1: 415 | version "2.5.1" 416 | resolved "https://registry.npmjs.org/jsesc/-/jsesc-2.5.1.tgz#e421a2a8e20d6b0819df28908f782526b96dd1fe" 417 | 418 | json3@3.3.2: 419 | version "3.3.2" 420 | resolved "https://registry.npmjs.org/json3/-/json3-3.3.2.tgz#3c0434743df93e2f5c42aee7b19bcb483575f4e1" 421 | 422 | kind-of@^3.0.2: 423 | version "3.2.2" 424 | resolved "https://registry.npmjs.org/kind-of/-/kind-of-3.2.2.tgz#31ea21a734bab9bbb0f32466d893aea51e4a3c64" 425 | dependencies: 426 | is-buffer "^1.1.5" 427 | 428 | lazy-cache@^1.0.3: 429 | version "1.0.4" 430 | resolved "https://registry.npmjs.org/lazy-cache/-/lazy-cache-1.0.4.tgz#a1d78fc3a50474cb80845d3b3b6e1da49a446e8e" 431 | 432 | levn@~0.3.0: 433 | version "0.3.0" 434 | resolved "https://registry.npmjs.org/levn/-/levn-0.3.0.tgz#3b09924edf9f083c0490fdd4c0bc4421e04764ee" 435 | dependencies: 436 | prelude-ls "~1.1.2" 437 | type-check "~0.3.2" 438 | 439 | lodash._baseassign@^3.0.0: 440 | version "3.2.0" 441 | resolved "https://registry.npmjs.org/lodash._baseassign/-/lodash._baseassign-3.2.0.tgz#8c38a099500f215ad09e59f1722fd0c52bfe0a4e" 442 | dependencies: 443 | lodash._basecopy "^3.0.0" 444 | lodash.keys "^3.0.0" 445 | 446 | lodash._basecopy@^3.0.0: 447 | version "3.0.1" 448 | resolved "https://registry.npmjs.org/lodash._basecopy/-/lodash._basecopy-3.0.1.tgz#8da0e6a876cf344c0ad8a54882111dd3c5c7ca36" 449 | 450 | lodash._basecreate@^3.0.0: 451 | version "3.0.3" 452 | resolved "https://registry.npmjs.org/lodash._basecreate/-/lodash._basecreate-3.0.3.tgz#1bc661614daa7fc311b7d03bf16806a0213cf821" 453 | 454 | lodash._getnative@^3.0.0: 455 | version "3.9.1" 456 | resolved "https://registry.npmjs.org/lodash._getnative/-/lodash._getnative-3.9.1.tgz#570bc7dede46d61cdcde687d65d3eecbaa3aaff5" 457 | 458 | lodash._isiterateecall@^3.0.0: 459 | version "3.0.9" 460 | resolved "https://registry.npmjs.org/lodash._isiterateecall/-/lodash._isiterateecall-3.0.9.tgz#5203ad7ba425fae842460e696db9cf3e6aac057c" 461 | 462 | lodash.create@3.1.1: 463 | version "3.1.1" 464 | resolved "https://registry.npmjs.org/lodash.create/-/lodash.create-3.1.1.tgz#d7f2849f0dbda7e04682bb8cd72ab022461debe7" 465 | dependencies: 466 | lodash._baseassign "^3.0.0" 467 | lodash._basecreate "^3.0.0" 468 | lodash._isiterateecall "^3.0.0" 469 | 470 | lodash.isarguments@^3.0.0: 471 | version "3.1.0" 472 | resolved "https://registry.npmjs.org/lodash.isarguments/-/lodash.isarguments-3.1.0.tgz#2f573d85c6a24289ff00663b491c1d338ff3458a" 473 | 474 | lodash.isarray@^3.0.0: 475 | version "3.0.4" 476 | resolved "https://registry.npmjs.org/lodash.isarray/-/lodash.isarray-3.0.4.tgz#79e4eb88c36a8122af86f844aa9bcd851b5fbb55" 477 | 478 | lodash.keys@^3.0.0: 479 | version "3.1.2" 480 | resolved "https://registry.npmjs.org/lodash.keys/-/lodash.keys-3.1.2.tgz#4dbc0472b156be50a0b286855d1bd0b0c656098a" 481 | dependencies: 482 | lodash._getnative "^3.0.0" 483 | lodash.isarguments "^3.0.0" 484 | lodash.isarray "^3.0.0" 485 | 486 | lodash@^4.2.0: 487 | version "4.17.10" 488 | resolved "https://registry.npmjs.org/lodash/-/lodash-4.17.10.tgz#1b7793cf7259ea38fb3661d4d38b3260af8ae4e7" 489 | 490 | longest@^1.0.1: 491 | version "1.0.1" 492 | resolved "https://registry.npmjs.org/longest/-/longest-1.0.1.tgz#30a0b2da38f73770e8294a0d22e6625ed77d0097" 493 | 494 | loose-envify@^1.0.0: 495 | version "1.4.0" 496 | resolved "https://registry.npmjs.org/loose-envify/-/loose-envify-1.4.0.tgz#71ee51fa7be4caec1a63839f7e682d8132d30caf" 497 | dependencies: 498 | js-tokens "^3.0.0 || ^4.0.0" 499 | 500 | "minimatch@2 || 3", minimatch@^3.0.2: 501 | version "3.0.4" 502 | resolved "https://registry.npmjs.org/minimatch/-/minimatch-3.0.4.tgz#5166e286457f03306064be5497e8dbb0c3d32083" 503 | dependencies: 504 | brace-expansion "^1.1.7" 505 | 506 | minimist@0.0.8: 507 | version "0.0.8" 508 | resolved "https://registry.npmjs.org/minimist/-/minimist-0.0.8.tgz#857fcabfc3397d2625b8228262e86aa7a011b05d" 509 | 510 | minimist@~0.0.1: 511 | version "0.0.10" 512 | resolved "https://registry.npmjs.org/minimist/-/minimist-0.0.10.tgz#de3f98543dbf96082be48ad1a0c7cda836301dcf" 513 | 514 | mkdirp@0.5.1, mkdirp@0.5.x: 515 | version "0.5.1" 516 | resolved "https://registry.npmjs.org/mkdirp/-/mkdirp-0.5.1.tgz#30057438eac6cf7f8c4767f38648d6697d75c903" 517 | dependencies: 518 | minimist "0.0.8" 519 | 520 | mocha@^3.3.0: 521 | version "3.5.3" 522 | resolved "https://registry.npmjs.org/mocha/-/mocha-3.5.3.tgz#1e0480fe36d2da5858d1eb6acc38418b26eaa20d" 523 | dependencies: 524 | browser-stdout "1.3.0" 525 | commander "2.9.0" 526 | debug "2.6.8" 527 | diff "3.2.0" 528 | escape-string-regexp "1.0.5" 529 | glob "7.1.1" 530 | growl "1.9.2" 531 | he "1.1.1" 532 | json3 "3.3.2" 533 | lodash.create "3.1.1" 534 | mkdirp "0.5.1" 535 | supports-color "3.1.2" 536 | 537 | ms@2.0.0: 538 | version "2.0.0" 539 | resolved "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz#5608aeadfc00be6c2901df5f9861788de0d597c8" 540 | 541 | nopt@3.x: 542 | version "3.0.6" 543 | resolved "https://registry.npmjs.org/nopt/-/nopt-3.0.6.tgz#c6465dbf08abcd4db359317f79ac68a646b28ff9" 544 | dependencies: 545 | abbrev "1" 546 | 547 | once@1.x, once@^1.3.0: 548 | version "1.4.0" 549 | resolved "https://registry.npmjs.org/once/-/once-1.4.0.tgz#583b1aa775961d4b113ac17d9c50baef9dd76bd1" 550 | dependencies: 551 | wrappy "1" 552 | 553 | optimist@^0.6.1: 554 | version "0.6.1" 555 | resolved "https://registry.npmjs.org/optimist/-/optimist-0.6.1.tgz#da3ea74686fa21a19a111c326e90eb15a0196686" 556 | dependencies: 557 | minimist "~0.0.1" 558 | wordwrap "~0.0.2" 559 | 560 | optionator@^0.8.1: 561 | version "0.8.2" 562 | resolved "https://registry.npmjs.org/optionator/-/optionator-0.8.2.tgz#364c5e409d3f4d6301d6c0b4c05bba50180aeb64" 563 | dependencies: 564 | deep-is "~0.1.3" 565 | fast-levenshtein "~2.0.4" 566 | levn "~0.3.0" 567 | prelude-ls "~1.1.2" 568 | type-check "~0.3.2" 569 | wordwrap "~1.0.0" 570 | 571 | path-is-absolute@^1.0.0: 572 | version "1.0.1" 573 | resolved "https://registry.npmjs.org/path-is-absolute/-/path-is-absolute-1.0.1.tgz#174b9268735534ffbc7ace6bf53a5a9e1b5c5f5f" 574 | 575 | path-to-regexp@^1.7.0: 576 | version "1.7.0" 577 | resolved "https://registry.npmjs.org/path-to-regexp/-/path-to-regexp-1.7.0.tgz#59fde0f435badacba103a84e9d3bc64e96b9937d" 578 | dependencies: 579 | isarray "0.0.1" 580 | 581 | prelude-ls@~1.1.2: 582 | version "1.1.2" 583 | resolved "https://registry.npmjs.org/prelude-ls/-/prelude-ls-1.1.2.tgz#21932a549f5e52ffd9a827f570e04be62a97da54" 584 | 585 | repeat-string@^1.5.2: 586 | version "1.6.1" 587 | resolved "https://registry.npmjs.org/repeat-string/-/repeat-string-1.6.1.tgz#8dcae470e1c88abc2d600fff4a776286da75e637" 588 | 589 | resolve@1.1.x: 590 | version "1.1.7" 591 | resolved "https://registry.npmjs.org/resolve/-/resolve-1.1.7.tgz#203114d82ad2c5ed9e8e0411b3932875e889e97b" 592 | 593 | right-align@^0.1.1: 594 | version "0.1.3" 595 | resolved "https://registry.npmjs.org/right-align/-/right-align-0.1.3.tgz#61339b722fe6a3515689210d24e14c96148613ef" 596 | dependencies: 597 | align-text "^0.1.1" 598 | 599 | rubberduck@^1.1.1: 600 | version "1.1.1" 601 | resolved "https://registry.npmjs.org/rubberduck/-/rubberduck-1.1.1.tgz#cd2cda4b867178135eafc995a71384f5f743db02" 602 | 603 | source-map@^0.4.4: 604 | version "0.4.4" 605 | resolved "https://registry.npmjs.org/source-map/-/source-map-0.4.4.tgz#eba4f5da9c0dc999de68032d8b4f76173652036b" 606 | dependencies: 607 | amdefine ">=0.0.4" 608 | 609 | source-map@^0.5.0, source-map@~0.5.1: 610 | version "0.5.7" 611 | resolved "https://registry.npmjs.org/source-map/-/source-map-0.5.7.tgz#8a039d2d1021d22d1ea14c80d8ea468ba2ef3fcc" 612 | 613 | source-map@~0.2.0: 614 | version "0.2.0" 615 | resolved "https://registry.npmjs.org/source-map/-/source-map-0.2.0.tgz#dab73fbcfc2ba819b4de03bd6f6eaa48164b3f9d" 616 | dependencies: 617 | amdefine ">=0.0.4" 618 | 619 | sprintf-js@~1.0.2: 620 | version "1.0.3" 621 | resolved "https://registry.npmjs.org/sprintf-js/-/sprintf-js-1.0.3.tgz#04e6926f662895354f3dd015203633b857297e2c" 622 | 623 | supports-color@3.1.2: 624 | version "3.1.2" 625 | resolved "https://registry.npmjs.org/supports-color/-/supports-color-3.1.2.tgz#72a262894d9d408b956ca05ff37b2ed8a6e2a2d5" 626 | dependencies: 627 | has-flag "^1.0.0" 628 | 629 | supports-color@^3.1.0: 630 | version "3.2.3" 631 | resolved "https://registry.npmjs.org/supports-color/-/supports-color-3.2.3.tgz#65ac0504b3954171d8a64946b2ae3cbb8a5f54f6" 632 | dependencies: 633 | has-flag "^1.0.0" 634 | 635 | supports-color@^5.3.0: 636 | version "5.4.0" 637 | resolved "https://registry.npmjs.org/supports-color/-/supports-color-5.4.0.tgz#1c6b337402c2137605efe19f10fec390f6faab54" 638 | dependencies: 639 | has-flag "^3.0.0" 640 | 641 | to-fast-properties@^2.0.0: 642 | version "2.0.0" 643 | resolved "https://registry.npmjs.org/to-fast-properties/-/to-fast-properties-2.0.0.tgz#dc5e698cbd079265bc73e0377681a4e4e83f616e" 644 | 645 | trim-right@^1.0.1: 646 | version "1.0.1" 647 | resolved "https://registry.npmjs.org/trim-right/-/trim-right-1.0.1.tgz#cb2e1203067e0c8de1f614094b9fe45704ea6003" 648 | 649 | type-check@~0.3.2: 650 | version "0.3.2" 651 | resolved "https://registry.npmjs.org/type-check/-/type-check-0.3.2.tgz#5884cab512cf1d355e3fb784f30804b2b520db72" 652 | dependencies: 653 | prelude-ls "~1.1.2" 654 | 655 | uberproto@^1.2.0: 656 | version "1.2.0" 657 | resolved "https://registry.npmjs.org/uberproto/-/uberproto-1.2.0.tgz#61d4eab024f909c4e6ea52be867c4894a4beeb76" 658 | 659 | uglify-js@^2.6: 660 | version "2.8.29" 661 | resolved "https://registry.npmjs.org/uglify-js/-/uglify-js-2.8.29.tgz#29c5733148057bb4e1f75df35b7a9cb72e6a59dd" 662 | dependencies: 663 | source-map "~0.5.1" 664 | yargs "~3.10.0" 665 | optionalDependencies: 666 | uglify-to-browserify "~1.0.0" 667 | 668 | uglify-to-browserify@~1.0.0: 669 | version "1.0.2" 670 | resolved "https://registry.npmjs.org/uglify-to-browserify/-/uglify-to-browserify-1.0.2.tgz#6e0924d6bda6b5afe349e39a6d632850a0f882b7" 671 | 672 | which@^1.1.1: 673 | version "1.3.1" 674 | resolved "https://registry.npmjs.org/which/-/which-1.3.1.tgz#a45043d54f5805316da8d62f9f50918d3da70b0a" 675 | dependencies: 676 | isexe "^2.0.0" 677 | 678 | window-size@0.1.0: 679 | version "0.1.0" 680 | resolved "https://registry.npmjs.org/window-size/-/window-size-0.1.0.tgz#5438cd2ea93b202efa3a19fe8887aee7c94f9c9d" 681 | 682 | wordwrap@0.0.2: 683 | version "0.0.2" 684 | resolved "https://registry.npmjs.org/wordwrap/-/wordwrap-0.0.2.tgz#b79669bb42ecb409f83d583cad52ca17eaa1643f" 685 | 686 | wordwrap@^1.0.0, wordwrap@~1.0.0: 687 | version "1.0.0" 688 | resolved "https://registry.npmjs.org/wordwrap/-/wordwrap-1.0.0.tgz#27584810891456a4171c8d0226441ade90cbcaeb" 689 | 690 | wordwrap@~0.0.2: 691 | version "0.0.3" 692 | resolved "https://registry.npmjs.org/wordwrap/-/wordwrap-0.0.3.tgz#a3d5da6cd5c0bc0008d37234bbaf1bed63059107" 693 | 694 | wrappy@1: 695 | version "1.0.2" 696 | resolved "https://registry.npmjs.org/wrappy/-/wrappy-1.0.2.tgz#b5243d8f3ec1aa35f1364605bc0d1036e30ab69f" 697 | 698 | yargs@~3.10.0: 699 | version "3.10.0" 700 | resolved "https://registry.npmjs.org/yargs/-/yargs-3.10.0.tgz#f7ee7bd857dd7c1d2d38c0e74efbd681d1431fd1" 701 | dependencies: 702 | camelcase "^1.0.2" 703 | cliui "^2.1.0" 704 | decamelize "^1.0.0" 705 | window-size "0.1.0" 706 | --------------------------------------------------------------------------------