1- /* eslint no-nested-ternary: off */
21import type { Rule } from "eslint" ;
32import type * as ESTree from "estree" ;
43import browserslist from "browserslist" ;
@@ -15,40 +14,34 @@ import { TargetNameMappings } from "./constants";
1514- Each API is given to versioning.ts with compatibility info
1615*/
1716
18- enum GuardType {
19- // Guard is true if the browser supports the API
20- POSITIVE ,
21- // Guard is false if the browser supports the API
22- NEGATIVE ,
23- }
24-
2517export interface GuardedScope {
26- scope : ESTree . Node & Rule . NodeParentExtension ;
18+ scope : Rule . Node ;
2719 index : number ;
2820}
2921
3022/**
31- * Checks if the given node is used in a guard, and whether it's used to guard for or against the
32- * block statement. Should be called with either a bare Identifier, or a MemberExpression.
23+ * Checks if the given node is used in an if statement, and if it is, returns the
24+ * scope that the guard applies to and after which index it applies.
25+ * Should be called with either a bare Identifier or a MemberExpression.
3326 */
3427export function determineGuardedScope (
3528 node : ( ESTree . Identifier | ESTree . MemberExpression ) & Rule . NodeParentExtension
3629) : GuardedScope | null {
3730 const result = getIfStatementAndGuardType ( node ) ;
3831 if ( ! result ) return null ;
3932
40- const [ ifStatement , guardType ] = result ;
33+ const [ ifStatement , positiveGuard ] = result ;
4134
42- if ( guardType === GuardType . POSITIVE ) {
43- return { scope : ifStatement . consequent as GuardedScope [ "scope" ] , index : 0 } ;
35+ if ( positiveGuard ) {
36+ // It's okay to use the identifier inside of the if statement
37+ return { scope : ifStatement . consequent as Rule . Node , index : 0 } ;
4438 }
4539
46- // guardType is NEGATIVE
47-
4840 if (
4941 ifStatementHasEarlyReturn ( ifStatement ) &&
5042 isBlockOrProgram ( ifStatement . parent )
5143 ) {
44+ // It's okay to use the identifier after the if statement
5245 const scope = ifStatement . parent ;
5346 const index = scope . body . indexOf ( ifStatement ) + 1 ;
5447 return { scope, index } ;
@@ -65,9 +58,9 @@ export function isBlockOrProgram(
6558
6659function getIfStatementAndGuardType (
6760 node : ( ESTree . Identifier | ESTree . MemberExpression ) & Rule . NodeParentExtension
68- ) : [ ESTree . IfStatement & Rule . NodeParentExtension , GuardType ] | null {
69- let guardType = GuardType . POSITIVE ;
70- let expression : ESTree . Node & Rule . NodeParentExtension = node ;
61+ ) : [ ESTree . IfStatement & Rule . NodeParentExtension , boolean ] | null {
62+ let positiveGuard = true ;
63+ let expression : Rule . Node = node ;
7164
7265 if (
7366 node . parent ?. type === "UnaryExpression" &&
@@ -92,11 +85,11 @@ function getIfStatementAndGuardType(
9285 ) {
9386 // typeof foo === "function"
9487 // typeof foo !== "undefined"
95- guardType = GuardType . POSITIVE ;
88+ positiveGuard = true ;
9689 } else {
9790 // typeof foo !== "function"
9891 // typepf foo === "undefined"
99- guardType = GuardType . NEGATIVE ;
92+ positiveGuard = false ;
10093 }
10194 }
10295
@@ -109,20 +102,17 @@ function getIfStatementAndGuardType(
109102 expression . parent . operator === "!"
110103 ) {
111104 expression = expression . parent ;
112- if ( guardType === GuardType . POSITIVE ) {
113- guardType = GuardType . NEGATIVE ;
114- } else {
115- guardType = GuardType . POSITIVE ;
116- }
105+ positiveGuard = ! positiveGuard ;
117106 }
118107
108+ // TODO: allow && checks, but || checks aren't really safe
119109 // skip over && and || expressions
120110 while ( expression . parent ?. type === "LogicalExpression" ) {
121111 expression = expression . parent ;
122112 }
123113
124114 if ( expression . parent ?. type === "IfStatement" ) {
125- return [ expression . parent , guardType ] ;
115+ return [ expression . parent , positiveGuard ] ;
126116 }
127117
128118 return null ;
0 commit comments