diff --git a/CHANGELOG.md b/CHANGELOG.md
index 4491394d8a..77b987055c 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -21,6 +21,7 @@ This change log adheres to standards from [Keep a CHANGELOG](https://keepachange
* [`display-name`], component detection: fix HOF returning null as Components ([#3347][] @jxm-math)
* [`forbid-prop-types`]: Ignore objects that are not of type React.PropTypes ([#3326][] @TildaDares)
* [`display-name`], component detection: fix false positive for HOF returning only nulls and literals ([#3305][] @golopot)
+* [`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)
@@ -39,6 +40,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..01dedf7207 100644
--- a/lib/rules/jsx-no-target-blank.js
+++ b/lib/rules/jsx-no-target-blank.js
@@ -74,7 +74,12 @@ function getStringFromValue(value) {
if (value.expression.type === 'TemplateLiteral') {
return value.expression.quasis[0].value.cooked;
}
- return value.expression && value.expression.value;
+ const expr = value.expression;
+ return expr && (
+ expr.type === 'ConditionalExpression'
+ ? [expr.consequent.value, expr.alternate.value]
+ : expr.value
+ );
}
}
return null;
@@ -88,12 +93,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).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;
+ });
}
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,
+ },
]),
});