├── .eslintrc ├── .gitignore ├── .npmignore ├── .prettierrc ├── .travis.yml ├── LICENCE ├── README.md ├── package.json ├── src ├── index.js └── lib │ ├── rules │ ├── check-addtoset-updates.js │ ├── check-addtoset-updates.mocha.js │ ├── check-current-date-updates.js │ ├── check-current-date-updates.mocha.js │ ├── check-deprecated-calls.js │ ├── check-deprecated-calls.mocha.js │ ├── check-deprecated-updates.js │ ├── check-deprecated-updates.mocha.js │ ├── check-insert-calls.js │ ├── check-insert-calls.mocha.js │ ├── check-minmax-updates.js │ ├── check-minmax-updates.mocha.js │ ├── check-numeric-updates.js │ ├── check-numeric-updates.mocha.js │ ├── check-pop-updates.js │ ├── check-pop-updates.mocha.js │ ├── check-pull-updates.js │ ├── check-pull-updates.mocha.js │ ├── check-push-updates.js │ ├── check-push-updates.mocha.js │ ├── check-query-calls.js │ ├── check-query-calls.mocha.js │ ├── check-remove-calls.js │ ├── check-remove-calls.mocha.js │ ├── check-rename-updates.js │ ├── check-rename-updates.mocha.js │ ├── check-set-updates.js │ ├── check-set-updates.mocha.js │ ├── check-unset-updates.js │ ├── check-unset-updates.mocha.js │ ├── check-update-calls.js │ ├── check-update-calls.mocha.js │ ├── no-replace.js │ └── no-replace.mocha.js │ └── utils.js └── yarn.lock /.eslintrc: -------------------------------------------------------------------------------- 1 | { 2 | "extends": "eslint-config-simplifield", 3 | "env": { 4 | "node": true, 5 | "mocha": true 6 | }, 7 | "globals": { 8 | "require": false, 9 | "describe": false, 10 | "beforeEach": false, 11 | "afterEach": false, 12 | "before": false, 13 | "after": false, 14 | "it": false, 15 | "sinon": false, 16 | "module": false 17 | }, 18 | "rules": { 19 | "strict": [2, "global"] 20 | } 21 | } 22 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | *~ 2 | *.swp 3 | node_modules/ 4 | test/results 5 | .git 6 | .coveralls.yml 7 | -------------------------------------------------------------------------------- /.npmignore: -------------------------------------------------------------------------------- 1 | *~ 2 | *.swp 3 | node_modules/ 4 | .git 5 | .coveralls.yml 6 | tests/results 7 | -------------------------------------------------------------------------------- /.prettierrc: -------------------------------------------------------------------------------- 1 | { 2 | "printWidth": 80, 3 | "trailingComma": "es5", 4 | "singleQuote": true 5 | } 6 | -------------------------------------------------------------------------------- /.travis.yml: -------------------------------------------------------------------------------- 1 | language: node_js 2 | node_js: 3 | - 10 4 | 5 | script: 6 | - npm test 7 | -------------------------------------------------------------------------------- /LICENCE: -------------------------------------------------------------------------------- 1 | The MIT License 2 | 3 | Copyright (c) 2015 Nicolas Froidure, 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 13 | all 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 21 | THE SOFTWARE. 22 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # eslint-plugin-mongodb 2 | > Eslint rules for the [NodeJS MongoDB native driver 2.0](http://mongodb.github.io/node-mongodb-native/2.0/) syntax and best practices. 3 | 4 | [![NPM version](https://badge.fury.io/js/eslint-plugin-mongodb.svg)](https://npmjs.org/package/eslint-plugin-mongodb) [![Build status](https://secure.travis-ci.org/nfroidure/eslint-plugin-mongodb.svg)](https://travis-ci.org/nfroidure/eslint-plugin-mongodb) [![Dependency Status](https://david-dm.org/nfroidure/eslint-plugin-mongodb.svg)](https://david-dm.org/nfroidure/eslint-plugin-mongodb) [![devDependency Status](https://david-dm.org/nfroidure/eslint-plugin-mongodb/dev-status.svg)](https://david-dm.org/nfroidure/eslint-plugin-mongodb#info=devDependencies) [![Coverage Status](https://coveralls.io/repos/nfroidure/eslint-plugin-mongodb/badge.svg?branch=master)](https://coveralls.io/r/nfroidure/eslint-plugin-mongodb?branch=master) [![Code Climate](https://codeclimate.com/github/nfroidure/eslint-plugin-mongodb.svg)](https://codeclimate.com/github/nfroidure/eslint-plugin-mongodb) 5 | 6 | **Disclaimer:** 7 | This is a work in progress. Use it only if you wish to be involved in this 8 | project evolution by reporting bugs or even sending PRs. 9 | 10 | The first stable release will be [1.0.0](https://github.com/nfroidure/eslint-plugin-mongodb/milestones/v1.0.0). 11 | 12 | ## Usage 13 | 14 | 1. Install `eslint` as a dev-dependency: 15 | 16 | ```shell 17 | npm install --save-dev eslint 18 | ``` 19 | 20 | 2. Install `eslint-plugin-mongodb` as a dev-dependency: 21 | 22 | ```shell 23 | npm install --save-dev eslint-plugin-mongodb 24 | ``` 25 | 26 | 3. Enable the plugin by adding it to your `.eslintrc`: 27 | 28 | ```yaml 29 | plugins: 30 | - mongodb 31 | ``` 32 | 33 | 4. You can also configure these rules in your `.eslintrc`. All rules defined in 34 | this plugin have to be prefixed by 'mongodb/' 35 | 36 | ```yaml 37 | plugins: 38 | - mongodb 39 | rules: 40 | - mongodb/no-replace: 0 41 | ``` 42 | 43 | ## Settings 44 | 45 | In order to recognize MongoDB native driver queries, this plugin check for 46 | function calls. By using [shared settings](http://eslint.org/docs/user-guide/configuring.html#adding-shared-settings) 47 | you can specify your own patterns, here are the defaults: 48 | 49 | ```json 50 | { 51 | "settings": { 52 | "mongodb": { 53 | "callPatterns": { 54 | "query": [ 55 | "(\\.|^)db\\.collection\\([^\\)]+\\)\\.(find|findOne|)$", 56 | ], 57 | "update": [ 58 | "(\\.|^)db\\.collection\\([^\\)]+\\)\\.(findOneAndUpdate|updateOne|updateMany)$", 59 | ], 60 | "insert": [ 61 | "(\\.|^)db\\.collection\\([^\\)]+\\)\\.(insertOne|insertMany)$", 62 | ], 63 | "remove": [ 64 | "(\\.|^)db\\.collection\\([^\\)]+\\)\\.(findOneAndDelete|deleteOne|deleteMany)$", 65 | ], 66 | "deprecated": [ 67 | "(\\.|^)db\\.collection\\([^\\)]+\\)\\.(remove|update|findAndModify|ensureIndex|findAndRemove|insert|dropAllIndexes)$", 68 | ] 69 | } 70 | } 71 | } 72 | }) 73 | ``` 74 | 75 | Note that the above are strings representing regular expressions. It will be 76 | cast with the `RegExp` constructor so you have to escape your escapes ;). 77 | 78 | ## Rules 79 | 80 | ### check-insert-calls 81 | 82 | Default: `'check-insert-calls': 2` 83 | 84 | Check `insertOne`/`insertMany` calls to ensure their arguments are well formed. 85 | 86 | ### check-query-calls 87 | 88 | Default: `'check-query-calls': 2` 89 | 90 | Check `find`/`findOne` calls to ensure their arguments are well formed. 91 | 92 | ### check-update-calls 93 | 94 | Default: `'check-update-calls': 2` 95 | 96 | Check `update` calls to ensure their arguments are well formed. 97 | 98 | ### check-remove-calls 99 | 100 | Default: `'check-remove-calls': 2` 101 | 102 | Check `remove` calls to ensure their arguments are well formed. 103 | 104 | ### check-deprecated-calls 105 | 106 | Default: `'check-deprecated-calls': 2` 107 | 108 | Check collection calls and warn in case of deprecated methods usage. 109 | 110 | ### no-replace 111 | 112 | Default: `'no_replace': 1` 113 | 114 | Check update queries to ensure no raw replace is done. 115 | 116 | ### check-rename-updates 117 | 118 | Default: `'check-rename-updates': 2` 119 | 120 | Check `$rename` update operator usage. 121 | 122 | ### check-unset-updates 123 | 124 | Default: `'check-unset-updates': 2` 125 | 126 | Check `$unset` update operator usage. 127 | 128 | ### check-current-date-updates 129 | 130 | Default: `'check-current-date-updates': 2` 131 | 132 | Check `$currentDate` update operator usage. 133 | 134 | ### check-numeric-updates 135 | 136 | Default: `'check-numeric-updates': 2` 137 | 138 | Check update queries to ensure numeric operators like `$mul` and `$inc` contain 139 | numeric values. 140 | 141 | ### check-minmax-updates 142 | 143 | Default: `'check-minmax-updates': 2` 144 | 145 | Check `$min` and `$max` update operators usage. 146 | 147 | ### check-set-updates 148 | 149 | Default: `'check-set-updates': 2` 150 | 151 | Check `$set` and `$setOnInsert` update operators usage. 152 | 153 | ### check-push-updates 154 | 155 | Default: `'check-push-updates': 2` 156 | 157 | Check `$push` update operator usage and its modifiers. 158 | 159 | ### check-pull-updates 160 | 161 | Default: `'check-pull-updates': 2` 162 | 163 | Check `$pull` update operator usage. 164 | 165 | ### check-pop-updates 166 | 167 | Default: `'check-pop-updates': 2` 168 | 169 | Check `$pop` update operator usage. 170 | 171 | ### check-addtoset-updates 172 | 173 | Default: `'check-addtoset-updates': 2` 174 | 175 | Check `$addToSet` update operator usage and common misuses. 176 | 177 | ### check-deprecated-updates 178 | 179 | Default: `'check-deprecated-updates': 2` 180 | 181 | Check deprecated update operator usage. 182 | 183 | ## Contributing 184 | Feel free to push your code if you agree with publishing under the MIT license. 185 | 186 | ### How to create a new rule 187 | 188 | Avoid wasting your time and follow those steps to suggest a new rule: 189 | - create and issue prefixed by [rule] and followed by it's name 190 | - OR create the rule tests file in the src/lib/rules directory directly, create 191 | a branch whose name is the proposed rule name. Finally create a pull request. 192 | - let's discuss about the feature and its implementation details. 193 | - implement the feature. 194 | 195 | ### Changing a specific rule behavior 196 | 197 | Create and issue prefixed by [rule] and let us know what should change. 198 | 199 | ## Stats 200 | [![NPM](https://nodei.co/npm/eslint-plugin-mongodb.png?downloads=true&stars=true)](https://nodei.co/npm/eslint-plugin-mongodb/) 201 | [![NPM](https://nodei.co/npm-dl/eslint-plugin-mongodb.png)](https://nodei.co/npm/eslint-plugin-mongodb/) 202 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "eslint-plugin-mongodb", 3 | "version": "0.2.5", 4 | "description": "Lint your MongoDB queries.", 5 | "main": "src/index.js", 6 | "scripts": { 7 | "test": "mocha src/**/*.mocha.js", 8 | "coveralls": "istanbul cover _mocha --report lcovonly -- src/**/*.mocha.js -R spec -t 5000 && cat ./coverage/lcov.info | coveralls && rm -rf ./coverage", 9 | "cover": "istanbul cover --report html _mocha -- src/**/*.mocha.js -R spec -t 5000", 10 | "lint": "eslint src/**/*.js", 11 | "preversion": "npm run lint && npm test", 12 | "prettify": "prettier --write 'src/**/*.js'", 13 | "cli": "env NPM_RUN_CLI=1" 14 | }, 15 | "repository": { 16 | "type": "git", 17 | "url": "https://github.com/nfroidure/eslint-plugin-mongodb" 18 | }, 19 | "keywords": [ 20 | "eslint", 21 | "eslintplugin", 22 | "mongodb", 23 | "query", 24 | "queries", 25 | "mongo" 26 | ], 27 | "author": "Nicolas Froidure", 28 | "license": "MIT", 29 | "bugs": { 30 | "url": "https://github.com/nfroidure/eslint-plugin-mongoquery/issues" 31 | }, 32 | "homepage": "https://github.com/nfroidure/eslint-plugin-mongoquery", 33 | "devDependencies": { 34 | "coveralls": "^3.0.0", 35 | "eslint": "4", 36 | "eslint-config-simplifield": "^7.1.1", 37 | "istanbul": "^0.4.5", 38 | "mocha": "^4.0.1", 39 | "mocha-lcov-reporter": "^1.0.0", 40 | "prettier": "^1.9.2" 41 | }, 42 | "dependencies": { 43 | "yerror": "^2.1.0" 44 | } 45 | } 46 | -------------------------------------------------------------------------------- /src/index.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | const rulesConfig = { 4 | 'check-insert-calls': 2, 5 | 'check-update-calls': 2, 6 | 'check-query-calls': 2, 7 | 'check-remove-calls': 2, 8 | 'check-deprecated-calls': 2, 9 | 'no-replace': 1, 10 | 'check-numeric-updates': 2, 11 | 'check-rename-updates': 2, 12 | 'check-unset-updates': 2, 13 | 'check-current-date-updates': 2, 14 | 'check-minmax-updates': 2, 15 | 'check-set-updates': 2, 16 | 'check-push-updates': 2, 17 | 'check-pull-updates': 2, 18 | 'check-pop-updates': 2, 19 | 'check-addtoset-updates': 2, 20 | 'check-deprecated-updates': 2, 21 | }; 22 | 23 | const addPrefix = rules => { 24 | const result = {}; 25 | 26 | for (const key in rules) { 27 | if (rules.hasOwnProperty(key)) { 28 | result[`mongodb/${key}`] = rules[key]; 29 | } 30 | } 31 | return result; 32 | }; 33 | 34 | module.exports = { 35 | rules: { 36 | 'check-insert-calls': require('./lib/rules/check-insert-calls'), 37 | 'check-update-calls': require('./lib/rules/check-update-calls'), 38 | 'check-query-calls': require('./lib/rules/check-query-calls'), 39 | 'check-remove-calls': require('./lib/rules/check-remove-calls'), 40 | 'check-deprecated-calls': require('./lib/rules/check-deprecated-calls'), 41 | 'no-replace': require('./lib/rules/no-replace'), 42 | 'check-numeric-updates': require('./lib/rules/check-numeric-updates'), 43 | 'check-rename-updates': require('./lib/rules/check-rename-updates'), 44 | 'check-unset-updates': require('./lib/rules/check-unset-updates'), 45 | 'check-current-date-updates': require('./lib/rules/check-current-date-updates'), 46 | 'check-minmax-updates': require('./lib/rules/check-minmax-updates'), 47 | 'check-set-updates': require('./lib/rules/check-set-updates'), 48 | 'check-push-updates': require('./lib/rules/check-push-updates'), 49 | 'check-pull-updates': require('./lib/rules/check-pull-updates'), 50 | 'check-pop-updates': require('./lib/rules/check-pop-updates'), 51 | 'check-addtoset-updates': require('./lib/rules/check-addtoset-updates'), 52 | 'check-deprecated-updates': require('./lib/rules/check-deprecated-updates'), 53 | }, 54 | rulesConfig, 55 | configs: { 56 | recommended: { 57 | plugins: ['mongodb'], 58 | rules: rulesConfig, 59 | }, 60 | all: { 61 | plugins: ['mongodb'], 62 | rules: addPrefix(rulesConfig), 63 | }, 64 | }, 65 | }; 66 | -------------------------------------------------------------------------------- /src/lib/rules/check-addtoset-updates.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | const utils = require('../utils'); 4 | 5 | function eMQCheckAddToSetUpdates(context) { 6 | return utils.lookupCall( 7 | context, 8 | utils.getCallPatterns('update', context.settings), 9 | (callSource, args) => { 10 | if ( 11 | !args[1] || 12 | 'ObjectExpression' !== args[1].type || 13 | !args[1].properties.length 14 | ) { 15 | return false; 16 | } 17 | return utils.everyProperties(args[1], [/\$addToSet/], property => { 18 | if ('ObjectExpression' !== property.value.type) { 19 | context.report( 20 | property, 21 | `Expected ${property.key.name} operator value to be an object.` 22 | ); 23 | return false; 24 | } 25 | return property.value.properties.every(propertyNode => { 26 | if (utils.nodeIsDynamic(propertyNode.value)) { 27 | return true; 28 | } 29 | if (utils.nodeIsArray(propertyNode.value)) { 30 | context.report( 31 | propertyNode, 32 | `Adding an array with $addToSet adds the array, use the $each modifier to add each elements (key: ${ 33 | propertyNode.key.name 34 | }).` 35 | ); 36 | return false; 37 | } 38 | if ('ObjectExpression' !== property.value.type) { 39 | return true; 40 | } 41 | return utils.everyProperties(property.value, [/\$each/], property => { 42 | if (utils.nodeIsDynamic(property.value)) { 43 | return true; 44 | } 45 | if ( 46 | '$each' === property.key.name && 47 | !utils.nodeIsArray(property.value) 48 | ) { 49 | context.report( 50 | property, 51 | `Expected ${property.key.name} modifier value to be an array.` 52 | ); 53 | return false; 54 | } 55 | return true; 56 | }); 57 | }); 58 | }); 59 | } 60 | ); 61 | } 62 | 63 | module.exports = eMQCheckAddToSetUpdates; 64 | -------------------------------------------------------------------------------- /src/lib/rules/check-addtoset-updates.mocha.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | const RuleTester = require('eslint').RuleTester; 4 | const rule = require('./check-addtoset-updates'); 5 | 6 | const ruleTester = new RuleTester(); 7 | 8 | ruleTester.run('check-addtoset-updates', rule, { 9 | valid: [ 10 | "db.collection('users').updateMany({}, { $addToSet: { qty: 1, schmilbick: plop, truc: false } });", 11 | "db.collection('users').updateMany({}, { $addToSet: { tags: { $each: ['plop', 'lol'] } } });", 12 | ], 13 | invalid: [ 14 | { 15 | code: "db.collection('users').updateMany({}, { $addToSet: 'test' });", 16 | errors: [ 17 | { 18 | message: 'Expected $addToSet operator value to be an object.', 19 | }, 20 | ], 21 | }, 22 | { 23 | code: 24 | "db.collection('users').updateMany({}, { $addToSet: { t: ['test', 'plop'] } });", 25 | errors: [ 26 | { 27 | message: 28 | 'Adding an array with $addToSet adds the array, use the $each' + 29 | ' modifier to add each elements (key: t).', 30 | }, 31 | ], 32 | }, 33 | { 34 | code: 35 | "db.collection('users').updateMany({}, { $addToSet: { $each: 'test' } });", 36 | errors: [ 37 | { 38 | message: 'Expected $each modifier value to be an array.', 39 | }, 40 | ], 41 | }, 42 | ], 43 | }); 44 | -------------------------------------------------------------------------------- /src/lib/rules/check-current-date-updates.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | const utils = require('../utils'); 4 | 5 | function eMQCheckCurrentDateUpdates(context) { 6 | return utils.lookupCall( 7 | context, 8 | utils.getCallPatterns('update', context.settings), 9 | (callSource, args) => { 10 | if ( 11 | !args[1] || 12 | 'ObjectExpression' !== args[1].type || 13 | !args[1].properties.length 14 | ) { 15 | return false; 16 | } 17 | return utils.everyProperties(args[1], [/\$currentDate/], property => { 18 | if ( 19 | 'ObjectExpression' !== property.value.type && 20 | !utils.nodeWillBeBoolean(property.value) 21 | ) { 22 | context.report( 23 | property, 24 | `Expected ${ 25 | property.key.name 26 | } operator value to be a boolean or an object.` 27 | ); 28 | return false; 29 | } 30 | if ('ObjectExpression' === property.value.type) { 31 | return property.value.properties.every(propertyNode => { 32 | if ('$type' !== propertyNode.key.name) { 33 | context.report( 34 | propertyNode, 35 | `${ 36 | property.key.name 37 | } operator should only have a $type modifier (found: ${ 38 | propertyNode.key.name 39 | }).` 40 | ); 41 | return false; 42 | } 43 | if ( 44 | utils.nodeIsString(propertyNode.value) && 45 | -1 === ['timestamp', 'date'].indexOf(propertyNode.value.value) 46 | ) { 47 | context.report( 48 | propertyNode, 49 | `${property.key.name} operator ${ 50 | propertyNode.key.name 51 | } modifier value can be only "date" or "timestamp" (got: ${ 52 | propertyNode.value.value 53 | }).` 54 | ); 55 | return false; 56 | } 57 | return true; 58 | }); 59 | } 60 | return true; 61 | }); 62 | } 63 | ); 64 | } 65 | 66 | module.exports = eMQCheckCurrentDateUpdates; 67 | -------------------------------------------------------------------------------- /src/lib/rules/check-current-date-updates.mocha.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | const RuleTester = require('eslint').RuleTester; 4 | const rule = require('./check-current-date-updates'); 5 | 6 | const ruleTester = new RuleTester(); 7 | 8 | ruleTester.run('check-current-date-updates', rule, { 9 | valid: [ 10 | { 11 | code: 'userCollection.updateMany({}, { $currentDate: true });', 12 | settings: { 13 | mongodb: { 14 | callPatterns: { 15 | update: [ 16 | '^(user|place|session)Collection\\.(update|findAndModify)$', 17 | ], 18 | }, 19 | }, 20 | }, 21 | }, 22 | "mongoClient.db.collection('users').updateMany({}, { $currentDate: { $type: 'timestamp' } });", 23 | "mongoClient.db.collection('users').updateMany({}, { $currentDate: { $type: 'date' } });", 24 | "mongoClient.db.collection('users').updateMany({}, { $currentDate: !mybool });", 25 | ], 26 | invalid: [ 27 | { 28 | code: "userCollection.updateMany({}, { $currentDate: 'true' });", 29 | settings: { 30 | mongodb: { 31 | callPatterns: { 32 | update: [ 33 | '^(user|place|session)Collection\\.(updateMany|updateOne)$', 34 | ], 35 | }, 36 | }, 37 | }, 38 | errors: [ 39 | { 40 | message: 41 | 'Expected $currentDate operator value to be a boolean or an object.', 42 | }, 43 | ], 44 | }, 45 | { 46 | code: 47 | "mongoClient.db.collection('users').updateMany({}, { $currentDate: { $type: 'date', type: '1664' } });", 48 | errors: [ 49 | { 50 | message: 51 | '$currentDate operator should only have a $type modifier (found: type).', 52 | }, 53 | ], 54 | }, 55 | { 56 | code: 57 | "mongoClient.db.collection('users').updateMany({}, { $currentDate: { $type: '1664' } });", 58 | errors: [ 59 | { 60 | message: 61 | '$currentDate operator $type modifier value can be only "date" or "timestamp" (got: 1664).', 62 | }, 63 | ], 64 | }, 65 | ], 66 | }); 67 | -------------------------------------------------------------------------------- /src/lib/rules/check-deprecated-calls.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | const utils = require('../utils'); 4 | const DEPRECATED_METHODS = [ 5 | 'remove', 6 | 'update', 7 | 'findAndModify', 8 | 'ensureIndex', 9 | 'findAndRemove', 10 | 'insert', 11 | 'dropAllIndexes', 12 | ]; 13 | 14 | function eMQCheckDeprecatedCalls(context) { 15 | return utils.lookupCall( 16 | context, 17 | utils.getCallPatterns('deprecated', context.settings), 18 | (callSource, args, node) => { 19 | const method = callSource.split('.').pop(); 20 | 21 | if (-1 !== DEPRECATED_METHODS.indexOf(method)) { 22 | context.report(node, `${method} method is deprecated.`); 23 | return false; 24 | } 25 | return true; 26 | } 27 | ); 28 | } 29 | 30 | module.exports = eMQCheckDeprecatedCalls; 31 | -------------------------------------------------------------------------------- /src/lib/rules/check-deprecated-calls.mocha.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | const RuleTester = require('eslint').RuleTester; 4 | const rule = require('./check-deprecated-calls'); 5 | 6 | const ruleTester = new RuleTester(); 7 | 8 | ruleTester.run('check-deprecated-calls', rule, { 9 | valid: [ 10 | "db.collection('users').findOne({_id: plop});", 11 | "mongoClient.db.collection('users').findMany({});", 12 | "mongoClient.db.collection('users').deleteOne(gen());", 13 | "mongoClient.db.collection('users').insertOne({});", 14 | ], 15 | invalid: [ 16 | { 17 | code: "db.collection('users').findAndModify();", 18 | errors: [ 19 | { 20 | message: 'findAndModify method is deprecated.', 21 | }, 22 | ], 23 | }, 24 | { 25 | code: "mongoClient.db.collection('users').update('test', {});", 26 | errors: [ 27 | { 28 | message: 'update method is deprecated.', 29 | }, 30 | ], 31 | }, 32 | { 33 | code: "mongoClient.db.collection('users').remove([{}]);", 34 | errors: [ 35 | { 36 | message: 'remove method is deprecated.', 37 | }, 38 | ], 39 | }, 40 | ], 41 | }); 42 | -------------------------------------------------------------------------------- /src/lib/rules/check-deprecated-updates.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | const utils = require('../utils'); 4 | 5 | function eMQCheckDeprecatedUpdates(context) { 6 | return utils.lookupCall( 7 | context, 8 | utils.getCallPatterns('update', context.settings), 9 | (callSource, args) => { 10 | if ( 11 | !args[1] || 12 | 'ObjectExpression' !== args[1].type || 13 | !args[1].properties.length 14 | ) { 15 | return false; 16 | } 17 | return utils.everyProperties( 18 | args[1], 19 | [/\$(pushAll|pullAll)/], 20 | property => { 21 | if ('$pushAll' === property.key.name) { 22 | context.report( 23 | property, 24 | 'The $pushAll operator is deprecated, ' + 25 | 'use the $push one with the $each modifier.' 26 | ); 27 | return false; 28 | } 29 | if ('$pullAll' === property.key.name) { 30 | context.report( 31 | property, 32 | 'The $pullAll operator is deprecated, ' + 'use the $pull one.' 33 | ); 34 | return false; 35 | } 36 | return true; 37 | } 38 | ); 39 | } 40 | ); 41 | } 42 | 43 | module.exports = eMQCheckDeprecatedUpdates; 44 | -------------------------------------------------------------------------------- /src/lib/rules/check-deprecated-updates.mocha.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | const RuleTester = require('eslint').RuleTester; 4 | const rule = require('./check-deprecated-updates'); 5 | 6 | const ruleTester = new RuleTester(); 7 | 8 | ruleTester.run('check-deprecated-updates', rule, { 9 | valid: [], 10 | invalid: [ 11 | { 12 | code: "db.collection('users').updateMany({}, { $pushAll: ['test'] });", 13 | errors: [ 14 | { 15 | message: 16 | 'The $pushAll operator is deprecated, use the $push one with the $each modifier.', 17 | }, 18 | ], 19 | }, 20 | { 21 | code: "db.collection('users').updateMany({}, { $pullAll: ['test'] });", 22 | errors: [ 23 | { 24 | message: 'The $pullAll operator is deprecated, use the $pull one.', 25 | }, 26 | ], 27 | }, 28 | ], 29 | }); 30 | -------------------------------------------------------------------------------- /src/lib/rules/check-insert-calls.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | const utils = require('../utils'); 4 | 5 | function eMQCheckInsertCalls(context) { 6 | return utils.lookupCall( 7 | context, 8 | utils.getCallPatterns('insert', context.settings), 9 | (callSource, args, node) => { 10 | const method = callSource.split('.').pop(); 11 | 12 | if ('insertOne' === method) { 13 | if (!args[0]) { 14 | context.report( 15 | node, 16 | `Expected ${callSource} to have at least 1 argument.` 17 | ); 18 | return false; 19 | } 20 | if ( 21 | !utils.nodeIsDynamic(args[0]) && 22 | 'ObjectExpression' !== args[0].type 23 | ) { 24 | context.report( 25 | args[0], 26 | `Expected ${callSource} call first argument value to be an object.` 27 | ); 28 | return false; 29 | } 30 | if ( 31 | args[1] && 32 | (!utils.nodeIsDynamic(args[1]) && 'ObjectExpression' !== args[1].type) 33 | ) { 34 | context.report( 35 | args[1], 36 | `Expected ${callSource} call second argument value to be an object or a callback function.` 37 | ); 38 | return false; 39 | } 40 | if ( 41 | args[2] && 42 | !utils.nodeIsDynamic(args[2]) && 43 | 'FunctionExpression' !== args[2].type 44 | ) { 45 | context.report( 46 | args[2], 47 | `Expected ${callSource} call third argument value to be a callback function.` 48 | ); 49 | return false; 50 | } 51 | if (args[3]) { 52 | context.report( 53 | node, 54 | `Expected ${callSource} call to have maximum 3 arguments.` 55 | ); 56 | return false; 57 | } 58 | return true; 59 | } 60 | if (!args[0]) { 61 | context.report( 62 | node, 63 | `Expected ${callSource} to have at least 1 argument.` 64 | ); 65 | return false; 66 | } 67 | if (!utils.nodeIsDynamic(args[0]) && !utils.nodeIsArray(args[0])) { 68 | context.report( 69 | args[0], 70 | `Expected ${callSource} call first argument value to be an array.` 71 | ); 72 | return false; 73 | } 74 | if ( 75 | args[1] && 76 | !utils.nodeIsDynamic(args[1]) && 77 | 'ObjectExpression' !== args[1].type 78 | ) { 79 | context.report( 80 | args[1], 81 | `Expected ${callSource} call second argument value to be an object or a callback function.` 82 | ); 83 | return false; 84 | } 85 | if ( 86 | args[2] && 87 | !utils.nodeIsDynamic(args[2]) && 88 | 'FunctionExpression' !== args[2].type 89 | ) { 90 | context.report( 91 | args[2], 92 | `Expected ${callSource} call third argument value to be a callback function.` 93 | ); 94 | return false; 95 | } 96 | if (args[3]) { 97 | context.report( 98 | node, 99 | `Expected ${callSource} call to have maximum 3 arguments.` 100 | ); 101 | return false; 102 | } 103 | return true; 104 | } 105 | ); 106 | } 107 | 108 | module.exports = eMQCheckInsertCalls; 109 | -------------------------------------------------------------------------------- /src/lib/rules/check-insert-calls.mocha.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | const RuleTester = require('eslint').RuleTester; 4 | const rule = require('./check-insert-calls'); 5 | 6 | const ruleTester = new RuleTester(); 7 | 8 | ruleTester.run('check-insert-calls', rule, { 9 | valid: [ 10 | "db.collection('users').insertMany([{}, {}, {}]);", 11 | "mongoClient.db.collection('users').insertOne({}, {});", 12 | "mongoClient.db.collection('users').insertMany(gen(), {});", 13 | "mongoClient.db.collection('users').insertOne(ref, {});", 14 | "mongoClient.db.collection('users').insertMany(gen(), plop, kikoo);", 15 | "mongoClient.db.collection('users').insertMany([{}], done);", 16 | "mongoClient.db.collection('users').insertMany([{field: 'value'}], done);", 17 | "mongoClient.db.collection('users').insertOne(ref, plop, kikoo);", 18 | "mongoClient.db.collection('users').insertOne(ref, {}, function(){});", 19 | ], 20 | invalid: [ 21 | { 22 | code: "db.collection('users').insertMany();", 23 | errors: [ 24 | { 25 | message: 26 | "Expected db.collection('users').insertMany to have at least 1 argument.", 27 | }, 28 | ], 29 | }, 30 | { 31 | code: "db.collection('users').insertOne();", 32 | errors: [ 33 | { 34 | message: 35 | "Expected db.collection('users').insertOne to have at least 1 argument.", 36 | }, 37 | ], 38 | }, 39 | { 40 | code: "mongoClient.db.collection('users').insertOne('test', {});", 41 | errors: [ 42 | { 43 | message: 44 | "Expected mongoClient.db.collection('users').insertOne call first argument value to be an object.", 45 | }, 46 | ], 47 | }, 48 | { 49 | code: "mongoClient.db.collection('users').insertMany('test', {});", 50 | errors: [ 51 | { 52 | message: 53 | "Expected mongoClient.db.collection('users').insertMany call first argument value to be an array.", 54 | }, 55 | ], 56 | }, 57 | { 58 | code: "mongoClient.db.collection('users').insertOne([{}], 'test');", 59 | errors: [ 60 | { 61 | message: 62 | "Expected mongoClient.db.collection('users').insertOne call second argument value to be an object or a callback function.", 63 | }, 64 | ], 65 | }, 66 | { 67 | code: 68 | "mongoClient.db.collection('users').insertOne({}, {}, function() {}, {});", 69 | errors: [ 70 | { 71 | message: 72 | "Expected mongoClient.db.collection('users').insertOne call to have maximum 3 arguments.", 73 | }, 74 | ], 75 | }, 76 | { 77 | code: "mongoClient.db.collection('users').insertOne({}, {}, 'test');", 78 | errors: [ 79 | { 80 | message: 81 | "Expected mongoClient.db.collection('users').insertOne call third argument value to be a callback function.", 82 | }, 83 | ], 84 | }, 85 | { 86 | code: "mongoClient.db.collection('users').insertMany([{}], 'test');", 87 | errors: [ 88 | { 89 | message: 90 | "Expected mongoClient.db.collection('users').insertMany call second argument value to be an object or a callback function.", 91 | }, 92 | ], 93 | }, 94 | { 95 | code: "mongoClient.db.collection('users').insertMany([{}], {}, 'test');", 96 | errors: [ 97 | { 98 | message: 99 | "Expected mongoClient.db.collection('users').insertMany call third argument value to be a callback function.", 100 | }, 101 | ], 102 | }, 103 | { 104 | code: 105 | "mongoClient.db.collection('users').insertMany([{}], {}, function() {}, {});", 106 | errors: [ 107 | { 108 | message: 109 | "Expected mongoClient.db.collection('users').insertMany call to have maximum 3 arguments.", 110 | }, 111 | ], 112 | }, 113 | ], 114 | }); 115 | -------------------------------------------------------------------------------- /src/lib/rules/check-minmax-updates.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | const utils = require('../utils'); 4 | 5 | function eMQCheckMinMaxUpdates(context) { 6 | return utils.lookupCall( 7 | context, 8 | utils.getCallPatterns('update', context.settings), 9 | (callSource, args) => { 10 | if (!args[1] || 'ObjectExpression' !== args[1].type) { 11 | return false; 12 | } 13 | if (!args[1].properties.length) { 14 | return false; 15 | } 16 | return utils.everyProperties(args[1], [/\$min|\$max/], property => { 17 | if ('ObjectExpression' !== property.value.type) { 18 | context.report( 19 | property, 20 | `Expected ${property.key.name} operator value to be an object.` 21 | ); 22 | return false; 23 | } 24 | return property.value.properties.every(propertyNode => { 25 | if ( 26 | !utils.nodeIsDynamic(propertyNode.value) && 27 | !utils.nodeWillBeNumber(propertyNode.value) 28 | ) { 29 | context.report( 30 | propertyNode, 31 | `${property.key.name} operator require numbers (key: ${ 32 | propertyNode.key.name 33 | }).` 34 | ); 35 | return false; 36 | } 37 | return true; 38 | }); 39 | }); 40 | } 41 | ); 42 | } 43 | 44 | module.exports = eMQCheckMinMaxUpdates; 45 | -------------------------------------------------------------------------------- /src/lib/rules/check-minmax-updates.mocha.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | const RuleTester = require('eslint').RuleTester; 4 | const rule = require('./check-minmax-updates'); 5 | 6 | const ruleTester = new RuleTester(); 7 | 8 | ruleTester.run('check-minmax-updates', rule, { 9 | valid: [ 10 | "db.collection('users').updateMany({}, { $min: { old: 18 }});", 11 | "mongoClient.db.collection('users').updateMany({}, { $max: { old: 33 }});", 12 | "mongoClient.db.collection('users').updateMany({}, { $max: { test: plop }});", // Computed :( 13 | "mongoClient.db.collection('users').updateMany({}, { $min: { qty: 33 * 33 }});", // Computed 14 | ], 15 | invalid: [ 16 | { 17 | code: "db.collection('users').updateMany({}, { $min: 'test' });", 18 | errors: [ 19 | { 20 | message: 'Expected $min operator value to be an object.', 21 | }, 22 | ], 23 | }, 24 | { 25 | code: 26 | "mongoClient.db.collection('users').updateMany({}, { $max: {test: 'test'}});", 27 | errors: [ 28 | { 29 | message: '$max operator require numbers (key: test).', 30 | }, 31 | ], 32 | }, 33 | ], 34 | }); 35 | -------------------------------------------------------------------------------- /src/lib/rules/check-numeric-updates.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | const utils = require('../utils'); 4 | 5 | function eMQCheckNumericUpdates(context) { 6 | return utils.lookupCall( 7 | context, 8 | utils.getCallPatterns('update', context.settings), 9 | (callSource, args) => { 10 | if (!args[1] || 'ObjectExpression' !== args[1].type) { 11 | return false; 12 | } 13 | if (!args[1].properties.length) { 14 | return false; 15 | } 16 | return utils.everyProperties(args[1], [/\$mul|\$inc/], property => { 17 | if ('ObjectExpression' !== property.value.type) { 18 | context.report( 19 | property, 20 | `Expected ${property.key.name} operator value to be an object.` 21 | ); 22 | return false; 23 | } 24 | return property.value.properties.every(propertyNode => { 25 | if ( 26 | !utils.nodeIsDynamic(propertyNode.value) && 27 | !utils.nodeWillBeNumber(propertyNode.value) 28 | ) { 29 | context.report( 30 | propertyNode, 31 | `${property.key.name} operator require numbers (key: ${ 32 | propertyNode.key.name 33 | }).` 34 | ); 35 | return false; 36 | } 37 | return true; 38 | }); 39 | }); 40 | } 41 | ); 42 | } 43 | 44 | module.exports = eMQCheckNumericUpdates; 45 | -------------------------------------------------------------------------------- /src/lib/rules/check-numeric-updates.mocha.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | const RuleTester = require('eslint').RuleTester; 4 | const rule = require('./check-numeric-updates'); 5 | 6 | const ruleTester = new RuleTester(); 7 | 8 | ruleTester.run('check-numeric-updates', rule, { 9 | valid: [ 10 | "db.collection('users').updateMany({}, { $inc: { qty: -1664.1664 }});", 11 | "mongoClient.db.collection('users').updateMany({}, { $mul: { qty: 33 }});", 12 | "mongoClient.db.collection('users').updateMany({}, { $mul: { test: plop }});", // Computed :( 13 | "mongoClient.db.collection('users').updateMany({}, { $mul: { qty: 33 * 33 }});", // Computed 14 | ], 15 | invalid: [ 16 | { 17 | code: "db.collection('users').updateMany({}, { $mul: 'test' });", 18 | errors: [ 19 | { 20 | message: 'Expected $mul operator value to be an object.', 21 | }, 22 | ], 23 | }, 24 | { 25 | code: 26 | "mongoClient.db.collection('users').updateMany({}, { $inc: {test: 'test'}});", 27 | errors: [ 28 | { 29 | message: '$inc operator require numbers (key: test).', 30 | }, 31 | ], 32 | }, 33 | ], 34 | }); 35 | -------------------------------------------------------------------------------- /src/lib/rules/check-pop-updates.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | const utils = require('../utils'); 4 | 5 | function eMQCheckPopUpdates(context) { 6 | return utils.lookupCall( 7 | context, 8 | utils.getCallPatterns('update', context.settings), 9 | (callSource, args) => { 10 | if (!args[1] || 'ObjectExpression' !== args[1].type) { 11 | return false; 12 | } 13 | if (!args[1].properties.length) { 14 | return false; 15 | } 16 | return utils.everyProperties(args[1], [/\$pop/], property => { 17 | if ('ObjectExpression' !== property.value.type) { 18 | context.report( 19 | property, 20 | `Expected ${property.key.name} operator value to be an object.` 21 | ); 22 | return false; 23 | } 24 | return property.value.properties.every(propertyNode => { 25 | if ( 26 | !utils.nodeIsDynamic(propertyNode.value) && 27 | !utils.nodeWillBeNumber(propertyNode.value) 28 | ) { 29 | context.report( 30 | propertyNode, 31 | `${property.key.name} operator require numbers (key: ${ 32 | propertyNode.key.name 33 | }).` 34 | ); 35 | return false; 36 | } 37 | return true; 38 | }); 39 | }); 40 | } 41 | ); 42 | } 43 | 44 | module.exports = eMQCheckPopUpdates; 45 | -------------------------------------------------------------------------------- /src/lib/rules/check-pop-updates.mocha.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | const RuleTester = require('eslint').RuleTester; 4 | const rule = require('./check-pop-updates'); 5 | 6 | const ruleTester = new RuleTester(); 7 | 8 | ruleTester.run('check-pop-updates', rule, { 9 | valid: [ 10 | "db.collection('users').updateMany({}, { $pop: { tags: 3 }});", 11 | "mongoClient.db.collection('users').updateMany({}, { $pop: { qty: 1 * 2 }});", 12 | "mongoClient.db.collection('users').updateOne({}, { $pop: { test: plop }});", 13 | "mongoClient.db.collection('users').updateMany({}, { $pop: { qty: getIndex() }});", 14 | ], 15 | invalid: [ 16 | { 17 | code: "db.collection('users').updateMany({}, { $pop: 'test' });", 18 | errors: [ 19 | { 20 | message: 'Expected $pop operator value to be an object.', 21 | }, 22 | ], 23 | }, 24 | { 25 | code: 26 | "mongoClient.db.collection('users').updateMany({}, { $pop: { tags: 'test' }});", 27 | errors: [ 28 | { 29 | message: '$pop operator require numbers (key: tags).', 30 | }, 31 | ], 32 | }, 33 | ], 34 | }); 35 | -------------------------------------------------------------------------------- /src/lib/rules/check-pull-updates.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | const utils = require('../utils'); 4 | 5 | function eMQCheckPullUpdates(context) { 6 | return utils.lookupCall( 7 | context, 8 | utils.getCallPatterns('update', context.settings), 9 | (callSource, args) => { 10 | if ( 11 | !args[1] || 12 | 'ObjectExpression' !== args[1].type || 13 | !args[1].properties.length 14 | ) { 15 | return false; 16 | } 17 | return utils.everyProperties(args[1], [/\$(pull)/], property => { 18 | if ('ObjectExpression' !== property.value.type) { 19 | context.report( 20 | property, 21 | `Expected ${property.key.name} operator value to be an object.` 22 | ); 23 | return false; 24 | } 25 | return true; 26 | }); 27 | } 28 | ); 29 | } 30 | 31 | module.exports = eMQCheckPullUpdates; 32 | -------------------------------------------------------------------------------- /src/lib/rules/check-pull-updates.mocha.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | const RuleTester = require('eslint').RuleTester; 4 | const rule = require('./check-pull-updates'); 5 | 6 | const ruleTester = new RuleTester(); 7 | 8 | ruleTester.run('check-pull-updates', rule, { 9 | valid: [ 10 | "db.collection('users').updateMany({}, { $pull: { qty: 1, schmilbick: plop, truc: false } });", 11 | "db.collection('users').updateOne({}, { $pull: { qty: { schmilbick: plop, truc: false } } });", 12 | ], 13 | invalid: [ 14 | { 15 | code: "db.collection('users').updateMany({}, { $pull: 'test' });", 16 | errors: [ 17 | { 18 | message: 'Expected $pull operator value to be an object.', 19 | }, 20 | ], 21 | }, 22 | ], 23 | }); 24 | -------------------------------------------------------------------------------- /src/lib/rules/check-push-updates.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | const utils = require('../utils'); 4 | 5 | function eMQCheckPushUpdates(context) { 6 | return utils.lookupCall( 7 | context, 8 | utils.getCallPatterns('update', context.settings), 9 | (callSource, args) => { 10 | if ( 11 | !args[1] || 12 | 'ObjectExpression' !== args[1].type || 13 | !args[1].properties.length 14 | ) { 15 | return false; 16 | } 17 | return utils.everyProperties(args[1], [/\$push/], property => { 18 | if (utils.nodeIsDynamic(property.value)) { 19 | return true; 20 | } 21 | if ('ObjectExpression' !== property.value.type) { 22 | context.report( 23 | property, 24 | `Expected ${property.key.name} operator value to be an object.` 25 | ); 26 | return false; 27 | } 28 | return utils.everyProperties(property.value, [/.*/], property => { 29 | if (utils.nodeIsDynamic(property.value)) { 30 | return true; 31 | } 32 | if ('ObjectExpression' !== property.value.type) { 33 | return true; 34 | } 35 | return utils.everyProperties( 36 | property.value, 37 | [/\$(each|slice|position)/], 38 | property => { 39 | if (utils.nodeIsDynamic(property.value)) { 40 | return true; 41 | } 42 | if ( 43 | '$each' === property.key.name && 44 | !utils.nodeIsArray(property.value) 45 | ) { 46 | context.report( 47 | property, 48 | `Expected ${property.key.name} modifier value to be an array.` 49 | ); 50 | return false; 51 | } 52 | if ( 53 | '$slice' === property.key.name && 54 | !utils.nodeWillBeNumber(property.value) 55 | ) { 56 | context.report( 57 | property, 58 | `Expected ${property.key.name} modifier value to be a number.` 59 | ); 60 | return false; 61 | } 62 | if ( 63 | '$position' === property.key.name && 64 | !utils.nodeWillBeNumber(property.value) 65 | ) { 66 | context.report( 67 | property, 68 | `Expected ${property.key.name} modifier value to be a number.` 69 | ); 70 | return false; 71 | } 72 | return true; 73 | } 74 | ); 75 | }); 76 | }); 77 | } 78 | ); 79 | } 80 | 81 | module.exports = eMQCheckPushUpdates; 82 | -------------------------------------------------------------------------------- /src/lib/rules/check-push-updates.mocha.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | const RuleTester = require('eslint').RuleTester; 4 | const rule = require('./check-push-updates'); 5 | 6 | const ruleTester = new RuleTester(); 7 | 8 | ruleTester.run('check-push-updates', rule, { 9 | valid: [ 10 | "db.collection('users').updateMany({}, { $push: { tags: 'hype' }, $position: 2 });", 11 | "db.collection('users').updateMany({}, { $push: { tags: { $each: ['hype', 'eslint'] } } });", 12 | ], 13 | invalid: [ 14 | { 15 | code: "db.collection('users').updateMany({}, { $push: 'test' });", 16 | errors: [ 17 | { 18 | message: 'Expected $push operator value to be an object.', 19 | }, 20 | ], 21 | }, 22 | { 23 | code: 24 | "db.collection('users').updateMany({}, { $push: { tags: { $each: ['hype'], $slice: 'aa' } } });", 25 | errors: [ 26 | { 27 | message: 'Expected $slice modifier value to be a number.', 28 | }, 29 | ], 30 | }, 31 | { 32 | code: 33 | "db.collection('users').updateMany({}, { $push: { tags: { $each: ['hype'], $position: 'aa' } } });", 34 | errors: [ 35 | { 36 | message: 'Expected $position modifier value to be a number.', 37 | }, 38 | ], 39 | }, 40 | ], 41 | }); 42 | -------------------------------------------------------------------------------- /src/lib/rules/check-query-calls.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | const utils = require('../utils'); 4 | 5 | function eMQCheckQueryCalls(context) { 6 | return utils.lookupCall( 7 | context, 8 | utils.getCallPatterns('query', context.settings), 9 | (callSource, args, node) => { 10 | if (!args[0]) { 11 | context.report( 12 | node, 13 | `Expected ${callSource} to have at least 1 argument.` 14 | ); 15 | return false; 16 | } 17 | if ( 18 | !utils.nodeIsDynamic(args[0]) && 19 | 'ObjectExpression' !== args[0].type 20 | ) { 21 | context.report( 22 | args[0], 23 | `Expected ${callSource} call first argument value to be an object.` 24 | ); 25 | return false; 26 | } 27 | if ( 28 | args[1] && 29 | !utils.nodeIsDynamic(args[1]) && 30 | 'ObjectExpression' !== args[1].type && 31 | 'FunctionExpression' !== args[1].type 32 | ) { 33 | context.report( 34 | args[1], 35 | `Expected ${callSource} call second argument value to be an object or a callback function.` 36 | ); 37 | return false; 38 | } 39 | if ( 40 | args[2] && 41 | !utils.nodeIsDynamic(args[2]) && 42 | 'FunctionExpression' !== args[2].type 43 | ) { 44 | context.report( 45 | args[2], 46 | `Expected ${callSource} call third argument value to be a callback function.` 47 | ); 48 | return false; 49 | } 50 | if (args[3]) { 51 | context.report( 52 | node, 53 | `Expected ${callSource} call to have maximum 3 arguments.` 54 | ); 55 | return false; 56 | } 57 | return true; 58 | } 59 | ); 60 | } 61 | 62 | module.exports = eMQCheckQueryCalls; 63 | -------------------------------------------------------------------------------- /src/lib/rules/check-query-calls.mocha.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | const RuleTester = require('eslint').RuleTester; 4 | const rule = require('./check-query-calls'); 5 | 6 | const ruleTester = new RuleTester(); 7 | 8 | ruleTester.run('check-query-calls', rule, { 9 | valid: [ 10 | "db.collection('users').find({_id: plop});", 11 | "mongoClient.db.collection('users').find({}, { limit: 10 });", 12 | "mongoClient.db.collection('users').findOne(gen(), {});", 13 | "mongoClient.db.collection('users').find(ref, {});", 14 | "mongoClient.db.collection('users').find(ref, ref, ref);", 15 | "mongoClient.db.collection('users').find(ref, function() {});", 16 | "mongoClient.db.collection('users').find(ref, {}, function() {});", 17 | ], 18 | invalid: [ 19 | { 20 | code: "db.collection('users').find();", 21 | errors: [ 22 | { 23 | message: 24 | "Expected db.collection('users').find to have at least 1 argument.", 25 | }, 26 | ], 27 | }, 28 | { 29 | code: "mongoClient.db.collection('users').find('test', {});", 30 | errors: [ 31 | { 32 | message: 33 | "Expected mongoClient.db.collection('users').find call first argument value to be an object.", 34 | }, 35 | ], 36 | }, 37 | { 38 | code: "mongoClient.db.collection('users').find({}, 'test');", 39 | errors: [ 40 | { 41 | message: 42 | "Expected mongoClient.db.collection('users').find call second argument value to be an object or a callback function.", 43 | }, 44 | ], 45 | }, 46 | { 47 | code: "mongoClient.db.collection('users').find({}, {}, 'test');", 48 | errors: [ 49 | { 50 | message: 51 | "Expected mongoClient.db.collection('users').find call third argument value to be a callback function.", 52 | }, 53 | ], 54 | }, 55 | { 56 | code: 57 | "mongoClient.db.collection('users').find({}, {}, function() {}, {});", 58 | errors: [ 59 | { 60 | message: 61 | "Expected mongoClient.db.collection('users').find call to have maximum 3 arguments.", 62 | }, 63 | ], 64 | }, 65 | ], 66 | }); 67 | -------------------------------------------------------------------------------- /src/lib/rules/check-remove-calls.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | const utils = require('../utils'); 4 | 5 | function eMQCheckRemoveCalls(context) { 6 | return utils.lookupCall( 7 | context, 8 | utils.getCallPatterns('remove', context.settings), 9 | (callSource, args, node) => { 10 | if (!args[0]) { 11 | context.report( 12 | node, 13 | `Expected ${callSource} to have at least 1 argument.` 14 | ); 15 | return false; 16 | } 17 | if ( 18 | !utils.nodeIsDynamic(args[0]) && 19 | 'ObjectExpression' !== args[0].type 20 | ) { 21 | context.report( 22 | args[0], 23 | `Expected ${callSource} call first argument value to be an object.` 24 | ); 25 | return false; 26 | } 27 | if ( 28 | args[1] && 29 | !utils.nodeIsDynamic(args[1]) && 30 | 'ObjectExpression' !== args[1].type && 31 | 'FunctionExpression' !== args[1].type 32 | ) { 33 | context.report( 34 | args[1], 35 | `Expected ${callSource} call second argument value to be an object or a callback function.` 36 | ); 37 | return false; 38 | } 39 | if ( 40 | args[2] && 41 | !utils.nodeIsDynamic(args[2]) && 42 | 'FunctionExpression' !== args[2].type 43 | ) { 44 | context.report( 45 | args[2], 46 | `Expected ${callSource} call third argument value to be a callback function.` 47 | ); 48 | return false; 49 | } 50 | if (args[3]) { 51 | context.report( 52 | node, 53 | `Expected ${callSource} call to have maximum 3 arguments.` 54 | ); 55 | return false; 56 | } 57 | return true; 58 | } 59 | ); 60 | } 61 | 62 | module.exports = eMQCheckRemoveCalls; 63 | -------------------------------------------------------------------------------- /src/lib/rules/check-remove-calls.mocha.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | const RuleTester = require('eslint').RuleTester; 4 | const rule = require('./check-remove-calls'); 5 | 6 | const ruleTester = new RuleTester(); 7 | 8 | ruleTester.run('check-remove-calls', rule, { 9 | valid: [ 10 | "db.collection('users').deleteOne({_id: plop});", 11 | "mongoClient.db.collection('users').deleteMany({}, { limit: 10 });", 12 | "mongoClient.db.collection('users').deleteMany(gen(), {});", 13 | "mongoClient.db.collection('users').deleteOne(ref, {});", 14 | "mongoClient.db.collection('users').deleteOne(ref, ref, ref);", 15 | "mongoClient.db.collection('users').deleteOne(ref, function() {});", 16 | "mongoClient.db.collection('users').deleteOne(ref, {}, function() {});", 17 | ], 18 | invalid: [ 19 | { 20 | code: "db.collection('users').deleteOne();", 21 | errors: [ 22 | { 23 | message: 24 | "Expected db.collection('users').deleteOne to have at least 1 argument.", 25 | }, 26 | ], 27 | }, 28 | { 29 | code: "mongoClient.db.collection('users').deleteMany('test', {});", 30 | errors: [ 31 | { 32 | message: 33 | "Expected mongoClient.db.collection('users').deleteMany call first argument value to be an object.", 34 | }, 35 | ], 36 | }, 37 | { 38 | code: "mongoClient.db.collection('users').deleteOne({}, 'test');", 39 | errors: [ 40 | { 41 | message: 42 | "Expected mongoClient.db.collection('users').deleteOne call second argument value to be an object or a callback function.", 43 | }, 44 | ], 45 | }, 46 | { 47 | code: "mongoClient.db.collection('users').deleteOne({}, {}, 'test');", 48 | errors: [ 49 | { 50 | message: 51 | "Expected mongoClient.db.collection('users').deleteOne call third argument value to be a callback function.", 52 | }, 53 | ], 54 | }, 55 | { 56 | code: 57 | "mongoClient.db.collection('users').deleteOne({}, {}, function() {}, {});", 58 | errors: [ 59 | { 60 | message: 61 | "Expected mongoClient.db.collection('users').deleteOne call to have maximum 3 arguments.", 62 | }, 63 | ], 64 | }, 65 | ], 66 | }); 67 | -------------------------------------------------------------------------------- /src/lib/rules/check-rename-updates.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | const utils = require('../utils'); 4 | 5 | function eMQCheckRenameUpdates(context) { 6 | return utils.lookupCall( 7 | context, 8 | utils.getCallPatterns('update', context.settings), 9 | (callSource, args) => { 10 | if ( 11 | !args[1] || 12 | 'ObjectExpression' !== args[1].type || 13 | !args[1].properties.length 14 | ) { 15 | return false; 16 | } 17 | return utils.everyProperties(args[1], [/\$rename/], property => { 18 | if ('ObjectExpression' !== property.value.type) { 19 | context.report( 20 | property, 21 | `Expected ${property.key.name} operator value to be an object.` 22 | ); 23 | return false; 24 | } 25 | return property.value.properties.every(propertyNode => { 26 | if ( 27 | !utils.nodeIsDynamic(propertyNode.value) && 28 | !utils.nodeWillBeString(propertyNode.value) 29 | ) { 30 | context.report( 31 | propertyNode, 32 | `${property.key.name} operator require strings (key: ${ 33 | propertyNode.key.name 34 | }).` 35 | ); 36 | return false; 37 | } 38 | return true; 39 | }); 40 | }); 41 | } 42 | ); 43 | } 44 | 45 | module.exports = eMQCheckRenameUpdates; 46 | -------------------------------------------------------------------------------- /src/lib/rules/check-rename-updates.mocha.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | const RuleTester = require('eslint').RuleTester; 4 | const rule = require('./check-rename-updates'); 5 | 6 | const ruleTester = new RuleTester(); 7 | 8 | ruleTester.run('check-rename-updates', rule, { 9 | valid: [ 10 | "db.collection('users').updateMany({}, { $rename: { qty: 'quantity' } });", 11 | "mongoClient.db.collection('users').updateMany({}, { $rename: { qty: newName } });", // Computed 12 | "mongoClient.db.collection('users').updateMany({}, { $rename: { qty: 'quantity', qty2: newName, } });", // Mix 13 | ], 14 | invalid: [ 15 | { 16 | code: "db.collection('users').updateMany({}, { $rename: 'test' });", 17 | errors: [ 18 | { 19 | message: 'Expected $rename operator value to be an object.', 20 | }, 21 | ], 22 | }, 23 | { 24 | code: 25 | "mongoClient.db.collection('users').updateMany({}, { $rename: { test: 1664 } });", 26 | errors: [ 27 | { 28 | message: '$rename operator require strings (key: test).', 29 | }, 30 | ], 31 | }, 32 | ], 33 | }); 34 | -------------------------------------------------------------------------------- /src/lib/rules/check-set-updates.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | const utils = require('../utils'); 4 | 5 | function eMQCheckSetUpdates(context) { 6 | return utils.lookupCall( 7 | context, 8 | utils.getCallPatterns('update', context.settings), 9 | (callSource, args) => { 10 | if ( 11 | !args[1] || 12 | 'ObjectExpression' !== args[1].type || 13 | !args[1].properties.length 14 | ) { 15 | return false; 16 | } 17 | return utils.everyProperties( 18 | args[1], 19 | [/\$(set|setOnInsert)/], 20 | property => { 21 | if ('ObjectExpression' !== property.value.type) { 22 | context.report( 23 | property, 24 | `Expected ${property.key.name} operator value to be an object.` 25 | ); 26 | return false; 27 | } 28 | return true; 29 | } 30 | ); 31 | } 32 | ); 33 | } 34 | 35 | module.exports = eMQCheckSetUpdates; 36 | -------------------------------------------------------------------------------- /src/lib/rules/check-set-updates.mocha.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | const RuleTester = require('eslint').RuleTester; 4 | const rule = require('./check-set-updates'); 5 | 6 | const ruleTester = new RuleTester(); 7 | 8 | ruleTester.run('check-set-updates', rule, { 9 | valid: [ 10 | "db.collection('users').updateMany({}, { $set: { qty: '', schmilbick: plop, truc: false } });", 11 | "db.collection('users').updateMany({}, { $setOnInsert: { qty: { schmilbick: plop, truc: false } } });", 12 | ], 13 | invalid: [ 14 | { 15 | code: "db.collection('users').updateMany({}, { $set: 'test' });", 16 | errors: [ 17 | { 18 | message: 'Expected $set operator value to be an object.', 19 | }, 20 | ], 21 | }, 22 | ], 23 | }); 24 | -------------------------------------------------------------------------------- /src/lib/rules/check-unset-updates.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | const utils = require('../utils'); 4 | 5 | function eMQCheckUnsetUpdates(context) { 6 | return utils.lookupCall( 7 | context, 8 | utils.getCallPatterns('update', context.settings), 9 | (callSource, args) => { 10 | if ( 11 | !args[1] || 12 | 'ObjectExpression' !== args[1].type || 13 | !args[1].properties.length 14 | ) { 15 | return false; 16 | } 17 | return utils.everyProperties(args[1], [/\$unset/], property => { 18 | if ('ObjectExpression' !== property.value.type) { 19 | context.report( 20 | property, 21 | `Expected ${property.key.name} operator value to be an object.` 22 | ); 23 | return false; 24 | } 25 | return property.value.properties.every(propertyNode => { 26 | if ( 27 | utils.nodeIsDynamic(propertyNode.value) || 28 | // ^ No sense to have a dynamic expression returning empty strings?? 29 | !utils.nodeIsEmptyString(propertyNode.value) 30 | ) { 31 | context.report( 32 | propertyNode, 33 | `${ 34 | property.key.name 35 | } operator require deleted keys to be set to empty strings (key: ${ 36 | propertyNode.key.name 37 | }).` 38 | ); 39 | return false; 40 | } 41 | return true; 42 | }); 43 | }); 44 | } 45 | ); 46 | } 47 | 48 | module.exports = eMQCheckUnsetUpdates; 49 | -------------------------------------------------------------------------------- /src/lib/rules/check-unset-updates.mocha.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | const RuleTester = require('eslint').RuleTester; 4 | const rule = require('./check-unset-updates'); 5 | 6 | const ruleTester = new RuleTester(); 7 | 8 | ruleTester.run('check-unset-updates', rule, { 9 | valid: [ 10 | "db.collection('users').updateMany({}, { $unset: { qty: '', schmilbick: '' } });", 11 | ], 12 | invalid: [ 13 | { 14 | code: "db.collection('users').updateMany({}, { $unset: 'test' });", 15 | errors: [ 16 | { 17 | message: 'Expected $unset operator value to be an object.', 18 | }, 19 | ], 20 | }, 21 | { 22 | code: 23 | "mongoClient.db.collection('users').updateMany({}, { $unset: { qty: newName } });", 24 | errors: [ 25 | { 26 | message: 27 | '$unset operator require deleted keys to be set to empty strings (key: qty).', 28 | }, 29 | ], 30 | }, 31 | { 32 | code: 33 | "mongoClient.db.collection('users').updateMany({}, { $unset: { test: 1664 } });", 34 | errors: [ 35 | { 36 | message: 37 | '$unset operator require deleted keys to be set to empty strings (key: test).', 38 | }, 39 | ], 40 | }, 41 | ], 42 | }); 43 | -------------------------------------------------------------------------------- /src/lib/rules/check-update-calls.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | const utils = require('../utils'); 4 | 5 | function eMQCheckUpdateCalls(context) { 6 | return utils.lookupCall( 7 | context, 8 | utils.getCallPatterns('update', context.settings), 9 | (callSource, args, node) => { 10 | if (!args[0] || !args[1]) { 11 | context.report( 12 | node, 13 | `Expected ${callSource} to have at least 2 arguments.` 14 | ); 15 | return false; 16 | } 17 | if ( 18 | !args[0] || 19 | (!utils.nodeIsDynamic(args[0]) && 'ObjectExpression' !== args[0].type) 20 | ) { 21 | context.report( 22 | args[0], 23 | `Expected ${callSource} call first argument value to be an object.` 24 | ); 25 | return false; 26 | } 27 | if ( 28 | !args[1] || 29 | (!utils.nodeIsDynamic(args[1]) && 'ObjectExpression' !== args[1].type) 30 | ) { 31 | context.report( 32 | args[1], 33 | `Expected ${callSource} call second argument value to be an object.` 34 | ); 35 | return false; 36 | } 37 | if ( 38 | args[2] && 39 | (!utils.nodeIsDynamic(args[2]) && 40 | 'ObjectExpression' !== args[2].type && 41 | 'FunctionExpression' !== args[2].type) 42 | ) { 43 | context.report( 44 | args[2], 45 | `Expected ${callSource} call third argument value to be an object or a callback function.` 46 | ); 47 | return false; 48 | } 49 | if ( 50 | args[3] && 51 | ('ObjectExpression' === args[3].type || 52 | (!utils.nodeIsDynamic(args[3]) && 53 | 'FunctionExpression' !== args[3].type)) 54 | ) { 55 | context.report( 56 | args[3], 57 | `Expected ${callSource} call fourth argument value to be a callback function.` 58 | ); 59 | return false; 60 | } 61 | if (args[4]) { 62 | context.report( 63 | node, 64 | `Expected ${callSource} call to have maximum 4 arguments.` 65 | ); 66 | return false; 67 | } 68 | return true; 69 | } 70 | ); 71 | } 72 | 73 | module.exports = eMQCheckUpdateCalls; 74 | -------------------------------------------------------------------------------- /src/lib/rules/check-update-calls.mocha.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | const RuleTester = require('eslint').RuleTester; 4 | const rule = require('./check-update-calls'); 5 | 6 | const ruleTester = new RuleTester(); 7 | 8 | ruleTester.run('check-update-calls', rule, { 9 | valid: [ 10 | "db.collection('users').updateMany({}, { $rename: { qty: 'quantity' } });", 11 | "mongoClient.db.collection('users').updateOne({}, { $rename: { qty: newName } }, {});", 12 | "mongoClient.db.collection('users').updateMany(gen(), {}, {});", 13 | "mongoClient.db.collection('users').updateOne(ref, {}, {});", 14 | "mongoClient.db.collection('users').updateMany(gen(), gen(), gen());", 15 | "mongoClient.db.collection('users').updateOne(ref, ref, ref);", 16 | ], 17 | invalid: [ 18 | { 19 | code: "db.collection('users').updateMany();", 20 | errors: [ 21 | { 22 | message: 23 | "Expected db.collection('users').updateMany to have at least 2 arguments.", 24 | }, 25 | ], 26 | }, 27 | { 28 | code: "db.collection('users').updateOne({});", 29 | errors: [ 30 | { 31 | message: 32 | "Expected db.collection('users').updateOne to have at least 2 arguments.", 33 | }, 34 | ], 35 | }, 36 | { 37 | code: "mongoClient.db.collection('users').updateOne('test', {});", 38 | errors: [ 39 | { 40 | message: 41 | "Expected mongoClient.db.collection('users').updateOne call first argument value to be an object.", 42 | }, 43 | ], 44 | }, 45 | { 46 | code: "mongoClient.db.collection('users').updateMany({}, 'test');", 47 | errors: [ 48 | { 49 | message: 50 | "Expected mongoClient.db.collection('users').updateMany call second argument value to be an object.", 51 | }, 52 | ], 53 | }, 54 | { 55 | code: "mongoClient.db.collection('users').updateOne({}, {}, 'test');", 56 | errors: [ 57 | { 58 | message: 59 | "Expected mongoClient.db.collection('users').updateOne call third argument value to be an object or a callback function.", 60 | }, 61 | ], 62 | }, 63 | { 64 | code: 65 | "mongoClient.db.collection('users').updateOne({}, {}, function() {}, {});", 66 | errors: [ 67 | { 68 | message: 69 | "Expected mongoClient.db.collection('users').updateOne call fourth argument value to be a callback function.", 70 | }, 71 | ], 72 | }, 73 | { 74 | code: 75 | "mongoClient.db.collection('users').updateOne({}, {}, {}, function() {}, function() {});", 76 | errors: [ 77 | { 78 | message: 79 | "Expected mongoClient.db.collection('users').updateOne call to have maximum 4 arguments.", 80 | }, 81 | ], 82 | }, 83 | ], 84 | }); 85 | -------------------------------------------------------------------------------- /src/lib/rules/no-replace.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | const utils = require('../utils'); 4 | 5 | function eMQNoReplace(context) { 6 | return utils.lookupCall( 7 | context, 8 | utils.getCallPatterns('update', context.settings), 9 | (callSource, args) => { 10 | if (!args[1] || 'ObjectExpression' !== args[1].type) { 11 | return false; 12 | } 13 | return utils.everyProperties(args[1], [/[^\$].*/], property => { 14 | if (0 !== property.key.name.indexOf('$')) { 15 | context.report( 16 | property, 17 | 'Raw update of a complete collection entry.' 18 | ); 19 | return false; 20 | } 21 | }); 22 | } 23 | ); 24 | } 25 | 26 | module.exports = eMQNoReplace; 27 | -------------------------------------------------------------------------------- /src/lib/rules/no-replace.mocha.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | const RuleTester = require('eslint').RuleTester; 4 | const rule = require('./no-replace'); 5 | 6 | const ruleTester = new RuleTester(); 7 | 8 | ruleTester.run('no-replace', rule, { 9 | valid: [ 10 | "db.collection('users').updateMany({}, { $set: { name: 'test' }});", 11 | "mongoClient.db.collection('users').update({}, { $set: { name: 'test' }});", 12 | "db.collection('users').updateMany({}, {});", 13 | "db.collection('users').updateMany({}, hey);", 14 | "db.collection('users').updateMany({});", 15 | ], 16 | invalid: [ 17 | { 18 | code: "db.collection('users').updateMany({}, { name: 'test' });", 19 | errors: [ 20 | { 21 | message: 'Raw update of a complete collection entry.', 22 | }, 23 | ], 24 | }, 25 | ], 26 | }); 27 | -------------------------------------------------------------------------------- /src/lib/utils.js: -------------------------------------------------------------------------------- 1 | /* eslint max-len:[1] */ 2 | 3 | 'use strict'; 4 | 5 | const YError = require('yerror'); 6 | 7 | const utils = { 8 | CALL_PATTERNS: { 9 | // See http://docs.mongodb.org/master/reference/method/js-collection/ 10 | QUERY: [/(\.|^)db\.collection\([^\)]+\)\.(find|findOne|)$/], 11 | UPDATE: [ 12 | /(\.|^)db\.collection\([^\)]+\)\.(findOneAndUpdate|updateOne|updateMany)$/, 13 | ], 14 | INSERT: [/(\.|^)db\.collection\([^\)]+\)\.(insertOne|insertMany)$/], 15 | REMOVE: [ 16 | /(\.|^)db\.collection\([^\)]+\)\.(findOneAndDelete|deleteOne|deleteMany)$/, 17 | ], 18 | DEPRECATED: [ 19 | /(\.|^)db\.collection\([^\)]+\)\.(remove|update|findAndModify|ensureIndex|findAndRemove|insert|dropAllIndexes)$/, 20 | ], 21 | }, 22 | getAllCallPatterns, 23 | getCallPatterns, 24 | nodeIsDynamic, 25 | nodeWillBeString, 26 | nodeWillBeNumber, 27 | nodeWillBeBoolean, 28 | lookupCall, 29 | everyProperties, 30 | nodeIsEmptyString, 31 | nodeIsString, 32 | nodeIsTrue, 33 | nodeIsArray, 34 | nodeIsEmptyArray, 35 | }; 36 | 37 | function getAllCallPatterns(settings) { 38 | return Object.keys(utils.CALL_PATTERNS).reduce( 39 | (patterns, type) => 40 | patterns.concat(utils.getCallPatterns(type.toLowerCase(), settings)), 41 | [] 42 | ); 43 | } 44 | 45 | function getCallPatterns(type, settings) { 46 | if ( 47 | settings && 48 | settings.mongodb && 49 | settings.mongodb.callPatterns && 50 | settings.mongodb.callPatterns[type] 51 | ) { 52 | return settings.mongodb.callPatterns[type].map( 53 | pattern => new RegExp(pattern) 54 | ); 55 | } 56 | return utils.CALL_PATTERNS[type.toUpperCase()]; 57 | } 58 | 59 | function lookupCall(context, callPatterns, cb) { 60 | return { 61 | CallExpression: function(node) { 62 | const functionCallSource = context.getSource(node.callee); 63 | 64 | return callPatterns.some(function(callPattern) { 65 | if (callPattern.exec(functionCallSource)) { 66 | cb.call(this, functionCallSource, node.arguments, node); 67 | return true; 68 | } 69 | return false; 70 | }); 71 | }, 72 | }; 73 | } 74 | 75 | function everyProperties(node, propertyPatterns, cb) { 76 | if ('ObjectExpression' !== node.type) { 77 | throw new YError('E_BAD_NODE', node.type); 78 | } 79 | return node.properties.every(property => { 80 | // Discard computed properties (maybe warn as harmful in another rule?) 81 | if ('Identifier' !== property.key.type) { 82 | return true; 83 | } 84 | if ( 85 | propertyPatterns.some( 86 | propertyPattern => !!propertyPattern.exec(property.key.name) 87 | ) 88 | ) { 89 | return cb(property); 90 | } 91 | return true; 92 | }); 93 | } 94 | 95 | function nodeIsDynamic(node) { 96 | if ('Literal' === node.type) { 97 | return false; 98 | } 99 | if ('UnaryExpression' === node.type) { 100 | return nodeIsDynamic(node.argument); 101 | } 102 | if ('BinaryExpression' === node.type) { 103 | return nodeIsDynamic(node.left) || nodeIsDynamic(node.right); 104 | } 105 | if ('ObjectExpression' === node.type) { 106 | return node.properties.every(nodeIsDynamic); 107 | } 108 | if ('ArrayExpression' === node.type) { 109 | return node.elements.every(nodeIsDynamic); 110 | } 111 | if ('Property' === node.type) { 112 | return nodeIsDynamic(node.value); 113 | } 114 | return true; 115 | } 116 | 117 | function nodeIsTrue(node) { 118 | if ('Literal' === node.type) { 119 | return true === String(node.value); 120 | } 121 | return false; 122 | } 123 | 124 | function nodeIsEmptyString(node) { 125 | if ('Literal' === node.type) { 126 | return '' === String(node.value); 127 | } 128 | return false; 129 | } 130 | 131 | function nodeIsString(node) { 132 | return 'Literal' === node.type && String(node.value) === node.value; 133 | } 134 | 135 | function nodeWillBeString(node) { 136 | if (nodeIsString(node)) { 137 | return true; 138 | } else if ('UnaryExpression' === node.type) { 139 | return nodeWillBeString(node.argument); 140 | } else if ('BinaryExpression' === node.type) { 141 | return nodeWillBeString(node.left) && nodeWillBeString(node.right); 142 | } 143 | return false; 144 | } 145 | 146 | function nodeWillBeNumber(node) { 147 | if ('Literal' === node.type) { 148 | return Number(node.value) === node.value; 149 | } else if ('UnaryExpression' === node.type) { 150 | return nodeWillBeNumber(node.argument); 151 | } else if ('BinaryExpression' === node.type) { 152 | return nodeWillBeNumber(node.left) && nodeWillBeNumber(node.right); 153 | } 154 | return false; 155 | } 156 | 157 | function nodeWillBeBoolean(node) { 158 | if ('Literal' === node.type) { 159 | return Boolean(node.value) === node.value; 160 | } else if ('UnaryExpression' === node.type) { 161 | return '!' === node.operator; 162 | } 163 | return false; 164 | } 165 | 166 | function nodeIsArray(node) { 167 | return 'ArrayExpression' === node.type; 168 | } 169 | 170 | function nodeIsEmptyArray(node) { 171 | return nodeIsArray(node) && 0 === node.elements.length; 172 | } 173 | 174 | module.exports = utils; 175 | -------------------------------------------------------------------------------- /yarn.lock: -------------------------------------------------------------------------------- 1 | # THIS IS AN AUTOGENERATED FILE. DO NOT EDIT THIS FILE DIRECTLY. 2 | # yarn lockfile v1 3 | 4 | 5 | abbrev@1: 6 | version "1.1.1" 7 | resolved "https://registry.yarnpkg.com/abbrev/-/abbrev-1.1.1.tgz#f8f2c887ad10bf67f634f005b6987fed3179aac8" 8 | 9 | abbrev@1.0.x: 10 | version "1.0.9" 11 | resolved "https://registry.yarnpkg.com/abbrev/-/abbrev-1.0.9.tgz#91b4792588a7738c25f35dd6f63752a2f8776135" 12 | 13 | acorn-jsx@^3.0.0: 14 | version "3.0.1" 15 | resolved "https://registry.yarnpkg.com/acorn-jsx/-/acorn-jsx-3.0.1.tgz#afdf9488fb1ecefc8348f6fb22f464e32a58b36b" 16 | dependencies: 17 | acorn "^3.0.4" 18 | 19 | acorn@^3.0.4: 20 | version "3.3.0" 21 | resolved "https://registry.yarnpkg.com/acorn/-/acorn-3.3.0.tgz#45e37fb39e8da3f25baee3ff5369e2bb5f22017a" 22 | 23 | acorn@^5.5.0: 24 | version "5.7.1" 25 | resolved "https://registry.yarnpkg.com/acorn/-/acorn-5.7.1.tgz#f095829297706a7c9776958c0afc8930a9b9d9d8" 26 | 27 | ajv-keywords@^2.1.0: 28 | version "2.1.1" 29 | resolved "https://registry.yarnpkg.com/ajv-keywords/-/ajv-keywords-2.1.1.tgz#617997fc5f60576894c435f940d819e135b80762" 30 | 31 | ajv@^5.1.0, ajv@^5.2.3, ajv@^5.3.0: 32 | version "5.5.2" 33 | resolved "https://registry.yarnpkg.com/ajv/-/ajv-5.5.2.tgz#73b5eeca3fab653e3d3f9422b341ad42205dc965" 34 | dependencies: 35 | co "^4.6.0" 36 | fast-deep-equal "^1.0.0" 37 | fast-json-stable-stringify "^2.0.0" 38 | json-schema-traverse "^0.3.0" 39 | 40 | amdefine@>=0.0.4: 41 | version "1.0.1" 42 | resolved "https://registry.yarnpkg.com/amdefine/-/amdefine-1.0.1.tgz#4a5282ac164729e93619bcfd3ad151f817ce91f5" 43 | 44 | ansi-escapes@^3.0.0: 45 | version "3.1.0" 46 | resolved "https://registry.yarnpkg.com/ansi-escapes/-/ansi-escapes-3.1.0.tgz#f73207bb81207d75fd6c83f125af26eea378ca30" 47 | 48 | ansi-regex@^2.0.0: 49 | version "2.1.1" 50 | resolved "https://registry.yarnpkg.com/ansi-regex/-/ansi-regex-2.1.1.tgz#c3b33ab5ee360d86e0e628f0468ae7ef27d654df" 51 | 52 | ansi-regex@^3.0.0: 53 | version "3.0.0" 54 | resolved "https://registry.yarnpkg.com/ansi-regex/-/ansi-regex-3.0.0.tgz#ed0317c322064f79466c02966bddb605ab37d998" 55 | 56 | ansi-styles@^2.2.1: 57 | version "2.2.1" 58 | resolved "https://registry.yarnpkg.com/ansi-styles/-/ansi-styles-2.2.1.tgz#b432dd3358b634cf75e1e4664368240533c1ddbe" 59 | 60 | ansi-styles@^3.2.1: 61 | version "3.2.1" 62 | resolved "https://registry.yarnpkg.com/ansi-styles/-/ansi-styles-3.2.1.tgz#41fbb20243e50b12be0f04b8dedbf07520ce841d" 63 | dependencies: 64 | color-convert "^1.9.0" 65 | 66 | argparse@^1.0.7: 67 | version "1.0.10" 68 | resolved "https://registry.yarnpkg.com/argparse/-/argparse-1.0.10.tgz#bcd6791ea5ae09725e17e5ad988134cd40b3d911" 69 | dependencies: 70 | sprintf-js "~1.0.2" 71 | 72 | array-union@^1.0.1: 73 | version "1.0.2" 74 | resolved "https://registry.yarnpkg.com/array-union/-/array-union-1.0.2.tgz#9a34410e4f4e3da23dea375be5be70f24778ec39" 75 | dependencies: 76 | array-uniq "^1.0.1" 77 | 78 | array-uniq@^1.0.1: 79 | version "1.0.3" 80 | resolved "https://registry.yarnpkg.com/array-uniq/-/array-uniq-1.0.3.tgz#af6ac877a25cc7f74e058894753858dfdb24fdb6" 81 | 82 | arrify@^1.0.0: 83 | version "1.0.1" 84 | resolved "https://registry.yarnpkg.com/arrify/-/arrify-1.0.1.tgz#898508da2226f380df904728456849c1501a4b0d" 85 | 86 | asn1@~0.2.3: 87 | version "0.2.3" 88 | resolved "https://registry.yarnpkg.com/asn1/-/asn1-0.2.3.tgz#dac8787713c9966849fc8180777ebe9c1ddf3b86" 89 | 90 | assert-plus@1.0.0, assert-plus@^1.0.0: 91 | version "1.0.0" 92 | resolved "https://registry.yarnpkg.com/assert-plus/-/assert-plus-1.0.0.tgz#f12e0f3c5d77b0b1cdd9146942e4e96c1e4dd525" 93 | 94 | async@1.x: 95 | version "1.5.2" 96 | resolved "https://registry.yarnpkg.com/async/-/async-1.5.2.tgz#ec6a61ae56480c0c3cb241c95618e20892f9672a" 97 | 98 | asynckit@^0.4.0: 99 | version "0.4.0" 100 | resolved "https://registry.yarnpkg.com/asynckit/-/asynckit-0.4.0.tgz#c79ed97f7f34cb8f2ba1bc9790bcc366474b4b79" 101 | 102 | aws-sign2@~0.7.0: 103 | version "0.7.0" 104 | resolved "https://registry.yarnpkg.com/aws-sign2/-/aws-sign2-0.7.0.tgz#b46e890934a9591f2d2f6f86d7e6a9f1b3fe76a8" 105 | 106 | aws4@^1.6.0: 107 | version "1.7.0" 108 | resolved "https://registry.yarnpkg.com/aws4/-/aws4-1.7.0.tgz#d4d0e9b9dbfca77bf08eeb0a8a471550fe39e289" 109 | 110 | babel-code-frame@^6.22.0: 111 | version "6.26.0" 112 | resolved "https://registry.yarnpkg.com/babel-code-frame/-/babel-code-frame-6.26.0.tgz#63fd43f7dc1e3bb7ce35947db8fe369a3f58c74b" 113 | dependencies: 114 | chalk "^1.1.3" 115 | esutils "^2.0.2" 116 | js-tokens "^3.0.2" 117 | 118 | balanced-match@^1.0.0: 119 | version "1.0.0" 120 | resolved "https://registry.yarnpkg.com/balanced-match/-/balanced-match-1.0.0.tgz#89b4d199ab2bee49de164ea02b89ce462d71b767" 121 | 122 | bcrypt-pbkdf@^1.0.0: 123 | version "1.0.2" 124 | resolved "https://registry.yarnpkg.com/bcrypt-pbkdf/-/bcrypt-pbkdf-1.0.2.tgz#a4301d389b6a43f9b67ff3ca11a3f6637e360e9e" 125 | dependencies: 126 | tweetnacl "^0.14.3" 127 | 128 | brace-expansion@^1.1.7: 129 | version "1.1.11" 130 | resolved "https://registry.yarnpkg.com/brace-expansion/-/brace-expansion-1.1.11.tgz#3c7fcbf529d87226f3d2f52b966ff5271eb441dd" 131 | dependencies: 132 | balanced-match "^1.0.0" 133 | concat-map "0.0.1" 134 | 135 | browser-stdout@1.3.0: 136 | version "1.3.0" 137 | resolved "https://registry.yarnpkg.com/browser-stdout/-/browser-stdout-1.3.0.tgz#f351d32969d32fa5d7a5567154263d928ae3bd1f" 138 | 139 | buffer-from@^1.0.0: 140 | version "1.1.0" 141 | resolved "https://registry.yarnpkg.com/buffer-from/-/buffer-from-1.1.0.tgz#87fcaa3a298358e0ade6e442cfce840740d1ad04" 142 | 143 | caller-path@^0.1.0: 144 | version "0.1.0" 145 | resolved "https://registry.yarnpkg.com/caller-path/-/caller-path-0.1.0.tgz#94085ef63581ecd3daa92444a8fe94e82577751f" 146 | dependencies: 147 | callsites "^0.2.0" 148 | 149 | callsites@^0.2.0: 150 | version "0.2.0" 151 | resolved "https://registry.yarnpkg.com/callsites/-/callsites-0.2.0.tgz#afab96262910a7f33c19a5775825c69f34e350ca" 152 | 153 | caseless@~0.12.0: 154 | version "0.12.0" 155 | resolved "https://registry.yarnpkg.com/caseless/-/caseless-0.12.0.tgz#1b681c21ff84033c826543090689420d187151dc" 156 | 157 | chalk@^1.1.3: 158 | version "1.1.3" 159 | resolved "https://registry.yarnpkg.com/chalk/-/chalk-1.1.3.tgz#a8115c55e4a702fe4d150abd3872822a7e09fc98" 160 | dependencies: 161 | ansi-styles "^2.2.1" 162 | escape-string-regexp "^1.0.2" 163 | has-ansi "^2.0.0" 164 | strip-ansi "^3.0.0" 165 | supports-color "^2.0.0" 166 | 167 | chalk@^2.0.0, chalk@^2.1.0: 168 | version "2.4.1" 169 | resolved "https://registry.yarnpkg.com/chalk/-/chalk-2.4.1.tgz#18c49ab16a037b6eb0152cc83e3471338215b66e" 170 | dependencies: 171 | ansi-styles "^3.2.1" 172 | escape-string-regexp "^1.0.5" 173 | supports-color "^5.3.0" 174 | 175 | chardet@^0.4.0: 176 | version "0.4.2" 177 | resolved "https://registry.yarnpkg.com/chardet/-/chardet-0.4.2.tgz#b5473b33dc97c424e5d98dc87d55d4d8a29c8bf2" 178 | 179 | circular-json@^0.3.1: 180 | version "0.3.3" 181 | resolved "https://registry.yarnpkg.com/circular-json/-/circular-json-0.3.3.tgz#815c99ea84f6809529d2f45791bdf82711352d66" 182 | 183 | cli-cursor@^2.1.0: 184 | version "2.1.0" 185 | resolved "https://registry.yarnpkg.com/cli-cursor/-/cli-cursor-2.1.0.tgz#b35dac376479facc3e94747d41d0d0f5238ffcb5" 186 | dependencies: 187 | restore-cursor "^2.0.0" 188 | 189 | cli-width@^2.0.0: 190 | version "2.2.0" 191 | resolved "https://registry.yarnpkg.com/cli-width/-/cli-width-2.2.0.tgz#ff19ede8a9a5e579324147b0c11f0fbcbabed639" 192 | 193 | co@^4.6.0: 194 | version "4.6.0" 195 | resolved "https://registry.yarnpkg.com/co/-/co-4.6.0.tgz#6ea6bdf3d853ae54ccb8e47bfa0bf3f9031fb184" 196 | 197 | color-convert@^1.9.0: 198 | version "1.9.2" 199 | resolved "https://registry.yarnpkg.com/color-convert/-/color-convert-1.9.2.tgz#49881b8fba67df12a96bdf3f56c0aab9e7913147" 200 | dependencies: 201 | color-name "1.1.1" 202 | 203 | color-name@1.1.1: 204 | version "1.1.1" 205 | resolved "https://registry.yarnpkg.com/color-name/-/color-name-1.1.1.tgz#4b1415304cf50028ea81643643bd82ea05803689" 206 | 207 | combined-stream@1.0.6, combined-stream@~1.0.5: 208 | version "1.0.6" 209 | resolved "https://registry.yarnpkg.com/combined-stream/-/combined-stream-1.0.6.tgz#723e7df6e801ac5613113a7e445a9b69cb632818" 210 | dependencies: 211 | delayed-stream "~1.0.0" 212 | 213 | commander@2.11.0: 214 | version "2.11.0" 215 | resolved "https://registry.yarnpkg.com/commander/-/commander-2.11.0.tgz#157152fd1e7a6c8d98a5b715cf376df928004563" 216 | 217 | commander@~2.20.3: 218 | version "2.20.3" 219 | resolved "https://registry.yarnpkg.com/commander/-/commander-2.20.3.tgz#fd485e84c03eb4881c20722ba48035e8531aeb33" 220 | 221 | concat-map@0.0.1: 222 | version "0.0.1" 223 | resolved "https://registry.yarnpkg.com/concat-map/-/concat-map-0.0.1.tgz#d8a96bd77fd68df7793a73036a3ba0d5405d477b" 224 | 225 | concat-stream@^1.6.0: 226 | version "1.6.2" 227 | resolved "https://registry.yarnpkg.com/concat-stream/-/concat-stream-1.6.2.tgz#904bdf194cd3122fc675c77fc4ac3d4ff0fd1a34" 228 | dependencies: 229 | buffer-from "^1.0.0" 230 | inherits "^2.0.3" 231 | readable-stream "^2.2.2" 232 | typedarray "^0.0.6" 233 | 234 | core-util-is@1.0.2, core-util-is@~1.0.0: 235 | version "1.0.2" 236 | resolved "https://registry.yarnpkg.com/core-util-is/-/core-util-is-1.0.2.tgz#b5fd54220aa2bc5ab57aab7140c940754503c1a7" 237 | 238 | coveralls@^3.0.0: 239 | version "3.0.2" 240 | resolved "https://registry.yarnpkg.com/coveralls/-/coveralls-3.0.2.tgz#f5a0bcd90ca4e64e088b710fa8dda640aea4884f" 241 | dependencies: 242 | growl "~> 1.10.0" 243 | js-yaml "^3.11.0" 244 | lcov-parse "^0.0.10" 245 | log-driver "^1.2.7" 246 | minimist "^1.2.0" 247 | request "^2.85.0" 248 | 249 | cross-spawn@^5.1.0: 250 | version "5.1.0" 251 | resolved "https://registry.yarnpkg.com/cross-spawn/-/cross-spawn-5.1.0.tgz#e8bd0efee58fcff6f8f94510a0a554bbfa235449" 252 | dependencies: 253 | lru-cache "^4.0.1" 254 | shebang-command "^1.2.0" 255 | which "^1.2.9" 256 | 257 | dashdash@^1.12.0: 258 | version "1.14.1" 259 | resolved "https://registry.yarnpkg.com/dashdash/-/dashdash-1.14.1.tgz#853cfa0f7cbe2fed5de20326b8dd581035f6e2f0" 260 | dependencies: 261 | assert-plus "^1.0.0" 262 | 263 | debug@3.1.0, debug@^3.1.0: 264 | version "3.1.0" 265 | resolved "https://registry.yarnpkg.com/debug/-/debug-3.1.0.tgz#5bb5a0672628b64149566ba16819e61518c67261" 266 | dependencies: 267 | ms "2.0.0" 268 | 269 | deep-is@~0.1.3: 270 | version "0.1.3" 271 | resolved "https://registry.yarnpkg.com/deep-is/-/deep-is-0.1.3.tgz#b369d6fb5dbc13eecf524f91b070feedc357cf34" 272 | 273 | del@^2.0.2: 274 | version "2.2.2" 275 | resolved "https://registry.yarnpkg.com/del/-/del-2.2.2.tgz#c12c981d067846c84bcaf862cff930d907ffd1a8" 276 | dependencies: 277 | globby "^5.0.0" 278 | is-path-cwd "^1.0.0" 279 | is-path-in-cwd "^1.0.0" 280 | object-assign "^4.0.1" 281 | pify "^2.0.0" 282 | pinkie-promise "^2.0.0" 283 | rimraf "^2.2.8" 284 | 285 | delayed-stream@~1.0.0: 286 | version "1.0.0" 287 | resolved "https://registry.yarnpkg.com/delayed-stream/-/delayed-stream-1.0.0.tgz#df3ae199acadfb7d440aaae0b29e2272b24ec619" 288 | 289 | diff@3.3.1: 290 | version "3.3.1" 291 | resolved "https://registry.yarnpkg.com/diff/-/diff-3.3.1.tgz#aa8567a6eed03c531fc89d3f711cd0e5259dec75" 292 | 293 | doctrine@^2.1.0: 294 | version "2.1.0" 295 | resolved "https://registry.yarnpkg.com/doctrine/-/doctrine-2.1.0.tgz#5cd01fc101621b42c4cd7f5d1a66243716d3f39d" 296 | dependencies: 297 | esutils "^2.0.2" 298 | 299 | ecc-jsbn@~0.1.1: 300 | version "0.1.1" 301 | resolved "https://registry.yarnpkg.com/ecc-jsbn/-/ecc-jsbn-0.1.1.tgz#0fc73a9ed5f0d53c38193398523ef7e543777505" 302 | dependencies: 303 | jsbn "~0.1.0" 304 | 305 | escape-string-regexp@1.0.5, escape-string-regexp@^1.0.2, escape-string-regexp@^1.0.5: 306 | version "1.0.5" 307 | resolved "https://registry.yarnpkg.com/escape-string-regexp/-/escape-string-regexp-1.0.5.tgz#1b61c0562190a8dff6ae3bb2cf0200ca130b86d4" 308 | 309 | escodegen@1.8.x: 310 | version "1.8.1" 311 | resolved "https://registry.yarnpkg.com/escodegen/-/escodegen-1.8.1.tgz#5a5b53af4693110bebb0867aa3430dd3b70a1018" 312 | dependencies: 313 | esprima "^2.7.1" 314 | estraverse "^1.9.1" 315 | esutils "^2.0.2" 316 | optionator "^0.8.1" 317 | optionalDependencies: 318 | source-map "~0.2.0" 319 | 320 | eslint-config-angular@0.5.0: 321 | version "0.5.0" 322 | resolved "https://registry.yarnpkg.com/eslint-config-angular/-/eslint-config-angular-0.5.0.tgz#e0aae0132e39e7467df3f7547fec81a44d3685c4" 323 | 324 | eslint-config-simplifield@^7.1.1: 325 | version "7.1.1" 326 | resolved "https://registry.yarnpkg.com/eslint-config-simplifield/-/eslint-config-simplifield-7.1.1.tgz#d208f0cf2ca8a099a263b280b705fd4f4954653f" 327 | dependencies: 328 | eslint-config-angular "0.5.0" 329 | eslint-plugin-angular "3.1.1" 330 | eslint-plugin-mongodb "1.0.0" 331 | eslint-plugin-node "5.2.1" 332 | eslint-plugin-promise "3.6.0" 333 | eslint-plugin-security "1.4.0" 334 | 335 | eslint-plugin-angular@3.1.1: 336 | version "3.1.1" 337 | resolved "https://registry.yarnpkg.com/eslint-plugin-angular/-/eslint-plugin-angular-3.1.1.tgz#b4ea24daa83c375820b59684b5f1adb474b5d946" 338 | 339 | eslint-plugin-mongodb@1.0.0: 340 | version "1.0.0" 341 | resolved "https://registry.yarnpkg.com/eslint-plugin-mongodb/-/eslint-plugin-mongodb-1.0.0.tgz#bbff863dde435664c6bde3bcc51a1c760eedba79" 342 | dependencies: 343 | yerror "^2.1.0" 344 | 345 | eslint-plugin-node@5.2.1: 346 | version "5.2.1" 347 | resolved "https://registry.yarnpkg.com/eslint-plugin-node/-/eslint-plugin-node-5.2.1.tgz#80df3253c4d7901045ec87fa660a284e32bdca29" 348 | dependencies: 349 | ignore "^3.3.6" 350 | minimatch "^3.0.4" 351 | resolve "^1.3.3" 352 | semver "5.3.0" 353 | 354 | eslint-plugin-promise@3.6.0: 355 | version "3.6.0" 356 | resolved "https://registry.yarnpkg.com/eslint-plugin-promise/-/eslint-plugin-promise-3.6.0.tgz#54b7658c8f454813dc2a870aff8152ec4969ba75" 357 | 358 | eslint-plugin-security@1.4.0: 359 | version "1.4.0" 360 | resolved "https://registry.yarnpkg.com/eslint-plugin-security/-/eslint-plugin-security-1.4.0.tgz#d4f314484a80b1b613b8c8886e84f52efe1526c2" 361 | dependencies: 362 | safe-regex "^1.1.0" 363 | 364 | eslint-scope@^3.7.1: 365 | version "3.7.3" 366 | resolved "https://registry.yarnpkg.com/eslint-scope/-/eslint-scope-3.7.3.tgz#bb507200d3d17f60247636160b4826284b108535" 367 | dependencies: 368 | esrecurse "^4.1.0" 369 | estraverse "^4.1.1" 370 | 371 | eslint-visitor-keys@^1.0.0: 372 | version "1.0.0" 373 | resolved "https://registry.yarnpkg.com/eslint-visitor-keys/-/eslint-visitor-keys-1.0.0.tgz#3f3180fb2e291017716acb4c9d6d5b5c34a6a81d" 374 | 375 | eslint@4: 376 | version "4.19.1" 377 | resolved "https://registry.yarnpkg.com/eslint/-/eslint-4.19.1.tgz#32d1d653e1d90408854bfb296f076ec7e186a300" 378 | dependencies: 379 | ajv "^5.3.0" 380 | babel-code-frame "^6.22.0" 381 | chalk "^2.1.0" 382 | concat-stream "^1.6.0" 383 | cross-spawn "^5.1.0" 384 | debug "^3.1.0" 385 | doctrine "^2.1.0" 386 | eslint-scope "^3.7.1" 387 | eslint-visitor-keys "^1.0.0" 388 | espree "^3.5.4" 389 | esquery "^1.0.0" 390 | esutils "^2.0.2" 391 | file-entry-cache "^2.0.0" 392 | functional-red-black-tree "^1.0.1" 393 | glob "^7.1.2" 394 | globals "^11.0.1" 395 | ignore "^3.3.3" 396 | imurmurhash "^0.1.4" 397 | inquirer "^3.0.6" 398 | is-resolvable "^1.0.0" 399 | js-yaml "^3.9.1" 400 | json-stable-stringify-without-jsonify "^1.0.1" 401 | levn "^0.3.0" 402 | lodash "^4.17.4" 403 | minimatch "^3.0.2" 404 | mkdirp "^0.5.1" 405 | natural-compare "^1.4.0" 406 | optionator "^0.8.2" 407 | path-is-inside "^1.0.2" 408 | pluralize "^7.0.0" 409 | progress "^2.0.0" 410 | regexpp "^1.0.1" 411 | require-uncached "^1.0.3" 412 | semver "^5.3.0" 413 | strip-ansi "^4.0.0" 414 | strip-json-comments "~2.0.1" 415 | table "4.0.2" 416 | text-table "~0.2.0" 417 | 418 | espree@^3.5.4: 419 | version "3.5.4" 420 | resolved "https://registry.yarnpkg.com/espree/-/espree-3.5.4.tgz#b0f447187c8a8bed944b815a660bddf5deb5d1a7" 421 | dependencies: 422 | acorn "^5.5.0" 423 | acorn-jsx "^3.0.0" 424 | 425 | esprima@2.7.x, esprima@^2.7.1: 426 | version "2.7.3" 427 | resolved "https://registry.yarnpkg.com/esprima/-/esprima-2.7.3.tgz#96e3b70d5779f6ad49cd032673d1c312767ba581" 428 | 429 | esprima@^4.0.0: 430 | version "4.0.1" 431 | resolved "https://registry.yarnpkg.com/esprima/-/esprima-4.0.1.tgz#13b04cdb3e6c5d19df91ab6987a8695619b0aa71" 432 | 433 | esquery@^1.0.0: 434 | version "1.0.1" 435 | resolved "https://registry.yarnpkg.com/esquery/-/esquery-1.0.1.tgz#406c51658b1f5991a5f9b62b1dc25b00e3e5c708" 436 | dependencies: 437 | estraverse "^4.0.0" 438 | 439 | esrecurse@^4.1.0: 440 | version "4.2.1" 441 | resolved "https://registry.yarnpkg.com/esrecurse/-/esrecurse-4.2.1.tgz#007a3b9fdbc2b3bb87e4879ea19c92fdbd3942cf" 442 | dependencies: 443 | estraverse "^4.1.0" 444 | 445 | estraverse@^1.9.1: 446 | version "1.9.3" 447 | resolved "https://registry.yarnpkg.com/estraverse/-/estraverse-1.9.3.tgz#af67f2dc922582415950926091a4005d29c9bb44" 448 | 449 | estraverse@^4.0.0, estraverse@^4.1.0, estraverse@^4.1.1: 450 | version "4.2.0" 451 | resolved "https://registry.yarnpkg.com/estraverse/-/estraverse-4.2.0.tgz#0dee3fed31fcd469618ce7342099fc1afa0bdb13" 452 | 453 | esutils@^2.0.2: 454 | version "2.0.2" 455 | resolved "https://registry.yarnpkg.com/esutils/-/esutils-2.0.2.tgz#0abf4f1caa5bcb1f7a9d8acc6dea4faaa04bac9b" 456 | 457 | extend@~3.0.1: 458 | version "3.0.2" 459 | resolved "https://registry.yarnpkg.com/extend/-/extend-3.0.2.tgz#f8b1136b4071fbd8eb140aff858b1019ec2915fa" 460 | 461 | external-editor@^2.0.4: 462 | version "2.2.0" 463 | resolved "https://registry.yarnpkg.com/external-editor/-/external-editor-2.2.0.tgz#045511cfd8d133f3846673d1047c154e214ad3d5" 464 | dependencies: 465 | chardet "^0.4.0" 466 | iconv-lite "^0.4.17" 467 | tmp "^0.0.33" 468 | 469 | extsprintf@1.3.0: 470 | version "1.3.0" 471 | resolved "https://registry.yarnpkg.com/extsprintf/-/extsprintf-1.3.0.tgz#96918440e3041a7a414f8c52e3c574eb3c3e1e05" 472 | 473 | extsprintf@^1.2.0: 474 | version "1.4.0" 475 | resolved "https://registry.yarnpkg.com/extsprintf/-/extsprintf-1.4.0.tgz#e2689f8f356fad62cca65a3a91c5df5f9551692f" 476 | 477 | fast-deep-equal@^1.0.0: 478 | version "1.1.0" 479 | resolved "https://registry.yarnpkg.com/fast-deep-equal/-/fast-deep-equal-1.1.0.tgz#c053477817c86b51daa853c81e059b733d023614" 480 | 481 | fast-json-stable-stringify@^2.0.0: 482 | version "2.0.0" 483 | resolved "https://registry.yarnpkg.com/fast-json-stable-stringify/-/fast-json-stable-stringify-2.0.0.tgz#d5142c0caee6b1189f87d3a76111064f86c8bbf2" 484 | 485 | fast-levenshtein@~2.0.4: 486 | version "2.0.6" 487 | resolved "https://registry.yarnpkg.com/fast-levenshtein/-/fast-levenshtein-2.0.6.tgz#3d8a5c66883a16a30ca8643e851f19baa7797917" 488 | 489 | figures@^2.0.0: 490 | version "2.0.0" 491 | resolved "https://registry.yarnpkg.com/figures/-/figures-2.0.0.tgz#3ab1a2d2a62c8bfb431a0c94cb797a2fce27c962" 492 | dependencies: 493 | escape-string-regexp "^1.0.5" 494 | 495 | file-entry-cache@^2.0.0: 496 | version "2.0.0" 497 | resolved "https://registry.yarnpkg.com/file-entry-cache/-/file-entry-cache-2.0.0.tgz#c392990c3e684783d838b8c84a45d8a048458361" 498 | dependencies: 499 | flat-cache "^1.2.1" 500 | object-assign "^4.0.1" 501 | 502 | flat-cache@^1.2.1: 503 | version "1.3.0" 504 | resolved "https://registry.yarnpkg.com/flat-cache/-/flat-cache-1.3.0.tgz#d3030b32b38154f4e3b7e9c709f490f7ef97c481" 505 | dependencies: 506 | circular-json "^0.3.1" 507 | del "^2.0.2" 508 | graceful-fs "^4.1.2" 509 | write "^0.2.1" 510 | 511 | forever-agent@~0.6.1: 512 | version "0.6.1" 513 | resolved "https://registry.yarnpkg.com/forever-agent/-/forever-agent-0.6.1.tgz#fbc71f0c41adeb37f96c577ad1ed42d8fdacca91" 514 | 515 | form-data@~2.3.1: 516 | version "2.3.2" 517 | resolved "https://registry.yarnpkg.com/form-data/-/form-data-2.3.2.tgz#4970498be604c20c005d4f5c23aecd21d6b49099" 518 | dependencies: 519 | asynckit "^0.4.0" 520 | combined-stream "1.0.6" 521 | mime-types "^2.1.12" 522 | 523 | fs.realpath@^1.0.0: 524 | version "1.0.0" 525 | resolved "https://registry.yarnpkg.com/fs.realpath/-/fs.realpath-1.0.0.tgz#1504ad2523158caa40db4a2787cb01411994ea4f" 526 | 527 | functional-red-black-tree@^1.0.1: 528 | version "1.0.1" 529 | resolved "https://registry.yarnpkg.com/functional-red-black-tree/-/functional-red-black-tree-1.0.1.tgz#1b0ab3bd553b2a0d6399d29c0e3ea0b252078327" 530 | 531 | getpass@^0.1.1: 532 | version "0.1.7" 533 | resolved "https://registry.yarnpkg.com/getpass/-/getpass-0.1.7.tgz#5eff8e3e684d569ae4cb2b1282604e8ba62149fa" 534 | dependencies: 535 | assert-plus "^1.0.0" 536 | 537 | glob@7.1.2, glob@^7.0.3, glob@^7.0.5, glob@^7.1.2: 538 | version "7.1.2" 539 | resolved "https://registry.yarnpkg.com/glob/-/glob-7.1.2.tgz#c19c9df9a028702d678612384a6552404c636d15" 540 | dependencies: 541 | fs.realpath "^1.0.0" 542 | inflight "^1.0.4" 543 | inherits "2" 544 | minimatch "^3.0.4" 545 | once "^1.3.0" 546 | path-is-absolute "^1.0.0" 547 | 548 | glob@^5.0.15: 549 | version "5.0.15" 550 | resolved "https://registry.yarnpkg.com/glob/-/glob-5.0.15.tgz#1bc936b9e02f4a603fcc222ecf7633d30b8b93b1" 551 | dependencies: 552 | inflight "^1.0.4" 553 | inherits "2" 554 | minimatch "2 || 3" 555 | once "^1.3.0" 556 | path-is-absolute "^1.0.0" 557 | 558 | globals@^11.0.1: 559 | version "11.7.0" 560 | resolved "https://registry.yarnpkg.com/globals/-/globals-11.7.0.tgz#a583faa43055b1aca771914bf68258e2fc125673" 561 | 562 | globby@^5.0.0: 563 | version "5.0.0" 564 | resolved "https://registry.yarnpkg.com/globby/-/globby-5.0.0.tgz#ebd84667ca0dbb330b99bcfc68eac2bc54370e0d" 565 | dependencies: 566 | array-union "^1.0.1" 567 | arrify "^1.0.0" 568 | glob "^7.0.3" 569 | object-assign "^4.0.1" 570 | pify "^2.0.0" 571 | pinkie-promise "^2.0.0" 572 | 573 | graceful-fs@^4.1.2: 574 | version "4.1.11" 575 | resolved "https://registry.yarnpkg.com/graceful-fs/-/graceful-fs-4.1.11.tgz#0e8bdfe4d1ddb8854d64e04ea7c00e2a026e5658" 576 | 577 | growl@1.10.3: 578 | version "1.10.3" 579 | resolved "https://registry.yarnpkg.com/growl/-/growl-1.10.3.tgz#1926ba90cf3edfe2adb4927f5880bc22c66c790f" 580 | 581 | "growl@~> 1.10.0": 582 | version "1.10.5" 583 | resolved "https://registry.yarnpkg.com/growl/-/growl-1.10.5.tgz#f2735dc2283674fa67478b10181059355c369e5e" 584 | 585 | handlebars@^4.0.1: 586 | version "4.5.1" 587 | resolved "https://registry.yarnpkg.com/handlebars/-/handlebars-4.5.1.tgz#8a01c382c180272260d07f2d1aa3ae745715c7ba" 588 | dependencies: 589 | neo-async "^2.6.0" 590 | optimist "^0.6.1" 591 | source-map "^0.6.1" 592 | optionalDependencies: 593 | uglify-js "^3.1.4" 594 | 595 | har-schema@^2.0.0: 596 | version "2.0.0" 597 | resolved "https://registry.yarnpkg.com/har-schema/-/har-schema-2.0.0.tgz#a94c2224ebcac04782a0d9035521f24735b7ec92" 598 | 599 | har-validator@~5.0.3: 600 | version "5.0.3" 601 | resolved "https://registry.yarnpkg.com/har-validator/-/har-validator-5.0.3.tgz#ba402c266194f15956ef15e0fcf242993f6a7dfd" 602 | dependencies: 603 | ajv "^5.1.0" 604 | har-schema "^2.0.0" 605 | 606 | has-ansi@^2.0.0: 607 | version "2.0.0" 608 | resolved "https://registry.yarnpkg.com/has-ansi/-/has-ansi-2.0.0.tgz#34f5049ce1ecdf2b0649af3ef24e45ed35416d91" 609 | dependencies: 610 | ansi-regex "^2.0.0" 611 | 612 | has-flag@^1.0.0: 613 | version "1.0.0" 614 | resolved "https://registry.yarnpkg.com/has-flag/-/has-flag-1.0.0.tgz#9d9e793165ce017a00f00418c43f942a7b1d11fa" 615 | 616 | has-flag@^2.0.0: 617 | version "2.0.0" 618 | resolved "https://registry.yarnpkg.com/has-flag/-/has-flag-2.0.0.tgz#e8207af1cc7b30d446cc70b734b5e8be18f88d51" 619 | 620 | has-flag@^3.0.0: 621 | version "3.0.0" 622 | resolved "https://registry.yarnpkg.com/has-flag/-/has-flag-3.0.0.tgz#b5d454dc2199ae225699f3467e5a07f3b955bafd" 623 | 624 | he@1.1.1: 625 | version "1.1.1" 626 | resolved "https://registry.yarnpkg.com/he/-/he-1.1.1.tgz#93410fd21b009735151f8868c2f271f3427e23fd" 627 | 628 | http-signature@~1.2.0: 629 | version "1.2.0" 630 | resolved "https://registry.yarnpkg.com/http-signature/-/http-signature-1.2.0.tgz#9aecd925114772f3d95b65a60abb8f7c18fbace1" 631 | dependencies: 632 | assert-plus "^1.0.0" 633 | jsprim "^1.2.2" 634 | sshpk "^1.7.0" 635 | 636 | iconv-lite@^0.4.17: 637 | version "0.4.23" 638 | resolved "https://registry.yarnpkg.com/iconv-lite/-/iconv-lite-0.4.23.tgz#297871f63be507adcfbfca715d0cd0eed84e9a63" 639 | dependencies: 640 | safer-buffer ">= 2.1.2 < 3" 641 | 642 | ignore@^3.3.3, ignore@^3.3.6: 643 | version "3.3.10" 644 | resolved "https://registry.yarnpkg.com/ignore/-/ignore-3.3.10.tgz#0a97fb876986e8081c631160f8f9f389157f0043" 645 | 646 | imurmurhash@^0.1.4: 647 | version "0.1.4" 648 | resolved "https://registry.yarnpkg.com/imurmurhash/-/imurmurhash-0.1.4.tgz#9218b9b2b928a238b13dc4fb6b6d576f231453ea" 649 | 650 | inflight@^1.0.4: 651 | version "1.0.6" 652 | resolved "https://registry.yarnpkg.com/inflight/-/inflight-1.0.6.tgz#49bd6331d7d02d0c09bc910a1075ba8165b56df9" 653 | dependencies: 654 | once "^1.3.0" 655 | wrappy "1" 656 | 657 | inherits@2, inherits@^2.0.3, inherits@~2.0.3: 658 | version "2.0.3" 659 | resolved "https://registry.yarnpkg.com/inherits/-/inherits-2.0.3.tgz#633c2c83e3da42a502f52466022480f4208261de" 660 | 661 | inquirer@^3.0.6: 662 | version "3.3.0" 663 | resolved "https://registry.yarnpkg.com/inquirer/-/inquirer-3.3.0.tgz#9dd2f2ad765dcab1ff0443b491442a20ba227dc9" 664 | dependencies: 665 | ansi-escapes "^3.0.0" 666 | chalk "^2.0.0" 667 | cli-cursor "^2.1.0" 668 | cli-width "^2.0.0" 669 | external-editor "^2.0.4" 670 | figures "^2.0.0" 671 | lodash "^4.3.0" 672 | mute-stream "0.0.7" 673 | run-async "^2.2.0" 674 | rx-lite "^4.0.8" 675 | rx-lite-aggregates "^4.0.8" 676 | string-width "^2.1.0" 677 | strip-ansi "^4.0.0" 678 | through "^2.3.6" 679 | 680 | is-fullwidth-code-point@^2.0.0: 681 | version "2.0.0" 682 | resolved "https://registry.yarnpkg.com/is-fullwidth-code-point/-/is-fullwidth-code-point-2.0.0.tgz#a3b30a5c4f199183167aaab93beefae3ddfb654f" 683 | 684 | is-path-cwd@^1.0.0: 685 | version "1.0.0" 686 | resolved "https://registry.yarnpkg.com/is-path-cwd/-/is-path-cwd-1.0.0.tgz#d225ec23132e89edd38fda767472e62e65f1106d" 687 | 688 | is-path-in-cwd@^1.0.0: 689 | version "1.0.1" 690 | resolved "https://registry.yarnpkg.com/is-path-in-cwd/-/is-path-in-cwd-1.0.1.tgz#5ac48b345ef675339bd6c7a48a912110b241cf52" 691 | dependencies: 692 | is-path-inside "^1.0.0" 693 | 694 | is-path-inside@^1.0.0: 695 | version "1.0.1" 696 | resolved "https://registry.yarnpkg.com/is-path-inside/-/is-path-inside-1.0.1.tgz#8ef5b7de50437a3fdca6b4e865ef7aa55cb48036" 697 | dependencies: 698 | path-is-inside "^1.0.1" 699 | 700 | is-promise@^2.1.0: 701 | version "2.1.0" 702 | resolved "https://registry.yarnpkg.com/is-promise/-/is-promise-2.1.0.tgz#79a2a9ece7f096e80f36d2b2f3bc16c1ff4bf3fa" 703 | 704 | is-resolvable@^1.0.0: 705 | version "1.1.0" 706 | resolved "https://registry.yarnpkg.com/is-resolvable/-/is-resolvable-1.1.0.tgz#fb18f87ce1feb925169c9a407c19318a3206ed88" 707 | 708 | is-typedarray@~1.0.0: 709 | version "1.0.0" 710 | resolved "https://registry.yarnpkg.com/is-typedarray/-/is-typedarray-1.0.0.tgz#e479c80858df0c1b11ddda6940f96011fcda4a9a" 711 | 712 | isarray@~1.0.0: 713 | version "1.0.0" 714 | resolved "https://registry.yarnpkg.com/isarray/-/isarray-1.0.0.tgz#bb935d48582cba168c06834957a54a3e07124f11" 715 | 716 | isexe@^2.0.0: 717 | version "2.0.0" 718 | resolved "https://registry.yarnpkg.com/isexe/-/isexe-2.0.0.tgz#e8fbf374dc556ff8947a10dcb0572d633f2cfa10" 719 | 720 | isstream@~0.1.2: 721 | version "0.1.2" 722 | resolved "https://registry.yarnpkg.com/isstream/-/isstream-0.1.2.tgz#47e63f7af55afa6f92e1500e690eb8b8529c099a" 723 | 724 | istanbul@^0.4.5: 725 | version "0.4.5" 726 | resolved "https://registry.yarnpkg.com/istanbul/-/istanbul-0.4.5.tgz#65c7d73d4c4da84d4f3ac310b918fb0b8033733b" 727 | dependencies: 728 | abbrev "1.0.x" 729 | async "1.x" 730 | escodegen "1.8.x" 731 | esprima "2.7.x" 732 | glob "^5.0.15" 733 | handlebars "^4.0.1" 734 | js-yaml "3.x" 735 | mkdirp "0.5.x" 736 | nopt "3.x" 737 | once "1.x" 738 | resolve "1.1.x" 739 | supports-color "^3.1.0" 740 | which "^1.1.1" 741 | wordwrap "^1.0.0" 742 | 743 | js-tokens@^3.0.2: 744 | version "3.0.2" 745 | resolved "https://registry.yarnpkg.com/js-tokens/-/js-tokens-3.0.2.tgz#9866df395102130e38f7f996bceb65443209c25b" 746 | 747 | js-yaml@3.x, js-yaml@^3.11.0, js-yaml@^3.9.1: 748 | version "3.13.1" 749 | resolved "https://registry.yarnpkg.com/js-yaml/-/js-yaml-3.13.1.tgz#aff151b30bfdfa8e49e05da22e7415e9dfa37847" 750 | dependencies: 751 | argparse "^1.0.7" 752 | esprima "^4.0.0" 753 | 754 | jsbn@~0.1.0: 755 | version "0.1.1" 756 | resolved "https://registry.yarnpkg.com/jsbn/-/jsbn-0.1.1.tgz#a5e654c2e5a2deb5f201d96cefbca80c0ef2f513" 757 | 758 | json-schema-traverse@^0.3.0: 759 | version "0.3.1" 760 | resolved "https://registry.yarnpkg.com/json-schema-traverse/-/json-schema-traverse-0.3.1.tgz#349a6d44c53a51de89b40805c5d5e59b417d3340" 761 | 762 | json-schema@0.2.3: 763 | version "0.2.3" 764 | resolved "https://registry.yarnpkg.com/json-schema/-/json-schema-0.2.3.tgz#b480c892e59a2f05954ce727bd3f2a4e882f9e13" 765 | 766 | json-stable-stringify-without-jsonify@^1.0.1: 767 | version "1.0.1" 768 | resolved "https://registry.yarnpkg.com/json-stable-stringify-without-jsonify/-/json-stable-stringify-without-jsonify-1.0.1.tgz#9db7b59496ad3f3cfef30a75142d2d930ad72651" 769 | 770 | json-stringify-safe@~5.0.1: 771 | version "5.0.1" 772 | resolved "https://registry.yarnpkg.com/json-stringify-safe/-/json-stringify-safe-5.0.1.tgz#1296a2d58fd45f19a0f6ce01d65701e2c735b6eb" 773 | 774 | jsprim@^1.2.2: 775 | version "1.4.1" 776 | resolved "https://registry.yarnpkg.com/jsprim/-/jsprim-1.4.1.tgz#313e66bc1e5cc06e438bc1b7499c2e5c56acb6a2" 777 | dependencies: 778 | assert-plus "1.0.0" 779 | extsprintf "1.3.0" 780 | json-schema "0.2.3" 781 | verror "1.10.0" 782 | 783 | lcov-parse@^0.0.10: 784 | version "0.0.10" 785 | resolved "https://registry.yarnpkg.com/lcov-parse/-/lcov-parse-0.0.10.tgz#1b0b8ff9ac9c7889250582b70b71315d9da6d9a3" 786 | 787 | levn@^0.3.0, levn@~0.3.0: 788 | version "0.3.0" 789 | resolved "https://registry.yarnpkg.com/levn/-/levn-0.3.0.tgz#3b09924edf9f083c0490fdd4c0bc4421e04764ee" 790 | dependencies: 791 | prelude-ls "~1.1.2" 792 | type-check "~0.3.2" 793 | 794 | lodash@^4.17.4, lodash@^4.3.0: 795 | version "4.17.15" 796 | resolved "https://registry.yarnpkg.com/lodash/-/lodash-4.17.15.tgz#b447f6670a0455bbfeedd11392eff330ea097548" 797 | 798 | log-driver@^1.2.7: 799 | version "1.2.7" 800 | resolved "https://registry.yarnpkg.com/log-driver/-/log-driver-1.2.7.tgz#63b95021f0702fedfa2c9bb0a24e7797d71871d8" 801 | 802 | lru-cache@^4.0.1: 803 | version "4.1.3" 804 | resolved "https://registry.yarnpkg.com/lru-cache/-/lru-cache-4.1.3.tgz#a1175cf3496dfc8436c156c334b4955992bce69c" 805 | dependencies: 806 | pseudomap "^1.0.2" 807 | yallist "^2.1.2" 808 | 809 | mime-db@~1.35.0: 810 | version "1.35.0" 811 | resolved "https://registry.yarnpkg.com/mime-db/-/mime-db-1.35.0.tgz#0569d657466491283709663ad379a99b90d9ab47" 812 | 813 | mime-types@^2.1.12, mime-types@~2.1.17: 814 | version "2.1.19" 815 | resolved "https://registry.yarnpkg.com/mime-types/-/mime-types-2.1.19.tgz#71e464537a7ef81c15f2db9d97e913fc0ff606f0" 816 | dependencies: 817 | mime-db "~1.35.0" 818 | 819 | mimic-fn@^1.0.0: 820 | version "1.2.0" 821 | resolved "https://registry.yarnpkg.com/mimic-fn/-/mimic-fn-1.2.0.tgz#820c86a39334640e99516928bd03fca88057d022" 822 | 823 | "minimatch@2 || 3", minimatch@^3.0.2, minimatch@^3.0.4: 824 | version "3.0.4" 825 | resolved "https://registry.yarnpkg.com/minimatch/-/minimatch-3.0.4.tgz#5166e286457f03306064be5497e8dbb0c3d32083" 826 | dependencies: 827 | brace-expansion "^1.1.7" 828 | 829 | minimist@0.0.8: 830 | version "0.0.8" 831 | resolved "https://registry.yarnpkg.com/minimist/-/minimist-0.0.8.tgz#857fcabfc3397d2625b8228262e86aa7a011b05d" 832 | 833 | minimist@^1.2.0: 834 | version "1.2.0" 835 | resolved "https://registry.yarnpkg.com/minimist/-/minimist-1.2.0.tgz#a35008b20f41383eec1fb914f4cd5df79a264284" 836 | 837 | minimist@~0.0.1: 838 | version "0.0.10" 839 | resolved "https://registry.yarnpkg.com/minimist/-/minimist-0.0.10.tgz#de3f98543dbf96082be48ad1a0c7cda836301dcf" 840 | 841 | mkdirp@0.5.1, mkdirp@0.5.x, mkdirp@^0.5.1: 842 | version "0.5.1" 843 | resolved "https://registry.yarnpkg.com/mkdirp/-/mkdirp-0.5.1.tgz#30057438eac6cf7f8c4767f38648d6697d75c903" 844 | dependencies: 845 | minimist "0.0.8" 846 | 847 | mocha-lcov-reporter@^1.0.0: 848 | version "1.3.0" 849 | resolved "https://registry.yarnpkg.com/mocha-lcov-reporter/-/mocha-lcov-reporter-1.3.0.tgz#469bdef4f8afc9a116056f079df6182d0afb0384" 850 | 851 | mocha@^4.0.1: 852 | version "4.1.0" 853 | resolved "https://registry.yarnpkg.com/mocha/-/mocha-4.1.0.tgz#7d86cfbcf35cb829e2754c32e17355ec05338794" 854 | dependencies: 855 | browser-stdout "1.3.0" 856 | commander "2.11.0" 857 | debug "3.1.0" 858 | diff "3.3.1" 859 | escape-string-regexp "1.0.5" 860 | glob "7.1.2" 861 | growl "1.10.3" 862 | he "1.1.1" 863 | mkdirp "0.5.1" 864 | supports-color "4.4.0" 865 | 866 | ms@2.0.0: 867 | version "2.0.0" 868 | resolved "https://registry.yarnpkg.com/ms/-/ms-2.0.0.tgz#5608aeadfc00be6c2901df5f9861788de0d597c8" 869 | 870 | mute-stream@0.0.7: 871 | version "0.0.7" 872 | resolved "https://registry.yarnpkg.com/mute-stream/-/mute-stream-0.0.7.tgz#3075ce93bc21b8fab43e1bc4da7e8115ed1e7bab" 873 | 874 | natural-compare@^1.4.0: 875 | version "1.4.0" 876 | resolved "https://registry.yarnpkg.com/natural-compare/-/natural-compare-1.4.0.tgz#4abebfeed7541f2c27acfb29bdbbd15c8d5ba4f7" 877 | 878 | neo-async@^2.6.0: 879 | version "2.6.1" 880 | resolved "https://registry.yarnpkg.com/neo-async/-/neo-async-2.6.1.tgz#ac27ada66167fa8849a6addd837f6b189ad2081c" 881 | 882 | nopt@3.x: 883 | version "3.0.6" 884 | resolved "https://registry.yarnpkg.com/nopt/-/nopt-3.0.6.tgz#c6465dbf08abcd4db359317f79ac68a646b28ff9" 885 | dependencies: 886 | abbrev "1" 887 | 888 | oauth-sign@~0.8.2: 889 | version "0.8.2" 890 | resolved "https://registry.yarnpkg.com/oauth-sign/-/oauth-sign-0.8.2.tgz#46a6ab7f0aead8deae9ec0565780b7d4efeb9d43" 891 | 892 | object-assign@^4.0.1: 893 | version "4.1.1" 894 | resolved "https://registry.yarnpkg.com/object-assign/-/object-assign-4.1.1.tgz#2109adc7965887cfc05cbbd442cac8bfbb360863" 895 | 896 | once@1.x, once@^1.3.0: 897 | version "1.4.0" 898 | resolved "https://registry.yarnpkg.com/once/-/once-1.4.0.tgz#583b1aa775961d4b113ac17d9c50baef9dd76bd1" 899 | dependencies: 900 | wrappy "1" 901 | 902 | onetime@^2.0.0: 903 | version "2.0.1" 904 | resolved "https://registry.yarnpkg.com/onetime/-/onetime-2.0.1.tgz#067428230fd67443b2794b22bba528b6867962d4" 905 | dependencies: 906 | mimic-fn "^1.0.0" 907 | 908 | optimist@^0.6.1: 909 | version "0.6.1" 910 | resolved "https://registry.yarnpkg.com/optimist/-/optimist-0.6.1.tgz#da3ea74686fa21a19a111c326e90eb15a0196686" 911 | dependencies: 912 | minimist "~0.0.1" 913 | wordwrap "~0.0.2" 914 | 915 | optionator@^0.8.1, optionator@^0.8.2: 916 | version "0.8.2" 917 | resolved "https://registry.yarnpkg.com/optionator/-/optionator-0.8.2.tgz#364c5e409d3f4d6301d6c0b4c05bba50180aeb64" 918 | dependencies: 919 | deep-is "~0.1.3" 920 | fast-levenshtein "~2.0.4" 921 | levn "~0.3.0" 922 | prelude-ls "~1.1.2" 923 | type-check "~0.3.2" 924 | wordwrap "~1.0.0" 925 | 926 | os-tmpdir@~1.0.2: 927 | version "1.0.2" 928 | resolved "https://registry.yarnpkg.com/os-tmpdir/-/os-tmpdir-1.0.2.tgz#bbe67406c79aa85c5cfec766fe5734555dfa1274" 929 | 930 | path-is-absolute@^1.0.0: 931 | version "1.0.1" 932 | resolved "https://registry.yarnpkg.com/path-is-absolute/-/path-is-absolute-1.0.1.tgz#174b9268735534ffbc7ace6bf53a5a9e1b5c5f5f" 933 | 934 | path-is-inside@^1.0.1, path-is-inside@^1.0.2: 935 | version "1.0.2" 936 | resolved "https://registry.yarnpkg.com/path-is-inside/-/path-is-inside-1.0.2.tgz#365417dede44430d1c11af61027facf074bdfc53" 937 | 938 | path-parse@^1.0.5: 939 | version "1.0.7" 940 | resolved "https://registry.yarnpkg.com/path-parse/-/path-parse-1.0.7.tgz#fbc114b60ca42b30d9daf5858e4bd68bbedb6735" 941 | 942 | performance-now@^2.1.0: 943 | version "2.1.0" 944 | resolved "https://registry.yarnpkg.com/performance-now/-/performance-now-2.1.0.tgz#6309f4e0e5fa913ec1c69307ae364b4b377c9e7b" 945 | 946 | pify@^2.0.0: 947 | version "2.3.0" 948 | resolved "https://registry.yarnpkg.com/pify/-/pify-2.3.0.tgz#ed141a6ac043a849ea588498e7dca8b15330e90c" 949 | 950 | pinkie-promise@^2.0.0: 951 | version "2.0.1" 952 | resolved "https://registry.yarnpkg.com/pinkie-promise/-/pinkie-promise-2.0.1.tgz#2135d6dfa7a358c069ac9b178776288228450ffa" 953 | dependencies: 954 | pinkie "^2.0.0" 955 | 956 | pinkie@^2.0.0: 957 | version "2.0.4" 958 | resolved "https://registry.yarnpkg.com/pinkie/-/pinkie-2.0.4.tgz#72556b80cfa0d48a974e80e77248e80ed4f7f870" 959 | 960 | pluralize@^7.0.0: 961 | version "7.0.0" 962 | resolved "https://registry.yarnpkg.com/pluralize/-/pluralize-7.0.0.tgz#298b89df8b93b0221dbf421ad2b1b1ea23fc6777" 963 | 964 | prelude-ls@~1.1.2: 965 | version "1.1.2" 966 | resolved "https://registry.yarnpkg.com/prelude-ls/-/prelude-ls-1.1.2.tgz#21932a549f5e52ffd9a827f570e04be62a97da54" 967 | 968 | prettier@^1.9.2: 969 | version "1.13.7" 970 | resolved "https://registry.yarnpkg.com/prettier/-/prettier-1.13.7.tgz#850f3b8af784a49a6ea2d2eaa7ed1428a34b7281" 971 | 972 | process-nextick-args@~2.0.0: 973 | version "2.0.0" 974 | resolved "https://registry.yarnpkg.com/process-nextick-args/-/process-nextick-args-2.0.0.tgz#a37d732f4271b4ab1ad070d35508e8290788ffaa" 975 | 976 | progress@^2.0.0: 977 | version "2.0.0" 978 | resolved "https://registry.yarnpkg.com/progress/-/progress-2.0.0.tgz#8a1be366bf8fc23db2bd23f10c6fe920b4389d1f" 979 | 980 | pseudomap@^1.0.2: 981 | version "1.0.2" 982 | resolved "https://registry.yarnpkg.com/pseudomap/-/pseudomap-1.0.2.tgz#f052a28da70e618917ef0a8ac34c1ae5a68286b3" 983 | 984 | punycode@^1.4.1: 985 | version "1.4.1" 986 | resolved "https://registry.yarnpkg.com/punycode/-/punycode-1.4.1.tgz#c0d5a63b2718800ad8e1eb0fa5269c84dd41845e" 987 | 988 | qs@~6.5.1: 989 | version "6.5.2" 990 | resolved "https://registry.yarnpkg.com/qs/-/qs-6.5.2.tgz#cb3ae806e8740444584ef154ce8ee98d403f3e36" 991 | 992 | readable-stream@^2.2.2: 993 | version "2.3.6" 994 | resolved "https://registry.yarnpkg.com/readable-stream/-/readable-stream-2.3.6.tgz#b11c27d88b8ff1fbe070643cf94b0c79ae1b0aaf" 995 | dependencies: 996 | core-util-is "~1.0.0" 997 | inherits "~2.0.3" 998 | isarray "~1.0.0" 999 | process-nextick-args "~2.0.0" 1000 | safe-buffer "~5.1.1" 1001 | string_decoder "~1.1.1" 1002 | util-deprecate "~1.0.1" 1003 | 1004 | regexpp@^1.0.1: 1005 | version "1.1.0" 1006 | resolved "https://registry.yarnpkg.com/regexpp/-/regexpp-1.1.0.tgz#0e3516dd0b7904f413d2d4193dce4618c3a689ab" 1007 | 1008 | request@^2.85.0: 1009 | version "2.87.0" 1010 | resolved "https://registry.yarnpkg.com/request/-/request-2.87.0.tgz#32f00235cd08d482b4d0d68db93a829c0ed5756e" 1011 | dependencies: 1012 | aws-sign2 "~0.7.0" 1013 | aws4 "^1.6.0" 1014 | caseless "~0.12.0" 1015 | combined-stream "~1.0.5" 1016 | extend "~3.0.1" 1017 | forever-agent "~0.6.1" 1018 | form-data "~2.3.1" 1019 | har-validator "~5.0.3" 1020 | http-signature "~1.2.0" 1021 | is-typedarray "~1.0.0" 1022 | isstream "~0.1.2" 1023 | json-stringify-safe "~5.0.1" 1024 | mime-types "~2.1.17" 1025 | oauth-sign "~0.8.2" 1026 | performance-now "^2.1.0" 1027 | qs "~6.5.1" 1028 | safe-buffer "^5.1.1" 1029 | tough-cookie "~2.3.3" 1030 | tunnel-agent "^0.6.0" 1031 | uuid "^3.1.0" 1032 | 1033 | require-uncached@^1.0.3: 1034 | version "1.0.3" 1035 | resolved "https://registry.yarnpkg.com/require-uncached/-/require-uncached-1.0.3.tgz#4e0d56d6c9662fd31e43011c4b95aa49955421d3" 1036 | dependencies: 1037 | caller-path "^0.1.0" 1038 | resolve-from "^1.0.0" 1039 | 1040 | resolve-from@^1.0.0: 1041 | version "1.0.1" 1042 | resolved "https://registry.yarnpkg.com/resolve-from/-/resolve-from-1.0.1.tgz#26cbfe935d1aeeeabb29bc3fe5aeb01e93d44226" 1043 | 1044 | resolve@1.1.x: 1045 | version "1.1.7" 1046 | resolved "https://registry.yarnpkg.com/resolve/-/resolve-1.1.7.tgz#203114d82ad2c5ed9e8e0411b3932875e889e97b" 1047 | 1048 | resolve@^1.3.3: 1049 | version "1.8.1" 1050 | resolved "https://registry.yarnpkg.com/resolve/-/resolve-1.8.1.tgz#82f1ec19a423ac1fbd080b0bab06ba36e84a7a26" 1051 | dependencies: 1052 | path-parse "^1.0.5" 1053 | 1054 | restore-cursor@^2.0.0: 1055 | version "2.0.0" 1056 | resolved "https://registry.yarnpkg.com/restore-cursor/-/restore-cursor-2.0.0.tgz#9f7ee287f82fd326d4fd162923d62129eee0dfaf" 1057 | dependencies: 1058 | onetime "^2.0.0" 1059 | signal-exit "^3.0.2" 1060 | 1061 | ret@~0.1.10: 1062 | version "0.1.15" 1063 | resolved "https://registry.yarnpkg.com/ret/-/ret-0.1.15.tgz#b8a4825d5bdb1fc3f6f53c2bc33f81388681c7bc" 1064 | 1065 | rimraf@^2.2.8: 1066 | version "2.6.2" 1067 | resolved "https://registry.yarnpkg.com/rimraf/-/rimraf-2.6.2.tgz#2ed8150d24a16ea8651e6d6ef0f47c4158ce7a36" 1068 | dependencies: 1069 | glob "^7.0.5" 1070 | 1071 | run-async@^2.2.0: 1072 | version "2.3.0" 1073 | resolved "https://registry.yarnpkg.com/run-async/-/run-async-2.3.0.tgz#0371ab4ae0bdd720d4166d7dfda64ff7a445a6c0" 1074 | dependencies: 1075 | is-promise "^2.1.0" 1076 | 1077 | rx-lite-aggregates@^4.0.8: 1078 | version "4.0.8" 1079 | resolved "https://registry.yarnpkg.com/rx-lite-aggregates/-/rx-lite-aggregates-4.0.8.tgz#753b87a89a11c95467c4ac1626c4efc4e05c67be" 1080 | dependencies: 1081 | rx-lite "*" 1082 | 1083 | rx-lite@*, rx-lite@^4.0.8: 1084 | version "4.0.8" 1085 | resolved "https://registry.yarnpkg.com/rx-lite/-/rx-lite-4.0.8.tgz#0b1e11af8bc44836f04a6407e92da42467b79444" 1086 | 1087 | safe-buffer@^5.0.1, safe-buffer@^5.1.1, safe-buffer@~5.1.0, safe-buffer@~5.1.1: 1088 | version "5.1.2" 1089 | resolved "https://registry.yarnpkg.com/safe-buffer/-/safe-buffer-5.1.2.tgz#991ec69d296e0313747d59bdfd2b745c35f8828d" 1090 | 1091 | safe-regex@^1.1.0: 1092 | version "1.1.0" 1093 | resolved "https://registry.yarnpkg.com/safe-regex/-/safe-regex-1.1.0.tgz#40a3669f3b077d1e943d44629e157dd48023bf2e" 1094 | dependencies: 1095 | ret "~0.1.10" 1096 | 1097 | "safer-buffer@>= 2.1.2 < 3", safer-buffer@^2.0.2: 1098 | version "2.1.2" 1099 | resolved "https://registry.yarnpkg.com/safer-buffer/-/safer-buffer-2.1.2.tgz#44fa161b0187b9549dd84bb91802f9bd8385cd6a" 1100 | 1101 | semver@5.3.0: 1102 | version "5.3.0" 1103 | resolved "https://registry.yarnpkg.com/semver/-/semver-5.3.0.tgz#9b2ce5d3de02d17c6012ad326aa6b4d0cf54f94f" 1104 | 1105 | semver@^5.3.0: 1106 | version "5.5.0" 1107 | resolved "https://registry.yarnpkg.com/semver/-/semver-5.5.0.tgz#dc4bbc7a6ca9d916dee5d43516f0092b58f7b8ab" 1108 | 1109 | shebang-command@^1.2.0: 1110 | version "1.2.0" 1111 | resolved "https://registry.yarnpkg.com/shebang-command/-/shebang-command-1.2.0.tgz#44aac65b695b03398968c39f363fee5deafdf1ea" 1112 | dependencies: 1113 | shebang-regex "^1.0.0" 1114 | 1115 | shebang-regex@^1.0.0: 1116 | version "1.0.0" 1117 | resolved "https://registry.yarnpkg.com/shebang-regex/-/shebang-regex-1.0.0.tgz#da42f49740c0b42db2ca9728571cb190c98efea3" 1118 | 1119 | signal-exit@^3.0.2: 1120 | version "3.0.2" 1121 | resolved "https://registry.yarnpkg.com/signal-exit/-/signal-exit-3.0.2.tgz#b5fdc08f1287ea1178628e415e25132b73646c6d" 1122 | 1123 | slice-ansi@1.0.0: 1124 | version "1.0.0" 1125 | resolved "https://registry.yarnpkg.com/slice-ansi/-/slice-ansi-1.0.0.tgz#044f1a49d8842ff307aad6b505ed178bd950134d" 1126 | dependencies: 1127 | is-fullwidth-code-point "^2.0.0" 1128 | 1129 | source-map@^0.6.1, source-map@~0.6.1: 1130 | version "0.6.1" 1131 | resolved "https://registry.yarnpkg.com/source-map/-/source-map-0.6.1.tgz#74722af32e9614e9c287a8d0bbde48b5e2f1a263" 1132 | 1133 | source-map@~0.2.0: 1134 | version "0.2.0" 1135 | resolved "https://registry.yarnpkg.com/source-map/-/source-map-0.2.0.tgz#dab73fbcfc2ba819b4de03bd6f6eaa48164b3f9d" 1136 | dependencies: 1137 | amdefine ">=0.0.4" 1138 | 1139 | sprintf-js@~1.0.2: 1140 | version "1.0.3" 1141 | resolved "https://registry.yarnpkg.com/sprintf-js/-/sprintf-js-1.0.3.tgz#04e6926f662895354f3dd015203633b857297e2c" 1142 | 1143 | sshpk@^1.7.0: 1144 | version "1.14.2" 1145 | resolved "https://registry.yarnpkg.com/sshpk/-/sshpk-1.14.2.tgz#c6fc61648a3d9c4e764fd3fcdf4ea105e492ba98" 1146 | dependencies: 1147 | asn1 "~0.2.3" 1148 | assert-plus "^1.0.0" 1149 | dashdash "^1.12.0" 1150 | getpass "^0.1.1" 1151 | safer-buffer "^2.0.2" 1152 | optionalDependencies: 1153 | bcrypt-pbkdf "^1.0.0" 1154 | ecc-jsbn "~0.1.1" 1155 | jsbn "~0.1.0" 1156 | tweetnacl "~0.14.0" 1157 | 1158 | string-width@^2.1.0, string-width@^2.1.1: 1159 | version "2.1.1" 1160 | resolved "https://registry.yarnpkg.com/string-width/-/string-width-2.1.1.tgz#ab93f27a8dc13d28cac815c462143a6d9012ae9e" 1161 | dependencies: 1162 | is-fullwidth-code-point "^2.0.0" 1163 | strip-ansi "^4.0.0" 1164 | 1165 | string_decoder@~1.1.1: 1166 | version "1.1.1" 1167 | resolved "https://registry.yarnpkg.com/string_decoder/-/string_decoder-1.1.1.tgz#9cf1611ba62685d7030ae9e4ba34149c3af03fc8" 1168 | dependencies: 1169 | safe-buffer "~5.1.0" 1170 | 1171 | strip-ansi@^3.0.0: 1172 | version "3.0.1" 1173 | resolved "https://registry.yarnpkg.com/strip-ansi/-/strip-ansi-3.0.1.tgz#6a385fb8853d952d5ff05d0e8aaf94278dc63dcf" 1174 | dependencies: 1175 | ansi-regex "^2.0.0" 1176 | 1177 | strip-ansi@^4.0.0: 1178 | version "4.0.0" 1179 | resolved "https://registry.yarnpkg.com/strip-ansi/-/strip-ansi-4.0.0.tgz#a8479022eb1ac368a871389b635262c505ee368f" 1180 | dependencies: 1181 | ansi-regex "^3.0.0" 1182 | 1183 | strip-json-comments@~2.0.1: 1184 | version "2.0.1" 1185 | resolved "https://registry.yarnpkg.com/strip-json-comments/-/strip-json-comments-2.0.1.tgz#3c531942e908c2697c0ec344858c286c7ca0a60a" 1186 | 1187 | supports-color@4.4.0: 1188 | version "4.4.0" 1189 | resolved "https://registry.yarnpkg.com/supports-color/-/supports-color-4.4.0.tgz#883f7ddabc165142b2a61427f3352ded195d1a3e" 1190 | dependencies: 1191 | has-flag "^2.0.0" 1192 | 1193 | supports-color@^2.0.0: 1194 | version "2.0.0" 1195 | resolved "https://registry.yarnpkg.com/supports-color/-/supports-color-2.0.0.tgz#535d045ce6b6363fa40117084629995e9df324c7" 1196 | 1197 | supports-color@^3.1.0: 1198 | version "3.2.3" 1199 | resolved "https://registry.yarnpkg.com/supports-color/-/supports-color-3.2.3.tgz#65ac0504b3954171d8a64946b2ae3cbb8a5f54f6" 1200 | dependencies: 1201 | has-flag "^1.0.0" 1202 | 1203 | supports-color@^5.3.0: 1204 | version "5.4.0" 1205 | resolved "https://registry.yarnpkg.com/supports-color/-/supports-color-5.4.0.tgz#1c6b337402c2137605efe19f10fec390f6faab54" 1206 | dependencies: 1207 | has-flag "^3.0.0" 1208 | 1209 | table@4.0.2: 1210 | version "4.0.2" 1211 | resolved "https://registry.yarnpkg.com/table/-/table-4.0.2.tgz#a33447375391e766ad34d3486e6e2aedc84d2e36" 1212 | dependencies: 1213 | ajv "^5.2.3" 1214 | ajv-keywords "^2.1.0" 1215 | chalk "^2.1.0" 1216 | lodash "^4.17.4" 1217 | slice-ansi "1.0.0" 1218 | string-width "^2.1.1" 1219 | 1220 | text-table@~0.2.0: 1221 | version "0.2.0" 1222 | resolved "https://registry.yarnpkg.com/text-table/-/text-table-0.2.0.tgz#7f5ee823ae805207c00af2df4a84ec3fcfa570b4" 1223 | 1224 | through@^2.3.6: 1225 | version "2.3.8" 1226 | resolved "https://registry.yarnpkg.com/through/-/through-2.3.8.tgz#0dd4c9ffaabc357960b1b724115d7e0e86a2e1f5" 1227 | 1228 | tmp@^0.0.33: 1229 | version "0.0.33" 1230 | resolved "https://registry.yarnpkg.com/tmp/-/tmp-0.0.33.tgz#6d34335889768d21b2bcda0aa277ced3b1bfadf9" 1231 | dependencies: 1232 | os-tmpdir "~1.0.2" 1233 | 1234 | tough-cookie@~2.3.3: 1235 | version "2.3.4" 1236 | resolved "https://registry.yarnpkg.com/tough-cookie/-/tough-cookie-2.3.4.tgz#ec60cee38ac675063ffc97a5c18970578ee83655" 1237 | dependencies: 1238 | punycode "^1.4.1" 1239 | 1240 | tunnel-agent@^0.6.0: 1241 | version "0.6.0" 1242 | resolved "https://registry.yarnpkg.com/tunnel-agent/-/tunnel-agent-0.6.0.tgz#27a5dea06b36b04a0a9966774b290868f0fc40fd" 1243 | dependencies: 1244 | safe-buffer "^5.0.1" 1245 | 1246 | tweetnacl@^0.14.3, tweetnacl@~0.14.0: 1247 | version "0.14.5" 1248 | resolved "https://registry.yarnpkg.com/tweetnacl/-/tweetnacl-0.14.5.tgz#5ae68177f192d4456269d108afa93ff8743f4f64" 1249 | 1250 | type-check@~0.3.2: 1251 | version "0.3.2" 1252 | resolved "https://registry.yarnpkg.com/type-check/-/type-check-0.3.2.tgz#5884cab512cf1d355e3fb784f30804b2b520db72" 1253 | dependencies: 1254 | prelude-ls "~1.1.2" 1255 | 1256 | typedarray@^0.0.6: 1257 | version "0.0.6" 1258 | resolved "https://registry.yarnpkg.com/typedarray/-/typedarray-0.0.6.tgz#867ac74e3864187b1d3d47d996a78ec5c8830777" 1259 | 1260 | uglify-js@^3.1.4: 1261 | version "3.6.8" 1262 | resolved "https://registry.yarnpkg.com/uglify-js/-/uglify-js-3.6.8.tgz#5edcbcf9d49cbb0403dc49f856fe81530d65145e" 1263 | dependencies: 1264 | commander "~2.20.3" 1265 | source-map "~0.6.1" 1266 | 1267 | util-deprecate@~1.0.1: 1268 | version "1.0.2" 1269 | resolved "https://registry.yarnpkg.com/util-deprecate/-/util-deprecate-1.0.2.tgz#450d4dc9fa70de732762fbd2d4a28981419a0ccf" 1270 | 1271 | uuid@^3.1.0: 1272 | version "3.3.2" 1273 | resolved "https://registry.yarnpkg.com/uuid/-/uuid-3.3.2.tgz#1b4af4955eb3077c501c23872fc6513811587131" 1274 | 1275 | verror@1.10.0: 1276 | version "1.10.0" 1277 | resolved "https://registry.yarnpkg.com/verror/-/verror-1.10.0.tgz#3a105ca17053af55d6e270c1f8288682e18da400" 1278 | dependencies: 1279 | assert-plus "^1.0.0" 1280 | core-util-is "1.0.2" 1281 | extsprintf "^1.2.0" 1282 | 1283 | which@^1.1.1, which@^1.2.9: 1284 | version "1.3.1" 1285 | resolved "https://registry.yarnpkg.com/which/-/which-1.3.1.tgz#a45043d54f5805316da8d62f9f50918d3da70b0a" 1286 | dependencies: 1287 | isexe "^2.0.0" 1288 | 1289 | wordwrap@^1.0.0, wordwrap@~1.0.0: 1290 | version "1.0.0" 1291 | resolved "https://registry.yarnpkg.com/wordwrap/-/wordwrap-1.0.0.tgz#27584810891456a4171c8d0226441ade90cbcaeb" 1292 | 1293 | wordwrap@~0.0.2: 1294 | version "0.0.3" 1295 | resolved "https://registry.yarnpkg.com/wordwrap/-/wordwrap-0.0.3.tgz#a3d5da6cd5c0bc0008d37234bbaf1bed63059107" 1296 | 1297 | wrappy@1: 1298 | version "1.0.2" 1299 | resolved "https://registry.yarnpkg.com/wrappy/-/wrappy-1.0.2.tgz#b5243d8f3ec1aa35f1364605bc0d1036e30ab69f" 1300 | 1301 | write@^0.2.1: 1302 | version "0.2.1" 1303 | resolved "https://registry.yarnpkg.com/write/-/write-0.2.1.tgz#5fc03828e264cea3fe91455476f7a3c566cb0757" 1304 | dependencies: 1305 | mkdirp "^0.5.1" 1306 | 1307 | yallist@^2.1.2: 1308 | version "2.1.2" 1309 | resolved "https://registry.yarnpkg.com/yallist/-/yallist-2.1.2.tgz#1c11f9218f076089a47dd512f93c6699a6a81d52" 1310 | 1311 | yerror@^2.1.0: 1312 | version "2.1.2" 1313 | resolved "https://registry.yarnpkg.com/yerror/-/yerror-2.1.2.tgz#dd9cfec6339029f6de266d9b7c2e9639b6e5337e" 1314 | --------------------------------------------------------------------------------