Skip to content

Commit f28fbf8

Browse files
authored
fix!: Deprecate "always" and "as-needed" options of the radix rule (#20223)
* fix!: Deprecate `"always"` and `"as-needed"` options of the `radix` rule * undo changes in types * update migration guide
1 parent aa3fb2b commit f28fbf8

6 files changed

Lines changed: 163 additions & 151 deletions

File tree

docs/src/_data/further_reading_links.json

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -831,5 +831,12 @@
831831
"logo": "https://github.githubassets.com/favicons/favicon.png",
832832
"title": "Error types that support `cause`",
833833
"description": "Interface declarations for all the Error types in JavaScript that support passing a `cause` property."
834+
},
835+
"https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/parseInt": {
836+
"domain": "developer.mozilla.org",
837+
"url": "https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/parseInt",
838+
"logo": "https://developer.mozilla.org/favicon.ico",
839+
"title": "parseInt() - JavaScript | MDN",
840+
"description": "The parseInt() function parses a string argument and returns an integer of the specified radix (the base in mathematical numeral systems)."
834841
}
835842
}

docs/src/rules/radix.md

Lines changed: 7 additions & 47 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@
22
title: radix
33
rule_type: suggestion
44
further_reading:
5+
- https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/parseInt
56
- https://davidwalsh.name/parseint-radix
67
---
78

@@ -23,22 +24,11 @@ const num = parseInt("071", 10); // 71
2324

2425
ECMAScript 5 changed the behavior of `parseInt()` so that it no longer autodetects octal literals and instead treats them as decimal literals. However, the differences between hexadecimal and decimal interpretation of the first parameter causes many developers to continue using the radix parameter to ensure the string is interpreted in the intended way.
2526

26-
On the other hand, if the code is targeting only ES5-compliant environments passing the radix `10` may be redundant. In such a case you might want to disallow using such a radix.
27-
2827
## Rule Details
2928

30-
This rule is aimed at preventing the unintended conversion of a string to a number of a different base than intended or at preventing the redundant `10` radix if targeting modern environments only.
31-
32-
## Options
33-
34-
There are two options for this rule:
29+
This rule is aimed at preventing the unintended conversion of a string to a number of a different base than intended.
3530

36-
* `"always"` enforces providing a radix (default)
37-
* `"as-needed"` disallows providing the `10` radix
38-
39-
### always
40-
41-
Examples of **incorrect** code for the default `"always"` option:
31+
Examples of **incorrect** code for this rule:
4232

4333
::: incorrect
4434

@@ -58,7 +48,7 @@ const num4 = parseInt();
5848

5949
:::
6050

61-
Examples of **correct** code for the default `"always"` option:
51+
Examples of **correct** code for this rule:
6252

6353
::: correct
6454

@@ -74,40 +64,10 @@ const num2 = parseFloat(someValue);
7464

7565
:::
7666

77-
### as-needed
78-
79-
Examples of **incorrect** code for the `"as-needed"` option:
80-
81-
::: incorrect
82-
83-
```js
84-
/*eslint radix: ["error", "as-needed"]*/
85-
86-
const num = parseInt("071", 10);
87-
88-
const num1 = parseInt("071", "abc");
89-
90-
const num2 = parseInt();
91-
```
92-
93-
:::
94-
95-
Examples of **correct** code for the `"as-needed"` option:
96-
97-
::: correct
98-
99-
```js
100-
/*eslint radix: ["error", "as-needed"]*/
101-
102-
const num = parseInt("071");
103-
104-
const num1 = parseInt("071", 8);
105-
106-
const num2 = parseFloat(someValue);
107-
```
67+
## Options
10868

109-
:::
69+
**Deprecated:** String options `"always"` and `"as-needed"` are deprecated. Setting either of these options doesn't change the behavior of this rule, which now always enforces providing a radix, as it was the case when the `"always"` option was specified. Since the default radix depends on the first argument of `parseInt()`, this rule assumes that the second argument (the radix) is always needed.
11070

11171
## When Not To Use It
11272

113-
If you don't want to enforce either presence or omission of the `10` radix value you can turn this rule off.
73+
If you want to use the default behavior of the `parseInt()` function when the radix argument is not specified, you can turn this rule off.

docs/src/use/migrate-to-10.0.0.md

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,7 @@ The lists below are ordered roughly by the number of users each change is expect
1717

