eslint-plugin-baseline-js 0.7.4 → 0.7.5

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 +5 -0
  2. package/dist/index.mjs +467 -344
  3. package/package.json +7 -1
package/README.md CHANGED
@@ -115,6 +115,11 @@ export default [
115
115
 
116
116
 
117
117
  ### Demo
118
+
119
+ For type-level checks too, pair it with [`typescript-baseline-lib`](https://github.com/3ru/TypeScript-Baseline-lib-generator), which gives TypeScript a built-in lib selected by Baseline data.
120
+ Try the [demo](https://github.com/3ru/baseline-checks-demo) to check JavaScript APIs with TypeScript and ESLint in your editor and CI.
121
+ Its [example PR](https://github.com/3ru/baseline-checks-demo/pull/1) changes one line to use `Set.prototype.difference()` and intentionally fails both checks.
122
+
118
123
  <img width="963" height="192" alt="getYear is deprecated" src="https://github.com/user-attachments/assets/e04e4a5c-c104-4945-96d6-889a47b7bcde" />
119
124
 
120
125
 
package/dist/index.mjs CHANGED
@@ -389,18 +389,33 @@ const descriptors$1 = [
389
389
  "base": "window",
390
390
  "prop": "alert"
391
391
  },
392
+ {
393
+ "featureId": "alerts",
394
+ "kind": "callGlobal",
395
+ "name": "alert"
396
+ },
392
397
  {
393
398
  "featureId": "alerts",
394
399
  "kind": "member",
395
400
  "base": "window",
396
401
  "prop": "confirm"
397
402
  },
403
+ {
404
+ "featureId": "alerts",
405
+ "kind": "callGlobal",
406
+ "name": "confirm"
407
+ },
398
408
  {
399
409
  "featureId": "alerts",
400
410
  "kind": "member",
401
411
  "base": "window",
402
412
  "prop": "prompt"
403
413
  },
414
+ {
415
+ "featureId": "alerts",
416
+ "kind": "callGlobal",
417
+ "name": "prompt"
418
+ },
404
419
  {
405
420
  "featureId": "ambient-light",
406
421
  "kind": "callGlobal",
@@ -1785,9 +1800,8 @@ const descriptors$1 = [
1785
1800
  },
1786
1801
  {
1787
1802
  "featureId": "audio",
1788
- "kind": "instanceMember",
1789
- "iface": "HTMLAudioElement",
1790
- "prop": "Audio"
1803
+ "kind": "newIdent",
1804
+ "name": "Audio"
1791
1805
  },
1792
1806
  {
1793
1807
  "featureId": "audio-session",
@@ -4035,7 +4049,7 @@ const descriptors$1 = [
4035
4049
  },
4036
4050
  {
4037
4051
  "featureId": "compute-pressure",
4038
- "kind": "callStatic",
4052
+ "kind": "staticMember",
4039
4053
  "base": "PressureObserver",
4040
4054
  "prop": "knownSources"
4041
4055
  },
@@ -7233,6 +7247,11 @@ const descriptors$1 = [
7233
7247
  "base": "window",
7234
7248
  "prop": "getDigitalGoodsService"
7235
7249
  },
7250
+ {
7251
+ "featureId": "digital-goods",
7252
+ "kind": "callGlobal",
7253
+ "name": "getDigitalGoodsService"
7254
+ },
7236
7255
  {
7237
7256
  "featureId": "dirname",
7238
7257
  "kind": "instanceMember",
@@ -11671,6 +11690,11 @@ const descriptors$1 = [
11671
11690
  "base": "window",
11672
11691
  "prop": "fetchLater"
11673
11692
  },
11693
+ {
11694
+ "featureId": "fetchlater",
11695
+ "kind": "callGlobal",
11696
+ "name": "fetchLater"
11697
+ },
11674
11698
  {
11675
11699
  "featureId": "fieldset",
11676
11700
  "kind": "callGlobal",
@@ -12001,18 +12025,33 @@ const descriptors$1 = [
12001
12025
  "base": "window",
12002
12026
  "prop": "showDirectoryPicker"
12003
12027
  },
12028
+ {
12029
+ "featureId": "file-system-access",
12030
+ "kind": "callGlobal",
12031
+ "name": "showDirectoryPicker"
12032
+ },
12004
12033
  {
12005
12034
  "featureId": "file-system-access",
12006
12035
  "kind": "member",
12007
12036
  "base": "window",
12008
12037
  "prop": "showOpenFilePicker"
12009
12038
  },
12039
+ {
12040
+ "featureId": "file-system-access",
12041
+ "kind": "callGlobal",
12042
+ "name": "showOpenFilePicker"
12043
+ },
12010
12044
  {
12011
12045
  "featureId": "file-system-access",
12012
12046
  "kind": "member",
12013
12047
  "base": "window",
12014
12048
  "prop": "showSaveFilePicker"
12015
12049
  },
12050
+ {
12051
+ "featureId": "file-system-access",
12052
+ "kind": "callGlobal",
12053
+ "name": "showSaveFilePicker"
12054
+ },
12016
12055
  {
12017
12056
  "featureId": "focus-events",
12018
12057
  "kind": "instanceMember",
@@ -12715,6 +12754,11 @@ const descriptors$1 = [
12715
12754
  "base": "window",
12716
12755
  "prop": "requestResize"
12717
12756
  },
12757
+ {
12758
+ "featureId": "frame-sizing",
12759
+ "kind": "callGlobal",
12760
+ "name": "requestResize"
12761
+ },
12718
12762
  {
12719
12763
  "featureId": "fullscreen",
12720
12764
  "kind": "instanceMember",
@@ -13265,6 +13309,11 @@ const descriptors$1 = [
13265
13309
  "base": "window",
13266
13310
  "prop": "getComputedStyle"
13267
13311
  },
13312
+ {
13313
+ "featureId": "get-computed-style",
13314
+ "kind": "callGlobal",
13315
+ "name": "getComputedStyle"
13316
+ },
13268
13317
  {
13269
13318
  "featureId": "getallrecords",
13270
13319
  "kind": "instanceMember",
@@ -13423,7 +13472,7 @@ const descriptors$1 = [
13423
13472
  },
13424
13473
  {
13425
13474
  "featureId": "highlight",
13426
- "kind": "callStatic",
13475
+ "kind": "staticMember",
13427
13476
  "base": "CSS",
13428
13477
  "prop": "highlights"
13429
13478
  },
@@ -14469,9 +14518,8 @@ const descriptors$1 = [
14469
14518
  },
14470
14519
  {
14471
14520
  "featureId": "img",
14472
- "kind": "instanceMember",
14473
- "iface": "HTMLImageElement",
14474
- "prop": "Image"
14521
+ "kind": "newIdent",
14522
+ "name": "Image"
14475
14523
  },
14476
14524
  {
14477
14525
  "featureId": "img",
@@ -16607,6 +16655,11 @@ const descriptors$1 = [
16607
16655
  "base": "window",
16608
16656
  "prop": "queryLocalFonts"
16609
16657
  },
16658
+ {
16659
+ "featureId": "local-fonts",
16660
+ "kind": "callGlobal",
16661
+ "name": "queryLocalFonts"
16662
+ },
16610
16663
  {
16611
16664
  "featureId": "local-network-access",
16612
16665
  "kind": "instanceMember",
@@ -17107,6 +17160,11 @@ const descriptors$1 = [
17107
17160
  "base": "window",
17108
17161
  "prop": "matchMedia"
17109
17162
  },
17163
+ {
17164
+ "featureId": "matchmedia",
17165
+ "kind": "callGlobal",
17166
+ "name": "matchMedia"
17167
+ },
17110
17168
  {
17111
17169
  "featureId": "mathml",
17112
17170
  "kind": "callGlobal",
@@ -17682,7 +17740,7 @@ const descriptors$1 = [
17682
17740
  },
17683
17741
  {
17684
17742
  "featureId": "media-source",
17685
- "kind": "callStatic",
17743
+ "kind": "staticMember",
17686
17744
  "base": "MediaSource",
17687
17745
  "prop": "canConstructInDedicatedWorker"
17688
17746
  },
@@ -19389,13 +19447,13 @@ const descriptors$1 = [
19389
19447
  },
19390
19448
  {
19391
19449
  "featureId": "notifications",
19392
- "kind": "callStatic",
19450
+ "kind": "staticMember",
19393
19451
  "base": "Notification",
19394
19452
  "prop": "maxActions"
19395
19453
  },
19396
19454
  {
19397
19455
  "featureId": "notifications",
19398
- "kind": "callStatic",
19456
+ "kind": "staticMember",
19399
19457
  "base": "Notification",
19400
19458
  "prop": "permission"
19401
19459
  },
@@ -21171,7 +21229,7 @@ const descriptors$1 = [
21171
21229
  },
21172
21230
  {
21173
21231
  "featureId": "paint",
21174
- "kind": "callStatic",
21232
+ "kind": "staticMember",
21175
21233
  "base": "CSS",
21176
21234
  "prop": "paintWorklet"
21177
21235
  },
@@ -21992,7 +22050,7 @@ const descriptors$1 = [
21992
22050
  },
21993
22051
  {
21994
22052
  "featureId": "performance",
21995
- "kind": "callStatic",
22053
+ "kind": "staticMember",
21996
22054
  "base": "PerformanceObserver",
21997
22055
  "prop": "supportedEntryTypes"
21998
22056
  },
@@ -22787,6 +22845,11 @@ const descriptors$1 = [
22787
22845
  "base": "window",
22788
22846
  "prop": "postMessage"
22789
22847
  },
22848
+ {
22849
+ "featureId": "postmessage",
22850
+ "kind": "callGlobal",
22851
+ "name": "postMessage"
22852
+ },
22790
22853
  {
22791
22854
  "featureId": "postmessage",
22792
22855
  "kind": "instanceMember",
@@ -23045,6 +23108,11 @@ const descriptors$1 = [
23045
23108
  "base": "window",
23046
23109
  "prop": "print"
23047
23110
  },
23111
+ {
23112
+ "featureId": "print",
23113
+ "kind": "callGlobal",
23114
+ "name": "print"
23115
+ },
23048
23116
  {
23049
23117
  "featureId": "print-events",
23050
23118
  "kind": "member",
@@ -23250,7 +23318,7 @@ const descriptors$1 = [
23250
23318
  },
23251
23319
  {
23252
23320
  "featureId": "push",
23253
- "kind": "callStatic",
23321
+ "kind": "staticMember",
23254
23322
  "base": "PushManager",
23255
23323
  "prop": "supportedContentEncodings"
23256
23324
  },
@@ -23816,12 +23884,22 @@ const descriptors$1 = [
23816
23884
  "base": "window",
23817
23885
  "prop": "cancelAnimationFrame"
23818
23886
  },
23887
+ {
23888
+ "featureId": "request-animation-frame",
23889
+ "kind": "callGlobal",
23890
+ "name": "cancelAnimationFrame"
23891
+ },
23819
23892
  {
23820
23893
  "featureId": "request-animation-frame",
23821
23894
  "kind": "member",
23822
23895
  "base": "window",
23823
23896
  "prop": "requestAnimationFrame"
23824
23897
  },
23898
+ {
23899
+ "featureId": "request-animation-frame",
23900
+ "kind": "callGlobal",
23901
+ "name": "requestAnimationFrame"
23902
+ },
23825
23903
  {
23826
23904
  "featureId": "request-animation-frame-workers",
23827
23905
  "kind": "instanceMember",
@@ -23875,12 +23953,22 @@ const descriptors$1 = [
23875
23953
  "base": "window",
23876
23954
  "prop": "cancelIdleCallback"
23877
23955
  },
23956
+ {
23957
+ "featureId": "requestidlecallback",
23958
+ "kind": "callGlobal",
23959
+ "name": "cancelIdleCallback"
23960
+ },
23878
23961
  {
23879
23962
  "featureId": "requestidlecallback",
23880
23963
  "kind": "member",
23881
23964
  "base": "window",
23882
23965
  "prop": "requestIdleCallback"
23883
23966
  },
23967
+ {
23968
+ "featureId": "requestidlecallback",
23969
+ "kind": "callGlobal",
23970
+ "name": "requestIdleCallback"
23971
+ },
23884
23972
  {
23885
23973
  "featureId": "resize-observer",
23886
23974
  "kind": "callGlobal",
@@ -24676,18 +24764,33 @@ const descriptors$1 = [
24676
24764
  "base": "window",
24677
24765
  "prop": "scroll"
24678
24766
  },
24767
+ {
24768
+ "featureId": "scroll-elements",
24769
+ "kind": "callGlobal",
24770
+ "name": "scroll"
24771
+ },
24679
24772
  {
24680
24773
  "featureId": "scroll-elements",
24681
24774
  "kind": "member",
24682
24775
  "base": "window",
24683
24776
  "prop": "scrollBy"
24684
24777
  },
24778
+ {
24779
+ "featureId": "scroll-elements",
24780
+ "kind": "callGlobal",
24781
+ "name": "scrollBy"
24782
+ },
24685
24783
  {
24686
24784
  "featureId": "scroll-elements",
24687
24785
  "kind": "member",
24688
24786
  "base": "window",
24689
24787
  "prop": "scrollTo"
24690
24788
  },
24789
+ {
24790
+ "featureId": "scroll-elements",
24791
+ "kind": "callGlobal",
24792
+ "name": "scrollTo"
24793
+ },
24691
24794
  {
24692
24795
  "featureId": "scroll-elements",
24693
24796
  "kind": "member",
@@ -24817,9 +24920,8 @@ const descriptors$1 = [
24817
24920
  },
24818
24921
  {
24819
24922
  "featureId": "select",
24820
- "kind": "instanceMember",
24821
- "iface": "HTMLOptionElement",
24822
- "prop": "Option"
24923
+ "kind": "newIdent",
24924
+ "name": "Option"
24823
24925
  },
24824
24926
  {
24825
24927
  "featureId": "select",
@@ -25461,6 +25563,11 @@ const descriptors$1 = [
25461
25563
  "base": "window",
25462
25564
  "prop": "getSelection"
25463
25565
  },
25566
+ {
25567
+ "featureId": "selection-api",
25568
+ "kind": "callGlobal",
25569
+ "name": "getSelection"
25570
+ },
25464
25571
  {
25465
25572
  "featureId": "serial",
25466
25573
  "kind": "member",
@@ -26582,6 +26689,15 @@ const descriptors$1 = [
26582
26689
  "iface": "SharedWorkerGlobalScope",
26583
26690
  "prop": "name"
26584
26691
  },
26692
+ {
26693
+ "featureId": "shared-workers-extended-lifetime",
26694
+ "kind": "newWithOptions",
26695
+ "name": "SharedWorker",
26696
+ "objectArg": {
26697
+ "index": 1,
26698
+ "hasKeys": ["extendedLifetime"]
26699
+ }
26700
+ },
26585
26701
  {
26586
26702
  "featureId": "show-picker-input",
26587
26703
  "kind": "instanceMember",
@@ -46460,6 +46576,11 @@ const descriptors$1 = [
46460
46576
  "base": "window",
46461
46577
  "prop": "close"
46462
46578
  },
46579
+ {
46580
+ "featureId": "window",
46581
+ "kind": "callGlobal",
46582
+ "name": "close"
46583
+ },
46463
46584
  {
46464
46585
  "featureId": "window",
46465
46586
  "kind": "member",
@@ -46478,6 +46599,11 @@ const descriptors$1 = [
46478
46599
  "base": "window",
46479
46600
  "prop": "focus"
46480
46601
  },
46602
+ {
46603
+ "featureId": "window",
46604
+ "kind": "callGlobal",
46605
+ "name": "focus"
46606
+ },
46481
46607
  {
46482
46608
  "featureId": "window",
46483
46609
  "kind": "member",
@@ -46526,12 +46652,22 @@ const descriptors$1 = [
46526
46652
  "base": "window",
46527
46653
  "prop": "moveBy"
46528
46654
  },
46655
+ {
46656
+ "featureId": "window",
46657
+ "kind": "callGlobal",
46658
+ "name": "moveBy"
46659
+ },
46529
46660
  {
46530
46661
  "featureId": "window",
46531
46662
  "kind": "member",
46532
46663
  "base": "window",
46533
46664
  "prop": "moveTo"
46534
46665
  },
46666
+ {
46667
+ "featureId": "window",
46668
+ "kind": "callGlobal",
46669
+ "name": "moveTo"
46670
+ },
46535
46671
  {
46536
46672
  "featureId": "window",
46537
46673
  "kind": "member",
@@ -46544,6 +46680,11 @@ const descriptors$1 = [
46544
46680
  "base": "window",
46545
46681
  "prop": "open"
46546
46682
  },
46683
+ {
46684
+ "featureId": "window",
46685
+ "kind": "callGlobal",
46686
+ "name": "open"
46687
+ },
46547
46688
  {
46548
46689
  "featureId": "window",
46549
46690
  "kind": "member",
@@ -46574,12 +46715,22 @@ const descriptors$1 = [
46574
46715
  "base": "window",
46575
46716
  "prop": "resizeBy"
46576
46717
  },
46718
+ {
46719
+ "featureId": "window",
46720
+ "kind": "callGlobal",
46721
+ "name": "resizeBy"
46722
+ },
46577
46723
  {
46578
46724
  "featureId": "window",
46579
46725
  "kind": "member",
46580
46726
  "base": "window",
46581
46727
  "prop": "resizeTo"
46582
46728
  },
46729
+ {
46730
+ "featureId": "window",
46731
+ "kind": "callGlobal",
46732
+ "name": "resizeTo"
46733
+ },
46583
46734
  {
46584
46735
  "featureId": "window",
46585
46736
  "kind": "member",
@@ -46628,6 +46779,11 @@ const descriptors$1 = [
46628
46779
  "base": "window",
46629
46780
  "prop": "stop"
46630
46781
  },
46782
+ {
46783
+ "featureId": "window",
46784
+ "kind": "callGlobal",
46785
+ "name": "stop"
46786
+ },
46631
46787
  {
46632
46788
  "featureId": "window",
46633
46789
  "kind": "member",
@@ -46797,6 +46953,11 @@ const descriptors$1 = [
46797
46953
  "base": "window",
46798
46954
  "prop": "getScreenDetails"
46799
46955
  },
46956
+ {
46957
+ "featureId": "window-management",
46958
+ "kind": "callGlobal",
46959
+ "name": "getScreenDetails"
46960
+ },
46800
46961
  {
46801
46962
  "featureId": "writingsuggestions",
46802
46963
  "kind": "instanceMember",
@@ -64093,360 +64254,294 @@ function isBeyondBaseline(featureId, baseline) {
64093
64254
  return false;
64094
64255
  }
64095
64256
  //#endregion
64096
- //#region src/utils/listeners.ts
64097
- /**
64098
- * Merge one or more source listener maps into an existing map.
64099
- * This preserves execution order (existing listeners run before new ones)
64100
- * while keeping the original object reference intact.
64101
- */
64102
- function mergeRuleListeners(target, ...sources) {
64103
- const dest = target;
64104
- for (const source of sources) {
64105
- if (!source) continue;
64106
- for (const [event, handler] of Object.entries(source)) {
64107
- const prev = target[event];
64108
- if (!prev) {
64109
- dest[event] = handler;
64110
- continue;
64111
- }
64112
- const next = handler;
64113
- dest[event] = function merged(...args) {
64114
- prev.apply(this, args);
64115
- next.apply(this, args);
64116
- };
64117
- }
64118
- }
64119
- return target;
64120
- }
64121
- //#endregion
64122
64257
  //#region src/util/ast.ts
64123
- /**
64124
- * Checks if an identifier refers to the global (not shadowed by a local declaration).
64125
- * Unlike isUnboundIdentifier, this treats global built-ins (like Atomics, structuredClone)
64126
- * as allowed, while still respecting explicit global declarations that shadow them.
64127
- *
64128
- * @param context - The ESLint rule context
64129
- * @param name - The identifier name to check
64130
- * @param parentNode - The parent node (CallExpression or MemberExpression)
64131
- */
64132
- function isGlobalNotShadowed(context, name, parentNode) {
64133
- function findVariable(scope, varName) {
64134
- const bySet = scope.set?.get?.(varName);
64135
- if (bySet) return {
64136
- found: true,
64137
- variable: bySet
64138
- };
64139
- if (Array.isArray(scope.variables)) {
64140
- const byVars = scope.variables.find((v) => v?.name === varName);
64141
- if (byVars) return {
64142
- found: true,
64143
- variable: byVars
64144
- };
64145
- }
64146
- if (scope.set?.has?.(varName)) return { found: true };
64147
- return { found: false };
64148
- }
64149
- const sourceCode = context.sourceCode;
64150
- if (!sourceCode?.getScope) return true;
64151
- let current = sourceCode.getScope(parentNode);
64152
- while (current) {
64153
- const s = current;
64154
- const { found, variable } = findVariable(s, name);
64155
- if (found) {
64156
- if (s.type !== "global") return false;
64157
- const defs = variable?.defs;
64158
- if (Array.isArray(defs) && defs.length > 0) return false;
64159
- return true;
64160
- }
64161
- current = s.upper || null;
64258
+ /** Built-in globals have no definitions; explicit declarations shadow them. */
64259
+ function isGlobalNotShadowed(context, name, reference) {
64260
+ let scope = context.sourceCode.getScope(reference);
64261
+ while (scope) {
64262
+ const variable = scope.set.get(name);
64263
+ if (variable) return scope.type === "global" && variable.defs.length === 0;
64264
+ scope = scope.upper;
64162
64265
  }
64163
64266
  return true;
64164
64267
  }
64165
- function isGlobalBase(_context, node, baseName) {
64166
- if (!node) return false;
64167
- const id = node;
64168
- if (id.type === "Identifier" && id.name === baseName) return true;
64169
- const me = node;
64170
- if (me.type === "MemberExpression" && me.computed === false) {
64171
- const obj = me.object;
64172
- const prop = me.property;
64173
- if (!(obj?.type === "Identifier" && (obj.name === "window" || obj.name === "globalThis"))) return false;
64174
- return prop?.type === "Identifier" && prop.name === baseName;
64268
+ const GLOBAL_OBJECT_NAMES = /* @__PURE__ */ new Set([
64269
+ "window",
64270
+ "globalThis",
64271
+ "self"
64272
+ ]);
64273
+ function staticPropertyName(node, computed) {
64274
+ if (!computed && node.type === "Identifier") return node.name;
64275
+ if (node.type === "Literal" && typeof node.value === "string") return node.value;
64276
+ return null;
64277
+ }
64278
+ function stripChain(node) {
64279
+ return node.type === "ChainExpression" ? node.expression : node;
64280
+ }
64281
+ function getStaticMemberName(node) {
64282
+ const member = stripChain(node);
64283
+ return member.type === "MemberExpression" ? staticPropertyName(member.property, member.computed) : null;
64284
+ }
64285
+ function globalObjectRoot(node) {
64286
+ let current = stripChain(node);
64287
+ while (current.type === "MemberExpression") {
64288
+ const name = getStaticMemberName(current);
64289
+ if (name === null || !GLOBAL_OBJECT_NAMES.has(name)) return null;
64290
+ current = stripChain(current.object);
64175
64291
  }
64176
- return false;
64292
+ return current.type === "Identifier" && GLOBAL_OBJECT_NAMES.has(current.name) ? current.name : null;
64177
64293
  }
64178
- function collectGlobalBaseRoots(node, baseName) {
64179
- const id = node;
64180
- if (id.type === "Identifier" && id.name === baseName) return [baseName];
64181
- const me = node;
64182
- if (me.type !== "MemberExpression" || me.computed) return [];
64183
- const obj = me.object;
64184
- const prop = me.property;
64185
- if (obj?.type !== "Identifier" || prop?.type !== "Identifier") return [];
64186
- if (prop.name !== baseName) return [];
64187
- if (obj.name === "window" || obj.name === "globalThis") return [obj.name];
64188
- return [];
64294
+ function globalBaseRoot(node, baseName) {
64295
+ const base = stripChain(node);
64296
+ if (base.type === "Identifier" && base.name === baseName) return baseName;
64297
+ if (baseName === "window") {
64298
+ const root = globalObjectRoot(base);
64299
+ if (root !== null) return root;
64300
+ }
64301
+ if (base.type !== "MemberExpression" || getStaticMemberName(base) !== baseName) return null;
64302
+ return globalObjectRoot(base.object);
64189
64303
  }
64190
- function isGlobalBaseNotShadowed(context, node, baseName, parentNode) {
64191
- if (!isGlobalBase(context, node, baseName)) return false;
64192
- const roots = collectGlobalBaseRoots(node, baseName);
64193
- if (!roots.length) return false;
64194
- return roots.every((name) => isGlobalNotShadowed(context, name, parentNode));
64304
+ function isGlobalBaseNotShadowed(context, node, baseName, reference) {
64305
+ const root = globalBaseRoot(node, baseName);
64306
+ return root !== null && isGlobalNotShadowed(context, root, reference);
64195
64307
  }
64196
- function isMemberWithProperty(node, propName) {
64197
- const me = node;
64198
- if (!me || me.type !== "MemberExpression" || me.computed) return false;
64199
- const prop = me.property;
64200
- return prop?.type === "Identifier" && prop.name === propName;
64308
+ function isMemberWithProperty(node, name) {
64309
+ return getStaticMemberName(node) === name;
64201
64310
  }
64202
- function stripChain(node) {
64203
- const n = node;
64204
- if (n && n.type === "ChainExpression") return n.expression;
64205
- return node;
64311
+ function getMemberPropertyNode(node) {
64312
+ const member = stripChain(node);
64313
+ return member.type === "MemberExpression" ? member.property : null;
64206
64314
  }
64207
64315
  function getCallStringArg(call, index) {
64208
- const a = (call.arguments || [])[index];
64209
- if (!a) return null;
64210
- if (a.type === "Literal" && typeof a.value === "string") return a.value;
64211
- return null;
64316
+ const argument = call.arguments[index];
64317
+ return argument?.type === "Literal" && typeof argument.value === "string" ? argument.value : null;
64212
64318
  }
64213
64319
  function getCallObjectArg(call, index) {
64214
- const a = (call.arguments || [])[index];
64215
- if (!a) return null;
64216
- if (a.type === "ObjectExpression") return a;
64217
- return null;
64320
+ const argument = call.arguments[index];
64321
+ return argument?.type === "ObjectExpression" ? argument : null;
64218
64322
  }
64219
- function objectHasKey(obj, key) {
64220
- const o = obj;
64221
- if (!o || o.type !== "ObjectExpression") return false;
64222
- for (const p of o.properties || []) {
64223
- const prop = p;
64224
- if (prop.type !== "Property") continue;
64225
- if (prop.computed) continue;
64226
- const k = prop.key;
64227
- if (k?.type === "Identifier" && k.name === key) return true;
64228
- if (k?.type === "Literal" && k.value === key) return true;
64229
- }
64230
- return false;
64323
+ function objectHasKey(object, key) {
64324
+ return object.properties.some((property) => property.type === "Property" && staticPropertyName(property.key, property.computed) === key);
64231
64325
  }
64232
- function objectHasKeyWithValues(obj, cfg) {
64233
- const o = obj;
64234
- if (!o || o.type !== "ObjectExpression") return false;
64235
- for (const p of o.properties || []) {
64236
- const prop = p;
64237
- if (prop.type !== "Property") continue;
64238
- if (prop.computed) continue;
64239
- const k = prop.key;
64240
- if (!(k?.type === "Identifier" && k.name === cfg.key || k?.type === "Literal" && k.value === cfg.key)) continue;
64241
- if (!cfg.values || cfg.values.length === 0) return true;
64242
- const v = prop.value;
64243
- if (v?.type === "Literal" && cfg.values.includes(String(v.value))) return true;
64326
+ function objectHasKeyWithValues(object, config) {
64327
+ for (let index = object.properties.length - 1; index >= 0; index--) {
64328
+ const property = object.properties[index];
64329
+ if (property.type !== "Property") return false;
64330
+ const key = staticPropertyName(property.key, property.computed);
64331
+ if (key === null && property.computed && property.key.type !== "Literal") return false;
64332
+ if (key !== config.key) continue;
64333
+ if (!config.values?.length) return true;
64334
+ return property.value.type === "Literal" && config.values.includes(String(property.value.value));
64244
64335
  }
64245
64336
  return false;
64246
64337
  }
64247
- function isCallOfMember(node, prop) {
64248
- const n = stripChain(node);
64249
- if (!n || n.type !== "CallExpression") return false;
64250
- const callee = n.callee;
64251
- return isMemberWithProperty(callee, prop);
64338
+ function isCallOfMember(node, property) {
64339
+ const call = stripChain(node);
64340
+ return call.type === "CallExpression" && getStaticMemberName(call.callee) === property;
64341
+ }
64342
+ //#endregion
64343
+ //#region src/util/typed-parser-services.ts
64344
+ function getTypedParserServices(context) {
64345
+ const services = context.sourceCode.parserServices;
64346
+ if (!services?.program || !services.esTreeNodeToTSNodeMap) return void 0;
64347
+ return {
64348
+ program: services.program,
64349
+ esTreeNodeToTSNodeMap: services.esTreeNodeToTSNodeMap
64350
+ };
64252
64351
  }
64253
64352
  //#endregion
64254
64353
  //#region src/rules/feature-usage/detectors/safe-args.ts
64255
- function matchesObjectArg(obj, d) {
64256
- if (!obj) return false;
64257
- if (d.hasKeys?.length) {
64258
- for (const k of d.hasKeys) if (!objectHasKey(obj, k)) return false;
64259
- }
64260
- if (d.keyValues?.length) {
64261
- for (const kv of d.keyValues) if (!objectHasKeyWithValues(obj, kv)) return false;
64262
- }
64354
+ function matchesObjectArg(object, descriptor) {
64355
+ if (!object) return false;
64356
+ for (const key of descriptor.hasKeys ?? []) if (!objectHasKey(object, key)) return false;
64357
+ for (const keyValue of descriptor.keyValues ?? []) if (!objectHasKeyWithValues(object, keyValue)) return false;
64263
64358
  return true;
64264
64359
  }
64265
- function addCallMemberWithArgsDetector(_context, d, report) {
64266
- const handler = (node) => {
64267
- const callee = node.callee;
64268
- if (!callee || callee.type !== "MemberExpression") return;
64269
- const propNode = callee.property;
64270
- if ((propNode?.type === "Identifier" ? propNode.name : propNode?.type === "Literal" ? String(propNode.value) : void 0) !== d.prop) return;
64271
- if (d.viaCall?.prop) {
64272
- const recv = callee.object;
64273
- if (!isCallOfMember(recv, d.viaCall.prop)) return;
64274
- }
64275
- if (d.stringArg) {
64276
- const s = getCallStringArg(node, d.stringArg.index);
64277
- if (!s || !d.stringArg.values.includes(s)) return;
64278
- }
64279
- if (d.objectArg) {
64280
- const obj = getCallObjectArg(node, d.objectArg.index);
64281
- if (!obj) return;
64282
- if (!matchesObjectArg(obj, d.objectArg)) return;
64283
- }
64284
- report(node, d.featureId);
64285
- };
64286
- return { CallExpression: handler };
64360
+ function addCallMemberWithArgsDetector(_context, descriptor, report) {
64361
+ return { CallExpression(node) {
64362
+ const callee = stripChain(node.callee);
64363
+ if (callee.type !== "MemberExpression" || getStaticMemberName(callee) !== descriptor.prop) return;
64364
+ if (descriptor.viaCall?.prop && !isCallOfMember(callee.object, descriptor.viaCall.prop)) return;
64365
+ if (descriptor.stringArg) {
64366
+ const argument = getCallStringArg(node, descriptor.stringArg.index);
64367
+ if (!argument || !descriptor.stringArg.values.includes(argument)) return;
64368
+ }
64369
+ if (descriptor.objectArg && !matchesObjectArg(getCallObjectArg(node, descriptor.objectArg.index), descriptor.objectArg)) return;
64370
+ report(node, descriptor.featureId);
64371
+ } };
64287
64372
  }
64288
- function addNewWithOptionsDetector(context, d, report) {
64289
- const handler = (node) => {
64290
- const callee = node.callee;
64291
- if (callee?.type !== "Identifier" || callee.name !== d.name) return;
64292
- if (!isGlobalBaseNotShadowed(context, callee, d.name, node)) return;
64293
- const obj = getCallObjectArg(node, d.objectArg.index);
64294
- if (!obj) return;
64295
- if (d.objectArg.hasKeys?.length) {
64296
- for (const k of d.objectArg.hasKeys) if (!objectHasKey(obj, k)) return;
64297
- }
64298
- if (d.objectArg.keyValues?.length) {
64299
- for (const kv of d.objectArg.keyValues) if (!objectHasKeyWithValues(obj, kv)) return;
64300
- }
64301
- report(callee, d.featureId);
64302
- };
64303
- return { NewExpression: handler };
64373
+ function addNewWithOptionsDetector(context, descriptor, report) {
64374
+ return { NewExpression(node) {
64375
+ const callee = stripChain(node.callee);
64376
+ if (!isGlobalBaseNotShadowed(context, callee, descriptor.name, node)) return;
64377
+ if (!matchesObjectArg(getCallObjectArg(node, descriptor.objectArg.index), descriptor.objectArg)) return;
64378
+ report(getMemberPropertyNode(callee) ?? callee, descriptor.featureId);
64379
+ } };
64304
64380
  }
64305
64381
  //#endregion
64306
64382
  //#region src/rules/feature-usage/detectors/safe-core.ts
64307
- function addNewIdentDetector(context, d, report) {
64308
- const name = d.name;
64309
- const featureId = d.featureId;
64310
- const handler = (node) => {
64311
- const callee = node.callee;
64312
- if (callee?.type === "Identifier" && callee.name === name && isGlobalBaseNotShadowed(context, callee, name, node)) report(callee, featureId);
64313
- };
64314
- return { NewExpression: handler };
64383
+ function addNewIdentDetector(context, descriptor, report) {
64384
+ const { name, featureId } = descriptor;
64385
+ return { NewExpression(node) {
64386
+ const callee = stripChain(node.callee);
64387
+ if (isGlobalBaseNotShadowed(context, callee, name, node)) report(getMemberPropertyNode(callee) ?? callee, featureId);
64388
+ } };
64315
64389
  }
64316
- function addNewMemberDetector(context, d, report) {
64317
- const { base, prop, featureId } = d;
64318
- const handler = (node) => {
64319
- const callee = node.callee;
64320
- if (isMemberWithProperty(callee, prop) && isGlobalBaseNotShadowed(context, callee.object, base, node)) report(callee.property, featureId);
64321
- };
64322
- return { NewExpression: handler };
64390
+ function addNewMemberDetector(context, descriptor, report) {
64391
+ const { base, prop, featureId } = descriptor;
64392
+ return { NewExpression(node) {
64393
+ const callee = stripChain(node.callee);
64394
+ if (callee.type === "MemberExpression" && getStaticMemberName(callee) === prop && isGlobalBaseNotShadowed(context, callee.object, base, node)) report(callee.property, featureId);
64395
+ } };
64323
64396
  }
64324
- function addCallStaticDetector(context, d, report) {
64325
- const { base, prop, featureId } = d;
64326
- const handler = (node) => {
64327
- const callee = node.callee;
64328
- if (isMemberWithProperty(callee, prop) && isGlobalBaseNotShadowed(context, callee.object, base, node)) report(callee.property, featureId);
64329
- };
64330
- return { CallExpression: handler };
64397
+ function addCallStaticDetector(context, descriptor, report) {
64398
+ const { base, prop, featureId } = descriptor;
64399
+ return { CallExpression(node) {
64400
+ const callee = stripChain(node.callee);
64401
+ if (callee.type === "MemberExpression" && getStaticMemberName(callee) === prop && isGlobalBaseNotShadowed(context, callee.object, base, node)) report(callee.property, featureId);
64402
+ } };
64331
64403
  }
64332
- function addCallGlobalDetector(context, d, report) {
64333
- const { name, featureId } = d;
64334
- const handler = (node) => {
64335
- const callee = node.callee;
64336
- if (callee?.type === "Identifier" && callee.name === name && isGlobalBaseNotShadowed(context, callee, name, node)) report(callee, featureId);
64337
- };
64338
- return { CallExpression: handler };
64404
+ function addCallGlobalDetector(context, descriptor, report) {
64405
+ const { name, featureId } = descriptor;
64406
+ return { CallExpression(node) {
64407
+ const callee = stripChain(node.callee);
64408
+ if (isGlobalBaseNotShadowed(context, callee, name, node)) report(getMemberPropertyNode(callee) ?? callee, featureId);
64409
+ } };
64339
64410
  }
64340
- function addMemberDetector(context, d, report) {
64341
- const { base, prop, featureId } = d;
64342
- const handler = (node) => {
64343
- if (isMemberWithProperty(node, prop) && isGlobalBaseNotShadowed(context, node.object, base, node)) report(node.property, featureId);
64344
- };
64345
- return { MemberExpression: handler };
64411
+ function addMemberDetector(context, descriptor, report) {
64412
+ const { base, prop, featureId } = descriptor;
64413
+ return { MemberExpression(node) {
64414
+ if (getStaticMemberName(node) === prop && isGlobalBaseNotShadowed(context, node.object, base, node)) report(node.property, featureId);
64415
+ } };
64346
64416
  }
64347
- function addStaticMemberDetector(context, d, report) {
64348
- return addMemberDetector(context, d, report);
64417
+ function addStaticMemberDetector(context, descriptor, report) {
64418
+ return addMemberDetector(context, descriptor, report);
64349
64419
  }
64350
64420
  //#endregion
64351
64421
  //#region src/rules/feature-usage/detectors/typed-instance-member.ts
64352
64422
  function addTypedInstanceMemberDetector(context, d, report) {
64353
64423
  const { iface, prop, featureId } = d;
64354
- const ctxLike = context;
64355
- const services = ctxLike.parserServices || ctxLike.sourceCode?.parserServices || {};
64356
- const checker = services.program?.getTypeChecker?.();
64357
- if (!checker || !services.esTreeNodeToTSNodeMap) return {};
64358
- const checkerOk = checker;
64359
- const tsMap = services.esTreeNodeToTSNodeMap;
64360
- const tsMapGet = tsMap.get;
64361
- if (typeof tsMapGet !== "function") return {};
64362
- const getTsNode = tsMapGet.bind(tsMap);
64363
- const typeAtLocation = checkerOk.getTypeAtLocation;
64364
- if (typeof typeAtLocation !== "function") return {};
64365
- const getTypeAtLocation = typeAtLocation.bind(checkerOk);
64366
- const propertyOfType = checkerOk.getPropertyOfType;
64367
- if (typeof propertyOfType !== "function") return {};
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 || [];
64424
+ const services = getTypedParserServices(context);
64425
+ if (!services) return {};
64426
+ const checker = services.program.getTypeChecker();
64427
+ function getBaseTypes(type) {
64428
+ const bases = type.getBaseTypes();
64429
+ if (bases) return bases;
64430
+ if (isTypeReference(type)) return type.target.getBaseTypes() ?? [];
64431
+ return [];
64372
64432
  }
64373
- function typeMatches(t) {
64374
- if (!t) return false;
64375
- const withTypes = t;
64376
- if (Array.isArray(withTypes.types)) return withTypes.types.some((tt) => typeMatches(tt));
64377
- const withSym = t;
64378
- const name = (withSym.symbol || withSym.aliasSymbol || withSym.getSymbol?.())?.name;
64433
+ function typeMatches(type, seen = /* @__PURE__ */ new Set()) {
64434
+ if (seen.has(type)) return false;
64435
+ seen.add(type);
64436
+ if (type.isUnionOrIntersection()) return type.types.some((part) => typeMatches(part, seen));
64437
+ const name = (type.getSymbol() ?? type.aliasSymbol)?.getName();
64379
64438
  if (name === iface || name?.endsWith(`.${iface}`)) return true;
64380
- const baseTypes = getBaseTypes(checkerOk.getApparentType?.(t) || t);
64381
- if (baseTypes?.length) {
64382
- if (baseTypes.some((bt) => bt.symbol?.name === iface)) return true;
64383
- for (const bt of baseTypes) {
64384
- const bt2 = getBaseTypes(bt);
64385
- if (Array.isArray(bt2) && bt2.some((b2) => b2.symbol?.name === iface)) return true;
64386
- }
64387
- }
64388
- return false;
64439
+ const apparent = checker.getApparentType(type);
64440
+ if (apparent !== type && typeMatches(apparent, seen)) return true;
64441
+ const constraint = checker.getBaseConstraintOfType(type);
64442
+ if (constraint && constraint !== type && typeMatches(constraint, seen)) return true;
64443
+ return getBaseTypes(type).some((base) => typeMatches(base, seen));
64389
64444
  }
64390
64445
  const handler = (node) => {
64391
64446
  if (!isMemberWithProperty(node, prop)) return;
64392
- const obj = node.object;
64393
- const tsNode = getTsNode(obj);
64447
+ const tsNode = services.esTreeNodeToTSNodeMap.get(node.object);
64394
64448
  if (!tsNode) return;
64395
- const type = getTypeAtLocation(tsNode);
64396
- if (!type) return;
64397
- if (!!!getPropertyOfType(type, prop)) return;
64449
+ const type = checker.getNonNullableType(checker.getTypeAtLocation(tsNode));
64450
+ if (!checker.getPropertyOfType(type, prop)) return;
64398
64451
  if (typeMatches(type)) report(node.property, featureId);
64399
64452
  };
64400
64453
  return { MemberExpression: handler };
64401
64454
  }
64455
+ function isTypeReference(type) {
64456
+ return "target" in type;
64457
+ }
64402
64458
  //#endregion
64403
64459
  //#region src/rules/feature-usage/builder.ts
64404
64460
  function buildListeners(context, opt) {
64405
- const listeners = {};
64406
- const ctxLike = context;
64407
- const services = ctxLike.parserServices || ctxLike.sourceCode?.parserServices || {};
64408
- const checker = services.program?.getTypeChecker?.();
64409
- const useTyped = !!opt.typed && !!checker && !!services.esTreeNodeToTSNodeMap;
64461
+ const calls = /* @__PURE__ */ new Map();
64462
+ const constructions = /* @__PURE__ */ new Map();
64463
+ const members = /* @__PURE__ */ new Map();
64464
+ function addHandler(handlers, name, handler) {
64465
+ if (!handler) return;
64466
+ const bucket = handlers.get(name);
64467
+ if (bucket) bucket.push(handler);
64468
+ else handlers.set(name, [handler]);
64469
+ }
64470
+ function calleeName(callee) {
64471
+ const node = stripChain(callee);
64472
+ return node.type === "Identifier" ? node.name : getStaticMemberName(node);
64473
+ }
64474
+ const reportedFeatures = /* @__PURE__ */ new WeakMap();
64475
+ const useTyped = !!opt.typed && !!getTypedParserServices(context);
64410
64476
  for (const d of opt.descriptors) {
64411
64477
  function report(node) {
64478
+ let features = reportedFeatures.get(node);
64479
+ if (features?.has(d.featureId)) return;
64480
+ if (!features) {
64481
+ features = /* @__PURE__ */ new Set();
64482
+ reportedFeatures.set(node, features);
64483
+ }
64484
+ features.add(d.featureId);
64412
64485
  opt.report(node, d);
64413
64486
  }
64414
64487
  switch (d.kind) {
64415
64488
  case "newIdent":
64416
- mergeRuleListeners(listeners, addNewIdentDetector(context, d, report));
64489
+ addHandler(constructions, d.name, addNewIdentDetector(context, d, report).NewExpression);
64417
64490
  break;
64418
64491
  case "newMember":
64419
- mergeRuleListeners(listeners, addNewMemberDetector(context, d, report));
64492
+ addHandler(constructions, d.prop, addNewMemberDetector(context, d, report).NewExpression);
64420
64493
  break;
64421
64494
  case "callStatic":
64422
- mergeRuleListeners(listeners, addCallStaticDetector(context, d, report));
64495
+ addHandler(calls, d.prop, addCallStaticDetector(context, d, report).CallExpression);
64423
64496
  break;
64424
64497
  case "callGlobal":
64425
- mergeRuleListeners(listeners, addCallGlobalDetector(context, d, report));
64498
+ addHandler(calls, d.name, addCallGlobalDetector(context, d, report).CallExpression);
64426
64499
  break;
64427
64500
  case "member":
64428
- mergeRuleListeners(listeners, addMemberDetector(context, d, report));
64501
+ addHandler(members, d.prop, addMemberDetector(context, d, report).MemberExpression);
64429
64502
  break;
64430
64503
  case "staticMember":
64431
- mergeRuleListeners(listeners, addStaticMemberDetector(context, d, report));
64504
+ addHandler(members, d.prop, addStaticMemberDetector(context, d, report).MemberExpression);
64432
64505
  break;
64433
64506
  case "instanceMember":
64434
- if (useTyped) mergeRuleListeners(listeners, addTypedInstanceMemberDetector(context, d, report));
64507
+ if (useTyped) addHandler(members, d.prop, addTypedInstanceMemberDetector(context, d, report).MemberExpression);
64435
64508
  break;
64436
64509
  case "callMemberWithArgs":
64437
- mergeRuleListeners(listeners, addCallMemberWithArgsDetector(context, d, report));
64510
+ addHandler(calls, d.prop, addCallMemberWithArgsDetector(context, d, report).CallExpression);
64438
64511
  break;
64439
- case "newWithOptions": mergeRuleListeners(listeners, addNewWithOptionsDetector(context, d, report));
64512
+ case "newWithOptions":
64513
+ addHandler(constructions, d.name, addNewWithOptionsDetector(context, d, report).NewExpression);
64514
+ break;
64515
+ default: throw new Error(`Unsupported descriptor: ${JSON.stringify(d)}`);
64440
64516
  }
64441
64517
  }
64442
- return listeners;
64518
+ return {
64519
+ CallExpression(node) {
64520
+ const name = calleeName(node.callee);
64521
+ if (name === null) return;
64522
+ for (const handler of calls.get(name) ?? []) handler(node);
64523
+ },
64524
+ NewExpression(node) {
64525
+ const name = calleeName(node.callee);
64526
+ if (name === null) return;
64527
+ for (const handler of constructions.get(name) ?? []) handler(node);
64528
+ },
64529
+ MemberExpression(node) {
64530
+ const name = getStaticMemberName(node);
64531
+ if (name === null) return;
64532
+ for (const handler of members.get(name) ?? []) handler(node);
64533
+ }
64534
+ };
64443
64535
  }
64444
64536
  //#endregion
64445
64537
  //#region src/rules/no-atomics-pause/index.ts
64446
64538
  const rule$5 = {
64447
64539
  meta: {
64448
64540
  type: "problem",
64449
- docs: { description: "disallow Atomics.pause() usage" },
64541
+ docs: {
64542
+ description: "disallow Atomics.pause() usage",
64543
+ url: "https://baselinejs.vercel.app/docs/config#standalone-rules"
64544
+ },
64450
64545
  messages: { forbidden: "Atomics.pause is not allowed." },
64451
64546
  schema: []
64452
64547
  },
@@ -64460,13 +64555,12 @@ const rule$5 = {
64460
64555
  return {
64461
64556
  CallExpression(node) {
64462
64557
  const callee = node.callee;
64463
- if (callee && callee.type === "MemberExpression" && callee.computed === false && isGlobalBaseNotShadowed(context, callee.object, "Atomics", node) && callee.property?.type === "Identifier" && callee.property?.name === "pause") report(callee.property);
64558
+ if (callee.type === "MemberExpression" && callee.computed === false && isGlobalBaseNotShadowed(context, callee.object, "Atomics", node) && callee.property.type === "Identifier" && callee.property.name === "pause") report(callee.property);
64464
64559
  },
64465
64560
  MemberExpression(node) {
64466
- const m = node;
64467
- const parent = m.parent;
64468
- if (parent?.type === "CallExpression" && parent.callee === node) return;
64469
- if (m.computed === false && isGlobalBaseNotShadowed(context, m.object, "Atomics", node) && m.property?.type === "Identifier" && m.property?.name === "pause") report(m.property);
64561
+ const parent = node.parent;
64562
+ if (parent.type === "CallExpression" && parent.callee === node) return;
64563
+ if (node.computed === false && isGlobalBaseNotShadowed(context, node.object, "Atomics", node) && node.property.type === "Identifier" && node.property.name === "pause") report(node.property);
64470
64564
  }
64471
64565
  };
64472
64566
  }
@@ -64476,7 +64570,10 @@ const rule$5 = {
64476
64570
  const rule$4 = {
64477
64571
  meta: {
64478
64572
  type: "problem",
64479
- docs: { description: "disallow BigInt64Array/BigUint64Array usage" },
64573
+ docs: {
64574
+ description: "disallow BigInt64Array/BigUint64Array usage",
64575
+ url: "https://baselinejs.vercel.app/docs/config#standalone-rules"
64576
+ },
64480
64577
  messages: { forbidden: "BigInt64Array/BigUint64Array are not allowed." },
64481
64578
  schema: []
64482
64579
  },
@@ -64494,16 +64591,13 @@ const rule$4 = {
64494
64591
  }
64495
64592
  return {
64496
64593
  NewExpression(node) {
64497
- const n = node;
64498
- if (resolveBigIntArrayBase(n.callee, node)) report(n.callee);
64594
+ if (resolveBigIntArrayBase(node.callee, node)) report(node.callee);
64499
64595
  },
64500
64596
  CallExpression(node) {
64501
- const n = node;
64502
- if (resolveBigIntArrayBase(n.callee, node)) report(n.callee);
64597
+ if (resolveBigIntArrayBase(node.callee, node)) report(node.callee);
64503
64598
  },
64504
64599
  MemberExpression(node) {
64505
- const m = node;
64506
- if (resolveBigIntArrayBase(m.object, node)) report(m.object);
64600
+ if (resolveBigIntArrayBase(node.object, node)) report(node.object);
64507
64601
  }
64508
64602
  };
64509
64603
  }
@@ -64513,7 +64607,10 @@ const rule$4 = {
64513
64607
  const rule$3 = {
64514
64608
  meta: {
64515
64609
  type: "problem",
64516
- docs: { description: "disallow Function#caller and Function#arguments" },
64610
+ docs: {
64611
+ description: "disallow Function#caller and Function#arguments",
64612
+ url: "https://baselinejs.vercel.app/docs/config#standalone-rules"
64613
+ },
64517
64614
  messages: { forbidden: "Function.caller/Function.arguments are forbidden." },
64518
64615
  schema: []
64519
64616
  },
@@ -64540,7 +64637,10 @@ const rule$3 = {
64540
64637
  const rule$2 = {
64541
64638
  meta: {
64542
64639
  type: "problem",
64543
- docs: { description: "disallow Math.sumPrecise() usage" },
64640
+ docs: {
64641
+ description: "disallow Math.sumPrecise() usage",
64642
+ url: "https://baselinejs.vercel.app/docs/config#standalone-rules"
64643
+ },
64544
64644
  messages: { forbidden: "Math.sumPrecise is not allowed." },
64545
64645
  schema: []
64546
64646
  },
@@ -64554,13 +64654,12 @@ const rule$2 = {
64554
64654
  return {
64555
64655
  CallExpression(node) {
64556
64656
  const callee = node.callee;
64557
- if (callee && callee.type === "MemberExpression" && callee.computed === false && isGlobalBaseNotShadowed(context, callee.object, "Math", node) && callee.property?.type === "Identifier" && callee.property?.name === "sumPrecise") report(callee.property);
64657
+ if (callee.type === "MemberExpression" && callee.computed === false && isGlobalBaseNotShadowed(context, callee.object, "Math", node) && callee.property.type === "Identifier" && callee.property.name === "sumPrecise") report(callee.property);
64558
64658
  },
64559
64659
  MemberExpression(node) {
64560
- const m = node;
64561
- const parent = m.parent;
64562
- if (parent?.type === "CallExpression" && parent.callee === node) return;
64563
- if (m.computed === false && isGlobalBaseNotShadowed(context, m.object, "Math", node) && m.property?.type === "Identifier" && m.property?.name === "sumPrecise") report(m.property);
64660
+ const parent = node.parent;
64661
+ if (parent.type === "CallExpression" && parent.callee === node) return;
64662
+ if (node.computed === false && isGlobalBaseNotShadowed(context, node.object, "Math", node) && node.property.type === "Identifier" && node.property.name === "sumPrecise") report(node.property);
64564
64663
  }
64565
64664
  };
64566
64665
  }
@@ -64570,7 +64669,10 @@ const rule$2 = {
64570
64669
  const rule$1 = {
64571
64670
  meta: {
64572
64671
  type: "problem",
64573
- docs: { description: "disallow Temporal API usage" },
64672
+ docs: {
64673
+ description: "disallow Temporal API usage",
64674
+ url: "https://baselinejs.vercel.app/docs/config#standalone-rules"
64675
+ },
64574
64676
  messages: { forbidden: "Temporal API usage is not allowed." },
64575
64677
  schema: []
64576
64678
  },
@@ -64583,18 +64685,17 @@ const rule$1 = {
64583
64685
  }
64584
64686
  return {
64585
64687
  MemberExpression(node) {
64586
- const m = node;
64587
- const parent = m.parent;
64588
- if (parent?.type === "NewExpression" && parent.callee === node) return;
64589
- if (m.computed === false && isGlobalBaseNotShadowed(context, m.object, "Temporal", node)) report(m.object);
64688
+ const parent = node.parent;
64689
+ if (parent.type === "NewExpression" && parent.callee === node) return;
64690
+ if (node.computed === false && isGlobalBaseNotShadowed(context, node.object, "Temporal", node)) report(node.object);
64590
64691
  },
64591
64692
  NewExpression(node) {
64592
- const n = node;
64593
- if (n.callee?.type === "Identifier") {
64594
- if (isGlobalBaseNotShadowed(context, n.callee, "Temporal", node)) report(n.callee);
64693
+ const callee = node.callee;
64694
+ if (callee.type === "Identifier") {
64695
+ if (isGlobalBaseNotShadowed(context, callee, "Temporal", node)) report(callee);
64595
64696
  return;
64596
64697
  }
64597
- if (n.callee?.type === "MemberExpression" && isGlobalBaseNotShadowed(context, n.callee.object, "Temporal", node)) report(n.callee.object);
64698
+ if (callee.type === "MemberExpression" && isGlobalBaseNotShadowed(context, callee.object, "Temporal", node)) report(callee.object);
64598
64699
  }
64599
64700
  };
64600
64701
  }
@@ -64687,6 +64788,32 @@ function listResolverPlugins() {
64687
64788
  return Object.keys(registry).sort();
64688
64789
  }
64689
64790
  //#endregion
64791
+ //#region src/utils/listeners.ts
64792
+ /**
64793
+ * Merge one or more source listener maps into an existing map.
64794
+ * This preserves execution order (existing listeners run before new ones)
64795
+ * while keeping the original object reference intact.
64796
+ */
64797
+ function mergeRuleListeners(target, ...sources) {
64798
+ const dest = target;
64799
+ for (const source of sources) {
64800
+ if (!source) continue;
64801
+ for (const [event, handler] of Object.entries(source)) {
64802
+ const prev = target[event];
64803
+ if (!prev) {
64804
+ dest[event] = handler;
64805
+ continue;
64806
+ }
64807
+ const next = handler;
64808
+ dest[event] = function merged(...args) {
64809
+ prev.apply(this, args);
64810
+ next.apply(this, args);
64811
+ };
64812
+ }
64813
+ }
64814
+ return target;
64815
+ }
64816
+ //#endregion
64690
64817
  //#region src/orchestrator/messages.ts
64691
64818
  function baselineMessage(featureId, baseline, subject) {
64692
64819
  const feature = getFeatureRecord(featureId);
@@ -64755,7 +64882,10 @@ registerSelfRules({
64755
64882
  const rule = {
64756
64883
  meta: {
64757
64884
  type: "problem",
64758
- docs: { description: "Enforce JS Baseline by delegating to underlying syntax rules (es-x)" },
64885
+ docs: {
64886
+ description: "Enforce JS Baseline by delegating to underlying syntax rules (es-x)",
64887
+ url: "https://baselinejs.vercel.app/docs/config#rule-options"
64888
+ },
64759
64889
  schema: [{
64760
64890
  type: "object",
64761
64891
  properties: {
@@ -64922,31 +65052,24 @@ const rule = {
64922
65052
  });
64923
65053
  mergeRuleListeners(listeners, impl.create(delegateCtx));
64924
65054
  }
64925
- let descriptors = getIncludedDescriptors({
64926
- webApis: includeWebApis,
64927
- jsBuiltins: includeJsBuiltins
64928
- });
64929
- if (matchIgnoreFeature) descriptors = descriptors.filter((d) => !matchIgnoreFeature(d.featureId));
64930
- descriptors = descriptors.filter((d) => isBeyondBaseline(d.featureId, baseline)).filter((d) => !mappedFeatureIds.has(d.featureId));
64931
- function resolveUseTypes(opt) {
64932
- if (!opt) return "off";
64933
- if (opt === true) return "off";
64934
- if (typeof opt === "object") {
64935
- const o = opt;
64936
- if (o.useTypes === "off" || o.useTypes === "auto" || o.useTypes === "require") return o.useTypes;
64937
- if (o.preset === "type-aware") return "require";
64938
- if (o.preset === "auto") return "auto";
64939
- return "off";
64940
- }
64941
- return "off";
64942
- }
64943
- const cx = ctx;
64944
- const ps = cx.parserServices || cx.sourceCode?.parserServices;
64945
- const typedAvailable = !!ps?.program && !!ps?.esTreeNodeToTSNodeMap;
65055
+ function resolveUseTypes(option) {
65056
+ if (option === false || option === true) return "off";
65057
+ if (option.useTypes) return option.useTypes;
65058
+ if (option.preset === "type-aware") return "require";
65059
+ return option.preset === "auto" ? "auto" : "off";
65060
+ }
65061
+ const typedAvailable = getTypedParserServices(ctx) !== void 0;
64946
65062
  const useTypesWeb = resolveUseTypes(includeWebApis);
64947
65063
  const useTypesJs = resolveUseTypes(includeJsBuiltins);
64948
- const typedEnabled = (useTypesWeb === "require" || useTypesJs === "require" || useTypesWeb === "auto" || useTypesJs === "auto") && typedAvailable;
64949
- if (!typedEnabled) descriptors = descriptors.filter((d) => d.kind !== "instanceMember" && !d.typedOnly);
65064
+ const typedWebEnabled = useTypesWeb !== "off" && typedAvailable;
65065
+ const typedJsEnabled = useTypesJs !== "off" && typedAvailable;
65066
+ const typedEnabled = typedWebEnabled || typedJsEnabled;
65067
+ function getEnabledDescriptors(options, useTypes) {
65068
+ return getIncludedDescriptors(options).filter((descriptor) => useTypes || descriptor.kind !== "instanceMember" && !descriptor.typedOnly);
65069
+ }
65070
+ let descriptors = [...getEnabledDescriptors({ webApis: includeWebApis }, typedWebEnabled), ...getEnabledDescriptors({ jsBuiltins: includeJsBuiltins }, typedJsEnabled)];
65071
+ if (matchIgnoreFeature) descriptors = descriptors.filter((d) => !matchIgnoreFeature(d.featureId));
65072
+ descriptors = descriptors.filter((d) => isBeyondBaseline(d.featureId, baseline)).filter((d) => !mappedFeatureIds.has(d.featureId));
64950
65073
  if (descriptors.length > 0) mergeRuleListeners(listeners, buildListeners(ctx, {
64951
65074
  descriptors,
64952
65075
  typed: typedEnabled,
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "eslint-plugin-baseline-js",
3
- "version": "0.7.4",
3
+ "version": "0.7.5",
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,6 +45,7 @@
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/estree": "^1.0.9",
48
49
  "@types/node": "^26.6.3",
49
50
  "@typescript-eslint/parser": "^8.70.1",
50
51
  "eslint": "^10.11.0",
@@ -62,6 +63,11 @@
62
63
  "pnpm": {
63
64
  "overrides": {
64
65
  "vite": "7.3.6"
66
+ },
67
+ "auditConfig": {
68
+ "ignoreGhsas": [
69
+ "GHSA-vfj7-8cjw-p6xm"
70
+ ]
65
71
  }
66
72
  },
67
73
  "engines": {