Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 0 additions & 6 deletions its/ruling/src/test/expected/jsts/Joust/typescript-S2310.json

This file was deleted.

Original file line number Diff line number Diff line change
@@ -1,7 +1,5 @@
{
"TypeScript:lib/tsc.js": [
18167,
22894,
55986
]
}
Original file line number Diff line number Diff line change
@@ -1,14 +1,5 @@
{
"TypeScript:src/compiler/binder.ts": [
1145
],
"TypeScript:src/compiler/checker.ts": [
2890
],
"TypeScript:src/compiler/program.ts": [
292
],
"TypeScript:src/services/documentHighlights.ts": [
583
]
}
33 changes: 1 addition & 32 deletions its/ruling/src/test/expected/jsts/ace/javascript-S2310.json
Original file line number Diff line number Diff line change
@@ -1,60 +1,29 @@
{
"ace:lib/ace/mode/html/saxparser.js": [
820
],
"ace:lib/ace/mode/javascript/jshint.js": [
3345
],
"ace:lib/ace/mode/yaml/yaml-lint.js": [
623
],
"ace:src/edit_session.js": [
1018
],
"ace:src/edit_session/folding.js": [
651
],
"ace:src/editor.js": [
1880,
1889
],
"ace:src/ext/whitespace.js": [
34
],
"ace:src/keyboard/vim.js": [
5346
],
"ace:src/layer/text.js": [
178
],
"ace:src/lib/bidiutil.js": [
330
],
"ace:src/mode/folding/xml.js": [
67,
72,
72
],
"ace:src/mode/text_highlight_rules.js": [
165
],
"ace:src/range_list.js": [
90
],
"ace:src/search.js": [
138
],
"ace:src/snippets.js": [
320
],
"ace:src/undomanager.js": [
428,
431,
547,
550
431
],
"ace:tool/tmlanguage.js": [
50,
127
]
}

This file was deleted.

12 changes: 0 additions & 12 deletions its/ruling/src/test/expected/jsts/angular.js/javascript-S2310.json

This file was deleted.

This file was deleted.

Original file line number Diff line number Diff line change
Expand Up @@ -3,15 +3,6 @@
449
],
"desktop:app/src/lib/git/diff.ts": [
302,
306,
324
],
"desktop:app/src/lib/git/log.ts": [
258,
263
],
"desktop:app/src/lib/status-parser.ts": [
80
]
}
5 changes: 0 additions & 5 deletions its/ruling/src/test/expected/jsts/http/javascript-S2310.json

This file was deleted.

Original file line number Diff line number Diff line change
@@ -1,12 +1,5 @@
{
"jquery:src/callbacks.js": [
76,
83
],
"jquery:src/effects.js": [
651
],
"jquery:src/selector.js": [
1367
]
}
Original file line number Diff line number Diff line change
Expand Up @@ -4,11 +4,5 @@
],
"knockout:src/binding/expressionRewriting.js": [
88
],
"knockout:src/subscribables/observableArray.js": [
28
],
"knockout:src/utils.domNodeDisposal.js": [
47
]
}

This file was deleted.

11 changes: 1 addition & 10 deletions its/ruling/src/test/expected/jsts/p5.js/javascript-S2310.json
Original file line number Diff line number Diff line change
@@ -1,15 +1,6 @@
{
"p5.js:docs/yuidoc-p5-theme/assets/js/reference.js": [
1346,
2781
],
"p5.js:lib/addons/p5.sound.js": [
1381,
1381,
2826,
2828
],
"p5.js:src/typography/p5.Font.js": [
757
1381
]
}

This file was deleted.

5 changes: 0 additions & 5 deletions its/ruling/src/test/expected/jsts/qunit/javascript-S2310.json

This file was deleted.

This file was deleted.

This file was deleted.

This file was deleted.

49 changes: 49 additions & 0 deletions packages/jsts/src/rules/S2310/rule.ts
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@ import type { Rule } from 'eslint';
import type estree from 'estree';
import {
generateMeta,
getNodeParent,
getParent,
getVariableFromName,
report,
Expand Down Expand Up @@ -50,6 +51,9 @@ export const rule: Rule.RuleModule = {
}
for (const ref of variable.references) {
if (ref.isWrite() && isUsedInsideBody(ref.identifier, block)) {
if (isIntentionalSkipAhead(ref.identifier, block)) {
continue;
}
report(
context,
{
Expand Down Expand Up @@ -95,7 +99,52 @@ function collectCountersFor(updateExpression: estree.Expression, counters: estre
}
}

/**
* Checks if a loop counter modification is an intentional skip-ahead pattern
* (UpdateExpression or compound assignment) rather than a simple assignment.
* Modifications in nested for-loop update clauses are not considered skip-ahead.
*/
function isIntentionalSkipAhead(id: estree.Identifier, outerLoopBody: estree.Node): boolean {
if (isInNestedForLoopUpdate(id, outerLoopBody)) {
return false;
}
const parent = getNodeParent(id);
if (parent?.type === 'UpdateExpression') {
return true;
}
if (parent?.type === 'AssignmentExpression' && parent.operator !== '=') {
return true;
}
return false;
}

function isUsedInsideBody(id: estree.Identifier, loopBody: estree.Node) {
const bodyRange = loopBody.range;
return id.range && bodyRange && id.range[0] > bodyRange[0] && id.range[1] < bodyRange[1];
}

function isInNestedForLoopUpdate(id: estree.Identifier, outerLoopBody: estree.Node): boolean {
let node: estree.Node | undefined = id;
let parent = getNodeParent(node);
while (parent) {
// Stop if we've reached the outer loop body
if (parent === outerLoopBody) {
return false;
}
// Check if we're in a nested for-loop's update clause
if (parent.type === 'ForStatement' && parent.update) {
const updateRange = parent.update.range;
if (
updateRange &&
id.range &&
id.range[0] >= updateRange[0] &&
id.range[1] <= updateRange[1]
) {
return true;
}
}
node = parent;
parent = getNodeParent(node);
}
return false;
}
Loading
Loading