@reventlessdev/reventless-gwt 1.0.0-alpha.74

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 (172) hide show
  1. package/CHANGELOG.md +698 -0
  2. package/LICENSE +202 -0
  3. package/bin/reventless-dev.mjs +21 -0
  4. package/package.json +54 -0
  5. package/rescript.json +36 -0
  6. package/src/.gwtignore +10 -0
  7. package/src/Automation_GWT.res +207 -0
  8. package/src/Automation_GWT.res.mjs +160 -0
  9. package/src/Behavior_GWT.res +603 -0
  10. package/src/Behavior_GWT.res.mjs +426 -0
  11. package/src/Bind.res +29 -0
  12. package/src/Bind.res.mjs +22 -0
  13. package/src/BuildClassifier.res +137 -0
  14. package/src/BuildClassifier.res.mjs +136 -0
  15. package/src/Cancellation.res +31 -0
  16. package/src/Cancellation.res.mjs +45 -0
  17. package/src/ChildProcess.res +84 -0
  18. package/src/ChildProcess.res.mjs +92 -0
  19. package/src/Cli.res +671 -0
  20. package/src/Cli.res.mjs +754 -0
  21. package/src/Collector.res +201 -0
  22. package/src/Collector.res.mjs +215 -0
  23. package/src/ComponentMeta.res +104 -0
  24. package/src/ComponentMeta.res.mjs +120 -0
  25. package/src/ComponentScan.res +103 -0
  26. package/src/ComponentScan.res.mjs +105 -0
  27. package/src/Delegate_GWT.res +303 -0
  28. package/src/Delegate_GWT.res.mjs +372 -0
  29. package/src/Diff.res +91 -0
  30. package/src/Diff.res.mjs +98 -0
  31. package/src/Discovery.res +105 -0
  32. package/src/Discovery.res.mjs +103 -0
  33. package/src/DomainDeadCode.res +93 -0
  34. package/src/DomainDeadCode.res.mjs +69 -0
  35. package/src/DomainGraph.res +0 -0
  36. package/src/DomainGraph.res.mjs +0 -0
  37. package/src/EventMapping_GWT.res +29 -0
  38. package/src/EventMapping_GWT.res.mjs +44 -0
  39. package/src/Filter.res +36 -0
  40. package/src/Filter.res.mjs +40 -0
  41. package/src/Flow_GWT.res +664 -0
  42. package/src/Flow_GWT.res.mjs +604 -0
  43. package/src/FormatterHuman.res +138 -0
  44. package/src/FormatterHuman.res.mjs +122 -0
  45. package/src/FormatterJson.res +257 -0
  46. package/src/FormatterJson.res.mjs +320 -0
  47. package/src/FormatterJunit.res +93 -0
  48. package/src/FormatterJunit.res.mjs +90 -0
  49. package/src/FormatterTap.res +139 -0
  50. package/src/FormatterTap.res.mjs +149 -0
  51. package/src/FormatterVsCode.res +362 -0
  52. package/src/FormatterVsCode.res.mjs +564 -0
  53. package/src/Hint.res +119 -0
  54. package/src/Hint.res.mjs +124 -0
  55. package/src/InboundTranslation_GWT.res +83 -0
  56. package/src/InboundTranslation_GWT.res.mjs +94 -0
  57. package/src/JestBind.res +70 -0
  58. package/src/JestBind.res.mjs +63 -0
  59. package/src/Loader.res +24 -0
  60. package/src/Loader.res.mjs +23 -0
  61. package/src/LocalHost.res +135 -0
  62. package/src/LocalHost.res.mjs +127 -0
  63. package/src/Mapping_GWT.res +474 -0
  64. package/src/Mapping_GWT.res.mjs +322 -0
  65. package/src/MultiSourceProjection_GWT.res +316 -0
  66. package/src/MultiSourceProjection_GWT.res.mjs +354 -0
  67. package/src/OutboundTranslation_GWT.res +238 -0
  68. package/src/OutboundTranslation_GWT.res.mjs +186 -0
  69. package/src/Outcome.res +161 -0
  70. package/src/Outcome.res.mjs +140 -0
  71. package/src/PackageScan.res +80 -0
  72. package/src/PackageScan.res.mjs +81 -0
  73. package/src/PlatformRunner.res +160 -0
  74. package/src/PlatformRunner.res.mjs +155 -0
  75. package/src/PlatformScan.res +138 -0
  76. package/src/PlatformScan.res.mjs +131 -0
  77. package/src/ProcessManager.res +91 -0
  78. package/src/ProcessManager.res.mjs +80 -0
  79. package/src/Projection_GWT.res +312 -0
  80. package/src/Projection_GWT.res.mjs +332 -0
  81. package/src/Query_GWT.res +379 -0
  82. package/src/Query_GWT.res.mjs +367 -0
  83. package/src/RenderRescript.res +125 -0
  84. package/src/RenderRescript.res.mjs +141 -0
  85. package/src/RunnerTypes.res +68 -0
  86. package/src/RunnerTypes.res.mjs +60 -0
  87. package/src/SideEffect_GWT.res +157 -0
  88. package/src/SideEffect_GWT.res.mjs +113 -0
  89. package/src/StateChange/ExternalAddCategorySlice.res +25 -0
  90. package/src/StateChange/ExternalAddCategorySlice.res.mjs +34 -0
  91. package/src/StateChange/ExternalAddCategorySlice_Behavior.res +19 -0
  92. package/src/StateChange/ExternalAddCategorySlice_Behavior.res.mjs +46 -0
  93. package/src/StateChange/WithFixtures.res +22 -0
  94. package/src/StateChange/WithFixtures.res.mjs +31 -0
  95. package/src/StateChange/WithFixtures_Behavior.res +17 -0
  96. package/src/StateChange/WithFixtures_Behavior.res.mjs +37 -0
  97. package/src/StateChange/WithManualOpen.res +23 -0
  98. package/src/StateChange/WithManualOpen.res.mjs +31 -0
  99. package/src/StateChange/WithManualOpen_Behavior.res +17 -0
  100. package/src/StateChange/WithManualOpen_Behavior.res.mjs +37 -0
  101. package/src/StubRuntime.res +53 -0
  102. package/src/StubRuntime.res.mjs +54 -0
  103. package/src/TestFixtures.res +16 -0
  104. package/src/TestFixtures.res.mjs +34 -0
  105. package/src/Watch.res +92 -0
  106. package/src/Watch.res.mjs +83 -0
  107. package/src/WatcherProbe.res +48 -0
  108. package/src/WatcherProbe.res.mjs +46 -0
  109. package/tests/AutomationGwtTest.res +71 -0
  110. package/tests/AutomationGwtTest.res.mjs +189 -0
  111. package/tests/BuildClassifierTest.res +94 -0
  112. package/tests/BuildClassifierTest.res.mjs +132 -0
  113. package/tests/ComponentMetaTest.res +52 -0
  114. package/tests/ComponentMetaTest.res.mjs +57 -0
  115. package/tests/DelegateGwtTest.res +487 -0
  116. package/tests/DelegateGwtTest.res.mjs +891 -0
  117. package/tests/DiscoveryTest.res +42 -0
  118. package/tests/DiscoveryTest.res.mjs +43 -0
  119. package/tests/DomainDeadCodeTest.res +116 -0
  120. package/tests/DomainDeadCodeTest.res.mjs +155 -0
  121. package/tests/DomainGraphTest.res +365 -0
  122. package/tests/DomainGraphTest.res.mjs +413 -0
  123. package/tests/FlowAggregateGwtTest.res +169 -0
  124. package/tests/FlowAggregateGwtTest.res.mjs +269 -0
  125. package/tests/FlowCrossPluginGwtTest.res +340 -0
  126. package/tests/FlowCrossPluginGwtTest.res.mjs +798 -0
  127. package/tests/FlowGwtTest.res +222 -0
  128. package/tests/FlowGwtTest.res.mjs +432 -0
  129. package/tests/FormatterVsCodeMessageTest.res +41 -0
  130. package/tests/FormatterVsCodeMessageTest.res.mjs +42 -0
  131. package/tests/InboundTranslationGwtTest.res +34 -0
  132. package/tests/InboundTranslationGwtTest.res.mjs +98 -0
  133. package/tests/LocalHostIntegration.res +70 -0
  134. package/tests/LocalHostIntegration.res.mjs +64 -0
  135. package/tests/LocalHostTest.res +71 -0
  136. package/tests/LocalHostTest.res.mjs +63 -0
  137. package/tests/MappingGwtTest.res +348 -0
  138. package/tests/MappingGwtTest.res.mjs +592 -0
  139. package/tests/OutboundTranslationGwtTest.res +59 -0
  140. package/tests/OutboundTranslationGwtTest.res.mjs +138 -0
  141. package/tests/PlatformRunnerTest.res +66 -0
  142. package/tests/PlatformRunnerTest.res.mjs +85 -0
  143. package/tests/PlatformScanTest.res +61 -0
  144. package/tests/PlatformScanTest.res.mjs +56 -0
  145. package/tests/QueryGwtTest.res +161 -0
  146. package/tests/QueryGwtTest.res.mjs +314 -0
  147. package/tests/QueryResolverGwtTest.res +71 -0
  148. package/tests/QueryResolverGwtTest.res.mjs +136 -0
  149. package/tests/RunnerUnitTest.res +219 -0
  150. package/tests/RunnerUnitTest.res.mjs +244 -0
  151. package/tests/SideEffect/FakeOrderNotification.res +23 -0
  152. package/tests/SideEffect/FakeOrderNotification.res.mjs +36 -0
  153. package/tests/SideEffect/FakeOrderNotificationGwtTest.res +35 -0
  154. package/tests/SideEffect/FakeOrderNotificationGwtTest.res.mjs +73 -0
  155. package/tests/SideEffect/MockEmail.res +18 -0
  156. package/tests/SideEffect/MockEmail.res.mjs +47 -0
  157. package/tests/StateChange/ExternalAddCategorySlice_GWT.res +27 -0
  158. package/tests/StateChange/ExternalAddCategorySlice_GWT.res.mjs +70 -0
  159. package/tests/StateChange/WithFixtures_Fixtures.res +9 -0
  160. package/tests/StateChange/WithFixtures_Fixtures.res.mjs +20 -0
  161. package/tests/StateChange/WithFixtures_GWT.res +23 -0
  162. package/tests/StateChange/WithFixtures_GWT.res.mjs +56 -0
  163. package/tests/StateChange/WithManualOpen_Fixtures.res +7 -0
  164. package/tests/StateChange/WithManualOpen_Fixtures.res.mjs +20 -0
  165. package/tests/StateChange/WithManualOpen_GWT.res +17 -0
  166. package/tests/StateChange/WithManualOpen_GWT.res.mjs +56 -0
  167. package/tests/StateChangeSliceGwtTest.res +160 -0
  168. package/tests/StateChangeSliceGwtTest.res.mjs +280 -0
  169. package/tests/StateViewSliceGwtTest.res +64 -0
  170. package/tests/StateViewSliceGwtTest.res.mjs +161 -0
  171. package/tests/WatchDebounceTest.res +78 -0
  172. package/tests/WatchDebounceTest.res.mjs +97 -0
