eslint 9.26.0 → 9.27.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -34,6 +34,8 @@ module.exports = {
34
34
  url: "https://eslint.org/docs/latest/rules/no-array-constructor",
35
35
  },
36
36
 
37
+ fixable: "code",
38
+
37
39
  hasSuggestions: true,
38
40
 
39
41
  schema: [],
@@ -49,6 +51,30 @@ module.exports = {
49
51
  create(context) {
50
52
  const sourceCode = context.sourceCode;
51
53
 
54
+ /**
55
+ * Checks if there are comments in Array constructor expressions.
56
+ * @param {ASTNode} node A CallExpression or NewExpression node.
57
+ * @returns {boolean} True if there are comments, false otherwise.
58
+ */
59
+ function hasCommentsInArrayConstructor(node) {
60
+ const firstToken = sourceCode.getFirstToken(node);
61
+ const lastToken = sourceCode.getLastToken(node);
62
+
63
+ let lastRelevantToken = sourceCode.getLastToken(node.callee);
64
+
65
+ while (
66
+ lastRelevantToken !== lastToken &&
67
+ !isOpeningParenToken(lastRelevantToken)
68
+ ) {
69
+ lastRelevantToken = sourceCode.getTokenAfter(lastRelevantToken);
70
+ }
71
+
72
+ return sourceCode.commentsExistBetween(
73
+ firstToken,
74
+ lastRelevantToken,
75
+ );
76
+ }
77
+
52
78
  /**
53
79
  * Gets the text between the calling parentheses of a CallExpression or NewExpression.
54
80
  * @param {ASTNode} node A CallExpression or NewExpression node.
@@ -107,6 +133,17 @@ module.exports = {
107
133
  let fixText;
108
134
  let messageId;
109
135
 
136
+ const nonSpreadCount = node.arguments.reduce(
137
+ (count, arg) =>
138
+ arg.type !== "SpreadElement" ? count + 1 : count,
139
+ 0,
140
+ );
141
+
142
+ const shouldSuggest =
143
+ node.optional ||
144
+ (node.arguments.length > 0 && nonSpreadCount < 2) ||
145
+ hasCommentsInArrayConstructor(node);
146
+
110
147
  /*
111
148
  * Check if the suggested change should include a preceding semicolon or not.
112
149
  * Due to JavaScript's ASI rules, a missing semicolon may be inserted automatically
@@ -127,10 +164,23 @@ module.exports = {
127
164
  context.report({
128
165
  node,
129
166
  messageId: "preferLiteral",
167
+ fix(fixer) {
168
+ if (shouldSuggest) {
169
+ return null;
170
+ }
171
+
172
+ return fixer.replaceText(node, fixText);
173
+ },
130
174
  suggest: [
131
175
  {
132
176
  messageId,
133
- fix: fixer => fixer.replaceText(node, fixText),
177
+ fix(fixer) {
178
+ if (shouldSuggest) {
179
+ return fixer.replaceText(node, fixText);
180
+ }
181
+
182
+ return null;
183
+ },
134
184
  },
135
185
  ],
136
186
  });
@@ -0,0 +1,72 @@
1
+ /**
2
+ * @fileoverview Rule to flag variables that are never assigned
3
+ * @author Jacob Bandes-Storch <https://github.com/jtbandes>
4
+ */
5
+ "use strict";
6
+
7
+ //------------------------------------------------------------------------------
8
+ // Rule Definition
9
+ //------------------------------------------------------------------------------
10
+
11
+ /** @type {import('../types').Rule.RuleModule} */
12
+ module.exports = {
13
+ meta: {
14
+ type: "problem",
15
+ dialects: ["typescript", "javascript"],
16
+ language: "javascript",
17
+
18
+ docs: {
19
+ description:
20
+ "Disallow `let` or `var` variables that are read but never assigned",
21
+ recommended: false,
22
+ url: "https://eslint.org/docs/latest/rules/no-unassigned-vars",
23
+ },
24
+
25
+ schema: [],
26
+ messages: {
27
+ unassigned:
28
+ "'{{name}}' is always 'undefined' because it's never assigned.",
29
+ },
30
+ },
31
+
32
+ create(context) {
33
+ const sourceCode = context.sourceCode;
34
+
35
+ return {
36
+ VariableDeclarator(node) {
37
+ /** @type {import('estree').VariableDeclaration} */
38
+ const declaration = node.parent;
39
+ const shouldCheck =
40
+ !node.init &&
41
+ node.id.type === "Identifier" &&
42
+ declaration.kind !== "const" &&
43
+ !declaration.declare;
44
+ if (!shouldCheck) {
45
+ return;
46
+ }
47
+ const [variable] = sourceCode.getDeclaredVariables(node);
48
+ if (!variable) {
49
+ return;
50
+ }
51
+ let hasRead = false;
52
+ for (const reference of variable.references) {
53
+ if (reference.isWrite()) {
54
+ return;
55
+ }
56
+ if (reference.isRead()) {
57
+ hasRead = true;
58
+ }
59
+ }
60
+ if (!hasRead) {
61
+ // Variables that are never read should be flagged by no-unused-vars instead
62
+ return;
63
+ }
64
+ context.report({
65
+ node,
66
+ messageId: "unassigned",
67
+ data: { name: node.id.name },
68
+ });
69
+ },
70
+ };
71
+ },
72
+ };
@@ -60,6 +60,12 @@ module.exports = {
60
60
  meta: {
61
61
  type: "suggestion",
62
62
 
63
+ defaultOptions: [
64
+ {
65
+ allowRegexCharacters: [],
66
+ },
67
+ ],
68
+
63
69
  docs: {
64
70
  description: "Disallow unnecessary escape characters",
65
71
  recommended: true,
@@ -78,11 +84,26 @@ module.exports = {
78
84
  "Replace the `\\` with `\\\\` to include the actual backslash character.",
79
85
  },
80
86
 
81
- schema: [],
87
+ schema: [
88
+ {
89
+ type: "object",
90
+ properties: {
91
+ allowRegexCharacters: {
92
+ type: "array",
93
+ items: {
94
+ type: "string",
95
+ },
96
+ uniqueItems: true,
97
+ },
98
+ },
99
+ additionalProperties: false,
100
+ },
101
+ ],
82
102
  },
83
103
 
84
104
  create(context) {
85
105
  const sourceCode = context.sourceCode;
106
+ const [{ allowRegexCharacters }] = context.options;
86
107
  const parser = new RegExpParser();
87
108
 
88
109
  /**
@@ -217,7 +238,8 @@ module.exports = {
217
238
 
218
239
  if (
219
240
  escapedChar !==
220
- String.fromCodePoint(characterNode.value)
241
+ String.fromCodePoint(characterNode.value) ||
242
+ allowRegexCharacters.includes(escapedChar)
221
243
  ) {
222
244
  // It's a valid escape.
223
245
  return;
@@ -17,6 +17,12 @@ const {
17
17
  } = require("@eslint-community/eslint-utils");
18
18
  const regexpp = require("@eslint-community/regexpp");
19
19
 
20
+ //------------------------------------------------------------------------------
21
+ // Typedefs
22
+ //------------------------------------------------------------------------------
23
+
24
+ /** @import { SuggestedEdit } from "@eslint/core"; */
25
+
20
26
  //------------------------------------------------------------------------------
21
27
  // Helpers
22
28
  //------------------------------------------------------------------------------
@@ -29,7 +35,7 @@ const parser = new regexpp.RegExpParser();
29
35
  * @param {string} pattern The regular expression pattern to be checked.
30
36
  * @param {string} rawText Source text of the regexNode.
31
37
  * @param {ASTNode} regexNode AST node which contains the regular expression.
32
- * @returns {Array<SuggestionResult>} Fixer suggestions for the regex, if statically determinable.
38
+ * @returns {Array<SuggestedEdit>} Fixer suggestions for the regex, if statically determinable.
33
39
  */
34
40
  function suggestIfPossible(groupStart, pattern, rawText, regexNode) {
35
41
  switch (regexNode.type) {
@@ -17,7 +17,7 @@ const { VFile } = require("../linter/vfile.js");
17
17
  // Types
18
18
  //-----------------------------------------------------------------------------
19
19
 
20
- /** @typedef {import("../shared/types.js").LintMessage} LintMessage */
20
+ /** @typedef {import("../types").Linter.LintMessage} LintMessage */
21
21
  /** @typedef {import("../linter/vfile.js").VFile} VFile */
22
22
  /** @typedef {import("@eslint/core").Language} Language */
23
23
  /** @typedef {import("eslint").Linter.Processor} Processor */
@@ -12,14 +12,16 @@
12
12
  const fs = require("node:fs");
13
13
  const path = require("node:path");
14
14
  const { calculateStatsPerFile } = require("../eslint/eslint-helpers");
15
+ const stringify = require("json-stable-stringify-without-jsonify");
15
16
 
16
17
  //------------------------------------------------------------------------------
17
18
  // Typedefs
18
19
  //------------------------------------------------------------------------------
19
20
 
20
21
  // For VSCode IntelliSense
21
- /** @typedef {import("../shared/types").LintResult} LintResult */
22
- /** @typedef {import("../shared/types").SuppressedViolations} SuppressedViolations */
22
+ /** @typedef {import("../types").Linter.LintMessage} LintMessage */
23
+ /** @typedef {import("../types").ESLint.LintResult} LintResult */
24
+ /** @typedef {Record<string, Record<string, { count: number; }>>} SuppressedViolations */
23
25
 
24
26
  //-----------------------------------------------------------------------------
25
27
  // Exports
@@ -224,7 +226,7 @@ class SuppressionsService {
224
226
  save(suppressions) {
225
227
  return fs.promises.writeFile(
226
228
  this.filePath,
227
- JSON.stringify(suppressions, null, 2),
229
+ stringify(suppressions, { space: 2 }),
228
230
  );
229
231
  }
230
232
 
@@ -27,6 +27,7 @@
27
27
  */
28
28
  const activeFlags = new Map([
29
29
  ["test_only", "Used only for testing."],
30
+ ["test_only_2", "Used only for testing."],
30
31
  [
31
32
  "unstable_config_lookup_from_file",
32
33
  "Look up `eslint.config.js` from the file being linted.",
@@ -1560,9 +1560,16 @@ export namespace Linter {
1560
1560
  /**
1561
1561
  * Parser options.
1562
1562
  *
1563
- * @see [Specifying Parser Options](https://eslint.org/docs/latest/use/configure/language-options-deprecated#specifying-parser-options)
1563
+ * @see [Specifying Parser Options](https://eslint.org/docs/latest/use/configure/language-options#specifying-parser-options)
1564
1564
  */
1565
1565
  interface ParserOptions {
1566
+ /**
1567
+ * Allow the use of reserved words as identifiers (if `ecmaVersion` is 3).
1568
+ *
1569
+ * @default false
1570
+ */
1571
+ allowReserved?: boolean | undefined;
1572
+
1566
1573
  /**
1567
1574
  * Accepts any valid ECMAScript version number or `'latest'`:
1568
1575
  *
@@ -1619,26 +1626,54 @@ export namespace Linter {
1619
1626
  }
1620
1627
 
1621
1628
  interface LintSuggestion {
1629
+ /** A short description. */
1622
1630
  desc: string;
1631
+
1632
+ /** Fix result info. */
1623
1633
  fix: Rule.Fix;
1634
+
1635
+ /** Id referencing a message for the description. */
1624
1636
  messageId?: string | undefined;
1625
1637
  }
1626
1638
 
1627
1639
  interface LintMessage {
1640
+ /** The 1-based column number. */
1628
1641
  column: number;
1642
+
1643
+ /** The 1-based line number. */
1629
1644
  line: number;
1645
+
1646
+ /** The 1-based column number of the end location. */
1630
1647
  endColumn?: number | undefined;
1648
+
1649
+ /** The 1-based line number of the end location. */
1631
1650
  endLine?: number | undefined;
1651
+
1652
+ /** The ID of the rule which makes this message. */
1632
1653
  ruleId: string | null;
1654
+
1655
+ /** The reported message. */
1633
1656
  message: string;
1657
+
1658
+ /** The ID of the message in the rule's meta. */
1634
1659
  messageId?: string | undefined;
1660
+
1635
1661
  /**
1662
+ * Type of node.
1636
1663
  * @deprecated `nodeType` is deprecated and will be removed in the next major version.
1637
1664
  */
1638
1665
  nodeType?: string | undefined;
1666
+
1667
+ /** If `true` then this is a fatal error. */
1639
1668
  fatal?: true | undefined;
1669
+
1670
+ /** The severity of this message. */
1640
1671
  severity: Exclude<Severity, 0>;
1672
+
1673
+ /** Information for autofix. */
1641
1674
  fix?: Rule.Fix | undefined;
1675
+
1676
+ /** Information for suggestions. */
1642
1677
  suggestions?: LintSuggestion[] | undefined;
1643
1678
  }
1644
1679
 
@@ -1648,6 +1683,7 @@ export namespace Linter {
1648
1683
  }
1649
1684
 
1650
1685
  interface SuppressedLintMessage extends LintMessage {
1686
+ /** The suppression info. */
1651
1687
  suppressions: LintSuppression[];
1652
1688
  }
1653
1689
 
@@ -1661,8 +1697,8 @@ export namespace Linter {
1661
1697
  messages: LintMessage[];
1662
1698
  }
1663
1699
 
1664
- // Temporarily loosen type for just flat config files (see #68232)
1665
- type NonESTreeParser = Omit<ESTreeParser, "parseForESLint"> &
1700
+ // Temporarily loosen type for just flat config files (see https://github.com/DefinitelyTyped/DefinitelyTyped/pull/68232)
1701
+ type NonESTreeParser = ESLint.ObjectMetaProperties &
1666
1702
  (
1667
1703
  | {
1668
1704
  parse(text: string, options?: any): unknown;
@@ -1687,9 +1723,16 @@ export namespace Linter {
1687
1723
  type Parser = NonESTreeParser | ESTreeParser;
1688
1724
 
1689
1725
  interface ESLintParseResult {
1726
+ /** The AST object. */
1690
1727
  ast: AST.Program;
1691
- parserServices?: SourceCode.ParserServices | undefined;
1728
+
1729
+ /** The services that the parser provides. */
1730
+ services?: SourceCode.ParserServices | undefined;
1731
+
1732
+ /** The scope manager of the AST. */
1692
1733
  scopeManager?: Scope.ScopeManager | undefined;
1734
+
1735
+ /** The visitor keys of the AST. */
1693
1736
  visitorKeys?: SourceCode.VisitorKeys | undefined;
1694
1737
  }
1695
1738
 
@@ -1702,8 +1745,13 @@ export namespace Linter {
1702
1745
  interface Processor<
1703
1746
  T extends string | ProcessorFile = string | ProcessorFile,
1704
1747
  > extends ESLint.ObjectMetaProperties {
1748
+ /** If `true` then it means the processor supports autofix. */
1705
1749
  supportsAutofix?: boolean | undefined;
1750
+
1751
+ /** The function to extract code blocks. */
1706
1752
  preprocess?(text: string, filename: string): T[];
1753
+
1754
+ /** The function to merge messages. */
1707
1755
  postprocess?(
1708
1756
  messages: LintMessage[][],
1709
1757
  filename: string,
@@ -1844,6 +1892,9 @@ export namespace Linter {
1844
1892
  reportUnusedInlineConfigs?: Severity | StringSeverity;
1845
1893
  }
1846
1894
 
1895
+ /**
1896
+ * Performance statistics.
1897
+ */
1847
1898
  interface Stats {
1848
1899
  /**
1849
1900
  * The number of times ESLint has applied at least one fix after linting.
@@ -1857,9 +1908,24 @@ export namespace Linter {
1857
1908
  }
1858
1909
 
1859
1910
  interface TimePass {
1911
+ /**
1912
+ * The parse object containing all parse time information.
1913
+ */
1860
1914
  parse: { total: number };
1915
+
1916
+ /**
1917
+ * The rules object containing all lint time information for each rule.
1918
+ */
1861
1919
  rules?: Record<string, { total: number }>;
1920
+
1921
+ /**
1922
+ * The fix object containing all fix time information.
1923
+ */
1862
1924
  fix: { total: number };
1925
+
1926
+ /**
1927
+ * The total time that is spent on (parsing, fixing, linting) a file.
1928
+ */
1863
1929
  total: number;
1864
1930
  }
1865
1931
  }
@@ -1915,7 +1981,10 @@ export namespace ESLint {
1915
1981
  Omit<Linter.LegacyConfig<Rules>, "$schema">;
1916
1982
 
1917
1983
  interface Environment {
1984
+ /** The definition of global variables. */
1918
1985
  globals?: Linter.Globals | undefined;
1986
+
1987
+ /** The parser options that will be enabled under this environment. */
1919
1988
  parserOptions?: Linter.ParserOptions | undefined;
1920
1989
  }
1921
1990
 
@@ -2022,21 +2091,48 @@ export namespace ESLint {
2022
2091
  flags?: string[] | undefined;
2023
2092
  }
2024
2093
 
2094
+ /** A linting result. */
2025
2095
  interface LintResult {
2096
+ /** The path to the file that was linted. */
2026
2097
  filePath: string;
2098
+
2099
+ /** All of the messages for the result. */
2027
2100
  messages: Linter.LintMessage[];
2101
+
2102
+ /** All of the suppressed messages for the result. */
2028
2103
  suppressedMessages: Linter.SuppressedLintMessage[];
2104
+
2105
+ /** Number of errors for the result. */
2029
2106
  errorCount: number;
2107
+
2108
+ /** Number of fatal errors for the result. */
2030
2109
  fatalErrorCount: number;
2110
+
2111
+ /** Number of warnings for the result. */
2031
2112
  warningCount: number;
2113
+
2114
+ /** Number of fixable errors for the result. */
2032
2115
  fixableErrorCount: number;
2116
+
2117
+ /** Number of fixable warnings for the result. */
2033
2118
  fixableWarningCount: number;
2119
+
2120
+ /** The source code of the file that was linted, with as many fixes applied as possible. */
2034
2121
  output?: string | undefined;
2122
+
2123
+ /** The source code of the file that was linted. */
2035
2124
  source?: string | undefined;
2125
+
2126
+ /** The performance statistics collected with the `stats` flag. */
2036
2127
  stats?: Linter.Stats | undefined;
2128
+
2129
+ /** The list of used deprecated rules. */
2037
2130
  usedDeprecatedRules: DeprecatedRuleUse[];
2038
2131
  }
2039
2132
 
2133
+ /**
2134
+ * Information provided when the maximum warning threshold is exceeded.
2135
+ */
2040
2136
  interface MaxWarningsExceeded {
2041
2137
  /**
2042
2138
  * Number of warnings to trigger nonzero exit code.
@@ -2057,12 +2153,34 @@ export namespace ESLint {
2057
2153
  };
2058
2154
  }
2059
2155
 
2156
+ /**
2157
+ * Information about deprecated rules.
2158
+ */
2060
2159
  interface DeprecatedRuleUse {
2160
+ /**
2161
+ * The rule ID.
2162
+ */
2061
2163
  ruleId: string;
2164
+
2165
+ /**
2166
+ * The rule IDs that replace this deprecated rule.
2167
+ */
2062
2168
  replacedBy: string[];
2169
+
2170
+ /**
2171
+ * The raw deprecated info provided by the rule.
2172
+ * Unset if the rule's `meta.deprecated` property is a boolean.
2173
+ */
2174
+ info?: DeprecatedInfo;
2063
2175
  }
2064
2176
 
2177
+ /**
2178
+ * Metadata about results for formatters.
2179
+ */
2065
2180
  interface ResultsMeta {
2181
+ /**
2182
+ * Present if the maxWarnings threshold was exceeded.
2183
+ */
2066
2184
  maxWarningsExceeded?: MaxWarningsExceeded | undefined;
2067
2185
  }
2068
2186
 
@@ -1800,6 +1800,10 @@ export interface ESLintRules extends Linter.RulesRecord {
1800
1800
  * @default 3
1801
1801
  */
1802
1802
  max: number;
1803
+ /**
1804
+ * @default false
1805
+ */
1806
+ countVoidThis: boolean;
1803
1807
  }>
1804
1808
  | number,
1805
1809
  ]
@@ -3710,6 +3714,14 @@ export interface ESLintRules extends Linter.RulesRecord {
3710
3714
  ]
3711
3715
  >;
3712
3716
 
3717
+ /**
3718
+ * Rule to disallow `let` or `var` variables that are read but never assigned.
3719
+ *
3720
+ * @since 9.27.0
3721
+ * @see https://eslint.org/docs/latest/rules/no-unassigned-vars
3722
+ */
3723
+ "no-unassigned-vars": Linter.RuleEntry<[]>;
3724
+
3713
3725
  /**
3714
3726
  * Rule to disallow the use of undeclared variables unless mentioned in \/*global *\/ comments.
3715
3727
  *
@@ -4130,7 +4142,13 @@ export interface ESLintRules extends Linter.RulesRecord {
4130
4142
  * @since 2.5.0
4131
4143
  * @see https://eslint.org/docs/latest/rules/no-useless-escape
4132
4144
  */
4133
- "no-useless-escape": Linter.RuleEntry<[]>;
4145
+ "no-useless-escape": Linter.RuleEntry<
4146
+ [
4147
+ Partial<{
4148
+ allowRegexCharacters: string[];
4149
+ }>,
4150
+ ]
4151
+ >;
4134
4152
 
4135
4153
  /**
4136
4154
  * Rule to disallow renaming import, export, and destructured assignments to the same name.
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "eslint",
3
- "version": "9.26.0",
3
+ "version": "9.27.0",
4
4
  "author": "Nicholas C. Zakas <nicholas+npm@nczconsulting.com>",
5
5
  "description": "An AST-based pattern checker for JavaScript.",
6
6
  "type": "commonjs",
@@ -108,14 +108,13 @@
108
108
  "@eslint-community/regexpp": "^4.12.1",
109
109
  "@eslint/config-array": "^0.20.0",
110
110
  "@eslint/config-helpers": "^0.2.1",
111
- "@eslint/core": "^0.13.0",
111
+ "@eslint/core": "^0.14.0",
112
112
  "@eslint/eslintrc": "^3.3.1",
113
- "@eslint/js": "9.26.0",
114
- "@eslint/plugin-kit": "^0.2.8",
113
+ "@eslint/js": "9.27.0",
114
+ "@eslint/plugin-kit": "^0.3.1",
115
115
  "@humanfs/node": "^0.16.6",
116
116
  "@humanwhocodes/module-importer": "^1.0.1",
117
117
  "@humanwhocodes/retry": "^0.4.2",
118
- "@modelcontextprotocol/sdk": "^1.8.0",
119
118
  "@types/estree": "^1.0.6",
120
119
  "@types/json-schema": "^7.0.15",
121
120
  "ajv": "^6.12.4",
@@ -139,11 +138,10 @@
139
138
  "lodash.merge": "^4.6.2",
140
139
  "minimatch": "^3.1.2",
141
140
  "natural-compare": "^1.4.0",
142
- "optionator": "^0.9.3",
143
- "zod": "^3.24.2"
141
+ "optionator": "^0.9.3"
144
142
  },
145
143
  "devDependencies": {
146
- "@arethetypeswrong/cli": "^0.17.0",
144
+ "@arethetypeswrong/cli": "^0.18.0",
147
145
  "@babel/core": "^7.4.3",
148
146
  "@babel/preset-env": "^7.4.3",
149
147
  "@cypress/webpack-preprocessor": "^6.0.2",