@reventlessdev/reventless-gwt 1.0.0-alpha.100

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 (184) hide show
  1. package/CHANGELOG.md +916 -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 +569 -0
  10. package/src/Behavior_GWT.res.mjs +523 -0
  11. package/src/Bind.res +29 -0
  12. package/src/Bind.res.mjs +22 -0
  13. package/src/BuildClassifier.res +147 -0
  14. package/src/BuildClassifier.res.mjs +136 -0
  15. package/src/Cancellation.res +37 -0
  16. package/src/Cancellation.res.mjs +46 -0
  17. package/src/ChildProcess.res +102 -0
  18. package/src/ChildProcess.res.mjs +107 -0
  19. package/src/Cli.res +905 -0
  20. package/src/Cli.res.mjs +952 -0
  21. package/src/Collector.res +212 -0
  22. package/src/Collector.res.mjs +218 -0
  23. package/src/ComponentMeta.res +77 -0
  24. package/src/ComponentMeta.res.mjs +91 -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 +99 -0
  33. package/src/DomainDeadCode.res +98 -0
  34. package/src/DomainDeadCode.res.mjs +72 -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 +45 -0
  40. package/src/Filter.res.mjs +47 -0
  41. package/src/Flow_GWT.res +664 -0
  42. package/src/Flow_GWT.res.mjs +604 -0
  43. package/src/FormatterHuman.res +109 -0
  44. package/src/FormatterHuman.res.mjs +115 -0
  45. package/src/FormatterJson.res +264 -0
  46. package/src/FormatterJson.res.mjs +322 -0
  47. package/src/FormatterJunit.res +93 -0
  48. package/src/FormatterJunit.res.mjs +90 -0
  49. package/src/FormatterTap.res +100 -0
  50. package/src/FormatterTap.res.mjs +131 -0
  51. package/src/FormatterVsCode.res +352 -0
  52. package/src/FormatterVsCode.res.mjs +546 -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 +119 -0
  62. package/src/LocalHost.res.mjs +99 -0
  63. package/src/Mapping_GWT.res +474 -0
  64. package/src/Mapping_GWT.res.mjs +322 -0
  65. package/src/MismatchRender.res +72 -0
  66. package/src/MismatchRender.res.mjs +127 -0
  67. package/src/MultiSourceProjection_GWT.res +316 -0
  68. package/src/MultiSourceProjection_GWT.res.mjs +354 -0
  69. package/src/OutboundTranslation_GWT.res +238 -0
  70. package/src/OutboundTranslation_GWT.res.mjs +186 -0
  71. package/src/Outcome.res +97 -0
  72. package/src/Outcome.res.mjs +93 -0
  73. package/src/PackageScan.res +80 -0
  74. package/src/PackageScan.res.mjs +81 -0
  75. package/src/PlatformRunner.res +181 -0
  76. package/src/PlatformRunner.res.mjs +176 -0
  77. package/src/PlatformScan.res +142 -0
  78. package/src/PlatformScan.res.mjs +132 -0
  79. package/src/ProcessManager.res +135 -0
  80. package/src/ProcessManager.res.mjs +119 -0
  81. package/src/Projection_GWT.res +312 -0
  82. package/src/Projection_GWT.res.mjs +332 -0
  83. package/src/Query_GWT.res +379 -0
  84. package/src/Query_GWT.res.mjs +367 -0
  85. package/src/RenderRescript.res +125 -0
  86. package/src/RenderRescript.res.mjs +141 -0
  87. package/src/RunWorker.res +24 -0
  88. package/src/RunWorker.res.mjs +16 -0
  89. package/src/RunnerTypes.res +68 -0
  90. package/src/RunnerTypes.res.mjs +60 -0
  91. package/src/SideEffect_GWT.res +157 -0
  92. package/src/SideEffect_GWT.res.mjs +113 -0
  93. package/src/StateChange/ExternalAddCategorySlice.res +25 -0
  94. package/src/StateChange/ExternalAddCategorySlice.res.mjs +34 -0
  95. package/src/StateChange/ExternalAddCategorySlice_Behavior.res +19 -0
  96. package/src/StateChange/ExternalAddCategorySlice_Behavior.res.mjs +46 -0
  97. package/src/StateChange/WithFixtures.res +22 -0
  98. package/src/StateChange/WithFixtures.res.mjs +31 -0
  99. package/src/StateChange/WithFixtures_Behavior.res +17 -0
  100. package/src/StateChange/WithFixtures_Behavior.res.mjs +37 -0
  101. package/src/StateChange/WithManualOpen.res +23 -0
  102. package/src/StateChange/WithManualOpen.res.mjs +31 -0
  103. package/src/StateChange/WithManualOpen_Behavior.res +17 -0
  104. package/src/StateChange/WithManualOpen_Behavior.res.mjs +37 -0
  105. package/src/StubRuntime.res +54 -0
  106. package/src/StubRuntime.res.mjs +55 -0
  107. package/src/TestFixtures.res +16 -0
  108. package/src/TestFixtures.res.mjs +34 -0
  109. package/src/Watch.res +108 -0
  110. package/src/Watch.res.mjs +85 -0
  111. package/src/WatcherProbe.res +56 -0
  112. package/src/WatcherProbe.res.mjs +59 -0
  113. package/src/Worker.res +24 -0
  114. package/src/Worker.res.mjs +9 -0
  115. package/tests/AutomationGwtTest.res +71 -0
  116. package/tests/AutomationGwtTest.res.mjs +189 -0
  117. package/tests/BuildClassifierTest.res +133 -0
  118. package/tests/BuildClassifierTest.res.mjs +176 -0
  119. package/tests/CliRunEntryTest.res +57 -0
  120. package/tests/CliRunEntryTest.res.mjs +65 -0
  121. package/tests/CliWatchScopeTest.res +62 -0
  122. package/tests/CliWatchScopeTest.res.mjs +95 -0
  123. package/tests/ComponentMetaTest.res +67 -0
  124. package/tests/ComponentMetaTest.res.mjs +71 -0
  125. package/tests/DelegateGwtTest.res +487 -0
  126. package/tests/DelegateGwtTest.res.mjs +891 -0
  127. package/tests/DiscoveryTest.res +42 -0
  128. package/tests/DiscoveryTest.res.mjs +43 -0
  129. package/tests/DomainDeadCodeTest.res +119 -0
  130. package/tests/DomainDeadCodeTest.res.mjs +158 -0
  131. package/tests/DomainGraphTest.res +448 -0
  132. package/tests/DomainGraphTest.res.mjs +505 -0
  133. package/tests/FlowAggregateGwtTest.res +171 -0
  134. package/tests/FlowAggregateGwtTest.res.mjs +273 -0
  135. package/tests/FlowCrossPluginGwtTest.res +340 -0
  136. package/tests/FlowCrossPluginGwtTest.res.mjs +798 -0
  137. package/tests/FlowGwtTest.res +222 -0
  138. package/tests/FlowGwtTest.res.mjs +433 -0
  139. package/tests/FormatterGoldenTest.res +125 -0
  140. package/tests/FormatterGoldenTest.res.mjs +162 -0
  141. package/tests/FormatterVsCodeMessageTest.res +41 -0
  142. package/tests/FormatterVsCodeMessageTest.res.mjs +42 -0
  143. package/tests/InboundTranslationGwtTest.res +34 -0
  144. package/tests/InboundTranslationGwtTest.res.mjs +99 -0
  145. package/tests/LocalHostIntegration.res +70 -0
  146. package/tests/LocalHostIntegration.res.mjs +64 -0
  147. package/tests/LocalHostTest.res +71 -0
  148. package/tests/LocalHostTest.res.mjs +63 -0
  149. package/tests/MappingGwtTest.res +350 -0
  150. package/tests/MappingGwtTest.res.mjs +596 -0
  151. package/tests/OutboundTranslationGwtTest.res +59 -0
  152. package/tests/OutboundTranslationGwtTest.res.mjs +139 -0
  153. package/tests/PlatformRunnerTest.res +66 -0
  154. package/tests/PlatformRunnerTest.res.mjs +85 -0
  155. package/tests/PlatformScanTest.res +61 -0
  156. package/tests/PlatformScanTest.res.mjs +56 -0
  157. package/tests/QueryGwtTest.res +161 -0
  158. package/tests/QueryGwtTest.res.mjs +314 -0
  159. package/tests/QueryResolverGwtTest.res +71 -0
  160. package/tests/QueryResolverGwtTest.res.mjs +136 -0
  161. package/tests/RunnerUnitTest.res +219 -0
  162. package/tests/RunnerUnitTest.res.mjs +244 -0
  163. package/tests/SideEffect/FakeOrderNotification.res +23 -0
  164. package/tests/SideEffect/FakeOrderNotification.res.mjs +36 -0
  165. package/tests/SideEffect/FakeOrderNotificationGwtTest.res +35 -0
  166. package/tests/SideEffect/FakeOrderNotificationGwtTest.res.mjs +73 -0
  167. package/tests/SideEffect/MockEmail.res +18 -0
  168. package/tests/SideEffect/MockEmail.res.mjs +47 -0
  169. package/tests/StateChange/ExternalAddCategorySlice_GWT.res +27 -0
  170. package/tests/StateChange/ExternalAddCategorySlice_GWT.res.mjs +70 -0
  171. package/tests/StateChange/WithFixtures_Fixtures.res +9 -0
  172. package/tests/StateChange/WithFixtures_Fixtures.res.mjs +20 -0
  173. package/tests/StateChange/WithFixtures_GWT.res +23 -0
  174. package/tests/StateChange/WithFixtures_GWT.res.mjs +56 -0
  175. package/tests/StateChange/WithManualOpen_Fixtures.res +7 -0
  176. package/tests/StateChange/WithManualOpen_Fixtures.res.mjs +20 -0
  177. package/tests/StateChange/WithManualOpen_GWT.res +17 -0
  178. package/tests/StateChange/WithManualOpen_GWT.res.mjs +56 -0
  179. package/tests/StateChangeSliceGwtTest.res +160 -0
  180. package/tests/StateChangeSliceGwtTest.res.mjs +280 -0
  181. package/tests/StateViewSliceGwtTest.res +64 -0
  182. package/tests/StateViewSliceGwtTest.res.mjs +161 -0
  183. package/tests/WatchDebounceTest.res +106 -0
  184. package/tests/WatchDebounceTest.res.mjs +128 -0
