Skip to content

Commit

Permalink
[Fix] jsx-no-target-blank: False negative when rel attribute is ass…
Browse files Browse the repository at this point in the history
…igned using ConditionalExpression
  • Loading branch information
V2dha authored and ljharb committed Jul 13, 2022
1 parent b3a3937 commit 91ee4d5
Show file tree
Hide file tree
Showing 3 changed files with 75 additions and 8 deletions.
2 changes: 2 additions & 0 deletions CHANGELOG.md
Expand Up @@ -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)
Expand All @@ -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
Expand Down
30 changes: 24 additions & 6 deletions lib/rules/jsx-no-target-blank.js
Expand Up @@ -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') {
Expand All @@ -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;
}
}
Expand All @@ -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 = {
Expand Down
51 changes: 49 additions & 2 deletions tests/lib/rules/jsx-no-target-blank.js
Expand Up @@ -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([
Expand Down Expand Up @@ -141,6 +142,19 @@ ruleTester.run('jsx-no-target-blank', rule, {
{
code: '<a href target="_blank"/>',
},
{
code: '<a href={href} target={isExternal ? "_blank" : undefined} rel="noopener noreferrer" />',
},
{
code: '<a href={href} target={isExternal ? undefined : "_blank"} rel={isExternal ? "noreferrer" : "noopener noreferrer"} />',
},
{
code: '<a href={href} target={isExternal ? undefined : "_blank"} rel={isExternal ? "noreferrer noopener" : "noreferrer"} />',
},
{
code: '<a href={href} target="_blank" rel={isExternal ? "noreferrer" : "noopener"} />',
options: [{ allowReferrer: true }],
},
]),
invalid: parsers.all([
{
Expand Down Expand Up @@ -251,13 +265,13 @@ ruleTester.run('jsx-no-target-blank', rule, {
code: '<a href="https://example.com/20" target="_blank" rel></a>',
output: '<a href="https://example.com/20" target="_blank" rel="noopener"></a>',
options: [{ allowReferrer: true }],
errors: [{ messageId: 'noTargetBlankWithoutNoopener' }],
errors: allowReferrerErrors,
},
{
code: '<a href="https://example.com/20" target="_blank"></a>',
output: '<a href="https://example.com/20" target="_blank" rel="noopener"></a>',
options: [{ allowReferrer: true }],
errors: [{ messageId: 'noTargetBlankWithoutNoopener' }],
errors: allowReferrerErrors,
},
{
code: '<a target="_blank" href={ dynamicLink }></a>',
Expand Down Expand Up @@ -352,5 +366,38 @@ ruleTester.run('jsx-no-target-blank', rule, {
options: [{ forms: true, links: false }],
errors: defaultErrors,
},
{
code: '<a href={href} target="_blank" rel={isExternal ? "undefined" : "undefined"} />',
errors: defaultErrors,
},
{
code: '<a href={href} target="_blank" rel={isExternal ? "noopener" : undefined} />',
errors: defaultErrors,
},
{
code: '<a href={href} target="_blank" rel={isExternal ? "undefined" : "noopener"} />',
errors: defaultErrors,
},
{
code: '<a href={href} target={isExternal ? "_blank" : undefined} rel={isExternal ? "noopener noreferrer" : undefined} />',
errors: defaultErrors,
},
{
code: '<a href={href} target={isExternal ? "_blank" : undefined} rel={isExternal ? undefined : "noopener noreferrer"} />',
errors: defaultErrors,
},
{
code: '<a href={href} target="_blank" rel={isExternal ? 3 : "noopener noreferrer"} />',
errors: defaultErrors,
},
{
code: '<a href={href} target="_blank" rel={isExternal ? "noopener noreferrer" : "3"} />',
errors: defaultErrors,
},
{
code: '<a href={href} target="_blank" rel={isExternal ? "noopener" : "2"} />',
options: [{ allowReferrer: true }],
errors: allowReferrerErrors,
},
]),
});

0 comments on commit 91ee4d5

Please sign in to comment.