Skip to content

Commit

Permalink
Add new rule: jsx-no-bind (#85)
Browse files Browse the repository at this point in the history
  • Loading branch information
lvillani authored and adidahiya committed Apr 13, 2017
1 parent cdd1d40 commit 84759ad
Show file tree
Hide file tree
Showing 4 changed files with 92 additions and 0 deletions.
59 changes: 59 additions & 0 deletions src/rules/jsxNoBindRule.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,59 @@
/**
* @license
* Copyright 2017 Palantir Technologies, Inc.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/

import * as Lint from "tslint";
import * as ts from "typescript";

export class Rule extends Lint.Rules.AbstractRule {
public static FAILURE_STRING = "Binds are forbidden in JSX attributes due to their rendering performance impact";

public apply(sourceFile: ts.SourceFile): Lint.RuleFailure[] {
// This creates a WalkContext<T> and passes it in as an argument.
// An optional 3rd parameter allows you to pass in a parsed version
// of this.ruleArguments. If used, it is preferred to parse it into
// a more useful object than this.getOptions().
return this.applyWithFunction(sourceFile, walk);
}
}

function walk(ctx: Lint.WalkContext<void>): void {
return ts.forEachChild(ctx.sourceFile, cb);

function cb(node: ts.Node): void {
if (node.kind !== ts.SyntaxKind.JsxAttribute) {
return ts.forEachChild(node, cb);
}

const initializer = (node as ts.JsxAttribute).initializer;

if (!initializer || (initializer.kind !== ts.SyntaxKind.JsxExpression)) {
return;
}

const expression = (initializer as ts.JsxExpression).expression;

if (!expression || expression.kind !== ts.SyntaxKind.CallExpression) {
return;
}

if (!expression.getText(ctx.sourceFile).includes(".bind(this)")) {
return;
}

return ctx.addFailureAtNode(expression, Rule.FAILURE_STRING);
}
}
27 changes: 27 additions & 0 deletions test/rules/jsx-no-bind/test.tsx.lint
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
function foo() {
}

export const myButton = (
<button onClick={foo.bind(this)}>
~~~~~~~~~~~~~~ [0]
Log something
</button>
);

export const myButton2 = (
<button onClick={this.foo.bind(this)}>
~~~~~~~~~~~~~~~~~~~ [0]
Log something
</button>
);

export const selector = (
<Component
prop1={this.state.availableColumns}
prop2={this.onChangeHandler.bind(this)}
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ [0]
prop3={this.state.stateVar1}
/>
);

[0]: Binds are forbidden in JSX attributes due to their rendering performance impact
5 changes: 5 additions & 0 deletions test/rules/jsx-no-bind/tslint.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
{
"rules": {
"jsx-no-bind": true
}
}
1 change: 1 addition & 0 deletions tslint-react.json
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@
"jsx-alignment": true,
"jsx-boolean-value": true,
"jsx-curly-spacing": [true, "never"],
"jsx-no-bind": true,
"jsx-no-lambda": true,
"jsx-no-multiline-js": true,
"jsx-no-string-ref": true,
Expand Down

0 comments on commit 84759ad

Please sign in to comment.