Repository navigation
Expand file tree
/
Copy pathmain.go
More file actions
85 lines (71 loc) · 2.85 KB
/
Copy pathmain.go
File metadata and controls
85 lines (71 loc) · 2.85 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
// Command example demonstrates the immutable-state-invariant middleware
// catching an in-place state mutation performed by a reducer.
//
// It is the Go port of the original example/src/index.js, which used redux's
// createStore + applyMiddleware. Go has no redux, so this file includes a
// tiny store shim providing just enough of the createStore/applyMiddleware
// contract for the middleware to run. The reducer mutates state in place on the
// ARRAY_MUTATION action, exactly like the JS example, so dispatching it trips
// the invariant and the program reports the detected mutation.
package main
import (
"fmt"
invariant "github.com/leoasis/redux-immutable-state-invariant"
)
// reducer mirrors the JS example reducer: on ARRAY_MUTATION it pushes the
// action's element onto state.stuff *in place* and returns the same state
// object (the mutation the middleware is designed to catch); otherwise it
// returns state unchanged.
func reducer(state *invariant.Obj, action invariant.Action) *invariant.Obj {
act := action.(*invariant.Obj)
typ, _ := act.Get("type")
if typ == invariant.Str("ARRAY_MUTATION") {
stuff, _ := state.Get("stuff")
element, _ := act.Get("element")
stuff.(*invariant.Arr).Push(element)
return state
}
return state
}
// store is a minimal Redux-like store: it holds the current state, exposes
// GetState, and threads dispatch through the single configured middleware.
type store struct {
state *invariant.Obj
dispatch invariant.Dispatch
}
// createStore wires the reducer together with the middleware, mirroring
// createStore(reducer, applyMiddleware(mw)).
func createStore(initial *invariant.Obj, mw invariant.Middleware) *store {
s := &store{state: initial}
api := invariant.MiddlewareAPI{GetState: func() invariant.Value { return s.state }}
// base is the innermost dispatch: run the reducer and store the result.
base := invariant.Dispatch(func(action invariant.Action) invariant.Value {
s.state = reducer(s.state, action)
return action
})
s.dispatch = mw(api)(base)
return s
}
func main() {
initialState := invariant.NewObj().Set("stuff", invariant.NewArr())
s := createStore(initialState, invariant.New(nil))
action := invariant.NewObj().
Set("type", invariant.Str("ARRAY_MUTATION")).
Set("element", invariant.NewObj().Set("a", invariant.Num(1)).Set("b", invariant.Num(2)))
// The reducer mutates state in place, so the middleware detects it and
// panics with an *InvariantError. Recover so the example prints the
// detected mutation rather than crashing, demonstrating the middleware's
// behavior end to end.
defer func() {
if r := recover(); r != nil {
if err, ok := r.(*invariant.InvariantError); ok {
fmt.Println("Mutation detected by middleware:")
fmt.Println(err.Message)
return
}
panic(r)
}
}()
s.dispatch(action)
fmt.Println("No mutation detected (unexpected for this example).")
}