diff --git a/CHANGELOG.md b/CHANGELOG.md
index 01df9f267e..24105ccb97 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -19,6 +19,7 @@ This change log adheres to standards from [Keep a CHANGELOG](https://keepachange
* [`display-name`]: fix identifying `_` as a capital letter ([#3335][] @apbarrero)
* [`require-default-props`]: avoid a crash when function has no props param ([#3350][] @noahnu)
* [`display-name`], component detection: fix HOF returning null as Components ([#3347][] @jxm-math)
+* [`jsx-no-target-blank`]: False negative when rel attribute is assigned using ConditionalExpression ([#3332][] @V2dha)
### Changed
* [Refactor] [`jsx-indent-props`]: improved readability of the checkNodesIndent function ([#3315][] @caroline223)
@@ -35,6 +36,7 @@ This change log adheres to standards from [Keep a CHANGELOG](https://keepachange
[#3339]: https://github.com/jsx-eslint/eslint-plugin-react/pull/3339
[#3338]: https://github.com/jsx-eslint/eslint-plugin-react/pull/3338
[#3335]: https://github.com/jsx-eslint/eslint-plugin-react/pull/3335
+[#3332]: https://github.com/jsx-eslint/eslint-plugin-react/pull/3332
[#3331]: https://github.com/jsx-eslint/eslint-plugin-react/pull/3331
[#3328]: https://github.com/jsx-eslint/eslint-plugin-react/issues/3328
[#3327]: https://github.com/jsx-eslint/eslint-plugin-react/issues/3327
diff --git a/lib/rules/jsx-no-target-blank.js b/lib/rules/jsx-no-target-blank.js
index 1f6edc9e07..9e2861b406 100644
--- a/lib/rules/jsx-no-target-blank.js
+++ b/lib/rules/jsx-no-target-blank.js
@@ -65,6 +65,12 @@ function hasDynamicLink(node, linkAttribute) {
}
}
+function attributeValuePossiblyRel(value) {
+ if (typeof value === 'string') {
+ return true;
+ }
+}
+
function getStringFromValue(value) {
if (value) {
if (value.type === 'Literal') {
@@ -74,6 +80,15 @@ function getStringFromValue(value) {
if (value.expression.type === 'TemplateLiteral') {
return value.expression.quasis[0].value.cooked;
}
+ const expr = value.expression;
+ if (expr.type === 'ConditionalExpression') {
+ if (
+ attributeValuePossiblyRel(expr.consequent.value)
+ && attributeValuePossiblyRel(expr.alternate.value)
+ ) {
+ return [expr.consequent.value, expr.alternate.value];
+ }
+ }
return value.expression && value.expression.value;
}
}
@@ -88,12 +103,15 @@ function hasSecureRel(node, allowReferrer, warnOnSpreadAttributes, spreadAttribu
const relAttribute = node.attributes[relIndex];
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).filter(Boolean).every((item) => {
+ const tags = typeof item === 'string' && item.toLowerCase().split(' ');
+ const noreferrer = tags && tags.indexOf('noreferrer') >= 0;
+ const noopener = tags && tags.indexOf('noopener') >= 0;
+ if (noreferrer) {
+ return true;
+ }
+ return allowReferrer && noopener;
+ });
}
const messages = {
diff --git a/tests/lib/rules/jsx-no-target-blank.js b/tests/lib/rules/jsx-no-target-blank.js
index 27a63cb09d..2208e371dc 100644
--- a/tests/lib/rules/jsx-no-target-blank.js
+++ b/tests/lib/rules/jsx-no-target-blank.js
@@ -28,6 +28,7 @@ const parserOptions = {
const ruleTester = new RuleTester({ parserOptions });
const defaultErrors = [{ messageId: 'noTargetBlankWithoutNoreferrer' }];
+const allowReferrerErrors = [{ messageId: 'noTargetBlankWithoutNoopener' }];
ruleTester.run('jsx-no-target-blank', rule, {
valid: parsers.all([
@@ -141,6 +142,19 @@ ruleTester.run('jsx-no-target-blank', rule, {
{
code: '',
},
+ {
+ code: '',
+ },
+ {
+ code: '',
+ },
+ {
+ code: '',
+ },
+ {
+ code: '',
+ options: [{ allowReferrer: true }],
+ },
]),
invalid: parsers.all([
{
@@ -251,13 +265,13 @@ ruleTester.run('jsx-no-target-blank', rule, {
code: '',
output: '',
options: [{ allowReferrer: true }],
- errors: [{ messageId: 'noTargetBlankWithoutNoopener' }],
+ errors: allowReferrerErrors,
},
{
code: '',
output: '',
options: [{ allowReferrer: true }],
- errors: [{ messageId: 'noTargetBlankWithoutNoopener' }],
+ errors: allowReferrerErrors,
},
{
code: '',
@@ -352,5 +366,38 @@ ruleTester.run('jsx-no-target-blank', rule, {
options: [{ forms: true, links: false }],
errors: defaultErrors,
},
+ {
+ code: '',
+ errors: defaultErrors,
+ },
+ {
+ code: '',
+ errors: defaultErrors,
+ },
+ {
+ code: '',
+ errors: defaultErrors,
+ },
+ {
+ code: '',
+ errors: defaultErrors,
+ },
+ {
+ code: '',
+ errors: defaultErrors,
+ },
+ {
+ code: '',
+ errors: defaultErrors,
+ },
+ {
+ code: '',
+ errors: defaultErrors,
+ },
+ {
+ code: '',
+ options: [{ allowReferrer: true }],
+ errors: allowReferrerErrors,
+ },
]),
});