eslint 9.27.0 → 9.29.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.
Files changed (37) hide show
  1. package/README.md +1 -1
  2. package/conf/ecma-version.js +1 -1
  3. package/conf/globals.js +10 -0
  4. package/lib/cli.js +20 -23
  5. package/lib/config/config-loader.js +32 -21
  6. package/lib/config/config.js +34 -11
  7. package/lib/eslint/eslint.js +18 -21
  8. package/lib/languages/js/source-code/source-code.js +104 -27
  9. package/lib/linter/apply-disable-directives.js +2 -4
  10. package/lib/linter/code-path-analysis/code-path-analyzer.js +8 -9
  11. package/lib/linter/linter.js +30 -61
  12. package/lib/linter/source-code-traverser.js +327 -0
  13. package/lib/linter/source-code-visitor.js +81 -0
  14. package/lib/options.js +7 -0
  15. package/lib/rules/class-methods-use-this.js +7 -0
  16. package/lib/rules/func-style.js +57 -7
  17. package/lib/rules/no-implicit-globals.js +31 -15
  18. package/lib/rules/no-magic-numbers.js +98 -5
  19. package/lib/rules/no-promise-executor-return.js +4 -35
  20. package/lib/rules/no-restricted-globals.js +35 -2
  21. package/lib/rules/no-restricted-properties.js +24 -10
  22. package/lib/rules/no-setter-return.js +13 -48
  23. package/lib/rules/no-shadow.js +262 -6
  24. package/lib/rules/no-unassigned-vars.js +14 -6
  25. package/lib/rules/no-use-before-define.js +99 -1
  26. package/lib/rules/no-var.js +14 -2
  27. package/lib/rules/prefer-arrow-callback.js +9 -0
  28. package/lib/rules/prefer-regex-literals.js +1 -18
  29. package/lib/services/suppressions-service.js +8 -0
  30. package/lib/services/warning-service.js +85 -0
  31. package/lib/shared/naming.js +109 -0
  32. package/lib/shared/relative-module-resolver.js +28 -0
  33. package/lib/types/index.d.ts +18 -7
  34. package/lib/types/rules.d.ts +52 -2
  35. package/package.json +12 -10
  36. package/lib/linter/node-event-generator.js +0 -256
  37. package/lib/linter/safe-emitter.js +0 -52
