@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,426 @@
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_option from "@rescript/runtime/lib/es6/Primitive_option.js";
8
+ import * as Primitive_string from "@rescript/runtime/lib/es6/Primitive_string.js";
9
+ import * as DcbTag$Reventless from "@reventlessdev/reventless-spec/src/components/DcbTag.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 DcbScopeInference$Reventless from "@reventlessdev/reventless-spec/src/components/DcbScopeInference.res.mjs";
15
+
16
+ function encodeTag(t) {
17
+ let d = {};
18
+ d["key"] = t.key;
19
+ d["value"] = t.value;
20
+ return d;
21
+ }
22
+
23
+ function encodeQueryItem(qi) {
24
+ let d = {};
25
+ let types = qi.eventTypes;
26
+ if (types !== undefined) {
27
+ d["eventTypes"] = types.map(prim => prim);
28
+ }
29
+ let tags = qi.tags;
30
+ if (tags !== undefined) {
31
+ d["tags"] = tags.map(encodeTag);
32
+ }
33
+ return d;
34
+ }
35
+
36
+ function encodeQuery(q) {
37
+ return q.map(encodeQueryItem);
38
+ }
39
+
40
+ function encodeAppendCondition(c) {
41
+ let d = {};
42
+ d["query"] = c.query.map(encodeQueryItem);
43
+ let pos = c.after;
44
+ if (pos !== undefined) {
45
+ d["after"] = pos;
46
+ }
47
+ return d;
48
+ }
49
+
50
+ function Make(Spec) {
51
+ return Behavior => {
52
+ S.enableJson();
53
+ let test = (name, body) => JestBind$ReventlessGwt.test(Spec.name, name, body);
54
+ let errors = {
55
+ contents: []
56
+ };
57
+ let derivedCondition = {
58
+ contents: undefined
59
+ };
60
+ let appendConditionFailure = {
61
+ contents: undefined
62
+ };
63
+ let consumedEventTypes = DcbDecode$Reventless.makeDecoder(Spec.consumedEventSchema).eventTypes;
64
+ let scopeShape = DcbTag$Reventless.sliceShapeFromSchemas("", Spec.commandSchema, Spec.consumedEventSchema, Spec.eventSchema);
65
+ let set = new Set();
66
+ DcbTag$Reventless.extractCrossPartitionTagKeys(Spec.eventSchema).forEach(k => {
67
+ set.add(k);
68
+ });
69
+ DcbScopeInference$Reventless.crossPartitionForSlice(scopeShape).forEach(k => {
70
+ set.add(k);
71
+ });
72
+ let crossPartitionTagKeys = Array.from(set.values()).toSorted(Primitive_string.compare);
73
+ let tagKeysByEventType = DcbScopeInference$Reventless.infer([scopeShape]).tagKeysByEventType;
74
+ let emittedEventTypes = DcbDecode$Reventless.makeDecoder(Spec.eventSchema).eventTypes;
75
+ let consumedTagKeysByType = DcbTag$Reventless.extractTagKeysByEventType(Spec.consumedEventSchema);
76
+ let queryTagKeys = query => query.flatMap(qi => Stdlib_Option.mapOr(qi.tags, [], tags => tags.map(t => t.key)));
77
+ let selectableBy = (query, declaredKeys) => {
78
+ if (query.length === 0) {
79
+ return true;
80
+ } else {
81
+ return query.some(qi => {
82
+ let tags = qi.tags;
83
+ if (tags !== undefined && tags.length !== 0) {
84
+ return tags.every(t => declaredKeys.includes(t.key));
85
+ } else {
86
+ return true;
87
+ }
88
+ });
89
+ }
90
+ };
91
+ let unreachableForeignReads = query => {
92
+ let qKeys = queryTagKeys(query);
93
+ return Stdlib_Array.filterMap(Object.entries(consumedTagKeysByType), param => {
94
+ let keys = param[1];
95
+ let evType = param[0];
96
+ let key = keys.find(k => qKeys.includes(k));
97
+ if (key !== undefined && !emittedEventTypes.includes(evType) && !selectableBy(query, keys)) {
98
+ return [
99
+ evType,
100
+ key
101
+ ];
102
+ }
103
+ });
104
+ };
105
+ let queryTagsTotal = q => Stdlib_Array.reduce(q, 0, (acc, qi) => acc + Stdlib_Option.mapOr(qi.tags, 0, t => t.length) | 0);
106
+ let givenEvents = consumed => consumed;
107
+ let whenCmd = (history, cmd) => {
108
+ errors.contents = [];
109
+ appendConditionFailure.contents = undefined;
110
+ let query = DcbTag$Reventless.buildQueryFromCommand(consumedEventTypes, Spec.commandSchema, cmd, tagKeysByEventType, crossPartitionTagKeys);
111
+ let condition = {
112
+ query: query
113
+ };
114
+ derivedCondition.contents = condition;
115
+ if (consumedEventTypes.length !== 0 && queryTagsTotal(query) === 0) {
116
+ appendConditionFailure.contents = {
117
+ TAG: "AppendConditionMismatch",
118
+ expected: "a non-empty tag set derived from @s.matches(DcbTag.string) fields on the command",
119
+ actual: encodeAppendCondition(condition)
120
+ };
121
+ } else {
122
+ let match = unreachableForeignReads(query)[0];
123
+ if (match !== undefined) {
124
+ let key = match[1];
125
+ let evType = match[0];
126
+ appendConditionFailure.contents = {
127
+ TAG: "AppendConditionMismatch",
128
+ expected: `a decision-query clause that selects '` + evType + `' on tag '` + key + `' alone — this is a cross-entity read, so mark '` + key + `' @crossPartition (or model it as a tagged array) and it will fan into its own clause; otherwise the decision model can never see '` + evType + `'`,
129
+ actual: encodeAppendCondition(condition)
130
+ };
131
+ }
132
+ }
133
+ let state = Stdlib_Array.reduce(history, Behavior.initialState, Behavior.evolve);
134
+ let events = Behavior.decide(state, cmd);
135
+ if (events.TAG === "Ok") {
136
+ return events._0;
137
+ }
138
+ errors.contents = [events._0];
139
+ return [];
140
+ };
141
+ let encEvent = e => Message$ReventlessCore.encode(e, Spec.eventSchema);
142
+ let encError = err => Message$ReventlessCore.encode(err, Spec.errorSchema);
143
+ let checkAppendCondition = () => Stdlib_Option.map(appendConditionFailure.contents, Outcome$ReventlessGwt.fail);
144
+ let unexpectedError = events => {
145
+ let actual = Stdlib_Option.map(errors.contents[0], encError);
146
+ return Outcome$ReventlessGwt.fail({
147
+ TAG: "ErrorMismatch",
148
+ expected: null,
149
+ actual: actual,
150
+ actualEvents: events.map(encEvent)
151
+ });
152
+ };
153
+ let thenEvents = (events, expectedEvents) => {
154
+ let o = checkAppendCondition();
155
+ if (o !== undefined) {
156
+ return o;
157
+ } else if (errors.contents.length !== 0) {
158
+ return unexpectedError(events);
159
+ } else if (Primitive_object.equal(events, expectedEvents)) {
160
+ return Outcome$ReventlessGwt.pass;
161
+ } else {
162
+ return Outcome$ReventlessGwt.fail({
163
+ TAG: "EventsMismatch",
164
+ expected: expectedEvents.map(encEvent),
165
+ actual: events.map(encEvent)
166
+ });
167
+ }
168
+ };
169
+ let thenEvent = (events, expectedEvent) => thenEvents(events, [expectedEvent]);
170
+ let thenNoEvent = events => {
171
+ let o = checkAppendCondition();
172
+ if (o !== undefined) {
173
+ return o;
174
+ } else if (errors.contents.length !== 0) {
175
+ return unexpectedError(events);
176
+ } else if (events.length === 0) {
177
+ return Outcome$ReventlessGwt.pass;
178
+ } else {
179
+ return Outcome$ReventlessGwt.fail({
180
+ TAG: "NoEventExpected",
181
+ actual: events.map(encEvent)
182
+ });
183
+ }
184
+ };
185
+ let matchesError = (events, expectedEvents, expectedError) => {
186
+ let expectedErrorJson = Message$ReventlessCore.encode(expectedError, Spec.errorSchema);
187
+ let actual = errors.contents[0];
188
+ if (actual === undefined) {
189
+ return Outcome$ReventlessGwt.fail({
190
+ TAG: "ErrorMismatch",
191
+ expected: expectedErrorJson,
192
+ actual: undefined,
193
+ actualEvents: events.map(encEvent)
194
+ });
195
+ }
196
+ let actual$1 = Primitive_option.valFromOption(actual);
197
+ if (Primitive_object.notequal(actual$1, expectedError)) {
198
+ return Outcome$ReventlessGwt.fail({
199
+ TAG: "ErrorMismatch",
200
+ expected: expectedErrorJson,
201
+ actual: Message$ReventlessCore.encode(actual$1, Spec.errorSchema),
202
+ actualEvents: events.map(encEvent)
203
+ });
204
+ } else if (Primitive_object.equal(events, expectedEvents)) {
205
+ return Outcome$ReventlessGwt.pass;
206
+ } else {
207
+ return Outcome$ReventlessGwt.fail({
208
+ TAG: "EventsMismatch",
209
+ expected: expectedEvents.map(encEvent),
210
+ actual: events.map(encEvent)
211
+ });
212
+ }
213
+ };
214
+ let thenError = (events, expectedError) => {
215
+ let o = checkAppendCondition();
216
+ if (o !== undefined) {
217
+ return o;
218
+ } else {
219
+ return matchesError(events, [], expectedError);
220
+ }
221
+ };
222
+ let thenEventWithError = (events, expectedEvent, expectedError) => {
223
+ let o = checkAppendCondition();
224
+ if (o !== undefined) {
225
+ return o;
226
+ } else {
227
+ return matchesError(events, [expectedEvent], expectedError);
228
+ }
229
+ };
230
+ let thenEventsWithError = (events, expectedEvents, expectedError) => {
231
+ let o = checkAppendCondition();
232
+ if (o !== undefined) {
233
+ return o;
234
+ } else {
235
+ return matchesError(events, expectedEvents, expectedError);
236
+ }
237
+ };
238
+ let thenAppendsConditionedOn = (_events, expectedQuery) => {
239
+ let cond = derivedCondition.contents;
240
+ if (cond !== undefined) {
241
+ if (Primitive_object.equal(cond.query, expectedQuery)) {
242
+ return Outcome$ReventlessGwt.pass;
243
+ } else {
244
+ return Outcome$ReventlessGwt.fail({
245
+ TAG: "AppendConditionMismatch",
246
+ expected: encodeAppendCondition({
247
+ query: expectedQuery
248
+ }),
249
+ actual: encodeAppendCondition(cond)
250
+ });
251
+ }
252
+ } else {
253
+ return Outcome$ReventlessGwt.fail({
254
+ TAG: "Throw",
255
+ error: "thenAppendsConditionedOn: whenCmd must be called before this assertion",
256
+ stack: ""
257
+ });
258
+ }
259
+ };
260
+ let thenAppendsConditionedOnExactly = (_events, expectedCondition) => {
261
+ let cond = derivedCondition.contents;
262
+ if (cond !== undefined) {
263
+ if (Primitive_object.equal(cond, expectedCondition)) {
264
+ return Outcome$ReventlessGwt.pass;
265
+ } else {
266
+ return Outcome$ReventlessGwt.fail({
267
+ TAG: "AppendConditionMismatch",
268
+ expected: encodeAppendCondition(expectedCondition),
269
+ actual: encodeAppendCondition(cond)
270
+ });
271
+ }
272
+ } else {
273
+ return Outcome$ReventlessGwt.fail({
274
+ TAG: "Throw",
275
+ error: "thenAppendsConditionedOnExactly: whenCmd must be called before this assertion",
276
+ stack: ""
277
+ });
278
+ }
279
+ };
280
+ return {
281
+ Spec: Spec,
282
+ describe: JestBind$ReventlessGwt.describe,
283
+ todo: JestBind$ReventlessGwt.todo,
284
+ test: test,
285
+ givenEvents: givenEvents,
286
+ whenCmd: whenCmd,
287
+ thenEvent: thenEvent,
288
+ thenEvents: thenEvents,
289
+ thenNoEvent: thenNoEvent,
290
+ thenEventWithError: thenEventWithError,
291
+ thenEventsWithError: thenEventsWithError,
292
+ thenError: thenError,
293
+ thenAppendsConditionedOn: thenAppendsConditionedOn,
294
+ thenAppendsConditionedOnExactly: thenAppendsConditionedOnExactly
295
+ };
296
+ };
297
+ }
298
+
299
+ function MakeFromAggregate(Spec) {
300
+ return Behavior => {
301
+ S.enableJson();
302
+ let test = (name, body) => JestBind$ReventlessGwt.test(Spec.name, name, body);
303
+ let errors = {
304
+ contents: []
305
+ };
306
+ let givenEvents = events => events;
307
+ let whenCmd = (history, cmd) => {
308
+ errors.contents = [];
309
+ let state = Stdlib_Array.reduce(history, Behavior.initialState, Behavior.evolve);
310
+ let events = Behavior.decide(state, cmd);
311
+ if (events.TAG === "Ok") {
312
+ return events._0;
313
+ }
314
+ errors.contents = [events._0];
315
+ return [];
316
+ };
317
+ let encEvent = e => Message$ReventlessCore.encode(e, Spec.eventSchema);
318
+ let encError = err => Message$ReventlessCore.encode(err, Spec.errorSchema);
319
+ let unexpectedError = events => {
320
+ let actual = Stdlib_Option.map(errors.contents[0], encError);
321
+ return Outcome$ReventlessGwt.fail({
322
+ TAG: "ErrorMismatch",
323
+ expected: null,
324
+ actual: actual,
325
+ actualEvents: events.map(encEvent)
326
+ });
327
+ };
328
+ let thenEvents = (events, expectedEvents) => {
329
+ if (errors.contents.length !== 0) {
330
+ return unexpectedError(events);
331
+ } else if (Primitive_object.equal(events, expectedEvents)) {
332
+ return Outcome$ReventlessGwt.pass;
333
+ } else {
334
+ return Outcome$ReventlessGwt.fail({
335
+ TAG: "EventsMismatch",
336
+ expected: expectedEvents.map(encEvent),
337
+ actual: events.map(encEvent)
338
+ });
339
+ }
340
+ };
341
+ let thenCompareEvents = (events, expectedEvents, cmp) => {
342
+ if (errors.contents.length !== 0) {
343
+ return unexpectedError(events);
344
+ } else if (events.length === expectedEvents.length && Stdlib_Array.zip(events, expectedEvents).every(param => cmp(param[0], param[1]))) {
345
+ return Outcome$ReventlessGwt.pass;
346
+ } else {
347
+ return Outcome$ReventlessGwt.fail({
348
+ TAG: "EventsMismatch",
349
+ expected: expectedEvents.map(encEvent),
350
+ actual: events.map(encEvent)
351
+ });
352
+ }
353
+ };
354
+ let thenEvent = (events, expectedEvent) => thenEvents(events, [expectedEvent]);
355
+ let thenCompareEvent = (events, expectedEvent, cmp) => thenCompareEvents(events, [expectedEvent], cmp);
356
+ let thenNoEvent = events => {
357
+ if (errors.contents.length !== 0) {
358
+ return unexpectedError(events);
359
+ } else if (events.length === 0) {
360
+ return Outcome$ReventlessGwt.pass;
361
+ } else {
362
+ return Outcome$ReventlessGwt.fail({
363
+ TAG: "NoEventExpected",
364
+ actual: events.map(encEvent)
365
+ });
366
+ }
367
+ };
368
+ let matchesError = (events, expectedEvents, expectedError) => {
369
+ let expectedErrorJson = Message$ReventlessCore.encode(expectedError, Spec.errorSchema);
370
+ let actual = errors.contents[0];
371
+ if (actual === undefined) {
372
+ return Outcome$ReventlessGwt.fail({
373
+ TAG: "ErrorMismatch",
374
+ expected: expectedErrorJson,
375
+ actual: undefined,
376
+ actualEvents: events.map(encEvent)
377
+ });
378
+ }
379
+ let actual$1 = Primitive_option.valFromOption(actual);
380
+ if (Primitive_object.notequal(actual$1, expectedError)) {
381
+ return Outcome$ReventlessGwt.fail({
382
+ TAG: "ErrorMismatch",
383
+ expected: expectedErrorJson,
384
+ actual: Message$ReventlessCore.encode(actual$1, Spec.errorSchema),
385
+ actualEvents: events.map(encEvent)
386
+ });
387
+ } else if (Primitive_object.equal(events, expectedEvents)) {
388
+ return Outcome$ReventlessGwt.pass;
389
+ } else {
390
+ return Outcome$ReventlessGwt.fail({
391
+ TAG: "EventsMismatch",
392
+ expected: expectedEvents.map(encEvent),
393
+ actual: events.map(encEvent)
394
+ });
395
+ }
396
+ };
397
+ let thenError = (events, expectedError) => matchesError(events, [], expectedError);
398
+ let thenEventWithError = (events, expectedEvent, expectedError) => matchesError(events, [expectedEvent], expectedError);
399
+ let thenEventsWithError = matchesError;
400
+ return {
401
+ Spec: Spec,
402
+ describe: JestBind$ReventlessGwt.describe,
403
+ test: test,
404
+ givenEvents: givenEvents,
405
+ whenCmd: whenCmd,
406
+ thenEvent: thenEvent,
407
+ thenCompareEvent: thenCompareEvent,
408
+ thenNoEvent: thenNoEvent,
409
+ thenEventWithError: thenEventWithError,
410
+ thenEvents: thenEvents,
411
+ thenCompareEvents: thenCompareEvents,
412
+ thenEventsWithError: thenEventsWithError,
413
+ thenError: thenError
414
+ };
415
+ };
416
+ }
417
+
418
+ export {
419
+ encodeTag,
420
+ encodeQueryItem,
421
+ encodeQuery,
422
+ encodeAppendCondition,
423
+ Make,
424
+ MakeFromAggregate,
425
+ }
426
+ /* S Not a pure module */
package/src/Bind.res ADDED
@@ -0,0 +1,29 @@
1
+ // CLI-mode binding for test files.
2
+ //
3
+ // Mirrors the shape of `JestBind` (`describe`, `test`, `testPromise`) but
4
+ // pushes directly into `Collector` instead of forwarding to Jest globals.
5
+ // Test files can either:
6
+ //
7
+ // 1. Rely on the DSL default (every `*_GWT.res` module uses `JestBind`
8
+ // internally, which routes to `Collector` when the CLI has activated it),
9
+ // or
10
+ // 2. Explicitly `open ReventlessGwt.Bind` to get these functions bound at
11
+ // compile time — useful for ad-hoc harnesses or tests that want to
12
+ // bypass the JestBind fallback entirely.
13
+ //
14
+ // Either way, the runtime contract is identical: each call pushes one entry
15
+ // into `Collector.entries`. The CLI drains the list after dynamic-import
16
+ // resolves.
17
+
18
+ let describe = (label: string, body: unit => unit) =>
19
+ Collector.pushDescribe(label, body)
20
+
21
+ let test = (~slice=?, name: string, body: unit => Outcome.outcome) => {
22
+ let location = Collector.captureLocation(1)
23
+ Collector.push(~slice?, ~location?, name, () => Promise.resolve(body()))
24
+ }
25
+
26
+ let testPromise = (~slice=?, name: string, body: unit => promise<Outcome.outcome>) => {
27
+ let location = Collector.captureLocation(1)
28
+ Collector.push(~slice?, ~location?, name, body)
29
+ }
@@ -0,0 +1,22 @@
1
+ // Generated by ReScript, PLEASE EDIT WITH CARE
2
+
3
+ import * as Collector$ReventlessGwt from "./Collector.res.mjs";
4
+
5
+ let describe = Collector$ReventlessGwt.pushDescribe;
6
+
7
+ function test(slice, name, body) {
8
+ let location = Collector$ReventlessGwt.captureLocation(1);
9
+ Collector$ReventlessGwt.push(slice, location, name, () => Promise.resolve(body()));
10
+ }
11
+
12
+ function testPromise(slice, name, body) {
13
+ let location = Collector$ReventlessGwt.captureLocation(1);
14
+ Collector$ReventlessGwt.push(slice, location, name, body);
15
+ }
16
+
17
+ export {
18
+ describe,
19
+ test,
20
+ testPromise,
21
+ }
22
+ /* No side effect */
@@ -0,0 +1,137 @@
1
+ // Turns a ReScript v12 `rescript build -w` stdout line-stream into build status
2
+ // callbacks. One classifier per managed package.
3
+ //
4
+ // The watch output cycle is:
5
+ // Parsed N source files ← a compile pass begins
6
+ // Compiled N modules
7
+ // Finished incremental compilation ← success terminator
8
+ // On a type/syntax error there is NO terminator — rescript prints a
9
+ // "We've found a bug for you!" block and waits. So success is detected on the
10
+ // "Finished … compilation" line; failure is detected by an error marker and
11
+ // flushed after the output settles (debounced), since there is no end line.
12
+ //
13
+ // Backstop: a build that prints "Parsed …" but then emits neither a terminator
14
+ // nor a recognised error marker — a crashed/hung watcher, or an error in a form
15
+ // the markers miss — would otherwise pin the consumer (the VS Code status bar)
16
+ // at "building" forever. A generous wall-clock watchdog fails such a build so
17
+ // the UI recovers.
18
+
19
+ @val external now: unit => float = "performance.now"
20
+ @val external setTimeout: (unit => unit, int) => float = "setTimeout"
21
+ @val external clearTimeout: float => unit = "clearTimeout"
22
+
23
+ let stripAnsi: string => string = %raw(`s => s.replace(/\x1b\[[0-9;]*m/g, "")`)
24
+
25
+ type callbacks = {
26
+ onStart: unit => unit,
27
+ onOk: float => unit,
28
+ onFail: string => unit,
29
+ }
30
+
31
+ let isStartLine = (l: string) =>
32
+ String.startsWith(l, "Parsed ") && String.endsWith(l, "source files")
33
+
34
+ let isFinishLine = (l: string) =>
35
+ String.includes(l, "Finished") && String.includes(l, "compilation")
36
+
37
+ let isErrorMarker = (l: string) =>
38
+ String.includes(l, "We've found a bug for you!") ||
39
+ String.includes(l, "Syntax error") ||
40
+ (String.startsWith(l, "Found ") && String.includes(l, "error"))
41
+
42
+ // Returns a `feed` function: hand it each raw stdout line. `watchdogMs` bounds
43
+ // how long a started-but-unterminated compile may stay "building" before it is
44
+ // reported failed (see the backstop note above).
45
+ let make = (~watchdogMs: int=120_000, cb: callbacks): (string => unit) => {
46
+ let compiling = ref(false)
47
+ let hasError = ref(false)
48
+ let startTime = ref(0.0)
49
+ let buffer = ref([])
50
+ let timer: ref<option<float>> = ref(None)
51
+ let watchdog: ref<option<float>> = ref(None)
52
+
53
+ let clearTimer = () =>
54
+ switch timer.contents {
55
+ | Some(t) => {
56
+ clearTimeout(t)
57
+ timer := None
58
+ }
59
+ | None => ()
60
+ }
61
+
62
+ let clearWatchdog = () =>
63
+ switch watchdog.contents {
64
+ | Some(t) => {
65
+ clearTimeout(t)
66
+ watchdog := None
67
+ }
68
+ | None => ()
69
+ }
70
+
71
+ let reset = () => {
72
+ compiling := false
73
+ hasError := false
74
+ buffer := []
75
+ }
76
+
77
+ // After output settles, a compile that saw an error (and thus no "Finished"
78
+ // terminator) is reported failed, capturing a concise message.
79
+ let settle = () =>
80
+ if compiling.contents && hasError.contents {
81
+ let msg = buffer.contents->Array.slice(~start=0, ~end=20)->Array.join("\n")
82
+ clearWatchdog()
83
+ cb.onFail(msg)
84
+ reset()
85
+ }
86
+
87
+ let arm = () => {
88
+ clearTimer()
89
+ timer := Some(setTimeout(settle, 400))
90
+ }
91
+
92
+ // Last-resort timer: fail a build still compiling after `watchdogMs` with no
93
+ // terminator and no recognised error, so the consumer never spins forever.
94
+ let armWatchdog = () => {
95
+ clearWatchdog()
96
+ watchdog :=
97
+ Some(
98
+ setTimeout(() =>
99
+ if compiling.contents {
100
+ clearTimer()
101
+ cb.onFail("build watchdog: no completion within " ++ Int.toString(watchdogMs / 1000) ++ "s")
102
+ reset()
103
+ }
104
+ , watchdogMs),
105
+ )
106
+ }
107
+
108
+ line => {
109
+ let l = stripAnsi(line)->String.trim
110
+ if isStartLine(l) {
111
+ if !compiling.contents {
112
+ cb.onStart()
113
+ }
114
+ compiling := true
115
+ hasError := false
116
+ buffer := []
117
+ startTime := now()
118
+ arm()
119
+ armWatchdog()
120
+ } else if isFinishLine(l) {
121
+ clearTimer()
122
+ clearWatchdog()
123
+ if compiling.contents {
124
+ cb.onOk(now() -. startTime.contents)
125
+ reset()
126
+ }
127
+ } else {
128
+ if String.length(l) > 0 {
129
+ buffer := Array.concat(buffer.contents, [l])
130
+ }
131
+ if isErrorMarker(l) {
132
+ hasError := true
133
+ }
134
+ arm()
135
+ }
136
+ }
137
+ }