├── .npmignore ├── index.js ├── README.md ├── .github └── workflows │ └── ci.yml ├── .gitignore ├── package.json ├── LICENSE ├── rules └── prefer-bind-operator.js └── tests └── prefer-bind-operator.js /.npmignore: -------------------------------------------------------------------------------- 1 | # Everything 2 | * 3 | 4 | !index.js 5 | !rules/* 6 | -------------------------------------------------------------------------------- /index.js: -------------------------------------------------------------------------------- 1 | /** 2 | * @fileoverview Suggest using the bind operator over Function methods or Reflect.apply. 3 | * @author Erik Desjardins 4 | * @copyright 2016 Erik Desjardins. All rights reserved. 5 | * See LICENSE file in root directory for full license. 6 | */ 7 | 'use strict'; 8 | 9 | module.exports = { 10 | rules: { 11 | 'prefer-bind-operator': require('./rules/prefer-bind-operator') 12 | } 13 | }; 14 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # eslint-plugin-prefer-bind-operator 2 | 3 | Suggest using the bind operator over Function methods or Reflect.apply. 4 | 5 | Warns for the following: 6 | 7 | ```js 8 | // with at least one argument 9 | var foo = bar.bind(/* ... */); 10 | foo.call(/* ... */); 11 | foo.apply(/* ... */); 12 | Reflect.apply(foo); 13 | ``` 14 | 15 | ## Usage 16 | 17 | `npm i --save-dev eslint-plugin-prefer-bind-operator` 18 | 19 | ```json 20 | { 21 | "plugins": [ 22 | "prefer-bind-operator" 23 | ], 24 | "rules": { 25 | "prefer-bind-operator/prefer-bind-operator": 2 26 | } 27 | } 28 | ``` 29 | -------------------------------------------------------------------------------- /.github/workflows/ci.yml: -------------------------------------------------------------------------------- 1 | name: CI 2 | 3 | on: 4 | push: 5 | branches: 6 | - master 7 | tags: 8 | - v*.*.* 9 | pull_request: 10 | 11 | jobs: 12 | build: 13 | runs-on: ubuntu-latest 14 | steps: 15 | - uses: actions/checkout@v1 16 | - uses: actions/setup-node@v1 17 | with: 18 | node-version: '12.x' 19 | registry-url: 'https://registry.npmjs.org' 20 | - run: npm install 21 | - run: npm test 22 | - run: npm publish 23 | if: startsWith(github.ref, 'refs/tags/') 24 | env: 25 | NODE_AUTH_TOKEN: ${{ secrets.NPM_TOKEN }} 26 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | # Logs 2 | logs 3 | *.log 4 | npm-debug.log* 5 | 6 | # Runtime data 7 | pids 8 | *.pid 9 | *.seed 10 | 11 | # Directory for instrumented libs generated by jscoverage/JSCover 12 | lib-cov 13 | 14 | # Coverage directory used by tools like istanbul 15 | coverage 16 | 17 | # Grunt intermediate storage (http://gruntjs.com/creating-plugins#storing-task-files) 18 | .grunt 19 | 20 | # node-waf configuration 21 | .lock-wscript 22 | 23 | # Compiled binary addons (http://nodejs.org/api/addons.html) 24 | build/Release 25 | 26 | # Dependency directory 27 | node_modules 28 | 29 | # Optional npm cache directory 30 | .npm 31 | 32 | # Optional REPL history 33 | .node_repl_history 34 | 35 | # IntelliJ 36 | *.iml 37 | .idea 38 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "eslint-plugin-prefer-bind-operator", 3 | "version": "0.0.4", 4 | "description": "Suggest using the bind operator over Function methods or Reflect.apply.", 5 | "keywords": [ 6 | "eslint", 7 | "eslintplugin", 8 | "eslint-plugin" 9 | ], 10 | "author": "Erik Desjardins", 11 | "repository": { 12 | "type": "git", 13 | "url": "https://github.com/erikdesjardins/eslint-plugin-prefer-bind-operator.git" 14 | }, 15 | "main": "index.js", 16 | "scripts": { 17 | "test": "mocha ./tests/*.js" 18 | }, 19 | "peerDependencies": { 20 | "eslint": ">=1.0.0" 21 | }, 22 | "devDependencies": { 23 | "eslint": "^6.6.0", 24 | "mocha": "^6.2.2" 25 | }, 26 | "license": "MIT" 27 | } 28 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | The MIT License (MIT) 2 | 3 | Copyright (c) 2016 Erik Desjardins 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /rules/prefer-bind-operator.js: -------------------------------------------------------------------------------- 1 | /** 2 | * @fileoverview Suggest using the bind operator over Function methods or Reflect.apply. 3 | * @author Erik Desjardins 4 | * @copyright 2016 Erik Desjardins. All rights reserved. 5 | * See LICENSE file in root directory for full license. 6 | */ 7 | 'use strict'; 8 | 9 | module.exports = function(context) { 10 | return { 11 | CallExpression: function(node) { 12 | if (!node.arguments.length) { 13 | return; 14 | } 15 | 16 | var firstArg = node.arguments[0]; 17 | if (firstArg.type === 'Literal' && firstArg.value !== null) { 18 | // probably $.fn.bind or something else 19 | return; 20 | } 21 | 22 | if (node.callee.type !== 'MemberExpression') { 23 | return; 24 | } 25 | 26 | var method = node.callee.property; 27 | 28 | if (method.name === 'call' || method.name === 'apply') { 29 | context.report({ 30 | node: method, 31 | message: 'Expected bind operator.' 32 | }); 33 | } else if (method.name === 'bind') { 34 | context.report({ 35 | node: method, 36 | message: 'Expected bind operator or arrow function.' 37 | }); 38 | } 39 | } 40 | }; 41 | }; 42 | -------------------------------------------------------------------------------- /tests/prefer-bind-operator.js: -------------------------------------------------------------------------------- 1 | /** 2 | * @fileoverview Suggest using the bind operator over Function methods or Reflect.apply. 3 | * @author Erik Desjardins 4 | * @copyright 2016 Erik Desjardins. All rights reserved. 5 | * See LICENSE file in root directory for full license. 6 | */ 7 | 'use strict'; 8 | 9 | var rule = require('../rules/prefer-bind-operator'); 10 | var RuleTester = require('eslint').RuleTester; 11 | 12 | var bindMessage = 'Expected bind operator or arrow function.'; 13 | var callMessage = 'Expected bind operator.'; 14 | 15 | var ruleTester = new RuleTester(); 16 | ruleTester.run('prefer-bind-operator', rule, { 17 | valid: [ 18 | // variables 19 | 'var apply; var call; var bind;', 20 | // properties 21 | 'a.apply; a.call; a.bind;', 22 | // deep properties 23 | 'a.b.apply; a.b.call; a.b.bind;', 24 | // too few arguments 25 | 'a.apply(); a.call(); a.bind();', 26 | // deep properties, too few arguments 27 | 'a.b.apply(); a.b.call(); a.b.bind();', 28 | // bare function calls 29 | 'apply(); call(); bind();', 30 | // bare function calls with arguments 31 | 'apply(foo); call(foo); bind(foo);', 32 | // bare function calls, multiple arguments 33 | 'apply(foo, bar); call(foo, bar); bind(foo, bar);', 34 | // bare Reflect.apply 35 | 'Reflect.apply', 36 | // too few arguments 37 | 'Reflect.apply()', 38 | // binding `this` to a literal, probably not a Function.prototype method call 39 | 'a.apply("foo"); a.call("foo"); a.bind("foo");', 40 | 'a.apply(4); a.call(5); a.bind(1);' 41 | ], 42 | invalid: [ 43 | // apply 44 | { 45 | code: 'a.apply(foo);', 46 | errors: [{ 47 | message: callMessage, 48 | type: 'Identifier', 49 | line: 1, 50 | column: 3 51 | }] 52 | }, 53 | // apply, multiple args and deep property access 54 | { 55 | code: 'a.b.apply(foo, bar);', 56 | errors: [{ 57 | message: callMessage, 58 | type: 'Identifier', 59 | line: 1, 60 | column: 5 61 | }] 62 | }, 63 | // apply, this = null 64 | { 65 | code: 'a.apply(null);', 66 | errors: [{ 67 | message: callMessage, 68 | type: 'Identifier', 69 | line: 1, 70 | column: 3 71 | }] 72 | }, 73 | // call 74 | { 75 | code: 'a.call(foo);', 76 | errors: [{ 77 | message: callMessage, 78 | type: 'Identifier', 79 | line: 1, 80 | column: 3 81 | }] 82 | }, 83 | // call, multiple args and deep property access 84 | { 85 | code: 'a.b.call(foo, bar);', 86 | errors: [{ 87 | message: callMessage, 88 | type: 'Identifier', 89 | line: 1, 90 | column: 5 91 | }] 92 | }, 93 | // call, this = null 94 | { 95 | code: 'a.call(null);', 96 | errors: [{ 97 | message: callMessage, 98 | type: 'Identifier', 99 | line: 1, 100 | column: 3 101 | }] 102 | }, 103 | // bind 104 | { 105 | code: 'a.bind(foo);', 106 | errors: [{ 107 | message: bindMessage, 108 | type: 'Identifier', 109 | line: 1, 110 | column: 3 111 | }] 112 | }, 113 | // bind, multiple args and deep property access 114 | { 115 | code: 'a.b.bind(foo, bar);', 116 | errors: [{ 117 | message: bindMessage, 118 | type: 'Identifier', 119 | line: 1, 120 | column: 5 121 | }] 122 | }, 123 | // bind, this = null 124 | { 125 | code: 'a.bind(null);', 126 | errors: [{ 127 | message: bindMessage, 128 | type: 'Identifier', 129 | line: 1, 130 | column: 3 131 | }] 132 | }, 133 | // Reflect.apply 134 | { 135 | code: 'Reflect.apply(foo);', 136 | errors: [{ 137 | message: callMessage, 138 | type: 'Identifier', 139 | line: 1, 140 | column: 9 141 | }] 142 | }, 143 | // Reflect.apply, multiple args 144 | { 145 | code: 'Reflect.apply(foo.bar, baz);', 146 | errors: [{ 147 | message: callMessage, 148 | type: 'Identifier', 149 | line: 1, 150 | column: 9 151 | }] 152 | }, 153 | // Reflect.apply, this = null 154 | { 155 | code: 'Reflect.apply(foo, null);', 156 | errors: [{ 157 | message: callMessage, 158 | type: 'Identifier', 159 | line: 1, 160 | column: 9 161 | }] 162 | } 163 | ] 164 | }); 165 | --------------------------------------------------------------------------------