@figliolia/galena 2.3.5 → 3.0.1

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 (106) hide show
  1. package/README.md +172 -476
  2. package/dist/Galena.cjs +102 -0
  3. package/dist/Galena.d.cts +80 -0
  4. package/dist/Galena.d.cts.map +1 -0
  5. package/dist/Galena.d.mts +80 -0
  6. package/dist/Galena.d.mts.map +1 -0
  7. package/dist/Galena.mjs +103 -0
  8. package/dist/Galena.mjs.map +1 -0
  9. package/dist/Logger.cjs +46 -0
  10. package/dist/Logger.d.cts +35 -0
  11. package/dist/Logger.d.cts.map +1 -0
  12. package/dist/Logger.d.mts +35 -0
  13. package/dist/Logger.d.mts.map +1 -0
  14. package/dist/Logger.mjs +48 -0
  15. package/dist/Logger.mjs.map +1 -0
  16. package/dist/Middleware.cjs +62 -0
  17. package/dist/Middleware.d.cts +65 -0
  18. package/dist/Middleware.d.cts.map +1 -0
  19. package/dist/Middleware.d.mts +65 -0
  20. package/dist/Middleware.d.mts.map +1 -0
  21. package/dist/Middleware.mjs +64 -0
  22. package/dist/Middleware.mjs.map +1 -0
  23. package/dist/Profiler.cjs +41 -0
  24. package/dist/Profiler.d.cts +31 -0
  25. package/dist/Profiler.d.cts.map +1 -0
  26. package/dist/Profiler.d.mts +31 -0
  27. package/dist/Profiler.d.mts.map +1 -0
  28. package/dist/Profiler.mjs +43 -0
  29. package/dist/Profiler.mjs.map +1 -0
  30. package/dist/State.cjs +147 -0
  31. package/dist/State.d.cts +114 -0
  32. package/dist/State.d.cts.map +1 -0
  33. package/dist/State.d.mts +114 -0
  34. package/dist/State.d.mts.map +1 -0
  35. package/dist/State.mjs +148 -0
  36. package/dist/State.mjs.map +1 -0
  37. package/dist/index.cjs +13 -0
  38. package/dist/index.d.cts +7 -0
  39. package/dist/index.d.mts +7 -0
  40. package/dist/index.mjs +6 -0
  41. package/dist/types.d.cts +16 -0
  42. package/dist/types.d.cts.map +1 -0
  43. package/dist/types.d.mts +16 -0
  44. package/dist/types.d.mts.map +1 -0
  45. package/media/Logging.png +0 -0
  46. package/media/Profiling.png +0 -0
  47. package/package.json +38 -59
  48. package/src/Galena.ts +120 -0
  49. package/src/{Middlewares/Logger.ts → Logger.ts} +15 -14
  50. package/src/Middleware.ts +62 -0
  51. package/src/Profiler.ts +53 -0
  52. package/src/State.ts +167 -0
  53. package/src/index.ts +6 -3
  54. package/src/types.ts +28 -0
  55. package/dist/cjs/Galena/Galena.js +0 -223
  56. package/dist/cjs/Galena/Guards.js +0 -40
  57. package/dist/cjs/Galena/Scheduler.js +0 -84
  58. package/dist/cjs/Galena/State.js +0 -314
  59. package/dist/cjs/Galena/index.js +0 -22
  60. package/dist/cjs/Galena/types.js +0 -9
  61. package/dist/cjs/Middleware/Middleware.js +0 -46
  62. package/dist/cjs/Middleware/index.js +0 -20
  63. package/dist/cjs/Middleware/types.js +0 -8
  64. package/dist/cjs/Middlewares/Logger.js +0 -51
  65. package/dist/cjs/Middlewares/Profiler.js +0 -38
  66. package/dist/cjs/Middlewares/index.js +0 -7
  67. package/dist/cjs/index.js +0 -19
  68. package/dist/cjs/package.json +0 -3
  69. package/dist/mjs/Galena/Galena.js +0 -218
  70. package/dist/mjs/Galena/Guards.js +0 -36
  71. package/dist/mjs/Galena/Scheduler.js +0 -79
  72. package/dist/mjs/Galena/State.js +0 -313
  73. package/dist/mjs/Galena/index.js +0 -3
  74. package/dist/mjs/Galena/types.js +0 -6
  75. package/dist/mjs/Middleware/Middleware.js +0 -42
  76. package/dist/mjs/Middleware/index.js +0 -2
  77. package/dist/mjs/Middleware/types.js +0 -5
  78. package/dist/mjs/Middlewares/Logger.js +0 -44
  79. package/dist/mjs/Middlewares/Profiler.js +0 -35
  80. package/dist/mjs/Middlewares/index.js +0 -2
  81. package/dist/mjs/index.js +0 -3
  82. package/dist/mjs/package.json +0 -4
  83. package/dist/types/Galena/Galena.d.ts +0 -160
  84. package/dist/types/Galena/Guards.d.ts +0 -29
  85. package/dist/types/Galena/Scheduler.d.ts +0 -51
  86. package/dist/types/Galena/State.d.ts +0 -235
  87. package/dist/types/Galena/index.d.ts +0 -3
  88. package/dist/types/Galena/types.d.ts +0 -13
  89. package/dist/types/Middleware/Middleware.d.ts +0 -43
  90. package/dist/types/Middleware/index.d.ts +0 -2
  91. package/dist/types/Middleware/types.d.ts +0 -4
  92. package/dist/types/Middlewares/Logger.d.ts +0 -27
  93. package/dist/types/Middlewares/Profiler.d.ts +0 -22
  94. package/dist/types/Middlewares/index.d.ts +0 -2
  95. package/dist/types/index.d.ts +0 -3
  96. package/src/Galena/Galena.ts +0 -252
  97. package/src/Galena/Guards.ts +0 -49
  98. package/src/Galena/Scheduler.ts +0 -85
  99. package/src/Galena/State.ts +0 -344
  100. package/src/Galena/index.ts +0 -3
  101. package/src/Galena/types.ts +0 -18
  102. package/src/Middleware/Middleware.ts +0 -45
  103. package/src/Middleware/index.ts +0 -2
  104. package/src/Middleware/types.ts +0 -4
  105. package/src/Middlewares/Profiler.ts +0 -41
  106. package/src/Middlewares/index.ts +0 -2