1818
- [Node.js < v20.19, v21, v23 are no longer supported](#drop-old-node)
1919
- [New configuration file lookup algorithm](#config-lookup-from-file)
20+
- [Deprecated options of the `radix` rule](#radix)
2021
- [`no-shadow-restricted-names` now reports `globalThis` by default](#no-shadow-restricted-names)
2122
- [`eslint:recommended` has been updated](#eslint-recommended)
2223
- [Jiti < v2.2.0 are no longer supported](#drop-old-jiti)
@@ -62,6 +63,20 @@ In ESLint v9, the alternate config lookup behavior could be enabled with the `v1
6263

6364
**Related issue(s):** [#19967](https://github.com/eslint/eslint/issues/19967)
6465

66+
## <a name="radix"></a> Deprecated options of the `radix` rule
67+
68+
As of ESLint v10.0.0, string options `"always"` and `"as-needed"` of the [`radix`](../rules/radix) rule are deprecated. Setting either of these options doesn't change the behavior of this rule, which now always enforces providing a radix, as it was the case when the `"always"` option (default) was specified. Since the default radix depends on the first argument of `parseInt()`, this rule assumes that the second argument (the radix) is always needed.
69+
70+
The default behavior of this rule has not been changed.
71+
72+
**To address:**
73+
74+
- If you are using this rule without any options specified, there is no action required.
75+
- If you are using this rule with the `"always"` option explicitly specified, remove the option. The behavior of this rule will remain the same.
76+
- If you are using this rule with the `"as-needed"` option, remove the option and update your code to always provide the second argument to the `parseInt()` function. Alternatively, you can disable this rule.
77+
78+
**Related issue(s):** [#19916](https://github.com/eslint/eslint/issues/19916)
79+
6580
## <a name="no-shadow-restricted-names"></a> `no-shadow-restricted-names` now reports `globalThis` by default
6681

6782
In ESLint v10, the [`no-shadow-restricted-names`](../rules/no-shadow-restricted-names) rule now treats `globalThis` as a restricted name by default. Consequently, the `reportGlobalThis` option now defaults to `true` (previously `false`). As a result, declarations such as `const globalThis = "foo";` or `function globalThis() {}` will now be reported by default.

lib/rules/radix.js

Lines changed: 25 additions & 48 deletions
Original file line numberDiff line numberDiff line change
@@ -15,9 +15,6 @@ const astUtils = require("./utils/ast-utils");
1515
// Helpers
1616
//------------------------------------------------------------------------------
1717

18-
const MODE_ALWAYS = "always",
19-
MODE_AS_NEEDED = "as-needed";
20-
2118
const validRadixValues = new Set(
2219
Array.from({ length: 37 - 2 }, (_, index) => index + 2),
2320
);
@@ -63,15 +60,6 @@ function isValidRadix(radix) {
6360
);
6461
}
6562

66-
/**
67-
* Checks whether a given node is a default value of radix or not.
68-
* @param {ASTNode} radix A node of radix to check.
69-
* @returns {boolean} `true` if the node is the literal node of `10`.
70-
*/
71-
function isDefaultRadix(radix) {
72-
return radix.type === "Literal" && radix.value === 10;
73-
}
74-
7563
//------------------------------------------------------------------------------
7664
// Rule Definition
7765
//------------------------------------------------------------------------------
@@ -81,26 +69,24 @@ module.exports = {
8169
meta: {
8270
type: "suggestion",
8371

84-
defaultOptions: [MODE_ALWAYS],
85-
8672
docs: {
8773
description:
88-
"Enforce the consistent use of the radix argument when using `parseInt()`",
74+
"Enforce the use of the radix argument when using `parseInt()`",
8975
recommended: false,
9076
url: "https://eslint.org/docs/latest/rules/radix",
9177
},
9278

9379
hasSuggestions: true,
9480

9581
schema: [
82+
// deprecated
9683
{
9784
enum: ["always", "as-needed"],
9885
},
9986
],
10087

10188
messages: {
10289
missingParameters: "Missing parameters.",
103-
redundantRadix: "Redundant radix parameter.",
10490
missingRadix: "Missing radix parameter.",
10591
invalidRadix:
10692
"Invalid radix parameter, must be an integer between 2 and 36.",
@@ -110,7 +96,6 @@ module.exports = {
11096
},
11197

11298
create(context) {
113-
const [mode] = context.options;
11499
const sourceCode = context.sourceCode;
115100

116101
/**
@@ -131,41 +116,33 @@ module.exports = {
131116
break;
132117

133118
case 1:
134-
if (mode === MODE_ALWAYS) {
135-
context.report({
136-
node,
137-
messageId: "missingRadix",
138-
suggest: [
139-
{
140-
messageId: "addRadixParameter10",
141-
fix(fixer) {
142-
const tokens =
143-
sourceCode.getTokens(node);
144-
const lastToken = tokens.at(-1); // Parenthesis.
145-
const secondToLastToken = tokens.at(-2); // May or may not be a comma.
146-
const hasTrailingComma =
147-
secondToLastToken.type ===
148-
"Punctuator" &&
149-
secondToLastToken.value === ",";
150-
151-
return fixer.insertTextBefore(
152-
lastToken,
153-
hasTrailingComma ? " 10," : ", 10",
154-
);
155-
},
119+
context.report({
120+
node,
121+
messageId: "missingRadix",
122+
suggest: [
123+
{
124+
messageId: "addRadixParameter10",
125+
fix(fixer) {
126+
const tokens = sourceCode.getTokens(node);
127+
const lastToken = tokens.at(-1); // Parenthesis.
128+
const secondToLastToken = tokens.at(-2); // May or may not be a comma.
129+
const hasTrailingComma =
130+
secondToLastToken.type ===
131+
"Punctuator" &&
132+
secondToLastToken.value === ",";
133+
134+
return fixer.insertTextBefore(
135+
lastToken,
136+
hasTrailingComma ? " 10," : ", 10",
137+
);
156138
},
157-
],
158-
});
159-
}
139+
},
140+
],
141+
});
160142
break;
161143

162144
default:
163-
if (mode === MODE_AS_NEEDED && isDefaultRadix(args[1])) {
164-
context.report({
165-
node,
166-
messageId: "redundantRadix",
167-
});
168-
} else if (!isValidRadix(args[1])) {
145+
if (!isValidRadix(args[1])) {
169146
context.report({
170147
node,
171148
messageId: "invalidRadix",

lib/types/rules.d.ts

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

50375037
/**
5038-
* Rule to enforce the consistent use of the radix argument when using `parseInt()`.
5038+
* Rule to enforce the use of the radix argument when using `parseInt()`.
50395039
*
50405040
* @since 0.0.7
50415041
* @see https://eslint.org/docs/latest/rules/radix

0 commit comments

Comments
 (0)