Skip to content

Commit

Permalink
Fix: dot notation rule failing to catch string template (fixes #9350)
Browse files Browse the repository at this point in the history
  • Loading branch information
philquinn committed Sep 27, 2017
1 parent 434d9e2 commit ad841b7
Show file tree
Hide file tree
Showing 2 changed files with 61 additions and 21 deletions.
74 changes: 53 additions & 21 deletions lib/rules/dot-notation.js
Original file line number Diff line number Diff line change
Expand Up @@ -54,6 +54,37 @@ module.exports = {
allowPattern = new RegExp(options.allowPattern);
}

/**
* Fixes code to use dot notation when expected
* @param {fixer} fixer Fixer
* @param {ASTNode} node The dot notation node
* @param {string} value Value which will be used in correction
* @returns {string} fixed dot notation
*/
function fixDotNotationWithValue(fixer, node, value) {
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 (
Expand All @@ -70,27 +101,28 @@ module.exports = {
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}`
);
return fixDotNotationWithValue(fixer, node, node.property.value);
}
});
}
}
if (
node.computed &&
node.property.type === "TemplateLiteral" &&
node.property.expressions.length === 0 &&
node.property.quasis.length === 1 &&
validIdentifier.test(node.property.quasis[0].value.raw) &&
(allowKeywords || keywords.indexOf(String(node.property.quasis[0].value.raw)) === -1)
) {
if (!(allowPattern && allowPattern.test(node.property.quasis[0].value.raw))) {
context.report({
node: node.property,
message: "[`{{propertyValue}}`] is better written in dot notation.",
data: {
propertyValue: node.property.quasis[0].value.raw
},
fix(fixer) {
return fixDotNotationWithValue(fixer, node, node.property.quasis[0].value.raw);
}
});
}
Expand Down
8 changes: 8 additions & 0 deletions tests/lib/rules/dot-notation.js
Original file line number Diff line number Diff line change
Expand Up @@ -40,6 +40,8 @@ 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[`time range`];", parserOptions: { ecmaVersion: 6 } },
"a.true;",
"a.null;",
"a[undefined];",
Expand All @@ -58,6 +60,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 ad841b7

Please sign in to comment.