@@ -0,0 +1,62 @@
1
+ import type { State } from "./State";
2
+
3
+ /**
4
+ * Middleware
5
+ *
6
+ * Galena's middleware API is designed to provide hooks
7
+ * for state changes that you can tap into to run your
8
+ * own logic.
9
+ *
10
+ * Middleware is great for logging, analytics, and profiling:
11
+ *
12
+ * ```typescript
13
+ * export class Profiler<T = any> extends Middleware<T> {
14
+ * private previousState: T | null = null;
15
+ * private startTime: null | number = null;
16
+ * constructor(public readonly threshold: number = 16) {
17
+ * super();
18
+ * }
19
+ *
20
+ * public override onBeforeUpdate(state: State<T>) {
21
+ * this.startTime = performance.now();
22
+ * this.previousState = state.getSnapshot();
23
+ * }
24
+ *
25
+ * public override onUpdate(state: T) {
26
+ * const diff = performance.now() - this.startTime;
27
+ * if(diff >= this.threshold) {
28
+ * console.warn(`A slow state transition was detected when transitioning the following piece of state`);
29
+ * console.log('Previous state', this.previousState);
30
+ * console.log('Current state', state.getSnapshot());
31
+ * }
32
+ * }
33
+ * }
34
+ * ```
35
+ *
36
+ * To register your middleware, simply add it when constructing
37
+ * a `State` or `Galena` instance.
38
+ *
39
+ * ```typescript
40
+ * import { State } from "@figliolia/galena";
41
+ * import { Profiler } from './myProfiler';
42
+ *
43
+ * const myState = new State(5, new Profiler());
44
+ * ```
45
+ */
46
+ export class Middleware<T = any> {
47
+ /**
48
+ * On Before Update
49
+ *
50
+ * Executes prior to a `State` instance being updated.
51
+ * Receives the state prior to its update as a parameter
52
+ */
53
+ public onBeforeUpdate(_state: State<T>) {}
54
+
55
+ /**
56
+ * On Update
57
+ *
58
+ * Executes after a `State` instance has been update.
59
+ * Receives the most recent state as a parameter
60
+ */
61
+ public onUpdate(_state: State<T>) {}
62
+ }
@@ -0,0 +1,53 @@
1
+ import { Middleware } from "./Middleware";
2
+ import type { State } from "./State";
3
+
4
+ /**
5
+ * Profiler
6
+ *
7
+ * A logger for state transitions exceeding a given
8
+ * millisecond threshold
9
+ *
10
+ * ```typescript
11
+ * const AppState = new Galena({}, new Profiler());
12
+ * // or
13
+ * AppState.registerMiddlerware(new Profiler());
14
+ * // or
15
+ * const MyState = new State(4, new Profiler());
16
+ * // or
17
+ * MyState.registerMiddleware(new Profiler());
18
+ * ```
19
+ */
20
+ export class Profiler<T = any> extends Middleware<T> {
21
+ private previousState: T | null = null;
22
+ private startTime: null | number = null;
23
+ constructor(public readonly threshold = 16) {
24
+ super();
25
+ }
26
+
27
+ public override onBeforeUpdate(state: State<T>) {
28
+ this.startTime = performance.now();
29
+ this.previousState = state.getSnapshot();
30
+ }
31
+
32
+ public override onUpdate(state: State<T>) {
33
+ if (this.startTime === null) {
34
+ return;
35
+ }
36
+ const diff = performance.now() - this.startTime;
37
+ if (diff >= this.threshold) {
38
+ console.warn(
39
+ `A slow state transition of ${diff.toFixed(1)}ms was detected when transitioning the following piece of state`,
40
+ );
41
+ console.log(
42
+ " %cPrevious State",
43
+ "color: #26ad65; font-weight: bold",
44
+ this.previousState,
45
+ );
46
+ console.log(
47
+ " %cCurrent State ",
48
+ "color: rgb(17, 118, 249); font-weight: bold",
49
+ state.getSnapshot(),
50
+ );
51
+ }
52
+ }
53
+ }
package/src/State.ts ADDED
@@ -0,0 +1,167 @@
1
+ import { EventEmitter } from "@figliolia/event-emitter";
2
+ import type { Middleware } from "./Middleware";
3
+ import type { NonFunction, Setter, Subscriber } from "./types";
4
+
5
+ /**
6
+ * State
7
+ *
8
+ * The unit of reactivity for Galena. `State`'s can act
9
+ * as isolated instances or be part of your global app
10
+ * state (via `Galena` instances).
11
+ *
12
+ * There are three ways to create state instances
13
+ *
14
+ * ```typescript
15
+ * import { State, createState, useState, Profiler } from "@figliolia/galena";
16
+ * // for island states that can be shared between react components
17
+ * const myState = new State("<any value>", ...middleware);
18
+ * // or
19
+ * const myState = createState("<any value>", ...middleware);
20
+ *
21
+ * myState.set("<new-value>");
22
+ * myState.update(previousValue => "<new-value>");
23
+ * myState.subscribe(nextValue => {});
24
+ * myState.registerMiddleware(new Profiler());
25
+ *
26
+ * // Similarly if you wish to use your state inside a react component
27
+ * const MyComponent = () => {
28
+ * const [state, setState] = useState(myState);
29
+ * // or
30
+ * const [state, setState] = useMyState("<any-value>", ...middlware);
31
+ *
32
+ * return (
33
+ * // your jsx
34
+ * );
35
+ * }
36
+ * ```
37
+ */
38
+ export class State<T> {
39
+ private state: NonFunction<T>;
40
+ public readonly middleware: Middleware<T>[] = [];
41
+ private readonly Emitter = new EventEmitter<{ change: NonFunction<T> }>();
42
+ constructor(
43
+ public readonly initialState: NonFunction<T>,
44
+ ...middleware: Middleware<T>[]
45
+ ) {
46
+ this.state = initialState;
47
+ this.registerMiddleware(...middleware);
48
+ }
49
+
50
+ /**
51
+ * Set
52
+ *
53
+ * Updates the current value of state notifying
54
+ * all interested parties
55
+ */
56
+ public readonly set = this.withEmission((state: NonFunction<T>) => state);
57
+
58
+ /**
59
+ * Update
60
+ *
61
+ * Updates the current value of state using a setter function
62
+ * receiving the previous state as a parameter. Notifies all
63
+ * interested parties
64
+ */
65
+ public readonly update = this.withEmission((setter: Setter<T>) => {
66
+ if (this.diffSetter(setter)) {
67
+ return setter;
68
+ }
69
+ return setter(this.state);
70
+ });
71
+
72
+ /**
73
+ * Reset
74
+ *
75
+ * Resets the current state back to the state which the instance
76
+ * was initialized with. Notifies all interested parties
77
+ */
78
+ public readonly reset = this.withEmission(() => this.initialState);
79
+
80
+ /**
81
+ * Get Snapshot
82
+ *
83
+ * Returns the current state. Designed for compatibility with
84
+ * `useSyncExternalStore`
85
+ */
86
+ public readonly getSnapshot = () => {
87
+ return this.state;
88
+ };
89
+
90
+ /**
91
+ * Subscribe
92
+ *
93
+ * Registers a callback to be executed each time state
94
+ * changes. Returns an `unsubscribe` function
95
+ */
96
+ public readonly subscribe = (fn: Subscriber<T>) => {
97
+ const ID = this.Emitter.on("change", fn);
98
+ return () => {
99
+ this.Emitter.off("change", ID);
100
+ };
101
+ };
102
+
103
+ /**
104
+ * Register Middleware
105
+ *
106
+ * Registers any number of `Middleware` instances on the
107
+ * current instance of `State`. Your middleware will begin
108
+ * executing at the next state transition
109
+ */
110
+ public registerMiddleware(...middleware: Middleware<T>[]) {
111
+ this.middleware.push(...middleware);
112
+ }
113
+
114
+ private withEmission<
115
+ F extends (...args: any[]) => NonFunction<T> | Promise<NonFunction<T>>,
116
+ >(fn: F) {
117
+ return (...args: Parameters<F>) => {
118
+ const result = fn(...args);
119
+ if (result instanceof Promise) {
120
+ void result.then(resolved => this.emit(resolved));
121
+ return;
122
+ }
123
+ return this.emit(result);
124
+ };
125
+ }
126
+
127
+ private emit(nextState: NonFunction<T>) {
128
+ this.invokeMiddleware("onBeforeUpdate");
129
+ this.state = nextState;
130
+ this.Emitter.emit("change", this.state);
131
+ this.invokeMiddleware("onUpdate");
132
+ }
133
+
134
+ protected diffSetter(setter: Setter<T>): setter is NonFunction<T> {
135
+ return typeof setter !== "function";
136
+ }
137
+
138
+ private invokeMiddleware<K extends keyof Middleware<T>>(fn: K) {
139
+ for (const middleware of this.middleware) {
140
+ middleware[fn](this);
141
+ }
142
+ }
143
+ }
144
+
145
+ /**
146
+ * Create State
147
+ *
148
+ * Returns the unit of reactivity for Galena. `State`'s can act
149
+ * as isolated instances or be part of your global app
150
+ * state (via `Galena` instances);
151
+ *
152
+ * ```typescript
153
+ * import { createState, Profiler } from "@figliolia/galena";
154
+ *
155
+ * const myState = createState("<any value>", ...middleware);
156
+ *
157
+ * myState.set("<new-value>");
158
+ * myState.update(previousValue => "<new-value>");
159
+ * myState.subscribe(nextValue => {});
160
+ * myState.registerMiddleware(new Profiler());
161
+ * ```
162
+ */
163
+ export function createState<T>(
164
+ ...args: ConstructorParameters<typeof State<T>>
165
+ ) {
166
+ return new State<T>(...args);
167
+ }
package/src/index.ts CHANGED
@@ -1,3 +1,6 @@
1
- export * from "Galena";
2
- export * from "Middleware";
3
- export * from "Middlewares";
1
+ export * from "./Galena";
2
+ export * from "./Logger";
3
+ export * from "./Middleware";
4
+ export * from "./Profiler";
5
+ export * from "./State";
6
+ export * from "./types";
package/src/types.ts ADDED
@@ -0,0 +1,28 @@
1
+ import type { State } from "./State";
2
+
3
+ export type NonFunction<T> = T extends (...args: any[]) => any ? never : T;
4
+
5
+ export type PartialSupport<T> = T extends Record<string, any> ? Partial<T> : T;
6
+
7
+ export type Setter<T> =
8
+ | NonFunction<T>
9
+ | ((prevState: NonFunction<T>) => NonFunction<T> | Promise<NonFunction<T>>);
10
+
11
+ export type Subscriber<T> = ((state: NonFunction<T>) => void) | (() => void);
12
+
13
+ export interface GalenaSnapshot<
14
+ T extends Record<string, State<any>>,
15
+ K extends Extract<keyof T, string> = Extract<keyof T, string>,
16
+ > {
17
+ updated: T[K];
18
+ state: T;
19
+ }
20
+
21
+ export type AppSubscriber<
22
+ T extends Record<string, State<any>>,
23
+ K extends Extract<keyof T, string> = Extract<keyof T, string>,
24
+ > = ((payload: GalenaSnapshot<T, K>) => void) | (() => void);
25
+
26
+ export type StateTypes<T extends Record<string, State<any>>> = ReturnType<
27
+ T[keyof T]["getSnapshot"]
28
+ >;
@@ -1,223 +0,0 @@
1
- "use strict";
2
- Object.defineProperty(exports, "__esModule", { value: true });
3
- exports.Galena = void 0;
4
- const event_emitter_1 = require("@figliolia/event-emitter");
5
- const State_1 = require("./State");
6
- const Guards_1 = require("./Guards");
7
- /**
8
- * ## Galena
9
- *
10
- * A performant global state solution that scales
11
- *
12
- * ### Creating State
13
- *
14
- * ```typescript
15
- * // AppState.ts
16
- * import { Galena } from "@figliolia/galena";
17
- *
18
- * const AppState = new Galena([...middleware]);
19
- *
20
- * const NavigationState = AppState.composeState("navigation", {
21
- * currentRoute: "/",
22
- * userID: "12345",
23
- * permittedRoutes: ["/*"]
24
- * });
25
- * ```
26
- *
27
- * ### Subscribing to State Changes
28
- * #### Using the Galena Instance
29
- * ```typescript
30
- * import { AppState } from "./AppState";
31
- *
32
- * AppState.subscribe(appState => {
33
- * const navState = appState.get("navigation");
34
- * const { currentRoute } = navState.state;
35
- * // do something with state changes!
36
- * });
37
- * ```
38
- * #### Using the State Instance
39
- * ```typescript
40
- * NavigationState.subscribe(navigation => {
41
- * const { currentRoute } = navigation
42
- * // do something with state changes!
43
- * });
44
- * ```
45
- *
46
- * #### Using Global Subscriptions
47
- * ```typescript
48
- * NavigationState.subscribeAll(nextState => {
49
- * const { currentRoute } = nextState.navigation
50
- * // do something with state changes!
51
- * });
52
- * ```
53
- *
54
- * ### Mutating State
55
- * ```typescript
56
- * NavigationState.update(state => {
57
- * state.currentRoute = "/profile";
58
- * // You can mutate state without creating new objects!
59
- * });
60
- * ```
61
- */
62
- class Galena extends Guards_1.Guards {
63
- constructor(middleware = []) {
64
- super();
65
- this.state = {};
66
- this.middleware = [];
67
- this.IDs = new event_emitter_1.AutoIncrementingID();
68
- this.subscriptions = new Map();
69
- this.middleware = middleware;
70
- }
71
- /**
72
- * Compose State
73
- *
74
- * Creates a new `State` instance and returns it. Your new state
75
- * becomes immediately available on your `Galena` instance and
76
- * is wired into your middleware. All existing subscriptions to
77
- * state will automatically receive updates when your new unit of
78
- * state updates
79
- */
80
- composeState(name, initialState, Model) {
81
- this.guardDuplicateStates(name, this.state);
82
- const StateModel = Model || (State_1.State);
83
- const state = new StateModel(name, initialState);
84
- state.registerMiddleware(...this.middleware);
85
- this.mutable[name] = state;
86
- this.reIndexSubscriptions(name);
87
- return state;
88
- }
89
- /**
90
- * Get State
91
- *
92
- * Returns a mutable state instance
93
- */
94
- getState() {
95
- return this.state;
96
- }
97
- /**
98
- * Get
99
- *
100
- * Returns a unit of `State` by name
101
- */
102
- get(name) {
103
- this.warnForUndefinedStates(name, this.state);
104
- return this.state[name];
105
- }
106
- /**
107
- * Mutable
108
- *
109
- * Returns a mutable state instance
110
- */
111
- get mutable() {
112
- return this.state;
113
- }
114
- /**
115
- * Update
116
- *
117
- * Runs a mutation on the specified unit of state
118
- */
119
- update(name, mutation) {
120
- return this.get(name).update(mutation);
121
- }
122
- /**
123
- * Background Update
124
- *
125
- * Runs a higher priority mutation on the specified unit of
126
- * state
127
- */
128
- backgroundUpdate(name, mutation) {
129
- return this.get(name).backgroundUpdate(mutation);
130
- }
131
- /**
132
- * Priority Update
133
- *
134
- * Runs an immediate priority mutation on the specified unit
135
- * of state
136
- */
137
- priorityUpdate(name, mutation) {
138
- return this.get(name).priorityUpdate(mutation);
139
- }
140
- /**
141
- * Subscribe
142
- *
143
- * Given the name of a unit of state, this method registers
144
- * a subscription on the target state instance. The callback
145
- * you provide will execute each time state changes. Returns
146
- * a unique identifier for your subscription. To clean up your
147
- * subscription, call `Galena.unsubscribe()` with the ID returned
148
- * by this method
149
- */
150
- subscribe(name, callback) {
151
- return this.get(name).subscribe(callback);
152
- }
153
- /**
154
- * Unsubscribe
155
- *
156
- * Given a subscription ID returned from the `subscribe` method,
157
- * this method removes and cleans up the corresponding subscription
158
- */
159
- unsubscribe(name, ID) {
160
- return this.get(name).unsubscribe(ID);
161
- }
162
- /**
163
- * Subscribe All
164
- *
165
- * Registers a callback on each registered `State` instance and
166
- * is invoked each time your state changes. Using `Galena`'s
167
- * `subscribeAll` method, although performant, can be less
168
- * performant than subscribing directly to a target `State`
169
- * instance using `Galena.subscribe()`. To clean up your
170
- * subscription, call `Galena.unsubscribeAll()` with the ID
171
- * returned
172
- */
173
- subscribeAll(callback) {
174
- const stateSubscriptions = [];
175
- for (const key in this.state) {
176
- stateSubscriptions.push([
177
- key,
178
- this.state[key].subscribe(() => {
179
- void callback(this.state);
180
- }),
181
- ]);
182
- }
183
- const subscriptionID = this.IDs.get();
184
- this.subscriptions.set(subscriptionID, stateSubscriptions);
185
- return subscriptionID;
186
- }
187
- /**
188
- * Unsubscribe
189
- *
190
- * Given a subscription ID returned from the `subscribeAll()` method,
191
- * this method removes and cleans up the corresponding subscription
192
- */
193
- unsubscribeAll(ID) {
194
- const IDs = this.subscriptions.get(ID);
195
- if (IDs) {
196
- for (const [state, ID] of IDs) {
197
- this.state[state].unsubscribe(ID);
198
- }
199
- this.subscriptions.delete(ID);
200
- }
201
- }
202
- /**
203
- * ReIndex Subscriptions
204
- *
205
- * When units of state are created lazily, this method updates
206
- * each existing subscription to receive mutations occurring on
207
- * recently created `State` instances that post-date prior
208
- * subscriptions
209
- */
210
- reIndexSubscriptions(name) {
211
- var _a, _b;
212
- for (const [ID, unitSubscriptions] of this.subscriptions) {
213
- const [stateName, listenerID] = unitSubscriptions[0];
214
- const subscriptions = this.state[stateName]["emitter"].storage.get(stateName);
215
- const listener = (_b = (_a = subscriptions === null || subscriptions === void 0 ? void 0 : subscriptions.storage) === null || _a === void 0 ? void 0 : _a.get) === null || _b === void 0 ? void 0 : _b.call(_a, listenerID);
216
- if (listener) {
217
- unitSubscriptions.push([name, this.state[name].subscribe(listener)]);
218
- this.subscriptions.set(ID, unitSubscriptions);
219
- }
220
- }
221
- }
222
- }
223
- exports.Galena = Galena;
@@ -1,40 +0,0 @@
1
- "use strict";
2
- Object.defineProperty(exports, "__esModule", { value: true });
3
- exports.Guards = void 0;
4
- /**
5
- * Guards
6
- *
7
- * Development-only warnings and runtime errors designed to
8
- * guard developers against possible pitfalls when using
9
- * Galena. This interface provides composable error and
10
- * warning methods that can be used to prevent invalid usage
11
- * of the library
12
- */
13
- class Guards {
14
- /**
15
- * Warn For Undefined States
16
- *
17
- * In Galena, it's normal to lazy initialize a unit of state
18
- * in attached to a `Galena` instance. This warning lets
19
- * developers know that they are attempting to manipulate a
20
- * unit of state that has not yet been initialized
21
- */
22
- warnForUndefinedStates(name, state) {
23
- if (!(name in state)) {
24
- console.warn(`A unit of state with the name "${name}" does not yet exist on this Galena instance. If this is expected, you can ignore this warning`);
25
- }
26
- }
27
- /**
28
- * Guard Duplicate States
29
- *
30
- * Throws an error if a developer attempts to create
31
- * more than one state with the same name on a single
32
- * `Galena` instance
33
- */
34
- guardDuplicateStates(name, state) {
35
- if (name in state) {
36
- console.warn(`A unit of state with the name "${name}" already exists on this Galena instance. Please re-name this new unit of state to something unique`);
37
- }
38
- }
39
- }
40
- exports.Guards = Guards;
@@ -1,84 +0,0 @@
1
- "use strict";
2
- Object.defineProperty(exports, "__esModule", { value: true });
3
- exports.Scheduler = void 0;
4
- const types_1 = require("./types");
5
- /**
6
- * Scheduler
7
- *
8
- * Scheduling dispatched events to state consumers is how Galena
9
- * out-performs just about every state management library out there.
10
- * The scheduler offers the ability to dispatch state updates on 3
11
- * priorities:
12
- *
13
- * 1. Immediate - Immediate synchronous task execution and propagation of
14
- * changes to consumers
15
- * 2. Microtask - Immediate task execution and scheduled propagation of
16
- * changes to consumers
17
- * 3. Batched - Immediate task execution and batched propagation of
18
- * changes to consumers
19
- *
20
- * This module manages the propagation of changes to State consumers
21
- * by implementing the three priorities outlined above
22
- */
23
- class Scheduler {
24
- constructor() {
25
- this.task = null;
26
- this.schedule = null;
27
- this.executeTasks = this.executeTasks.bind(this);
28
- }
29
- /**
30
- * Schedule Task
31
- *
32
- * Given a task (the emission of state changes to consumers)
33
- * and a priority, this method executes the task on the priority
34
- * level specified
35
- */
36
- scheduleTask(task, priority) {
37
- this.task = task;
38
- switch (priority) {
39
- case types_1.Priority.IMMEDIATE:
40
- return this.executeTasks();
41
- case types_1.Priority.MICROTASK:
42
- return Promise.resolve().then(() => {
43
- return this.executeTasks();
44
- });
45
- case types_1.Priority.BATCHED:
46
- default:
47
- if (!this.schedule) {
48
- this.createSchedule();
49
- }
50
- }
51
- }
52
- /**
53
- * Create Schedule
54
- *
55
- * Schedules the execution of the current task after 5 milliseconds
56
- */
57
- createSchedule() {
58
- this.clearSchedule();
59
- this.schedule = setTimeout(this.executeTasks, 5);
60
- }
61
- /**
62
- * Clear Schedule
63
- *
64
- * Clears the schedule if it exists
65
- */
66
- clearSchedule() {
67
- if (this.schedule !== null) {
68
- clearTimeout(this.schedule);
69
- this.schedule = null;
70
- }
71
- }
72
- /**
73
- * Execute Tasks
74
- *
75
- * Clears the schedule if it exists and executes the current task
76
- */
77
- executeTasks() {
78
- var _a;
79
- this.clearSchedule();
80
- (_a = this.task) === null || _a === void 0 ? void 0 : _a.call(this);
81
- this.task = null;
82
- }
83
- }
84
- exports.Scheduler = Scheduler;