Socket
Socket
Sign inDemoInstall

eslint-plugin-react

Package Overview
Dependencies
Maintainers
2
Versions
212
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 7.30.1 to 7.30.2

.markdownlint.json

4

lib/rules/boolean-prop-naming.js

@@ -175,5 +175,3 @@ /**

function runCheck(proptypes, addInvalidProp) {
proptypes = proptypes || [];
proptypes.forEach((prop) => {
(proptypes || []).forEach((prop) => {
if (config.validateNested && nestedPropTypes(prop)) {

@@ -180,0 +178,0 @@ runCheck(prop.value.arguments[0].properties, addInvalidProp);

@@ -34,3 +34,3 @@ /**

docs: {
description: 'Forbid "button" element without an explicit "type" attribute',
description: 'Disallow usage of `button` elements without an explicit `type` attribute',
category: 'Possible Errors',

@@ -37,0 +37,0 @@ recommended: false,

@@ -25,3 +25,3 @@ /**

docs: {
description: 'Enforce all defaultProps are defined and not "required" in propTypes.',
description: 'Enforce all defaultProps have a corresponding non-required PropType',
category: 'Best Practices',

@@ -28,0 +28,0 @@ url: docsUrl('default-props-match-prop-types'),

@@ -14,2 +14,3 @@ /**

const docsUrl = require('../util/docsUrl');
const testReactVersion = require('../util/version').testReactVersion;
const propsUtil = require('../util/props');

@@ -29,3 +30,3 @@ const report = require('../util/report');

docs: {
description: 'Prevent missing displayName in a React component definition',
description: 'Disallow missing displayName in a React component definition',
category: 'Best Practices',

@@ -64,2 +65,13 @@ recommended: true,

/**
* Checks if React.forwardRef is nested inside React.memo
* @param {ASTNode} node The AST node being checked.
* @returns {Boolean} True if React.forwardRef is nested inside React.memo, false if not.
*/
function isNestedMemo(node) {
const argumentIsCallExpression = node.arguments && node.arguments[0] && node.arguments[0].type === 'CallExpression';
return node.type === 'CallExpression' && argumentIsCallExpression && utils.isPragmaComponentWrapper(node);
}
/**
* Reports missing display name for a given component

@@ -69,2 +81,9 @@ * @param {Object} component The component to process

function reportMissingDisplayName(component) {
if (
testReactVersion(context, '^0.14.10 || ^15.7.0 || >= 16.12.0')
&& isNestedMemo(component.node)
) {
return;
}
report(context, messages.noDisplayName, 'noDisplayName', {

@@ -71,0 +90,0 @@ node: component.node,

@@ -28,3 +28,3 @@ /**

docs: {
description: 'Forbid certain props on components',
description: 'Disallow certain props on components',
category: 'Best Practices',

@@ -31,0 +31,0 @@ recommended: false,

@@ -21,2 +21,17 @@ /**

/**
* @param {Map<string, object>} forbidMap // { disallowList: null | string[], message: null | string }
* @param {string} prop
* @param {string} tagName
* @returns {boolean}
*/
function isForbidden(forbidMap, prop, tagName) {
const options = forbidMap.get(prop);
return options && (
typeof tagName === 'undefined'
|| !options.disallowList
|| options.disallowList.indexOf(tagName) !== -1
);
}
const messages = {

@@ -29,3 +44,3 @@ propIsForbidden: 'Prop "{{prop}}" is forbidden on DOM Nodes',

docs: {
description: 'Forbid certain props on DOM Nodes',
description: 'Disallow certain props on DOM Nodes',
category: 'Best Practices',

@@ -52,2 +67,9 @@ recommended: false,

},
disallowedFor: {
type: 'array',
uniqueItems: true,
items: {
type: 'string',
},
},
message: {

@@ -71,12 +93,8 @@ type: 'string',

const propName = typeof value === 'string' ? value : value.propName;
const options = {
return [propName, {
disallowList: typeof value === 'string' ? null : (value.disallowedFor || null),
message: typeof value === 'string' ? null : value.message,
};
return [propName, options];
}];
}));
function isForbidden(prop) {
return forbid.has(prop);
}
return {

@@ -92,3 +110,3 @@ JSXAttribute(node) {

if (!isForbidden(prop)) {
if (!isForbidden(forbid, prop, tag)) {
return;

@@ -95,0 +113,0 @@ }

@@ -25,3 +25,3 @@ /**

docs: {
description: 'Forbid certain elements',
description: 'Disallow certain elements',
category: 'Best Practices',

@@ -28,0 +28,0 @@ recommended: false,

@@ -19,3 +19,3 @@ /**

docs: {
description: 'Forbid using another component\'s propTypes',
description: 'Disallow using another component\'s propTypes',
category: 'Best Practices',

@@ -22,0 +22,0 @@ recommended: false,

@@ -31,3 +31,3 @@ /**

docs: {
description: 'Forbid certain propTypes',
description: 'Disallow certain propTypes',
category: 'Best Practices',

@@ -64,3 +64,24 @@ recommended: false,

const checkChildContextTypes = configuration.checkChildContextTypes || false;
let propTypesPackageName = null;
let reactPackageName = null;
let isForeignPropTypesPackage = false;
function isPropTypesPackage(node) {
return (
node.type === 'Identifier'
&& (
node.name === null
|| node.name === propTypesPackageName
|| !isForeignPropTypesPackage
)
) || (
node.type === 'MemberExpression'
&& (
node.object.name === null
|| node.object.name === reactPackageName
|| !isForeignPropTypesPackage
)
);
}
function isForbidden(type) {

@@ -118,2 +139,5 @@ const forbid = configuration.forbid || DEFAULTS;

if (value.type === 'CallExpression') {
if (!isPropTypesPackage(value.callee)) {
return;
}
value.arguments.forEach((arg) => {

@@ -125,2 +149,5 @@ const name = arg.type === 'MemberExpression' ? arg.property.name : arg.name;

}
if (!isPropTypesPackage(value)) {
return;
}
if (value.property) {

@@ -164,5 +191,31 @@ target = value.property.name;

return {
ImportDeclaration(node) {
if (node.source && node.source.value === 'prop-types') { // import PropType from "prop-types"
if (node.specifiers.length > 0) {
propTypesPackageName = node.specifiers[0].local.name;
}
} else if (node.source && node.source.value === 'react') { // import { PropTypes } from "react"
if (node.specifiers.length > 0) {
reactPackageName = node.specifiers[0].local.name; // guard against accidental anonymous `import "react"`
}
if (node.specifiers.length >= 1) {
const propTypesSpecifier = node.specifiers.find((specifier) => (
specifier.imported && specifier.imported.name === 'PropTypes'
));
if (propTypesSpecifier) {
propTypesPackageName = propTypesSpecifier.local.name;
}
}
} else { // package is not imported from "react" or "prop-types"
// eslint-disable-next-line no-lonely-if
if (node.specifiers.some((x) => x.local.name === 'PropTypes')) { // assert: node.specifiers.length > 1
isForeignPropTypesPackage = true;
}
}
},
'ClassProperty, PropertyDefinition'(node) {
if (
!propsUtil.isPropTypesDeclaration(node)
&& !isPropTypesPackage(node)
&& !shouldCheckContextTypes(node)

@@ -179,2 +232,3 @@ && !shouldCheckChildContextTypes(node)

!propsUtil.isPropTypesDeclaration(node)
&& !isPropTypesPackage(node)
&& !shouldCheckContextTypes(node)

@@ -191,2 +245,10 @@ && !shouldCheckChildContextTypes(node)

if (
node.callee.object
&& !isPropTypesPackage(node.callee.object)
&& !propsUtil.isPropTypesDeclaration(node.callee)
) {
return;
}
if (
node.arguments.length > 0

@@ -202,2 +264,3 @@ && (node.callee.name === 'shape' || astUtil.getPropertyName(node.callee) === 'shape')

!propsUtil.isPropTypesDeclaration(node)
&& !isPropTypesPackage(node)
&& !shouldCheckContextTypes(node)

@@ -224,2 +287,3 @@ && !shouldCheckChildContextTypes(node)

!propsUtil.isPropTypesDeclaration(property)
&& !isPropTypesPackage(property)
&& !shouldCheckContextTypes(property)

@@ -226,0 +290,0 @@ && !shouldCheckChildContextTypes(property)

@@ -121,3 +121,3 @@ /**

docs: {
description: 'Standardize the way function component get defined',
description: 'Enforce a specific function type for function components',
category: 'Stylistic Issues',

@@ -124,0 +124,0 @@ recommended: false,

@@ -23,3 +23,3 @@ /**

docs: {
description: 'Ensure symmetric naming of useState hook value and setter variables',
description: 'Ensure destructuring and symmetric naming of useState hook value and setter variables',
category: 'Best Practices',

@@ -26,0 +26,0 @@ recommended: false,

@@ -25,2 +25,6 @@ /**

const errorData = new WeakMap();
/**
* @param {object} exceptions
* @returns {object}
*/
function getErrorData(exceptions) {

@@ -34,3 +38,8 @@ if (!errorData.has(exceptions)) {

}
/**
* @param {string} configuration
* @param {Set<string>} exceptions
* @param {string} propName
* @returns {boolean} propName
*/
function isAlways(configuration, exceptions, propName) {

@@ -43,3 +52,8 @@ const isException = exceptions.has(propName);

}
/**
* @param {string} configuration
* @param {Set<string>} exceptions
* @param {string} propName
* @returns {boolean} propName
*/
function isNever(configuration, exceptions, propName) {

@@ -115,3 +129,6 @@ const isException = exceptions.has(propName);

if (isAlways(configuration, exceptions, propName) && value === null) {
if (
isAlways(configuration, exceptions, propName)
&& value === null
) {
const data = getErrorData(exceptions);

@@ -127,3 +144,8 @@ const messageId = data.exceptionsMessage ? 'setBoolean' : 'setBoolean_noMessage';

}
if (isNever(configuration, exceptions, propName) && value && value.type === 'JSXExpressionContainer' && value.expression.value === true) {
if (
isNever(configuration, exceptions, propName)
&& value
&& value.type === 'JSXExpressionContainer'
&& value.expression.value === true
) {
const data = getErrorData(exceptions);

@@ -130,0 +152,0 @@ const messageId = data.exceptionsMessage ? 'omitBoolean' : 'omitBoolean_noMessage';

@@ -50,3 +50,3 @@ 'use strict';

docs: {
description: 'Ensures inline tags are not rendered without spaces between them',
description: 'Enforce or disallow spaces inside of curly braces in JSX attributes and expressions',
category: 'Stylistic Issues',

@@ -60,10 +60,3 @@ recommended: false,

schema: [
{
type: 'object',
properties: {},
default: {},
additionalProperties: false,
},
],
schema: [],
},

@@ -70,0 +63,0 @@ create(context) {

@@ -23,3 +23,3 @@ /**

docs: {
description: 'Validate closing bracket location in JSX',
description: 'Enforce closing bracket location in JSX',
category: 'Stylistic Issues',

@@ -169,3 +169,3 @@ recommended: false,

function getIndentation(tokens, expectedLocation, correctColumn) {
correctColumn = correctColumn || 0;
const newColumn = correctColumn || 0;
let indentation;

@@ -184,3 +184,3 @@ let spaces = [];

}
if (indentation.length + 1 < correctColumn) {
if (indentation.length + 1 < newColumn) {
// Non-whitespace characters were included in the column offset

@@ -187,0 +187,0 @@ spaces = new Array(+correctColumn + 1 - indentation.length);

@@ -24,3 +24,3 @@ /**

docs: {
description: 'Validate closing tag location for multiline JSX',
description: 'Enforce closing tag location for multiline JSX',
category: 'Stylistic Issues',

@@ -27,0 +27,0 @@ recommended: false,

@@ -42,3 +42,3 @@ /**

docs: {
description: 'Disallow unnecessary JSX expressions when literals alone are sufficient or enfore JSX expressions on literals in JSX children or attributes',
description: 'Disallow unnecessary JSX expressions when literals alone are sufficient or enforce JSX expressions on literals in JSX children or attributes',
category: 'Stylistic Issues',

@@ -142,4 +142,4 @@ recommended: false,

const htmlEntities = text.match(HTML_ENTITY_REGEX());
return htmlEntities.reduce((acc, htmlEntitiy) => (
acc.replace(HTML_ENTITY, htmlEntitiy)
return htmlEntities.reduce((acc, htmlEntity) => (
acc.replace(HTML_ENTITY, htmlEntity)
), withCurlyBraces);

@@ -249,4 +249,4 @@ }

// Bail out if there is any character that needs to be escaped in JSX
// because escaping decreases readiblity and the original code may be more
// readible anyway or intentional for other specific reasons
// because escaping decreases readability and the original code may be more
// readable anyway or intentional for other specific reasons
function lintUnnecessaryCurly(JSXExpressionNode) {

@@ -253,0 +253,0 @@ const expression = JSXExpressionNode.expression;

@@ -49,3 +49,3 @@ /**

docs: {
description: 'Enforce consistent line breaks inside jsx curly',
description: 'Enforce consistent linebreaks in curly braces in JSX attributes and expressions',
category: 'Stylistic Issues',

@@ -52,0 +52,0 @@ recommended: false,

@@ -40,3 +40,3 @@ /**

docs: {
description: 'Enforce or disallow spaces inside of curly braces in JSX attributes',
description: 'Enforce or disallow spaces inside of curly braces in JSX attributes and expressions',
category: 'Stylistic Issues',

@@ -43,0 +43,0 @@ recommended: false,

@@ -25,3 +25,3 @@ /**

docs: {
description: 'Disallow or enforce spaces around equal signs in JSX attributes',
description: 'Enforce or disallow spaces around equal signs in JSX attributes',
category: 'Stylistic Issues',

@@ -28,0 +28,0 @@ recommended: false,

@@ -33,3 +33,3 @@ /**

docs: {
description: 'Restrict file extensions that may contain JSX',
description: 'Disallow file extensions that may contain JSX',
category: 'Stylistic Issues',

@@ -36,0 +36,0 @@ recommended: false,

@@ -23,3 +23,3 @@ /**

docs: {
description: 'Ensure proper position of the first property in JSX',
description: 'Enforce proper position of the first property in JSX',
category: 'Stylistic Issues',

@@ -26,0 +26,0 @@ recommended: false,

@@ -48,3 +48,3 @@ /**

docs: {
description: 'Validate props indentation in JSX',
description: 'Enforce props indentation in JSX',
category: 'Stylistic Issues',

@@ -176,6 +176,12 @@ recommended: false,

function checkNodesIndent(nodes, indent) {
let nestedIndent = indent;
nodes.forEach((node) => {
const nodeIndent = getNodeIndent(node);
if (line.isUsingOperator && !line.currentOperator && indentSize !== 'first' && !ignoreTernaryOperator) {
indent += indentSize;
if (
line.isUsingOperator
&& !line.currentOperator
&& indentSize !== 'first'
&& !ignoreTernaryOperator
) {
nestedIndent += indentSize;
line.isUsingOperator = false;

@@ -185,5 +191,5 @@ }

node.type !== 'ArrayExpression' && node.type !== 'ObjectExpression'
&& nodeIndent !== indent && astUtil.isNodeFirstInLine(context, node)
&& nodeIndent !== nestedIndent && astUtil.isNodeFirstInLine(context, node)
) {
report(node, indent, nodeIndent);
report(node, nestedIndent, nodeIndent);
}

@@ -190,0 +196,0 @@ });

@@ -51,3 +51,3 @@ /**

docs: {
description: 'Validate JSX indentation',
description: 'Enforce JSX indentation',
category: 'Stylistic Issues',

@@ -172,5 +172,2 @@ recommended: false,

function getNodeIndent(node, byLastLine, excludeCommas) {
byLastLine = byLastLine || false;
excludeCommas = excludeCommas || false;
let src = context.getSourceCode().getText(node, node.loc.start.column + extraColumnStart);

@@ -177,0 +174,0 @@ const lines = src.split('\n');

@@ -37,3 +37,3 @@ /**

docs: {
description: 'Report missing `key` props in iterators/collection literals',
description: 'Disallow missing `key` props in iterators/collection literals',
category: 'Possible Errors',

@@ -90,4 +90,24 @@ recommended: true,

function getReturnStatement(body) {
return body.filter((item) => item.type === 'ReturnStatement')[0];
function getReturnStatements(node) {
const returnStatements = arguments[1] || [];
if (node.type === 'IfStatement') {
if (node.consequent) {
getReturnStatements(node.consequent, returnStatements);
}
if (node.alternate) {
getReturnStatements(node.alternate, returnStatements);
}
} else if (Array.isArray(node.body)) {
node.body.forEach((item) => {
if (item.type === 'IfStatement') {
getReturnStatements(item, returnStatements);
}
if (item.type === 'ReturnStatement') {
returnStatements.push(item);
}
});
}
return returnStatements;
}

@@ -194,6 +214,7 @@

if (fn.body.type === 'BlockStatement') {
const returnStatement = getReturnStatement(fn.body.body);
if (returnStatement && returnStatement.argument) {
checkIteratorElement(returnStatement.argument);
}
getReturnStatements(fn.body)
.filter((returnStatement) => returnStatement && returnStatement.argument)
.forEach((returnStatement) => {
checkIteratorElement(returnStatement.argument);
});
}

@@ -200,0 +221,0 @@ }

@@ -26,3 +26,3 @@ /**

docs: {
description: 'Validate JSX maximum depth',
description: 'Enforce JSX maximum depth',
category: 'Stylistic Issues',

@@ -29,0 +29,0 @@ recommended: false,

@@ -29,3 +29,3 @@ /**

docs: {
description: 'Limit maximum of props on a single line in JSX',
description: 'Enforce maximum of props on a single line in JSX',
category: 'Stylistic Issues',

@@ -32,0 +32,0 @@ recommended: false,

@@ -19,4 +19,9 @@ /**

prevent: 'JSX element should not start in a new line',
allowMultilines: 'Multiline JSX elements should start in a new line',
};
function isMultilined(node) {
return node.loc.start.line !== node.loc.end.line;
}
module.exports = {

@@ -41,4 +46,25 @@ meta: {

},
allowMultilines: {
default: false,
type: 'boolean',
},
},
additionalProperties: false,
if: {
properties: {
allowMultilines: {
const: true,
},
},
},
then: {
properties: {
prevent: {
const: true,
},
},
required: [
'prevent',
],
},
},

@@ -50,2 +76,3 @@ ],

const sourceCode = context.getSourceCode();
return {

@@ -56,2 +83,6 @@ 'Program:exit'() {

if (element.type === 'JSXElement' || element.type === 'JSXExpressionContainer') {
const configuration = context.options[0] || {};
const prevent = configuration.prevent || false;
const allowMultilines = configuration.allowMultilines || false;
const firstAdjacentSibling = elements[index + 1];

@@ -69,6 +100,24 @@ const secondAdjacentSibling = elements[index + 2];

const prevent = !!(context.options[0] || {}).prevent;
if (allowMultilines && (isMultilined(element) || isMultilined(secondAdjacentSibling))) {
if (!isWithoutNewLine) return;
const regex = /(\n)(?!.*\1)/g;
const replacement = '\n\n';
const messageId = 'allowMultilines';
report(context, messages[messageId], messageId, {
node: secondAdjacentSibling,
fix(fixer) {
return fixer.replaceText(
firstAdjacentSibling,
sourceCode.getText(firstAdjacentSibling)
.replace(regex, replacement)
);
},
});
return;
}
if (isWithoutNewLine === prevent) return;
const messageId = prevent

@@ -75,0 +124,0 @@ ? 'prevent'

@@ -29,3 +29,3 @@ /**

docs: {
description: 'Prevents usage of Function.prototype.bind and arrow functions in React component props',
description: 'Disallow `.bind()` or arrow functions in JSX props',
category: 'Best Practices',

@@ -73,2 +73,5 @@ recommended: false,

/**
* @param {string | number} blockStart
*/
function setBlockVariableNameSet(blockStart) {

@@ -85,3 +88,2 @@ blockVariableNameSets[blockStart] = {

const nodeType = node.type;
if (

@@ -117,2 +119,7 @@ !configuration.allowBind

/**
* @param {string | number} violationType
* @param {any} variableName
* @param {string | number} blockStart
*/
function addVariableNameToSet(violationType, variableName, blockStart) {

@@ -119,0 +126,0 @@ blockVariableNameSets[blockStart][violationType].add(variableName);

@@ -39,3 +39,3 @@ /**

docs: {
description: 'Comments inside children section of tag should be placed inside braces',
description: 'Disallow comments from being inserted as text nodes',
category: 'Possible Errors',

@@ -48,7 +48,3 @@ recommended: true,

schema: [{
type: 'object',
properties: {},
additionalProperties: false,
}],
schema: [],
},

@@ -55,0 +51,0 @@

@@ -134,3 +134,3 @@ /**

docs: {
description: 'Prevents JSX context provider values from taking values that will cause needless rerenders.',
description: 'Disallows JSX context provider values from taking values that will cause needless rerenders',
category: 'Best Practices',

@@ -137,0 +137,0 @@ recommended: false,

@@ -23,3 +23,3 @@ /**

docs: {
description: 'Enforce no duplicate props',
description: 'Disallow duplicate properties in JSX',
category: 'Possible Errors',

@@ -26,0 +26,0 @@ recommended: true,

@@ -43,2 +43,11 @@ /**

function extractExpressionBetweenLogicalAnds(node) {
if (node.type !== 'LogicalExpression') return [node];
if (node.operator !== '&&') return [node];
return [].concat(
extractExpressionBetweenLogicalAnds(node.left),
extractExpressionBetweenLogicalAnds(node.right)
);
}
function ruleFixer(context, fixStrategy, fixer, reportedNode, leftNode, rightNode) {

@@ -49,10 +58,12 @@ const sourceCode = context.getSourceCode();

if (fixStrategy === COERCE_STRATEGY) {
let leftSideText = sourceCode.getText(leftNode);
if (isParenthesized(context, leftNode)) {
leftSideText = `(${leftSideText})`;
}
const expressions = extractExpressionBetweenLogicalAnds(leftNode);
const newText = expressions.map((node) => {
let nodeText = sourceCode.getText(node);
if (isParenthesized(context, node)) {
nodeText = `(${nodeText})`;
}
return `${getIsCoerceValidNestedLogicalExpression(node) ? '' : '!!'}${nodeText}`;
}).join(' && ');
const shouldPrefixDoubleNegation = leftNode.type !== 'UnaryExpression';
return fixer.replaceText(reportedNode, `${shouldPrefixDoubleNegation ? '!!' : ''}${leftSideText} && ${rightSideText}`);
return fixer.replaceText(reportedNode, `${newText} && ${rightSideText}`);
}

@@ -77,3 +88,3 @@

docs: {
description: 'Prevent problematic leaked values from being rendered',
description: 'Disallow problematic leaked values from being rendered',
category: 'Possible Errors',

@@ -80,0 +91,0 @@ recommended: false,

@@ -30,3 +30,3 @@ /**

docs: {
description: 'Prevent using string literals in React component definition',
description: 'Disallow usage of string literals in JSX',
category: 'Stylistic Issues',

@@ -74,3 +74,4 @@ recommended: false,

function defaultMessageId() {
if (config.noAttributeStrings) {
const ancestorIsJSXElement = arguments.length >= 1 && arguments[0];
if (config.noAttributeStrings && !ancestorIsJSXElement) {
return 'noStringsInAttributes';

@@ -84,13 +85,2 @@ }

function reportLiteralNode(node, messageId) {
messageId = messageId || defaultMessageId();
report(context, messages[messageId], messageId, {
node,
data: {
text: context.getSourceCode().getText(node).trim(),
},
});
}
function getParentIgnoringBinaryExpressions(node) {

@@ -105,5 +95,7 @@ let current = node;

function getValidation(node) {
if (config.allowedStrings.has(trimIfString(node.value))) {
const values = [trimIfString(node.raw), trimIfString(node.value)];
if (values.some((value) => config.allowedStrings.has(value))) {
return false;
}
const parent = getParentIgnoringBinaryExpressions(node);

@@ -114,3 +106,3 @@

if (config.noAttributeStrings) {
return parent.type === 'JSXAttribute';
return parent.type === 'JSXAttribute' || parent.type === 'JSXElement';
}

@@ -154,2 +146,14 @@ if (!config.noAttributeStrings) {

function reportLiteralNode(node, messageId) {
const ancestorIsJSXElement = hasJSXElementParentOrGrandParent(node);
messageId = messageId || defaultMessageId(ancestorIsJSXElement);
report(context, messages[messageId], messageId, {
node,
data: {
text: context.getSourceCode().getText(node).trim(),
},
});
}
// --------------------------------------------------------------------------

@@ -156,0 +160,0 @@ // Public

@@ -53,3 +53,3 @@ /**

docs: {
description: 'Forbid `javascript:` URLs',
description: 'Disallow usage of `javascript:` URLs',
category: 'Best Practices',

@@ -56,0 +56,0 @@ recommended: false,

@@ -77,3 +77,8 @@ /**

}
return value.expression && value.expression.value;
const expr = value.expression;
return expr && (
expr.type === 'ConditionalExpression'
? [expr.consequent.value, expr.alternate.value]
: expr.value
);
}

@@ -92,8 +97,11 @@ }

const value = getStringFromValue(relAttribute.value);
const tags = value && typeof value === 'string' && value.toLowerCase().split(' ');
const noreferrer = tags && tags.indexOf('noreferrer') >= 0;
if (noreferrer) {
return true;
}
return allowReferrer && tags && tags.indexOf('noopener') >= 0;
return [].concat(value).every((item) => {
const tags = typeof item === 'string' ? item.toLowerCase().split(' ') : false;
const noreferrer = tags && tags.indexOf('noreferrer') >= 0;
if (noreferrer) {
return true;
}
const noopener = tags && tags.indexOf('noopener') >= 0;
return allowReferrer && noopener;
});
}

@@ -110,3 +118,3 @@

docs: {
description: 'Forbid `target="_blank"` attribute without `rel="noreferrer"`',
description: 'Disallow `target="_blank"` attribute without `rel="noreferrer"`',
category: 'Best Practices',

@@ -113,0 +121,0 @@ recommended: true,

@@ -27,3 +27,3 @@ /**

docs: {
description: 'Limit to one expression per line in JSX',
description: 'Require one JSX element per line',
category: 'Stylistic Issues',

@@ -30,0 +30,0 @@ recommended: false,

@@ -44,3 +44,3 @@ /**

docs: {
description: 'Prevent JSX prop spreading',
description: 'Disallow JSX prop spreading',
category: 'Best Practices',

@@ -47,0 +47,0 @@ recommended: false,

@@ -23,3 +23,3 @@ /**

docs: {
description: 'Enforce default props alphabetical sorting',
description: 'Enforce defaultProps declarations alphabetical sorting',
category: 'Stylistic Issues',

@@ -26,0 +26,0 @@ recommended: false,

@@ -49,2 +49,10 @@ /**

let attributeMap;
// attributeMap = [endrange, true||false if comment in between nodes exists, it needs to be sorted to end]
function shouldSortToEnd(node) {
const attr = attributeMap.get(node);
return !!attr && !!attr[1];
}
function contextCompare(a, b, options) {

@@ -54,2 +62,11 @@ let aProp = propName(a);

const aSortToEnd = shouldSortToEnd(a);
const bSortToEnd = shouldSortToEnd(b);
if (aSortToEnd && !bSortToEnd) {
return 1;
}
if (!aSortToEnd && bSortToEnd) {
return -1;
}
if (options.reservedFirst) {

@@ -123,9 +140,25 @@ const aIsReserved = isReservedPropName(aProp, options.reservedList);

* @param {Array<JSXSpreadAttribute|JSXAttribute>} attributes
* @param {Object} context The context of the rule
* @return {Array<Array<JSXAttribute>>}
*/
function getGroupsOfSortableAttributes(attributes) {
function getGroupsOfSortableAttributes(attributes, context) {
const sourceCode = context.getSourceCode();
const sortableAttributeGroups = [];
let groupCount = 0;
function addtoSortableAttributeGroups(attribute) {
sortableAttributeGroups[groupCount - 1].push(attribute);
}
for (let i = 0; i < attributes.length; i++) {
const attribute = attributes[i];
const nextAttribute = attributes[i + 1];
const attributeline = attribute.loc.start.line;
let comment = [];
try {
comment = sourceCode.getCommentsAfter(attribute);
} catch (e) { /**/ }
const lastAttr = attributes[i - 1];
const attrIsSpread = attribute.type === 'JSXSpreadAttribute';
// If we have no groups or if the last attribute was JSXSpreadAttribute

@@ -136,4 +169,3 @@ // then we start a new group. Append attributes to the group until we

!lastAttr
|| (lastAttr.type === 'JSXSpreadAttribute'
&& attributes[i].type !== 'JSXSpreadAttribute')
|| (lastAttr.type === 'JSXSpreadAttribute' && !attrIsSpread)
) {

@@ -143,4 +175,36 @@ groupCount += 1;

}
if (attributes[i].type !== 'JSXSpreadAttribute') {
sortableAttributeGroups[groupCount - 1].push(attributes[i]);
if (!attrIsSpread) {
if (comment.length === 0) {
attributeMap.set(attribute, [attribute.range[1], false]);
addtoSortableAttributeGroups(attribute);
} else {
const firstComment = comment[0];
const commentline = firstComment.loc.start.line;
if (comment.length === 1) {
if (attributeline + 1 === commentline && nextAttribute) {
attributeMap.set(attribute, [nextAttribute.range[1], true]);
addtoSortableAttributeGroups(attribute);
i += 1;
} else if (attributeline === commentline) {
if (firstComment.type === 'Block') {
attributeMap.set(attribute, [nextAttribute.range[1], true]);
i += 1;
} else {
attributeMap.set(attribute, [firstComment.range[1], false]);
}
addtoSortableAttributeGroups(attribute);
}
} else if (comment.length > 1 && attributeline + 1 === comment[1].loc.start.line && nextAttribute) {
const commentNextAttribute = sourceCode.getCommentsAfter(nextAttribute);
attributeMap.set(attribute, [nextAttribute.range[1], true]);
if (
commentNextAttribute.length === 1
&& nextAttribute.loc.start.line === commentNextAttribute[0].loc.start.line
) {
attributeMap.set(attribute, [commentNextAttribute[0].range[1], true]);
}
addtoSortableAttributeGroups(attribute);
i += 1;
}
}
}

@@ -151,3 +215,3 @@ }

const generateFixerFunction = (node, context, reservedList) => {
function generateFixerFunction(node, context, reservedList) {
const sourceCode = context.getSourceCode();

@@ -179,3 +243,3 @@ const attributes = node.attributes.slice(0);

};
const sortableAttributeGroups = getGroupsOfSortableAttributes(attributes);
const sortableAttributeGroups = getGroupsOfSortableAttributes(attributes, context);
const sortedAttributeGroups = sortableAttributeGroups

@@ -189,9 +253,9 @@ .slice(0)

// Replace each unsorted attribute with the sorted one.
sortableAttributeGroups.forEach((sortableGroup, ii) => {
sortableGroup.forEach((attr, jj) => {
const sortedAttr = sortedAttributeGroups[ii][jj];
const sortedAttrText = sourceCode.getText(sortedAttr);
const sortedAttrText = source.substring(sortedAttr.range[0], attributeMap.get(sortedAttr)[0]);
const attrrangeEnd = attributeMap.get(attr)[0];
fixers.push({
range: [attr.range[0], attr.range[1]],
range: [attr.range[0], attrrangeEnd],
text: sortedAttrText,

@@ -213,3 +277,3 @@ });

};
};
}

@@ -343,11 +407,13 @@ /**

const reservedFirstError = validateReservedFirstConfig(context, reservedFirst);
let reservedList = Array.isArray(reservedFirst) ? reservedFirst : RESERVED_PROPS_LIST;
const reservedList = Array.isArray(reservedFirst) ? reservedFirst : RESERVED_PROPS_LIST;
const locale = configuration.locale || 'auto';
return {
Program() {
attributeMap = new WeakMap();
},
JSXOpeningElement(node) {
// `dangerouslySetInnerHTML` is only "reserved" on DOM components
if (reservedFirst && !jsxUtil.isDOMComponent(node)) {
reservedList = reservedList.filter((prop) => prop !== 'dangerouslySetInnerHTML');
}
const nodeReservedList = reservedFirst && !jsxUtil.isDOMComponent(node) ? reservedList.filter((prop) => prop !== 'dangerouslySetInnerHTML') : reservedList;

@@ -365,4 +431,2 @@ node.attributes.reduce((memo, decl, idx, attrs) => {

const currentIsCallback = isCallbackPropName(currentPropName);
const previousIsMultiline = isMultilineProp(memo);
const currentIsMultiline = isMultilineProp(decl);

@@ -380,4 +444,4 @@ if (ignoreCase) {

const previousIsReserved = isReservedPropName(previousPropName, reservedList);
const currentIsReserved = isReservedPropName(currentPropName, reservedList);
const previousIsReserved = isReservedPropName(previousPropName, nodeReservedList);
const currentIsReserved = isReservedPropName(currentPropName, nodeReservedList);

@@ -388,3 +452,3 @@ if (previousIsReserved && !currentIsReserved) {

if (!previousIsReserved && currentIsReserved) {
reportNodeAttribute(decl, 'listReservedPropsFirst', node, context, reservedList);
reportNodeAttribute(decl, 'listReservedPropsFirst', node, context, nodeReservedList);

@@ -402,3 +466,3 @@ return memo;

// Encountered a non-callback prop after a callback prop
reportNodeAttribute(memo, 'listCallbacksLast', node, context, reservedList);
reportNodeAttribute(memo, 'listCallbacksLast', node, context, nodeReservedList);

@@ -414,3 +478,3 @@ return memo;

if (!currentValue && previousValue) {
reportNodeAttribute(decl, 'listShorthandFirst', node, context, reservedList);
reportNodeAttribute(decl, 'listShorthandFirst', node, context, nodeReservedList);

@@ -426,3 +490,3 @@ return memo;

if (currentValue && !previousValue) {
reportNodeAttribute(memo, 'listShorthandLast', node, context, reservedList);
reportNodeAttribute(memo, 'listShorthandLast', node, context, nodeReservedList);

@@ -433,2 +497,4 @@ return memo;

const previousIsMultiline = isMultilineProp(memo);
const currentIsMultiline = isMultilineProp(decl);
if (multiline === 'first') {

@@ -441,9 +507,7 @@ if (previousIsMultiline && !currentIsMultiline) {

// Encountered a non-multiline prop before a multiline prop
reportNodeAttribute(decl, 'listMultilineFirst', node, context, reservedList);
reportNodeAttribute(decl, 'listMultilineFirst', node, context, nodeReservedList);
return memo;
}
}
if (multiline === 'last') {
} else if (multiline === 'last') {
if (!previousIsMultiline && currentIsMultiline) {

@@ -455,3 +519,3 @@ // Entering the multiline prop section

// Encountered a non-multiline prop after a multiline prop
reportNodeAttribute(memo, 'listMultilineLast', node, context, reservedList);
reportNodeAttribute(memo, 'listMultilineLast', node, context, nodeReservedList);

@@ -470,3 +534,3 @@ return memo;

) {
reportNodeAttribute(decl, 'sortPropsByAlpha', node, context, reservedList);
reportNodeAttribute(decl, 'sortPropsByAlpha', node, context, nodeReservedList);

@@ -473,0 +537,0 @@ return memo;

@@ -29,3 +29,3 @@ /**

docs: {
description: 'Validate spacing before closing bracket in JSX',
description: 'Enforce spacing before closing bracket in JSX',
category: 'Stylistic Issues',

@@ -32,0 +32,0 @@ recommended: false,

@@ -261,3 +261,3 @@ /**

docs: {
description: 'Validate whitespace in and around the JSX opening and closing brackets',
description: 'Enforce whitespace in and around the JSX opening and closing brackets',
category: 'Stylistic Issues',

@@ -264,0 +264,0 @@ recommended: false,

@@ -16,5 +16,6 @@ /**

module.exports = {
// eslint-disable-next-line eslint-plugin/prefer-message-ids -- https://github.com/not-an-aardvark/eslint-plugin-eslint-plugin/issues/292
meta: {
docs: {
description: 'Prevent React to be marked as unused',
description: 'Disallow React to be incorrectly marked as unused',
category: 'Best Practices',

@@ -21,0 +22,0 @@ recommended: true,

@@ -18,5 +18,6 @@ /**

module.exports = {
// eslint-disable-next-line eslint-plugin/prefer-message-ids -- https://github.com/not-an-aardvark/eslint-plugin-eslint-plugin/issues/292
meta: {
docs: {
description: 'Prevent variables used in JSX to be marked as unused',
description: 'Disallow variables used in JSX to be incorrectly marked as unused',
category: 'Best Practices',

@@ -23,0 +24,0 @@ recommended: true,

@@ -40,3 +40,3 @@ /**

docs: {
description: 'Prevent missing parentheses around multilines JSX',
description: 'Disallow missing parentheses around multiline JSX',
category: 'Stylistic Issues',

@@ -43,0 +43,0 @@ recommended: false,

@@ -23,3 +23,3 @@ /**

docs: {
description: 'Reports when this.state is accessed within setState',
description: 'Disallow when this.state is accessed within setState',
category: 'Possible Errors',

@@ -134,3 +134,3 @@ recommended: false,

// Storing all variables containg this.state
// Storing all variables containing this.state
if (current.type === 'VariableDeclarator') {

@@ -137,0 +137,0 @@ vars.push({

@@ -82,3 +82,3 @@ /**

docs: {
description: 'Prevent adjacent inline elements not separated by whitespace.',
description: 'Disallow adjacent inline elements not separated by whitespace.',
category: 'Best Practices',

@@ -85,0 +85,0 @@ recommended: false,

@@ -47,3 +47,3 @@ /**

docs: {
description: 'Prevent usage of Array index in keys',
description: 'Disallow usage of Array index in keys',
category: 'Best Practices',

@@ -50,0 +50,0 @@ recommended: false,

@@ -43,3 +43,3 @@ /**

docs: {
description: 'Prevent passing of children as props.',
description: 'Disallow passing of children as props',
category: 'Best Practices',

@@ -46,0 +46,0 @@ recommended: true,

@@ -23,3 +23,3 @@ /**

docs: {
description: 'Report when a DOM element is using both children and dangerouslySetInnerHTML',
description: 'Disallow when a DOM element is using both children and dangerouslySetInnerHTML',
category: 'Possible Errors',

@@ -26,0 +26,0 @@ recommended: true,

@@ -32,3 +32,3 @@ /**

* @param {String} name - Name of the attribute to check.
* @returns {boolean} Whether or not the attribute is dnagerous.
* @returns {boolean} Whether or not the attribute is dangerous.
*/

@@ -50,3 +50,3 @@ function isDangerous(name) {

docs: {
description: 'Prevent usage of dangerous JSX props',
description: 'Disallow usage of dangerous JSX properties',
category: 'Best Practices',

@@ -53,0 +53,0 @@ recommended: false,

@@ -95,3 +95,3 @@ /**

docs: {
description: 'Prevent usage of deprecated methods',
description: 'Disallow usage of deprecated methods',
category: 'Best Practices',

@@ -98,0 +98,0 @@ recommended: true,

@@ -25,3 +25,3 @@ /**

docs: {
description: 'Prevent direct mutation of this.state',
description: 'Disallow direct mutation of this.state',
category: 'Possible Errors',

@@ -60,3 +60,3 @@ recommended: true,

/**
* Walks throughs the MemberExpression to the top-most property.
* Walks through the MemberExpression to the top-most property.
* @param {Object} node The node to process

@@ -63,0 +63,0 @@ * @returns {Object} The outer-most MemberExpression

@@ -22,3 +22,3 @@ /**

docs: {
description: 'Prevent usage of findDOMNode',
description: 'Disallow usage of findDOMNode',
category: 'Best Practices',

@@ -25,0 +25,0 @@ recommended: true,

@@ -536,3 +536,3 @@ /**

docs: {
description: 'Forbid attribute with an invalid values`',
description: 'Disallow usage of invalid attributes',
category: 'Possible Errors',

@@ -539,0 +539,0 @@ url: docsUrl('no-invalid-html-attribute'),

@@ -22,3 +22,3 @@ /**

docs: {
description: 'Prevent usage of isMounted',
description: 'Disallow usage of isMounted',
category: 'Best Practices',

@@ -25,0 +25,0 @@ recommended: true,

@@ -23,3 +23,3 @@ /**

docs: {
description: 'Prevent multiple component definition per file',
description: 'Disallow multiple component definition per file',
category: 'Stylistic Issues',

@@ -26,0 +26,0 @@ recommended: false,

@@ -32,6 +32,3 @@ /**

schema: [{
type: 'object',
additionalProperties: false,
}],
schema: [],
},

@@ -38,0 +35,0 @@

@@ -23,3 +23,3 @@ /**

docs: {
description: 'Flag shouldComponentUpdate when extending PureComponent',
description: 'Disallow usage of shouldComponentUpdate when extending React.PureComponent',
category: 'Possible Errors',

@@ -26,0 +26,0 @@ recommended: false,

@@ -23,3 +23,3 @@ /**

docs: {
description: 'Prevent usage of the return value of React.render',
description: 'Disallow usage of the return value of ReactDOM.render',
category: 'Best Practices',

@@ -26,0 +26,0 @@ recommended: true,

@@ -23,3 +23,3 @@ /**

docs: {
description: 'Prevent usage of setState',
description: 'Disallow usage of setState',
category: 'Stylistic Issues',

@@ -26,0 +26,0 @@ recommended: false,

@@ -24,3 +24,3 @@ /**

docs: {
description: 'Prevent string definitions for references and prevent referencing this.refs',
description: 'Disallow using string references',
category: 'Best Practices',

@@ -27,0 +27,0 @@ recommended: true,

@@ -22,3 +22,3 @@ /**

docs: {
description: 'Report "this" being used in stateless components',
description: 'Disallow `this` from being used in stateless functional components',
category: 'Possible Errors',

@@ -25,0 +25,0 @@ recommended: false,

@@ -34,3 +34,3 @@ /**

docs: {
description: 'Prevent common typos',
description: 'Disallow common typos',
category: 'Stylistic Issues',

@@ -37,0 +37,0 @@ recommended: false,

@@ -41,3 +41,3 @@ /**

docs: {
description: 'Detect unescaped HTML entities, which might represent malformed tags',
description: 'Disallow unescaped HTML entities from appearing in markup',
category: 'Possible Errors',

@@ -85,3 +85,3 @@ recommended: true,

// HTML entites are already escaped in node.value (as well as node.raw),
// HTML entities are already escaped in node.value (as well as node.raw),
// so pull the raw text from context.getSourceCode()

@@ -88,0 +88,0 @@ for (let i = node.loc.start.line; i <= node.loc.end.line; i++) {

@@ -224,3 +224,3 @@ /**

docs: {
description: 'Prevent usage of unknown DOM property',
description: 'Disallow usage of unknown DOM property',
category: 'Possible Errors',

@@ -227,0 +227,0 @@ recommended: true,

@@ -25,3 +25,3 @@ /**

docs: {
description: 'Prevent usage of unsafe lifecycle methods',
description: 'Disallow usage of unsafe lifecycle methods',
category: 'Best Practices',

@@ -28,0 +28,0 @@ recommended: false,

@@ -271,3 +271,3 @@ /**

docs: {
description: 'Prevent creating unstable components inside components',
description: 'Disallow creating unstable components inside components',
category: 'Possible Errors',

@@ -436,3 +436,3 @@ recommended: false,

// Do not mark components declared inside hooks (or falsly '() => null' clean-up methods)
// Do not mark components declared inside hooks (or falsy '() => null' clean-up methods)
|| isReturnStatementOfHook(node, context)

@@ -446,3 +446,3 @@

// Prevent falsely reporting deteceted "components" which do not return JSX
// Prevent falsely reporting detected "components" which do not return JSX
|| isStatelessComponentReturningNull(node)

@@ -449,0 +449,0 @@ ) {

@@ -104,3 +104,3 @@ /**

docs: {
description: 'Prevent declaring unused methods of component class',
description: 'Disallow declaring unused methods of component class',
category: 'Best Practices',

@@ -111,8 +111,3 @@ recommended: false,

messages,
schema: [
{
type: 'object',
additionalProperties: false,
},
],
schema: [],
},

@@ -119,0 +114,0 @@

@@ -26,3 +26,3 @@ /**

docs: {
description: 'Prevent definitions of unused prop types',
description: 'Disallow definitions of unused propTypes',
category: 'Best Practices',

@@ -29,0 +29,0 @@ recommended: false,

@@ -83,3 +83,3 @@ /**

docs: {
description: 'Prevent definition of unused state fields',
description: 'Disallow definitions of unused state',
category: 'Best Practices',

@@ -86,0 +86,0 @@ recommended: false,

@@ -38,3 +38,3 @@ /**

docs: {
description: 'Require read-only props.',
description: 'Enforce that props are read-only',
category: 'Stylistic Issues',

@@ -41,0 +41,0 @@ recommended: false,

@@ -171,3 +171,3 @@ /**

* @param {Array} ctorParams - The params to check against super call.
* @returns {boolean} true if the construtor body is redundant
* @returns {boolean} true if the constructor body is redundant
*/

@@ -174,0 +174,0 @@ function isRedundantSuperCall(body, ctorParams) {

@@ -26,3 +26,3 @@ /**

docs: {
description: 'Prevent missing props validation in a React component definition',
description: 'Disallow missing props validation in a React component definition',
category: 'Best Practices',

@@ -29,0 +29,0 @@ recommended: true,

@@ -24,3 +24,3 @@ /**

docs: {
description: 'Prevent missing React when using JSX',
description: 'Disallow missing React when using JSX',
category: 'Possible Errors',

@@ -27,0 +27,0 @@ recommended: true,

@@ -30,3 +30,3 @@ /**

docs: {
description: 'Enforce a defaultProps definition for every prop that is not a required prop.',
description: 'Enforce a defaultProps definition for every prop that is not a required prop',
category: 'Best Practices',

@@ -129,2 +129,6 @@ url: docsUrl('require-default-props'),

if (!props) {
return;
}
if (props.type === 'Identifier') {

@@ -131,0 +135,0 @@ const hasOptionalProp = values(propTypes).some((propType) => !propType.isRequired);

@@ -25,3 +25,3 @@ /**

docs: {
description: 'Prevent extra closing tags for components without children',
description: 'Disallow extra closing tags for components without children',
category: 'Stylistic Issues',

@@ -28,0 +28,0 @@ recommended: false,

@@ -25,3 +25,3 @@ /**

docs: {
description: 'State initialization in an ES6 class component should be in a constructor',
description: 'Enforce class component state initialization style',
category: 'Stylistic Issues',

@@ -28,0 +28,0 @@ recommended: false,

@@ -61,3 +61,3 @@ /**

docs: {
description: 'Defines where React component static properties should be positioned.',
description: 'Enforces where React component static properties should be positioned.',
category: 'Stylistic Issues',

@@ -64,0 +64,0 @@ recommended: false,

@@ -53,3 +53,3 @@ /**

docs: {
description: 'Prevent passing of children to void DOM elements (e.g. `<br />`).',
description: 'Disallow void DOM elements (e.g. `<img />`, `<br />`) from receiving children',
category: 'Best Practices',

@@ -56,0 +56,0 @@ recommended: false,

@@ -47,3 +47,3 @@ /**

/**
* Find a return statment in the current node
* Find a return statement in the current node
*

@@ -50,0 +50,0 @@ * @param {ASTNode} node The AST node being checked

@@ -389,3 +389,3 @@ /**

/**
* It will check wheater memo/forwardRef is wrapping existing component or
* It will check whether memo/forwardRef is wrapping existing component or
* creating a new one.

@@ -507,3 +507,2 @@ * @param {object} node

&& !utils.isReturningJSX(node)
&& !utils.isReturningOnlyNull(node)
) {

@@ -513,2 +512,52 @@ return undefined;

// case: any = () => { return => null }
// case: any = () => null
if (node.parent.type === 'AssignmentExpression' && !isPropertyAssignment && utils.isReturningJSXOrNull(node)) {
if (isFirstLetterCapitalized(node.parent.left.name)) {
return node;
}
return undefined;
}
// case: any = () => () => null
if (node.parent.type === 'ArrowFunctionExpression' && node.parent.parent.type === 'AssignmentExpression' && !isPropertyAssignment && utils.isReturningJSXOrNull(node)) {
if (isFirstLetterCapitalized(node.parent.parent.left.name)) {
return node;
}
return undefined;
}
// case: { any: () => () => null }
if (node.parent.type === 'ArrowFunctionExpression' && node.parent.parent.type === 'Property' && !isPropertyAssignment && utils.isReturningJSXOrNull(node)) {
if (isFirstLetterCapitalized(node.parent.parent.key.name)) {
return node;
}
return undefined;
}
// case: any = function() {return function() {return null;};}
if (node.parent.type === 'ReturnStatement') {
if (isFirstLetterCapitalized(node.id && node.id.name)) {
return node;
}
const functionExpr = node.parent.parent.parent;
if (functionExpr.parent.type === 'AssignmentExpression' && !isPropertyAssignment && utils.isReturningJSXOrNull(node)) {
if (isFirstLetterCapitalized(functionExpr.parent.left.name)) {
return node;
}
return undefined;
}
}
// case: { any: function() {return function() {return null;};} }
if (node.parent.type === 'ReturnStatement') {
const functionExpr = node.parent.parent.parent;
if (functionExpr.parent.type === 'Property' && !isPropertyAssignment && utils.isReturningJSXOrNull(node)) {
if (isFirstLetterCapitalized(functionExpr.parent.key.name)) {
return node;
}
return undefined;
}
}
// for case abc = { [someobject.somekey]: props => { ... return not-jsx } }

@@ -515,0 +564,0 @@ if (node.parent && node.parent.key && node.parent.key.type === 'MemberExpression' && !utils.isReturningJSX(node) && !utils.isReturningOnlyNull(node)) {

@@ -9,3 +9,3 @@ 'use strict';

function isFirstLetterCapitalized(word) {
if (!word) {
if (!word || word.charAt(0) === '_') {
return false;

@@ -12,0 +12,0 @@ }

@@ -48,3 +48,3 @@ /**

docs: {
description: `Prevent usage of setState in ${methodName}`,
description: `Disallow usage of setState in ${methodName}`,
category: 'Best Practices',

@@ -51,0 +51,0 @@ recommended: false,

@@ -69,3 +69,3 @@ /**

* @param {Boolean=} requiredFirst whether or not to sort required elements first.
* @param {Boolean=} callbacksLast whether or not to sort callbacks after everyting else.
* @param {Boolean=} callbacksLast whether or not to sort callbacks after everything else.
* @returns {Number} the sort order of the two elements.

@@ -116,3 +116,3 @@ */

* @param {Boolean=} requiredFirst whether or not to sort required elements first.
* @param {Boolean=} callbacksLast whether or not to sort callbacks after everyting else.
* @param {Boolean=} callbacksLast whether or not to sort callbacks after everything else.
* @param {Boolean=} sortShapeProp whether or not to sort propTypes defined in PropTypes.shape.

@@ -119,0 +119,0 @@ * @returns {Object|*|{range, text}} the sort order of the two elements.

{
"name": "eslint-plugin-react",
"version": "7.30.1",
"version": "7.30.2",
"author": "Yannick Croissant <yannick.croissant+npm@gmail.com>",

@@ -9,2 +9,4 @@ "description": "React specific linting rules for ESLint",

"prepack": "npmignore --auto --commentLines=autogenerated",
"prelint": "npm run lint:docs",
"lint:docs": "markdownlint \"**/*.md\"",
"lint": "eslint .",

@@ -43,11 +45,12 @@ "postlint": "npm run type-check",

"devDependencies": {
"@babel/core": "^7.18.5",
"@babel/eslint-parser": "^7.18.2",
"@babel/plugin-syntax-decorators": "^7.17.12",
"@babel/plugin-syntax-do-expressions": "^7.16.7",
"@babel/plugin-syntax-function-bind": "^7.16.7",
"@babel/preset-react": "^7.17.12",
"@babel/core": "^7.18.13",
"@babel/eslint-parser": "^7.18.9",
"@babel/plugin-syntax-decorators": "^7.18.6",
"@babel/plugin-syntax-do-expressions": "^7.18.6",
"@babel/plugin-syntax-function-bind": "^7.18.6",
"@babel/preset-react": "^7.18.6",
"@technote-space/doctoc": "~2.4",
"@types/eslint": "=7.2.10",
"@types/estree": "0.0.51",
"@types/node": "^16.11.35",
"@types/estree": "0.0.52",
"@types/node": "^4.9.5",
"@typescript-eslint/parser": "^2.34.0 || ^3.10.1 || ^4.0.0 || ^5.0.0",

@@ -58,5 +61,5 @@ "aud": "^2.0.0",

"eslint-config-airbnb-base": "^15.0.0",
"eslint-plugin-eslint-plugin": "^2.3.0 || ^3.5.3 || ^4.0.1",
"eslint-plugin-eslint-plugin": "^2.3.0 || ^3.5.3 || ^4.0.1 || ^5.0.5",
"eslint-plugin-import": "^2.26.0",
"eslint-remote-tester": "^2.1.4",
"eslint-remote-tester": "^3.0.0",
"eslint-remote-tester-repositories": "^0.0.6",

@@ -68,2 +71,3 @@ "eslint-scope": "^3.7.3",

"markdown-magic": "^2.6.0",
"markdownlint-cli": "^0.8.0 || ^0.32.2",
"mocha": "^5.2.0",

@@ -70,0 +74,0 @@ "npmignore": "^0.3.0",

@@ -1,12 +0,16 @@

`eslint-plugin-react`
# `eslint-plugin-react` <sup>[![Version Badge][npm-version-svg]][package-url]</sup>
===================
[![Maintenance Status][status-image]][status-url] [![NPM version][npm-image]][npm-url] [![Dependency Status][deps-image]][deps-url] [![Code Climate][climate-image]][climate-url] [![Tidelift][tidelift-image]][tidelift-url]
[![github actions][actions-image]][actions-url]
[![Maintenance Status][status-image]][status-url]
[![NPM version][npm-image]][npm-url]
[![Tidelift][tidelift-image]][tidelift-url]
React specific linting rules for `eslint`
# Installation
## Installation
```sh
$ npm install eslint eslint-plugin-react --save-dev
npm install eslint eslint-plugin-react --save-dev
```

@@ -16,5 +20,4 @@

# Configuration
## Configuration
Use [our preset](#recommended) to get reasonable defaults:

@@ -110,118 +113,119 @@

# List of supported rules
## List of supported rules
✔: Enabled in the [`recommended`](#recommended) configuration.\
🔧: Fixable with [`eslint --fix`](https://eslint.org/docs/user-guide/command-line-interface#fixing-problems).
🔧: Fixable with [`eslint --fix`](https://eslint.org/docs/user-guide/command-line-interface#fixing-problems).\
💡: Provides editor [suggestions](https://eslint.org/docs/developer-guide/working-with-rules#providing-suggestions).
<!-- AUTO-GENERATED-CONTENT:START (BASIC_RULES) -->
| ✔ | 🔧 | Rule | Description |
| :---: | :---: | :--- | :--- |
| | | [react/boolean-prop-naming](docs/rules/boolean-prop-naming.md) | Enforces consistent naming for boolean props |
| | | [react/button-has-type](docs/rules/button-has-type.md) | Forbid "button" element without an explicit "type" attribute |
| | | [react/default-props-match-prop-types](docs/rules/default-props-match-prop-types.md) | Enforce all defaultProps are defined and not "required" in propTypes. |
| | 🔧 | [react/destructuring-assignment](docs/rules/destructuring-assignment.md) | Enforce consistent usage of destructuring assignment of props, state, and context |
| ✔ | | [react/display-name](docs/rules/display-name.md) | Prevent missing displayName in a React component definition |
| | | [react/forbid-component-props](docs/rules/forbid-component-props.md) | Forbid certain props on components |
| | | [react/forbid-dom-props](docs/rules/forbid-dom-props.md) | Forbid certain props on DOM Nodes |
| | | [react/forbid-elements](docs/rules/forbid-elements.md) | Forbid certain elements |
| | | [react/forbid-foreign-prop-types](docs/rules/forbid-foreign-prop-types.md) | Forbid using another component's propTypes |
| | | [react/forbid-prop-types](docs/rules/forbid-prop-types.md) | Forbid certain propTypes |
| | 🔧 | [react/function-component-definition](docs/rules/function-component-definition.md) | Standardize the way function component get defined |
| | | [react/hook-use-state](docs/rules/hook-use-state.md) | Ensure symmetric naming of useState hook value and setter variables |
| | | [react/iframe-missing-sandbox](docs/rules/iframe-missing-sandbox.md) | Enforce sandbox attribute on iframe elements |
| | | [react/no-access-state-in-setstate](docs/rules/no-access-state-in-setstate.md) | Reports when this.state is accessed within setState |
| | | [react/no-adjacent-inline-elements](docs/rules/no-adjacent-inline-elements.md) | Prevent adjacent inline elements not separated by whitespace. |
| | | [react/no-array-index-key](docs/rules/no-array-index-key.md) | Prevent usage of Array index in keys |
| | 🔧 | [react/no-arrow-function-lifecycle](docs/rules/no-arrow-function-lifecycle.md) | Lifecycle methods should be methods on the prototype, not class fields |
| ✔ | | [react/no-children-prop](docs/rules/no-children-prop.md) | Prevent passing of children as props. |
| | | [react/no-danger](docs/rules/no-danger.md) | Prevent usage of dangerous JSX props |
| ✔ | | [react/no-danger-with-children](docs/rules/no-danger-with-children.md) | Report when a DOM element is using both children and dangerouslySetInnerHTML |
| ✔ | | [react/no-deprecated](docs/rules/no-deprecated.md) | Prevent usage of deprecated methods |
| | | [react/no-did-mount-set-state](docs/rules/no-did-mount-set-state.md) | Prevent usage of setState in componentDidMount |
| | | [react/no-did-update-set-state](docs/rules/no-did-update-set-state.md) | Prevent usage of setState in componentDidUpdate |
| ✔ | | [react/no-direct-mutation-state](docs/rules/no-direct-mutation-state.md) | Prevent direct mutation of this.state |
| ✔ | | [react/no-find-dom-node](docs/rules/no-find-dom-node.md) | Prevent usage of findDOMNode |
| | 🔧 | [react/no-invalid-html-attribute](docs/rules/no-invalid-html-attribute.md) | Forbid attribute with an invalid values` |
| ✔ | | [react/no-is-mounted](docs/rules/no-is-mounted.md) | Prevent usage of isMounted |
| | | [react/no-multi-comp](docs/rules/no-multi-comp.md) | Prevent multiple component definition per file |
| | | [react/no-namespace](docs/rules/no-namespace.md) | Enforce that namespaces are not used in React elements |
| | | [react/no-redundant-should-component-update](docs/rules/no-redundant-should-component-update.md) | Flag shouldComponentUpdate when extending PureComponent |
| ✔ | | [react/no-render-return-value](docs/rules/no-render-return-value.md) | Prevent usage of the return value of React.render |
| | | [react/no-set-state](docs/rules/no-set-state.md) | Prevent usage of setState |
| ✔ | | [react/no-string-refs](docs/rules/no-string-refs.md) | Prevent string definitions for references and prevent referencing this.refs |
| | | [react/no-this-in-sfc](docs/rules/no-this-in-sfc.md) | Report "this" being used in stateless components |
| | | [react/no-typos](docs/rules/no-typos.md) | Prevent common typos |
| ✔ | | [react/no-unescaped-entities](docs/rules/no-unescaped-entities.md) | Detect unescaped HTML entities, which might represent malformed tags |
| ✔ | 🔧 | [react/no-unknown-property](docs/rules/no-unknown-property.md) | Prevent usage of unknown DOM property |
| | | [react/no-unsafe](docs/rules/no-unsafe.md) | Prevent usage of unsafe lifecycle methods |
| | | [react/no-unstable-nested-components](docs/rules/no-unstable-nested-components.md) | Prevent creating unstable components inside components |
| | | [react/no-unused-class-component-methods](docs/rules/no-unused-class-component-methods.md) | Prevent declaring unused methods of component class |
| | | [react/no-unused-prop-types](docs/rules/no-unused-prop-types.md) | Prevent definitions of unused prop types |
| | | [react/no-unused-state](docs/rules/no-unused-state.md) | Prevent definition of unused state fields |
| | | [react/no-will-update-set-state](docs/rules/no-will-update-set-state.md) | Prevent usage of setState in componentWillUpdate |
| | | [react/prefer-es6-class](docs/rules/prefer-es6-class.md) | Enforce ES5 or ES6 class for React Components |
| | | [react/prefer-exact-props](docs/rules/prefer-exact-props.md) | Prefer exact proptype definitions |
| | 🔧 | [react/prefer-read-only-props](docs/rules/prefer-read-only-props.md) | Require read-only props. |
| | | [react/prefer-stateless-function](docs/rules/prefer-stateless-function.md) | Enforce stateless components to be written as a pure function |
| ✔ | | [react/prop-types](docs/rules/prop-types.md) | Prevent missing props validation in a React component definition |
| ✔ | | [react/react-in-jsx-scope](docs/rules/react-in-jsx-scope.md) | Prevent missing React when using JSX |
| | | [react/require-default-props](docs/rules/require-default-props.md) | Enforce a defaultProps definition for every prop that is not a required prop. |
| | | [react/require-optimization](docs/rules/require-optimization.md) | Enforce React components to have a shouldComponentUpdate method |
| ✔ | | [react/require-render-return](docs/rules/require-render-return.md) | Enforce ES5 or ES6 class for returning value in render function |
| | 🔧 | [react/self-closing-comp](docs/rules/self-closing-comp.md) | Prevent extra closing tags for components without children |
| | | [react/sort-comp](docs/rules/sort-comp.md) | Enforce component methods order |
| | | [react/sort-prop-types](docs/rules/sort-prop-types.md) | Enforce propTypes declarations alphabetical sorting |
| | | [react/state-in-constructor](docs/rules/state-in-constructor.md) | State initialization in an ES6 class component should be in a constructor |
| | | [react/static-property-placement](docs/rules/static-property-placement.md) | Defines where React component static properties should be positioned. |
| | | [react/style-prop-object](docs/rules/style-prop-object.md) | Enforce style prop value is an object |
| | | [react/void-dom-elements-no-children](docs/rules/void-dom-elements-no-children.md) | Prevent passing of children to void DOM elements (e.g. `<br />`). |
| ✔ | 🔧 | 💡 | Rule | Description |
| :---: | :---: | :---: | :--- | :--- |
| | | | [react/boolean-prop-naming](docs/rules/boolean-prop-naming.md) | Enforces consistent naming for boolean props |
| | | | [react/button-has-type](docs/rules/button-has-type.md) | Disallow usage of `button` elements without an explicit `type` attribute |
| | | | [react/default-props-match-prop-types](docs/rules/default-props-match-prop-types.md) | Enforce all defaultProps have a corresponding non-required PropType |
| | 🔧 | | [react/destructuring-assignment](docs/rules/destructuring-assignment.md) | Enforce consistent usage of destructuring assignment of props, state, and context |
| ✔ | | | [react/display-name](docs/rules/display-name.md) | Disallow missing displayName in a React component definition |
| | | | [react/forbid-component-props](docs/rules/forbid-component-props.md) | Disallow certain props on components |
| | | | [react/forbid-dom-props](docs/rules/forbid-dom-props.md) | Disallow certain props on DOM Nodes |
| | | | [react/forbid-elements](docs/rules/forbid-elements.md) | Disallow certain elements |
| | | | [react/forbid-foreign-prop-types](docs/rules/forbid-foreign-prop-types.md) | Disallow using another component's propTypes |
| | | | [react/forbid-prop-types](docs/rules/forbid-prop-types.md) | Disallow certain propTypes |
| | 🔧 | | [react/function-component-definition](docs/rules/function-component-definition.md) | Enforce a specific function type for function components |
| | | 💡 | [react/hook-use-state](docs/rules/hook-use-state.md) | Ensure destructuring and symmetric naming of useState hook value and setter variables |
| | | | [react/iframe-missing-sandbox](docs/rules/iframe-missing-sandbox.md) | Enforce sandbox attribute on iframe elements |
| | | | [react/no-access-state-in-setstate](docs/rules/no-access-state-in-setstate.md) | Disallow when this.state is accessed within setState |
| | | | [react/no-adjacent-inline-elements](docs/rules/no-adjacent-inline-elements.md) | Disallow adjacent inline elements not separated by whitespace. |
| | | | [react/no-array-index-key](docs/rules/no-array-index-key.md) | Disallow usage of Array index in keys |
| | 🔧 | | [react/no-arrow-function-lifecycle](docs/rules/no-arrow-function-lifecycle.md) | Lifecycle methods should be methods on the prototype, not class fields |
| ✔ | | | [react/no-children-prop](docs/rules/no-children-prop.md) | Disallow passing of children as props |
| | | | [react/no-danger](docs/rules/no-danger.md) | Disallow usage of dangerous JSX properties |
| ✔ | | | [react/no-danger-with-children](docs/rules/no-danger-with-children.md) | Disallow when a DOM element is using both children and dangerouslySetInnerHTML |
| ✔ | | | [react/no-deprecated](docs/rules/no-deprecated.md) | Disallow usage of deprecated methods |
| | | | [react/no-did-mount-set-state](docs/rules/no-did-mount-set-state.md) | Disallow usage of setState in componentDidMount |
| | | | [react/no-did-update-set-state](docs/rules/no-did-update-set-state.md) | Disallow usage of setState in componentDidUpdate |
| ✔ | | | [react/no-direct-mutation-state](docs/rules/no-direct-mutation-state.md) | Disallow direct mutation of this.state |
| ✔ | | | [react/no-find-dom-node](docs/rules/no-find-dom-node.md) | Disallow usage of findDOMNode |
| | 🔧 | | [react/no-invalid-html-attribute](docs/rules/no-invalid-html-attribute.md) | Disallow usage of invalid attributes |
| ✔ | | | [react/no-is-mounted](docs/rules/no-is-mounted.md) | Disallow usage of isMounted |
| | | | [react/no-multi-comp](docs/rules/no-multi-comp.md) | Disallow multiple component definition per file |
| | | | [react/no-namespace](docs/rules/no-namespace.md) | Enforce that namespaces are not used in React elements |
| | | | [react/no-redundant-should-component-update](docs/rules/no-redundant-should-component-update.md) | Disallow usage of shouldComponentUpdate when extending React.PureComponent |
| ✔ | | | [react/no-render-return-value](docs/rules/no-render-return-value.md) | Disallow usage of the return value of ReactDOM.render |
| | | | [react/no-set-state](docs/rules/no-set-state.md) | Disallow usage of setState |
| ✔ | | | [react/no-string-refs](docs/rules/no-string-refs.md) | Disallow using string references |
| | | | [react/no-this-in-sfc](docs/rules/no-this-in-sfc.md) | Disallow `this` from being used in stateless functional components |
| | | | [react/no-typos](docs/rules/no-typos.md) | Disallow common typos |
| ✔ | | | [react/no-unescaped-entities](docs/rules/no-unescaped-entities.md) | Disallow unescaped HTML entities from appearing in markup |
| ✔ | 🔧 | | [react/no-unknown-property](docs/rules/no-unknown-property.md) | Disallow usage of unknown DOM property |
| | | | [react/no-unsafe](docs/rules/no-unsafe.md) | Disallow usage of unsafe lifecycle methods |
| | | | [react/no-unstable-nested-components](docs/rules/no-unstable-nested-components.md) | Disallow creating unstable components inside components |
| | | | [react/no-unused-class-component-methods](docs/rules/no-unused-class-component-methods.md) | Disallow declaring unused methods of component class |
| | | | [react/no-unused-prop-types](docs/rules/no-unused-prop-types.md) | Disallow definitions of unused propTypes |
| | | | [react/no-unused-state](docs/rules/no-unused-state.md) | Disallow definitions of unused state |
| | | | [react/no-will-update-set-state](docs/rules/no-will-update-set-state.md) | Disallow usage of setState in componentWillUpdate |
| | | | [react/prefer-es6-class](docs/rules/prefer-es6-class.md) | Enforce ES5 or ES6 class for React Components |
| | | | [react/prefer-exact-props](docs/rules/prefer-exact-props.md) | Prefer exact proptype definitions |
| | 🔧 | | [react/prefer-read-only-props](docs/rules/prefer-read-only-props.md) | Enforce that props are read-only |
| | | | [react/prefer-stateless-function](docs/rules/prefer-stateless-function.md) | Enforce stateless components to be written as a pure function |
| ✔ | | | [react/prop-types](docs/rules/prop-types.md) | Disallow missing props validation in a React component definition |
| ✔ | | | [react/react-in-jsx-scope](docs/rules/react-in-jsx-scope.md) | Disallow missing React when using JSX |
| | | | [react/require-default-props](docs/rules/require-default-props.md) | Enforce a defaultProps definition for every prop that is not a required prop |
| | | | [react/require-optimization](docs/rules/require-optimization.md) | Enforce React components to have a shouldComponentUpdate method |
| ✔ | | | [react/require-render-return](docs/rules/require-render-return.md) | Enforce ES5 or ES6 class for returning value in render function |
| | 🔧 | | [react/self-closing-comp](docs/rules/self-closing-comp.md) | Disallow extra closing tags for components without children |
| | | | [react/sort-comp](docs/rules/sort-comp.md) | Enforce component methods order |
| | | | [react/sort-prop-types](docs/rules/sort-prop-types.md) | Enforce propTypes declarations alphabetical sorting |
| | | | [react/state-in-constructor](docs/rules/state-in-constructor.md) | Enforce class component state initialization style |
| | | | [react/static-property-placement](docs/rules/static-property-placement.md) | Enforces where React component static properties should be positioned. |
| | | | [react/style-prop-object](docs/rules/style-prop-object.md) | Enforce style prop value is an object |
| | | | [react/void-dom-elements-no-children](docs/rules/void-dom-elements-no-children.md) | Disallow void DOM elements (e.g. `<img />`, `<br />`) from receiving children |
<!-- AUTO-GENERATED-CONTENT:END -->
## JSX-specific rules
### JSX-specific rules
<!-- AUTO-GENERATED-CONTENT:START (JSX_RULES) -->
| ✔ | 🔧 | Rule | Description |
| :---: | :---: | :--- | :--- |
| | 🔧 | [react/jsx-boolean-value](docs/rules/jsx-boolean-value.md) | Enforce boolean attributes notation in JSX |
| | | [react/jsx-child-element-spacing](docs/rules/jsx-child-element-spacing.md) | Ensures inline tags are not rendered without spaces between them |
| | 🔧 | [react/jsx-closing-bracket-location](docs/rules/jsx-closing-bracket-location.md) | Validate closing bracket location in JSX |
| | 🔧 | [react/jsx-closing-tag-location](docs/rules/jsx-closing-tag-location.md) | Validate closing tag location for multiline JSX |
| | 🔧 | [react/jsx-curly-brace-presence](docs/rules/jsx-curly-brace-presence.md) | Disallow unnecessary JSX expressions when literals alone are sufficient or enfore JSX expressions on literals in JSX children or attributes |
| | 🔧 | [react/jsx-curly-newline](docs/rules/jsx-curly-newline.md) | Enforce consistent line breaks inside jsx curly |
| | 🔧 | [react/jsx-curly-spacing](docs/rules/jsx-curly-spacing.md) | Enforce or disallow spaces inside of curly braces in JSX attributes |
| | 🔧 | [react/jsx-equals-spacing](docs/rules/jsx-equals-spacing.md) | Disallow or enforce spaces around equal signs in JSX attributes |
| | | [react/jsx-filename-extension](docs/rules/jsx-filename-extension.md) | Restrict file extensions that may contain JSX |
| | 🔧 | [react/jsx-first-prop-new-line](docs/rules/jsx-first-prop-new-line.md) | Ensure proper position of the first property in JSX |
| | 🔧 | [react/jsx-fragments](docs/rules/jsx-fragments.md) | Enforce shorthand or standard form for React fragments |
| | | [react/jsx-handler-names](docs/rules/jsx-handler-names.md) | Enforce event handler naming conventions in JSX |
| | 🔧 | [react/jsx-indent](docs/rules/jsx-indent.md) | Validate JSX indentation |
| | 🔧 | [react/jsx-indent-props](docs/rules/jsx-indent-props.md) | Validate props indentation in JSX |
| ✔ | | [react/jsx-key](docs/rules/jsx-key.md) | Report missing `key` props in iterators/collection literals |
| | | [react/jsx-max-depth](docs/rules/jsx-max-depth.md) | Validate JSX maximum depth |
| | 🔧 | [react/jsx-max-props-per-line](docs/rules/jsx-max-props-per-line.md) | Limit maximum of props on a single line in JSX |
| | 🔧 | [react/jsx-newline](docs/rules/jsx-newline.md) | Require or prevent a new line after jsx elements and expressions. |
| | | [react/jsx-no-bind](docs/rules/jsx-no-bind.md) | Prevents usage of Function.prototype.bind and arrow functions in React component props |
| ✔ | | [react/jsx-no-comment-textnodes](docs/rules/jsx-no-comment-textnodes.md) | Comments inside children section of tag should be placed inside braces |
| | | [react/jsx-no-constructed-context-values](docs/rules/jsx-no-constructed-context-values.md) | Prevents JSX context provider values from taking values that will cause needless rerenders. |
| ✔ | | [react/jsx-no-duplicate-props](docs/rules/jsx-no-duplicate-props.md) | Enforce no duplicate props |
| | 🔧 | [react/jsx-no-leaked-render](docs/rules/jsx-no-leaked-render.md) | Prevent problematic leaked values from being rendered |
| | | [react/jsx-no-literals](docs/rules/jsx-no-literals.md) | Prevent using string literals in React component definition |
| | | [react/jsx-no-script-url](docs/rules/jsx-no-script-url.md) | Forbid `javascript:` URLs |
| ✔ | 🔧 | [react/jsx-no-target-blank](docs/rules/jsx-no-target-blank.md) | Forbid `target="_blank"` attribute without `rel="noreferrer"` |
| ✔ | | [react/jsx-no-undef](docs/rules/jsx-no-undef.md) | Disallow undeclared variables in JSX |
| | 🔧 | [react/jsx-no-useless-fragment](docs/rules/jsx-no-useless-fragment.md) | Disallow unnecessary fragments |
| | 🔧 | [react/jsx-one-expression-per-line](docs/rules/jsx-one-expression-per-line.md) | Limit to one expression per line in JSX |
| | | [react/jsx-pascal-case](docs/rules/jsx-pascal-case.md) | Enforce PascalCase for user-defined JSX components |
| | 🔧 | [react/jsx-props-no-multi-spaces](docs/rules/jsx-props-no-multi-spaces.md) | Disallow multiple spaces between inline JSX props |
| | | [react/jsx-props-no-spreading](docs/rules/jsx-props-no-spreading.md) | Prevent JSX prop spreading |
| | | [react/jsx-sort-default-props](docs/rules/jsx-sort-default-props.md) | Enforce default props alphabetical sorting |
| | 🔧 | [react/jsx-sort-props](docs/rules/jsx-sort-props.md) | Enforce props alphabetical sorting |
| | 🔧 | [react/jsx-space-before-closing](docs/rules/jsx-space-before-closing.md) | Validate spacing before closing bracket in JSX |
| | 🔧 | [react/jsx-tag-spacing](docs/rules/jsx-tag-spacing.md) | Validate whitespace in and around the JSX opening and closing brackets |
| ✔ | | [react/jsx-uses-react](docs/rules/jsx-uses-react.md) | Prevent React to be marked as unused |
| ✔ | | [react/jsx-uses-vars](docs/rules/jsx-uses-vars.md) | Prevent variables used in JSX to be marked as unused |
| | 🔧 | [react/jsx-wrap-multilines](docs/rules/jsx-wrap-multilines.md) | Prevent missing parentheses around multilines JSX |
| ✔ | 🔧 | 💡 | Rule | Description |
| :---: | :---: | :---: | :--- | :--- |
| | 🔧 | | [react/jsx-boolean-value](docs/rules/jsx-boolean-value.md) | Enforce boolean attributes notation in JSX |
| | | | [react/jsx-child-element-spacing](docs/rules/jsx-child-element-spacing.md) | Enforce or disallow spaces inside of curly braces in JSX attributes and expressions |
| | 🔧 | | [react/jsx-closing-bracket-location](docs/rules/jsx-closing-bracket-location.md) | Enforce closing bracket location in JSX |
| | 🔧 | | [react/jsx-closing-tag-location](docs/rules/jsx-closing-tag-location.md) | Enforce closing tag location for multiline JSX |
| | 🔧 | | [react/jsx-curly-brace-presence](docs/rules/jsx-curly-brace-presence.md) | Disallow unnecessary JSX expressions when literals alone are sufficient or enforce JSX expressions on literals in JSX children or attributes |
| | 🔧 | | [react/jsx-curly-newline](docs/rules/jsx-curly-newline.md) | Enforce consistent linebreaks in curly braces in JSX attributes and expressions |
| | 🔧 | | [react/jsx-curly-spacing](docs/rules/jsx-curly-spacing.md) | Enforce or disallow spaces inside of curly braces in JSX attributes and expressions |
| | 🔧 | | [react/jsx-equals-spacing](docs/rules/jsx-equals-spacing.md) | Enforce or disallow spaces around equal signs in JSX attributes |
| | | | [react/jsx-filename-extension](docs/rules/jsx-filename-extension.md) | Disallow file extensions that may contain JSX |
| | 🔧 | | [react/jsx-first-prop-new-line](docs/rules/jsx-first-prop-new-line.md) | Enforce proper position of the first property in JSX |
| | 🔧 | | [react/jsx-fragments](docs/rules/jsx-fragments.md) | Enforce shorthand or standard form for React fragments |
| | | | [react/jsx-handler-names](docs/rules/jsx-handler-names.md) | Enforce event handler naming conventions in JSX |
| | 🔧 | | [react/jsx-indent](docs/rules/jsx-indent.md) | Enforce JSX indentation |
| | 🔧 | | [react/jsx-indent-props](docs/rules/jsx-indent-props.md) | Enforce props indentation in JSX |
| ✔ | | | [react/jsx-key](docs/rules/jsx-key.md) | Disallow missing `key` props in iterators/collection literals |
| | | | [react/jsx-max-depth](docs/rules/jsx-max-depth.md) | Enforce JSX maximum depth |
| | 🔧 | | [react/jsx-max-props-per-line](docs/rules/jsx-max-props-per-line.md) | Enforce maximum of props on a single line in JSX |
| | 🔧 | | [react/jsx-newline](docs/rules/jsx-newline.md) | Require or prevent a new line after jsx elements and expressions. |
| | | | [react/jsx-no-bind](docs/rules/jsx-no-bind.md) | Disallow `.bind()` or arrow functions in JSX props |
| ✔ | | | [react/jsx-no-comment-textnodes](docs/rules/jsx-no-comment-textnodes.md) | Disallow comments from being inserted as text nodes |
| | | | [react/jsx-no-constructed-context-values](docs/rules/jsx-no-constructed-context-values.md) | Disallows JSX context provider values from taking values that will cause needless rerenders |
| ✔ | | | [react/jsx-no-duplicate-props](docs/rules/jsx-no-duplicate-props.md) | Disallow duplicate properties in JSX |
| | 🔧 | | [react/jsx-no-leaked-render](docs/rules/jsx-no-leaked-render.md) | Disallow problematic leaked values from being rendered |
| | | | [react/jsx-no-literals](docs/rules/jsx-no-literals.md) | Disallow usage of string literals in JSX |
| | | | [react/jsx-no-script-url](docs/rules/jsx-no-script-url.md) | Disallow usage of `javascript:` URLs |
| ✔ | 🔧 | | [react/jsx-no-target-blank](docs/rules/jsx-no-target-blank.md) | Disallow `target="_blank"` attribute without `rel="noreferrer"` |
| ✔ | | | [react/jsx-no-undef](docs/rules/jsx-no-undef.md) | Disallow undeclared variables in JSX |
| | 🔧 | | [react/jsx-no-useless-fragment](docs/rules/jsx-no-useless-fragment.md) | Disallow unnecessary fragments |
| | 🔧 | | [react/jsx-one-expression-per-line](docs/rules/jsx-one-expression-per-line.md) | Require one JSX element per line |
| | | | [react/jsx-pascal-case](docs/rules/jsx-pascal-case.md) | Enforce PascalCase for user-defined JSX components |
| | 🔧 | | [react/jsx-props-no-multi-spaces](docs/rules/jsx-props-no-multi-spaces.md) | Disallow multiple spaces between inline JSX props |
| | | | [react/jsx-props-no-spreading](docs/rules/jsx-props-no-spreading.md) | Disallow JSX prop spreading |
| | | | [react/jsx-sort-default-props](docs/rules/jsx-sort-default-props.md) | Enforce defaultProps declarations alphabetical sorting |
| | 🔧 | | [react/jsx-sort-props](docs/rules/jsx-sort-props.md) | Enforce props alphabetical sorting |
| | 🔧 | | [react/jsx-space-before-closing](docs/rules/jsx-space-before-closing.md) | Enforce spacing before closing bracket in JSX. ❌ This rule is deprecated. |
| | 🔧 | | [react/jsx-tag-spacing](docs/rules/jsx-tag-spacing.md) | Enforce whitespace in and around the JSX opening and closing brackets |
| ✔ | | | [react/jsx-uses-react](docs/rules/jsx-uses-react.md) | Disallow React to be incorrectly marked as unused |
| ✔ | | | [react/jsx-uses-vars](docs/rules/jsx-uses-vars.md) | Disallow variables used in JSX to be incorrectly marked as unused |
| | 🔧 | | [react/jsx-wrap-multilines](docs/rules/jsx-wrap-multilines.md) | Disallow missing parentheses around multiline JSX |
<!-- AUTO-GENERATED-CONTENT:END -->
## Other useful plugins
### Other useful plugins

@@ -232,5 +236,5 @@ - Rules of Hooks: [eslint-plugin-react-hooks](https://github.com/facebook/react/tree/master/packages/eslint-plugin-react-hooks)

# Shareable configurations
## Shareable configurations
## Recommended
### Recommended

@@ -249,3 +253,3 @@ This plugin exports a `recommended` configuration that enforces React good practices.

## All
### All

@@ -266,16 +270,9 @@ This plugin also exports an `all` configuration that includes every available rule.

# License
## License
`eslint-plugin-react` is licensed under the [MIT License](https://opensource.org/licenses/mit-license.php).
[npm-url]: https://npmjs.org/package/eslint-plugin-react
[npm-image]: https://img.shields.io/npm/v/eslint-plugin-react.svg
[deps-url]: https://david-dm.org/jsx-eslint/eslint-plugin-react
[deps-image]: https://img.shields.io/david/dev/jsx-eslint/eslint-plugin-react.svg
[climate-url]: https://codeclimate.com/github/jsx-eslint/eslint-plugin-react
[climate-image]: https://img.shields.io/codeclimate/maintainability/jsx-eslint/eslint-plugin-react.svg
[status-url]: https://github.com/jsx-eslint/eslint-plugin-react/pulse

@@ -285,2 +282,8 @@ [status-image]: https://img.shields.io/github/last-commit/jsx-eslint/eslint-plugin-react.svg

[tidelift-url]: https://tidelift.com/subscription/pkg/npm-eslint-plugin-react?utm_source=npm-eslint-plugin-react&utm_medium=referral&utm_campaign=readme
[tidelift-image]: https://tidelift.com/badges/github/jsx-eslint/eslint-plugin-react?style=flat
[tidelift-image]: https://tidelift.com/badges/package/npm/eslint-plugin-react?style=flat
[package-url]: https://npmjs.org/package/eslint-plugin-react
[npm-version-svg]: https://versionbadg.es/jsx-eslint/eslint-plugin-react.svg
[actions-image]: https://img.shields.io/endpoint?url=https://github-actions-badge-u3jn4tfpocch.runkit.sh/jsx-eslint/eslint-plugin-react
[actions-url]: https://github.com/jsx-eslint/eslint-plugin-react/actions
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