eslint-plugin-react
Advanced tools
Comparing version 2.5.2 to 2.6.0
@@ -0,1 +1,32 @@ | ||
2.6.0 / 2015-06-28 | ||
================== | ||
* update dependencies | ||
* add support for nested prop types ([#62][] [#105][] @Cellule) | ||
* add require-extension rule ([#117][] @scothis) | ||
* add support for computed string format in prop-types ([#127][] @Cellule) | ||
* add ES6 methods to sort-comp default configuration ([#97][] [#122][]) | ||
* add support for props destructuring directly on the this keyword | ||
* add schema to validate rules options | ||
* fix test command for Windows ([#114][] @Cellule) | ||
* fix detection of missing displayName and propTypes when ecmaFeatures.jsx is false ([#119][] @rpl) | ||
* fix `prop-types` destructuring with properties as string ([#118][] @Cellule) | ||
* fix `jsx-sort-prop-types` support for keys as string ([#123][] @Cellule) | ||
* fix crash if a ClassProperty has only one token ([#125][]) | ||
* fix invalid class property handling in jsx-sort-prop-types ([#129][]) | ||
[#62]: https://github.com/yannickcr/eslint-plugin-react/issues/62 | ||
[#105]: https://github.com/yannickcr/eslint-plugin-react/issues/105 | ||
[#114]: https://github.com/yannickcr/eslint-plugin-react/pull/114 | ||
[#117]: https://github.com/yannickcr/eslint-plugin-react/pull/117 | ||
[#119]: https://github.com/yannickcr/eslint-plugin-react/pull/119 | ||
[#118]: https://github.com/yannickcr/eslint-plugin-react/issues/118 | ||
[#123]: https://github.com/yannickcr/eslint-plugin-react/pull/123 | ||
[#125]: https://github.com/yannickcr/eslint-plugin-react/issues/125 | ||
[#127]: https://github.com/yannickcr/eslint-plugin-react/pull/127 | ||
[#97]: https://github.com/yannickcr/eslint-plugin-react/issues/97 | ||
[#122]: https://github.com/yannickcr/eslint-plugin-react/issues/122 | ||
[#129]: https://github.com/yannickcr/eslint-plugin-react/issues/129 | ||
2.5.2 / 2015-06-14 | ||
@@ -2,0 +33,0 @@ ================== |
@@ -21,3 +21,4 @@ 'use strict'; | ||
'jsx-boolean-value': require('./lib/rules/jsx-boolean-value'), | ||
'sort-comp': require('./lib/rules/sort-comp') | ||
'sort-comp': require('./lib/rules/sort-comp'), | ||
'require-extension': require('./lib/rules/require-extension') | ||
}, | ||
@@ -41,4 +42,5 @@ rulesConfig: { | ||
'jsx-boolean-value': 0, | ||
'sort-comp': 0 | ||
'sort-comp': 0, | ||
'require-extension': 0 | ||
} | ||
}; |
@@ -16,2 +16,5 @@ /** | ||
var config = context.options[0] || {}; | ||
var acceptTranspilerName = config.acceptTranspilerName || false; | ||
var componentList = new ComponentList(); | ||
@@ -46,3 +49,6 @@ | ||
var tokens = context.getFirstTokens(node, 2); | ||
if (tokens[0].value === 'displayName' || tokens[1].value === 'displayName') { | ||
if ( | ||
tokens[0].value === 'displayName' || | ||
(tokens[1] && tokens[1].value === 'displayName') | ||
) { | ||
return true; | ||
@@ -82,2 +88,35 @@ } | ||
/** | ||
* Checks if the component have a name set by the transpiler | ||
* @param {ASTNode} node The AST node being checked. | ||
* @returns {Boolean} True ifcomponent have a name, false if not. | ||
*/ | ||
function hasTranspilerName(node) { | ||
var namedAssignment = ( | ||
node.type === 'ObjectExpression' && | ||
node.parent && | ||
node.parent.parent && | ||
node.parent.parent.type === 'AssignmentExpression' && ( | ||
!node.parent.parent.left.object || | ||
node.parent.parent.left.object.name !== 'module' || | ||
node.parent.parent.left.property.name !== 'exports' | ||
) | ||
); | ||
var namedDeclaration = ( | ||
node.type === 'ObjectExpression' && | ||
node.parent && | ||
node.parent.parent && | ||
node.parent.parent.type === 'VariableDeclarator' | ||
); | ||
var namedClass = ( | ||
node.type === 'ClassDeclaration' && | ||
node.id && node.id.name | ||
); | ||
if (namedAssignment || namedDeclaration || namedClass) { | ||
return true; | ||
} | ||
return false; | ||
} | ||
// -------------------------------------------------------------------------- | ||
@@ -115,2 +154,9 @@ // Public | ||
ClassDeclaration: function(node) { | ||
if (!acceptTranspilerName || !hasTranspilerName(node)) { | ||
return; | ||
} | ||
markDisplayNameAsDeclared(node); | ||
}, | ||
ObjectExpression: function(node) { | ||
@@ -124,2 +170,12 @@ // Search for the displayName declaration | ||
}); | ||
// Has transpiler name | ||
if (acceptTranspilerName && hasTranspilerName(node)) { | ||
markDisplayNameAsDeclared(node); | ||
} | ||
if (componentUtil.isComponentDefinition(node)) { | ||
componentList.set(context, node, { | ||
isReactComponent: true | ||
}); | ||
} | ||
}, | ||
@@ -149,1 +205,11 @@ | ||
}; | ||
module.exports.schema = [{ | ||
type: 'object', | ||
properties: { | ||
acceptTranspilerName: { | ||
type: 'boolean' | ||
} | ||
}, | ||
additionalProperties: false | ||
}]; |
@@ -37,1 +37,5 @@ /** | ||
}; | ||
module.exports.schema = [{ | ||
enum: ['always', 'never'] | ||
}]; |
@@ -66,1 +66,3 @@ /** | ||
}; | ||
module.exports.schema = []; |
@@ -71,1 +71,7 @@ /** | ||
}; | ||
module.exports.schema = [{ | ||
enum: ['single', 'double'] | ||
}, { | ||
enum: ['avoid-escape'] | ||
}]; |
@@ -38,2 +38,6 @@ /** | ||
function getKey(node) { | ||
return node.key.type === 'Identifier' ? node.key.name : node.key.value; | ||
} | ||
/** | ||
@@ -46,4 +50,4 @@ * Checks if propTypes declarations are sorted | ||
declarations.reduce(function(prev, curr) { | ||
var prevPropName = prev.key.name; | ||
var currenPropName = curr.key.name; | ||
var prevPropName = getKey(prev); | ||
var currenPropName = getKey(curr); | ||
@@ -66,3 +70,3 @@ if (ignoreCase) { | ||
ClassProperty: function(node) { | ||
if (isPropTypesDeclaration(node) && node.value.type === 'ObjectExpression') { | ||
if (isPropTypesDeclaration(node) && node.value && node.value.type === 'ObjectExpression') { | ||
checkSorted(node.value.properties); | ||
@@ -94,1 +98,11 @@ } | ||
}; | ||
module.exports.schema = [{ | ||
type: 'object', | ||
properties: { | ||
ignoreCase: { | ||
type: 'boolean' | ||
} | ||
}, | ||
additionalProperties: false | ||
}]; |
@@ -41,1 +41,11 @@ /** | ||
}; | ||
module.exports.schema = [{ | ||
type: 'object', | ||
properties: { | ||
ignoreCase: { | ||
type: 'boolean' | ||
} | ||
}, | ||
additionalProperties: false | ||
}]; |
@@ -41,1 +41,11 @@ /** | ||
}; | ||
module.exports.schema = [{ | ||
type: 'object', | ||
properties: { | ||
pragma: { | ||
type: 'string' | ||
} | ||
}, | ||
additionalProperties: false | ||
}]; |
@@ -33,1 +33,3 @@ /** | ||
}; | ||
module.exports.schema = []; |
@@ -50,1 +50,5 @@ /** | ||
}; | ||
module.exports.schema = [{ | ||
enum: ['allow-in-func'] | ||
}]; |
@@ -38,1 +38,3 @@ /** | ||
}; | ||
module.exports.schema = []; |
@@ -49,1 +49,3 @@ /** | ||
}; | ||
module.exports.schema = []; |
@@ -81,1 +81,3 @@ /** | ||
}; | ||
module.exports.schema = []; |
@@ -50,3 +50,6 @@ /** | ||
var tokens = context.getFirstTokens(node, 2); | ||
if (tokens[0].value === 'propTypes' || tokens[1].value === 'propTypes') { | ||
if ( | ||
tokens[0].value === 'propTypes' || | ||
(tokens[1] && tokens[1].value === 'propTypes') | ||
) { | ||
return true; | ||
@@ -88,11 +91,69 @@ } | ||
/** | ||
* Internal: Checks if the prop is declared | ||
* @param {Object} declaredPropTypes Description of propTypes declared in the current component | ||
* @param {String[]} keyList Dot separated name of the prop to check. | ||
* @returns {Boolean} True if the prop is declared, false if not. | ||
*/ | ||
function _isDeclaredInComponent(declaredPropTypes, keyList) { | ||
for (var i = 0, j = keyList.length; i < j; i++) { | ||
var key = keyList[i]; | ||
var propType = ( | ||
// Check if this key is declared | ||
declaredPropTypes[key] || | ||
// If not, check if this type accepts any key | ||
declaredPropTypes.__ANY_KEY__ | ||
); | ||
if (!propType) { | ||
// If it's a computed property, we can't make any further analysis, but is valid | ||
return key === '__COMPUTED_PROP__'; | ||
} | ||
if (propType === true) { | ||
return true; | ||
} | ||
// Consider every children as declared | ||
if (propType.children === true) { | ||
return true; | ||
} | ||
if (propType.acceptedProperties) { | ||
return key in propType.acceptedProperties; | ||
} | ||
if (propType.type === 'union') { | ||
// If we fall in this case, we know there is at least one complex type in the union | ||
if (i + 1 >= j) { | ||
// this is the last key, accept everything | ||
return true; | ||
} | ||
// non trivial, check all of them | ||
var unionTypes = propType.children; | ||
var unionPropType = {}; | ||
for (var k = 0, z = unionTypes.length; k < z; k++) { | ||
unionPropType[key] = unionTypes[k]; | ||
var isValid = _isDeclaredInComponent( | ||
unionPropType, | ||
keyList.slice(i) | ||
); | ||
if (isValid) { | ||
return true; | ||
} | ||
} | ||
// every possible union were invalid | ||
return false; | ||
} | ||
declaredPropTypes = propType.children; | ||
} | ||
return true; | ||
} | ||
/** | ||
* Checks if the prop is declared | ||
* @param {String} name Name of the prop to check. | ||
* @param {Object} component The component to process | ||
* @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, name) { | ||
return ( | ||
component.declaredPropTypes && | ||
component.declaredPropTypes.indexOf(name) !== -1 | ||
function isDeclaredInComponent(component, names) { | ||
return _isDeclaredInComponent( | ||
component.declaredPropTypes || {}, | ||
names | ||
); | ||
@@ -112,27 +173,246 @@ } | ||
/** | ||
* Retrieve the name of a key node | ||
* @param {ASTNode} node The AST node with the key. | ||
* @return {string} the name of the key | ||
*/ | ||
function getKeyValue(node) { | ||
var key = node.key; | ||
return key.type === 'Identifier' ? key.name : key.value; | ||
} | ||
/** | ||
* Iterates through a properties node, like a customized forEach. | ||
* @param {Object[]} properties Array of properties to iterate. | ||
* @param {Function} fn Function to call on each property, receives property key | ||
and property value. (key, value) => void | ||
*/ | ||
function iterateProperties(properties, fn) { | ||
if (properties.length && typeof fn === 'function') { | ||
for (var i = 0, j = properties.length; i < j; i++) { | ||
var node = properties[i]; | ||
var key = getKeyValue(node); | ||
var value = node.value; | ||
fn(key, value); | ||
} | ||
} | ||
} | ||
/** | ||
* Creates the representation of the React propTypes for the component. | ||
* The representation is used to verify nested used properties. | ||
* @param {ASTNode} value Node of the React.PropTypes for the desired propery | ||
* @return {Object|Boolean} The representation of the declaration, true means | ||
* the property is declared without the need for further analysis. | ||
*/ | ||
function buildReactDeclarationTypes(value) { | ||
if ( | ||
value.type === 'MemberExpression' && | ||
value.property && | ||
value.property.name && | ||
value.property.name === 'isRequired' | ||
) { | ||
value = value.object; | ||
} | ||
// Verify React.PropTypes that are functions | ||
if ( | ||
value.type === 'CallExpression' && | ||
value.callee && | ||
value.callee.property && | ||
value.callee.property.name && | ||
value.arguments && | ||
value.arguments.length > 0 | ||
) { | ||
var callName = value.callee.property.name; | ||
var argument = value.arguments[0]; | ||
switch (callName) { | ||
case 'shape': | ||
if (argument.type !== 'ObjectExpression') { | ||
// Invalid proptype or cannot analyse statically | ||
return true; | ||
} | ||
var shapeTypeDefinition = { | ||
type: 'shape', | ||
children: {} | ||
}; | ||
iterateProperties(argument.properties, function(childKey, childValue) { | ||
shapeTypeDefinition.children[childKey] = buildReactDeclarationTypes(childValue); | ||
}); | ||
return shapeTypeDefinition; | ||
case 'arrayOf': | ||
return { | ||
type: 'array', | ||
children: { | ||
// Accept only array prototype and computed properties | ||
__ANY_KEY__: { | ||
acceptedProperties: Array.prototype | ||
}, | ||
__COMPUTED_PROP__: buildReactDeclarationTypes(argument) | ||
} | ||
}; | ||
case 'objectOf': | ||
return { | ||
type: 'object', | ||
children: { | ||
__ANY_KEY__: buildReactDeclarationTypes(argument) | ||
} | ||
}; | ||
case 'oneOfType': | ||
if ( | ||
!argument.elements || | ||
!argument.elements.length | ||
) { | ||
// Invalid proptype or cannot analyse statically | ||
return true; | ||
} | ||
var unionTypeDefinition = { | ||
type: 'union', | ||
children: [] | ||
}; | ||
for (var i = 0, j = argument.elements.length; i < j; i++) { | ||
var type = buildReactDeclarationTypes(argument.elements[i]); | ||
// keep only complex type | ||
if (type !== true) { | ||
if (type.children === true) { | ||
// every child is accepted for one type, abort type analysis | ||
unionTypeDefinition.children = true; | ||
return unionTypeDefinition; | ||
} | ||
unionTypeDefinition.children.push(type); | ||
} | ||
} | ||
if (unionTypeDefinition.length === 0) { | ||
// no complex type found, simply accept everything | ||
return true; | ||
} | ||
return unionTypeDefinition; | ||
case 'instanceOf': | ||
return { | ||
type: 'instance', | ||
// Accept all children because we can't know what type they are | ||
children: true | ||
}; | ||
case 'oneOf': | ||
default: | ||
return true; | ||
} | ||
} | ||
if ( | ||
value.type === 'MemberExpression' && | ||
value.property && | ||
value.property.name | ||
) { | ||
var name = value.property.name; | ||
// React propTypes with limited possible properties | ||
var propertiesMap = { | ||
array: Array.prototype, | ||
bool: Boolean.prototype, | ||
func: Function.prototype, | ||
number: Number.prototype, | ||
string: String.prototype | ||
}; | ||
if (name in propertiesMap) { | ||
return { | ||
type: name, | ||
children: { | ||
__ANY_KEY__: { | ||
acceptedProperties: propertiesMap[name] | ||
} | ||
} | ||
}; | ||
} | ||
} | ||
// Unknown property or accepts everything (any, object, ...) | ||
return true; | ||
} | ||
/** | ||
* Retrieve the name of a property node | ||
* @param {ASTNode} node The AST node with the property. | ||
* @return {string} the name of the property or undefined if not found | ||
*/ | ||
function getPropertyName(node) { | ||
var property = node.property; | ||
if (property) { | ||
switch (property.type) { | ||
case 'Identifier': | ||
if (node.computed) { | ||
return '__COMPUTED_PROP__'; | ||
} | ||
return property.name; | ||
case 'Literal': | ||
// Accept computed properties that are literal strings | ||
if (typeof property.value === 'string') { | ||
return property.value; | ||
} | ||
// falls through | ||
default: | ||
if (node.computed) { | ||
return '__COMPUTED_PROP__'; | ||
} | ||
break; | ||
} | ||
} | ||
} | ||
/** | ||
* Mark a prop type as used | ||
* @param {ASTNode} node The AST node being marked. | ||
*/ | ||
function markPropTypesAsUsed(node) { | ||
var component = componentList.getByNode(context, node); | ||
var usedPropTypes = component && component.usedPropTypes || []; | ||
function markPropTypesAsUsed(node, parentNames) { | ||
parentNames = parentNames || []; | ||
var type; | ||
if (node.parent.property && node.parent.property.name && !node.parent.computed) { | ||
type = 'direct'; | ||
} else if ( | ||
node.parent.parent.declarations && | ||
node.parent.parent.declarations[0].id.properties && | ||
node.parent.parent.declarations[0].id.properties[0].key.name | ||
) { | ||
type = 'destructuring'; | ||
var name; | ||
var allNames; | ||
var properties; | ||
switch (node.type) { | ||
case 'MemberExpression': | ||
name = getPropertyName(node.parent); | ||
if (name) { | ||
allNames = parentNames.concat(name); | ||
if (node.parent.type === 'MemberExpression') { | ||
markPropTypesAsUsed(node.parent, allNames); | ||
} | ||
// Do not mark computed props as used. | ||
type = name !== '__COMPUTED_PROP__' ? 'direct' : null; | ||
} else if ( | ||
node.parent.parent.declarations && | ||
node.parent.parent.declarations[0].id.properties && | ||
getKeyValue(node.parent.parent.declarations[0].id.properties[0]) | ||
) { | ||
type = 'destructuring'; | ||
properties = node.parent.parent.declarations[0].id.properties; | ||
} | ||
break; | ||
case 'VariableDeclarator': | ||
type = 'destructuring'; | ||
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' | ||
) { | ||
continue; | ||
} | ||
properties = node.id.properties[i].value.properties; | ||
break; | ||
} | ||
break; | ||
default: | ||
throw new Error(node.type + ' ASTNodes are not handled by markPropTypesAsUsed'); | ||
} | ||
var component = componentList.getByNode(context, node); | ||
var usedPropTypes = component && component.usedPropTypes || []; | ||
switch (type) { | ||
case 'direct': | ||
// Ignore Object methods | ||
if (Object.prototype[node.parent.property.name]) { | ||
if (Object.prototype[name]) { | ||
break; | ||
} | ||
usedPropTypes.push({ | ||
name: node.parent.property.name, | ||
name: name, | ||
allNames: allNames, | ||
node: node.parent.property | ||
@@ -142,11 +422,14 @@ }); | ||
case 'destructuring': | ||
var properties = node.parent.parent.declarations[0].id.properties; | ||
for (var i = 0, j = properties.length; i < j; i++) { | ||
if (hasSpreadOperator(properties[i])) { | ||
for (var k = 0, l = properties.length; k < l; k++) { | ||
if (hasSpreadOperator(properties[k])) { | ||
continue; | ||
} | ||
usedPropTypes.push({ | ||
name: properties[i].key.name, | ||
node: properties[i] | ||
}); | ||
var propName = getKeyValue(properties[k]); | ||
if (propName) { | ||
usedPropTypes.push({ | ||
name: propName, | ||
allNames: [propName], | ||
node: properties[k] | ||
}); | ||
} | ||
} | ||
@@ -170,3 +453,3 @@ break; | ||
var component = componentList.getByNode(context, node); | ||
var declaredPropTypes = component && component.declaredPropTypes || []; | ||
var declaredPropTypes = component && component.declaredPropTypes || {}; | ||
var ignorePropsValidation = false; | ||
@@ -176,9 +459,30 @@ | ||
case 'ObjectExpression': | ||
for (var i = 0, j = propTypes.properties.length; i < j; i++) { | ||
var key = propTypes.properties[i].key; | ||
declaredPropTypes.push(key.type === 'Identifier' ? key.name : key.value); | ||
} | ||
iterateProperties(propTypes.properties, function(key, value) { | ||
declaredPropTypes[key] = buildReactDeclarationTypes(value); | ||
}); | ||
break; | ||
case 'MemberExpression': | ||
declaredPropTypes.push(propTypes.property.name); | ||
var curDeclaredPropTypes = declaredPropTypes; | ||
// Walk the list of properties, until we reach the assignment | ||
// ie: ClassX.propTypes.a.b.c = ... | ||
while ( | ||
propTypes && | ||
propTypes.parent.type !== 'AssignmentExpression' && | ||
propTypes.property && | ||
curDeclaredPropTypes | ||
) { | ||
var propName = propTypes.property.name; | ||
if (propName in curDeclaredPropTypes) { | ||
curDeclaredPropTypes = curDeclaredPropTypes[propName].children; | ||
propTypes = propTypes.parent; | ||
} else { | ||
// This will crash at runtime because we haven't seen this key before | ||
// stop this and do not declare it | ||
propTypes = null; | ||
} | ||
} | ||
if (propTypes) { | ||
curDeclaredPropTypes[propTypes.property.name] = | ||
buildReactDeclarationTypes(propTypes.parent.right); | ||
} | ||
break; | ||
@@ -196,3 +500,2 @@ case null: | ||
}); | ||
} | ||
@@ -205,6 +508,10 @@ | ||
function reportUndeclaredPropTypes(component) { | ||
var name; | ||
var allNames, name; | ||
for (var i = 0, j = component.usedPropTypes.length; i < j; i++) { | ||
name = component.usedPropTypes[i].name; | ||
if (isDeclaredInComponent(component, name) || isIgnored(name)) { | ||
allNames = component.usedPropTypes[i].allNames; | ||
if ( | ||
isIgnored(name) || | ||
isDeclaredInComponent(component, allNames) | ||
) { | ||
continue; | ||
@@ -215,3 +522,3 @@ } | ||
component.name === componentUtil.DEFAULT_COMPONENT_NAME ? MISSING_MESSAGE : MISSING_MESSAGE_NAMED_COMP, { | ||
name: name, | ||
name: allNames.join('.').replace(/\.__COMPUTED_PROP__/g, '[]'), | ||
component: component.name | ||
@@ -237,2 +544,9 @@ } | ||
VariableDeclarator: function(node) { | ||
if (node.init.type !== 'ThisExpression' || node.id.type !== 'ObjectPattern') { | ||
return; | ||
} | ||
markPropTypesAsUsed(node); | ||
}, | ||
MemberExpression: function(node) { | ||
@@ -285,2 +599,8 @@ var type; | ||
}); | ||
if (componentUtil.isComponentDefinition(node)) { | ||
componentList.set(context, node, { | ||
isReactComponent: true | ||
}); | ||
} | ||
}, | ||
@@ -310,1 +630,14 @@ | ||
}; | ||
module.exports.schema = [{ | ||
type: 'object', | ||
properties: { | ||
ignore: { | ||
type: 'array', | ||
items: { | ||
type: 'string' | ||
} | ||
} | ||
}, | ||
additionalProperties: false | ||
}]; |
@@ -43,1 +43,3 @@ /** | ||
}; | ||
module.exports.schema = []; |
@@ -48,1 +48,3 @@ /** | ||
}; | ||
module.exports.schema = []; |
@@ -63,2 +63,4 @@ /** | ||
'statics', | ||
'defaultProps', | ||
'constructor', | ||
'getDefaultProps', | ||
@@ -372,1 +374,25 @@ 'getInitialState', | ||
}; | ||
module.exports.schema = [{ | ||
type: 'object', | ||
properties: { | ||
order: { | ||
type: 'array', | ||
items: { | ||
type: 'string' | ||
} | ||
}, | ||
groups: { | ||
type: 'object', | ||
patternProperties: { | ||
'^.*$': { | ||
type: 'array', | ||
items: { | ||
type: 'string' | ||
} | ||
} | ||
} | ||
} | ||
}, | ||
additionalProperties: false | ||
}]; |
@@ -84,6 +84,13 @@ /** | ||
properties: { | ||
declaration: {type: 'boolean'}, | ||
assignment: {type: 'boolean'}, | ||
return: {type: 'boolean'} | ||
} | ||
declaration: { | ||
type: 'boolean' | ||
}, | ||
assignment: { | ||
type: 'boolean' | ||
}, | ||
return: { | ||
type: 'boolean' | ||
} | ||
}, | ||
additionalProperties: false | ||
}]; |
{ | ||
"name": "eslint-plugin-react", | ||
"version": "2.5.2", | ||
"version": "2.6.0", | ||
"author": "Yannick Croissant <yannick.croissant+npm@gmail.com>", | ||
@@ -10,3 +10,3 @@ "description": "React specific linting rules for ESLint", | ||
"lint": "eslint ./", | ||
"unit-test": "istanbul cover --dir reports/coverage _mocha tests/**/*.js -- --reporter dot", | ||
"unit-test": "istanbul cover --dir reports/coverage node_modules/mocha/bin/_mocha tests/**/*.js -- --reporter dot", | ||
"coveralls": "cat ./reports/coverage/lcov.info | coveralls" | ||
@@ -27,7 +27,7 @@ }, | ||
"devDependencies": { | ||
"babel-eslint": "3.1.15", | ||
"babel-eslint": "3.1.19", | ||
"coveralls": "2.11.2", | ||
"eslint": "0.22.1", | ||
"eslint-tester": "0.7.0", | ||
"istanbul": "0.3.15", | ||
"eslint": "0.24.0", | ||
"eslint-tester": "0.8.2", | ||
"istanbul": "0.3.17", | ||
"mocha": "2.2.5" | ||
@@ -34,0 +34,0 @@ }, |
@@ -59,2 +59,3 @@ ESLint-plugin-React | ||
"react/react-in-jsx-scope": 1, | ||
"react/require-extension": 1, | ||
"react/self-closing-comp": 1, | ||
@@ -83,2 +84,3 @@ "react/sort-comp": 1, | ||
* [react-in-jsx-scope](docs/rules/react-in-jsx-scope.md): Prevent missing React when using JSX | ||
* [require-extension](docs/rules/require-extension.md): Restrict file extensions that may be required | ||
* [self-closing-comp](docs/rules/self-closing-comp.md): Prevent extra closing tags for components without children | ||
@@ -85,0 +87,0 @@ * [sort-comp](docs/rules/sort-comp.md): Enforce component methods order |
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
85506
25
2154
120