eslint-plugin-react
Advanced tools
Comparing version 3.10.0 to 3.11.0
@@ -6,2 +6,26 @@ # Change Log | ||
## [3.11.0] - 2015-11-29 | ||
### Added | ||
* Add `jsx-handler-names` rule ([#315][] @jakemmarsh) | ||
* Add SVG attributes support to `no-unknown-property` ([#318][]) | ||
* Add shorthandFirst option to `jsx-sort-props` ([#336][] @lucasmotta) | ||
### Fixed | ||
* Fix destructured props detection in stateless components ([#326][]) | ||
* Fix props validation for nested stateless components ([#331][]) | ||
* Fix `require-extension` to ignore extension if it's part of the package name ([#319][]) | ||
### Changed | ||
* Allow consecutive uppercase letters in `jsx-pascal-case` ([#328][] @lencioni) | ||
* Update dependencies | ||
[3.11.0]: https://github.com/yannickcr/eslint-plugin-react/compare/v3.10.0...v3.11.0 | ||
[#315]: https://github.com/yannickcr/eslint-plugin-react/pull/315 | ||
[#318]: https://github.com/yannickcr/eslint-plugin-react/issues/318 | ||
[#336]: https://github.com/yannickcr/eslint-plugin-react/pull/336 | ||
[#326]: https://github.com/yannickcr/eslint-plugin-react/issues/326 | ||
[#331]: https://github.com/yannickcr/eslint-plugin-react/issues/331 | ||
[#319]: https://github.com/yannickcr/eslint-plugin-react/issues/319 | ||
[#328]: https://github.com/yannickcr/eslint-plugin-react/issues/328 | ||
## [3.10.0] - 2015-11-21 | ||
@@ -8,0 +32,0 @@ ### Added |
@@ -17,2 +17,3 @@ 'use strict'; | ||
'jsx-uses-vars': require('./lib/rules/jsx-uses-vars'), | ||
'jsx-handler-names': require('./lib/rules/jsx-handler-names'), | ||
'jsx-pascal-case': require('./lib/rules/jsx-pascal-case'), | ||
@@ -52,2 +53,3 @@ 'jsx-no-bind': require('./lib/rules/jsx-no-bind'), | ||
'jsx-uses-vars': 1, | ||
'jsx-handler-names': 0, | ||
'jsx-pascal-case': 0, | ||
@@ -54,0 +56,0 @@ 'jsx-no-bind': 0, |
@@ -14,3 +14,3 @@ /** | ||
var PASCAL_CASE_REGEX = /^[A-Z][a-z]+(?:[A-Z][a-z]+)*$/; | ||
var PASCAL_CASE_REGEX = /^[A-Z]+[a-z]+(?:[A-Z]+[a-z]*)*$/; | ||
@@ -17,0 +17,0 @@ // ------------------------------------------------------------------------------ |
@@ -20,2 +20,3 @@ /** | ||
var callbacksLast = configuration.callbacksLast || false; | ||
var shorthandFirst = configuration.shorthandFirst || false; | ||
@@ -31,2 +32,4 @@ return { | ||
var currentPropName = decl.name.name; | ||
var previousValue = memo.value; | ||
var currentValue = decl.value; | ||
var previousIsCallback = isCallbackPropName(previousPropName); | ||
@@ -52,2 +55,12 @@ var currentIsCallback = isCallbackPropName(currentPropName); | ||
if (shorthandFirst) { | ||
if (currentValue && !previousValue) { | ||
return decl; | ||
} | ||
if (!currentValue && previousValue) { | ||
context.report(memo, 'Shorthand props must be listed before all other props'); | ||
return memo; | ||
} | ||
} | ||
if (currentPropName < previousPropName) { | ||
@@ -72,2 +85,6 @@ context.report(decl, 'Props should be sorted alphabetically'); | ||
}, | ||
// Whether shorthand properties (without a value) should be listed first | ||
shorthandFirst: { | ||
type: 'boolean' | ||
}, | ||
ignoreCase: { | ||
@@ -74,0 +91,0 @@ type: 'boolean' |
@@ -21,2 +21,3 @@ /** | ||
var DOM_PROPERTY_NAMES = [ | ||
// Standard | ||
'acceptCharset', 'accessKey', 'allowFullScreen', 'allowTransparency', 'autoComplete', 'autoFocus', 'autoPlay', | ||
@@ -32,3 +33,16 @@ 'cellPadding', 'cellSpacing', 'charSet', 'classID', 'className', 'colSpan', 'contentEditable', 'contextMenu', | ||
'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' | ||
]; | ||
@@ -74,3 +88,3 @@ | ||
}); | ||
return found ? DOM_PROPERTY_NAMES[i] : null; | ||
return found ? DOM_PROPERTY_NAMES[i].replace(':', '') : null; | ||
} | ||
@@ -87,3 +101,4 @@ | ||
JSXAttribute: function(node) { | ||
var standardName = getStandardName(node.name.name); | ||
var name = context.getSource(node.name); | ||
var standardName = getStandardName(name); | ||
if (!isTagName(node) || !standardName) { | ||
@@ -93,3 +108,3 @@ return; | ||
context.report(node, UNKNOWN_MESSAGE, { | ||
name: node.name.name, | ||
name: name, | ||
standardName: standardName | ||
@@ -96,0 +111,0 @@ }); |
@@ -156,11 +156,19 @@ /** | ||
* Checks if the prop is declared | ||
* @param {Object} component The component to process | ||
* @param {ASTNode} node The AST node being checked. | ||
* @param {String[]} names List of names of the prop to check. | ||
* @returns {Boolean} True if the prop is declared, false if not. | ||
*/ | ||
function isDeclaredInComponent(component, names) { | ||
return _isDeclaredInComponent( | ||
component.declaredPropTypes || {}, | ||
names | ||
); | ||
function isDeclaredInComponent(node, names) { | ||
while (node) { | ||
var component = components.get(node); | ||
var isDeclared = | ||
component && component.confidence === 2 && | ||
_isDeclaredInComponent(component.declaredPropTypes || {}, names) | ||
; | ||
if (isDeclared) { | ||
return true; | ||
} | ||
node = node.parent; | ||
} | ||
return false; | ||
} | ||
@@ -397,10 +405,18 @@ | ||
for (var i = 0, j = node.id.properties.length; i < j; i++) { | ||
if ( | ||
(node.id.properties[i].key.name !== 'props' && node.id.properties[i].key.value !== 'props') || | ||
node.id.properties[i].value.type !== 'ObjectPattern' | ||
) { | ||
// let {props: {firstname}} = this | ||
var thisDestructuring = ( | ||
(node.id.properties[i].key.name === 'props' || node.id.properties[i].key.value === 'props') && | ||
node.id.properties[i].value.type === 'ObjectPattern' | ||
); | ||
// let {firstname} = props | ||
var statelessDestructuring = node.init.name === 'props' && utils.getParentStatelessComponent(); | ||
if (thisDestructuring) { | ||
properties = node.id.properties[i].value.properties; | ||
} else if (statelessDestructuring) { | ||
properties = node.id.properties; | ||
} else { | ||
continue; | ||
} | ||
type = 'destructuring'; | ||
properties = node.id.properties[i].value.properties; | ||
break; | ||
@@ -529,3 +545,3 @@ } | ||
isIgnored(allNames[0]) || | ||
isDeclaredInComponent(component, allNames) | ||
isDeclaredInComponent(component.node, allNames) | ||
) { | ||
@@ -556,3 +572,8 @@ continue; | ||
VariableDeclarator: function(node) { | ||
if (!node.init || node.init.type !== 'ThisExpression' || node.id.type !== 'ObjectPattern') { | ||
// let {props: {firstname}} = this | ||
var thisDestructuring = node.init && node.init.type === 'ThisExpression' && node.id.type === 'ObjectPattern'; | ||
// let {firstname} = props | ||
var statelessDestructuring = node.init && node.init.name === 'props' && utils.getParentStatelessComponent(); | ||
if (!thisDestructuring && !statelessDestructuring) { | ||
return; | ||
@@ -559,0 +580,0 @@ } |
@@ -17,2 +17,4 @@ /** | ||
var PKG_REGEX = /^[^\.]((?!\/).)*$/; | ||
// ------------------------------------------------------------------------------ | ||
@@ -24,2 +26,6 @@ // Rule Definition | ||
function isPackage(id) { | ||
return PKG_REGEX.test(id); | ||
} | ||
function isRequire(expression) { | ||
@@ -58,4 +64,5 @@ return expression.callee.name === 'require'; | ||
if (isRequire(node)) { | ||
var ext = getExtension(getId(node)); | ||
if (isForbiddenExtension(ext)) { | ||
var id = getId(node); | ||
var ext = getExtension(id); | ||
if (!isPackage(id) && isForbiddenExtension(ext)) { | ||
context.report(node, 'Unable to require module with extension \'' + ext + '\''); | ||
@@ -62,0 +69,0 @@ } |
{ | ||
"name": "eslint-plugin-react", | ||
"version": "3.10.0", | ||
"version": "3.11.0", | ||
"author": "Yannick Croissant <yannick.croissant+npm@gmail.com>", | ||
@@ -26,6 +26,6 @@ "description": "React specific linting rules for ESLint", | ||
"devDependencies": { | ||
"babel-eslint": "4.1.5", | ||
"babel-eslint": "5.0.0-beta4", | ||
"coveralls": "2.11.4", | ||
"eslint": "1.10.0", | ||
"istanbul": "0.4.0", | ||
"eslint": "1.10.2", | ||
"istanbul": "0.4.1", | ||
"mocha": "2.3.4" | ||
@@ -32,0 +32,0 @@ }, |
@@ -54,2 +54,3 @@ ESLint-plugin-React | ||
"react/jsx-curly-spacing": 1, | ||
"react/jsx-handler-names": 1, | ||
"react/jsx-indent-props": 1, | ||
@@ -62,2 +63,3 @@ "react/jsx-key": 1, | ||
"react/jsx-no-undef": 1, | ||
"react/jsx-pascal-case": 1, | ||
"react/jsx-quotes": 1, | ||
@@ -93,2 +95,3 @@ "react/jsx-sort-prop-types": 1, | ||
* [jsx-curly-spacing](docs/rules/jsx-curly-spacing.md): Enforce or disallow spaces inside of curly braces in JSX attributes | ||
* [jsx-handler-names](docs/rules/jsx-handler-names.md): Enforce event handler naming conventions in JSX | ||
* [jsx-indent-props](docs/rules/jsx-indent-props.md): Validate props indentation in JSX | ||
@@ -95,0 +98,0 @@ * [jsx-key](docs/rules/jsx-key.md): Validate JSX has key prop when in array or iterator |
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
156309
40
3587
154