eslint-plugin-react
Advanced tools
Comparing version 3.6.3 to 3.7.0
@@ -6,2 +6,23 @@ # Change Log | ||
## [3.7.0] - 2015-11-05 | ||
### Added | ||
* Add `jsx-no-bind` rule ([#184][] @Daniel15) | ||
* Add line-aligned option to `jsx-closing-bracket-location` ([#243][] @alopatin) | ||
### Fixed | ||
* Fix a lot of issues about components detection, mostly related to stateless components ([#264][], [#267][], [#268][], [#276][], [#277][], [#280][]) | ||
### Changed | ||
* Update dependencies | ||
[3.7.0]: https://github.com/yannickcr/eslint-plugin-react/compare/v3.6.3...v3.7.0 | ||
[#184]: https://github.com/yannickcr/eslint-plugin-react/issues/184 | ||
[#243]: https://github.com/yannickcr/eslint-plugin-react/issues/243 | ||
[#264]: https://github.com/yannickcr/eslint-plugin-react/issues/264 | ||
[#267]: https://github.com/yannickcr/eslint-plugin-react/issues/267 | ||
[#268]: https://github.com/yannickcr/eslint-plugin-react/issues/268 | ||
[#276]: https://github.com/yannickcr/eslint-plugin-react/issues/276 | ||
[#277]: https://github.com/yannickcr/eslint-plugin-react/issues/277 | ||
[#280]: https://github.com/yannickcr/eslint-plugin-react/issues/280 | ||
## [3.6.3] - 2015-10-20 | ||
@@ -8,0 +29,0 @@ ### Fixed |
@@ -17,2 +17,3 @@ 'use strict'; | ||
'jsx-uses-vars': require('./lib/rules/jsx-uses-vars'), | ||
'jsx-no-bind': require('./lib/rules/jsx-no-bind'), | ||
'jsx-no-undef': require('./lib/rules/jsx-no-undef'), | ||
@@ -49,2 +50,3 @@ 'jsx-quotes': require('./lib/rules/jsx-quotes'), | ||
'jsx-uses-vars': 1, | ||
'jsx-no-bind': 0, | ||
'jsx-no-undef': 0, | ||
@@ -51,0 +53,0 @@ 'jsx-quotes': 0, |
@@ -7,4 +7,3 @@ /** | ||
var componentUtil = require('../util/component'); | ||
var ComponentList = componentUtil.List; | ||
var Components = require('../util/Components'); | ||
@@ -15,3 +14,3 @@ // ------------------------------------------------------------------------------ | ||
module.exports = function(context) { | ||
module.exports = Components.detect(function(context, components) { | ||
@@ -21,6 +20,3 @@ var config = context.options[0] || {}; | ||
var componentList = new ComponentList(); | ||
var MISSING_MESSAGE = 'Component definition is missing display name'; | ||
var MISSING_MESSAGE_NAMED_COMP = '{{component}} component definition is missing display name'; | ||
@@ -57,3 +53,3 @@ /** | ||
function markDisplayNameAsDeclared(node) { | ||
componentList.set(context, node, { | ||
components.set(node, { | ||
hasDisplayName: true | ||
@@ -70,3 +66,3 @@ }); | ||
component.node, | ||
component.name === componentUtil.DEFAULT_COMPONENT_NAME ? MISSING_MESSAGE : MISSING_MESSAGE_NAMED_COMP, { | ||
MISSING_MESSAGE, { | ||
component: component.name | ||
@@ -143,3 +139,3 @@ } | ||
} | ||
var component = componentList.getByName(context.getSource(node.object)); | ||
var component = context.react.getRelatedComponent(node); | ||
if (!component) { | ||
@@ -152,3 +148,2 @@ return; | ||
FunctionExpression: function(node) { | ||
componentList.set(context, node); | ||
if (!acceptTranspilerName || !hasTranspilerName(node)) { | ||
@@ -161,3 +156,2 @@ return; | ||
FunctionDeclaration: function(node) { | ||
componentList.set(context, node); | ||
if (!acceptTranspilerName || !hasTranspilerName(node)) { | ||
@@ -170,3 +164,2 @@ return; | ||
ArrowFunctionExpression: function(node) { | ||
componentList.set(context, node); | ||
if (!acceptTranspilerName || !hasTranspilerName(node)) { | ||
@@ -186,3 +179,2 @@ return; | ||
ClassDeclaration: function(node) { | ||
componentList.set(context, node); | ||
if (!acceptTranspilerName || !hasTranspilerName(node)) { | ||
@@ -195,3 +187,2 @@ return; | ||
ObjectExpression: function(node) { | ||
componentList.set(context, node); | ||
if (!acceptTranspilerName || !hasTranspilerName(node)) { | ||
@@ -210,8 +201,4 @@ // Search for the displayName declaration | ||
ReturnStatement: function(node) { | ||
componentList.set(context, node); | ||
}, | ||
'Program:exit': function() { | ||
var list = componentList.getList(); | ||
var list = components.list(); | ||
// Report missing display name for all components | ||
@@ -226,3 +213,3 @@ for (var component in list) { | ||
}; | ||
}; | ||
}); | ||
@@ -229,0 +216,0 @@ module.exports.schema = [{ |
@@ -17,3 +17,4 @@ /** | ||
'props-aligned': 'aligned with the last prop', | ||
'tag-aligned': 'aligned with the opening tag' | ||
'tag-aligned': 'aligned with the opening tag', | ||
'line-aligned': 'aligned with the line containing the opening tag' | ||
}; | ||
@@ -84,2 +85,4 @@ var DEFAULT_LOCATION = 'tag-aligned'; | ||
return tokens.opening.column === tokens.closing.column; | ||
case 'line-aligned': | ||
return tokens.openingStartOfLine.column === tokens.closing.column; | ||
default: | ||
@@ -91,5 +94,7 @@ return true; | ||
/** | ||
* Get the locations of the opening bracket, closing bracket and last prop | ||
* Get the locations of the opening bracket, closing bracket, last prop, and | ||
* start of opening line. | ||
* @param {ASTNode} node The node to check | ||
* @return {Object} Locations of the opening bracket, closing bracket and last prop | ||
* @return {Object} Locations of the opening bracket, closing bracket, last | ||
* prop and start of opening line. | ||
*/ | ||
@@ -108,2 +113,7 @@ function getTokensLocations(node) { | ||
} | ||
var openingLine = context.getSourceCode().lines[opening.line - 1]; | ||
var openingStartOfLine = { | ||
column: /^\s*/.exec(openingLine)[0].length, | ||
line: opening.line | ||
}; | ||
return { | ||
@@ -114,3 +124,4 @@ tag: tag, | ||
lastProp: lastProp, | ||
selfClosing: node.selfClosing | ||
selfClosing: node.selfClosing, | ||
openingStartOfLine: openingStartOfLine | ||
}; | ||
@@ -137,3 +148,3 @@ } | ||
{ | ||
enum: ['after-props', 'props-aligned', 'tag-aligned'] | ||
enum: ['after-props', 'props-aligned', 'tag-aligned', 'line-aligned'] | ||
}, | ||
@@ -144,3 +155,3 @@ { | ||
location: { | ||
enum: ['after-props', 'props-aligned', 'tag-aligned'] | ||
enum: ['after-props', 'props-aligned', 'tag-aligned', 'line-aligned'] | ||
} | ||
@@ -153,6 +164,6 @@ }, | ||
nonEmpty: { | ||
enum: ['after-props', 'props-aligned', 'tag-aligned'] | ||
enum: ['after-props', 'props-aligned', 'tag-aligned', 'line-aligned'] | ||
}, | ||
selfClosing: { | ||
enum: ['after-props', 'props-aligned', 'tag-aligned'] | ||
enum: ['after-props', 'props-aligned', 'tag-aligned', 'line-aligned'] | ||
} | ||
@@ -159,0 +170,0 @@ }, |
@@ -7,4 +7,3 @@ /** | ||
var componentUtil = require('../util/component'); | ||
var ComponentList = componentUtil.List; | ||
var Components = require('../util/Components'); | ||
@@ -15,6 +14,4 @@ // ------------------------------------------------------------------------------ | ||
module.exports = function(context) { | ||
module.exports = Components.detect(function(context, components) { | ||
var componentList = new ComponentList(); | ||
/** | ||
@@ -46,11 +43,2 @@ * Checks if the component is valid | ||
return { | ||
ObjectExpression: function(node) { | ||
componentList.set(context, node); | ||
}, | ||
ClassDeclaration: function(node) { | ||
componentList.set(context, node); | ||
}, | ||
AssignmentExpression: function(node) { | ||
@@ -69,6 +57,6 @@ var item; | ||
) { | ||
var component = componentList.getByNode(context, node); | ||
var component = components.get(context.react.getParentComponent()); | ||
var mutations = component && component.mutations || []; | ||
mutations.push(node.left.object); | ||
componentList.set(context, node, { | ||
components.set(node, { | ||
mutateSetState: true, | ||
@@ -81,3 +69,3 @@ mutations: mutations | ||
'Program:exit': function() { | ||
var list = componentList.getList(); | ||
var list = components.list(); | ||
for (var component in list) { | ||
@@ -92,2 +80,2 @@ if (!list.hasOwnProperty(component) || isValid(list[component])) { | ||
}; | ||
}); |
@@ -7,4 +7,3 @@ /** | ||
var componentUtil = require('../util/component'); | ||
var ComponentList = componentUtil.List; | ||
var Components = require('../util/Components'); | ||
@@ -15,6 +14,4 @@ // ------------------------------------------------------------------------------ | ||
module.exports = function(context) { | ||
module.exports = Components.detect(function(context, components) { | ||
var componentList = new ComponentList(); | ||
var MULTI_COMP_MESSAGE = 'Declare only one React component per file'; | ||
@@ -27,17 +24,8 @@ | ||
return { | ||
ClassDeclaration: function(node) { | ||
componentList.set(context, node); | ||
}, | ||
ObjectExpression: function(node) { | ||
componentList.set(context, node); | ||
}, | ||
'Program:exit': function() { | ||
if (componentList.count() <= 1) { | ||
if (components.length() <= 1) { | ||
return; | ||
} | ||
var list = componentList.getList(); | ||
var list = components.list(); | ||
var i = 0; | ||
@@ -53,4 +41,4 @@ | ||
}; | ||
}; | ||
}); | ||
module.exports.schema = []; |
@@ -7,3 +7,3 @@ /** | ||
var componentUtil = require('../util/component'); | ||
var Components = require('../util/Components'); | ||
@@ -14,7 +14,7 @@ // ------------------------------------------------------------------------------ | ||
module.exports = function(context) { | ||
module.exports = Components.detect(function(context) { | ||
return { | ||
ObjectExpression: function(node) { | ||
if (componentUtil.isComponentDefinition(context, node)) { | ||
if (context.react.isES5Component(node)) { | ||
context.report(node, 'Component should use es6 class instead of createClass'); | ||
@@ -24,4 +24,4 @@ } | ||
}; | ||
}; | ||
}); | ||
module.exports.schema = []; |
@@ -10,4 +10,3 @@ /** | ||
var componentUtil = require('../util/component'); | ||
var ComponentList = componentUtil.List; | ||
var Components = require('../util/Components'); | ||
@@ -18,3 +17,3 @@ // ------------------------------------------------------------------------------ | ||
module.exports = function(context) { | ||
module.exports = Components.detect(function(context, components) { | ||
@@ -25,6 +24,3 @@ var configuration = context.options[0] || {}; | ||
var componentList = new ComponentList(); | ||
var MISSING_MESSAGE = '\'{{name}}\' is missing in props validation'; | ||
var MISSING_MESSAGE_NAMED_COMP = '\'{{name}}\' is missing in props validation for {{component}}'; | ||
@@ -38,3 +34,3 @@ /** | ||
var isClassUsage = ( | ||
componentUtil.getNode(context, node) && | ||
(context.react.getParentES6Component() || context.react.getParentES5Component()) && | ||
node.object.type === 'ThisExpression' && node.property.name === 'props' | ||
@@ -338,7 +334,9 @@ ); | ||
function getPropertyName(node) { | ||
var directProp = /^props\./.test(context.getSource(node)); | ||
if (directProp && componentUtil.getNode(context, node) && !inConstructor(node)) { | ||
var isDirectProp = /^props\./.test(context.getSource(node)); | ||
var isInClassComponent = context.react.getParentES6Component() || context.react.getParentES5Component(); | ||
var isNotInConstructor = !inConstructor(node); | ||
if (isDirectProp && isInClassComponent && isNotInConstructor) { | ||
return void 0; | ||
} | ||
if (!directProp) { | ||
if (!isDirectProp) { | ||
node = node.parent; | ||
@@ -418,3 +416,3 @@ } | ||
var component = componentList.getByNode(context, node); | ||
var component = components.get(context.react.getParentComponent()); | ||
var usedPropTypes = component && component.usedPropTypes || []; | ||
@@ -428,6 +426,9 @@ | ||
} | ||
var isDirectProp = /^props\./.test(context.getSource(node)); | ||
usedPropTypes.push({ | ||
name: name, | ||
allNames: allNames, | ||
node: node.object.name !== 'props' && !inConstructor() ? node.parent.property : node.property | ||
node: !isDirectProp && !inConstructor(node) ? node.parent.property : node.property | ||
}); | ||
@@ -463,3 +464,3 @@ break; | ||
componentList.set(context, node, { | ||
components.set(node, { | ||
usedPropTypes: usedPropTypes | ||
@@ -475,3 +476,3 @@ }); | ||
function markPropTypesAsDeclared(node, propTypes) { | ||
var component = componentList.getByNode(context, node); | ||
var component = components.get(node); | ||
var declaredPropTypes = component && component.declaredPropTypes || {}; | ||
@@ -519,3 +520,3 @@ var ignorePropsValidation = false; | ||
componentList.set(context, node, { | ||
components.set(node, { | ||
declaredPropTypes: declaredPropTypes, | ||
@@ -542,5 +543,4 @@ ignorePropsValidation: ignorePropsValidation | ||
component.usedPropTypes[i].node, | ||
component.name === componentUtil.DEFAULT_COMPONENT_NAME ? MISSING_MESSAGE : MISSING_MESSAGE_NAMED_COMP, { | ||
name: allNames.join('.').replace(/\.__COMPUTED_PROP__/g, '[]'), | ||
component: component.name | ||
MISSING_MESSAGE, { | ||
name: allNames.join('.').replace(/\.__COMPUTED_PROP__/g, '[]') | ||
} | ||
@@ -556,7 +556,2 @@ ); | ||
return { | ||
ClassDeclaration: function(node) { | ||
componentList.set(context, node); | ||
}, | ||
ClassProperty: function(node) { | ||
@@ -566,3 +561,2 @@ if (!isPropTypesDeclaration(node)) { | ||
} | ||
markPropTypesAsDeclared(node, node.value); | ||
@@ -591,3 +585,3 @@ }, | ||
case 'declaration': | ||
var component = componentList.getByName(node.object.name); | ||
var component = context.react.getRelatedComponent(node); | ||
if (!component) { | ||
@@ -621,3 +615,2 @@ return; | ||
ObjectExpression: function(node) { | ||
componentList.set(context, node); | ||
// Search for the proptypes declaration | ||
@@ -632,8 +625,4 @@ node.properties.forEach(function(property) { | ||
ReturnStatement: function(node) { | ||
componentList.set(context, node); | ||
}, | ||
'Program:exit': function() { | ||
var list = componentList.getList(); | ||
var list = components.list(); | ||
// Report undeclared proptypes for all classes | ||
@@ -649,3 +638,3 @@ for (var component in list) { | ||
}; | ||
}); | ||
@@ -652,0 +641,0 @@ module.exports.schema = [{ |
@@ -9,4 +9,3 @@ /** | ||
var componentUtil = require('../util/component'); | ||
var ComponentList = componentUtil.List; | ||
var Components = require('../util/Components'); | ||
@@ -43,5 +42,4 @@ /** | ||
module.exports = function(context) { | ||
module.exports = Components.detect(function(context, components) { | ||
var componentList = new ComponentList(); | ||
var errors = {}; | ||
@@ -350,13 +348,4 @@ | ||
return { | ||
ClassDeclaration: function(node) { | ||
componentList.set(context, node); | ||
}, | ||
ObjectExpression: function(node) { | ||
componentList.set(context, node); | ||
}, | ||
'Program:exit': function() { | ||
var list = componentList.getList(); | ||
var list = components.list(); | ||
for (var component in list) { | ||
@@ -374,3 +363,3 @@ if (!list.hasOwnProperty(component) || !mustBeValidated(list[component])) { | ||
}; | ||
}); | ||
@@ -377,0 +366,0 @@ module.exports.schema = [{ |
{ | ||
"name": "eslint-plugin-react", | ||
"version": "3.6.3", | ||
"version": "3.7.0", | ||
"author": "Yannick Croissant <yannick.croissant+npm@gmail.com>", | ||
@@ -26,5 +26,5 @@ "description": "React specific linting rules for ESLint", | ||
"devDependencies": { | ||
"babel-eslint": "4.1.3", | ||
"babel-eslint": "4.1.4", | ||
"coveralls": "2.11.4", | ||
"eslint": "1.7.1", | ||
"eslint": "1.8.0", | ||
"istanbul": "0.4.0", | ||
@@ -31,0 +31,0 @@ "mocha": "2.3.3" |
@@ -56,2 +56,3 @@ ESLint-plugin-React | ||
"react/jsx-max-props-per-line": 1, | ||
"react/jsx-no-bind": 1, | ||
"react/jsx-no-duplicate-props": 1, | ||
@@ -92,2 +93,3 @@ "react/jsx-no-literals": 1, | ||
* [jsx-max-props-per-line](docs/rules/jsx-max-props-per-line.md): Limit maximum of props on a single line in JSX | ||
* [jsx-no-bind](docs/rules/jsx-no-bind.md): Prevent usage of `.bind()` and arrow functions in JSX props | ||
* [jsx-no-duplicate-props](docs/rules/jsx-no-duplicate-props.md): Prevent duplicate props in JSX | ||
@@ -94,0 +96,0 @@ * [jsx-no-literals](docs/rules/jsx-no-literals.md): Prevent usage of unwrapped JSX strings |
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
142187
37
3311
148