@figliolia/galena 1.0.0
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.
- package/README.md +534 -0
- package/dist/Galena/Galena.d.ts +152 -0
- package/dist/Galena/Galena.js +219 -0
- package/dist/Galena/Scheduler.d.ts +51 -0
- package/dist/Galena/Scheduler.js +84 -0
- package/dist/Galena/State.d.ts +228 -0
- package/dist/Galena/State.js +286 -0
- package/dist/Galena/index.d.ts +3 -0
- package/dist/Galena/index.js +22 -0
- package/dist/Galena/types.d.ts +10 -0
- package/dist/Galena/types.js +9 -0
- package/dist/Middleware/Middleware.d.ts +54 -0
- package/dist/Middleware/Middleware.js +68 -0
- package/dist/Middleware/index.d.ts +2 -0
- package/dist/Middleware/index.js +20 -0
- package/dist/Middleware/types.d.ts +6 -0
- package/dist/Middleware/types.js +8 -0
- package/dist/Middlewares/Logger.d.ts +27 -0
- package/dist/Middlewares/Logger.js +51 -0
- package/dist/Middlewares/Profiler.d.ts +22 -0
- package/dist/Middlewares/Profiler.js +38 -0
- package/dist/Middlewares/index.d.ts +2 -0
- package/dist/Middlewares/index.js +7 -0
- package/dist/index.d.ts +3 -0
- package/dist/index.js +19 -0
- package/package.json +60 -0
- package/src/Galena/Galena.ts +253 -0
- package/src/Galena/Scheduler.ts +85 -0
- package/src/Galena/State.ts +311 -0
- package/src/Galena/index.ts +3 -0
- package/src/Galena/types.ts +13 -0
- package/src/Middleware/Middleware.ts +72 -0
- package/src/Middleware/index.ts +2 -0
- package/src/Middleware/types.ts +11 -0
- package/src/Middlewares/Logger.ts +62 -0
- package/src/Middlewares/Profiler.ts +38 -0
- package/src/Middlewares/index.ts +2 -0
- package/src/index.ts +3 -0
|
@@ -0,0 +1,72 @@
|
|
|
1
|
+
import { EventEmitter } from "@figliolia/event-emitter";
|
|
2
|
+
|
|
3
|
+
import type { State } from "Galena/State";
|
|
4
|
+
import type { MiddlewareEvent } from "Middleware/types";
|
|
5
|
+
import { MiddlewareEvents } from "Middleware/types";
|
|
6
|
+
|
|
7
|
+
/**
|
|
8
|
+
* # Middleware
|
|
9
|
+
*
|
|
10
|
+
* A root interface for all `Galena` Middleware. When creating
|
|
11
|
+
* a middleware for your `Galena` state, simply extend this
|
|
12
|
+
* class any override any of its public lifecycle methods.
|
|
13
|
+
*
|
|
14
|
+
* ### Creating a Profiling Middleware
|
|
15
|
+
*
|
|
16
|
+
* ```typescript
|
|
17
|
+
* export class ProfilerMiddleware extends Middleware {
|
|
18
|
+
* updateState: number | null = null;
|
|
19
|
+
*
|
|
20
|
+
* override onBeforeUpdate(state: State) {
|
|
21
|
+
* this.updateStart = performance.now();
|
|
22
|
+
* }
|
|
23
|
+
*
|
|
24
|
+
* override onUpdate(state: State) {
|
|
25
|
+
* if(this.updateStart) {
|
|
26
|
+
* const timeToUpdate = performance.now() - this.updateStart;
|
|
27
|
+
* if(timeToUpdate > 16) {
|
|
28
|
+
* console.warn("A state transition took more than 16 milliseconds!", State);
|
|
29
|
+
* }
|
|
30
|
+
* }
|
|
31
|
+
* }
|
|
32
|
+
* }
|
|
33
|
+
* ```
|
|
34
|
+
*/
|
|
35
|
+
export class Middleware<T extends any = any> {
|
|
36
|
+
public static Emitter = new EventEmitter<MiddlewareEvent<any>>();
|
|
37
|
+
constructor() {
|
|
38
|
+
const extension = Object.getPrototypeOf(this);
|
|
39
|
+
const methods = Object.getOwnPropertyNames(extension);
|
|
40
|
+
methods.forEach((event) => {
|
|
41
|
+
if (Middleware.validateEvent(event)) {
|
|
42
|
+
Middleware.Emitter.on(MiddlewareEvents[event], this[event]);
|
|
43
|
+
}
|
|
44
|
+
});
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
/**
|
|
48
|
+
* Validate Event
|
|
49
|
+
*
|
|
50
|
+
* Asserts that a given method on an extending class prototype
|
|
51
|
+
* is one of the supported `Galena` lifecycle events
|
|
52
|
+
*/
|
|
53
|
+
private static validateEvent(event: string): event is MiddlewareEvents {
|
|
54
|
+
return event in MiddlewareEvents;
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
/* Life Cycle Events */
|
|
58
|
+
|
|
59
|
+
/**
|
|
60
|
+
* On Before Update
|
|
61
|
+
*
|
|
62
|
+
* An event emitted each time a `State` mutation is enqueued
|
|
63
|
+
*/
|
|
64
|
+
public onBeforeUpdate(state: State<T>) {}
|
|
65
|
+
|
|
66
|
+
/**
|
|
67
|
+
* On Update
|
|
68
|
+
*
|
|
69
|
+
* An event emitted each time a `State` instance is mutated
|
|
70
|
+
*/
|
|
71
|
+
public onUpdate(state: State<T>) {}
|
|
72
|
+
}
|
|
@@ -0,0 +1,62 @@
|
|
|
1
|
+
import { State } from "Galena/State";
|
|
2
|
+
import { Middleware } from "Middleware/Middleware";
|
|
3
|
+
|
|
4
|
+
/**
|
|
5
|
+
* Logger
|
|
6
|
+
*
|
|
7
|
+
* A middleware for Redux-style logging! Each state transition
|
|
8
|
+
* will log to the console the `State` instance that changed
|
|
9
|
+
* along with a before and after snapshot of the current state:
|
|
10
|
+
*
|
|
11
|
+
* ```typescript
|
|
12
|
+
* const State = new Galena([new Logger()]);
|
|
13
|
+
* // if using isolated state instances:
|
|
14
|
+
* const MyState = new State(...args);
|
|
15
|
+
* MyState.registerMiddleware(new Logger())
|
|
16
|
+
* ```
|
|
17
|
+
*/
|
|
18
|
+
export class Logger extends Middleware {
|
|
19
|
+
private previousState: Record<string, any> | null = null;
|
|
20
|
+
|
|
21
|
+
override onBeforeUpdate(state: State) {
|
|
22
|
+
this.previousState = State.clone(state.state);
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
override onUpdate(state: State) {
|
|
26
|
+
console.log(
|
|
27
|
+
"%cMutation:",
|
|
28
|
+
"color: rgb(187, 186, 186); font-weight: bold",
|
|
29
|
+
state.name,
|
|
30
|
+
"@",
|
|
31
|
+
this.time
|
|
32
|
+
);
|
|
33
|
+
console.log(
|
|
34
|
+
" %cPrevious State",
|
|
35
|
+
"color: #26ad65; font-weight: bold",
|
|
36
|
+
this.previousState
|
|
37
|
+
);
|
|
38
|
+
console.log(
|
|
39
|
+
" %cNext State ",
|
|
40
|
+
"color: rgb(17, 118, 249); font-weight: bold",
|
|
41
|
+
state.getState()
|
|
42
|
+
);
|
|
43
|
+
this.previousState = null;
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
/**
|
|
47
|
+
* Time
|
|
48
|
+
*
|
|
49
|
+
* Returns the time in which a given state transition completed
|
|
50
|
+
*/
|
|
51
|
+
private get time() {
|
|
52
|
+
const date = new Date();
|
|
53
|
+
const mHours = date.getHours();
|
|
54
|
+
const hours = mHours > 12 ? mHours - 12 : mHours;
|
|
55
|
+
const mins = date.getMinutes();
|
|
56
|
+
const minutes = mins.toString().length === 1 ? `0${mins}` : mins;
|
|
57
|
+
const secs = date.getSeconds();
|
|
58
|
+
const seconds = secs.toString().length === 1 ? `0${secs}` : secs;
|
|
59
|
+
const milliseconds = date.getMilliseconds();
|
|
60
|
+
return `${hours}:${minutes}:${seconds}:${milliseconds}`;
|
|
61
|
+
}
|
|
62
|
+
}
|
|
@@ -0,0 +1,38 @@
|
|
|
1
|
+
import type { State } from "Galena/State";
|
|
2
|
+
import { Middleware } from "Middleware/Middleware";
|
|
3
|
+
|
|
4
|
+
/**
|
|
5
|
+
* Profiler
|
|
6
|
+
*
|
|
7
|
+
* A logger for state transitions exceeding a given threshold
|
|
8
|
+
* for duration:
|
|
9
|
+
*
|
|
10
|
+
* ```typescript
|
|
11
|
+
* const State = new Galena([new Profiler()]);
|
|
12
|
+
* // if using isolated state instances:
|
|
13
|
+
* const MyState = new State(...args);
|
|
14
|
+
* MyState.registerMiddleware(new Profiler())
|
|
15
|
+
* ```
|
|
16
|
+
*/
|
|
17
|
+
export class Profiler extends Middleware {
|
|
18
|
+
private threshold: number;
|
|
19
|
+
private startTime: number | null = null;
|
|
20
|
+
constructor(threshold = 16) {
|
|
21
|
+
super();
|
|
22
|
+
this.threshold = threshold;
|
|
23
|
+
}
|
|
24
|
+
onBeforeUpdate(_: State) {
|
|
25
|
+
this.startTime = performance.now();
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
onUpdate(nextState: State) {
|
|
29
|
+
if (this.startTime) {
|
|
30
|
+
const endTime = performance.now();
|
|
31
|
+
const diff = endTime - this.startTime;
|
|
32
|
+
if (diff > this.threshold) {
|
|
33
|
+
console.warn("Slow state transition detected", nextState);
|
|
34
|
+
console.warn(`The last transition took ${diff}ms`);
|
|
35
|
+
}
|
|
36
|
+
}
|
|
37
|
+
}
|
|
38
|
+
}
|
package/src/index.ts
ADDED