@@ -0,0 +1,222 @@
1
+ // Worked example for Flow_GWT — a single-plugin order flow threaded through a
2
+ // command slice, an automation, a second command slice, a read-model view and
3
+ // an outbound effect. One declarative chain asserts that the slices compose as
4
+ // an Event Modeling lane would draw them.
5
+ //
6
+ // Also exercises DCB tag isolation: a second order is placed successfully even
7
+ // though a first order is already on the shared log, because each command step
8
+ // filters the log by its command's tags.
9
+ // See `docs/plans/done/gwt-flow-and-extension-test-kinds.md` Phase 2.
10
+
11
+ S.enableJson()
12
+
13
+ open Flow_GWT
14
+
15
+ // -- Slices ------------------------------------------------------------------
16
+
17
+ module PlaceOrderSlice = {
18
+ let name = "PlaceOrder"
19
+
20
+ @schema
21
+ type consumedEvent = OrderPlaced({orderId: @s.matches(Reventless.DcbTag.string) string})
22
+
23
+ @schema
24
+ type command = PlaceOrder({orderId: @s.matches(Reventless.DcbTag.string) string, item: string})
25
+
26
+ @schema
27
+ type error = AlreadyPlaced
28
+
29
+ @schema
30
+ type event = OrderPlaced({orderId: @s.matches(Reventless.DcbTag.string) string, item: string})
31
+ }
32
+
33
+ module PlaceOrderBehavior = {
34
+ module Spec = PlaceOrderSlice
35
+ type state = {placed: bool}
36
+ let initialState = {placed: false}
37
+
38
+ let evolve = (_state, event: PlaceOrderSlice.consumedEvent) =>
39
+ switch event {
40
+ | OrderPlaced(_) => {placed: true}
41
+ }
42
+
43
+ let decide = (state, command: PlaceOrderSlice.command) =>
44
+ switch command {
45
+ | PlaceOrder({orderId, item}) =>
46
+ state.placed
47
+ ? Error(PlaceOrderSlice.AlreadyPlaced)
48
+ : Ok([PlaceOrderSlice.OrderPlaced({orderId, item})])
49
+ }
50
+ }
51
+
52
+ module AutoShipSlice = {
53
+ let name = "AutoShip"
54
+
55
+ @schema
56
+ type consumedEvent =
57
+ | OrderPlaced({orderId: string})
58
+ | OrderShipped({orderId: string})
59
+
60
+ @schema
61
+ type todoItem = {orderId: string}
62
+
63
+ @schema
64
+ type command = ShipOrder({orderId: string})
65
+
66
+ let collect = event =>
67
+ switch event {
68
+ | OrderPlaced({orderId}) => [(orderId, ({orderId: orderId}: todoItem))]
69
+ | OrderShipped(_) => []
70
+ }
71
+
72
+ let resolve = event =>
73
+ switch event {
74
+ | OrderShipped({orderId}) => Some(orderId)
75
+ | OrderPlaced(_) => None
76
+ }
77
+
78
+ let process = (id, _todo) => Some((id, ShipOrder({orderId: id})))
79
+ }
80
+
81
+ module ShipOrderSlice = {
82
+ let name = "ShipOrder"
83
+
84
+ @schema
85
+ type consumedEvent =
86
+ | OrderPlaced({orderId: @s.matches(Reventless.DcbTag.string) string})
87
+ | OrderShipped({orderId: @s.matches(Reventless.DcbTag.string) string})
88
+
89
+ @schema
90
+ type command = ShipOrder({orderId: @s.matches(Reventless.DcbTag.string) string})
91
+
92
+ @schema
93
+ type error = NotPlaced
94
+
95
+ @schema
96
+ type event = OrderShipped({orderId: @s.matches(Reventless.DcbTag.string) string})
97
+ }
98
+
99
+ module ShipOrderBehavior = {
100
+ module Spec = ShipOrderSlice
101
+ type state = {placed: bool, shipped: bool}
102
+ let initialState = {placed: false, shipped: false}
103
+
104
+ let evolve = (state, event: ShipOrderSlice.consumedEvent) =>
105
+ switch event {
106
+ | OrderPlaced(_) => {...state, placed: true}
107
+ | OrderShipped(_) => {...state, shipped: true}
108
+ }
109
+
110
+ let decide = (state, command: ShipOrderSlice.command) =>
111
+ switch command {
112
+ | ShipOrder({orderId}) =>
113
+ if !state.placed {
114
+ Error(ShipOrderSlice.NotPlaced)
115
+ } else if state.shipped {
116
+ Ok([])
117
+ } else {
118
+ Ok([ShipOrderSlice.OrderShipped({orderId: orderId})])
119
+ }
120
+ }
121
+ }
122
+
123
+ module OrdersViewSlice = {
124
+ let name = "OrdersView"
125
+
126
+ @schema
127
+ type state = {orderId: string, item: string, status: string}
128
+
129
+ @schema
130
+ type consumedEvent =
131
+ | OrderPlaced({orderId: string, item: string})
132
+ | OrderShipped({orderId: string})
133
+
134
+ let subIdConfig = None
135
+ }
136
+
137
+ module OrdersViewProjection = {
138
+ module Spec = OrdersViewSlice
139
+ open Reventless.Projection
140
+
141
+ let project = (event: OrdersViewSlice.consumedEvent) =>
142
+ switch event {
143
+ | OrderPlaced({orderId, item}) => [
144
+ Set(orderId, ({orderId, item, status: "Placed"}: OrdersViewSlice.state)),
145
+ ]
146
+ | OrderShipped({orderId}) => [Update(orderId, state => {...state, status: "Shipped"})]
147
+ }
148
+ }
149
+
150
+ module ConfirmSlice = {
151
+ let name = "Confirm"
152
+
153
+ @schema
154
+ type consumedEvent = OrderPlaced({orderId: string})
155
+
156
+ @schema
157
+ type outboundItem = {orderId: string}
158
+
159
+ @schema
160
+ type inboundCommand = unit
161
+
162
+ let collect = event =>
163
+ switch event {
164
+ | OrderPlaced({orderId}) => [(orderId, ({orderId: orderId}: outboundItem))]
165
+ }
166
+ }
167
+
168
+ // -- Step modules ------------------------------------------------------------
169
+
170
+ module Place = CommandStep(PlaceOrderSlice, PlaceOrderBehavior)
171
+ module Auto = AutomationStep(AutoShipSlice)
172
+ module Ship = CommandStep(ShipOrderSlice, ShipOrderBehavior)
173
+ module View = ViewStep(OrdersViewSlice, OrdersViewProjection)
174
+ module Confirm = OutboundStep(ConfirmSlice)
175
+
176
+ // -- Flows -------------------------------------------------------------------
177
+
178
+ describe("Order flow (single plugin)", () => {
179
+ test("place → auto-ship → ship → view Shipped → confirmation fired", () =>
180
+ start
181
+ ->Place.whenCommand(PlaceOrderSlice.PlaceOrder({orderId: "o1", item: "book"}))
182
+ ->Place.thenEvents([PlaceOrderSlice.OrderPlaced({orderId: "o1", item: "book"})])
183
+ ->Auto.whenReacts
184
+ ->Auto.thenIssuesCommand(AutoShipSlice.ShipOrder({orderId: "o1"}))
185
+ ->Ship.whenCommand(ShipOrderSlice.ShipOrder({orderId: "o1"}))
186
+ ->Ship.thenEvents([ShipOrderSlice.OrderShipped({orderId: "o1"})])
187
+ ->View.thenViewState("o1", {OrdersViewSlice.orderId: "o1", item: "book", status: "Shipped"})
188
+ ->Confirm.thenOutbound([("o1", {ConfirmSlice.orderId: "o1"})])
189
+ )
190
+
191
+ test("automation does not re-issue ShipOrder once the order is shipped", () =>
192
+ start
193
+ ->Place.whenCommand(PlaceOrderSlice.PlaceOrder({orderId: "o1", item: "book"}))
194
+ ->Ship.whenCommand(ShipOrderSlice.ShipOrder({orderId: "o1"}))
195
+ ->Auto.whenReacts
196
+ ->Auto.thenIssuesNoCommand
197
+ )
198
+
199
+ test("re-placing the same order is rejected", () =>
200
+ start
201
+ ->Place.whenCommand(PlaceOrderSlice.PlaceOrder({orderId: "o1", item: "book"}))
202
+ ->Place.whenCommand(PlaceOrderSlice.PlaceOrder({orderId: "o1", item: "book"}))
203
+ ->Place.thenError(AlreadyPlaced)
204
+ )
205
+
206
+ test("a second, different order is not blocked by the first (DCB tag isolation)", () =>
207
+ start
208
+ ->Place.whenCommand(PlaceOrderSlice.PlaceOrder({orderId: "o1", item: "book"}))
209
+ ->Place.thenEvent(PlaceOrderSlice.OrderPlaced({orderId: "o1", item: "book"}))
210
+ ->Place.whenCommand(PlaceOrderSlice.PlaceOrder({orderId: "o2", item: "pen"}))
211
+ ->Place.thenEvent(PlaceOrderSlice.OrderPlaced({orderId: "o2", item: "pen"}))
212
+ )
213
+
214
+ test("shipping one order leaves a sibling order Placed", () =>
215
+ start
216
+ ->Place.whenCommand(PlaceOrderSlice.PlaceOrder({orderId: "o1", item: "book"}))
217
+ ->Place.whenCommand(PlaceOrderSlice.PlaceOrder({orderId: "o2", item: "pen"}))
218
+ ->Ship.whenCommand(ShipOrderSlice.ShipOrder({orderId: "o1"}))
219
+ ->View.thenViewState("o1", {OrdersViewSlice.orderId: "o1", item: "book", status: "Shipped"})
220
+ ->View.thenViewState("o2", {OrdersViewSlice.orderId: "o2", item: "pen", status: "Placed"})
221
+ )
222
+ })
@@ -0,0 +1,432 @@
1
+ // Generated by ReScript, PLEASE EDIT WITH CARE
2
+
3
+ import * as S from "sury/src/S.res.mjs";
4
+ import * as DcbTag$Reventless from "@reventlessdev/reventless-spec/src/components/DcbTag.res.mjs";
5
+ import * as Flow_GWT$ReventlessGwt from "../src/Flow_GWT.res.mjs";
6
+
7
+ S.enableJson();
8
+
9
+ let consumedEventSchema = S.schema(s => ({
10
+ TAG: "OrderPlaced",
11
+ orderId: s.m(DcbTag$Reventless.string)
12
+ }));
13
+
14
+ let commandSchema = S.schema(s => ({
15
+ TAG: "PlaceOrder",
16
+ orderId: s.m(DcbTag$Reventless.string),
17
+ item: s.m(S.string)
18
+ }));
19
+
20
+ let errorSchema = S.literal("AlreadyPlaced");
21
+
22
+ let eventSchema = S.schema(s => ({
23
+ TAG: "OrderPlaced",
24
+ orderId: s.m(DcbTag$Reventless.string),
25
+ item: s.m(S.string)
26
+ }));
27
+
28
+ function commandAuthorization(param) {
29
+ return "AllowAuthenticated";
30
+ }
31
+
32
+ let PlaceOrderSlice = {
33
+ name: "PlaceOrder",
34
+ consumedEventSchema: consumedEventSchema,
35
+ commandSchema: commandSchema,
36
+ errorSchema: errorSchema,
37
+ eventSchema: eventSchema,
38
+ commandAuthorization: commandAuthorization,
39
+ readConsistency: "EscalateOnRetry"
40
+ };
41
+
42
+ let initialState = {
43
+ placed: false
44
+ };
45
+
46
+ function evolve(_state, event) {
47
+ return {
48
+ placed: true
49
+ };
50
+ }
51
+
52
+ function decide(state, command) {
53
+ if (state.placed) {
54
+ return {
55
+ TAG: "Error",
56
+ _0: "AlreadyPlaced"
57
+ };
58
+ } else {
59
+ return {
60
+ TAG: "Ok",
61
+ _0: [{
62
+ TAG: "OrderPlaced",
63
+ orderId: command.orderId,
64
+ item: command.item
65
+ }]
66
+ };
67
+ }
68
+ }
69
+
70
+ let PlaceOrderBehavior = {
71
+ Spec: undefined,
72
+ initialState: initialState,
73
+ evolve: evolve,
74
+ decide: decide
75
+ };
76
+
77
+ let consumedEventSchema$1 = S.union([
78
+ S.schema(s => ({
79
+ TAG: "OrderPlaced",
80
+ orderId: s.m(S.string)
81
+ })),
82
+ S.schema(s => ({
83
+ TAG: "OrderShipped",
84
+ orderId: s.m(S.string)
85
+ }))
86
+ ]);
87
+
88
+ let todoItemSchema = S.schema(s => ({
89
+ orderId: s.m(S.string)
90
+ }));
91
+
92
+ let commandSchema$1 = S.schema(s => ({
93
+ TAG: "ShipOrder",
94
+ orderId: s.m(S.string)
95
+ }));
96
+
97
+ function collect(event) {
98
+ if (event.TAG !== "OrderPlaced") {
99
+ return [];
100
+ }
101
+ let orderId = event.orderId;
102
+ return [[
103
+ orderId,
104
+ {
105
+ orderId: orderId
106
+ }
107
+ ]];
108
+ }
109
+
110
+ function resolve(event) {
111
+ if (event.TAG === "OrderPlaced") {
112
+ return;
113
+ } else {
114
+ return event.orderId;
115
+ }
116
+ }
117
+
118
+ function process(id, _todo) {
119
+ return [
120
+ id,
121
+ {
122
+ TAG: "ShipOrder",
123
+ orderId: id
124
+ }
125
+ ];
126
+ }
127
+
128
+ function commandAuthorization$1(param) {
129
+ return "AllowAuthenticated";
130
+ }
131
+
132
+ let AutoShipSlice = {
133
+ name: "AutoShip",
134
+ consumedEventSchema: consumedEventSchema$1,
135
+ todoItemSchema: todoItemSchema,
136
+ commandSchema: commandSchema$1,
137
+ collect: collect,
138
+ resolve: resolve,
139
+ process: process,
140
+ commandAuthorization: commandAuthorization$1
141
+ };
142
+
143
+ let consumedEventSchema$2 = S.union([
144
+ S.schema(s => ({
145
+ TAG: "OrderPlaced",
146
+ orderId: s.m(DcbTag$Reventless.string)
147
+ })),
148
+ S.schema(s => ({
149
+ TAG: "OrderShipped",
150
+ orderId: s.m(DcbTag$Reventless.string)
151
+ }))
152
+ ]);
153
+
154
+ let commandSchema$2 = S.schema(s => ({
155
+ TAG: "ShipOrder",
156
+ orderId: s.m(DcbTag$Reventless.string)
157
+ }));
158
+
159
+ let errorSchema$1 = S.literal("NotPlaced");
160
+
161
+ let eventSchema$1 = S.schema(s => ({
162
+ TAG: "OrderShipped",
163
+ orderId: s.m(DcbTag$Reventless.string)
164
+ }));
165
+
166
+ function commandAuthorization$2(param) {
167
+ return "AllowAuthenticated";
168
+ }
169
+
170
+ let ShipOrderSlice = {
171
+ name: "ShipOrder",
172
+ consumedEventSchema: consumedEventSchema$2,
173
+ commandSchema: commandSchema$2,
174
+ errorSchema: errorSchema$1,
175
+ eventSchema: eventSchema$1,
176
+ commandAuthorization: commandAuthorization$2,
177
+ readConsistency: "EscalateOnRetry"
178
+ };
179
+
180
+ let initialState$1 = {
181
+ placed: false,
182
+ shipped: false
183
+ };
184
+
185
+ function evolve$1(state, event) {
186
+ if (event.TAG === "OrderPlaced") {
187
+ return {
188
+ placed: true,
189
+ shipped: state.shipped
190
+ };
191
+ } else {
192
+ return {
193
+ placed: state.placed,
194
+ shipped: true
195
+ };
196
+ }
197
+ }
198
+
199
+ function decide$1(state, command) {
200
+ if (state.placed) {
201
+ if (state.shipped) {
202
+ return {
203
+ TAG: "Ok",
204
+ _0: []
205
+ };
206
+ } else {
207
+ return {
208
+ TAG: "Ok",
209
+ _0: [{
210
+ TAG: "OrderShipped",
211
+ orderId: command.orderId
212
+ }]
213
+ };
214
+ }
215
+ } else {
216
+ return {
217
+ TAG: "Error",
218
+ _0: "NotPlaced"
219
+ };
220
+ }
221
+ }
222
+
223
+ let ShipOrderBehavior = {
224
+ Spec: undefined,
225
+ initialState: initialState$1,
226
+ evolve: evolve$1,
227
+ decide: decide$1
228
+ };
229
+
230
+ let stateSchema = S.schema(s => ({
231
+ orderId: s.m(S.string),
232
+ item: s.m(S.string),
233
+ status: s.m(S.string)
234
+ }));
235
+
236
+ let consumedEventSchema$3 = S.union([
237
+ S.schema(s => ({
238
+ TAG: "OrderPlaced",
239
+ orderId: s.m(S.string),
240
+ item: s.m(S.string)
241
+ })),
242
+ S.schema(s => ({
243
+ TAG: "OrderShipped",
244
+ orderId: s.m(S.string)
245
+ }))
246
+ ]);
247
+
248
+ let OrdersViewSlice = {
249
+ name: "OrdersView",
250
+ stateSchema: stateSchema,
251
+ consumedEventSchema: consumedEventSchema$3,
252
+ subIdConfig: undefined,
253
+ authorization: "AllowAuthenticated",
254
+ visibility: "Public"
255
+ };
256
+
257
+ function project(event) {
258
+ if (event.TAG !== "OrderPlaced") {
259
+ return [{
260
+ TAG: "Update",
261
+ _0: event.orderId,
262
+ _1: state => ({
263
+ orderId: state.orderId,
264
+ item: state.item,
265
+ status: "Shipped"
266
+ })
267
+ }];
268
+ }
269
+ let orderId = event.orderId;
270
+ return [{
271
+ TAG: "Set",
272
+ _0: orderId,
273
+ _1: {
274
+ orderId: orderId,
275
+ item: event.item,
276
+ status: "Placed"
277
+ }
278
+ }];
279
+ }
280
+
281
+ let OrdersViewProjection = {
282
+ Spec: undefined,
283
+ project: project
284
+ };
285
+
286
+ let consumedEventSchema$4 = S.schema(s => ({
287
+ TAG: "OrderPlaced",
288
+ orderId: s.m(S.string)
289
+ }));
290
+
291
+ let outboundItemSchema = S.schema(s => ({
292
+ orderId: s.m(S.string)
293
+ }));
294
+
295
+ function collect$1(event) {
296
+ let orderId = event.orderId;
297
+ return [[
298
+ orderId,
299
+ {
300
+ orderId: orderId
301
+ }
302
+ ]];
303
+ }
304
+
305
+ let ConfirmSlice = {
306
+ name: "Confirm",
307
+ consumedEventSchema: consumedEventSchema$4,
308
+ outboundItemSchema: outboundItemSchema,
309
+ inboundCommandSchema: S.unit,
310
+ collect: collect$1
311
+ };
312
+
313
+ let Place = Flow_GWT$ReventlessGwt.CommandStep(PlaceOrderSlice)({
314
+ initialState: initialState,
315
+ evolve: evolve,
316
+ decide: decide
317
+ });
318
+
319
+ let Auto = Flow_GWT$ReventlessGwt.AutomationStep(AutoShipSlice);
320
+
321
+ let Ship = Flow_GWT$ReventlessGwt.CommandStep(ShipOrderSlice)({
322
+ initialState: initialState$1,
323
+ evolve: evolve$1,
324
+ decide: decide$1
325
+ });
326
+
327
+ let View = Flow_GWT$ReventlessGwt.ViewStep(OrdersViewSlice)({
328
+ project: project
329
+ });
330
+
331
+ let Confirm = Flow_GWT$ReventlessGwt.OutboundStep(ConfirmSlice);
332
+
333
+ Flow_GWT$ReventlessGwt.describe("Order flow (single plugin)", () => {
334
+ Flow_GWT$ReventlessGwt.test("place → auto-ship → ship → view Shipped → confirmation fired", undefined, () => Confirm.thenOutbound(View.thenViewState(Ship.thenEvents(Ship.whenCommand(Auto.thenIssuesCommand(Auto.whenReacts(Place.thenEvents(Place.whenCommand(Flow_GWT$ReventlessGwt.start, {
335
+ TAG: "PlaceOrder",
336
+ orderId: "o1",
337
+ item: "book"
338
+ }), [{
339
+ TAG: "OrderPlaced",
340
+ orderId: "o1",
341
+ item: "book"
342
+ }])), {
343
+ TAG: "ShipOrder",
344
+ orderId: "o1"
345
+ }), {
346
+ TAG: "ShipOrder",
347
+ orderId: "o1"
348
+ }), [{
349
+ TAG: "OrderShipped",
350
+ orderId: "o1"
351
+ }]), "o1", {
352
+ orderId: "o1",
353
+ item: "book",
354
+ status: "Shipped"
355
+ }), [[
356
+ "o1",
357
+ {
358
+ orderId: "o1"
359
+ }
360
+ ]]));
361
+ Flow_GWT$ReventlessGwt.test("automation does not re-issue ShipOrder once the order is shipped", undefined, () => Auto.thenIssuesNoCommand(Auto.whenReacts(Ship.whenCommand(Place.whenCommand(Flow_GWT$ReventlessGwt.start, {
362
+ TAG: "PlaceOrder",
363
+ orderId: "o1",
364
+ item: "book"
365
+ }), {
366
+ TAG: "ShipOrder",
367
+ orderId: "o1"
368
+ }))));
369
+ Flow_GWT$ReventlessGwt.test("re-placing the same order is rejected", undefined, () => Place.thenError(Place.whenCommand(Place.whenCommand(Flow_GWT$ReventlessGwt.start, {
370
+ TAG: "PlaceOrder",
371
+ orderId: "o1",
372
+ item: "book"
373
+ }), {
374
+ TAG: "PlaceOrder",
375
+ orderId: "o1",
376
+ item: "book"
377
+ }), "AlreadyPlaced"));
378
+ Flow_GWT$ReventlessGwt.test("a second, different order is not blocked by the first (DCB tag isolation)", undefined, () => Place.thenEvent(Place.whenCommand(Place.thenEvent(Place.whenCommand(Flow_GWT$ReventlessGwt.start, {
379
+ TAG: "PlaceOrder",
380
+ orderId: "o1",
381
+ item: "book"
382
+ }), {
383
+ TAG: "OrderPlaced",
384
+ orderId: "o1",
385
+ item: "book"
386
+ }), {
387
+ TAG: "PlaceOrder",
388
+ orderId: "o2",
389
+ item: "pen"
390
+ }), {
391
+ TAG: "OrderPlaced",
392
+ orderId: "o2",
393
+ item: "pen"
394
+ }));
395
+ Flow_GWT$ReventlessGwt.test("shipping one order leaves a sibling order Placed", undefined, () => View.thenViewState(View.thenViewState(Ship.whenCommand(Place.whenCommand(Place.whenCommand(Flow_GWT$ReventlessGwt.start, {
396
+ TAG: "PlaceOrder",
397
+ orderId: "o1",
398
+ item: "book"
399
+ }), {
400
+ TAG: "PlaceOrder",
401
+ orderId: "o2",
402
+ item: "pen"
403
+ }), {
404
+ TAG: "ShipOrder",
405
+ orderId: "o1"
406
+ }), "o1", {
407
+ orderId: "o1",
408
+ item: "book",
409
+ status: "Shipped"
410
+ }), "o2", {
411
+ orderId: "o2",
412
+ item: "pen",
413
+ status: "Placed"
414
+ }));
415
+ });
416
+
417
+ export {
418
+ PlaceOrderSlice,
419
+ PlaceOrderBehavior,
420
+ AutoShipSlice,
421
+ ShipOrderSlice,
422
+ ShipOrderBehavior,
423
+ OrdersViewSlice,
424
+ OrdersViewProjection,
425
+ ConfirmSlice,
426
+ Place,
427
+ Auto,
428
+ Ship,
429
+ View,
430
+ Confirm,
431
+ }
432
+ /* Not a pure module */
@@ -0,0 +1,41 @@
1
+ // Unit test for FormatterVsCode.messagePayload — the failure payload the
2
+ // VS Code extension renders. Asserts the `kind` discriminator (the mismatch
3
+ // family) is present so a client can gate the apply-expected quick-fix.
4
+
5
+ open JestGlobals
6
+
7
+ let failingResult = (~mismatch): RunnerTypes.testResult => {
8
+ id: "t1",
9
+ name: "rejects when category already exists",
10
+ describePath: [],
11
+ status: RunnerTypes.Fail,
12
+ durationMs: 1.0,
13
+ location: None,
14
+ slice: None,
15
+ mismatch,
16
+ skipReason: None,
17
+ }
18
+
19
+ describe("FormatterVsCode.messagePayload", () => {
20
+ testPromise("includes the mismatch kind for an EventsMismatch", async () => {
21
+ let m = FormatterVsCode.messagePayload(
22
+ failingResult(~mismatch=Some(Outcome.EventsMismatch({expected: [], actual: []}))),
23
+ )
24
+ expect(m.kind)->toEqual(Some("EventsMismatch"))
25
+ })
26
+
27
+ testPromise("includes the mismatch kind for an ErrorMismatch", async () => {
28
+ let m = FormatterVsCode.messagePayload(
29
+ failingResult(
30
+ ~mismatch=Some(
31
+ Outcome.ErrorMismatch({
32
+ expected: JSON.String("CategoryAlreadyExists"),
33
+ actual: None,
34
+ actualEvents: [],
35
+ }),
36
+ ),
37
+ ),
38
+ )
39
+ expect(m.kind)->toEqual(Some("ErrorMismatch"))
40
+ })
41
+ })