eslint 10.0.0-beta.0 → 10.0.0-rc.1

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.
@@ -53,8 +53,14 @@ module.exports = {
53
53
  description:
54
54
  "Whether to count a `this` declaration when the type is `void`.",
55
55
  },
56
+ countThis: {
57
+ enum: ["never", "except-void", "always"],
58
+ description:
59
+ "Whether to count a `this` declaration.",
60
+ },
56
61
  },
57
62
  additionalProperties: false,
63
+ not: { required: ["countVoidThis", "countThis"] },
58
64
  },
59
65
  ],
60
66
  },
@@ -68,7 +74,7 @@ module.exports = {
68
74
  const sourceCode = context.sourceCode;
69
75
  const option = context.options[0];
70
76
  let numParams = 3;
71
- let countVoidThis = false;
77
+ let countThis = "except-void";
72
78
 
73
79
  if (typeof option === "object") {
74
80
  if (
@@ -77,7 +83,12 @@ module.exports = {
77
83
  ) {
78
84
  numParams = option.maximum || option.max;
79
85
  }
80
- countVoidThis = option.countVoidThis;
86
+
87
+ countThis = option.countThis;
88
+ if (!countThis && Object.hasOwn(option, "countVoidThis")) {
89
+ countThis = option.countVoidThis ? "always" : "except-void";
90
+ }
91
+ countThis ||= "except-void";
81
92
  }
82
93
  if (typeof option === "number") {
83
94
  numParams = option;
@@ -90,17 +101,25 @@ module.exports = {
90
101
  * @private
91
102
  */
92
103
  function checkFunction(node) {
93
- const hasVoidThisParam =
104
+ const thisParam =
94
105
  node.params.length > 0 &&
95
106
  node.params[0].type === "Identifier" &&
96
- node.params[0].name === "this" &&
97
- node.params[0].typeAnnotation?.typeAnnotation.type ===
98
- "TSVoidKeyword";
107
+ node.params[0].name === "this"
108
+ ? node.params[0]
109
+ : null;
99
110
 
100
- const effectiveParamCount =
101
- hasVoidThisParam && !countVoidThis
102
- ? node.params.length - 1
103
- : node.params.length;
111
+ let effectiveParamCount = node.params.length;
112
+ if (thisParam) {
113
+ if (countThis === "never") {
114
+ effectiveParamCount = node.params.length - 1;
115
+ } else if (
116
+ countThis === "except-void" &&
117
+ thisParam.typeAnnotation?.typeAnnotation.type ===
118
+ "TSVoidKeyword"
119
+ ) {
120
+ effectiveParamCount = node.params.length - 1;
121
+ }
122
+ }
104
123
 
105
124
  if (effectiveParamCount > numParams) {
106
125
  context.report({
@@ -346,32 +346,97 @@ module.exports = {
346
346
  }
347
347
 
348
348
  /**
349
- * Checks if a variable is inside the initializer of scopeVar.
349
+ * Finds the uppermost expression node that can evaluate to the given one.
350
350
  *
351
- * To avoid reporting at declarations such as `var a = function a() {};`.
352
- * But it should report `var a = function(a) {};` or `var a = function() { function a() {} };`.
353
- * @param {Object} variable The variable to check.
354
- * @param {Object} scopeVar The scope variable to look for.
355
- * @returns {boolean} Whether or not the variable is inside initializer of scopeVar.
351
+ * Examples:
352
+ * If given `a` in `a || foo`, it returns the `a || foo` node.
353
+ * If given `a` in `foo ? a : bar`, it returns the `foo ? a : bar` node.
354
+ * If given `a` in `foo ? bar : (baz && a)`, it returns the `foo ? bar : (baz && a)` node.
355
+ * If given `a` in `a ? foo : bar`, it returns the `a` node.
356
+ * If given `a` in `foo(a)`, it returns the `a` node.
357
+ * @param {ASTNode} expression The expression node to unwrap.
358
+ * @returns {ASTNode} The uppermost ancestor that can evaluate to the given node
359
+ * or the given node if there is no such ancestor.
356
360
  */
357
- function isOnInitializer(variable, scopeVar) {
358
- const outerScope = scopeVar.scope;
359
- const outerDef = scopeVar.defs[0];
360
- const outer = outerDef && outerDef.parent && outerDef.parent.range;
361
- const innerScope = variable.scope;
362
- const innerDef = variable.defs[0];
363
- const inner = innerDef && innerDef.name.range;
361
+ function unwrapExpression(expression) {
362
+ const { parent } = expression;
364
363
 
365
- return (
366
- outer &&
367
- inner &&
368
- outer[0] < inner[0] &&
369
- inner[1] < outer[1] &&
370
- ((innerDef.type === "FunctionName" &&
371
- innerDef.node.type === "FunctionExpression") ||
372
- innerDef.node.type === "ClassExpression") &&
373
- outerScope === innerScope.upper
374
- );
364
+ const shouldUnwrap =
365
+ parent.type === "LogicalExpression" ||
366
+ (parent.type === "ConditionalExpression" &&
367
+ parent.test !== expression);
368
+
369
+ return shouldUnwrap ? unwrapExpression(parent) : expression;
370
+ }
371
+
372
+ /**
373
+ * Checks if inner variable is the name of a function or class
374
+ * that is assigned to outer variable as its initializer.
375
+ *
376
+ * To avoid reporting at declarations such as:
377
+ * var a = function a() {};
378
+ * var A = class A {};
379
+ * var a = foo || function a() {};
380
+ * var a = foo ? function a() {} : bar;
381
+ * var { a = function a() {} } = foo;
382
+ *
383
+ * But it should report at declarations such as:
384
+ * var a = function(a) {};
385
+ * var a = function() { function a() {} };
386
+ * var a = wrap(function a() {});
387
+ * @param {Object} innerVariable The inner variable to check.
388
+ * @param {Object} outerVariable The outer variable.
389
+ * @returns {boolean} Whether or not inner variable is the name of a
390
+ * function or class that is assigned to outer variable as its initializer.
391
+ */
392
+ function isFunctionNameInitializerException(
393
+ innerVariable,
394
+ outerVariable,
395
+ ) {
396
+ const outerDef = outerVariable.defs[0];
397
+ const innerDef = innerVariable.defs[0];
398
+
399
+ if (!outerDef || !innerDef) {
400
+ return false;
401
+ }
402
+
403
+ if (
404
+ !(
405
+ (innerDef.type === "FunctionName" &&
406
+ innerDef.node.type === "FunctionExpression") ||
407
+ (innerDef.type === "ClassName" &&
408
+ innerDef.node.type === "ClassExpression")
409
+ )
410
+ ) {
411
+ return false;
412
+ }
413
+
414
+ const outerIdentifier = outerDef.name;
415
+ let initializerNode;
416
+
417
+ if (outerIdentifier.parent.type === "VariableDeclarator") {
418
+ initializerNode = outerIdentifier.parent.init;
419
+ } else if (outerIdentifier.parent.type === "AssignmentPattern") {
420
+ initializerNode = outerIdentifier.parent.right;
421
+ }
422
+
423
+ if (!initializerNode) {
424
+ return false;
425
+ }
426
+
427
+ const nodeToCheck = innerDef.node; // FunctionExpression or ClassExpression node
428
+
429
+ // Exit early if the node to check isn't inside the initializer
430
+ if (
431
+ !(
432
+ initializerNode.range[0] <= nodeToCheck.range[0] &&
433
+ nodeToCheck.range[1] <= initializerNode.range[1]
434
+ )
435
+ ) {
436
+ return false;
437
+ }
438
+
439
+ return initializerNode === unwrapExpression(nodeToCheck);
375
440
  }
376
441
 
377
442
  /**
@@ -577,7 +642,7 @@ module.exports = {
577
642
  shadowed &&
578
643
  (shadowed.identifiers.length > 0 ||
579
644
  (builtinGlobals && "writeable" in shadowed)) &&
580
- !isOnInitializer(variable, shadowed) &&
645
+ !isFunctionNameInitializerException(variable, shadowed) &&
581
646
  !(
582
647
  ignoreOnInitialization &&
583
648
  isInitPatternNode(variable, shadowed)
@@ -53,7 +53,6 @@ import type {
53
53
  EcmaVersion as CoreEcmaVersion,
54
54
  ConfigOverride as CoreConfigOverride,
55
55
  ProcessorFile as CoreProcessorFile,
56
- JavaScriptParserOptionsConfig,
57
56
  RulesMeta,
58
57
  RuleConfig,
59
58
  RuleTextEditor,
@@ -71,6 +70,7 @@ import type {
71
70
  SuggestedEditBase,
72
71
  SuggestedEdit,
73
72
  ViolationReport,
73
+ MessagePlaceholderData,
74
74
  } from "@eslint/core";
75
75
 
76
76
  //------------------------------------------------------------------------------
@@ -139,7 +139,7 @@ export namespace Scope {
139
139
 
140
140
  getDeclaredVariables(node: ESTree.Node): Variable[];
141
141
 
142
- addGlobals(names: string[]): void;
142
+ addGlobals(names: ReadonlyArray<string>): void;
143
143
  }
144
144
 
145
145
  interface Scope {
@@ -155,8 +155,7 @@ export namespace Scope {
155
155
  | "global"
156
156
  | "module"
157
157
  | "switch"
158
- | "with"
159
- | "TDZ";
158
+ | "with";
160
159
  isStrict: boolean;
161
160
  upper: Scope | null;
162
161
  childScopes: Scope[];
@@ -185,8 +184,8 @@ export namespace Scope {
185
184
  identifier: ESTree.Identifier | JSXIdentifier;
186
185
  from: Scope;
187
186
  resolved: Variable | null;
188
- writeExpr: ESTree.Node | null;
189
- init: boolean;
187
+ writeExpr?: ESTree.Expression | null;
188
+ init?: boolean;
190
189
 
191
190
  isWrite(): boolean;
192
191
 
@@ -235,7 +234,6 @@ export namespace Scope {
235
234
  | ESTree.ArrowFunctionExpression;
236
235
  parent: null;
237
236
  }
238
- | { type: "TDZ"; node: any; parent: null }
239
237
  | {
240
238
  type: "Variable";
241
239
  node: ESTree.VariableDeclarator;
@@ -812,23 +810,23 @@ export class Linter {
812
810
 
813
811
  verify(
814
812
  code: SourceCode | string,
815
- config: Linter.LegacyConfig | Linter.Config | Linter.Config[],
813
+ config: Linter.Config | Linter.Config[],
816
814
  filename?: string,
817
815
  ): Linter.LintMessage[];
818
816
  verify(
819
817
  code: SourceCode | string,
820
- config: Linter.LegacyConfig | Linter.Config | Linter.Config[],
818
+ config: Linter.Config | Linter.Config[],
821
819
  options: Linter.LintOptions,
822
820
  ): Linter.LintMessage[];
823
821
 
824
822
  verifyAndFix(
825
823
  code: string,
826
- config: Linter.LegacyConfig | Linter.Config | Linter.Config[],
824
+ config: Linter.Config | Linter.Config[],
827
825
  filename?: string,
828
826
  ): Linter.FixReport;
829
827
  verifyAndFix(
830
828
  code: string,
831
- config: Linter.LegacyConfig | Linter.Config | Linter.Config[],
829
+ config: Linter.Config | Linter.Config[],
832
830
  options: Linter.FixOptions,
833
831
  ): Linter.FixReport;
834
832
 
@@ -935,7 +933,43 @@ export namespace Linter {
935
933
  *
936
934
  * @see [Specifying Parser Options](https://eslint.org/docs/latest/use/configure/language-options#specifying-parser-options)
937
935
  */
938
- type ParserOptions = JavaScriptParserOptionsConfig;
936
+ interface ParserOptions {
937
+ /**
938
+ * Allow the use of reserved words as identifiers (if `ecmaVersion` is 3).
939
+ *
940
+ * @default false
941
+ */
942
+ allowReserved?: boolean | undefined;
943
+ /**
944
+ * An object indicating which additional language features you'd like to use.
945
+ *
946
+ * @see https://eslint.org/docs/latest/use/configure/language-options#specifying-parser-options
947
+ */
948
+ ecmaFeatures?:
949
+ | {
950
+ /**
951
+ * Allow `return` statements in the global scope.
952
+ *
953
+ * @default false
954
+ */
955
+ globalReturn?: boolean | undefined;
956
+ /**
957
+ * Enable global [strict mode](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Strict_mode) (if `ecmaVersion` is 5 or greater).
958
+ *
959
+ * @default false
960
+ */
961
+ impliedStrict?: boolean | undefined;
962
+ /**
963
+ * Enable [JSX](https://facebook.github.io/jsx/).
964
+ *
965
+ * @default false
966
+ */
967
+ jsx?: boolean | undefined;
968
+ [key: string]: any;
969
+ }
970
+ | undefined;
971
+ [key: string]: any;
972
+ }
939
973
 
940
974
  /**
941
975
  * Options used for linting code with `Linter#verify` and `Linter#verifyAndFix`.
@@ -1386,6 +1420,12 @@ export class RuleTester {
1386
1420
  * error does not contain them.
1387
1421
  */
1388
1422
  requireLocation?: boolean;
1423
+ /**
1424
+ * If true, each error and suggestion with a `messageId` must specify a `data`
1425
+ * property if the referenced message contains placeholders.
1426
+ * `"error"` and `"suggestion" limit the assertion to errors and suggestions respectively.
1427
+ */
1428
+ requireData?: boolean | "error" | "suggestion";
1389
1429
  };
1390
1430
  },
1391
1431
  ): void;
@@ -1419,7 +1459,7 @@ export namespace RuleTester {
1419
1459
  interface SuggestionOutput {
1420
1460
  messageId?: string;
1421
1461
  desc?: string;
1422
- data?: Record<string, unknown> | undefined;
1462
+ data?: MessagePlaceholderData | undefined;
1423
1463
  output: string;
1424
1464
  }
1425
1465
 
@@ -1431,7 +1471,7 @@ export namespace RuleTester {
1431
1471
  interface TestCaseError {
1432
1472
  message?: string | RegExp;
1433
1473
  messageId?: string;
1434
- data?: any;
1474
+ data?: MessagePlaceholderData | undefined;
1435
1475
  line?: number | undefined;
1436
1476
  column?: number | undefined;
1437
1477
  endLine?: number | undefined;
@@ -1858,9 +1858,14 @@ export interface ESLintRules extends Linter.RulesRecord {
1858
1858
  */
1859
1859
  max: number;
1860
1860
  /**
1861
+ * @deprecated Replaced with `countThis'
1861
1862
  * @default false
1862
1863
  */
1863
1864
  countVoidThis: boolean;
1865
+ /**
1866
+ * @default "except-void"
1867
+ */
1868
+ countThis: "always" | "never" | "except-void";
1864
1869
  }>,
1865
1870
  ]
1866
1871
  >;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "eslint",
3
- "version": "10.0.0-beta.0",
3
+ "version": "10.0.0-rc.1",
4
4
  "author": "Nicholas C. Zakas <nicholas+npm@nczconsulting.com>",
5
5
  "description": "An AST-based pattern checker for JavaScript.",
6
6
  "type": "commonjs",
@@ -109,9 +109,9 @@
109
109
  "@eslint-community/eslint-utils": "^4.8.0",
110
110
  "@eslint-community/regexpp": "^4.12.2",
111
111
  "@eslint/config-array": "^0.23.0",
112
- "@eslint/config-helpers": "^0.5.0",
113
- "@eslint/core": "^1.0.0",
114
- "@eslint/plugin-kit": "^0.5.0",
112
+ "@eslint/config-helpers": "^0.5.1",
113
+ "@eslint/core": "^1.0.1",
114
+ "@eslint/plugin-kit": "^0.5.1",
115
115
  "@humanfs/node": "^0.16.6",
116
116
  "@humanwhocodes/module-importer": "^1.0.1",
117
117
  "@humanwhocodes/retry": "^0.4.2",
@@ -120,9 +120,9 @@
120
120
  "cross-spawn": "^7.0.6",
121
121
  "debug": "^4.3.2",
122
122
  "escape-string-regexp": "^4.0.0",
123
- "eslint-scope": "^9.0.0",
123
+ "eslint-scope": "^9.1.0",
124
124
  "eslint-visitor-keys": "^5.0.0",
125
- "espree": "^11.0.0",
125
+ "espree": "^11.1.0",
126
126
  "esquery": "^1.5.0",
127
127
  "esutils": "^2.0.2",
128
128
  "fast-deep-equal": "^3.1.3",
@@ -193,7 +193,7 @@
193
193
  "semver": "^7.5.3",
194
194
  "shelljs": "^0.10.0",
195
195
  "sinon": "^11.0.0",
196
- "typescript": "^5.3.3",
196
+ "typescript": "^5.9.3",
197
197
  "webpack": "^5.23.0",
198
198
  "webpack-cli": "^4.5.0",
199
199
  "yorkie": "^2.0.0"
@@ -1,71 +0,0 @@
1
- /**
2
- * @fileoverview Defines a storage for rules.
3
- * @author Nicholas C. Zakas
4
- * @author aladdin-add
5
- */
6
-
7
- "use strict";
8
-
9
- //------------------------------------------------------------------------------
10
- // Requirements
11
- //------------------------------------------------------------------------------
12
-
13
- const builtInRules = require("../rules");
14
-
15
- //------------------------------------------------------------------------------
16
- // Typedefs
17
- //------------------------------------------------------------------------------
18
-
19
- /** @typedef {import("../types").Rule.RuleModule} Rule */
20
-
21
- //------------------------------------------------------------------------------
22
- // Public Interface
23
- //------------------------------------------------------------------------------
24
-
25
- /**
26
- * A storage for rules.
27
- */
28
- class Rules {
29
- constructor() {
30
- this._rules = Object.create(null);
31
- }
32
-
33
- /**
34
- * Registers a rule module for rule id in storage.
35
- * @param {string} ruleId Rule id (file name).
36
- * @param {Rule} rule Rule object.
37
- * @returns {void}
38
- */
39
- define(ruleId, rule) {
40
- this._rules[ruleId] = rule;
41
- }
42
-
43
- /**
44
- * Access rule handler by id (file name).
45
- * @param {string} ruleId Rule id (file name).
46
- * @returns {Rule} Rule object.
47
- */
48
- get(ruleId) {
49
- if (typeof this._rules[ruleId] === "string") {
50
- this.define(ruleId, require(this._rules[ruleId]));
51
- }
52
- if (this._rules[ruleId]) {
53
- return this._rules[ruleId];
54
- }
55
- if (builtInRules.has(ruleId)) {
56
- return builtInRules.get(ruleId);
57
- }
58
-
59
- return null;
60
- }
61
-
62
- *[Symbol.iterator]() {
63
- yield* builtInRules;
64
-
65
- for (const ruleId of Object.keys(this._rules)) {
66
- yield [ruleId, this.get(ruleId)];
67
- }
68
- }
69
- }
70
-
71
- module.exports = Rules;