Skip to content

Commit

Permalink
fix(eslint-plugin): [prefer-string-starts-ends-with] only report slic…
Browse files Browse the repository at this point in the history
…e/substring with correct range (#7712)
  • Loading branch information
Josh-Cena committed Oct 8, 2023
1 parent 8f4d939 commit db40a0a
Show file tree
Hide file tree
Showing 2 changed files with 62 additions and 38 deletions.
67 changes: 47 additions & 20 deletions packages/eslint-plugin/src/rules/prefer-string-starts-ends-with.ts
Expand Up @@ -161,23 +161,22 @@ export default createRule({
}

/**
* Check if a given node is a negative index expression
*
* E.g. `s.slice(- <expr>)`, `s.substring(s.length - <expr>)`
*
* @param node The node to check.
* @param expectedIndexedNode The node which is expected as the receiver of index expression.
* Returns true if `node` is `-substring.length` or
* `parentString.length - substring.length`
*/
function isNegativeIndexExpression(
function isLengthAheadOfEnd(
node: TSESTree.Node,
expectedIndexedNode: TSESTree.Node,
substring: TSESTree.Node,
parentString: TSESTree.Node,
): boolean {
return (
(node.type === AST_NODE_TYPES.UnaryExpression &&
node.operator === '-') ||
node.operator === '-' &&
isLengthExpression(node.argument, substring)) ||
(node.type === AST_NODE_TYPES.BinaryExpression &&
node.operator === '-' &&
isLengthExpression(node.left, expectedIndexedNode))
isLengthExpression(node.left, parentString) &&
isLengthExpression(node.right, substring))
);
}

Expand Down Expand Up @@ -567,16 +566,44 @@ export default createRule({
return;
}

const isEndsWith =
(callNode.arguments.length === 1 ||
(callNode.arguments.length === 2 &&
isLengthExpression(callNode.arguments[1], node.object))) &&
isNegativeIndexExpression(callNode.arguments[0], node.object);
const isStartsWith =
!isEndsWith &&
callNode.arguments.length === 2 &&
isNumber(callNode.arguments[0], 0) &&
!isNegativeIndexExpression(callNode.arguments[1], node.object);
let isEndsWith = false;
let isStartsWith = false;
if (callNode.arguments.length === 1) {
if (
// foo.slice(-bar.length) === bar
// foo.slice(foo.length - bar.length) === bar
isLengthAheadOfEnd(
callNode.arguments[0],
parentNode.right,
node.object,
)
) {
isEndsWith = true;
}
} else if (callNode.arguments.length === 2) {
if (
// foo.slice(0, bar.length) === bar
isNumber(callNode.arguments[0], 0) &&
isLengthExpression(callNode.arguments[1], parentNode.right)
) {
isStartsWith = true;
} else if (
// foo.slice(foo.length - bar.length, foo.length) === bar
// foo.slice(foo.length - bar.length, 0) === bar
// foo.slice(-bar.length, foo.length) === bar
// foo.slice(-bar.length, 0) === bar
(isLengthExpression(callNode.arguments[1], node.object) ||
isNumber(callNode.arguments[1], 0)) &&
isLengthAheadOfEnd(
callNode.arguments[0],
parentNode.right,
node.object,
)
) {
isEndsWith = true;
}
}

if (!isStartsWith && !isEndsWith) {
return;
}
Expand Down
Expand Up @@ -242,6 +242,21 @@ ruleTester.run('prefer-string-starts-ends-with', rule, {
x.endsWith('foo') && x.slice(0, -4) === 'bar'
}
`,
`
function f(s: string) {
s.slice(0, length) === needle // the 'length' can be different to 'needle.length'
}
`,
`
function f(s: string) {
s.slice(-length) === needle // 'length' can be different
}
`,
`
function f(s: string) {
s.slice(0, 3) === needle
}
`,
]),
invalid: addOptional([
// String indexing.
Expand Down Expand Up @@ -817,15 +832,6 @@ ruleTester.run('prefer-string-starts-ends-with', rule, {
`,
errors: [{ messageId: 'preferStartsWith' }],
},
{
code: `
function f(s: string) {
s.slice(0, length) === needle // the 'length' can be different to 'needle.length'
}
`,
output: null,
errors: [{ messageId: 'preferStartsWith' }],
},
{
code: `
function f(s: string) {
Expand Down Expand Up @@ -887,15 +893,6 @@ ruleTester.run('prefer-string-starts-ends-with', rule, {
`,
errors: [{ messageId: 'preferEndsWith' }],
},
{
code: `
function f(s: string) {
s.slice(-length) === needle // 'length' can be different
}
`,
output: null,
errors: [{ messageId: 'preferEndsWith' }],
},
{
code: `
function f(s: string) {
Expand Down

0 comments on commit db40a0a

Please sign in to comment.