Skip to content

Commit

Permalink
Merge branch 'master' into jsx-handler-names
Browse files Browse the repository at this point in the history
  • Loading branch information
jakemmarsh committed Nov 23, 2015
2 parents 4ecbfe1 + add052f commit fcc0ffe
Show file tree
Hide file tree
Showing 12 changed files with 73 additions and 41 deletions.
13 changes: 13 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,19 @@ All notable changes to this project will be documented in this file.
This project adheres to [Semantic Versioning](http://semver.org/).
This change log adheres to standards from [Keep a CHANGELOG](http://keepachangelog.com).

## [3.10.0] - 2015-11-21
### Added
* Add `jsx-pascal-case` rule ([#306][] @jakemmarsh)

### Fixed
* Fix crash on incomplete class property declaration ([#317][] @dapetcu21)
* Fix crash with ESLint 1.10.0 ([#323][] @lukekarrys)

[3.10.0]: https://github.com/yannickcr/eslint-plugin-react/compare/v3.9.0...v3.10.0
[#306]: https://github.com/yannickcr/eslint-plugin-react/pull/306
[#317]: https://github.com/yannickcr/eslint-plugin-react/issues/317
[#323]: https://github.com/yannickcr/eslint-plugin-react/issues/323

## [3.9.0] - 2015-11-17
### Added
* Add `jsx-key` rule ([#293][] @benmosher)
Expand Down
1 change: 1 addition & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -59,6 +59,7 @@ Finally, enable all of the rules that you would like to use.
"react/jsx-no-duplicate-props": 1,
"react/jsx-no-literals": 1,
"react/jsx-no-undef": 1,
"react/jsx-pascal-case": 1,
"react/jsx-quotes": 1,
"react/jsx-sort-prop-types": 1,
"react/jsx-sort-props": 1,
Expand Down
4 changes: 2 additions & 2 deletions lib/rules/display-name.js
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@ var Components = require('../util/Components');
// Rule Definition
// ------------------------------------------------------------------------------

module.exports = Components.detect(function(context, components) {
module.exports = Components.detect(function(context, components, utils) {

var config = context.options[0] || {};
var acceptTranspilerName = config.acceptTranspilerName || false;
Expand Down Expand Up @@ -131,7 +131,7 @@ module.exports = Components.detect(function(context, components) {
if (!isDisplayNameDeclaration(node.property)) {
return;
}
var component = context.react.getRelatedComponent(node);
var component = utils.getRelatedComponent(node);
if (!component) {
return;
}
Expand Down
6 changes: 2 additions & 4 deletions lib/rules/jsx-sort-prop-types.js
Original file line number Diff line number Diff line change
Expand Up @@ -24,10 +24,8 @@ module.exports = function(context) {
// (babel-eslint does not expose property name so we have to rely on tokens)
if (node.type === 'ClassProperty') {
var tokens = context.getFirstTokens(node, 2);
if (tokens[0].value === 'propTypes' || tokens[1].value === 'propTypes') {
return true;
}
return false;
return (tokens[0] && tokens[0].value === 'propTypes') ||
(tokens[1] && tokens[1].value === 'propTypes');
}

return Boolean(
Expand Down
4 changes: 2 additions & 2 deletions lib/rules/no-direct-mutation-state.js
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@ var Components = require('../util/Components');
// Rule Definition
// ------------------------------------------------------------------------------

module.exports = Components.detect(function(context, components) {
module.exports = Components.detect(function(context, components, utils) {

/**
* Checks if the component is valid
Expand Down Expand Up @@ -51,7 +51,7 @@ module.exports = Components.detect(function(context, components) {
item.object.type === 'ThisExpression' &&
item.property.name === 'state'
) {
var component = components.get(context.react.getParentComponent());
var component = components.get(utils.getParentComponent());
var mutations = component && component.mutations || [];
mutations.push(node.left.object);
components.set(node, {
Expand Down
23 changes: 19 additions & 4 deletions lib/rules/no-unknown-property.js
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@ var DOM_ATTRIBUTE_NAMES = {
};

var DOM_PROPERTY_NAMES = [
// Standard
'acceptCharset', 'accessKey', 'allowFullScreen', 'allowTransparency', 'autoComplete', 'autoFocus', 'autoPlay',
'cellPadding', 'cellSpacing', 'charSet', 'classID', 'className', 'colSpan', 'contentEditable', 'contextMenu',
'crossOrigin', 'dateTime', 'encType', 'formAction', 'formEncType', 'formMethod', 'formNoValidate', 'formTarget',
Expand All @@ -28,7 +29,20 @@ var DOM_PROPERTY_NAMES = [
'onMouseMove', 'onMouseOut', 'onMouseOver', 'onMouseUp', 'onPaste', 'onScroll', 'onSubmit', 'onTouchCancel',
'onTouchEnd', 'onTouchMove', 'onTouchStart', 'onWheel',
'radioGroup', 'readOnly', 'rowSpan', 'spellCheck', 'srcDoc', 'srcSet', 'tabIndex', 'useMap',
'itemProp', 'itemScope', 'itemType', 'itemRef', 'itemID'
// Non standard
'autoCapitalize', 'autoCorrect',
'autoSave',
'itemProp', 'itemScope', 'itemType', 'itemRef', 'itemID',
// SVG
'clipPath', 'cx', 'cy', 'd', 'dx', 'dy', 'fill', 'fillOpacity', 'fontFamily',
'fontSize', 'fx', 'fy', 'gradientTransform', 'gradientUnits', 'markerEnd',
'markerMid', 'markerStart', 'offset', 'opacity', 'patternContentUnits',
'patternUnits', 'points', 'preserveAspectRatio', 'r', 'rx', 'ry', 'spreadMethod',
'stopColor', 'stopOpacity', 'stroke', 'strokeDasharray', 'strokeLinecap',
'strokeOpacity', 'strokeWidth', 'textAnchor', 'transform', 'version',
'viewBox', 'x1', 'x2', 'x', 'y1', 'y2', 'y',
'xlink:Actuate', 'xlink:Arcrole', 'xlink:Href', 'xlink:Role', 'xlink:Show', 'xlink:Title', 'xlink:Type',
'xml:Base', 'xml:Lang', 'xml:Space'
];

// ------------------------------------------------------------------------------
Expand Down Expand Up @@ -69,7 +83,7 @@ function getStandardName(name) {
i = index;
return element.toLowerCase() === name;
});
return found ? DOM_PROPERTY_NAMES[i] : null;
return found ? DOM_PROPERTY_NAMES[i].replace(':', '') : null;
}

// ------------------------------------------------------------------------------
Expand All @@ -81,12 +95,13 @@ module.exports = function(context) {
return {

JSXAttribute: function(node) {
var standardName = getStandardName(node.name.name);
var name = context.getSource(node.name);
var standardName = getStandardName(name);
if (!isTagName(node) || !standardName) {
return;
}
context.report(node, UNKNOWN_MESSAGE, {
name: node.name.name,
name: name,
standardName: standardName
});
}
Expand Down
4 changes: 2 additions & 2 deletions lib/rules/prefer-es6-class.js
Original file line number Diff line number Diff line change
Expand Up @@ -10,11 +10,11 @@ var Components = require('../util/Components');
// Rule Definition
// ------------------------------------------------------------------------------

module.exports = Components.detect(function(context) {
module.exports = Components.detect(function(context, components, utils) {

return {
ObjectExpression: function(node) {
if (context.react.isES5Component(node)) {
if (utils.isES5Component(node)) {
context.report(node, 'Component should use es6 class instead of createClass');
}
}
Expand Down
10 changes: 5 additions & 5 deletions lib/rules/prop-types.js
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@ var Components = require('../util/Components');
// Rule Definition
// ------------------------------------------------------------------------------

module.exports = Components.detect(function(context, components) {
module.exports = Components.detect(function(context, components, utils) {

var configuration = context.options[0] || {};
var ignored = configuration.ignore || [];
Expand All @@ -28,7 +28,7 @@ module.exports = Components.detect(function(context, components) {
*/
function isPropTypesUsage(node) {
var isClassUsage = (
(context.react.getParentES6Component() || context.react.getParentES5Component()) &&
(utils.getParentES6Component() || utils.getParentES5Component()) &&
node.object.type === 'ThisExpression' && node.property.name === 'props'
);
var isStatelessFunctionUsage = node.object.name === 'props';
Expand Down Expand Up @@ -328,7 +328,7 @@ module.exports = Components.detect(function(context, components) {
*/
function getPropertyName(node) {
var isDirectProp = /^props(\.|\[)/.test(context.getSource(node));
var isInClassComponent = context.react.getParentES6Component() || context.react.getParentES5Component();
var isInClassComponent = utils.getParentES6Component() || utils.getParentES5Component();
var isNotInConstructor = !inConstructor(node);
if (isDirectProp && isInClassComponent && isNotInConstructor) {
return void 0;
Expand Down Expand Up @@ -408,7 +408,7 @@ module.exports = Components.detect(function(context, components) {
throw new Error(node.type + ' ASTNodes are not handled by markPropTypesAsUsed');
}

var component = components.get(context.react.getParentComponent());
var component = components.get(utils.getParentComponent());
var usedPropTypes = component && component.usedPropTypes || [];

switch (type) {
Expand Down Expand Up @@ -569,7 +569,7 @@ module.exports = Components.detect(function(context, components) {
markPropTypesAsUsed(node);
break;
case 'declaration':
var component = context.react.getRelatedComponent(node);
var component = utils.getRelatedComponent(node);
if (!component) {
return;
}
Expand Down
2 changes: 1 addition & 1 deletion lib/rules/sort-comp.js
Original file line number Diff line number Diff line change
Expand Up @@ -132,7 +132,7 @@ module.exports = Components.detect(function(context, components) {
// (babel-eslint does not expose property name so we have to rely on tokens)
if (node.type === 'ClassProperty') {
var tokens = context.getFirstTokens(node, 2);
return tokens[1].type === 'Identifier' ? tokens[1].value : tokens[0].value;
return tokens[1] && tokens[1].type === 'Identifier' ? tokens[1].value : tokens[0].value;
}

return node.key.name;
Expand Down
34 changes: 17 additions & 17 deletions lib/util/Components.js
Original file line number Diff line number Diff line change
Expand Up @@ -108,7 +108,7 @@ function componentRule(rule, context) {
var components = new Components();

// Utilities for component detection
context.react = {
var utils = {

/**
* Check if the node is a React ES5 component
Expand Down Expand Up @@ -176,9 +176,9 @@ function componentRule(rule, context) {
*/
getParentComponent: function() {
return (
context.react.getParentES6Component() ||
context.react.getParentES5Component() ||
context.react.getParentStatelessComponent()
utils.getParentES6Component() ||
utils.getParentES5Component() ||
utils.getParentStatelessComponent()
);
},

Expand All @@ -191,7 +191,7 @@ function componentRule(rule, context) {
var scope = context.getScope();
while (scope) {
var node = scope.block && scope.block.parent && scope.block.parent.parent;
if (node && context.react.isES5Component(node)) {
if (node && utils.isES5Component(node)) {
return node;
}
scope = scope.upper;
Expand All @@ -210,7 +210,7 @@ function componentRule(rule, context) {
scope = scope.upper;
}
var node = scope && scope.block;
if (!node || !context.react.isES6Component(node)) {
if (!node || !utils.isES6Component(node)) {
return null;
}
return node;
Expand Down Expand Up @@ -316,57 +316,57 @@ function componentRule(rule, context) {
// Component detection instructions
var detectionInstructions = {
ClassDeclaration: function(node) {
if (!context.react.isES6Component(node)) {
if (!utils.isES6Component(node)) {
return;
}
components.add(node, 2);
},

ClassProperty: function(node) {
node = context.react.getParentComponent();
node = utils.getParentComponent();
if (!node) {
return;
}
components.add(node, 2);
},

ObjectExpression: function(node) {
if (!context.react.isES5Component(node)) {
if (!utils.isES5Component(node)) {
return;
}
components.add(node, 2);
},

FunctionExpression: function(node) {
node = context.react.getParentComponent();
node = utils.getParentComponent();
if (!node) {
return;
}
components.add(node, 1);
},

FunctionDeclaration: function(node) {
node = context.react.getParentComponent();
node = utils.getParentComponent();
if (!node) {
return;
}
components.add(node, 1);
},

ArrowFunctionExpression: function(node) {
node = context.react.getParentComponent();
node = utils.getParentComponent();
if (!node) {
return;
}
if (node.expression && context.react.isReturningJSX(node)) {
if (node.expression && utils.isReturningJSX(node)) {
components.add(node, 2);
} else {
components.add(node, 1);
}
},

ThisExpression: function(node) {
node = context.react.getParentComponent();
node = utils.getParentComponent();
if (!node || !/Function/.test(node.type)) {
return;
}
Expand All @@ -375,10 +375,10 @@ function componentRule(rule, context) {
},

ReturnStatement: function(node) {
if (!context.react.isReturningJSX(node)) {
if (!utils.isReturningJSX(node)) {
return;
}
node = context.react.getParentComponent();
node = utils.getParentComponent();
if (!node) {
return;
}
Expand All @@ -387,7 +387,7 @@ function componentRule(rule, context) {
};

// Update the provided rule instructions to add the component detection
var ruleInstructions = rule(context, components);
var ruleInstructions = rule(context, components, utils);
var updatedRuleInstructions = util._extend({}, ruleInstructions);
Object.keys(detectionInstructions).forEach(function(instruction) {
updatedRuleInstructions[instruction] = function(node) {
Expand Down
4 changes: 2 additions & 2 deletions package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "eslint-plugin-react",
"version": "3.9.0",
"version": "3.10.0",
"author": "Yannick Croissant <yannick.croissant+npm@gmail.com>",
"description": "React specific linting rules for ESLint",
"main": "index.js",
Expand All @@ -25,7 +25,7 @@
"devDependencies": {
"babel-eslint": "4.1.5",
"coveralls": "2.11.4",
"eslint": "1.9.0",
"eslint": "1.10.0",
"istanbul": "0.4.0",
"mocha": "2.3.4"
},
Expand Down
9 changes: 7 additions & 2 deletions tests/lib/rules/no-unknown-property.js
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,7 @@ ruleTester.run('no-unknown-property', rule, {
{code: '<App for="bar" />;', ecmaFeatures: {jsx: true}},
{code: '<App accept-charset="bar" />;', ecmaFeatures: {jsx: true}},
{code: '<App http-equiv="bar" />;', ecmaFeatures: {jsx: true}},
{code: '<App xlink:href="bar" />;', ecmaFeatures: {jsx: true}},
{code: '<div className="bar"></div>;', ecmaFeatures: {jsx: true}},
{code: '<div data-foo="bar"></div>;', ecmaFeatures: {jsx: true}},
{code: '<div class="foo" is="my-elem"></div>;', ecmaFeatures: {jsx: true}},
Expand Down Expand Up @@ -56,6 +57,10 @@ ruleTester.run('no-unknown-property', rule, {
}, {
code: '<div onmousedown="bar"></div>;',
errors: [{message: 'Unknown property \'onmousedown\' found, use \'onMouseDown\' instead'}],
ecmaFeatures: {jsx: true}}
]
ecmaFeatures: {jsx: true}
}, {
code: '<use xlink:href="bar" />;',
errors: [{message: 'Unknown property \'xlink:href\' found, use \'xlinkHref\' instead'}],
ecmaFeatures: {jsx: true}
}]
});

0 comments on commit fcc0ffe

Please sign in to comment.