Socket
Socket
Sign inDemoInstall

eslint-plugin-react

Package Overview
Dependencies
Maintainers
1
Versions
210
Alerts
File Explorer

Advanced tools

Socket logo

Install Socket

Detect and block malicious and high-risk dependencies

Install

eslint-plugin-react - npm Package Compare versions

Comparing version 3.16.1 to 4.0.0-rc.0

lib/rules/jsx-space-before-closing.js

40

CHANGELOG.md

@@ -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": [

@@ -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 @@

SocketSocket SOC 2 Logo

Product

  • Package Alerts
  • Integrations
  • Docs
  • Pricing
  • FAQ
  • Roadmap
  • Changelog

Packages

npm

Stay in touch

Get open source security insights delivered straight into your inbox.


  • Terms
  • Privacy
  • Security

Made with ⚡️ by Socket Inc