Skip to content

Commit a6a6325

Browse files
authored
feat: support explicit resource management in no-loop-func (#19895)
* feat: support explicit resource management in `no-loop-func` * replace tabs with spaces
1 parent 4682cdc commit a6a6325

File tree

3 files changed

+92
-10
lines changed

3 files changed

+92
-10
lines changed

docs/src/rules/no-loop-func.md

Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -115,6 +115,34 @@ for (let i=10; i; i--) {
115115
a();
116116
}
117117

118+
for (const i of foo) {
119+
var a = function() { return i; }; // OK, all references are referring to block scoped variables in the loop.
120+
a();
121+
}
122+
123+
for (using i of foo) {
124+
var a = function() { return i; }; // OK, all references are referring to block scoped variables in the loop.
125+
a();
126+
}
127+
128+
for (var i=10; i; i--) {
129+
const foo = getsomething(i);
130+
var a = function() { return foo; }; // OK, all references are referring to block scoped variables in the loop.
131+
a();
132+
}
133+
134+
for (var i=10; i; i--) {
135+
using foo = getsomething(i);
136+
var a = function() { return foo; }; // OK, all references are referring to block scoped variables in the loop.
137+
a();
138+
}
139+
140+
for (var i=10; i; i--) {
141+
await using foo = getsomething(i);
142+
var a = function() { return foo; }; // OK, all references are referring to block scoped variables in the loop.
143+
a();
144+
}
145+
118146
var foo = 100;
119147
for (let i=10; i; i--) {
120148
var a = function() { return foo; }; // OK, all references are referring to never modified variables.

lib/rules/no-loop-func.js

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,8 @@
99
// Helpers
1010
//------------------------------------------------------------------------------
1111

12+
const CONSTANT_BINDINGS = new Set(["const", "using", "await using"]);
13+
1214
/**
1315
* Identifies is a node is a FunctionExpression which is part of an IIFE
1416
* @param {ASTNode} node Node to test
@@ -148,8 +150,8 @@ module.exports = {
148150
? declaration.kind
149151
: "";
150152

151-
// Variables which are declared by `const` is safe.
152-
if (kind === "const") {
153+
// Constant variables are safe.
154+
if (CONSTANT_BINDINGS.has(kind)) {
153155
return true;
154156
}
155157

tests/lib/rules/no-loop-func.js

Lines changed: 60 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -50,6 +50,22 @@ ruleTester.run("no-loop-func", rule, {
5050
code: "for (const i of {}) { (function() { i; }) }",
5151
languageOptions: { ecmaVersion: 6 },
5252
},
53+
{
54+
code: "for (using i of foo) { (function() { i; }) }",
55+
languageOptions: { ecmaVersion: 2026 },
56+
},
57+
{
58+
code: "for (await using i of foo) { (function() { i; }) }",
59+
languageOptions: { ecmaVersion: 2026 },
60+
},
61+
{
62+
code: "for (var i = 0; i < 10; ++i) { using foo = bar(i); (function() { foo; }) }",
63+
languageOptions: { ecmaVersion: 2026 },
64+
},
65+
{
66+
code: "for (var i = 0; i < 10; ++i) { await using foo = bar(i); (function() { foo; }) }",
67+
languageOptions: { ecmaVersion: 2026 },
68+
},
5369
{
5470
code: "for (let i = 0; i < 10; ++i) { for (let x in xs.filter(x => x != i)) { } }",
5571
languageOptions: { ecmaVersion: 6 },
@@ -170,7 +186,7 @@ ruleTester.run("no-loop-func", rule, {
170186
current.c;
171187
current.d;
172188
})();
173-
189+
174190
current = current.upper;
175191
}
176192
`,
@@ -208,6 +224,42 @@ ruleTester.run("no-loop-func", rule, {
208224
`,
209225
languageOptions: { ecmaVersion: 6 },
210226
},
227+
{
228+
code: `
229+
const foo = bar;
230+
231+
for (var i = 0; i < 5; i++) {
232+
arr.push(() => foo);
233+
}
234+
235+
foo = baz; // This is a runtime error, but not concern of this rule. For this rule, variable 'foo' is constant.
236+
`,
237+
languageOptions: { ecmaVersion: 6 },
238+
},
239+
{
240+
code: `
241+
using foo = bar;
242+
243+
for (var i = 0; i < 5; i++) {
244+
arr.push(() => foo);
245+
}
246+
247+
foo = baz; // This is a runtime error, but not concern of this rule. For this rule, variable 'foo' is constant.
248+
`,
249+
languageOptions: { ecmaVersion: 2026 },
250+
},
251+
{
252+
code: `
253+
await using foo = bar;
254+
255+
for (var i = 0; i < 5; i++) {
256+
arr.push(() => foo);
257+
}
258+
259+
foo = baz; // This is a runtime error, but not concern of this rule. For this rule, variable 'foo' is constant.
260+
`,
261+
languageOptions: { ecmaVersion: 2026 },
262+
},
211263
],
212264
invalid: [
213265
{
@@ -471,7 +523,7 @@ ruleTester.run("no-loop-func", rule, {
471523
current;
472524
arr.push(f);
473525
})();
474-
526+
475527
current = current.upper;
476528
}
477529
`,
@@ -615,7 +667,7 @@ ruleTester.run("no-loop-func", rule, {
615667
616668
for (var i = 0; i < 5; i++) {
617669
arr.push((() => {
618-
return () =>
670+
return () =>
619671
(() => i)();
620672
})());
621673
}
@@ -666,7 +718,7 @@ ruleTester.run("no-loop-func", rule, {
666718
return i;
667719
})();
668720
})();
669-
721+
670722
}
671723
`,
672724
languageOptions: { ecmaVersion: 2022 },
@@ -839,7 +891,7 @@ ruleTesterTypeScript.run("no-loop-func", rule, {
839891
// ConfiguredType is in globals, UnconfiguredType is not
840892
// Both should be considered safe as they are type references
841893
const process = (configItem: ConfiguredType, unconfigItem: UnconfiguredType) => {
842-
return {
894+
return {
843895
config: configItem.value,
844896
unconfig: unconfigItem.value
845897
};
@@ -892,14 +944,14 @@ ruleTesterTypeScript.run("no-loop-func", rule, {
892944
id: number;
893945
name: string;
894946
}
895-
947+
896948
const items: Item[] = [];
897949
for (var i = 0; i < 10; i++) {
898950
items.push({
899951
id: i,
900952
name: "Item " + i
901953
});
902-
954+
903955
const process = function(callback: (item: Item) => void): void {
904956
callback({ id: i, name: "Item " + i });
905957
};
@@ -916,7 +968,7 @@ ruleTesterTypeScript.run("no-loop-func", rule, {
916968
{
917969
code: `
918970
type Processor<T> = (item: T) => void;
919-
971+
920972
for (var i = 0; i < 10; i++) {
921973
const processor: Processor<number> = (item) => {
922974
return item + i;

0 commit comments

Comments
 (0)