eslint-plugin-baseline-js 0.7.2 → 0.7.4

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 (3) hide show
  1. package/README.md +4 -1
  2. package/dist/index.mjs +185 -133
  3. package/package.json +5 -5
package/README.md CHANGED
@@ -26,7 +26,7 @@ This plugin delegates detection to eslint-plugin-es-x and ESLint core (plus a fe
26
26
  - yarn: `yarn add -D eslint-plugin-baseline-js`
27
27
 
28
28
  Recommended
29
- - ESLint >= 8.57 (Flat Config)
29
+ - ESLint >= 9.29.0 and < 11 (Flat Config)
30
30
 
31
31
  ## Quick Start (Flat Config)
32
32
 
@@ -196,3 +196,6 @@ MIT
196
196
  [jsdocs-href]: https://www.jsdocs.io/package/eslint-plugin-baseline-js
197
197
  [license-src]: https://img.shields.io/github/license/3ru/eslint-plugin-baseline-js.svg?style=flat&colorA=080f12&colorB=1ea446
198
198
  [license-href]: https://github.com/3ru/eslint-plugin-baseline-js/blob/main/LICENSE
199
+
200
+ ---
201
+ <sub>Thanks to Anthropic for sponsoring</sub>
package/dist/index.mjs CHANGED
@@ -13857,18 +13857,6 @@ const descriptors$1 = [
13857
13857
  "iface": "Element",
13858
13858
  "prop": "prependHTMLUnsafe"
13859
13859
  },
13860
- {
13861
- "featureId": "html-setters",
13862
- "kind": "instanceMember",
13863
- "iface": "Element",
13864
- "prop": "replaceHTML"
13865
- },
13866
- {
13867
- "featureId": "html-setters",
13868
- "kind": "instanceMember",
13869
- "iface": "Element",
13870
- "prop": "replaceHTMLUnsafe"
13871
- },
13872
13860
  {
13873
13861
  "featureId": "html-setters",
13874
13862
  "kind": "instanceMember",
@@ -13970,6 +13958,12 @@ const descriptors$1 = [
13970
13958
  "iface": "TrustedHTMLParserOptions",
13971
13959
  "prop": "sanitizer"
13972
13960
  },
13961
+ {
13962
+ "featureId": "html-streaming-setters",
13963
+ "kind": "instanceMember",
13964
+ "iface": "Blob",
13965
+ "prop": "textStream"
13966
+ },
13973
13967
  {
13974
13968
  "featureId": "html-streaming-setters",
13975
13969
  "kind": "instanceMember",
@@ -14106,25 +14100,25 @@ const descriptors$1 = [
14106
14100
  "featureId": "html-streaming-setters",
14107
14101
  "kind": "instanceMember",
14108
14102
  "iface": "Element",
14109
- "prop": "streamReplaceHTML"
14103
+ "prop": "streamReplaceWithHTML"
14110
14104
  },
14111
14105
  {
14112
14106
  "featureId": "html-streaming-setters",
14113
14107
  "kind": "instanceMember",
14114
14108
  "iface": "Element",
14115
- "prop": "streamReplaceHTMLUnsafe"
14109
+ "prop": "streamReplaceWithHTMLUnsafe"
14116
14110
  },
14117
14111
  {
14118
14112
  "featureId": "html-streaming-setters",
14119
14113
  "kind": "instanceMember",
14120
- "iface": "Element",
14121
- "prop": "streamReplaceWithHTML"
14114
+ "iface": "Request",
14115
+ "prop": "textStream"
14122
14116
  },
14123
14117
  {
14124
14118
  "featureId": "html-streaming-setters",
14125
14119
  "kind": "instanceMember",
14126
- "iface": "Element",
14127
- "prop": "streamReplaceWithHTMLUnsafe"
14120
+ "iface": "Response",
14121
+ "prop": "textStream"
14128
14122
  },
14129
14123
  {
14130
14124
  "featureId": "html-streaming-setters",
@@ -49210,6 +49204,12 @@ const descriptors = [
49210
49204
  "base": "Error",
49211
49205
  "prop": "isError"
49212
49206
  },
49207
+ {
49208
+ "featureId": "iterator-join",
49209
+ "kind": "instanceMember",
49210
+ "iface": "Iterator",
49211
+ "prop": "join"
49212
+ },
49213
49213
  {
49214
49214
  "featureId": "iterator-methods",
49215
49215
  "kind": "instanceMember",
@@ -50512,6 +50512,18 @@ const descriptors = [
50512
50512
  "iface": "String",
50513
50513
  "prop": "startsWith"
50514
50514
  },
50515
+ {
50516
+ "featureId": "string-trim-leftright",
50517
+ "kind": "instanceMember",
50518
+ "iface": "String",
50519
+ "prop": "trimLeft"
50520
+ },
50521
+ {
50522
+ "featureId": "string-trim-leftright",
50523
+ "kind": "instanceMember",
50524
+ "iface": "String",
50525
+ "prop": "trimRight"
50526
+ },
50515
50527
  {
50516
50528
  "featureId": "string-trim-startend",
50517
50529
  "kind": "instanceMember",
@@ -52404,8 +52416,9 @@ var features_api_default = {
52404
52416
  "id": "abortsignal-any",
52405
52417
  "name": "AbortSignal.any()",
52406
52418
  "status": {
52407
- "baseline": "low",
52419
+ "baseline": "high",
52408
52420
  "baseline_low_date": "2024-03-19",
52421
+ "baseline_high_date": "2026-09-19",
52409
52422
  "support": {
52410
52423
  "chrome": "116",
52411
52424
  "chrome_android": "116",
@@ -52606,8 +52619,12 @@ var features_api_default = {
52606
52619
  "id": "arianotify",
52607
52620
  "name": "ariaNotify()",
52608
52621
  "status": {
52609
- "baseline": false,
52622
+ "baseline": "low",
52623
+ "baseline_low_date": "2026-09-14",
52610
52624
  "support": {
52625
+ "chrome": "141",
52626
+ "chrome_android": "141",
52627
+ "edge": "141",
52611
52628
  "firefox": "150",
52612
52629
  "firefox_android": "150",
52613
52630
  "safari": "27",
@@ -53658,7 +53675,7 @@ var features_api_default = {
53658
53675
  },
53659
53676
  "container-queries": {
53660
53677
  "id": "container-queries",
53661
- "name": "Container queries",
53678
+ "name": "Container queries (size)",
53662
53679
  "group": ["container-queries"],
53663
53680
  "status": {
53664
53681
  "baseline": "high",
@@ -54989,11 +55006,7 @@ var features_api_default = {
54989
55006
  "name": "<fencedframe>",
54990
55007
  "status": {
54991
55008
  "baseline": false,
54992
- "support": {
54993
- "chrome": "128",
54994
- "chrome_android": "128",
54995
- "edge": "128"
54996
- }
55009
+ "support": { "edge": "128" }
54997
55010
  },
54998
55011
  "discouraged": {
54999
55012
  "according_to": ["https://groups.google.com/a/chromium.org/g/blink-dev/c/c9w5uH3eSuo/m/KcvocvF1DQAJ", "https://chromestatus.com/feature/6366274495053824"],
@@ -55292,7 +55305,10 @@ var features_api_default = {
55292
55305
  "name": "Responsive iframes",
55293
55306
  "status": {
55294
55307
  "baseline": false,
55295
- "support": {}
55308
+ "support": {
55309
+ "chrome": "154",
55310
+ "chrome_android": "154"
55311
+ }
55296
55312
  }
55297
55313
  },
55298
55314
  "fullscreen": {
@@ -63010,6 +63026,21 @@ var features_jsbi_default = {
63010
63026
  }
63011
63027
  }
63012
63028
  },
63029
+ "iterator-join": {
63030
+ "id": "iterator-join",
63031
+ "name": "Iterator join()",
63032
+ "group": ["iterators"],
63033
+ "status": {
63034
+ "baseline": false,
63035
+ "support": {
63036
+ "chrome": "153",
63037
+ "chrome_android": "153",
63038
+ "edge": "153",
63039
+ "firefox": "154",
63040
+ "firefox_android": "154"
63041
+ }
63042
+ }
63043
+ },
63013
63044
  "iterator-methods": {
63014
63045
  "id": "iterator-methods",
63015
63046
  "name": "Iterator methods",
@@ -63729,6 +63760,29 @@ var features_jsbi_default = {
63729
63760
  }
63730
63761
  }
63731
63762
  },
63763
+ "string-trim-leftright": {
63764
+ "id": "string-trim-leftright",
63765
+ "name": "String trimLeft() and trimRight()",
63766
+ "group": ["string"],
63767
+ "status": {
63768
+ "baseline": false,
63769
+ "support": {
63770
+ "chrome": "4",
63771
+ "chrome_android": "18",
63772
+ "edge": "12",
63773
+ "firefox": "3.5",
63774
+ "firefox_android": "4",
63775
+ "safari": "5",
63776
+ "safari_ios": "4.2"
63777
+ }
63778
+ },
63779
+ "discouraged": {
63780
+ "according_to": ["https://tc39.es/ecma262/multipage/additional-ecmascript-features-for-web-browsers.html#String.prototype.trimleft"],
63781
+ "alternatives": ["string-trim-startend"],
63782
+ "reason": "TC39 recommends using trimStart() and trimEnd() instead. The trimLeft() and trimRight() aliases are provided for compatibility with old code.",
63783
+ "reason_html": "TC39 recommends using <code>trimStart()</code> and <code>trimEnd()</code> instead. The <code>trimLeft()</code> and <code>trimRight()</code> aliases are provided for compatibility with old code."
63784
+ }
63785
+ },
63732
63786
  "string-trim-startend": {
63733
63787
  "id": "string-trim-startend",
63734
63788
  "name": "String trimStart() and trimEnd()",
@@ -64312,6 +64366,10 @@ function addTypedInstanceMemberDetector(context, d, report) {
64312
64366
  const propertyOfType = checkerOk.getPropertyOfType;
64313
64367
  if (typeof propertyOfType !== "function") return {};
64314
64368
  const getPropertyOfType = propertyOfType.bind(checkerOk);
64369
+ function getBaseTypes(t) {
64370
+ const type = t;
64371
+ return type.getBaseTypes?.() || type.baseTypes || type.target?.getBaseTypes?.() || type.target?.baseTypes || [];
64372
+ }
64315
64373
  function typeMatches(t) {
64316
64374
  if (!t) return false;
64317
64375
  const withTypes = t;
@@ -64319,12 +64377,11 @@ function addTypedInstanceMemberDetector(context, d, report) {
64319
64377
  const withSym = t;
64320
64378
  const name = (withSym.symbol || withSym.aliasSymbol || withSym.getSymbol?.())?.name;
64321
64379
  if (name === iface || name?.endsWith(`.${iface}`)) return true;
64322
- const ap = checkerOk.getApparentType?.(t) || t;
64323
- const baseTypes = ap.getBaseTypes?.() || ap.baseTypes || [];
64380
+ const baseTypes = getBaseTypes(checkerOk.getApparentType?.(t) || t);
64324
64381
  if (baseTypes?.length) {
64325
64382
  if (baseTypes.some((bt) => bt.symbol?.name === iface)) return true;
64326
64383
  for (const bt of baseTypes) {
64327
- const bt2 = bt.getBaseTypes?.() || [];
64384
+ const bt2 = getBaseTypes(bt);
64328
64385
  if (Array.isArray(bt2) && bt2.some((b2) => b2.symbol?.name === iface)) return true;
64329
64386
  }
64330
64387
  }
@@ -64346,71 +64403,45 @@ function addTypedInstanceMemberDetector(context, d, report) {
64346
64403
  //#region src/rules/feature-usage/builder.ts
64347
64404
  function buildListeners(context, opt) {
64348
64405
  const listeners = {};
64349
- function report(node, featureId) {
64350
- const msg = opt.messages[featureId] ?? `Feature '${featureId}' exceeds configured Baseline.`;
64351
- context.report({
64352
- node,
64353
- message: msg
64354
- });
64355
- }
64356
64406
  const ctxLike = context;
64357
64407
  const services = ctxLike.parserServices || ctxLike.sourceCode?.parserServices || {};
64358
64408
  const checker = services.program?.getTypeChecker?.();
64359
64409
  const useTyped = !!opt.typed && !!checker && !!services.esTreeNodeToTSNodeMap;
64360
- for (const d of opt.descriptors) switch (d.kind) {
64361
- case "newIdent":
64362
- mergeRuleListeners(listeners, addNewIdentDetector(context, d, report));
64363
- break;
64364
- case "newMember":
64365
- mergeRuleListeners(listeners, addNewMemberDetector(context, d, report));
64366
- break;
64367
- case "callStatic":
64368
- mergeRuleListeners(listeners, addCallStaticDetector(context, d, report));
64369
- break;
64370
- case "callGlobal":
64371
- mergeRuleListeners(listeners, addCallGlobalDetector(context, d, report));
64372
- break;
64373
- case "member":
64374
- mergeRuleListeners(listeners, addMemberDetector(context, d, report));
64375
- break;
64376
- case "staticMember":
64377
- mergeRuleListeners(listeners, addStaticMemberDetector(context, d, report));
64378
- break;
64379
- case "instanceMember":
64380
- if (useTyped) mergeRuleListeners(listeners, addTypedInstanceMemberDetector(context, d, report));
64381
- break;
64382
- case "callMemberWithArgs":
64383
- mergeRuleListeners(listeners, addCallMemberWithArgsDetector(context, d, report));
64384
- break;
64385
- case "newWithOptions": mergeRuleListeners(listeners, addNewWithOptionsDetector(context, d, report));
64410
+ for (const d of opt.descriptors) {
64411
+ function report(node) {
64412
+ opt.report(node, d);
64413
+ }
64414
+ switch (d.kind) {
64415
+ case "newIdent":
64416
+ mergeRuleListeners(listeners, addNewIdentDetector(context, d, report));
64417
+ break;
64418
+ case "newMember":
64419
+ mergeRuleListeners(listeners, addNewMemberDetector(context, d, report));
64420
+ break;
64421
+ case "callStatic":
64422
+ mergeRuleListeners(listeners, addCallStaticDetector(context, d, report));
64423
+ break;
64424
+ case "callGlobal":
64425
+ mergeRuleListeners(listeners, addCallGlobalDetector(context, d, report));
64426
+ break;
64427
+ case "member":
64428
+ mergeRuleListeners(listeners, addMemberDetector(context, d, report));
64429
+ break;
64430
+ case "staticMember":
64431
+ mergeRuleListeners(listeners, addStaticMemberDetector(context, d, report));
64432
+ break;
64433
+ case "instanceMember":
64434
+ if (useTyped) mergeRuleListeners(listeners, addTypedInstanceMemberDetector(context, d, report));
64435
+ break;
64436
+ case "callMemberWithArgs":
64437
+ mergeRuleListeners(listeners, addCallMemberWithArgsDetector(context, d, report));
64438
+ break;
64439
+ case "newWithOptions": mergeRuleListeners(listeners, addNewWithOptionsDetector(context, d, report));
64440
+ }
64386
64441
  }
64387
64442
  return listeners;
64388
64443
  }
64389
64444
  //#endregion
64390
- //#region src/rules/feature-usage/index.ts
64391
- const rule$6 = {
64392
- meta: {
64393
- type: "problem",
64394
- docs: { description: "Detect usage of Web APIs and JS builtins beyond configured Baseline (data-driven)." },
64395
- schema: [{
64396
- type: "object",
64397
- properties: {
64398
- descriptors: { type: "array" },
64399
- messages: { type: "object" }
64400
- },
64401
- additionalProperties: false
64402
- }]
64403
- },
64404
- create(context) {
64405
- const opt = context.options?.[0] ?? {};
64406
- return buildListeners(context, {
64407
- descriptors: opt.descriptors ?? [],
64408
- messages: opt.messages ?? {},
64409
- typed: !!opt.typed
64410
- });
64411
- }
64412
- };
64413
- //#endregion
64414
64445
  //#region src/rules/no-atomics-pause/index.ts
64415
64446
  const rule$5 = {
64416
64447
  meta: {
@@ -64656,6 +64687,52 @@ function listResolverPlugins() {
64656
64687
  return Object.keys(registry).sort();
64657
64688
  }
64658
64689
  //#endregion
64690
+ //#region src/orchestrator/messages.ts
64691
+ function baselineMessage(featureId, baseline, subject) {
64692
+ const feature = getFeatureRecord(featureId);
64693
+ const label = subject ?? `'${feature?.name ?? featureId}'`;
64694
+ if (baseline === "widely") return `${label} is not Baseline Widely available (${featureId}).`;
64695
+ if (baseline === "newly") return `${label} is not Baseline Newly available (${featureId}).`;
64696
+ if (feature?.status?.baseline === false) return `${label} has Limited availability and exceeds ${baseline} (${featureId}).`;
64697
+ return `${label} became Baseline in ${baselineYearLabel(feature?.status) ?? "unknown"} and exceeds ${baseline} (${featureId}).`;
64698
+ }
64699
+ function delegateSubject(name) {
64700
+ const separator = name.lastIndexOf(".");
64701
+ if (separator === -1) return `'${name}'`;
64702
+ const owner = name.slice(0, separator).replace(/\.prototype$/, "");
64703
+ return memberSubject(name.slice(separator + 1), owner);
64704
+ }
64705
+ function descriptorSubject(descriptor) {
64706
+ switch (descriptor.kind) {
64707
+ case "newIdent":
64708
+ case "callGlobal": return `'${descriptor.name}'`;
64709
+ case "newMember":
64710
+ case "callStatic":
64711
+ case "member":
64712
+ case "staticMember": return memberSubject(descriptor.prop, descriptor.base);
64713
+ case "instanceMember": return memberSubject(descriptor.prop, descriptor.iface);
64714
+ case "callMemberWithArgs":
64715
+ case "newWithOptions": return callSubject(descriptor);
64716
+ }
64717
+ }
64718
+ function memberSubject(name, owner) {
64719
+ return `'${name}' on ${owner}`;
64720
+ }
64721
+ function callSubject(descriptor) {
64722
+ const args = [];
64723
+ const objectArg = descriptor.objectArg;
64724
+ if (descriptor.kind === "callMemberWithArgs" && descriptor.stringArg) args[descriptor.stringArg.index] = descriptor.stringArg.values.map((value) => JSON.stringify(value)).join(" | ");
64725
+ if (objectArg) {
64726
+ const properties = /* @__PURE__ */ new Map();
64727
+ for (const key of objectArg.hasKeys ?? []) properties.set(key, "...");
64728
+ for (const { key, values } of objectArg.keyValues ?? []) properties.set(key, values?.map((value) => JSON.stringify(value)).join(" | ") || "...");
64729
+ args[objectArg.index] = `{ ${Array.from(properties, ([key, value]) => `${key}: ${value}`).join(", ")} }`;
64730
+ }
64731
+ const argumentsText = Array.from(args, (argument) => argument ?? "...").join(", ");
64732
+ if (descriptor.kind === "newWithOptions") return `new ${descriptor.name}(${argumentsText})`;
64733
+ return `${descriptor.viaCall ? `${descriptor.viaCall.prop}().` : ""}${descriptor.prop}(${argumentsText})`;
64734
+ }
64735
+ //#endregion
64659
64736
  //#region src/orchestrator/use-baseline.ts
64660
64737
  function buildDelegateContext(ctx, overrides) {
64661
64738
  const src = ctx;
@@ -64675,15 +64752,6 @@ registerSelfRules({
64675
64752
  "no-math-sum-precise": rule$2,
64676
64753
  "no-temporal": rule$1
64677
64754
  });
64678
- function baselineMessage(featureId, baseline) {
64679
- const rec = getFeatureRecord(featureId);
64680
- const label = rec?.name || featureId;
64681
- const idSuffix = rec?.name ? ` (${featureId})` : "";
64682
- if (baseline === "widely") return `Feature '${label}'${idSuffix} is not a widely available Baseline feature.`;
64683
- if (baseline === "newly") return `Feature '${label}'${idSuffix} is not a newly available Baseline feature.`;
64684
- if (rec?.status?.baseline === false) return `Feature '${label}'${idSuffix} has Limited availability and exceeds ${baseline}.`;
64685
- return `Feature '${label}'${idSuffix} became Baseline in ${baselineYearLabel(rec?.status) ?? "unknown"} and exceeds ${baseline}.`;
64686
- }
64687
64755
  const rule = {
64688
64756
  meta: {
64689
64757
  type: "problem",
@@ -64839,14 +64907,16 @@ const rule = {
64839
64907
  },
64840
64908
  options: delegateOptions,
64841
64909
  report(arg) {
64842
- const node = typeof arg === "object" && arg !== null && "node" in arg ? arg.node : arg;
64843
- if (matchIgnoreNodeType) {
64844
- const t = node?.type;
64845
- if (t && matchIgnoreNodeType(t)) return;
64846
- }
64847
- ctx.report({
64848
- node,
64849
- message: baselineMessage(featureId, baseline)
64910
+ if ("node" in arg && matchIgnoreNodeType?.(arg.node.type)) return;
64911
+ const subject = arg.data?.name ? delegateSubject(String(arg.data.name)) : void 0;
64912
+ const message = baselineMessage(featureId, baseline, subject);
64913
+ if ("node" in arg) ctx.report({
64914
+ node: arg.node,
64915
+ message
64916
+ });
64917
+ else ctx.report({
64918
+ loc: arg.loc,
64919
+ message
64850
64920
  });
64851
64921
  }
64852
64922
  });
@@ -64877,35 +64947,17 @@ const rule = {
64877
64947
  const useTypesJs = resolveUseTypes(includeJsBuiltins);
64878
64948
  const typedEnabled = (useTypesWeb === "require" || useTypesJs === "require" || useTypesWeb === "auto" || useTypesJs === "auto") && typedAvailable;
64879
64949
  if (!typedEnabled) descriptors = descriptors.filter((d) => d.kind !== "instanceMember" && !d.typedOnly);
64880
- if (descriptors.length > 0) {
64881
- const messages = {};
64882
- for (const d of descriptors) messages[d.featureId] = baselineMessage(d.featureId, baseline);
64883
- const delegateCtx = buildDelegateContext(ctx, {
64884
- options: [typedEnabled ? {
64885
- descriptors,
64886
- messages,
64887
- typed: true
64888
- } : {
64889
- descriptors,
64890
- messages
64891
- }],
64892
- report(arg) {
64893
- const isObj = typeof arg === "object" && arg !== null;
64894
- const node = isObj && "node" in arg ? arg.node : arg;
64895
- if (matchIgnoreNodeType) {
64896
- const t = node?.type;
64897
- if (t && matchIgnoreNodeType(t)) return;
64898
- }
64899
- let msg;
64900
- if (isObj && typeof arg.message === "string") msg = arg.message;
64901
- ctx.report({
64902
- node,
64903
- message: msg
64904
- });
64905
- }
64906
- });
64907
- mergeRuleListeners(listeners, rule$6.create(delegateCtx));
64908
- }
64950
+ if (descriptors.length > 0) mergeRuleListeners(listeners, buildListeners(ctx, {
64951
+ descriptors,
64952
+ typed: typedEnabled,
64953
+ report(node, descriptor) {
64954
+ if (matchIgnoreNodeType?.(node.type)) return;
64955
+ ctx.report({
64956
+ node,
64957
+ message: baselineMessage(descriptor.featureId, baseline, descriptorSubject(descriptor))
64958
+ });
64959
+ }
64960
+ }));
64909
64961
  return listeners;
64910
64962
  }
64911
64963
  };
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "eslint-plugin-baseline-js",
3
- "version": "0.7.2",
3
+ "version": "0.7.4",
4
4
  "description": "Enforce JavaScript Baseline (widely/newly/year) browser compatibility with a single ESLint rule. Prevent runtime errors by catching unsupported JavaScript features during development.",
5
5
  "license": "MIT",
6
6
  "type": "module",
@@ -45,15 +45,15 @@
45
45
  "@semantic-release/changelog": "^7.0.0",
46
46
  "@semantic-release/git": "^11.0.1",
47
47
  "@types/eslint": "^9.6.1",
48
- "@types/node": "^26.6.2",
49
- "@typescript-eslint/parser": "^8.70.0",
48
+ "@types/node": "^26.6.3",
49
+ "@typescript-eslint/parser": "^8.70.1",
50
50
  "eslint": "^10.11.0",
51
51
  "semantic-release": "^25.0.9",
52
52
  "tsdown": "0.23.0",
53
53
  "typescript": "^6.0.3",
54
- "vitest": "^4.1.11",
54
+ "vitest": "^5.0.2",
55
55
  "vue-eslint-parser": "^10.4.1",
56
- "web-features": "3.39.0"
56
+ "web-features": "3.40.0"
57
57
  },
58
58
  "peerDependencies": {
59
59
  "eslint": ">=9.29.0 <11"