UNPKG

2.71 kBJavaScriptView Raw
1'use strict';
2
3Object.defineProperty(exports, '__esModule', { value: true });
4
5function systemReducer(state, action) {
6 switch (action.type) {
7 case "SET": {
8 const { name, value } = action.payload;
9 return {
10 ...state,
11 [name]: value,
12 }
13 }
14 case "MERGE": {
15 return {
16 ...state,
17 ...action.payload,
18 }
19 }
20 }
21}
22
23/*
24
25Notes
26
27 - any call to dispatch will immediately invoke the reducer
28 - any call to dispatch within middleware is also immediately processed
29 - SET and MERGE are not interceptable by middleware
30 - middleware functions are assumed to call next synchronously
31 - the render function (subscriber) is invoked once for every call to dispatch
32 - the render function is debounced
33
34*/
35
36function configure(
37 { update = {}, middleware = [], derivations = {}, initialState = {} },
38 node
39) {
40 let subscribers = [];
41 let state;
42 let updatedCallback = () => {};
43
44 function updateState(o) {
45 state = { ...o };
46 for (let k in derivations) {
47 state[k] = derivations[k](o);
48 }
49 }
50
51 updateState(initialState);
52
53 function getState() {
54 return { ...state }
55 }
56
57 function subscribe(fn) {
58 subscribers.push(fn);
59 }
60
61 function flush() {
62 subscribers.forEach((fn) => fn());
63 subscribers = [];
64 }
65
66 function onUpdate(fn) {
67 updatedCallback = fn;
68 }
69
70 function dispatch(action) {
71 const { type } = action;
72 if (type === "SET" || type === "MERGE") {
73 updateState(systemReducer(getState(), action));
74 } else {
75 if (middleware.length) {
76 let mw = middleware.slice();
77
78 let next = (action) => {
79 if (mw.length) {
80 let x = mw.shift();
81
82 if (action.type in x) {
83 x[action.type](action, next, {
84 getState,
85 dispatch,
86 afterNextRender: subscribe,
87 });
88 } else {
89 next(action);
90 }
91 } else if (action.type in update) {
92 updateState(update[action.type](getState(), action));
93 }
94 };
95
96 let x = mw.shift();
97
98 if (type in x) {
99 x[type](action, next, {
100 getState,
101 dispatch,
102 afterNextRender: subscribe,
103 });
104 } else {
105 next(action);
106 }
107 } else if (type in update) {
108 updateState(update[type](getState(), action));
109 }
110 }
111 updatedCallback();
112 }
113
114 for (let actionName in update) {
115 if (actionName.startsWith("$")) {
116 node.addEventListener(actionName, ({ detail }) => dispatch(detail));
117 }
118 }
119
120 return {
121 dispatch,
122 getState,
123 onUpdate,
124 flush,
125 }
126}
127
128exports.configure = configure;