├── .babelrc
├── .eslintignore
├── .eslintrc
├── .flowconfig
├── .gitignore
├── .npmignore
├── .travis.yml
├── LICENSE
├── README.md
├── package.json
├── src
├── __tests__
│ └── autobind-test.js
└── autobind.js
└── test
└── mocha.opts
/.babelrc:
--------------------------------------------------------------------------------
1 | {
2 | "plugins": [
3 | "transform-class-properties"
4 | ],
5 | "presets": [
6 | "babel-preset-es2015-loose",
7 | "babel-preset-react",
8 | "babel-preset-stage-2"
9 | ]
10 | }
11 |
--------------------------------------------------------------------------------
/.eslintignore:
--------------------------------------------------------------------------------
1 | _*
2 | !__tests__
3 | /lib
4 | /node_modules
5 |
--------------------------------------------------------------------------------
/.eslintrc:
--------------------------------------------------------------------------------
1 | {
2 | "parser": "babel-eslint",
3 | "plugins": [
4 | "babel",
5 | "flow-vars",
6 | "react"
7 | ],
8 | "env": {
9 | "browser": true,
10 | "node": true
11 | },
12 | "globals": {
13 | "Map": false
14 | },
15 | "rules": {
16 | "no-cond-assign": 1, // disallow assignment in conditional expressions
17 | "no-console": 0, // disallow use of console: should use nuclide-logging instead
18 | "no-constant-condition": 1, // disallow use of constant expressions in conditions
19 | "comma-dangle": [ // disallow trailing commas in object and array literals
20 | 1, "always-multiline"
21 | ],
22 | "no-control-regex": 1, // disallow control characters in regular expressions
23 | "no-debugger": 1, // disallow use of debugger
24 | "no-dupe-keys": 1, // disallow duplicate keys when creating object literals
25 | "no-dupe-args": 1, // disallow duplicate arguments in functions
26 | "no-duplicate-case": 1, // disallow a duplicate case label
27 | "no-empty": 0, // disallow empty statements
28 | "no-empty-character-class": 1, // disallow the use of empty character classes in regular expressions
29 | "no-ex-assign": 1, // disallow assigning to the exception in a catch block
30 | "no-extra-boolean-cast": 1, // disallow double-negation boolean casts in a boolean context
31 | "no-extra-semi": 1, // disallow unnecessary semicolons
32 | "no-func-assign": 1, // disallow overwriting functions written as function declarations
33 | "no-inner-declarations": 0, // disallow function or variable declarations in nested blocks
34 | "no-invalid-regexp": 1, // disallow invalid regular expression strings in the RegExp constructor
35 | "no-negated-in-lhs": 1, // disallow negation of the left operand of an in expression
36 | "no-obj-calls": 1, // disallow the use of object properties of the global object (Math and JSON) as functions
37 | "no-regex-spaces": 1, // disallow multiple spaces in a regular expression literal
38 | "no-reserved-keys": 0, // disallow reserved words being used as object literal keys
39 | "no-sparse-arrays": 1, // disallow sparse arrays
40 | "no-unreachable": 1, // disallow unreachable statements after a return, throw, continue, or break statement
41 | "use-isnan": 1, // disallow comparisons with the value NaN
42 | "valid-jsdoc": 0, // Ensure JSDoc comments are valid
43 | "valid-typeof": 1, // Ensure that the results of typeof are compared against a valid string
44 |
45 | // Best Practices (designed to prevent you from making mistakes)
46 |
47 | "block-scoped-var": 0, // treat var statements as if they were block scoped
48 | "complexity": 0, // specify the maximum cyclomatic complexity allowed in a program
49 | "consistent-return": 0, // require return statements to either always or never specify values
50 | "curly": 1, // specify curly brace conventions for all control statements
51 | "default-case": 0, // require default case in switch statements
52 | "dot-notation": 0, // dot notation encouraged except for foreign properties that cannot be renamed (i.e., Closure Compiler rules)
53 | "eqeqeq": [1, "allow-null"], // require the use of === and !==
54 | "guard-for-in": 1, // make sure for-in loops have an if statement
55 | "no-alert": 1, // disallow the use of alert, confirm, and prompt
56 | "no-caller": 1, // disallow use of arguments.caller or arguments.callee
57 | "no-div-regex": 1, // disallow division operators explicitly at beginning of regular expression
58 | "no-else-return": 0, // disallow else after a return in an if
59 | "no-eq-null": 0, // disallow comparisons to null without a type-checking operator
60 | "no-eval": 1, // disallow use of eval()
61 | "no-extend-native": 1, // disallow adding to native types
62 | "no-extra-bind": 1, // disallow unnecessary function binding
63 | "no-fallthrough": 1, // disallow fallthrough of case statements
64 | "no-floating-decimal": 1, // disallow the use of leading or trailing decimal points in numeric literals
65 | "no-implied-eval": 1, // disallow use of eval()-like methods
66 | "no-labels": 1, // disallow use of labeled statements
67 | "no-iterator": 1, // disallow usage of __iterator__ property
68 | "no-lone-blocks": 1, // disallow unnecessary nested blocks
69 | "no-loop-func": 0, // disallow creation of functions within loops
70 | "no-multi-str": 0, // disallow use of multiline strings
71 | "no-native-reassign": 0, // disallow reassignments of native objects
72 | "no-new": 1, // disallow use of new operator when not part of the assignment or comparison
73 | "no-new-func": 1, // disallow use of new operator for Function object
74 | "no-new-wrappers": 1, // disallows creating new instances of String,Number, and Boolean
75 | "no-octal": 1, // disallow use of octal literals
76 | "no-octal-escape": 1, // disallow use of octal escape sequences in string literals, such as var foo = "Copyright \251";
77 | "no-proto": 1, // disallow usage of __proto__ property
78 | "no-redeclare": 1, // disallow declaring the same variable more then once
79 | "no-return-assign": 1, // disallow use of assignment in return statement
80 | "no-script-url": 1, // disallow use of javascript: urls.
81 | "no-self-compare": 1, // disallow comparisons where both sides are exactly the same
82 | "no-sequences": 1, // disallow use of comma operator
83 | "no-unused-expressions": 0, // disallow usage of expressions in statement position
84 | "no-void": 1, // disallow use of void operator
85 | "no-warning-comments": 0, // disallow usage of configurable warning terms in comments e.g. TODO or FIXME
86 | "no-with": 1, // disallow use of the with statement
87 | "radix": 1, // require use of the second argument for parseInt()
88 | "vars-on-top": 0, // requires to declare all vars on top of their containing scope
89 | "wrap-iife": 0, // require immediate function invocation to be wrapped in parentheses
90 | "yoda": 1, // require or disallow Yoda conditions
91 | "strict": 0, // this rule conflicts with 'use-babel' so we'll just disable it
92 |
93 | // Variables
94 |
95 | "no-catch-shadow": 1, // disallow the catch clause parameter name being the same as a variable in the outer scope (off by default in the node environment)
96 | "no-delete-var": 1, // disallow deletion of variables
97 | "no-label-var": 1, // disallow labels that share a name with a variable
98 | "no-shadow": 0, // disallow declaration of variables already declared in the outer scope
99 | "no-shadow-restricted-names": 1, // disallow shadowing of names such as arguments
100 | "no-undef": 1, // disallow undeclared variables
101 | "no-undefined": 0, // disallow use of undefined variable
102 | "no-undef-init": 0, // disallow use of undefined when initializing variables
103 | "no-unused-vars": 1, // disallow declaration of variables that are not used in the code
104 | "no-use-before-define": 0, // disallow use of variables before they are defined
105 |
106 | // Node.js
107 |
108 | "handle-callback-err": 1, // enforces error handling in callbacks
109 | "no-mixed-requires": 1, // disallow mixing regular variable and require declarations
110 | "no-new-require": 1, // disallow use of new operator with the require function
111 | "no-path-concat": 1, // disallow string concatenation with __dirname and __filename
112 | "no-process-exit": 0, // disallow process.exit()
113 | "no-restricted-modules": 1, // restrict usage of specified node modules
114 | "no-sync": 0, // disallow use of synchronous methods
115 |
116 | // React (eslint-plugin-react)
117 |
118 | "jsx-quotes": [1, "prefer-double"], // not
119 | "react/jsx-curly-spacing": [ // Enforce or disallow spaces inside of curly braces in JSX attributes
120 | 1, "never"
121 | ],
122 | "react/jsx-no-undef": 1, // Disallow undeclared variables in JSX
123 | "react/jsx-uses-react": 1, // Prevent React to be incorrectly marked as unused
124 | "react/jsx-uses-vars": 1, // Prevent variables used in JSX to be incorrectly marked as unused
125 | "react/no-unknown-property": 1, // Prevent usage of unknown DOM property
126 | "react/prop-types": 1, // Prevent missing props validation in a React component definition
127 | "react/react-in-jsx-scope": 2, // Prevent missing React when using JSX
128 |
129 | // Stylistic (these rules are purely matters of style and are quite subjective)
130 |
131 | "key-spacing": 1, // require space after colon `{a: 1}`
132 | "comma-spacing": 1, // require space after comma `var a, b;`
133 | "no-multi-spaces": 1, // don't allow more spaces than necessary
134 | "brace-style": [ // enforce one true brace style
135 | 1, "1tbs", {
136 | "allowSingleLine": false
137 | }
138 | ],
139 | "camelcase": [ // require camel case names
140 | 1, {"properties": "never"}
141 | ],
142 | "consistent-this": [1, "self"], // enforces consistent naming when capturing the current execution context
143 | "eol-last": 1, // enforce newline at the end of file, with no multiple empty lines
144 | "func-names": 0, // require function expressions to have a name
145 | "func-style": 0, // enforces use of function declarations or expressions
146 | "new-cap": 0, // require a capital letter for constructors
147 | "new-parens": 1, // disallow the omission of parentheses when invoking a constructor with no arguments
148 | "no-nested-ternary": 0, // disallow nested ternary expressions
149 | "no-array-constructor": 1, // disallow use of the Array constructor
150 | "no-lonely-if": 0, // disallow if as the only statement in an else block
151 | "no-new-object": 1, // disallow use of the Object constructor
152 | "no-spaced-func": 1, // disallow space between function identifier and application
153 | "semi-spacing": 1, // disallow space before semicolon
154 | "no-ternary": 0, // disallow the use of ternary operators
155 | "no-trailing-spaces": 1, // disallow trailing whitespace at the end of lines
156 | "no-underscore-dangle": 0, // disallow dangling underscores in identifiers
157 | "no-extra-parens": [1, "functions"], // disallow wrapping of non-IIFE statements in parens
158 | "no-mixed-spaces-and-tabs": 1, // disallow mixed spaces and tabs for indentation
159 | "indent": [1, 2, {"SwitchCase": 1}], // indentation should be two spaces
160 | "quotes": [ // enforce single quotes, allow double to avoid escaping ("don't escape" instead of 'don\'t escape')
161 | 1, "single", "avoid-escape"
162 | ],
163 | "quote-props": [1, "as-needed"], // require quotes around object literal property names
164 | "semi": 1, // require or disallow use of semicolons instead of ASI
165 | "sort-vars": 0, // sort variables within the same declaration block
166 | "keyword-spacing": 1, // require a space around certain keywords
167 | "space-before-blocks": 1, // require a space before blocks
168 | "space-before-function-paren": [ // disallow a space before function parenthesis
169 | 1, "never"
170 | ],
171 | "object-curly-spacing": [ // disallow spaces inside of curly braces in object literals
172 | 1, "never"
173 | ],
174 | "array-bracket-spacing": [ // disallow spaces inside of curly braces in array literals
175 | 1, "never"
176 | ],
177 | "space-in-parens": 1, // require or disallow spaces inside parentheses
178 | "space-infix-ops": 1, // require spaces around operators
179 | "space-unary-ops": 1, // require a space around word operators such as typeof
180 | "max-nested-callbacks": 0, // specify the maximum depth callbacks can be nested
181 | "one-var": [1, "never"], // allow just one var statement per function
182 | "wrap-regex": 0, // require regex literals to be wrapped in parentheses
183 |
184 | // ECMAScript 6/7 (2015 and above)
185 | "arrow-parens": 1, // require parens in arrow function arguments
186 | "arrow-spacing": 1, // require space before/after arrow function's arrow (fixable)
187 | "constructor-super": 1, // verify calls of super() in constructors
188 | "generator-star-spacing": 0, // enforce spacing around the * in generator functions (fixable)
189 | "no-class-assign": 1, // disallow modifying variables of class declarations
190 | "no-const-assign": 1, // disallow modifying variables that are declared using const
191 | "no-dupe-class-members": 1, // disallow duplicate name in class members
192 | "no-this-before-super": 1, // disallow use of this/super before calling super() in constructors.
193 | "no-var": 0, // require let or const instead of var
194 | "object-shorthand": 0, // require method and property shorthand syntax for object literals
195 | "prefer-arrow-callback": 1, // suggest using arrow functions as callbacks
196 | "prefer-const": 0, // suggest using const declaration for variables that are never modified after declared
197 | "prefer-reflect": 0, // suggest using Reflect methods where applicable
198 | "prefer-spread": 0, // suggest using the spread operator instead of .apply().
199 | "prefer-template": 0, // suggest using template literals instead of strings concatenation
200 | "require-yield": 0, // disallow generator functions that do not have yield
201 | "babel/no-await-in-loop": 1, // async inside a loop will run operations in serial, when often the desired behavior is to do do in parallel
202 |
203 | // Legacy (included for compatibility with JSHint and JSLint. While the names of the rules may not match up with the JSHint/JSLint counterpart, the functionality is the same)
204 |
205 | "max-depth": 0, // specify the maximum depth that blocks can be nested
206 | //"max-len": [ // specify the maximum length of a line in your program [warning level, max line length, number of characters to treat a tab as]
207 | // 1, 100, 2, {
208 | // "ignoreUrls": true,
209 | // "ignorePattern": "^\\s*(import\\s[^{]+from|(var|const|let)\\s[^{]+=\\s*require\\s*\\()"
210 | // }
211 | //],
212 | "max-params": 0, // limits the number of parameters that can be used in the function declaration.
213 | "max-statements": 0, // specify the maximum number of statement allowed in a function
214 | "no-bitwise": 0, // disallow use of bitwise operators
215 | "no-plusplus": 0 // disallow use of unary operators, ++ and --
216 |
217 | }
218 | }
219 |
--------------------------------------------------------------------------------
/.flowconfig:
--------------------------------------------------------------------------------
1 | [ignore]
2 | .*node_modules/babel.*
3 | .*node_modules/fbjs.*
4 |
5 | [include]
6 |
7 | [libs]
8 |
9 | [options]
10 | esproposal.class_static_fields=enable
11 | suppress_type=$FlowIssue
12 | suppress_comment=\\(.\\|\n\\)*\\$FlowIssue
13 |
--------------------------------------------------------------------------------
/.gitignore:
--------------------------------------------------------------------------------
1 | _*
2 | !__tests__
3 | /lib
4 | /node_modules
5 |
--------------------------------------------------------------------------------
/.npmignore:
--------------------------------------------------------------------------------
1 | .babelrc
2 | .eslintignore
3 | .eslintrc
4 | .flowconfig
5 | .travis.yml
6 | _*
7 | /src
8 |
--------------------------------------------------------------------------------
/.travis.yml:
--------------------------------------------------------------------------------
1 | language: node_js
2 | node_js:
3 | - "5"
4 |
--------------------------------------------------------------------------------
/LICENSE:
--------------------------------------------------------------------------------
1 | Copyright (c) 2016, Simon Sturmer
2 |
3 | Permission to use, copy, modify, and/or distribute this software for any
4 | purpose with or without fee is hereby granted, provided that the above
5 | copyright notice and this permission notice appear in all copies.
6 |
7 | THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
8 | WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
9 | MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
10 | ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
11 | WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
12 | ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
13 | OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
14 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | # Method auto-bind for ES6 (ES2015) classes
2 |
3 | This package provides a single function, `autobind`, for use within a constructor to bind all methods to the instance itself.
4 |
5 | For example, this allows us to pass a method to an event handler `element.addEventListener('click', this.onClick)` and be sure the `onClick` method will always be called with the right context.
6 |
7 | Note: This has some specific logic for React, but could be used in any project.
8 |
9 | ## Installation:
10 |
11 | `npm install --save class-autobind`
12 |
13 | ## Usage:
14 |
15 | ```js
16 | import autobind from 'class-autobind';
17 |
18 | class MyComponent extends React.Component {
19 | constructor() {
20 | super(...arguments);
21 | autobind(this);
22 | }
23 | render() {
24 | return ;
25 | }
26 | onClick() {
27 | console.log('Button Clicked');
28 | }
29 | }
30 | ```
31 |
32 | ## Advanced Usage:
33 |
34 | If your component will possibly be subclassed (you really should not do this, but some third-party libraries like [react-css-modules](https://npmjs.com/package/react-css-modules) do so) then you will need to specify which prototype will be the source of methods that are to be automatically bound.
35 |
36 | ```js
37 | import autobind from 'class-autobind';
38 |
39 | class MyComponent extends React.Component {
40 | constructor() {
41 | super(...arguments);
42 | autobind(this, MyComponent.prototype); // Note the second parameter.
43 | }
44 | render() {
45 | /* ... */
46 | }
47 | }
48 |
49 | class MySubClassedComponent extends MyComponent {
50 | /* This is probably a very bad idea. */
51 | }
52 | ```
53 |
54 | ## License
55 |
56 | This software is [BSD Licensed](/LICENSE).
57 |
--------------------------------------------------------------------------------
/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "class-autobind",
3 | "version": "0.1.4",
4 | "description": "Method auto-bind for ES6 (ES2015) classes",
5 | "main": "lib/autobind.js",
6 | "scripts": {
7 | "build": "rimraf lib && babel src --ignore '_*' --out-dir lib",
8 | "prepublish": "npm run build",
9 | "lint": "eslint --max-warnings 0 .",
10 | "typecheck": "flow",
11 | "test-src": "mocha src/__tests__/*.js src/**/__tests__/*.js",
12 | "test": "npm run lint && npm run typecheck && npm run test-src"
13 | },
14 | "dependencies": {},
15 | "devDependencies": {
16 | "babel-cli": "^6.10.1",
17 | "babel-core": "^6.9.1",
18 | "babel-eslint": "^6.0.4",
19 | "babel-plugin-transform-class-properties": "^6.9.1",
20 | "babel-preset-es2015": "^6.9.0",
21 | "babel-preset-es2015-loose": "^7.0.0",
22 | "babel-preset-react": "^6.5.0",
23 | "babel-preset-stage-2": "^6.5.0",
24 | "eslint": "^2.12.0",
25 | "eslint-plugin-babel": "^3.2.0",
26 | "eslint-plugin-flow-vars": "^0.4.0",
27 | "eslint-plugin-react": "^5.1.1",
28 | "expect": "^1.20.1",
29 | "flow-bin": "^0.27.0",
30 | "mocha": "^2.5.3",
31 | "rimraf": "^2.5.2"
32 | },
33 | "repository": {
34 | "type": "git",
35 | "url": "git+ssh://git@github.com/kodefox/class-autobind.git"
36 | },
37 | "keywords": [
38 | "react",
39 | "autobind",
40 | "es6-class"
41 | ],
42 | "author": "team@kodefox.com",
43 | "license": "ISC",
44 | "bugs": {
45 | "url": "https://github.com/kodefox/class-autobind/issues"
46 | },
47 | "homepage": "https://github.com/kodefox/class-autobind#readme"
48 | }
49 |
--------------------------------------------------------------------------------
/src/__tests__/autobind-test.js:
--------------------------------------------------------------------------------
1 | /* @flow */
2 | const {describe, it} = global;
3 | import expect from 'expect';
4 | import autobind from '../autobind';
5 |
6 | const invoke = (fn) => fn();
7 |
8 | describe('autobind', () => {
9 | it('should bind methods', () => {
10 | class Foo {
11 | constructor() {
12 | autobind(this);
13 | }
14 | getThis() {
15 | return this;
16 | }
17 | }
18 | let foo = new Foo();
19 | expect(foo.getThis).toNotBe(Foo.prototype.getThis);
20 | expect(invoke(foo.getThis)).toBe(foo);
21 | });
22 |
23 | it('should NOT bind excluded methods', () => {
24 | class Foo {
25 | constructor() {
26 | autobind(this);
27 | }
28 | render() {
29 | return this;
30 | }
31 | }
32 | let foo = new Foo();
33 | expect(foo.render).toBe(Foo.prototype.render);
34 | expect(invoke(foo.render)).toBe(undefined);
35 | });
36 |
37 | it('should NOT accept optional second param', () => {
38 | class Foo {
39 | constructor() {
40 | // When called from a subclass via super(), we cannot auto-detect which
41 | // prototype we should use as a source for autobind.
42 | autobind(this, Foo.prototype);
43 | }
44 | getThis() {
45 | return this;
46 | }
47 | }
48 | class Bar extends Foo {}
49 | let bar = new Bar();
50 | expect(bar.getThis).toNotBe(Foo.prototype.getThis);
51 | expect(invoke(bar.getThis)).toBe(bar);
52 | });
53 | });
54 |
--------------------------------------------------------------------------------
/src/autobind.js:
--------------------------------------------------------------------------------
1 | /* @flow */
2 |
3 | // The following React methods should not be automatically bound.
4 | const REACT_EXCLUDE_METHODS = {
5 | getChildContext: true,
6 | render: true,
7 | componentWillMount: true,
8 | componentDidMount: true,
9 | componentWillReceiveProps: true,
10 | shouldComponentUpdate: true,
11 | componentWillUpdate: true,
12 | componentDidUpdate: true,
13 | componentWillUnmount: true,
14 | };
15 |
16 | function isExcluded(methodName) {
17 | return (REACT_EXCLUDE_METHODS[methodName] === true);
18 | }
19 |
20 | function isFunction(item) {
21 | return (typeof item === 'function');
22 | }
23 |
24 | export default function autobind(instance: Object, proto: ?Object) {
25 | if (proto == null) {
26 | proto = Object.getPrototypeOf(instance);
27 | }
28 | let propertyNames = Object.getOwnPropertyNames(proto);
29 | for (let name of propertyNames) {
30 | let value = proto[name];
31 | if (isFunction(value) && !isExcluded(name)) {
32 | instance[name] = proto[name].bind(instance);
33 | }
34 | }
35 | }
36 |
--------------------------------------------------------------------------------
/test/mocha.opts:
--------------------------------------------------------------------------------
1 | --compilers js:babel-core/register
2 |
--------------------------------------------------------------------------------