Skip to content

Commit bb370b8

Browse files
authored
feat: support explicit resource management in no-const-assign (#19892)
* feat: support explicit resource management in `no-const-assign` * update When Not To Use It section * fix typo
1 parent 5a0069d commit bb370b8

File tree

4 files changed

+124
-10
lines changed

4 files changed

+124
-10
lines changed

docs/src/rules/no-const-assign.md

Lines changed: 39 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -6,14 +6,11 @@ handled_by_typescript: true
66

77

88

9-
We cannot modify variables that are declared using `const` keyword.
10-
It will raise a runtime error.
11-
12-
Under non ES2015 environment, it might be ignored merely.
9+
Constant bindings cannot be modified. An attempt to modify a constant binding will raise a runtime error.
1310

1411
## Rule Details
1512

16-
This rule is aimed to flag modifying variables that are declared using `const` keyword.
13+
This rule is aimed to flag modifying variables that are declared using `const`, `using`, or `await using` keywords.
1714

1815
Examples of **incorrect** code for this rule:
1916

@@ -50,6 +47,24 @@ const a = 0;
5047

5148
:::
5249

50+
::: incorrect
51+
52+
```js
53+
/*eslint no-const-assign: "error"*/
54+
55+
if (foo) {
56+
using a = getSomething();
57+
a = somethingElse;
58+
}
59+
60+
if (bar) {
61+
await using a = getSomething();
62+
a = somethingElse;
63+
}
64+
```
65+
66+
:::
67+
5368
Examples of **correct** code for this rule:
5469

5570
::: correct
@@ -68,6 +83,24 @@ console.log(a);
6883
```js
6984
/*eslint no-const-assign: "error"*/
7085

86+
if (foo) {
87+
using a = getSomething();
88+
a.execute();
89+
}
90+
91+
if (bar) {
92+
await using a = getSomething();
93+
a.execute();
94+
}
95+
```
96+
97+
:::
98+
99+
::: correct
100+
101+
```js
102+
/*eslint no-const-assign: "error"*/
103+
71104
for (const a in [1, 2, 3]) { // `a` is re-defined (not modified) on each loop step.
72105
console.log(a);
73106
}
@@ -89,4 +122,4 @@ for (const a of [1, 2, 3]) { // `a` is re-defined (not modified) on each loop st
89122

90123
## When Not To Use It
91124

92-
If you don't want to be notified about modifying variables that are declared using `const` keyword, you can safely disable this rule.
125+
If you don't want to be notified about modifying variables that are declared using `const`, `using`, and `await using` keywords, you can safely disable this rule.

lib/rules/no-const-assign.js

Lines changed: 13 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -5,8 +5,18 @@
55

66
"use strict";
77

8+
//------------------------------------------------------------------------------
9+
// Requirements
10+
//------------------------------------------------------------------------------
11+
812
const astUtils = require("./utils/ast-utils");
913

14+
//------------------------------------------------------------------------------
15+
// Helpers
16+
//------------------------------------------------------------------------------
17+
18+
const CONSTANT_BINDINGS = new Set(["const", "using", "await using"]);
19+
1020
//------------------------------------------------------------------------------
1121
// Rule Definition
1222
//------------------------------------------------------------------------------
@@ -17,7 +27,8 @@ module.exports = {
1727
type: "problem",
1828

1929
docs: {
20-
description: "Disallow reassigning `const` variables",
30+
description:
31+
"Disallow reassigning `const`, `using`, and `await using` variables",
2132
recommended: true,
2233
url: "https://eslint.org/docs/latest/rules/no-const-assign",
2334
},
@@ -51,7 +62,7 @@ module.exports = {
5162

5263
return {
5364
VariableDeclaration(node) {
54-
if (node.kind === "const") {
65+
if (CONSTANT_BINDINGS.has(node.kind)) {
5566
sourceCode
5667
.getDeclaredVariables(node)
5768
.forEach(checkVariable);

lib/types/rules.d.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2126,7 +2126,7 @@ export interface ESLintRules extends Linter.RulesRecord {
21262126
>;
21272127

21282128
/**
2129-
* Rule to disallow reassigning `const` variables.
2129+
* Rule to disallow reassigning `const`, `using`, and `await using` variables.
21302130
*
21312131
* @remarks
21322132
* Recommended by ESLint, the rule was enabled in `eslint:recommended`.

tests/lib/rules/no-const-assign.js

Lines changed: 71 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -16,7 +16,7 @@ const RuleTester = require("../../../lib/rule-tester/rule-tester");
1616
// Tests
1717
//------------------------------------------------------------------------------
1818

19-
const ruleTester = new RuleTester({ languageOptions: { ecmaVersion: 6 } });
19+
const ruleTester = new RuleTester();
2020

2121
ruleTester.run("no-const-assign", rule, {
2222
valid: [
@@ -26,6 +26,10 @@ ruleTester.run("no-const-assign", rule, {
2626
"for (const x in [1,2,3]) { foo(x); }",
2727
"for (const x of [1,2,3]) { foo(x); }",
2828
"const x = {key: 0}; x.key = 1;",
29+
"using x = foo();",
30+
"await using x = foo();",
31+
"using x = foo(); bar(x);",
32+
"await using x = foo(); bar(x);",
2933

3034
// ignores non constant.
3135
"var x = 0; x = 1;",
@@ -115,5 +119,71 @@ ruleTester.run("no-const-assign", rule, {
115119
{ messageId: "const", data: { name: "x" }, type: "Identifier" },
116120
],
117121
},
122+
{
123+
code: "using x = foo(); x = 1;",
124+
errors: [
125+
{
126+
messageId: "const",
127+
data: { name: "x" },
128+
type: "Identifier",
129+
column: 18,
130+
},
131+
],
132+
},
133+
{
134+
code: "await using x = foo(); x = 1;",
135+
errors: [
136+
{
137+
messageId: "const",
138+
data: { name: "x" },
139+
type: "Identifier",
140+
column: 24,
141+
},
142+
],
143+
},
144+
{
145+
code: "using x = foo(); x ??= bar();",
146+
errors: [
147+
{
148+
messageId: "const",
149+
data: { name: "x" },
150+
type: "Identifier",
151+
column: 18,
152+
},
153+
],
154+
},
155+
{
156+
code: "await using x = foo(); x ||= bar();",
157+
errors: [
158+
{
159+
messageId: "const",
160+
data: { name: "x" },
161+
type: "Identifier",
162+
column: 24,
163+
},
164+
],
165+
},
166+
{
167+
code: "using x = foo(); [x, y] = bar();",
168+
errors: [
169+
{
170+
messageId: "const",
171+
data: { name: "x" },
172+
type: "Identifier",
173+
column: 19,
174+
},
175+
],
176+
},
177+
{
178+
code: "await using x = foo(); [x = baz, y] = bar();",
179+
errors: [
180+
{
181+
messageId: "const",
182+
data: { name: "x" },
183+
type: "Identifier",
184+
column: 25,
185+
},
186+
],
187+
},
118188
],
119189
});

0 commit comments

Comments
 (0)