Skip to content

Commit 88d80a4

Browse files
committed
add rule and spec for no-common-typos
1 parent 0a40c27 commit 88d80a4

File tree

2 files changed

+158
-0
lines changed

2 files changed

+158
-0
lines changed

lib/rules/no-common-typos.js

Lines changed: 94 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,94 @@
1+
/**
2+
* @fileoverview Warn for common attribute typos.
3+
* @author Koen Punt
4+
*/
5+
'use strict';
6+
7+
var Components = require('../util/Components');
8+
9+
// ------------------------------------------------------------------------------
10+
// Rule Definition
11+
// ------------------------------------------------------------------------------
12+
13+
var PATTERN_REGEXP = new RegExp('^/(.+)/(.+)?$');
14+
15+
/**
16+
* Convert pattern string to a regular expression.
17+
* @param {String|RegExp} string regex
18+
* @return {RegExp}
19+
*/
20+
function parsePattern(pattern) {
21+
if (pattern instanceof RegExp) {
22+
return pattern;
23+
}
24+
if (PATTERN_REGEXP.exec(pattern)) {
25+
return new RegExp(RegExp.$1, RegExp.$2);
26+
}
27+
return new RegExp('^' + pattern + '$');
28+
}
29+
30+
module.exports = {
31+
meta: {
32+
docs: {
33+
description: 'Warn for common attribute typos.',
34+
category: 'Possible Errors',
35+
recommended: false
36+
},
37+
schema: [{
38+
type: 'object',
39+
rules: {
40+
type: 'array',
41+
items: {
42+
type: 'object',
43+
properties: {
44+
pattern: {
45+
type: 'string'
46+
},
47+
correct: {
48+
type: 'string'
49+
}
50+
},
51+
additionalProperties: false
52+
}
53+
}
54+
}],
55+
fixable: 'code'
56+
},
57+
58+
create: Components.detect(function(context) {
59+
60+
var rules = context.options || [];
61+
62+
/**
63+
* Checks if we are using an incorrect cased dangerouslySetInnerHTML attribute.
64+
* @param {ASTNode} node The AST node being checked.
65+
* @returns {Boolean} True if we are using a ref attribute, false if not.
66+
*/
67+
function isIncorrectAttributeName(regex, correct, node) {
68+
return Boolean(
69+
node.type === 'JSXAttribute' &&
70+
node.name &&
71+
node.name.name !== correct &&
72+
regex.test(node.name.name)
73+
);
74+
}
75+
76+
return {
77+
JSXAttribute: function(node) {
78+
rules.forEach(function(rule) {
79+
var regex = parsePattern(rule.pattern);
80+
if (isIncorrectAttributeName(regex, rule.correct, node)) {
81+
var attribute = node.name.name;
82+
context.report({
83+
node: node,
84+
message: 'Using possible incorrect attribute `' + attribute + '`, did you mean `' + rule.correct + '`?',
85+
fix: function(fixer) {
86+
return fixer.replaceText(attribute, rule.correct);
87+
}
88+
});
89+
}
90+
});
91+
}
92+
};
93+
})
94+
};

tests/lib/rules/no-common-typos.js

Lines changed: 64 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,64 @@
1+
/**
2+
* @fileoverview Prevent string definitions for references and prevent referencing this.refs
3+
* @author Tom Hastjarjanto
4+
*/
5+
'use strict';
6+
7+
// ------------------------------------------------------------------------------
8+
// Requirements
9+
// ------------------------------------------------------------------------------
10+
11+
var rule = require('../../../lib/rules/no-common-typos');
12+
var RuleTester = require('eslint').RuleTester;
13+
14+
require('babel-eslint');
15+
16+
// ------------------------------------------------------------------------------
17+
// Tests
18+
// ------------------------------------------------------------------------------
19+
20+
var options = [
21+
{
22+
pattern: /dangerouslySetInnerHTML/i,
23+
correct: 'dangerouslySetInnerHTML'
24+
}
25+
];
26+
27+
var ruleTester = new RuleTester();
28+
ruleTester.run('no-common-typos', rule, {
29+
30+
valid: [{
31+
code: [
32+
'var Hello = React.createClass({',
33+
' render: function() {',
34+
' return <div dangerouslySetInnerHTML={{__html: "Hello World"}}/>;',
35+
' }',
36+
'});'
37+
].join('\n'),
38+
options: options,
39+
parser: 'babel-eslint',
40+
ecmaFeatures: {
41+
jsx: true
42+
}
43+
}
44+
],
45+
46+
invalid: [{
47+
code: [
48+
'var Hello = React.createClass({',
49+
' render: function() {',
50+
' return <div dangerouslySetInnerHtml={{__html: "Hello World"}}/>;',
51+
' }',
52+
'});'
53+
].join('\n'),
54+
options: options,
55+
parser: 'babel-eslint',
56+
ecmaFeatures: {
57+
classes: true,
58+
jsx: true
59+
},
60+
errors: [{
61+
message: 'Using possible incorrect attribute `dangerouslySetInnerHtml`, did you mean `dangerouslySetInnerHTML`?'
62+
}]
63+
}]
64+
});

0 commit comments

Comments
 (0)