@@ -35,6 +35,13 @@ const subBucketsByBucket: Map<Bucket, Bucket[]> = new Map([
3535 [ 'type-2' , [ 'name' ] ] ,
3636] ) ;
3737
38+ // Some buckets exclude others. For the purppose of determining their unions, this lists supertypes pet bucket.
39+ const superBucketsByBucket : Map < Bucket , Bucket > = new Map ( [
40+ [ 'name' , 'type-1-or-type-2' ] ,
41+ [ 'type-1' , 'type-1-or-type-2' ] ,
42+ [ 'type-2' , 'type-1-or-type-2' ] ,
43+ ] ) ;
44+
3845/**
3946 * Determine the intersection between the two passed buckets. The intersection is the 'strongest'
4047 * bucket of the two. This may return `empty` if there is no such intersection.
@@ -78,3 +85,54 @@ export function intersectBuckets(bucket1: Bucket | null, bucket2: Bucket | null)
7885 // Expression will never match any nodes
7986 return 'empty' ;
8087}
88+
89+ /**
90+ * Determine the union between the two passed buckets. The union is the common denominator between buckets
91+ *
92+ * Example: `null` ∪ `name-div` = `null`
93+ * Example: `name-p` ∪ `name-div` = `type-1-or-type-2`
94+ * Example: `type-1` ∪ `name-p` = `type-1`
95+ * Example: `type-1` ∪ `empty` = `type-1`
96+ *
97+ * @param bucket1 - The first bucket to check
98+ * @param bucket2 - The second bucket to check
99+ *
100+ * @returns The union of the two buckets.
101+ */
102+ export function unionBucket ( bucket1 : Bucket | null , bucket2 : Bucket | null ) : Bucket | null {
103+ // null bucket applies to everything
104+ if ( bucket1 === null || bucket2 === null ) {
105+ return null ;
106+ }
107+ if ( bucket1 === 'empty' ) {
108+ return bucket2 ;
109+ }
110+ if ( bucket2 === 'empty' ) {
111+ return bucket1 ;
112+ }
113+ // Same bucket is same
114+ if ( bucket1 === bucket2 ) {
115+ return bucket1 ;
116+ }
117+ // Find the more specific one, given that the buckets are not equal
118+ const type1 = bucket1 . startsWith ( 'name-' ) ? 'name' : bucket1 ;
119+ const type2 = bucket2 . startsWith ( 'name-' ) ? 'name' : bucket2 ;
120+
121+ const supertypes1 = superBucketsByBucket . get ( type1 ) ;
122+ if ( supertypes1 !== undefined && supertypes1 === type2 ) {
123+ // bucket 2 includes bucket 1
124+ return supertypes1 ;
125+ }
126+ const supertypes2 = superBucketsByBucket . get ( type2 ) ;
127+ if ( supertypes2 !== undefined && supertypes2 === type1 ) {
128+ // bucket 1 includes bucket 2
129+ return supertypes2 ;
130+ }
131+
132+ if ( supertypes1 === supertypes2 ) {
133+ return supertypes1 ;
134+ }
135+
136+ // Expression will never match any nodes
137+ return 'empty' ;
138+ }
0 commit comments