diff --git a/CHANGELOG.md b/CHANGELOG.md
index e70c0cc101..b57162789e 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -13,10 +13,12 @@ This change log adheres to standards from [Keep a CHANGELOG](https://keepachange
### Fixed
* configs: avoid legacy config system error ([#3461][] @ljharb)
+* [`jsx-no-target-blank`]: allow ternaries with literals ([#3464][] @akulsr0)
### Changed
* [Perf] component detection: improve performance by avoiding traversing parents unnecessarily ([#3459][] @golopot)
+[#3464]: https://github.com/jsx-eslint/eslint-plugin-react/pull/3464
[#3461]: https://github.com/jsx-eslint/eslint-plugin-react/issues/3461
[#3459]: https://github.com/jsx-eslint/eslint-plugin-react/pull/3459
[#3449]: https://github.com/jsx-eslint/eslint-plugin-react/pull/3449
diff --git a/lib/rules/jsx-no-target-blank.js b/lib/rules/jsx-no-target-blank.js
index ca1eb7c7cb..9b77e37f4c 100644
--- a/lib/rules/jsx-no-target-blank.js
+++ b/lib/rules/jsx-no-target-blank.js
@@ -65,7 +65,13 @@ function hasDynamicLink(node, linkAttribute) {
}
}
-function getStringFromValue(value) {
+/**
+ * Get the string(s) from a value
+ * @param {ASTNode} value The AST node being checked.
+ * @param {ASTNode} targetValue The AST node being checked.
+ * @returns {String | String[] | null} The string value, or null if not a string.
+ */
+function getStringFromValue(value, targetValue) {
if (value) {
if (value.type === 'Literal') {
return value.value;
@@ -75,11 +81,19 @@ function getStringFromValue(value) {
return value.expression.quasis[0].value.cooked;
}
const expr = value.expression;
- return expr && (
- expr.type === 'ConditionalExpression'
- ? [expr.consequent.value, expr.alternate.value]
- : expr.value
- );
+ if (expr && expr.type === 'ConditionalExpression') {
+ const relValues = [expr.consequent.value, expr.alternate.value];
+ if (targetValue.type === 'JSXExpressionContainer' && targetValue.expression && targetValue.expression.type === 'ConditionalExpression') {
+ const targetTestCond = targetValue.expression.test.name;
+ const relTestCond = value.expression.test.name;
+ if (targetTestCond === relTestCond) {
+ const targetBlankIndex = [targetValue.expression.consequent.value, targetValue.expression.alternate.value].indexOf('_blank');
+ return relValues[targetBlankIndex];
+ }
+ }
+ return relValues;
+ }
+ return expr.value;
}
}
return null;
@@ -87,12 +101,14 @@ function getStringFromValue(value) {
function hasSecureRel(node, allowReferrer, warnOnSpreadAttributes, spreadAttributeIndex) {
const relIndex = findLastIndex(node.attributes, (attr) => (attr.type === 'JSXAttribute' && attr.name.name === 'rel'));
+ const targetIndex = findLastIndex(node.attributes, (attr) => (attr.type === 'JSXAttribute' && attr.name.name === 'target'));
if (relIndex === -1 || (warnOnSpreadAttributes && relIndex < spreadAttributeIndex)) {
return false;
}
const relAttribute = node.attributes[relIndex];
- const value = getStringFromValue(relAttribute.value);
+ const targetAttributeValue = node.attributes[targetIndex] && node.attributes[targetIndex].value;
+ const value = getStringFromValue(relAttribute.value, targetAttributeValue);
return [].concat(value).every((item) => {
const tags = typeof item === 'string' ? item.toLowerCase().split(' ') : false;
const noreferrer = tags && tags.indexOf('noreferrer') >= 0;
diff --git a/tests/lib/rules/jsx-no-target-blank.js b/tests/lib/rules/jsx-no-target-blank.js
index 2208e371dc..f5ab6b8793 100644
--- a/tests/lib/rules/jsx-no-target-blank.js
+++ b/tests/lib/rules/jsx-no-target-blank.js
@@ -155,6 +155,18 @@ ruleTester.run('jsx-no-target-blank', rule, {
code: '',
options: [{ allowReferrer: true }],
},
+ {
+ code: '',
+ },
+ {
+ code: '',
+ },
+ {
+ code: '',
+ },
+ {
+ code: '',
+ },
]),
invalid: parsers.all([
{
@@ -378,10 +390,6 @@ ruleTester.run('jsx-no-target-blank', rule, {
code: '',
errors: defaultErrors,
},
- {
- code: '',
- errors: defaultErrors,
- },
{
code: '',
errors: defaultErrors,