@@ -8,14 +8,31 @@ public final class LoggerMiddleware<AppAction, AppState: Equatable>: Middleware
88 public typealias StateType = AppState
99
1010 private var getState : GetState < StateType > ?
11- private let printer : ( StaticString , CVarArg . . . ) -> Void
12-
13- public init ( printer: ( ( StaticString , CVarArg . . . ) -> Void ) ? = nil ) {
14- self . printer = printer ?? { ( message: StaticString, args: CVarArg... ) - > Void in os_log ( . debug, log: . default, message, args) }
15- }
16-
17- public init ( printer: @escaping ( String ) -> Void ) {
18- self . printer = { ( message: StaticString, args: CVarArg... ) - > Void in printer ( String ( format: " \( message) " , args) ) }
11+ private let actionTransform : ( AppAction , ActionSource ) -> String
12+ private let actionPrinter : ( String ) -> Void
13+ private let stateDiffTransform : ( AppState , AppState ) -> String ?
14+ private let stateDiffPrinter : ( String ? ) -> Void
15+
16+ public init (
17+ actionTransform: @escaping ( AppAction , ActionSource ) -> String = { " 🕹 \( LoggerMiddleware . dumpToString ( $0) ) from \( $1) " } ,
18+ actionPrinter: @escaping ( String ) -> Void = { os_log ( . debug, log: . default, " %{PUBLIC}@ " , $0) } ,
19+ stateDiffTransform: @escaping ( AppState , AppState ) -> String ? = {
20+ let stateBefore = LoggerMiddleware . dumpToString ( $0)
21+ let stateAfter = LoggerMiddleware . dumpToString ( $1)
22+ return LoggerMiddleware . diff ( old: stateBefore, new: stateAfter, linesOfContext: 2 , prefixLines: " 🏛 " )
23+ } ,
24+ stateDiffPrinter: @escaping ( String ? ) -> Void = { state in
25+ if let state = state {
26+ os_log ( . debug, log: . default, " %{PUBLIC}@ " , state)
27+ } else {
28+ os_log ( . debug, log: . default, " %{PUBLIC}@ " , " 🏛 No state mutation " )
29+ }
30+ }
31+ ) {
32+ self . actionTransform = actionTransform
33+ self . actionPrinter = actionPrinter
34+ self . stateDiffTransform = stateDiffTransform
35+ self . stateDiffPrinter = stateDiffPrinter
1936 }
2037
2138 public func receiveContext( getState: @escaping GetState < StateType > , output: AnyActionHandler < OutputActionType > ) {
@@ -25,27 +42,67 @@ public final class LoggerMiddleware<AppAction, AppState: Equatable>: Middleware
2542 public func handle( action: InputActionType , from dispatcher: ActionSource , afterReducer: inout AfterReducer ) {
2643 guard let getState = self . getState else { return }
2744
28- var stateBefore = " "
29- dump ( getState ( ) , to: & stateBefore, name: nil , indent: 2 )
45+ let stateBefore = getState ( )
46+ let actionMessage = actionTransform ( action, dispatcher)
47+
3048 afterReducer = . do {
31- var stateAfter = " "
32- dump ( getState ( ) , to: & stateAfter, name: nil , indent: 2 )
49+ let stateAfter = getState ( )
50+
51+ self . actionPrinter ( actionMessage)
52+ self . stateDiffPrinter ( self . stateDiffTransform ( stateBefore, stateAfter) )
53+ }
54+ }
3355
34- let message = " 🕹 \( action) from \( dispatcher) "
35- self . printer ( " %{PUBLIC}@ " , message)
56+ public static func dumpToString< T> ( _ something: T , indent: Int = 2 ) -> String {
57+ var output = " "
58+ dump ( something, to: & output, name: nil , indent: indent)
59+ return output
60+ }
3661
37- if let stateString = diff ( old: stateBefore, new: stateAfter) {
38- self . printer ( " \n %{PUBLIC}@ " , stateString)
39- } else {
40- self . printer ( " 🏛 No state mutation " )
41- }
62+ public static func diff( old: String , new: String , linesOfContext: Int , prefixLines: String = " " ) -> String ? {
63+ guard old != new else { return nil }
64+ let oldSplit = old. split ( separator: " \n " , omittingEmptySubsequences: false ) . map ( String . init)
65+ let newSplit = new. split ( separator: " \n " , omittingEmptySubsequences: false ) . map ( String . init)
66+
67+ return chunk (
68+ diff: diff ( oldSplit, newSplit) ,
69+ context: linesOfContext
70+ ) . lazy. flatMap { [ $0. patchMark] + $0. lines } . map { " \( prefixLines) \( $0) " } . joined ( separator: " \n " )
71+ }
72+
73+ public static func diff( _ fst: [ String ] , _ snd: [ String ] ) -> [ Difference < String > ] {
74+ var idxsOf = [ String: [ Int] ] ( )
75+ fst. enumerated ( ) . forEach { idxsOf [ $1, default: [ ] ] . append ( $0) }
4276
43- self . printer ( " " )
77+ let sub = snd. enumerated ( ) . reduce ( ( overlap: [ Int: Int] ( ) , fst: 0 , snd: 0 , len: 0 ) ) { sub, sndPair in
78+ ( idxsOf [ sndPair. element] ?? [ ] )
79+ . reduce ( ( overlap: [ Int: Int] ( ) , fst: sub. fst, snd: sub. snd, len: sub. len) ) { innerSub, fstIdx in
80+
81+ var newOverlap = innerSub. overlap
82+ newOverlap [ fstIdx] = ( sub. overlap [ fstIdx - 1 ] ?? 0 ) + 1
83+
84+ if let newLen = newOverlap [ fstIdx] , newLen > sub. len {
85+ return ( newOverlap, fstIdx - newLen + 1 , sndPair. offset - newLen + 1 , newLen)
86+ }
87+ return ( newOverlap, innerSub. fst, innerSub. snd, innerSub. len)
88+ }
89+ }
90+ let ( _, fstIdx, sndIdx, len) = sub
91+
92+ if len == 0 {
93+ let fstDiff = fst. isEmpty ? [ ] : [ Difference ( elements: fst, which: . first) ]
94+ let sndDiff = snd. isEmpty ? [ ] : [ Difference ( elements: snd, which: . second) ]
95+ return fstDiff + sndDiff
96+ } else {
97+ let fstDiff = diff ( Array ( fst. prefix ( upTo: fstIdx) ) , Array ( snd. prefix ( upTo: sndIdx) ) )
98+ let midDiff = [ Difference ( elements: Array ( fst. suffix ( from: fstIdx) . prefix ( len) ) , which: . both) ]
99+ let lstDiff = diff ( Array ( fst. suffix ( from: fstIdx + len) ) , Array ( snd. suffix ( from: sndIdx + len) ) )
100+ return fstDiff + midDiff + lstDiff
44101 }
45102 }
46103}
47104
48- struct Difference < A> {
105+ public struct Difference < A> {
49106 enum Which {
50107 case first
51108 case second
@@ -56,48 +113,6 @@ struct Difference<A> {
56113 let which : Which
57114}
58115
59- func diff( old: String , new: String ) -> String ? {
60- guard old != new else { return nil }
61- let oldSplit = old. split ( separator: " \n " , omittingEmptySubsequences: false ) . map ( String . init)
62- let newSplit = new. split ( separator: " \n " , omittingEmptySubsequences: false ) . map ( String . init)
63-
64- return chunk (
65- diff: diff ( oldSplit, newSplit) ,
66- context: 2 // Lines before and after the changes to be shown as context
67- ) . lazy. flatMap { [ $0. patchMark] + $0. lines } . map { " 🏛 \( $0) " } . joined ( separator: " \n " )
68- }
69-
70- func diff( _ fst: [ String ] , _ snd: [ String ] ) -> [ Difference < String > ] {
71- var idxsOf = [ String: [ Int] ] ( )
72- fst. enumerated ( ) . forEach { idxsOf [ $1, default: [ ] ] . append ( $0) }
73-
74- let sub = snd. enumerated ( ) . reduce ( ( overlap: [ Int: Int] ( ) , fst: 0 , snd: 0 , len: 0 ) ) { sub, sndPair in
75- ( idxsOf [ sndPair. element] ?? [ ] )
76- . reduce ( ( overlap: [ Int: Int] ( ) , fst: sub. fst, snd: sub. snd, len: sub. len) ) { innerSub, fstIdx in
77-
78- var newOverlap = innerSub. overlap
79- newOverlap [ fstIdx] = ( sub. overlap [ fstIdx - 1 ] ?? 0 ) + 1
80-
81- if let newLen = newOverlap [ fstIdx] , newLen > sub. len {
82- return ( newOverlap, fstIdx - newLen + 1 , sndPair. offset - newLen + 1 , newLen)
83- }
84- return ( newOverlap, innerSub. fst, innerSub. snd, innerSub. len)
85- }
86- }
87- let ( _, fstIdx, sndIdx, len) = sub
88-
89- if len == 0 {
90- let fstDiff = fst. isEmpty ? [ ] : [ Difference ( elements: fst, which: . first) ]
91- let sndDiff = snd. isEmpty ? [ ] : [ Difference ( elements: snd, which: . second) ]
92- return fstDiff + sndDiff
93- } else {
94- let fstDiff = diff ( Array ( fst. prefix ( upTo: fstIdx) ) , Array ( snd. prefix ( upTo: sndIdx) ) )
95- let midDiff = [ Difference ( elements: Array ( fst. suffix ( from: fstIdx) . prefix ( len) ) , which: . both) ]
96- let lstDiff = diff ( Array ( fst. suffix ( from: fstIdx + len) ) , Array ( snd. suffix ( from: sndIdx + len) ) )
97- return fstDiff + midDiff + lstDiff
98- }
99- }
100-
101116let minus = " − "
102117let plus = " + "
103118private let figureSpace = " \u{2007} "
0 commit comments