@@ -0,0 +1,604 @@
1
+ // Generated by ReScript, PLEASE EDIT WITH CARE
2
+
3
+ import * as S from "sury/src/S.res.mjs";
4
+ import * as Stdlib_Array from "@rescript/runtime/lib/es6/Stdlib_Array.js";
5
+ import * as Stdlib_Option from "@rescript/runtime/lib/es6/Stdlib_Option.js";
6
+ import * as Primitive_object from "@rescript/runtime/lib/es6/Primitive_object.js";
7
+ import * as Primitive_string from "@rescript/runtime/lib/es6/Primitive_string.js";
8
+ import * as DcbTag$Reventless from "@reventlessdev/reventless-spec/src/components/DcbTag.res.mjs";
9
+ import * as Message$Reventless from "@reventlessdev/reventless-spec/src/types/Message.res.mjs";
10
+ import * as DcbDecode$Reventless from "@reventlessdev/reventless-spec/src/components/DcbDecode.res.mjs";
11
+ import * as Outcome$ReventlessGwt from "./Outcome.res.mjs";
12
+ import * as JestBind$ReventlessGwt from "./JestBind.res.mjs";
13
+ import * as Message$ReventlessCore from "@reventlessdev/reventless-core/src/Message.res.mjs";
14
+ import * as StubRuntime$ReventlessGwt from "./StubRuntime.res.mjs";
15
+ import * as DcbScopeInference$Reventless from "@reventlessdev/reventless-spec/src/components/DcbScopeInference.res.mjs";
16
+ import * as Projection_GWT$ReventlessGwt from "./Projection_GWT.res.mjs";
17
+
18
+ S.enableJson();
19
+
20
+ let emptyState_log = [];
21
+
22
+ let emptyState_lastEvents = [];
23
+
24
+ let emptyState_lastCommands = [];
25
+
26
+ let emptyState_lastPublic = [];
27
+
28
+ let emptyState = {
29
+ log: emptyState_log,
30
+ outcome: Outcome$ReventlessGwt.pass,
31
+ lastEvents: emptyState_lastEvents,
32
+ lastError: undefined,
33
+ lastCommands: emptyState_lastCommands,
34
+ lastPublic: emptyState_lastPublic,
35
+ lastAggregateId: undefined
36
+ };
37
+
38
+ let start = Promise.resolve(emptyState);
39
+
40
+ function recordOutcome(s, o) {
41
+ let match = s.outcome;
42
+ if (match.TAG === "Ok") {
43
+ return {
44
+ log: s.log,
45
+ outcome: o,
46
+ lastEvents: s.lastEvents,
47
+ lastError: s.lastError,
48
+ lastCommands: s.lastCommands,
49
+ lastPublic: s.lastPublic,
50
+ lastAggregateId: s.lastAggregateId
51
+ };
52
+ } else {
53
+ return s;
54
+ }
55
+ }
56
+
57
+ function entryMatchesQuery(entry, query) {
58
+ if (query.length === 0) {
59
+ return true;
60
+ } else {
61
+ return query.some(qi => {
62
+ let types = qi.eventTypes;
63
+ let typeMatch = types !== undefined ? types.includes(entry.eventType) : true;
64
+ let tags = qi.tags;
65
+ let tagMatch = tags !== undefined ? tags.every(tag => entry.tags.some(et => {
66
+ if (et.key === tag.key) {
67
+ return et.value === tag.value;
68
+ } else {
69
+ return false;
70
+ }
71
+ })) : true;
72
+ if (typeMatch) {
73
+ return tagMatch;
74
+ } else {
75
+ return false;
76
+ }
77
+ });
78
+ }
79
+ }
80
+
81
+ function appendEvents(log, events, schema) {
82
+ return log.concat(events.map(ev => {
83
+ let json = Message$ReventlessCore.encode(ev, schema);
84
+ return {
85
+ eventType: Message$Reventless.variantNameOfJson(json),
86
+ tags: DcbTag$Reventless.extractTagsExpanded(schema, ev),
87
+ json: json,
88
+ aggregateId: undefined
89
+ };
90
+ }));
91
+ }
92
+
93
+ function appendAggregateEvents(log, id, events, schema) {
94
+ return log.concat(events.map(ev => {
95
+ let json = Message$ReventlessCore.encode(ev, schema);
96
+ return {
97
+ eventType: Message$Reventless.variantNameOfJson(json),
98
+ tags: DcbTag$Reventless.extractTagsExpanded(schema, ev),
99
+ json: json,
100
+ aggregateId: id
101
+ };
102
+ }));
103
+ }
104
+
105
+ function decodeMatching(log, decoder, query) {
106
+ return Stdlib_Array.filterMap(log, entry => {
107
+ if (!entryMatchesQuery(entry, query)) {
108
+ return;
109
+ }
110
+ let d = entry.json;
111
+ let data;
112
+ data = typeof d === "object" && d !== null && !Array.isArray(d) ? d : ({});
113
+ return decoder.decode(entry.eventType, data);
114
+ });
115
+ }
116
+
117
+ function decodeAggregateMatching(log, id, decoder) {
118
+ return Stdlib_Array.filterMap(log, entry => {
119
+ let eid = entry.aggregateId;
120
+ if (eid === undefined) {
121
+ return;
122
+ }
123
+ if (eid !== id) {
124
+ return;
125
+ }
126
+ let d = entry.json;
127
+ let data;
128
+ data = typeof d === "object" && d !== null && !Array.isArray(d) ? d : ({});
129
+ return decoder.decode(entry.eventType, data);
130
+ });
131
+ }
132
+
133
+ function test(name, timeout, body) {
134
+ JestBind$ReventlessGwt.testPromise("Flow", name, timeout, async () => (await body()).outcome);
135
+ }
136
+
137
+ function CommandStep(Spec) {
138
+ return Behavior => {
139
+ let consumedDecoder = DcbDecode$Reventless.makeDecoder(Spec.consumedEventSchema);
140
+ let consumedEventTypes = consumedDecoder.eventTypes;
141
+ let givenEvents = async (flowP, events) => {
142
+ let s = await flowP;
143
+ return {
144
+ log: appendEvents(s.log, events, Spec.eventSchema),
145
+ outcome: s.outcome,
146
+ lastEvents: s.lastEvents,
147
+ lastError: s.lastError,
148
+ lastCommands: s.lastCommands,
149
+ lastPublic: s.lastPublic,
150
+ lastAggregateId: s.lastAggregateId
151
+ };
152
+ };
153
+ let scopeShape = DcbTag$Reventless.sliceShapeFromSchemas("", Spec.commandSchema, Spec.consumedEventSchema, Spec.eventSchema);
154
+ let set = new Set();
155
+ DcbTag$Reventless.extractCrossPartitionTagKeys(Spec.eventSchema).forEach(k => {
156
+ set.add(k);
157
+ });
158
+ DcbScopeInference$Reventless.crossPartitionForSlice(scopeShape).forEach(k => {
159
+ set.add(k);
160
+ });
161
+ let crossPartitionTagKeys = Array.from(set.values()).toSorted(Primitive_string.compare);
162
+ let tagKeysByEventType = DcbScopeInference$Reventless.infer([scopeShape]).tagKeysByEventType;
163
+ let whenCommand = async (flowP, command) => {
164
+ let s = await flowP;
165
+ let query = DcbTag$Reventless.buildQueryFromCommand(consumedEventTypes, Spec.commandSchema, command, tagKeysByEventType, crossPartitionTagKeys);
166
+ let history = decodeMatching(s.log, consumedDecoder, query);
167
+ let state = Stdlib_Array.reduce(history, Behavior.initialState, Behavior.evolve);
168
+ let events = Behavior.decide(state, command);
169
+ if (events.TAG !== "Ok") {
170
+ return {
171
+ log: s.log,
172
+ outcome: s.outcome,
173
+ lastEvents: [],
174
+ lastError: Message$ReventlessCore.encode(events._0, Spec.errorSchema),
175
+ lastCommands: s.lastCommands,
176
+ lastPublic: s.lastPublic,
177
+ lastAggregateId: undefined
178
+ };
179
+ }
180
+ let events$1 = events._0;
181
+ return {
182
+ log: appendEvents(s.log, events$1, Spec.eventSchema),
183
+ outcome: s.outcome,
184
+ lastEvents: events$1.map(e => Message$ReventlessCore.encode(e, Spec.eventSchema)),
185
+ lastError: undefined,
186
+ lastCommands: s.lastCommands,
187
+ lastPublic: s.lastPublic,
188
+ lastAggregateId: undefined
189
+ };
190
+ };
191
+ let thenEvents = async (flowP, expected) => {
192
+ let s = await flowP;
193
+ let expectedJson = expected.map(e => Message$ReventlessCore.encode(e, Spec.eventSchema));
194
+ let err = s.lastError;
195
+ let o = err !== undefined ? Outcome$ReventlessGwt.fail({
196
+ TAG: "ErrorMismatch",
197
+ expected: null,
198
+ actual: err,
199
+ actualEvents: s.lastEvents
200
+ }) : (
201
+ Primitive_object.equal(s.lastEvents, expectedJson) ? Outcome$ReventlessGwt.pass : Outcome$ReventlessGwt.fail({
202
+ TAG: "EventsMismatch",
203
+ expected: expectedJson,
204
+ actual: s.lastEvents
205
+ })
206
+ );
207
+ return recordOutcome(s, o);
208
+ };
209
+ let thenEvent = (flowP, event) => thenEvents(flowP, [event]);
210
+ let thenError = async (flowP, expected) => {
211
+ let s = await flowP;
212
+ let expJson = Message$ReventlessCore.encode(expected, Spec.errorSchema);
213
+ let actual = s.lastError;
214
+ let o = actual !== undefined ? (
215
+ Primitive_object.equal(actual, expJson) ? Outcome$ReventlessGwt.pass : Outcome$ReventlessGwt.fail({
216
+ TAG: "ErrorMismatch",
217
+ expected: expJson,
218
+ actual: actual,
219
+ actualEvents: s.lastEvents
220
+ })
221
+ ) : Outcome$ReventlessGwt.fail({
222
+ TAG: "ErrorMismatch",
223
+ expected: expJson,
224
+ actual: undefined,
225
+ actualEvents: s.lastEvents
226
+ });
227
+ return recordOutcome(s, o);
228
+ };
229
+ return {
230
+ consumedDecoder: consumedDecoder,
231
+ consumedEventTypes: consumedEventTypes,
232
+ givenEvents: givenEvents,
233
+ scopeShape: scopeShape,
234
+ crossPartitionTagKeys: crossPartitionTagKeys,
235
+ tagKeysByEventType: tagKeysByEventType,
236
+ whenCommand: whenCommand,
237
+ thenEvents: thenEvents,
238
+ thenEvent: thenEvent,
239
+ thenError: thenError
240
+ };
241
+ };
242
+ }
243
+
244
+ function AggregateCommandStep(Spec) {
245
+ return Behavior => {
246
+ let aggregateDecoder = DcbDecode$Reventless.makeDecoder(Spec.eventSchema);
247
+ let givenEvents = async (flowP, id, events) => {
248
+ let s = await flowP;
249
+ return {
250
+ log: appendAggregateEvents(s.log, id, events, Spec.eventSchema),
251
+ outcome: s.outcome,
252
+ lastEvents: s.lastEvents,
253
+ lastError: s.lastError,
254
+ lastCommands: s.lastCommands,
255
+ lastPublic: s.lastPublic,
256
+ lastAggregateId: s.lastAggregateId
257
+ };
258
+ };
259
+ let whenCommand = async (flowP, id, command) => {
260
+ let s = await flowP;
261
+ let history = decodeAggregateMatching(s.log, id, aggregateDecoder);
262
+ let state = Stdlib_Array.reduce(history, Behavior.initialState, Behavior.evolve);
263
+ let events = Behavior.decide(state, command);
264
+ if (events.TAG !== "Ok") {
265
+ return {
266
+ log: s.log,
267
+ outcome: s.outcome,
268
+ lastEvents: [],
269
+ lastError: Message$ReventlessCore.encode(events._0, Spec.errorSchema),
270
+ lastCommands: s.lastCommands,
271
+ lastPublic: s.lastPublic,
272
+ lastAggregateId: id
273
+ };
274
+ }
275
+ let events$1 = events._0;
276
+ return {
277
+ log: appendAggregateEvents(s.log, id, events$1, Spec.eventSchema),
278
+ outcome: s.outcome,
279
+ lastEvents: events$1.map(e => Message$ReventlessCore.encode(e, Spec.eventSchema)),
280
+ lastError: undefined,
281
+ lastCommands: s.lastCommands,
282
+ lastPublic: s.lastPublic,
283
+ lastAggregateId: id
284
+ };
285
+ };
286
+ let thenEvents = async (flowP, expected) => {
287
+ let s = await flowP;
288
+ let expectedJson = expected.map(e => Message$ReventlessCore.encode(e, Spec.eventSchema));
289
+ let err = s.lastError;
290
+ let o = err !== undefined ? Outcome$ReventlessGwt.fail({
291
+ TAG: "ErrorMismatch",
292
+ expected: null,
293
+ actual: err,
294
+ actualEvents: s.lastEvents
295
+ }) : (
296
+ Primitive_object.equal(s.lastEvents, expectedJson) ? Outcome$ReventlessGwt.pass : Outcome$ReventlessGwt.fail({
297
+ TAG: "EventsMismatch",
298
+ expected: expectedJson,
299
+ actual: s.lastEvents
300
+ })
301
+ );
302
+ return recordOutcome(s, o);
303
+ };
304
+ let thenEvent = (flowP, event) => thenEvents(flowP, [event]);
305
+ let thenNoEvent = async flowP => {
306
+ let s = await flowP;
307
+ let err = s.lastError;
308
+ let o = err !== undefined ? Outcome$ReventlessGwt.fail({
309
+ TAG: "ErrorMismatch",
310
+ expected: null,
311
+ actual: err,
312
+ actualEvents: s.lastEvents
313
+ }) : (
314
+ s.lastEvents.length === 0 ? Outcome$ReventlessGwt.pass : Outcome$ReventlessGwt.fail({
315
+ TAG: "NoEventExpected",
316
+ actual: s.lastEvents
317
+ })
318
+ );
319
+ return recordOutcome(s, o);
320
+ };
321
+ let thenError = async (flowP, expected) => {
322
+ let s = await flowP;
323
+ let expJson = Message$ReventlessCore.encode(expected, Spec.errorSchema);
324
+ let actual = s.lastError;
325
+ let o = actual !== undefined ? (
326
+ Primitive_object.equal(actual, expJson) ? Outcome$ReventlessGwt.pass : Outcome$ReventlessGwt.fail({
327
+ TAG: "ErrorMismatch",
328
+ expected: expJson,
329
+ actual: actual,
330
+ actualEvents: s.lastEvents
331
+ })
332
+ ) : Outcome$ReventlessGwt.fail({
333
+ TAG: "ErrorMismatch",
334
+ expected: expJson,
335
+ actual: undefined,
336
+ actualEvents: s.lastEvents
337
+ });
338
+ return recordOutcome(s, o);
339
+ };
340
+ return {
341
+ aggregateDecoder: aggregateDecoder,
342
+ givenEvents: givenEvents,
343
+ whenCommand: whenCommand,
344
+ thenEvents: thenEvents,
345
+ thenEvent: thenEvent,
346
+ thenNoEvent: thenNoEvent,
347
+ thenError: thenError
348
+ };
349
+ };
350
+ }
351
+
352
+ function AutomationStep(Spec) {
353
+ let consumedDecoder = DcbDecode$Reventless.makeDecoder(Spec.consumedEventSchema);
354
+ let whenReacts = async flowP => {
355
+ let s = await flowP;
356
+ let events = decodeMatching(s.log, consumedDecoder, []);
357
+ let collected = events.map(e => Spec.collect(e)).flat();
358
+ let resolvedIds = Stdlib_Array.filterMap(events, e => Spec.resolve(e));
359
+ let pending = collected.filter(param => !resolvedIds.includes(param[0]));
360
+ let commands = Stdlib_Array.filterMap(pending, param => Spec.process(param[0], param[1]));
361
+ return {
362
+ log: s.log,
363
+ outcome: s.outcome,
364
+ lastEvents: s.lastEvents,
365
+ lastError: s.lastError,
366
+ lastCommands: commands.map(param => Message$ReventlessCore.encode(param[1], Spec.commandSchema)),
367
+ lastPublic: s.lastPublic,
368
+ lastAggregateId: s.lastAggregateId
369
+ };
370
+ };
371
+ let thenIssuesCommands = async (flowP, expected) => {
372
+ let s = await flowP;
373
+ let expJson = expected.map(c => Message$ReventlessCore.encode(c, Spec.commandSchema));
374
+ let o = Primitive_object.equal(s.lastCommands, expJson) ? Outcome$ReventlessGwt.pass : Outcome$ReventlessGwt.fail({
375
+ TAG: "EventsMismatch",
376
+ expected: expJson,
377
+ actual: s.lastCommands
378
+ });
379
+ return recordOutcome(s, o);
380
+ };
381
+ let thenIssuesCommand = (flowP, command) => thenIssuesCommands(flowP, [command]);
382
+ let thenIssuesNoCommand = flowP => thenIssuesCommands(flowP, []);
383
+ return {
384
+ consumedDecoder: consumedDecoder,
385
+ whenReacts: whenReacts,
386
+ thenIssuesCommands: thenIssuesCommands,
387
+ thenIssuesCommand: thenIssuesCommand,
388
+ thenIssuesNoCommand: thenIssuesNoCommand
389
+ };
390
+ }
391
+
392
+ function ViewStep(Spec) {
393
+ return Projection => {
394
+ let P = Projection_GWT$ReventlessGwt.Make(Spec)(Projection);
395
+ let consumedDecoder = DcbDecode$Reventless.makeDecoder(Spec.consumedEventSchema);
396
+ let encState = st => Message$ReventlessCore.encode(st, Spec.stateSchema);
397
+ let thenViewStates = async (flowP, id, expected) => {
398
+ let s = await flowP;
399
+ let events = decodeMatching(s.log, consumedDecoder, []);
400
+ let store = await P.givenEvents(events);
401
+ let actual = Stdlib_Option.getOr(store[id], []).map(encState);
402
+ let expectedJson = expected.map(encState);
403
+ let o = Primitive_object.equal(actual, expectedJson) ? Outcome$ReventlessGwt.pass : Outcome$ReventlessGwt.fail({
404
+ TAG: "StateMismatch",
405
+ key: id,
406
+ expected: expectedJson,
407
+ actual: actual
408
+ });
409
+ return recordOutcome(s, o);
410
+ };
411
+ let thenViewState = (flowP, id, state) => thenViewStates(flowP, id, [state]);
412
+ return {
413
+ P: P,
414
+ consumedDecoder: consumedDecoder,
415
+ encState: encState,
416
+ thenViewStates: thenViewStates,
417
+ thenViewState: thenViewState
418
+ };
419
+ };
420
+ }
421
+
422
+ function OutboundStep(Spec) {
423
+ let consumedDecoder = DcbDecode$Reventless.makeDecoder(Spec.consumedEventSchema);
424
+ let encItems = arr => arr.map(param => [
425
+ param[0],
426
+ Message$ReventlessCore.encode(param[1], Spec.outboundItemSchema)
427
+ ]);
428
+ let thenOutbound = async (flowP, expected) => {
429
+ let s = await flowP;
430
+ let events = decodeMatching(s.log, consumedDecoder, []);
431
+ let collected = events.map(e => Spec.collect(e)).flat();
432
+ let actual = encItems(collected);
433
+ let expectedJson = encItems(expected);
434
+ let o = Primitive_object.equal(actual, expectedJson) ? Outcome$ReventlessGwt.pass : Outcome$ReventlessGwt.fail({
435
+ TAG: "TodoMismatch",
436
+ expected: expectedJson,
437
+ actual: actual
438
+ });
439
+ return recordOutcome(s, o);
440
+ };
441
+ let thenOutboundNothing = flowP => thenOutbound(flowP, []);
442
+ return {
443
+ consumedDecoder: consumedDecoder,
444
+ encItems: encItems,
445
+ thenOutbound: thenOutbound,
446
+ thenOutboundNothing: thenOutboundNothing
447
+ };
448
+ }
449
+
450
+ function sortJson(arr) {
451
+ return arr.toSorted((a, b) => Primitive_string.compare(JSON.stringify(a), JSON.stringify(b)));
452
+ }
453
+
454
+ function ExtensionPointStep(M) {
455
+ let delegateDecoder = DcbDecode$Reventless.makeDecoder(M.Delegate.eventSchema);
456
+ let runMapping = async (sourceId, events) => {
457
+ let f = M.mapOutgoingEvent;
458
+ if (f === undefined) {
459
+ return [];
460
+ }
461
+ let actions = events.map(ev => f(sourceId, ev, StubRuntime$ReventlessGwt.meta, StubRuntime$ReventlessGwt.queryEngine)).flat();
462
+ return (await Promise.all(actions.map(async action => {
463
+ switch (action.TAG) {
464
+ case "PublishEvent" :
465
+ return [action._1];
466
+ case "PublishEventAsync" :
467
+ let match = await action._0;
468
+ return [match[1]];
469
+ case "HandleDirective" :
470
+ return [];
471
+ }
472
+ }))).flat();
473
+ };
474
+ let whenPublishedThrough = async flowP => {
475
+ let s = await flowP;
476
+ let delegateEvents = Stdlib_Array.filterMap(s.lastEvents, json => {
477
+ let data;
478
+ data = typeof json === "object" && json !== null && !Array.isArray(json) ? json : ({});
479
+ return delegateDecoder.decode(Message$Reventless.variantNameOfJson(json), data);
480
+ });
481
+ let sourceId = Stdlib_Option.getOr(s.lastAggregateId, "gwt-id");
482
+ let publicEvents = await runMapping(sourceId, delegateEvents);
483
+ return {
484
+ log: appendEvents(s.log, publicEvents, M.ExtensionPoint.eventSchema),
485
+ outcome: s.outcome,
486
+ lastEvents: s.lastEvents,
487
+ lastError: s.lastError,
488
+ lastCommands: s.lastCommands,
489
+ lastPublic: publicEvents.map(e => Message$ReventlessCore.encode(e, M.ExtensionPoint.eventSchema)),
490
+ lastAggregateId: s.lastAggregateId
491
+ };
492
+ };
493
+ let thenPublicEvents = async (flowP, expected) => {
494
+ let s = await flowP;
495
+ let expJson = expected.map(e => Message$ReventlessCore.encode(e, M.ExtensionPoint.eventSchema));
496
+ let o = Primitive_object.equal(sortJson(s.lastPublic), sortJson(expJson)) ? Outcome$ReventlessGwt.pass : Outcome$ReventlessGwt.fail({
497
+ TAG: "PublishedActionsMismatch",
498
+ expected: expJson,
499
+ actual: s.lastPublic
500
+ });
501
+ return recordOutcome(s, o);
502
+ };
503
+ let thenPublicEvent = (flowP, event) => thenPublicEvents(flowP, [event]);
504
+ return {
505
+ delegateDecoder: delegateDecoder,
506
+ runMapping: runMapping,
507
+ whenPublishedThrough: whenPublishedThrough,
508
+ thenPublicEvents: thenPublicEvents,
509
+ thenPublicEvent: thenPublicEvent
510
+ };
511
+ }
512
+
513
+ function ExtensionStep(M) {
514
+ let epDecoder = DcbDecode$Reventless.makeDecoder(M.ExtensionPoint.eventSchema);
515
+ let encCmd = c => Message$ReventlessCore.encode(c, M.Delegate.commandSchema);
516
+ let whenExtensionReacts = async flowP => {
517
+ let s = await flowP;
518
+ let epEvents = Stdlib_Array.filterMap(s.lastPublic, json => {
519
+ let data;
520
+ data = typeof json === "object" && json !== null && !Array.isArray(json) ? json : ({});
521
+ return epDecoder.decode(Message$Reventless.variantNameOfJson(json), data);
522
+ });
523
+ let actions = epEvents.map(ev => M.mapIncomingEvent("gwt-id", ev, StubRuntime$ReventlessGwt.meta, StubRuntime$ReventlessGwt.pluginDefinition, StubRuntime$ReventlessGwt.queryEngine)).flat();
524
+ let nested = await Promise.all(actions.map(async action => {
525
+ switch (action.TAG) {
526
+ case "PublishAggregateCommand" :
527
+ return [Message$ReventlessCore.encode(action._1, M.Delegate.commandSchema)];
528
+ case "PublishAggregateCommandAsync" :
529
+ let match = await action._0;
530
+ return [Message$ReventlessCore.encode(match[1], M.Delegate.commandSchema)];
531
+ case "PublishAggregateCommandsAsync" :
532
+ return (await action._0).map(param => Message$ReventlessCore.encode(param[1], M.Delegate.commandSchema));
533
+ case "PublishStateChangeSliceCommand" :
534
+ return [Message$ReventlessCore.encode(action._0, M.Delegate.commandSchema)];
535
+ case "PublishStateChangeSliceCommandAsync" :
536
+ let cmd = await action._0;
537
+ return [Message$ReventlessCore.encode(cmd, M.Delegate.commandSchema)];
538
+ case "PublishStateChangeSliceCommandsAsync" :
539
+ return (await action._0).map(encCmd);
540
+ default:
541
+ return [];
542
+ }
543
+ }));
544
+ return {
545
+ log: s.log,
546
+ outcome: s.outcome,
547
+ lastEvents: s.lastEvents,
548
+ lastError: s.lastError,
549
+ lastCommands: nested.flat(),
550
+ lastPublic: s.lastPublic,
551
+ lastAggregateId: s.lastAggregateId
552
+ };
553
+ };
554
+ let thenIssuesCommands = async (flowP, expected) => {
555
+ let s = await flowP;
556
+ let expJson = expected.map(encCmd);
557
+ let o = Primitive_object.equal(sortJson(s.lastCommands), sortJson(expJson)) ? Outcome$ReventlessGwt.pass : Outcome$ReventlessGwt.fail({
558
+ TAG: "PublishedActionsMismatch",
559
+ expected: expJson,
560
+ actual: s.lastCommands
561
+ });
562
+ return recordOutcome(s, o);
563
+ };
564
+ let thenIssuesCommand = (flowP, command) => thenIssuesCommands(flowP, [command]);
565
+ let thenIssuesNoCommand = flowP => thenIssuesCommands(flowP, []);
566
+ return {
567
+ epDecoder: epDecoder,
568
+ encCmd: encCmd,
569
+ whenExtensionReacts: whenExtensionReacts,
570
+ thenIssuesCommands: thenIssuesCommands,
571
+ thenIssuesCommand: thenIssuesCommand,
572
+ thenIssuesNoCommand: thenIssuesNoCommand
573
+ };
574
+ }
575
+
576
+ let EPMapping;
577
+
578
+ let ExtMapping;
579
+
580
+ let describe = JestBind$ReventlessGwt.describe;
581
+
582
+ export {
583
+ EPMapping,
584
+ ExtMapping,
585
+ emptyState,
586
+ start,
587
+ recordOutcome,
588
+ entryMatchesQuery,
589
+ appendEvents,
590
+ appendAggregateEvents,
591
+ decodeMatching,
592
+ decodeAggregateMatching,
593
+ describe,
594
+ test,
595
+ CommandStep,
596
+ AggregateCommandStep,
597
+ AutomationStep,
598
+ ViewStep,
599
+ OutboundStep,
600
+ sortJson,
601
+ ExtensionPointStep,
602
+ ExtensionStep,
603
+ }
604
+ /* Not a pure module */
@@ -0,0 +1,109 @@
1
+ // Terminal-coloured human formatter. Shipped as the default output for
2
+ // `reventless-gwt run`. Uses picocolors for ANSI colours — it is a tiny
3
+ // zero-dependency helper that transparently disables colour when stdout
4
+ // is not a TTY.
5
+
6
+ type colour = string => string
7
+ type picocolors = {
8
+ red: colour,
9
+ green: colour,
10
+ yellow: colour,
11
+ cyan: colour,
12
+ gray: colour,
13
+ bold: colour,
14
+ dim: colour,
15
+ }
16
+
17
+ @module("picocolors") external pc: picocolors = "default"
18
+
19
+ @val external processStdout: {"write": string => unit} = "process.stdout"
20
+ @val external processCwd: unit => string = "process.cwd"
21
+ @module("node:path") external pathBasename: string => string = "basename"
22
+ @module("node:path") external pathRelative: (string, string) => string = "relative"
23
+
24
+ let write = (s: string) => processStdout["write"](s)
25
+ let writeLine = (s: string) => write(s ++ "\n")
26
+
27
+ let formatFilePath = (abs: string) => {
28
+ let base = pathBasename(abs)
29
+ let name = if String.endsWith(base, ".res.mjs") {
30
+ String.slice(base, ~start=0, ~end=String.length(base) - 8)
31
+ } else {
32
+ base
33
+ }
34
+ let rel = pathRelative(processCwd(), abs)
35
+ `${name} - ${rel}`
36
+ }
37
+
38
+ let formatLocation = (loc: option<Collector.location>) =>
39
+ switch loc {
40
+ | None => ""
41
+ | Some(l) => `${l.file}:${Int.toString(l.line)}`
42
+ }
43
+
44
+ // Frames one normalized field as a terminal line. Labels are padded so values
45
+ // align at column 12 (`key:`, `expected:`, `actual:`); `error:` is its own
46
+ // shorter form and the `Throw` stack is dumped raw beneath it.
47
+ let renderField = (f: MismatchRender.field) =>
48
+ switch f {
49
+ | Expected(v) => ` expected: ${v}`
50
+ | Actual(v) => ` actual: ${v}`
51
+ | Key(k) => ` key: "${k}"`
52
+ | ExpectedNoEvents => " expected no events"
53
+ | Error(e) => ` error: ${e}`
54
+ | Stack(s) => s
55
+ }
56
+
57
+ let renderMismatch = (m: Outcome.mismatch) =>
58
+ MismatchRender.normalize(m).fields->Array.map(renderField)->Array.join("\n")
59
+
60
+ let emitTest = (t: RunnerTypes.testResult) => {
61
+ let path = t.describePath->Array.join(" > ")
62
+ let full = path == "" ? t.name : `${path} > ${t.name}`
63
+ let loc = formatLocation(t.location)
64
+ let locStr = loc == "" ? "" : ` ${pc.dim(loc)}`
65
+ switch t.status {
66
+ | Pass => writeLine(` ${pc.green("✓")} ${full}${locStr}`)
67
+ | Skip =>
68
+ writeLine(
69
+ ` ${pc.yellow("○")} ${full}${locStr} ${pc.dim(
70
+ t.skipReason->Option.getOr("skipped"),
71
+ )}`,
72
+ )
73
+ | Fail => {
74
+ writeLine(` ${pc.red("✗")} ${pc.bold(full)}${locStr}`)
75
+ switch t.mismatch {
76
+ | Some(m) => {
77
+ writeLine("")
78
+ writeLine(renderMismatch(m))
79
+ let hint = Hint.forMismatch(~slice=?t.slice, m)
80
+ writeLine("")
81
+ writeLine(` ${pc.cyan(Hint.format(hint))}`)
82
+ writeLine("")
83
+ }
84
+ | None => ()
85
+ }
86
+ }
87
+ }
88
+ }
89
+
90
+ let emitFile = (f: RunnerTypes.fileResult) => {
91
+ writeLine("")
92
+ writeLine(pc.bold(formatFilePath(f.path)))
93
+ f.tests->Array.forEach(emitTest)
94
+ }
95
+
96
+ let emitSummary = (s: RunnerTypes.summary) => {
97
+ writeLine("")
98
+ let line = `Tests: ${Int.toString(s.total)} ${pc.green(
99
+ Int.toString(s.passed) ++ " passed",
100
+ )} ${pc.red(Int.toString(s.failed) ++ " failed")} ${pc.yellow(
101
+ Int.toString(s.skipped) ++ " skipped",
102
+ )} (${Float.toString(s.durationMs)} ms)`
103
+ writeLine(line)
104
+ }
105
+
106
+ let emit = (r: RunnerTypes.runResult) => {
107
+ r.files->Array.forEach(emitFile)
108
+ emitSummary(r.summary)
109
+ }