Skip to content

Commit

Permalink
Browse files Browse the repository at this point in the history
Fix: dot notation rule failing to catch string template (fixes #9350) (
  • Loading branch information
philquinn authored and kaicataldo committed Sep 29, 2017
1 parent b1372da commit ff2be59
Show file tree
Hide file tree
Showing 2 changed files with 65 additions and 35 deletions.
91 changes: 56 additions & 35 deletions lib/rules/dot-notation.js
Expand Up @@ -54,46 +54,67 @@ module.exports = {
allowPattern = new RegExp(options.allowPattern);
}

/**
* Check if the property is valid dot notation
* @param {ASTNode} node The dot notation node
* @param {string} value Value which is to be checked
* @returns {void}
*/
function checkComputedProperty(node, value) {
if (
validIdentifier.test(value) &&
(allowKeywords || keywords.indexOf(String(value)) === -1) &&
!(allowPattern && allowPattern.test(value))
) {
const formattedValue = node.property.type === "Literal" ? JSON.stringify(value) : `\`${value}\``;

context.report({
node: node.property,
message: "[{{propertyValue}}] is better written in dot notation.",
data: {
propertyValue: formattedValue
},
fix(fixer) {
const leftBracket = sourceCode.getTokenAfter(node.object, astUtils.isOpeningBracketToken);
const rightBracket = sourceCode.getLastToken(node);

if (sourceCode.getFirstTokenBetween(leftBracket, rightBracket, { includeComments: true, filter: astUtils.isCommentToken })) {

// Don't perform any fixes if there are comments inside the brackets.
return null;
}

const tokenAfterProperty = sourceCode.getTokenAfter(rightBracket);
const needsSpaceAfterProperty = tokenAfterProperty &&
rightBracket.range[1] === tokenAfterProperty.range[0] &&
!astUtils.canTokensBeAdjacent(String(value), tokenAfterProperty);

const textBeforeDot = astUtils.isDecimalInteger(node.object) ? " " : "";
const textAfterProperty = needsSpaceAfterProperty ? " " : "";

return fixer.replaceTextRange(
[leftBracket.range[0], rightBracket.range[1]],
`${textBeforeDot}.${value}${textAfterProperty}`
);
}
});
}
}

return {
MemberExpression(node) {
if (
node.computed &&
node.property.type === "Literal" &&
validIdentifier.test(node.property.value) &&
(allowKeywords || keywords.indexOf(String(node.property.value)) === -1)
node.property.type === "Literal"
) {
if (!(allowPattern && allowPattern.test(node.property.value))) {
context.report({
node: node.property,
message: "[{{propertyValue}}] is better written in dot notation.",
data: {
propertyValue: JSON.stringify(node.property.value)
},
fix(fixer) {
const leftBracket = sourceCode.getTokenAfter(node.object, astUtils.isOpeningBracketToken);
const rightBracket = sourceCode.getLastToken(node);

if (sourceCode.getFirstTokenBetween(leftBracket, rightBracket, { includeComments: true, filter: astUtils.isCommentToken })) {

// Don't perform any fixes if there are comments inside the brackets.
return null;
}

const tokenAfterProperty = sourceCode.getTokenAfter(rightBracket);
const needsSpaceAfterProperty = tokenAfterProperty &&
rightBracket.range[1] === tokenAfterProperty.range[0] &&
!astUtils.canTokensBeAdjacent(String(node.property.value), tokenAfterProperty);

const textBeforeDot = astUtils.isDecimalInteger(node.object) ? " " : "";
const textAfterProperty = needsSpaceAfterProperty ? " " : "";

return fixer.replaceTextRange(
[leftBracket.range[0], rightBracket.range[1]],
`${textBeforeDot}.${node.property.value}${textAfterProperty}`
);
}
});
}
checkComputedProperty(node, node.property.value);
}
if (
node.computed &&
node.property.type === "TemplateLiteral" &&
node.property.expressions.length === 0
) {
checkComputedProperty(node, node.property.quasis[0].value.cooked);
}
if (
!allowKeywords &&
Expand Down
9 changes: 9 additions & 0 deletions tests/lib/rules/dot-notation.js
Expand Up @@ -40,6 +40,9 @@ ruleTester.run("dot-notation", rule, {
{ code: "a.null;", options: [{ allowKeywords: true }] },
{ code: "a['snake_case'];", options: [{ allowPattern: "^[a-z]+(_[a-z]+)+$" }] },
{ code: "a['lots_of_snake_case'];", options: [{ allowPattern: "^[a-z]+(_[a-z]+)+$" }] },
{ code: "a[`time${range}`];", parserOptions: { ecmaVersion: 6 } },
{ code: "a[`while`];", options: [{ allowKeywords: false }], parserOptions: { ecmaVersion: 6 } },
{ code: "a[`time range`];", parserOptions: { ecmaVersion: 6 } },
"a.true;",
"a.null;",
"a[undefined];",
Expand All @@ -58,6 +61,12 @@ ruleTester.run("dot-notation", rule, {
output: "a.true;",
errors: [{ message: "[\"true\"] is better written in dot notation." }]
},
{
code: "a[`time`];",
output: "a.time;",
parserOptions: { ecmaVersion: 6 },
errors: [{ message: "[`time`] is better written in dot notation." }]
},
{
code: "a[null];",
output: "a.null;",
Expand Down

0 comments on commit ff2be59

Please sign in to comment.