@@ -7,7 +7,15 @@ import type { Draft, Patch } from 'immer';
7
7
enablePatches ( ) ;
8
8
9
9
/**
10
- * State change callbacks
10
+ * A state change listener.
11
+ *
12
+ * This function will get called for each state change, and is given a copy of
13
+ * the new state along with a set of patches describing the changes since the
14
+ * last update.
15
+ *
16
+ * @param state - The new controller state
17
+ * @param patches - A list of patches describing any changes (see here for more
18
+ * information: https://immerjs.github.io/immer/docs/patches)
11
19
*/
12
20
export type Listener < T > = ( state : T , patches : Patch [ ] ) => void ;
13
21
@@ -22,17 +30,46 @@ type RecursivePartial<T> = {
22
30
RecursivePartial < T > ;
23
31
} ;
24
32
33
+ /**
34
+ * An anonymizing function
35
+ *
36
+ * This function will accept one piece of the controller state (one property),
37
+ * and will return an anonymized representation of this state. By "anonymized",
38
+ * we mean that it should not contain any information that could be personally
39
+ * identifiable.
40
+ *
41
+ * @param value - A piece of controller state
42
+ * @returns An anonymized representation of the given state
43
+ */
25
44
export type Anonymizer < T > = ( value : T ) => T extends Primitive ? T : RecursivePartial < T > ;
26
45
46
+ /**
47
+ * State metadata.
48
+ *
49
+ * This metadata describes which parts of state should be persisted, and how to
50
+ * get an anonymized representation of the state.
51
+ */
27
52
export type StateMetadata < T > = {
28
- [ P in keyof T ] : {
29
- persist : boolean ;
30
- anonymous : boolean | Anonymizer < T [ P ] > ;
31
- } ;
53
+ [ P in keyof T ] : StatePropertyMetadata < T [ P ] >
32
54
} ;
33
55
34
56
/**
35
- * Controller class that provides state management and subscriptions
57
+ * Metadata for a single state property
58
+ *
59
+ * @property persist - Indicates whether this property should be persisted
60
+ * (`true` for persistent, `false` for transient)
61
+ * @property anonymous - Indicates whether this property is already anonymous,
62
+ * (`true` for anonymous, `false` if it has potential to be personally
63
+ * identifiable), or is set to a function that returns an anonymized
64
+ * representation of this state.
65
+ */
66
+ export interface StatePropertyMetadata < P > {
67
+ persist : boolean ;
68
+ anonymous : boolean | Anonymizer < P > ;
69
+ }
70
+
71
+ /**
72
+ * Controller class that provides state management, subscriptions, and state metadata
36
73
*/
37
74
export class BaseController < S extends Record < string , any > > {
38
75
private internalState : S ;
@@ -120,6 +157,17 @@ function isAnonymizingFunction<T>(x: boolean | Anonymizer<T>): x is Anonymizer<T
120
157
return typeof x === 'function' ;
121
158
}
122
159
160
+ /**
161
+ * Returns an anonymized representation of the controller state.
162
+ *
163
+ * By "anonymized" we mean that it should not contain any information that could be personally
164
+ * identifiable.
165
+ *
166
+ * @param state - The controller state
167
+ * @param metadata - The controller state metadata, which describes how to derive the
168
+ * anonymized state
169
+ * @returns The anonymized controller state
170
+ */
123
171
export function getAnonymizedState < S extends Record < string , any > > ( state : S , metadata : StateMetadata < S > ) : RecursivePartial < S > {
124
172
return Object . keys ( state ) . reduce ( ( anonymizedState , _key ) => {
125
173
const key : keyof S = _key ; // https://stackoverflow.com/questions/63893394/string-cannot-be-used-to-index-type-t
@@ -133,6 +181,13 @@ export function getAnonymizedState<S extends Record<string, any>>(state: S, meta
133
181
} , { } as RecursivePartial < S > ) ;
134
182
}
135
183
184
+ /**
185
+ * Returns the subset of state that should be persisted
186
+ *
187
+ * @param state - The controller state
188
+ * @param metadata - The controller state metadata, which describes which pieces of state should be persisted
189
+ * @returns The subset of controller state that should be persisted
190
+ */
136
191
export function getPersistentState < S extends Record < string , any > > ( state : S , metadata : StateMetadata < S > ) : RecursivePartial < S > {
137
192
return Object . keys ( state ) . reduce ( ( persistedState , _key ) => {
138
193
const key : keyof S = _key ; // https://stackoverflow.com/questions/63893394/string-cannot-be-used-to-index-type-t
0 commit comments