Skip to content

Commit

Permalink
[Fix] jsx-no-target-blank: allow ternaries with literals
Browse files Browse the repository at this point in the history
  • Loading branch information
akulsr0 authored and ljharb committed Oct 15, 2022
1 parent 611b9ee commit 5efd774
Show file tree
Hide file tree
Showing 3 changed files with 37 additions and 11 deletions.
2 changes: 2 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
30 changes: 23 additions & 7 deletions lib/rules/jsx-no-target-blank.js
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand All @@ -75,24 +81,34 @@ 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;
}

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;
Expand Down
16 changes: 12 additions & 4 deletions tests/lib/rules/jsx-no-target-blank.js
Original file line number Diff line number Diff line change
Expand Up @@ -155,6 +155,18 @@ ruleTester.run('jsx-no-target-blank', rule, {
code: '<a href={href} target="_blank" rel={isExternal ? "noreferrer" : "noopener"} />',
options: [{ allowReferrer: true }],
},
{
code: '<a href={href} target={isExternal ? "_blank" : undefined} rel={isExternal ? "noreferrer" : undefined} />',
},
{
code: '<a href={href} target={isSelf ? "_self" : "_blank"} rel={isSelf ? undefined : "noreferrer"} />',
},
{
code: '<a href={href} target={isSelf ? "_self" : ""} rel={isSelf ? undefined : ""} />',
},
{
code: '<a href={href} target={isExternal ? "_blank" : undefined} rel={isExternal ? "noopener noreferrer" : undefined} />',
},
]),
invalid: parsers.all([
{
Expand Down Expand Up @@ -378,10 +390,6 @@ ruleTester.run('jsx-no-target-blank', rule, {
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,
Expand Down

0 comments on commit 5efd774

Please sign in to comment.