@@ -27,59 +27,70 @@ const Experiments = {
27
27
/**
28
28
* Experiment "example" will be activate on login for 10% of all clients.
29
29
*/
30
- // "example": 0.1,
30
+ "example" : 0.1 ,
31
31
} ;
32
- const ExperimentsSet = new Set ( Object . keys ( Experiments ) ) as Set < Experiment > ;
32
+ type Experiments = Partial < { [ e in Experiment ] : boolean } > ;
33
33
export type Experiment = keyof ( typeof Experiments ) ;
34
34
35
35
export namespace Experiment {
36
- export function seed ( keepCurrent : boolean ) : Set < Experiment > {
37
- const current = keepCurrent ? get ( ) : undefined ;
38
-
39
- // add all current experiments to ensure stability
40
- const result = new Set < Experiment > ( [ ...( current || [ ] ) ] . filter ( e => ExperimentsSet . has ( e ) ) ) ;
36
+ /**
37
+ * Randomly decides what the set of Experiments is the user participates in
38
+ * @param keepCurrent
39
+ * @returns Experiments
40
+ */
41
+ export function seed ( keepCurrent : boolean ) : Experiments {
42
+ const result = keepCurrent ? get ( ) || { } : { } ;
41
43
42
- // identify all new experiments and add if random
43
- const newExperiment = new Set < Experiment > ( [ ...ExperimentsSet ] . filter ( e => ! result . has ( e ) ) ) ;
44
- for ( const e of newExperiment ) {
45
- if ( Math . random ( ) < Experiments [ e ] ) {
46
- result . add ( e ) ;
44
+ for ( const experiment of Object . keys ( Experiments ) as Experiment [ ] ) {
45
+ if ( ! ( experiment in result ) ) {
46
+ result [ experiment ] = Math . random ( ) < Experiments [ experiment ] ;
47
47
}
48
48
}
49
49
50
50
return result ;
51
51
}
52
52
53
- export function set ( set : Set < Experiment > ) : void {
53
+ export function set ( set : Experiments ) : void {
54
54
try {
55
- const arr = Array . from ( set ) ;
56
- window . localStorage . setItem ( UI_EXPERIMENTS_KEY , JSON . stringify ( arr ) ) ;
55
+ window . localStorage . setItem ( UI_EXPERIMENTS_KEY , JSON . stringify ( set ) ) ;
57
56
} catch ( err ) {
58
- console . error ( `error setting ${ UI_EXPERIMENTS_KEY } ` , err ) ;
57
+ console . warn ( `error setting ${ UI_EXPERIMENTS_KEY } ` , err ) ;
59
58
}
60
59
}
61
60
62
61
export function has ( experiment : Experiment ) : boolean {
63
- const set = get ( ) ;
64
- if ( ! set ) {
62
+ try {
63
+ const set = get ( ) ;
64
+ if ( ! set ) {
65
+ return false ;
66
+ }
67
+ return set [ experiment ] === true ;
68
+ } catch ( err ) {
69
+ console . warn ( `error checking experiment '${ experiment } '` , err ) ;
65
70
return false ;
66
71
}
67
- return set . has ( experiment ) ;
68
72
}
69
73
70
- export function get ( ) : Set < Experiment > | undefined {
71
- const arr = window . localStorage . getItem ( UI_EXPERIMENTS_KEY ) ;
72
- if ( arr === null ) {
73
- return undefined ;
74
- }
75
- return new Set ( arr ) as Set < Experiment > ;
76
- }
74
+ /** Retrieves all currently valid Experiments from localStorage */
75
+ export function get ( ) : Experiments | undefined {
76
+ try {
77
+ const objStr = window . localStorage . getItem ( UI_EXPERIMENTS_KEY ) ;
78
+ if ( objStr === null ) {
79
+ return undefined ;
80
+ }
77
81
78
- export function getAsArray ( ) : Experiment [ ] {
79
- const set = get ( ) ;
80
- if ( ! set ) {
81
- return [ ] ;
82
+ const obj = JSON . parse ( objStr ) as Experiments ;
83
+ // trim to contain only known keys so we're type-safe
84
+ for ( const e of Object . keys ( obj ) ) {
85
+ if ( ! ( e in Experiments ) ) {
86
+ delete ( obj as any ) [ e ] ;
87
+ }
88
+ }
89
+ return obj ;
90
+ } catch ( err ) {
91
+ // we definitely don't want to break anybody because of weird errors
92
+ console . warn ( `error getting ${ UI_EXPERIMENTS_KEY } ` , err ) ;
93
+ return undefined ;
82
94
}
83
- return Array . from ( set ) ;
84
95
}
85
96
}
0 commit comments