@@ -151,6 +151,8 @@ function hasDuplicateParams(paramsList) {
151
151
  module.exports = {
152
152
  meta: {
153
153
  type: "suggestion",
154
+ dialects: ["javascript", "typescript"],
155
+ language: "javascript",
154
156
 
155
157
  defaultOptions: [
156
158
  { allowNamedFunctions: false, allowUnboundThis: true },
@@ -308,6 +310,13 @@ module.exports = {
308
310
  return;
309
311
  }
310
312
 
313
+ if (
314
+ node.params.length &&
315
+ node.params[0].name === "this"
316
+ ) {
317
+ return;
318
+ }
319
+
311
320
  // Remove `.bind(this)` if exists.
312
321
  if (callbackInfo.isLexicalThis) {
313
322
  const memberNode = node.parent;
@@ -14,7 +14,6 @@ const {
14
14
  CALL,
15
15
  CONSTRUCT,
16
16
  ReferenceTracker,
17
- findVariable,
18
17
  } = require("@eslint-community/eslint-utils");
19
18
  const {
20
19
  RegExpValidator,
@@ -167,22 +166,6 @@ module.exports = {
167
166
  const [{ disallowRedundantWrapping }] = context.options;
168
167
  const sourceCode = context.sourceCode;
169
168
 
170
- /**
171
- * Determines whether the given identifier node is a reference to a global variable.
172
- * @param {ASTNode} node `Identifier` node to check.
173
- * @returns {boolean} True if the identifier is a reference to a global variable.
174
- */
175
- function isGlobalReference(node) {
176
- const scope = sourceCode.getScope(node);
177
- const variable = findVariable(scope, node);
178
-
179
- return (
180
- variable !== null &&
181
- variable.scope.type === "global" &&
182
- variable.defs.length === 0
183
- );
184
- }
185
-
186
169
  /**
187
170
  * Determines whether the given node is a String.raw`` tagged template expression
188
171
  * with a static template literal.
@@ -193,7 +176,7 @@ module.exports = {
193
176
  return (
194
177
  node.type === "TaggedTemplateExpression" &&
195
178
  astUtils.isSpecificMemberAccess(node.tag, "String", "raw") &&
196
- isGlobalReference(
179
+ sourceCode.isGlobalReference(
197
180
  astUtils.skipChainExpression(node.tag).object,
198
181
  ) &&
199
182
  astUtils.isStaticTemplateLiteral(node.quasi)
@@ -112,6 +112,14 @@ class SuppressionsService {
112
112
  }
113
113
  }
114
114
 
115
+ for (const file of Object.keys(suppressions)) {
116
+ const absolutePath = path.resolve(this.cwd, file);
117
+
118
+ if (!fs.existsSync(absolutePath)) {
119
+ delete suppressions[file];
120
+ }
121
+ }
122
+
115
123
  return this.save(suppressions);
116
124
  }
117
125
 
@@ -0,0 +1,85 @@
1
+ /**
2
+ * @fileoverview Emits warnings for ESLint.
3
+ * @author Francesco Trotta
4
+ */
5
+
6
+ "use strict";
7
+
8
+ //-----------------------------------------------------------------------------
9
+ // Exports
10
+ //-----------------------------------------------------------------------------
11
+
12
+ /**
13
+ * A service that emits warnings for ESLint.
14
+ */
15
+ class WarningService {
16
+ /**
17
+ * Creates a new instance of the service.
18
+ * @param {{ emitWarning?: ((warning: string, type: string) => void) | undefined }} [options] A function called internally to emit warnings using API provided by the runtime.
19
+ */
20
+ constructor({
21
+ emitWarning = globalThis.process?.emitWarning ?? (() => {}),
22
+ } = {}) {
23
+ this.emitWarning = emitWarning;
24
+ }
25
+
26
+ /**
27
+ * Emits a warning when circular fixes are detected while fixing a file.
28
+ * This method is used by the Linter and is safe to call outside Node.js.
29
+ * @param {string} filename The name of the file being fixed.
30
+ * @returns {void}
31
+ */
32
+ emitCircularFixesWarning(filename) {
33
+ this.emitWarning(
34
+ `Circular fixes detected while fixing ${filename}. It is likely that you have conflicting rules in your configuration.`,
35
+ "ESLintCircularFixesWarning",
36
+ );
37
+ }
38
+
39
+ /**
40
+ * Emits a warning when an empty config file has been loaded.
41
+ * @param {string} configFilePath The path to the config file.
42
+ * @returns {void}
43
+ */
44
+ emitEmptyConfigWarning(configFilePath) {
45
+ this.emitWarning(
46
+ `Running ESLint with an empty config (from ${configFilePath}). Please double-check that this is what you want. If you want to run ESLint with an empty config, export [{}] to remove this warning.`,
47
+ "ESLintEmptyConfigWarning",
48
+ );
49
+ }
50
+
51
+ /**
52
+ * Emits a warning when an ".eslintignore" file is found.
53
+ * @returns {void}
54
+ */
55
+ emitESLintIgnoreWarning() {
56
+ this.emitWarning(
57
+ 'The ".eslintignore" file is no longer supported. Switch to using the "ignores" property in "eslint.config.js": https://eslint.org/docs/latest/use/configure/migration-guide#ignoring-files',
58
+ "ESLintIgnoreWarning",
59
+ );
60
+ }
61
+
62
+ /**
63
+ * Emits a warning when the ESLINT_USE_FLAT_CONFIG environment variable is set to "false".
64
+ * @returns {void}
65
+ */
66
+ emitESLintRCWarning() {
67
+ this.emitWarning(
68
+ "You are using an eslintrc configuration file, which is deprecated and support will be removed in v10.0.0. Please migrate to an eslint.config.js file. See https://eslint.org/docs/latest/use/configure/migration-guide for details. An eslintrc configuration file is used because you have the ESLINT_USE_FLAT_CONFIG environment variable set to false. If you want to use an eslint.config.js file, remove the environment variable. If you want to find the location of the eslintrc configuration file, use the --debug flag.",
69
+ "ESLintRCWarning",
70
+ );
71
+ }
72
+
73
+ /**
74
+ * Emits a warning when an inactive flag is used.
75
+ * This method is used by the Linter and is safe to call outside Node.js.
76
+ * @param {string} flag The name of the flag.
77
+ * @param {string} message The warning message.
78
+ * @returns {void}
79
+ */
80
+ emitInactiveFlagWarning(flag, message) {
81
+ this.emitWarning(message, `ESLintInactiveFlag_${flag}`);
82
+ }
83
+ }
84
+
85
+ module.exports = { WarningService };
@@ -0,0 +1,109 @@
1
+ /**
2
+ * @fileoverview Common helpers for naming of plugins, formatters and configs
3
+ */
4
+
5
+ "use strict";
6
+
7
+ const NAMESPACE_REGEX = /^@.*\//iu;
8
+
9
+ /**
10
+ * Brings package name to correct format based on prefix
11
+ * @param {string} name The name of the package.
12
+ * @param {string} prefix Can be either "eslint-plugin", "eslint-config" or "eslint-formatter"
13
+ * @returns {string} Normalized name of the package
14
+ * @private
15
+ */
16
+ function normalizePackageName(name, prefix) {
17
+ let normalizedName = name;
18
+
19
+ /**
20
+ * On Windows, name can come in with Windows slashes instead of Unix slashes.
21
+ * Normalize to Unix first to avoid errors later on.
22
+ * https://github.com/eslint/eslint/issues/5644
23
+ */
24
+ if (normalizedName.includes("\\")) {
25
+ normalizedName = normalizedName.replace(/\\/gu, "/");
26
+ }
27
+
28
+ if (normalizedName.charAt(0) === "@") {
29
+ /**
30
+ * it's a scoped package
31
+ * package name is the prefix, or just a username
32
+ */
33
+ const scopedPackageShortcutRegex = new RegExp(
34
+ `^(@[^/]+)(?:/(?:${prefix})?)?$`,
35
+ "u",
36
+ ),
37
+ scopedPackageNameRegex = new RegExp(`^${prefix}(-|$)`, "u");
38
+
39
+ if (scopedPackageShortcutRegex.test(normalizedName)) {
40
+ normalizedName = normalizedName.replace(
41
+ scopedPackageShortcutRegex,
42
+ `$1/${prefix}`,
43
+ );
44
+ } else if (!scopedPackageNameRegex.test(normalizedName.split("/")[1])) {
45
+ /**
46
+ * for scoped packages, insert the prefix after the first / unless
47
+ * the path is already @scope/eslint or @scope/eslint-xxx-yyy
48
+ */
49
+ normalizedName = normalizedName.replace(
50
+ /^@([^/]+)\/(.*)$/u,
51
+ `@$1/${prefix}-$2`,
52
+ );
53
+ }
54
+ } else if (!normalizedName.startsWith(`${prefix}-`)) {
55
+ normalizedName = `${prefix}-${normalizedName}`;
56
+ }
57
+
58
+ return normalizedName;
59
+ }
60
+
61
+ /**
62
+ * Removes the prefix from a fullname.
63
+ * @param {string} fullname The term which may have the prefix.
64
+ * @param {string} prefix The prefix to remove.
65
+ * @returns {string} The term without prefix.
66
+ */
67
+ function getShorthandName(fullname, prefix) {
68
+ if (fullname[0] === "@") {
69
+ let matchResult = new RegExp(`^(@[^/]+)/${prefix}$`, "u").exec(
70
+ fullname,
71
+ );
72
+
73
+ if (matchResult) {
74
+ return matchResult[1];
75
+ }
76
+
77
+ matchResult = new RegExp(`^(@[^/]+)/${prefix}-(.+)$`, "u").exec(
78
+ fullname,
79
+ );
80
+ if (matchResult) {
81
+ return `${matchResult[1]}/${matchResult[2]}`;
82
+ }
83
+ } else if (fullname.startsWith(`${prefix}-`)) {
84
+ return fullname.slice(prefix.length + 1);
85
+ }
86
+
87
+ return fullname;
88
+ }
89
+
90
+ /**
91
+ * Gets the scope (namespace) of a term.
92
+ * @param {string} term The term which may have the namespace.
93
+ * @returns {string} The namespace of the term if it has one.
94
+ */
95
+ function getNamespaceFromTerm(term) {
96
+ const match = term.match(NAMESPACE_REGEX);
97
+
98
+ return match ? match[0] : "";
99
+ }
100
+
101
+ //------------------------------------------------------------------------------
102
+ // Public Interface
103
+ //------------------------------------------------------------------------------
104
+
105
+ module.exports = {
106
+ normalizePackageName,
107
+ getShorthandName,
108
+ getNamespaceFromTerm,
109
+ };
@@ -0,0 +1,28 @@
1
+ /**
2
+ * Utility for resolving a module relative to another module
3
+ * @author Teddy Katz
4
+ */
5
+
6
+ "use strict";
7
+
8
+ const Module = require("node:module");
9
+
10
+ /*
11
+ * `Module.createRequire` is added in v12.2.0. It supports URL as well.
12
+ * We only support the case where the argument is a filepath, not a URL.
13
+ */
14
+ const createRequire = Module.createRequire;
15
+
16
+ /**
17
+ * Resolves a Node module relative to another module
18
+ * @param {string} moduleName The name of a Node module, or a path to a Node module.
19
+ * @param {string} relativeToPath An absolute path indicating the module that `moduleName` should be resolved relative to. This must be
20
+ * a file rather than a directory, but the file need not actually exist.
21
+ * @returns {string} The absolute path that would result from calling `require.resolve(moduleName)` in a file located at `relativeToPath`
22
+ * @throws {Error} When the module cannot be resolved.
23
+ */
24
+ function resolve(moduleName, relativeToPath) {
25
+ return createRequire(relativeToPath).resolve(moduleName);
26
+ }
27
+
28
+ exports.resolve = resolve;
@@ -289,6 +289,8 @@ export class SourceCode
289
289
  second: ESTree.Node | AST.Token,
290
290
  ): boolean;
291
291
 
292
+ isGlobalReference(node: ESTree.Identifier): boolean;
293
+
292
294
  markVariableAsUsed(name: string, refNode?: ESTree.Node): boolean;
293
295
 
294
296
  traverse(): Iterable<TraversalStep>;
@@ -584,6 +586,11 @@ export namespace SourceCode {
584
586
 
585
587
  // #endregion
586
588
 
589
+ export type JSSyntaxElement = {
590
+ type: string;
591
+ loc?: ESTree.SourceLocation | null | undefined;
592
+ };
593
+
587
594
  export namespace Rule {
588
595
  interface RuleModule
589
596
  extends RuleDefinition<{
@@ -591,7 +598,7 @@ export namespace Rule {
591
598
  Code: SourceCode;
592
599
  RuleOptions: any[];
593
600
  Visitor: NodeListener;
594
- Node: ESTree.Node;
601
+ Node: JSSyntaxElement;
595
602
  MessageIds: string;
596
603
  ExtRuleDocs: {};
597
604
  }> {
@@ -1159,10 +1166,10 @@ export namespace Rule {
1159
1166
  /**
1160
1167
  * Indicates the type of rule:
1161
1168
  * - `"problem"` means the rule is identifying code that either will cause an error or may cause a confusing behavior. Developers should consider this a high priority to resolve.
1162
- * - `"suggestion"` means the rule is identifying something that could be done in a better way but no errors will occur if the code isnt changed.
1169
+ * - `"suggestion"` means the rule is identifying something that could be done in a better way but no errors will occur if the code isn't changed.
1163
1170
  * - `"layout"` means the rule cares primarily about whitespace, semicolons, commas, and parentheses,
1164
1171
  * all the parts of the program that determine how the code looks rather than how it executes.
1165
- * These rules work on parts of the code that arent specified in the AST.
1172
+ * These rules work on parts of the code that aren't specified in the AST.
1166
1173
  */
1167
1174
  type?: "problem" | "suggestion" | "layout" | undefined;
1168
1175
  /**
@@ -1177,7 +1184,7 @@ export namespace Rule {
1177
1184
  LangOptions: Linter.LanguageOptions;
1178
1185
  Code: SourceCode;
1179
1186
  RuleOptions: any[];
1180
- Node: ESTree.Node;
1187
+ Node: JSSyntaxElement;
1181
1188
  MessageIds: string;
1182
1189
  }> {
1183
1190
  /*
@@ -1275,7 +1282,7 @@ export type JSRuleDefinition<
1275
1282
  LangOptions: Linter.LanguageOptions;
1276
1283
  Code: SourceCode;
1277
1284
  Visitor: Rule.NodeListener;
1278
- Node: ESTree.Node;
1285
+ Node: JSSyntaxElement;
1279
1286
  } & Required<
1280
1287
  // Rule specific type options (custom)
1281
1288
  Options &
@@ -1409,6 +1416,7 @@ export namespace Linter {
1409
1416
  | 14
1410
1417
  | 15
1411
1418
  | 16
1419
+ | 17
1412
1420
  | 2015
1413
1421
  | 2016
1414
1422
  | 2017
@@ -1420,6 +1428,7 @@ export namespace Linter {
1420
1428
  | 2023
1421
1429
  | 2024
1422
1430
  | 2025
1431
+ | 2026
1423
1432
  | "latest";
1424
1433
 
1425
1434
  /**
@@ -1619,7 +1628,9 @@ export namespace Linter {
1619
1628
  postprocess?:
1620
1629
  | ((problemLists: LintMessage[][]) => LintMessage[])
1621
1630
  | undefined;
1622
- filterCodeBlock?: boolean | undefined;
1631
+ filterCodeBlock?:
1632
+ | ((filename: string, text: string) => boolean)
1633
+ | undefined;
1623
1634
  disableFixes?: boolean | undefined;
1624
1635
  allowInlineConfig?: boolean | undefined;
1625
1636
  reportUnusedDisableDirectives?: boolean | undefined;
@@ -1824,7 +1835,7 @@ export namespace Linter {
1824
1835
  }
1825
1836
 
1826
1837
  /** @deprecated Use `Config` instead of `FlatConfig` */
1827
- type FlatConfig = Config;
1838
+ type FlatConfig<Rules extends RulesRecord = RulesRecord> = Config<Rules>;
1828
1839
 
1829
1840
  type GlobalConf =
1830
1841
  | boolean
@@ -619,7 +619,7 @@ export interface ESLintRules extends Linter.RulesRecord {
619
619
  * @see https://eslint.org/docs/latest/rules/curly
620
620
  */
621
621
  curly: Linter.RuleEntry<
622
- ["all" | "multi" | "multi-line" | "multi-or-nest" | "consistent"]
622
+ ["all"] | ["multi" | "multi-line" | "multi-or-nest", "consistent"?]
623
623
  >;
624
624
 
625
625
  /**
@@ -807,6 +807,10 @@ export interface ESLintRules extends Linter.RulesRecord {
807
807
  * @default false
808
808
  */
809
809
  allowArrowFunctions: boolean;
810
+ /**
811
+ * @default false
812
+ */
813
+ allowTypeAnnotation: boolean;
810
814
  overrides: {
811
815
  namedExports: "declaration" | "expression" | "ignore";
812
816
  };
@@ -2854,6 +2858,22 @@ export interface ESLintRules extends Linter.RulesRecord {
2854
2858
  * @default false
2855
2859
  */
2856
2860
  detectObjects: boolean;
2861
+ /**
2862
+ * @default false
2863
+ */
2864
+ ignoreEnums: boolean;
2865
+ /**
2866
+ * @default false
2867
+ */
2868
+ ignoreNumericLiteralTypes: boolean;
2869
+ /**
2870
+ * @default false
2871
+ */
2872
+ ignoreReadonlyClassProperties: boolean;
2873
+ /**
2874
+ * @default false
2875
+ */
2876
+ ignoreTypeIndexes: boolean;
2857
2877
  }>,
2858
2878
  ]
2859
2879
  >;
@@ -3450,6 +3470,11 @@ export interface ESLintRules extends Linter.RulesRecord {
3450
3470
  allowObjects?: string[];
3451
3471
  message?: string | undefined;
3452
3472
  }
3473
+ | {
3474
+ object: string;
3475
+ allowProperties?: string[];
3476
+ message?: string | undefined;
3477
+ }
3453
3478
  >,
3454
3479
  ]
3455
3480
  >;
@@ -3562,13 +3587,26 @@ export interface ESLintRules extends Linter.RulesRecord {
3562
3587
  /**
3563
3588
  * @default 'functions'
3564
3589
  */
3565
- hoist: "functions" | "all" | "never";
3590
+ hoist:
3591
+ | "functions"
3592
+ | "all"
3593
+ | "never"
3594
+ | "types"
3595
+ | "functions-and-types";
3566
3596
  allow: string[];
3567
3597
  /**
3568
3598
  * @since 8.10.0
3569
3599
  * @default false
3570
3600
  */
3571
3601
  ignoreOnInitialization: boolean;
3602
+ /**
3603
+ * @default true
3604
+ */
3605
+ ignoreTypeValueShadow: boolean;
3606
+ /**
3607
+ * @default true
3608
+ */
3609
+ ignoreFunctionTypeParameterNameValueShadow: boolean;
3572
3610
  }>,
3573
3611
  ]
3574
3612
  >;
@@ -4057,6 +4095,18 @@ export interface ESLintRules extends Linter.RulesRecord {
4057
4095
  * @default false
4058
4096
  */
4059
4097
  allowNamedExports: boolean;
4098
+ /**
4099
+ * @default true
4100
+ */
4101
+ enums: boolean;
4102
+ /**
4103
+ * @default true
4104
+ */
4105
+ typedefs: boolean;
4106
+ /**
4107
+ * @default true
4108
+ */
4109
+ ignoreTypeReferences: boolean;
4060
4110
  }>
4061
4111
  | "nofunc",
4062
4112
  ]
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "eslint",
3
- "version": "9.27.0",
3
+ "version": "9.29.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",
@@ -106,11 +106,11 @@
106
106
  "dependencies": {
107
107
  "@eslint-community/eslint-utils": "^4.2.0",
108
108
  "@eslint-community/regexpp": "^4.12.1",
109
- "@eslint/config-array": "^0.20.0",
109
+ "@eslint/config-array": "^0.20.1",
110
110
  "@eslint/config-helpers": "^0.2.1",
111
111
  "@eslint/core": "^0.14.0",
112
112
  "@eslint/eslintrc": "^3.3.1",
113
- "@eslint/js": "9.27.0",
113
+ "@eslint/js": "9.29.0",
114
114
  "@eslint/plugin-kit": "^0.3.1",
115
115
  "@humanfs/node": "^0.16.6",
116
116
  "@humanwhocodes/module-importer": "^1.0.1",
@@ -122,9 +122,9 @@
122
122
  "cross-spawn": "^7.0.6",
123
123
  "debug": "^4.3.2",
124
124
  "escape-string-regexp": "^4.0.0",
125
- "eslint-scope": "^8.3.0",
126
- "eslint-visitor-keys": "^4.2.0",
127
- "espree": "^10.3.0",
125
+ "eslint-scope": "^8.4.0",
126
+ "eslint-visitor-keys": "^4.2.1",
127
+ "espree": "^10.4.0",
128
128
  "esquery": "^1.5.0",
129
129
  "esutils": "^2.0.2",
130
130
  "fast-deep-equal": "^3.1.3",
@@ -170,11 +170,13 @@
170
170
  "fast-glob": "^3.2.11",
171
171
  "fs-teardown": "^0.1.3",
172
172
  "glob": "^10.0.0",
173
- "globals": "^15.0.0",
173
+ "globals": "^16.2.0",
174
174
  "got": "^11.8.3",
175
175
  "gray-matter": "^4.0.3",
176
- "jiti": "^2.1.0",
177
- "knip": "^5.32.0",
176
+ "jiti": "^2.2.0",
177
+ "jiti-v2.0": "npm:jiti@2.0.x",
178
+ "jiti-v2.1": "npm:jiti@2.1.x",
179
+ "knip": "^5.60.2",
178
180
  "lint-staged": "^11.0.0",
179
181
  "load-perf": "^0.2.0",
180
182
  "markdown-it": "^12.2.0",
@@ -195,7 +197,7 @@
195
197
  "recast": "^0.23.0",
196
198
  "regenerator-runtime": "^0.14.0",
197
199
  "semver": "^7.5.3",
198
- "shelljs": "^0.9.0",
200
+ "shelljs": "^0.10.0",
199
201
  "sinon": "^11.0.0",
200
202
  "typescript": "^5.3.3",
201
203
  "webpack": "^5.23.0",