New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Extend fixers for prefer-string-slice
#424
Changes from 11 commits
4e71bc2
79c27bb
4ac5039
b8e27a5
cff2a13
3d0d45c
e0a7d6f
bbd45a2
e9736b3
e904cef
7234b60
a06024e
860738c
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change | ||||
---|---|---|---|---|---|---|
|
@@ -10,6 +10,24 @@ const argumentsVariable = templates.spreadVariable(); | |||||
const substrCallTemplate = templates.template`${objectVariable}.substr(${argumentsVariable})`; | ||||||
const substringCallTemplate = templates.template`${objectVariable}.substring(${argumentsVariable})`; | ||||||
|
||||||
const getNumericValue = node => { | ||||||
if (node.type === 'Literal' && typeof node.value === 'number') { | ||||||
return node.value; | ||||||
} | ||||||
|
||||||
if (node.type === 'UnaryExpression' && node.operator === '-') { | ||||||
return 0 - getNumericValue(node.argument); | ||||||
} | ||||||
}; | ||||||
|
||||||
const isLengthProperty = node => ( | ||||||
fisker marked this conversation as resolved.
Show resolved
Hide resolved
|
||||||
node && | ||||||
node.type === 'MemberExpression' && | ||||||
node.computed === false && | ||||||
node.property.type === 'Identifier' && | ||||||
node.property.name === 'length' | ||||||
); | ||||||
|
||||||
const create = context => { | ||||||
const sourceCode = context.getSourceCode(); | ||||||
|
||||||
|
@@ -23,10 +41,33 @@ const create = context => { | |||||
message: 'Prefer `String#slice()` over `String#substr()`.' | ||||||
}; | ||||||
|
||||||
const canFix = argumentNodes.length === 0; | ||||||
const firstArgument = argumentNodes[0] ? sourceCode.getText(argumentNodes[0]) : undefined; | ||||||
const secondArgument = argumentNodes[1] ? sourceCode.getText(argumentNodes[1]) : undefined; | ||||||
|
||||||
let slice; | ||||||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. this can be an array and concat with There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. rename to There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. could you rename this variable? more specific |
||||||
|
||||||
if (argumentNodes.length === 0) { | ||||||
slice = []; | ||||||
} else if (argumentNodes.length === 1) { | ||||||
slice = [firstArgument]; | ||||||
} else if (argumentNodes.length === 2) { | ||||||
if (firstArgument === '0') { | ||||||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. should be literal zero, we don't want handle There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. The text representation of an argument node can only ever be There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. sorry, my comment is based on There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. As almost every branch used the value of As There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. thanks for explaining this, this make sense now, but I think it makes the logic little hard to understand. you want use those functions?
|
||||||
slice = [firstArgument, secondArgument]; | ||||||
} else if (argumentNodes[0].type === 'Literal') { | ||||||
if (argumentNodes[1].type === 'Literal' && typeof argumentNodes[1].value === 'number' && typeof argumentNodes[0].value === 'number') { | ||||||
fisker marked this conversation as resolved.
Show resolved
Hide resolved
|
||||||
slice = [argumentNodes[0].value, argumentNodes[0].value + argumentNodes[1].value]; | ||||||
} else { | ||||||
slice = [firstArgument, firstArgument + ' + ' + secondArgument]; | ||||||
voxpelli marked this conversation as resolved.
Show resolved
Hide resolved
|
||||||
} | ||||||
} | ||||||
} | ||||||
|
||||||
if (slice) { | ||||||
const objectText = objectNode.type === 'LogicalExpression' ? | ||||||
`(${sourceCode.getText(objectNode)})` : | ||||||
sourceCode.getText(objectNode); | ||||||
|
||||||
if (canFix) { | ||||||
problem.fix = fixer => fixer.replaceText(node, sourceCode.getText(objectNode) + '.slice()'); | ||||||
problem.fix = fixer => fixer.replaceText(node, `${objectText}.slice(${slice.join(', ')})`); | ||||||
} | ||||||
|
||||||
context.report(problem); | ||||||
|
@@ -41,10 +82,48 @@ const create = context => { | |||||
message: 'Prefer `String#slice()` over `String#substring()`.' | ||||||
}; | ||||||
|
||||||
const canFix = argumentNodes.length === 0; | ||||||
const firstArgument = argumentNodes[0] ? sourceCode.getText(argumentNodes[0]) : undefined; | ||||||
const secondArgument = argumentNodes[1] ? sourceCode.getText(argumentNodes[1]) : undefined; | ||||||
|
||||||
const firstNumber = argumentNodes[0] ? getNumericValue(argumentNodes[0]) : undefined; | ||||||
|
||||||
let slice; | ||||||
|
||||||
if (argumentNodes.length === 0) { | ||||||
slice = []; | ||||||
} else if (argumentNodes.length === 1) { | ||||||
fisker marked this conversation as resolved.
Show resolved
Hide resolved
|
||||||
if (firstNumber !== undefined) { | ||||||
slice = [Math.max(0, firstNumber)]; | ||||||
} else if (isLengthProperty(argumentNodes[0])) { | ||||||
slice = [firstArgument]; | ||||||
} else { | ||||||
slice = [`Math.max(0, ${firstArgument})`]; | ||||||
} | ||||||
} else if (argumentNodes.length === 2) { | ||||||
const secondNumber = argumentNodes[1] ? getNumericValue(argumentNodes[1]) : undefined; | ||||||
|
||||||
if (firstNumber !== undefined && secondNumber !== undefined) { | ||||||
slice = firstNumber > secondNumber ? | ||||||
[Math.max(0, secondNumber), Math.max(0, firstNumber)] : | ||||||
[Math.max(0, firstNumber), Math.max(0, secondNumber)]; | ||||||
} else if (firstNumber === 0 || secondNumber === 0) { | ||||||
slice = [0, `Math.max(0, ${firstNumber === 0 ? secondArgument : firstArgument})`]; | ||||||
} else { | ||||||
// As values aren't Literal, we can not know whether secondArgument will become smaller than the first or not, causing an issue: | ||||||
// .substring(0, 2) and .substring(2, 0) returns the same result | ||||||
// .slice(0, 2) and .slice(2, 0) doesn't return the same result | ||||||
// There's also an issue with us now knowing whether the value will be negative or not, due to: | ||||||
// .substring() treats a negative number the same as it treats a zero. | ||||||
// The latter issue could be solved by wrapping all dynamic numbers in Math.max(0, <value>), but the resulting code would not be nice | ||||||
} | ||||||
} | ||||||
|
||||||
if (slice) { | ||||||
const objectText = objectNode.type === 'LogicalExpression' ? | ||||||
`(${sourceCode.getText(objectNode)})` : | ||||||
sourceCode.getText(objectNode); | ||||||
|
||||||
if (canFix) { | ||||||
problem.fix = fixer => fixer.replaceText(node, sourceCode.getText(objectNode) + '.slice()'); | ||||||
problem.fix = fixer => fixer.replaceText(node, `${objectText}.slice(${slice.join(', ')})`); | ||||||
} | ||||||
|
||||||
context.report(problem); | ||||||
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
this 0 should remove
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
also, do we really want recury this? just number and negative number should enough
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
It's usually useful to explain why if it's not immediately obvious.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Why should the
0
be removed?There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
sorry, I was not explaining clear, this is negative number, right?
0 - 1
is the same as-1
am I missing something?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
It's a positive number
Literal
wrapped in aUnaryExpression
with a-
operator, so the0 -
part is to convert the positive number into its correct negative value. I do think I have added tests for that?There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I know that
-1
is parsed asUnaryExpression
andoperator:-
andargument:1
so
return 0 - node.argument
equals toreturn - node.argument
.I am getting confused, am I wrong?