eslint-plugin-react
Advanced tools
Comparing version 3.16.1 to 4.0.0-rc.0
@@ -6,2 +6,38 @@ # Change Log | ||
## [4.0.0-rc.0] - 2016-02-14 | ||
### Added | ||
* Add `jsx-space-before-closing` rule ([#244][] @ryym) | ||
* Add support for destructing in function signatures to `prop-types` ([#354][] @lencioni) | ||
### Breaking | ||
* Add support for static methods to `sort-comp`. Static methods must now be declared first, see [rule documentation](docs/rules/sort-comp.md) ([#128][] @lencioni) | ||
* Add shareable config in place of default configuration. `jsx-uses-vars` is not enabled by default anymore, see [documentation](README.md#recommended-configuration) ([#192][]) | ||
* Rename `jsx-sort-prop-types` to `sort-prop-types`. `jsx-sort-prop-types` still works but will trigger a warning ([#87][] @lencioni) | ||
* Remove deprecated `jsx-quotes` rule ([#433][] @lencioni) | ||
* `display-name` now accept the transpiler name by default. You can use the `ignoreTranspilerName` option to get the old behavior, see [rule documentation](docs/rules/display-name.md#ignoretranspilername) ([#440][] @lencioni) | ||
### Fixed | ||
* Only ignore lowercase JSXIdentifier in `jsx-no-undef` ([#435][]) | ||
### Changed | ||
* Update dependencies ([#426][] @quentin-) | ||
* Documentation improvements ([#414][] @vkrol, [#370][] @tmcw, [#441][] [#429][] @lencioni, [#432][] @Niler851, [#438][] @jmann6) | ||
[4.0.0-rc.0]: https://github.com/yannickcr/eslint-plugin-react/compare/v3.16.1...v4.0.0-rc.0 | ||
[#244]: https://github.com/yannickcr/eslint-plugin-react/issues/244 | ||
[#354]: https://github.com/yannickcr/eslint-plugin-react/issues/354 | ||
[#128]: https://github.com/yannickcr/eslint-plugin-react/issues/128 | ||
[#192]: https://github.com/yannickcr/eslint-plugin-react/issues/192 | ||
[#87]: https://github.com/yannickcr/eslint-plugin-react/issues/87 | ||
[#440]: https://github.com/yannickcr/eslint-plugin-react/pull/440 | ||
[#435]: https://github.com/yannickcr/eslint-plugin-react/issues/435 | ||
[#426]: https://github.com/yannickcr/eslint-plugin-react/pull/426 | ||
[#414]: https://github.com/yannickcr/eslint-plugin-react/pull/414 | ||
[#370]: https://github.com/yannickcr/eslint-plugin-react/pull/370 | ||
[#441]: https://github.com/yannickcr/eslint-plugin-react/pull/441 | ||
[#429]: https://github.com/yannickcr/eslint-plugin-react/pull/429 | ||
[#432]: https://github.com/yannickcr/eslint-plugin-react/pull/432 | ||
[#438]: https://github.com/yannickcr/eslint-plugin-react/pull/438 | ||
[#433]: https://github.com/yannickcr/eslint-plugin-react/pull/433 | ||
## [3.16.1] - 2016-01-24 | ||
@@ -493,3 +529,3 @@ ### Fixed | ||
## Breaking | ||
### Breaking | ||
* In `jsx-curly-spacing` braces spanning multiple lines are now allowed with `never` option ([#156][] @mathieumg) | ||
@@ -751,3 +787,3 @@ | ||
## Breaking | ||
### Breaking | ||
* In `prop-types` the children prop is no longer ignored | ||
@@ -754,0 +790,0 @@ |
66
index.js
@@ -23,3 +23,2 @@ 'use strict'; | ||
'jsx-no-undef': require('./lib/rules/jsx-no-undef'), | ||
'jsx-quotes': require('./lib/rules/jsx-quotes'), | ||
'no-unknown-property': require('./lib/rules/no-unknown-property'), | ||
@@ -29,2 +28,3 @@ 'jsx-curly-spacing': require('./lib/rules/jsx-curly-spacing'), | ||
'jsx-sort-props': require('./lib/rules/jsx-sort-props'), | ||
'sort-prop-types': require('./lib/rules/sort-prop-types'), | ||
'jsx-sort-prop-types': require('./lib/rules/jsx-sort-prop-types'), | ||
@@ -40,2 +40,3 @@ 'jsx-boolean-value': require('./lib/rules/jsx-boolean-value'), | ||
'jsx-closing-bracket-location': require('./lib/rules/jsx-closing-bracket-location'), | ||
'jsx-space-before-closing': require('./lib/rules/jsx-space-before-closing'), | ||
'no-direct-mutation-state': require('./lib/rules/no-direct-mutation-state'), | ||
@@ -47,42 +48,27 @@ 'forbid-prop-types': require('./lib/rules/forbid-prop-types'), | ||
}, | ||
rulesConfig: { | ||
'jsx-uses-react': 0, | ||
'no-multi-comp': 0, | ||
'prop-types': 0, | ||
'display-name': 0, | ||
'wrap-multilines': 0, | ||
'self-closing-comp': 0, | ||
'no-deprecated': 0, | ||
'no-danger': 0, | ||
'no-set-state': 0, | ||
'no-is-mounted': 0, | ||
'no-did-mount-set-state': 0, | ||
'no-did-update-set-state': 0, | ||
'react-in-jsx-scope': 0, | ||
'jsx-uses-vars': 1, | ||
'jsx-handler-names': 0, | ||
'jsx-pascal-case': 0, | ||
'jsx-no-bind': 0, | ||
'jsx-no-undef': 0, | ||
'jsx-quotes': 0, | ||
'no-unknown-property': 0, | ||
'jsx-curly-spacing': 0, | ||
'jsx-equals-spacing': 0, | ||
'jsx-sort-props': 0, | ||
'jsx-sort-prop-types': 0, | ||
'jsx-boolean-value': 0, | ||
'sort-comp': 0, | ||
'require-extension': 0, | ||
'jsx-no-duplicate-props': 0, | ||
'jsx-max-props-per-line': 0, | ||
'jsx-no-literals': 0, | ||
'jsx-indent-props': 0, | ||
'jsx-indent': 0, | ||
'jsx-closing-bracket-location': 0, | ||
'no-direct-mutation-state': 0, | ||
'forbid-prop-types': 0, | ||
'prefer-es6-class': 0, | ||
'jsx-key': 0, | ||
'no-string-refs': 0 | ||
configs: { | ||
recommended: { | ||
parserOptions: { | ||
ecmaFeatures: { | ||
jsx: true | ||
} | ||
}, | ||
rules: { | ||
'react/display-name': 2, | ||
'react/jsx-no-duplicate-props': 2, | ||
'react/jsx-no-undef': 2, | ||
'react/jsx-uses-react': 2, | ||
'react/jsx-uses-vars': 2, | ||
'react/no-danger': 2, | ||
'react/no-deprecated': 2, | ||
'react/no-did-mount-set-state': [2, 'allow-in-func'], | ||
'react/no-did-update-set-state': [2, 'allow-in-func'], | ||
'react/no-direct-mutation-state': 2, | ||
'react/no-is-mounted': 2, | ||
'react/no-unknown-property': 2, | ||
'react/prop-types': 2, | ||
'react/react-in-jsx-scope': 2 | ||
} | ||
} | ||
} | ||
}; |
@@ -15,4 +15,5 @@ /** | ||
var sourceCode = context.getSourceCode(); | ||
var config = context.options[0] || {}; | ||
var acceptTranspilerName = config.acceptTranspilerName || false; | ||
var ignoreTranspilerName = config.ignoreTranspilerName || false; | ||
@@ -30,3 +31,3 @@ var MISSING_MESSAGE = 'Component definition is missing display name'; | ||
if (node.type === 'ClassProperty') { | ||
var tokens = context.getFirstTokens(node, 2); | ||
var tokens = sourceCode.getFirstTokens(node, 2); | ||
if ( | ||
@@ -62,8 +63,9 @@ tokens[0].value === 'displayName' || | ||
function reportMissingDisplayName(component) { | ||
context.report( | ||
component.node, | ||
MISSING_MESSAGE, { | ||
context.report({ | ||
node: component.node, | ||
message: MISSING_MESSAGE, | ||
data: { | ||
component: component.name | ||
} | ||
); | ||
}); | ||
} | ||
@@ -145,3 +147,3 @@ | ||
FunctionExpression: function(node) { | ||
if (!acceptTranspilerName || !hasTranspilerName(node)) { | ||
if (ignoreTranspilerName || !hasTranspilerName(node)) { | ||
return; | ||
@@ -153,3 +155,3 @@ } | ||
FunctionDeclaration: function(node) { | ||
if (!acceptTranspilerName || !hasTranspilerName(node)) { | ||
if (ignoreTranspilerName || !hasTranspilerName(node)) { | ||
return; | ||
@@ -161,3 +163,3 @@ } | ||
ArrowFunctionExpression: function(node) { | ||
if (!acceptTranspilerName || !hasTranspilerName(node)) { | ||
if (ignoreTranspilerName || !hasTranspilerName(node)) { | ||
return; | ||
@@ -176,3 +178,3 @@ } | ||
ClassDeclaration: function(node) { | ||
if (!acceptTranspilerName || !hasTranspilerName(node)) { | ||
if (ignoreTranspilerName || !hasTranspilerName(node)) { | ||
return; | ||
@@ -184,3 +186,3 @@ } | ||
ObjectExpression: function(node) { | ||
if (!acceptTranspilerName || !hasTranspilerName(node)) { | ||
if (ignoreTranspilerName || !hasTranspilerName(node)) { | ||
// Search for the displayName declaration | ||
@@ -214,3 +216,3 @@ node.properties.forEach(function(property) { | ||
properties: { | ||
acceptTranspilerName: { | ||
ignoreTranspilerName: { | ||
type: 'boolean' | ||
@@ -217,0 +219,0 @@ } |
@@ -78,3 +78,6 @@ /** | ||
if (isForbidden(target)) { | ||
context.report(declaration, 'Prop type `' + target + '` is forbidden'); | ||
context.report({ | ||
node: declaration, | ||
message: 'Prop type `' + target + '` is forbidden' | ||
}); | ||
} | ||
@@ -81,0 +84,0 @@ }); |
@@ -22,2 +22,3 @@ /** | ||
var sourceCode = context.getSourceCode(); | ||
var config = context.options[0]; | ||
@@ -119,5 +120,5 @@ var options = { | ||
function getTokensLocations(node) { | ||
var opening = context.getFirstToken(node).loc.start; | ||
var closing = context.getLastTokens(node, node.selfClosing ? 2 : 1)[0].loc.start; | ||
var tag = context.getFirstToken(node.name).loc.start; | ||
var opening = sourceCode.getFirstToken(node).loc.start; | ||
var closing = sourceCode.getLastTokens(node, node.selfClosing ? 2 : 1)[0].loc.start; | ||
var tag = sourceCode.getFirstToken(node.name).loc.start; | ||
var lastProp; | ||
@@ -127,7 +128,7 @@ if (node.attributes.length) { | ||
lastProp = { | ||
column: context.getFirstToken(lastProp).loc.start.column, | ||
line: context.getLastToken(lastProp).loc.end.line | ||
column: sourceCode.getFirstToken(lastProp).loc.start.column, | ||
line: sourceCode.getLastToken(lastProp).loc.end.line | ||
}; | ||
} | ||
var openingLine = context.getSourceCode().lines[opening.line - 1]; | ||
var openingLine = sourceCode.lines[opening.line - 1]; | ||
var openingStartOfLine = { | ||
@@ -134,0 +135,0 @@ column: /^\s*/.exec(openingLine)[0].length, |
@@ -18,2 +18,4 @@ /** | ||
module.exports = function(context) { | ||
var sourceCode = context.getSourceCode(); | ||
var spaced = context.options[0] === 'always'; | ||
@@ -196,4 +198,4 @@ var multiline = context.options[1] ? context.options[1].allowMultiline : true; | ||
var second = context.getFirstToken(node, 1); | ||
var penultimate = context.getLastToken(node, 1); | ||
var last = context.getLastToken(node); | ||
var penultimate = sourceCode.getLastToken(node, 1); | ||
var last = sourceCode.getLastToken(node); | ||
@@ -200,0 +202,0 @@ if (first === penultimate && second === last) { |
@@ -43,8 +43,14 @@ /** | ||
if (spacedBefore) { | ||
context.report(attrNode, equalToken.loc.start, | ||
'There should be no space before \'=\''); | ||
context.report({ | ||
node: attrNode, | ||
loc: equalToken.loc.start, | ||
message: 'There should be no space before \'=\'' | ||
}); | ||
} | ||
if (spacedAfter) { | ||
context.report(attrNode, equalToken.loc.start, | ||
'There should be no space after \'=\''); | ||
context.report({ | ||
node: attrNode, | ||
loc: equalToken.loc.start, | ||
message: 'There should be no space after \'=\'' | ||
}); | ||
} | ||
@@ -54,8 +60,14 @@ break; | ||
if (!spacedBefore) { | ||
context.report(attrNode, equalToken.loc.start, | ||
'A space is required before \'=\''); | ||
context.report({ | ||
node: attrNode, | ||
loc: equalToken.loc.start, | ||
message: 'A space is required before \'=\'' | ||
}); | ||
} | ||
if (!spacedAfter) { | ||
context.report(attrNode, equalToken.loc.start, | ||
'A space is required after \'=\''); | ||
context.report({ | ||
node: attrNode, | ||
loc: equalToken.loc.start, | ||
message: 'A space is required after \'=\'' | ||
}); | ||
} | ||
@@ -62,0 +74,0 @@ break; |
@@ -13,2 +13,3 @@ /** | ||
var sourceCode = context.getSourceCode(); | ||
var configuration = context.options[0] || {}; | ||
@@ -29,3 +30,3 @@ var eventHandlerPrefix = configuration.eventHandlerPrefix || 'handle'; | ||
var propKey = typeof node.name === 'object' ? node.name.name : node.name; | ||
var propValue = context.getSource(node.value.expression).replace(/^this\./, ''); | ||
var propValue = sourceCode.getText(node.value.expression).replace(/^this\./, ''); | ||
@@ -40,11 +41,11 @@ if (propKey === 'ref') { | ||
if (propIsEventHandler && !propFnIsNamedCorrectly) { | ||
context.report( | ||
node, | ||
'Handler function for ' + propKey + ' prop key must begin with \'' + eventHandlerPrefix + '\'' | ||
); | ||
context.report({ | ||
node: node, | ||
message: 'Handler function for ' + propKey + ' prop key must begin with \'' + eventHandlerPrefix + '\'' | ||
}); | ||
} else if (propFnIsNamedCorrectly && !propIsEventHandler) { | ||
context.report( | ||
node, | ||
'Prop key for ' + propValue + ' must begin with \'' + eventHandlerPropPrefix + '\'' | ||
); | ||
context.report({ | ||
node: node, | ||
message: 'Prop key for ' + propValue + ' must begin with \'' + eventHandlerPropPrefix + '\'' | ||
}); | ||
} | ||
@@ -51,0 +52,0 @@ } |
@@ -43,2 +43,4 @@ /** | ||
var sourceCode = context.getSourceCode(); | ||
if (context.options.length) { | ||
@@ -70,5 +72,14 @@ if (context.options[0] === 'tab') { | ||
if (loc) { | ||
context.report(node, loc, MESSAGE, msgContext); | ||
context.report({ | ||
node: node, | ||
loc: loc, | ||
message: MESSAGE, | ||
data: msgContext | ||
}); | ||
} else { | ||
context.report(node, MESSAGE, msgContext); | ||
context.report({ | ||
node: node, | ||
message: MESSAGE, | ||
data: msgContext | ||
}); | ||
} | ||
@@ -88,3 +99,3 @@ } | ||
var src = context.getSource(node, node.loc.start.column + extraColumnStart); | ||
var src = sourceCode.getText(node, node.loc.start.column + extraColumnStart); | ||
var lines = src.split('\n'); | ||
@@ -117,3 +128,3 @@ if (byLastLine) { | ||
function isNodeFirstInLine(node, byEndLocation) { | ||
var firstToken = byEndLocation === true ? context.getLastToken(node, 1) : context.getTokenBefore(node); | ||
var firstToken = byEndLocation === true ? sourceCode.getLastToken(node, 1) : sourceCode.getTokenBefore(node); | ||
var startLine = byEndLocation === true ? node.loc.end.line : node.loc.start.line; | ||
@@ -120,0 +131,0 @@ var endLine = firstToken ? firstToken.loc.end.line : -1; |
@@ -43,2 +43,4 @@ /** | ||
var sourceCode = context.getSourceCode(); | ||
if (context.options.length) { | ||
@@ -70,5 +72,14 @@ if (context.options[0] === 'tab') { | ||
if (loc) { | ||
context.report(node, loc, MESSAGE, msgContext); | ||
context.report({ | ||
node: node, | ||
loc: loc, | ||
message: MESSAGE, | ||
data: msgContext | ||
}); | ||
} else { | ||
context.report(node, MESSAGE, msgContext); | ||
context.report({ | ||
node: node, | ||
message: MESSAGE, | ||
data: msgContext | ||
}); | ||
} | ||
@@ -88,3 +99,3 @@ } | ||
var src = context.getSource(node, node.loc.start.column + extraColumnStart); | ||
var src = sourceCode.getText(node, node.loc.start.column + extraColumnStart); | ||
var lines = src.split('\n'); | ||
@@ -118,3 +129,3 @@ if (byLastLine) { | ||
do { | ||
token = context.getTokenBefore(token); | ||
token = sourceCode.getTokenBefore(token); | ||
} while (token.type === 'JSXText'); | ||
@@ -121,0 +132,0 @@ var startLine = node.loc.start.line; |
@@ -26,3 +26,6 @@ /** | ||
if (node.type === 'JSXElement' && !hasKeyProp(node)) { | ||
context.report(node, 'Missing "key" prop for element in iterator'); | ||
context.report({ | ||
node: node, | ||
message: 'Missing "key" prop for element in iterator' | ||
}); | ||
} | ||
@@ -44,3 +47,6 @@ } | ||
if (node.parent.type === 'ArrayExpression') { | ||
context.report(node, 'Missing "key" prop for element in array'); | ||
context.report({ | ||
node: node, | ||
message: 'Missing "key" prop for element in array' | ||
}); | ||
} | ||
@@ -47,0 +53,0 @@ }, |
@@ -14,2 +14,3 @@ /** | ||
var sourceCode = context.getSourceCode(); | ||
var configuration = context.options[0] || {}; | ||
@@ -20,3 +21,3 @@ var maximum = configuration.maximum || 1; | ||
if (propNode.type === 'JSXSpreadAttribute') { | ||
return context.getSource(propNode.argument); | ||
return sourceCode.getText(propNode.argument); | ||
} | ||
@@ -45,3 +46,6 @@ return propNode.name.name; | ||
var name = getPropName(props[line][maximum]); | ||
context.report(props[line][maximum], 'Prop `' + name + '` must be placed on a new line'); | ||
context.report({ | ||
node: props[line][maximum], | ||
message: 'Prop `' + name + '` must be placed on a new line' | ||
}); | ||
break; | ||
@@ -48,0 +52,0 @@ } |
@@ -28,3 +28,6 @@ /** | ||
) { | ||
context.report(node, 'JSX props should not use .bind()'); | ||
context.report({ | ||
node: node, | ||
message: 'JSX props should not use .bind()' | ||
}); | ||
} else if ( | ||
@@ -34,3 +37,6 @@ !configuration.allowArrowFunctions && | ||
) { | ||
context.report(node, 'JSX props should not use arrow functions'); | ||
context.report({ | ||
node: node, | ||
message: 'JSX props should not use arrow functions' | ||
}); | ||
} | ||
@@ -37,0 +43,0 @@ } |
@@ -33,3 +33,6 @@ /** | ||
if (props.hasOwnProperty(name)) { | ||
context.report(decl, 'No duplicate props allowed'); | ||
context.report({ | ||
node: decl, | ||
message: 'No duplicate props allowed' | ||
}); | ||
} else { | ||
@@ -36,0 +39,0 @@ props[name] = 1; |
@@ -14,3 +14,6 @@ /* | ||
function reportLiteralNode(node) { | ||
context.report(node, 'Missing JSX expression container around literal string'); | ||
context.report({ | ||
node: node, | ||
message: 'Missing JSX expression container around literal string' | ||
}); | ||
} | ||
@@ -17,0 +20,0 @@ |
@@ -53,3 +53,6 @@ /** | ||
context.report(node, '\'' + node.name + '\' is not defined.'); | ||
context.report({ | ||
node: node, | ||
message: '\'' + node.name + '\' is not defined.' | ||
}); | ||
} | ||
@@ -62,2 +65,5 @@ | ||
node = node.name; | ||
if (isTagName(node.name)) { | ||
return; | ||
} | ||
break; | ||
@@ -73,5 +79,2 @@ case 'JSXMemberExpression': | ||
} | ||
if (isTagName(node.name)) { | ||
return; | ||
} | ||
checkIdentifierInJSX(node); | ||
@@ -78,0 +81,0 @@ } |
@@ -41,3 +41,6 @@ /** | ||
if (!isPascalCase && !isCompatTag) { | ||
context.report(node, 'Imported JSX component ' + node.name + ' must be in PascalCase'); | ||
context.report({ | ||
node: node, | ||
message: 'Imported JSX component ' + node.name + ' must be in PascalCase' | ||
}); | ||
} | ||
@@ -44,0 +47,0 @@ } |
/** | ||
* @fileoverview Enforce propTypes declarations alphabetical sorting | ||
* @deprecated | ||
*/ | ||
@@ -10,130 +11,20 @@ 'use strict'; | ||
var util = require('util'); | ||
var sortPropTypes = require('./sort-prop-types'); | ||
var isWarnedForDeprecation = false; | ||
module.exports = function(context) { | ||
var configuration = context.options[0] || {}; | ||
var requiredFirst = configuration.requiredFirst || false; | ||
var callbacksLast = configuration.callbacksLast || false; | ||
var ignoreCase = configuration.ignoreCase || false; | ||
/** | ||
* Checks if node is `propTypes` declaration | ||
* @param {ASTNode} node The AST node being checked. | ||
* @returns {Boolean} True if node is `propTypes` declaration, false if not. | ||
*/ | ||
function isPropTypesDeclaration(node) { | ||
// Special case for class properties | ||
// (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[0] && tokens[0].value === 'propTypes') || | ||
(tokens[1] && tokens[1].value === 'propTypes'); | ||
} | ||
return Boolean( | ||
node && | ||
node.name === 'propTypes' | ||
); | ||
} | ||
function getKey(node) { | ||
return node.key.type === 'Identifier' ? node.key.name : node.key.value; | ||
} | ||
function getValueName(node) { | ||
return node.value.property && node.value.property.name; | ||
} | ||
function isCallbackPropName(propName) { | ||
return /^on[A-Z]/.test(propName); | ||
} | ||
function isRequiredProp(node) { | ||
return getValueName(node) === 'isRequired'; | ||
} | ||
/** | ||
* Checks if propTypes declarations are sorted | ||
* @param {Array} declarations The array of AST nodes being checked. | ||
* @returns {void} | ||
*/ | ||
function checkSorted(declarations) { | ||
declarations.reduce(function(prev, curr) { | ||
var prevPropName = getKey(prev); | ||
var currentPropName = getKey(curr); | ||
var previousIsRequired = isRequiredProp(prev); | ||
var currentIsRequired = isRequiredProp(curr); | ||
var previousIsCallback = isCallbackPropName(prevPropName); | ||
var currentIsCallback = isCallbackPropName(currentPropName); | ||
if (ignoreCase) { | ||
prevPropName = prevPropName.toLowerCase(); | ||
currentPropName = currentPropName.toLowerCase(); | ||
return util._extend(sortPropTypes(context), { | ||
Program: function() { | ||
if (isWarnedForDeprecation || /\=-(f|-format)=/.test(process.argv.join('='))) { | ||
return; | ||
} | ||
if (requiredFirst) { | ||
if (previousIsRequired && !currentIsRequired) { | ||
// Transition between required and non-required. Don't compare for alphabetical. | ||
return curr; | ||
} | ||
if (!previousIsRequired && currentIsRequired) { | ||
// Encountered a non-required prop after a required prop | ||
context.report(curr, 'Required prop types must be listed before all other prop types'); | ||
return curr; | ||
} | ||
} | ||
if (callbacksLast) { | ||
if (!previousIsCallback && currentIsCallback) { | ||
// Entering the callback prop section | ||
return curr; | ||
} | ||
if (previousIsCallback && !currentIsCallback) { | ||
// Encountered a non-callback prop after a callback prop | ||
context.report(prev, 'Callback prop types must be listed after all other prop types'); | ||
return prev; | ||
} | ||
} | ||
if (currentPropName < prevPropName) { | ||
context.report(curr, 'Prop types declarations should be sorted alphabetically'); | ||
return prev; | ||
} | ||
return curr; | ||
}, declarations[0]); | ||
} | ||
return { | ||
ClassProperty: function(node) { | ||
if (isPropTypesDeclaration(node) && node.value && node.value.type === 'ObjectExpression') { | ||
checkSorted(node.value.properties); | ||
} | ||
}, | ||
MemberExpression: function(node) { | ||
if (isPropTypesDeclaration(node.property)) { | ||
var right = node.parent.right; | ||
if (right && right.type === 'ObjectExpression') { | ||
checkSorted(right.properties); | ||
} | ||
} | ||
}, | ||
ObjectExpression: function(node) { | ||
node.properties.forEach(function(property) { | ||
if (!property.key) { | ||
return; | ||
} | ||
if (!isPropTypesDeclaration(property.key)) { | ||
return; | ||
} | ||
if (property.value.type === 'ObjectExpression') { | ||
checkSorted(property.value.properties); | ||
} | ||
}); | ||
/* eslint-disable no-console */ | ||
console.log('The react/jsx-sort-prop-types rule is deprecated. Please ' + | ||
'use the react/sort-prop-types rule instead.'); | ||
/* eslint-enable no-console */ | ||
isWarnedForDeprecation = true; | ||
} | ||
}; | ||
}); | ||
}; | ||
@@ -140,0 +31,0 @@ |
@@ -48,3 +48,6 @@ /** | ||
// Encountered a non-callback prop after a callback prop | ||
context.report(memo, 'Callbacks must be listed after all other props'); | ||
context.report({ | ||
node: memo, | ||
message: 'Callbacks must be listed after all other props' | ||
}); | ||
return memo; | ||
@@ -59,3 +62,6 @@ } | ||
if (!currentValue && previousValue) { | ||
context.report(memo, 'Shorthand props must be listed before all other props'); | ||
context.report({ | ||
node: memo, | ||
message: 'Shorthand props must be listed before all other props' | ||
}); | ||
return memo; | ||
@@ -66,3 +72,6 @@ } | ||
if (currentPropName < previousPropName) { | ||
context.report(decl, 'Props should be sorted alphabetically'); | ||
context.report({ | ||
node: decl, | ||
message: 'Props should be sorted alphabetically' | ||
}); | ||
return memo; | ||
@@ -69,0 +78,0 @@ } |
@@ -55,4 +55,8 @@ /** | ||
if (isTagName(node.parent.name.name) && isDangerous(node.name.name)) { | ||
context.report(node, DANGEROUS_MESSAGE, { | ||
name: node.name.name | ||
context.report({ | ||
node: node, | ||
message: DANGEROUS_MESSAGE, | ||
data: { | ||
name: node.name.name | ||
} | ||
}); | ||
@@ -59,0 +63,0 @@ } |
@@ -22,2 +22,4 @@ /** | ||
var sourceCode = context.getSourceCode(); | ||
// Validate React version passed in options | ||
@@ -90,3 +92,3 @@ // (append the patch version if missing, allowing shorthands like 0.12 for React 0.12.0) | ||
MemberExpression: function(node) { | ||
var method = context.getSource(node); | ||
var method = sourceCode.getText(node); | ||
if (!isDeprecated(node.type, method)) { | ||
@@ -96,6 +98,10 @@ return; | ||
var deprecated = getDeprecated(); | ||
context.report(node, DEPRECATED_MESSAGE, { | ||
oldMethod: method, | ||
version: deprecated[node.type][method][0], | ||
newMethod: deprecated[node.type][method][1] ? ', use ' + deprecated[node.type][method][1] + ' instead' : '' | ||
context.report({ | ||
node: node, | ||
message: DEPRECATED_MESSAGE, | ||
data: { | ||
oldMethod: method, | ||
version: deprecated[node.type][method][0], | ||
newMethod: deprecated[node.type][method][1] ? ', use ' + deprecated[node.type][method][1] + ' instead' : '' | ||
} | ||
}); | ||
@@ -102,0 +108,0 @@ }, |
@@ -43,3 +43,6 @@ /** | ||
} | ||
context.report(callee, 'Do not use setState in componentDidMount'); | ||
context.report({ | ||
node: callee, | ||
message: 'Do not use setState in componentDidMount' | ||
}); | ||
break; | ||
@@ -46,0 +49,0 @@ } |
@@ -43,3 +43,6 @@ /** | ||
} | ||
context.report(callee, 'Do not use setState in componentDidUpdate'); | ||
context.report({ | ||
node: callee, | ||
message: 'Do not use setState in componentDidUpdate' | ||
}); | ||
break; | ||
@@ -46,0 +49,0 @@ } |
/** | ||
* @fileoverview Prevent usage of setState in componentDidMount | ||
* @fileoverview Prevent direct mutation of this.state | ||
* @author David Petersen | ||
@@ -32,3 +32,6 @@ */ | ||
mutation = component.mutations[i]; | ||
context.report(mutation, 'Do not mutate state directly. Use setState().'); | ||
context.report({ | ||
node: mutation, | ||
message: 'Do not mutate state directly. Use setState().' | ||
}); | ||
} | ||
@@ -35,0 +38,0 @@ } |
@@ -30,3 +30,6 @@ /** | ||
if (ancestors[i].type === 'Property' || ancestors[i].type === 'MethodDefinition') { | ||
context.report(callee, 'Do not use isMounted'); | ||
context.report({ | ||
node: callee, | ||
message: 'Do not use isMounted' | ||
}); | ||
break; | ||
@@ -33,0 +36,0 @@ } |
@@ -46,3 +46,6 @@ /** | ||
} | ||
context.report(list[component].node, MULTI_COMP_MESSAGE); | ||
context.report({ | ||
node: list[component].node, | ||
message: MULTI_COMP_MESSAGE | ||
}); | ||
} | ||
@@ -49,0 +52,0 @@ } |
@@ -30,3 +30,6 @@ /** | ||
if (ancestors[i].type === 'Property' || ancestors[i].type === 'MethodDefinition') { | ||
context.report(callee, 'Do not use setState'); | ||
context.report({ | ||
node: callee, | ||
message: 'Do not use setState' | ||
}); | ||
break; | ||
@@ -33,0 +36,0 @@ } |
@@ -74,3 +74,6 @@ /** | ||
if (isRefsUsage(node)) { | ||
context.report(node, 'Using this.refs is deprecated.'); | ||
context.report({ | ||
node: node, | ||
message: 'Using this.refs is deprecated.' | ||
}); | ||
} | ||
@@ -83,3 +86,6 @@ }, | ||
) { | ||
context.report(node, 'Using string literals in ref attributes is deprecated.'); | ||
context.report({ | ||
node: node, | ||
message: 'Using string literals in ref attributes is deprecated.' | ||
}); | ||
} | ||
@@ -86,0 +92,0 @@ } |
@@ -111,6 +111,8 @@ /** | ||
var sourceCode = context.getSourceCode(); | ||
return { | ||
JSXAttribute: function(node) { | ||
var name = context.getSource(node.name); | ||
var name = sourceCode.getText(node.name); | ||
var standardName = getStandardName(name); | ||
@@ -117,0 +119,0 @@ if (!isTagName(node) || !standardName) { |
@@ -19,3 +19,6 @@ /** | ||
if (utils.isES5Component(node) && configuration === 'always') { | ||
context.report(node, 'Component should use es6 class instead of createClass'); | ||
context.report({ | ||
node: node, | ||
message: 'Component should use es6 class instead of createClass' | ||
}); | ||
} | ||
@@ -25,3 +28,6 @@ }, | ||
if (utils.isES6Component(node) && configuration === 'never') { | ||
context.report(node, 'Component should use createClass instead of es6 class'); | ||
context.report({ | ||
node: node, | ||
message: 'Component should use createClass instead of es6 class' | ||
}); | ||
} | ||
@@ -28,0 +34,0 @@ } |
@@ -19,2 +19,3 @@ /** | ||
var sourceCode = context.getSourceCode(); | ||
var configuration = context.options[0] || {}; | ||
@@ -222,3 +223,3 @@ var ignored = configuration.ignore || []; | ||
function hasSpreadOperator(node) { | ||
var tokens = context.getTokens(node); | ||
var tokens = sourceCode.getTokens(node); | ||
return tokens.length && tokens[0].value === '...'; | ||
@@ -445,3 +446,3 @@ } | ||
function getPropertyName(node) { | ||
var isDirectProp = /^props(\.|\[)/.test(context.getSource(node)); | ||
var isDirectProp = /^props(\.|\[)/.test(sourceCode.getText(node)); | ||
var isInClassComponent = utils.getParentES6Component() || utils.getParentES5Component(); | ||
@@ -511,2 +512,8 @@ var isNotInConstructor = !inConstructor(node); | ||
break; | ||
case 'ArrowFunctionExpression': | ||
case 'FunctionDeclaration': | ||
case 'FunctionExpression': | ||
type = 'destructuring'; | ||
properties = node.params[0].properties; | ||
break; | ||
case 'VariableDeclarator': | ||
@@ -547,3 +554,3 @@ for (var i = 0, j = node.id.properties.length; i < j; i++) { | ||
var isDirectProp = /^props(\.|\[)/.test(context.getSource(node)); | ||
var isDirectProp = /^props(\.|\[)/.test(sourceCode.getText(node)); | ||
@@ -709,2 +716,17 @@ usedPropTypes.push({ | ||
/** | ||
* @param {ASTNode} node We expect either an ArrowFunctionExpression, | ||
* FunctionDeclaration, or FunctionExpression | ||
*/ | ||
function markDestructuredFunctionArgumentsAsUsed(node) { | ||
var destructuring = node.params && | ||
node.params.length === 1 && | ||
node.params[0] && | ||
node.params[0].type === 'ObjectPattern'; | ||
if (destructuring) { | ||
markPropTypesAsUsed(node); | ||
} | ||
} | ||
// -------------------------------------------------------------------------- | ||
@@ -736,2 +758,8 @@ // Public | ||
FunctionDeclaration: markDestructuredFunctionArgumentsAsUsed, | ||
ArrowFunctionExpression: markDestructuredFunctionArgumentsAsUsed, | ||
FunctionExpression: markDestructuredFunctionArgumentsAsUsed, | ||
MemberExpression: function(node) { | ||
@@ -738,0 +766,0 @@ var type; |
@@ -26,4 +26,8 @@ /** | ||
} | ||
context.report(node, NOT_DEFINED_MESSAGE, { | ||
name: pragma | ||
context.report({ | ||
node: node, | ||
message: NOT_DEFINED_MESSAGE, | ||
data: { | ||
name: pragma | ||
} | ||
}); | ||
@@ -30,0 +34,0 @@ }, |
@@ -65,3 +65,6 @@ /** | ||
if (!isPackage(id) && isForbiddenExtension(ext)) { | ||
context.report(node, 'Unable to require module with extension \'' + ext + '\''); | ||
context.report({ | ||
node: node, | ||
message: 'Unable to require module with extension \'' + ext + '\'' | ||
}); | ||
} | ||
@@ -68,0 +71,0 @@ } |
@@ -43,3 +43,6 @@ /** | ||
} | ||
context.report(node, 'Empty components are self-closing'); | ||
context.report({ | ||
node: node, | ||
message: 'Empty components are self-closing' | ||
}); | ||
} | ||
@@ -46,0 +49,0 @@ }; |
@@ -49,2 +49,3 @@ /** | ||
order: [ | ||
'static-methods', | ||
'lifecycle', | ||
@@ -87,3 +88,3 @@ 'everything-else', | ||
* Get indexes of the matching patterns in methods order configuration | ||
* @param {String} method - Method name. | ||
* @param {Object} method - Method metadata. | ||
* @returns {Array} The matching patterns indexes. Return [Infinity] if there is no match. | ||
@@ -97,11 +98,25 @@ */ | ||
var indexes = []; | ||
for (i = 0, j = methodsOrder.length; i < j; i++) { | ||
isRegExp = methodsOrder[i].match(regExpRegExp); | ||
if (isRegExp) { | ||
matching = new RegExp(isRegExp[1], isRegExp[2]).test(method); | ||
} else { | ||
matching = methodsOrder[i] === method; | ||
if (method.static) { | ||
for (i = 0, j = methodsOrder.length; i < j; i++) { | ||
if (methodsOrder[i] === 'static-methods') { | ||
indexes.push(i); | ||
break; | ||
} | ||
} | ||
if (matching) { | ||
indexes.push(i); | ||
} | ||
// Either this is not a static method or static methods are not specified | ||
// in the methodsOrder. | ||
if (indexes.length === 0) { | ||
for (i = 0, j = methodsOrder.length; i < j; i++) { | ||
isRegExp = methodsOrder[i].match(regExpRegExp); | ||
if (isRegExp) { | ||
matching = new RegExp(isRegExp[1], isRegExp[2]).test(method.name); | ||
} else { | ||
matching = methodsOrder[i] === method.name; | ||
} | ||
if (matching) { | ||
indexes.push(i); | ||
} | ||
} | ||
@@ -115,2 +130,3 @@ } | ||
indexes.push(i); | ||
break; | ||
} | ||
@@ -134,3 +150,2 @@ } | ||
function getPropertyName(node) { | ||
// Special case for class properties | ||
@@ -218,6 +233,10 @@ // (babel-eslint does not expose property name so we have to rely on tokens) | ||
context.report(nodeA, MISPOSITION_MESSAGE, { | ||
propA: getPropertyName(nodeA), | ||
propB: getPropertyName(nodeB), | ||
position: indexA < indexB ? 'before' : 'after' | ||
context.report({ | ||
node: nodeA, | ||
message: MISPOSITION_MESSAGE, | ||
data: { | ||
propA: getPropertyName(nodeA), | ||
propB: getPropertyName(nodeB), | ||
position: indexA < indexB ? 'before' : 'after' | ||
} | ||
}); | ||
@@ -245,8 +264,8 @@ } | ||
* Compare two properties and find out if they are in the right order | ||
* @param {Array} propertiesNames Array containing all the properties names. | ||
* @param {String} propA First property name. | ||
* @param {String} propB Second property name. | ||
* @param {Array} propertiesInfos Array containing all the properties metadata. | ||
* @param {Object} propA First property name and metadata | ||
* @param {Object} propB Second property name. | ||
* @returns {Object} Object containing a correct true/false flag and the correct indexes for the two properties. | ||
*/ | ||
function comparePropsOrder(propertiesNames, propA, propB) { | ||
function comparePropsOrder(propertiesInfos, propA, propB) { | ||
var i; | ||
@@ -264,4 +283,4 @@ var j; | ||
// Get current indexes for given properties | ||
var classIndexA = propertiesNames.indexOf(propA); | ||
var classIndexB = propertiesNames.indexOf(propB); | ||
var classIndexA = propertiesInfos.indexOf(propA); | ||
var classIndexB = propertiesInfos.indexOf(propB); | ||
@@ -307,3 +326,9 @@ // Loop around the references indexes for the 1st property | ||
function checkPropsOrder(properties) { | ||
var propertiesNames = properties.map(getPropertyName); | ||
var propertiesInfos = properties.map(function(node) { | ||
return { | ||
name: getPropertyName(node), | ||
static: node.static | ||
}; | ||
}); | ||
var i; | ||
@@ -318,11 +343,11 @@ var j; | ||
// Loop around the properties | ||
for (i = 0, j = propertiesNames.length; i < j; i++) { | ||
propA = propertiesNames[i]; | ||
for (i = 0, j = propertiesInfos.length; i < j; i++) { | ||
propA = propertiesInfos[i]; | ||
// Loop around the properties a second time (for comparison) | ||
for (k = 0, l = propertiesNames.length; k < l; k++) { | ||
propB = propertiesNames[k]; | ||
for (k = 0, l = propertiesInfos.length; k < l; k++) { | ||
propB = propertiesInfos[k]; | ||
// Compare the properties order | ||
order = comparePropsOrder(propertiesNames, propA, propB); | ||
order = comparePropsOrder(propertiesInfos, propA, propB); | ||
@@ -329,0 +354,0 @@ // Continue to next comparison is order is correct |
@@ -26,4 +26,4 @@ /** | ||
function isParenthesised(node) { | ||
var previousToken = context.getTokenBefore(node); | ||
var nextToken = context.getTokenAfter(node); | ||
var previousToken = sourceCode.getTokenBefore(node); | ||
var nextToken = sourceCode.getTokenAfter(node); | ||
@@ -30,0 +30,0 @@ return previousToken && nextToken && |
{ | ||
"name": "eslint-plugin-react", | ||
"version": "3.16.1", | ||
"version": "4.0.0-rc.0", | ||
"author": "Yannick Croissant <yannick.croissant+npm@gmail.com>", | ||
@@ -26,7 +26,7 @@ "description": "React specific linting rules for ESLint", | ||
"devDependencies": { | ||
"babel-eslint": "5.0.0-beta6", | ||
"babel-eslint": "5.0.0-beta10", | ||
"coveralls": "2.11.6", | ||
"eslint": "2.0.0-beta.2", | ||
"eslint": "2.0.0", | ||
"istanbul": "0.4.2", | ||
"mocha": "2.3.4" | ||
"mocha": "2.4.5" | ||
}, | ||
@@ -33,0 +33,0 @@ "keywords": [ |
122
README.md
@@ -72,47 +72,2 @@ ESLint-plugin-React | ||
```json | ||
{ | ||
"rules": { | ||
"react/display-name": 1, | ||
"react/forbid-prop-types": 1, | ||
"react/jsx-boolean-value": 1, | ||
"react/jsx-closing-bracket-location": 1, | ||
"react/jsx-curly-spacing": 1, | ||
"react/jsx-equals-spacing": 1, | ||
"react/jsx-handler-names": 1, | ||
"react/jsx-indent-props": 1, | ||
"react/jsx-indent": 1, | ||
"react/jsx-key": 1, | ||
"react/jsx-max-props-per-line": 1, | ||
"react/jsx-no-bind": 1, | ||
"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, | ||
"react/jsx-uses-react": 1, | ||
"react/jsx-uses-vars": 1, | ||
"react/no-danger": 1, | ||
"react/no-deprecated": 1, | ||
"react/no-did-mount-set-state": 1, | ||
"react/no-did-update-set-state": 1, | ||
"react/no-direct-mutation-state": 1, | ||
"react/no-is-mounted": 1, | ||
"react/no-multi-comp": 1, | ||
"react/no-set-state": 1, | ||
"react/no-string-refs": 1, | ||
"react/no-unknown-property": 1, | ||
"react/prefer-es6-class": 1, | ||
"react/prop-types": 1, | ||
"react/react-in-jsx-scope": 1, | ||
"react/require-extension": 1, | ||
"react/self-closing-comp": 1, | ||
"react/sort-comp": 1, | ||
"react/wrap-multilines": 1 | ||
} | ||
} | ||
``` | ||
# List of supported rules | ||
@@ -122,2 +77,22 @@ | ||
* [forbid-prop-types](docs/rules/forbid-prop-types.md): Forbid certain propTypes | ||
* [no-danger](docs/rules/no-danger.md): Prevent usage of dangerous JSX properties | ||
* [no-deprecated](docs/rules/no-deprecated.md): Prevent usage of deprecated methods | ||
* [no-did-mount-set-state](docs/rules/no-did-mount-set-state.md): Prevent usage of `setState` in `componentDidMount` | ||
* [no-did-update-set-state](docs/rules/no-did-update-set-state.md): Prevent usage of `setState` in `componentDidUpdate` | ||
* [no-direct-mutation-state](docs/rules/no-direct-mutation-state.md): Prevent direct mutation of `this.state` | ||
* [no-is-mounted](docs/rules/no-is-mounted.md): Prevent usage of `isMounted` | ||
* [no-multi-comp](docs/rules/no-multi-comp.md): Prevent multiple component definition per file | ||
* [no-set-state](docs/rules/no-set-state.md): Prevent usage of `setState` | ||
* [no-string-refs](docs/rules/no-string-refs.md): Prevent using string references in `ref` attribute. | ||
* [no-unknown-property](docs/rules/no-unknown-property.md): Prevent usage of unknown DOM property (fixable) | ||
* [prefer-es6-class](docs/rules/prefer-es6-class.md): Enforce ES5 or ES6 class for React Components | ||
* [prop-types](docs/rules/prop-types.md): Prevent missing props validation in a React component definition | ||
* [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 | ||
* [sort-comp](docs/rules/sort-comp.md): Enforce component methods order | ||
* [wrap-multilines](docs/rules/wrap-multilines.md): Prevent missing parentheses around multilines JSX (fixable) | ||
## JSX-specific rules | ||
* [jsx-boolean-value](docs/rules/jsx-boolean-value.md): Enforce boolean attributes notation in JSX (fixable) | ||
@@ -137,29 +112,48 @@ * [jsx-closing-bracket-location](docs/rules/jsx-closing-bracket-location.md): Validate closing bracket location in JSX | ||
* [jsx-pascal-case](docs/rules/jsx-pascal-case.md): Enforce PascalCase for user-defined JSX components | ||
* [jsx-quotes](docs/rules/jsx-quotes.md): Enforce quote style for JSX attributes | ||
* [jsx-sort-prop-types](docs/rules/jsx-sort-prop-types.md): Enforce propTypes declarations alphabetical sorting | ||
* [jsx-sort-props](docs/rules/jsx-sort-props.md): Enforce props alphabetical sorting | ||
* [jsx-space-before-closing](docs/rules/jsx-space-before-closing.md): Validate spacing before closing bracket in JSX (fixable) | ||
* [jsx-uses-react](docs/rules/jsx-uses-react.md): Prevent React to be incorrectly marked as unused | ||
* [jsx-uses-vars](docs/rules/jsx-uses-vars.md): Prevent variables used in JSX to be incorrectly marked as unused | ||
* [no-danger](docs/rules/no-danger.md): Prevent usage of dangerous JSX properties | ||
* [no-deprecated](docs/rules/no-deprecated.md): Prevent usage of deprecated methods | ||
* [no-did-mount-set-state](docs/rules/no-did-mount-set-state.md): Prevent usage of `setState` in `componentDidMount` | ||
* [no-did-update-set-state](docs/rules/no-did-update-set-state.md): Prevent usage of `setState` in `componentDidUpdate` | ||
* [no-direct-mutation-state](docs/rules/no-direct-mutation-state.md): Prevent direct mutation of `this.state` | ||
* [no-is-mounted](docs/rules/no-is-mounted.md): Prevent usage of `isMounted` | ||
* [no-multi-comp](docs/rules/no-multi-comp.md): Prevent multiple component definition per file | ||
* [no-set-state](docs/rules/no-set-state.md): Prevent usage of `setState` | ||
* [no-string-refs](docs/rules/no-string-refs.md): Prevent using string references in `ref` attribute. | ||
* [no-unknown-property](docs/rules/no-unknown-property.md): Prevent usage of unknown DOM property (fixable) | ||
* [prefer-es6-class](docs/rules/prefer-es6-class.md): Enforce ES5 or ES6 class for React Components | ||
* [prop-types](docs/rules/prop-types.md): Prevent missing props validation in a React component definition | ||
* [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 | ||
* [sort-comp](docs/rules/sort-comp.md): Enforce component methods order | ||
* [wrap-multilines](docs/rules/wrap-multilines.md): Prevent missing parentheses around multilines JSX (fixable) | ||
## React Native | ||
## React Native rules | ||
If you're searching for React Native specific linting rules, check out [eslint-plugin-react-native](https://github.com/Intellicode/eslint-plugin-react-native). | ||
# Recommended configuration | ||
This plugin export a `recommended` configuration that enforce React good practices. | ||
To enable this configuration use the `extends` property in your `.eslintrc` config file: | ||
```js | ||
{ | ||
"plugins": [ | ||
"react" | ||
], | ||
"extends": "plugin:react/recommended" | ||
} | ||
``` | ||
See [ESLint documentation](http://eslint.org/docs/user-guide/configuring#extending-configuration-files) for more information about extending configuration files. | ||
The rules enabled in this configuration are: | ||
* [display-name](docs/rules/display-name.md) | ||
* [jsx-no-duplicate-props](docs/rules/jsx-no-duplicate-props.md) | ||
* [jsx-no-undef](docs/rules/jsx-no-undef.md) | ||
* [jsx-uses-react](docs/rules/jsx-uses-react.md) | ||
* [jsx-uses-vars](docs/rules/jsx-uses-vars.md) | ||
* [no-danger](docs/rules/no-danger.md) | ||
* [no-deprecated](docs/rules/no-deprecated.md) | ||
* [no-did-mount-set-state](docs/rules/no-did-mount-set-state.md) with `allow-in-func` option | ||
* [no-did-update-set-state](docs/rules/no-did-update-set-state.md) with `allow-in-func` option | ||
* [no-direct-mutation-state](docs/rules/no-direct-mutation-state.md) | ||
* [no-is-mounted](docs/rules/no-is-mounted.md) | ||
* [no-unknown-property](docs/rules/no-unknown-property.md) | ||
* [prop-types](docs/rules/prop-types.md) | ||
* [react-in-jsx-scope](docs/rules/react-in-jsx-scope.md) | ||
**Note**: This configuration will also enable JSX in [parser options](http://eslint.org/docs/user-guide/configuring#specifying-parser-options). | ||
# License | ||
@@ -166,0 +160,0 @@ |
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
No v1
QualityPackage is not semver >=1. This means it is not stable and does not support ^ ranges.
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
197934
47
4525
1
181