@reventlessdev/reventless-gwt 1.0.0-alpha.238 → 1.0.0-alpha.240
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.
- package/CHANGELOG.md +21 -0
- package/package.json +6 -6
- package/src/Automation_GWT.res +130 -0
- package/src/Automation_GWT.res.mjs +193 -0
- package/src/Behavior_GWT.res +6 -6
- package/src/Behavior_GWT.res.mjs +5 -5
- package/src/Capabilities_Fake.res +157 -0
- package/src/Capabilities_Fake.res.mjs +254 -0
- package/src/Flow_GWT.res +112 -1
- package/src/Flow_GWT.res.mjs +165 -11
- package/src/InboundTranslation_GWT.res +112 -0
- package/src/InboundTranslation_GWT.res.mjs +190 -1
- package/src/OutboundTranslation_GWT.res +207 -4
- package/src/OutboundTranslation_GWT.res.mjs +257 -1
- package/src/StateChange/ExternalAddCategorySlice.res +1 -1
- package/src/StateChange/ExternalAddCategorySlice.res.mjs +2 -2
- package/src/StateChange/WithFixtures.res +1 -1
- package/src/StateChange/WithFixtures.res.mjs +2 -2
- package/src/StateChange/WithManualOpen.res +1 -1
- package/src/StateChange/WithManualOpen.res.mjs +2 -2
- package/tests/AutomationFromSliceGwtTest.res +145 -0
- package/tests/AutomationFromSliceGwtTest.res.mjs +353 -0
- package/tests/AutomationGwtTest.res.mjs +2 -2
- package/tests/DelegateGwtTest.res +5 -5
- package/tests/DelegateGwtTest.res.mjs +27 -27
- package/tests/FlowAggregateGwtTest.res.mjs +4 -4
- package/tests/FlowCrossPluginGwtTest.res +4 -4
- package/tests/FlowCrossPluginGwtTest.res.mjs +22 -22
- package/tests/FlowGwtTest.res.mjs +6 -6
- package/tests/InboundFromSliceGwtTest.res +63 -0
- package/tests/InboundFromSliceGwtTest.res.mjs +164 -0
- package/tests/InboundTranslationGwtTest.res.mjs +2 -7
- package/tests/MappingGwtTest.res.mjs +12 -12
- package/tests/OutboundFromSliceGwtTest.res +124 -0
- package/tests/OutboundFromSliceGwtTest.res.mjs +268 -0
- package/tests/StateChangeSliceAuthorizeGwtTest.res.mjs +20 -16
- package/tests/StateChangeSliceGwtTest.res.mjs +6 -6
|
@@ -0,0 +1,254 @@
|
|
|
1
|
+
// Generated by ReScript, PLEASE EDIT WITH CARE
|
|
2
|
+
|
|
3
|
+
import * as Belt_Array from "@rescript/runtime/lib/es6/Belt_Array.js";
|
|
4
|
+
import * as Stdlib_Option from "@rescript/runtime/lib/es6/Stdlib_Option.js";
|
|
5
|
+
import * as Messaging$Reventless from "@reventlessdev/reventless-spec/src/semantic/Messaging.res.mjs";
|
|
6
|
+
import * as IdentityProvider$Reventless from "@reventlessdev/reventless-spec/src/semantic/IdentityProvider.res.mjs";
|
|
7
|
+
|
|
8
|
+
function make(geocode, send, channelsOpt, pushServicesOpt, createPrincipal, token, hash, secrets, param) {
|
|
9
|
+
let channels = channelsOpt !== undefined ? channelsOpt : [
|
|
10
|
+
"Email",
|
|
11
|
+
"Sms"
|
|
12
|
+
];
|
|
13
|
+
let pushServices = pushServicesOpt !== undefined ? pushServicesOpt : [];
|
|
14
|
+
let log = [];
|
|
15
|
+
let geocode$1 = async text => {
|
|
16
|
+
log.push({
|
|
17
|
+
TAG: "Geocoded",
|
|
18
|
+
text: text
|
|
19
|
+
});
|
|
20
|
+
if (geocode !== undefined) {
|
|
21
|
+
return await geocode(text);
|
|
22
|
+
} else {
|
|
23
|
+
return {
|
|
24
|
+
TAG: "Ok",
|
|
25
|
+
_0: []
|
|
26
|
+
};
|
|
27
|
+
}
|
|
28
|
+
};
|
|
29
|
+
let send$1 = async (recipient, message) => {
|
|
30
|
+
log.push({
|
|
31
|
+
TAG: "Sent",
|
|
32
|
+
recipient: recipient,
|
|
33
|
+
message: message
|
|
34
|
+
});
|
|
35
|
+
if (send !== undefined) {
|
|
36
|
+
return await send(recipient, message);
|
|
37
|
+
} else {
|
|
38
|
+
return {
|
|
39
|
+
TAG: "Ok",
|
|
40
|
+
_0: {
|
|
41
|
+
ref: `receipt-` + log.length.toString()
|
|
42
|
+
}
|
|
43
|
+
};
|
|
44
|
+
}
|
|
45
|
+
};
|
|
46
|
+
let createPrincipal$1 = async (contact, credential, groups) => {
|
|
47
|
+
log.push({
|
|
48
|
+
TAG: "PrincipalCreated",
|
|
49
|
+
contact: contact,
|
|
50
|
+
credential: credential,
|
|
51
|
+
groups: groups
|
|
52
|
+
});
|
|
53
|
+
if (createPrincipal !== undefined) {
|
|
54
|
+
return await createPrincipal(contact, credential, groups);
|
|
55
|
+
} else {
|
|
56
|
+
return {
|
|
57
|
+
TAG: "Ok",
|
|
58
|
+
_0: {
|
|
59
|
+
providerId: `principal-` + log.length.toString()
|
|
60
|
+
}
|
|
61
|
+
};
|
|
62
|
+
}
|
|
63
|
+
};
|
|
64
|
+
let capabilities_messaging = Messaging$Reventless.makeProvider(channels, pushServices, send$1);
|
|
65
|
+
let capabilities_identityProvider = IdentityProvider$Reventless.make(createPrincipal$1, async (principal, group) => {
|
|
66
|
+
log.push({
|
|
67
|
+
TAG: "AddedToGroup",
|
|
68
|
+
principal: principal,
|
|
69
|
+
group: group
|
|
70
|
+
});
|
|
71
|
+
return {
|
|
72
|
+
TAG: "Ok",
|
|
73
|
+
_0: undefined
|
|
74
|
+
};
|
|
75
|
+
}, async (principal, group) => {
|
|
76
|
+
log.push({
|
|
77
|
+
TAG: "RemovedFromGroup",
|
|
78
|
+
principal: principal,
|
|
79
|
+
group: group
|
|
80
|
+
});
|
|
81
|
+
return {
|
|
82
|
+
TAG: "Ok",
|
|
83
|
+
_0: undefined
|
|
84
|
+
};
|
|
85
|
+
}, async principal => {
|
|
86
|
+
log.push({
|
|
87
|
+
TAG: "PrincipalDeleted",
|
|
88
|
+
principal: principal
|
|
89
|
+
});
|
|
90
|
+
return {
|
|
91
|
+
TAG: "Ok",
|
|
92
|
+
_0: undefined
|
|
93
|
+
};
|
|
94
|
+
}, [
|
|
95
|
+
"CreatePrincipal",
|
|
96
|
+
"AddToGroup",
|
|
97
|
+
"RemoveFromGroup",
|
|
98
|
+
"DeletePrincipal"
|
|
99
|
+
]);
|
|
100
|
+
let capabilities_secrets = {
|
|
101
|
+
randomToken: (length, alphabet) => {
|
|
102
|
+
log.push({
|
|
103
|
+
TAG: "TokenDrawn",
|
|
104
|
+
length: length,
|
|
105
|
+
alphabet: alphabet
|
|
106
|
+
});
|
|
107
|
+
if (secrets !== undefined) {
|
|
108
|
+
return secrets.randomToken(length, alphabet);
|
|
109
|
+
} else {
|
|
110
|
+
return {
|
|
111
|
+
TAG: "Ok",
|
|
112
|
+
_0: Stdlib_Option.getOr(token, "t".repeat(length))
|
|
113
|
+
};
|
|
114
|
+
}
|
|
115
|
+
},
|
|
116
|
+
hash: input => {
|
|
117
|
+
log.push({
|
|
118
|
+
TAG: "Hashed",
|
|
119
|
+
input: input
|
|
120
|
+
});
|
|
121
|
+
if (secrets !== undefined) {
|
|
122
|
+
return secrets.hash(input);
|
|
123
|
+
} else {
|
|
124
|
+
return {
|
|
125
|
+
TAG: "Ok",
|
|
126
|
+
_0: Stdlib_Option.mapOr(hash, `hash:` + input, f => f(input))
|
|
127
|
+
};
|
|
128
|
+
}
|
|
129
|
+
}
|
|
130
|
+
};
|
|
131
|
+
let capabilities = {
|
|
132
|
+
geocode: geocode$1,
|
|
133
|
+
messaging: capabilities_messaging,
|
|
134
|
+
identityProvider: capabilities_identityProvider,
|
|
135
|
+
secrets: capabilities_secrets
|
|
136
|
+
};
|
|
137
|
+
return {
|
|
138
|
+
capabilities: capabilities,
|
|
139
|
+
calls: () => log.slice()
|
|
140
|
+
};
|
|
141
|
+
}
|
|
142
|
+
|
|
143
|
+
function toJson(c) {
|
|
144
|
+
let recipientText = r => {
|
|
145
|
+
switch (r.TAG) {
|
|
146
|
+
case "ToEmail" :
|
|
147
|
+
return `email:` + r._0;
|
|
148
|
+
case "ToSms" :
|
|
149
|
+
return `sms:` + r._0;
|
|
150
|
+
case "ToPush" :
|
|
151
|
+
return `push:` + Messaging$Reventless.pushServiceToString(Messaging$Reventless.serviceOf(r._0));
|
|
152
|
+
}
|
|
153
|
+
};
|
|
154
|
+
let obj = (tag, fields) => Object.fromEntries(Belt_Array.concatMany([
|
|
155
|
+
[[
|
|
156
|
+
"TAG",
|
|
157
|
+
tag
|
|
158
|
+
]],
|
|
159
|
+
fields
|
|
160
|
+
]));
|
|
161
|
+
let str = prim => prim;
|
|
162
|
+
switch (c.TAG) {
|
|
163
|
+
case "Geocoded" :
|
|
164
|
+
return obj("Geocoded", [[
|
|
165
|
+
"text",
|
|
166
|
+
c.text
|
|
167
|
+
]]);
|
|
168
|
+
case "Sent" :
|
|
169
|
+
let message = c.message;
|
|
170
|
+
return obj("Sent", [
|
|
171
|
+
[
|
|
172
|
+
"recipient",
|
|
173
|
+
recipientText(c.recipient)
|
|
174
|
+
],
|
|
175
|
+
[
|
|
176
|
+
"subject",
|
|
177
|
+
Stdlib_Option.mapOr(message.subject, null, str)
|
|
178
|
+
],
|
|
179
|
+
[
|
|
180
|
+
"body",
|
|
181
|
+
message.body
|
|
182
|
+
]
|
|
183
|
+
]);
|
|
184
|
+
case "PrincipalCreated" :
|
|
185
|
+
return obj("PrincipalCreated", [
|
|
186
|
+
[
|
|
187
|
+
"contact",
|
|
188
|
+
recipientText(c.contact)
|
|
189
|
+
],
|
|
190
|
+
[
|
|
191
|
+
"groups",
|
|
192
|
+
c.groups.map(str)
|
|
193
|
+
]
|
|
194
|
+
]);
|
|
195
|
+
case "AddedToGroup" :
|
|
196
|
+
return obj("AddedToGroup", [
|
|
197
|
+
[
|
|
198
|
+
"principal",
|
|
199
|
+
c.principal.providerId
|
|
200
|
+
],
|
|
201
|
+
[
|
|
202
|
+
"group",
|
|
203
|
+
c.group
|
|
204
|
+
]
|
|
205
|
+
]);
|
|
206
|
+
case "RemovedFromGroup" :
|
|
207
|
+
return obj("RemovedFromGroup", [
|
|
208
|
+
[
|
|
209
|
+
"principal",
|
|
210
|
+
c.principal.providerId
|
|
211
|
+
],
|
|
212
|
+
[
|
|
213
|
+
"group",
|
|
214
|
+
c.group
|
|
215
|
+
]
|
|
216
|
+
]);
|
|
217
|
+
case "PrincipalDeleted" :
|
|
218
|
+
return obj("PrincipalDeleted", [[
|
|
219
|
+
"principal",
|
|
220
|
+
c.principal.providerId
|
|
221
|
+
]]);
|
|
222
|
+
case "TokenDrawn" :
|
|
223
|
+
return obj("TokenDrawn", [[
|
|
224
|
+
"length",
|
|
225
|
+
c.length
|
|
226
|
+
]]);
|
|
227
|
+
case "Hashed" :
|
|
228
|
+
return obj("Hashed", [[
|
|
229
|
+
"input",
|
|
230
|
+
c.input
|
|
231
|
+
]]);
|
|
232
|
+
}
|
|
233
|
+
}
|
|
234
|
+
|
|
235
|
+
let Capabilities;
|
|
236
|
+
|
|
237
|
+
let Geocoding;
|
|
238
|
+
|
|
239
|
+
let Messaging;
|
|
240
|
+
|
|
241
|
+
let IdentityProvider;
|
|
242
|
+
|
|
243
|
+
let Secrets;
|
|
244
|
+
|
|
245
|
+
export {
|
|
246
|
+
Capabilities,
|
|
247
|
+
Geocoding,
|
|
248
|
+
Messaging,
|
|
249
|
+
IdentityProvider,
|
|
250
|
+
Secrets,
|
|
251
|
+
make,
|
|
252
|
+
toJson,
|
|
253
|
+
}
|
|
254
|
+
/* No side effect */
|
package/src/Flow_GWT.res
CHANGED
|
@@ -20,7 +20,7 @@ open ReventlessCore
|
|
|
20
20
|
// pipe-first so it reads top-to-bottom:
|
|
21
21
|
//
|
|
22
22
|
// module Place = Flow_GWT.CommandStep(PlaceOrder, PlaceOrder_Behavior)
|
|
23
|
-
// module Auto = Flow_GWT.
|
|
23
|
+
// module Auto = Flow_GWT.AutomationSlice(AutoShipOrder, AutoShipOrder_Automation)
|
|
24
24
|
// module Ship = Flow_GWT.CommandStep(ShipOrder, ShipOrder_Behavior)
|
|
25
25
|
// module View = Flow_GWT.ViewStep(Orders, Orders_Projection)
|
|
26
26
|
//
|
|
@@ -77,6 +77,8 @@ type flowState = {
|
|
|
77
77
|
// step falls back to the synthetic `gwt-id` so the existing DCB Flow tests
|
|
78
78
|
// are unchanged.
|
|
79
79
|
lastAggregateId: option<string>,
|
|
80
|
+
// Why the last inbound step produced no commands, when it was refused.
|
|
81
|
+
lastRefusal: option<string>,
|
|
80
82
|
}
|
|
81
83
|
|
|
82
84
|
type flow = promise<flowState>
|
|
@@ -89,6 +91,7 @@ let emptyState = {
|
|
|
89
91
|
lastCommands: [],
|
|
90
92
|
lastPublic: [],
|
|
91
93
|
lastAggregateId: None,
|
|
94
|
+
lastRefusal: None,
|
|
92
95
|
}
|
|
93
96
|
|
|
94
97
|
// Entry point for a chain — an empty flow with no prior history.
|
|
@@ -489,6 +492,8 @@ module AggregateCommandStep = (
|
|
|
489
492
|
|
|
490
493
|
// -- AutomationStep: a policy that reacts to log events and issues a command --
|
|
491
494
|
|
|
495
|
+
// Deprecated: takes an adapter. Use `AutomationSlice`; this goes one release
|
|
496
|
+
// after the examples have moved.
|
|
492
497
|
module AutomationStep = (Spec: Automation_GWT.SliceSpec) => {
|
|
493
498
|
let consumedDecoder = Reventless.DcbDecode.makeDecoder(Spec.consumedEventSchema)
|
|
494
499
|
|
|
@@ -558,6 +563,8 @@ module ViewStep = (
|
|
|
558
563
|
|
|
559
564
|
// -- OutboundStep: an OutboundTranslationSlice's `collect` over the log -------
|
|
560
565
|
|
|
566
|
+
// Deprecated: takes an adapter. Use `OutboundSlice`; this goes one release
|
|
567
|
+
// after the examples have moved.
|
|
561
568
|
module OutboundStep = (Spec: OutboundTranslation_GWT.SliceSpec) => {
|
|
562
569
|
let consumedDecoder = Reventless.DcbDecode.makeDecoder(Spec.consumedEventSchema)
|
|
563
570
|
|
|
@@ -587,6 +594,110 @@ module OutboundStep = (Spec: OutboundTranslation_GWT.SliceSpec) => {
|
|
|
587
594
|
let thenOutboundNothing = flowP => thenOutbound(flowP, [])
|
|
588
595
|
}
|
|
589
596
|
|
|
597
|
+
// -- Slice-as-written steps --------------------------------------------------
|
|
598
|
+
//
|
|
599
|
+
// The same steps over a slice's `Spec` and body, with no adapter. The log keeps
|
|
600
|
+
// no source name, so every mapping is offered every entry; the source id is the
|
|
601
|
+
// producing aggregate's, or "" for a DCB event, which names its own subject.
|
|
602
|
+
|
|
603
|
+
let sourceIdOf = (entry: logEntry) => entry.aggregateId->Option.getOr("")
|
|
604
|
+
|
|
605
|
+
let encodedCommandsMatch = async (flowP: flow, expJson: array<JSON.t>) => {
|
|
606
|
+
let s = await flowP
|
|
607
|
+
let o = switch s.lastRefusal {
|
|
608
|
+
| Some(reason) => Outcome.fail(TranslateError({expected: "(commands)", actual: Some(reason)}))
|
|
609
|
+
| None =>
|
|
610
|
+
s.lastCommands == expJson
|
|
611
|
+
? Outcome.pass
|
|
612
|
+
: Outcome.fail(EventsMismatch({expected: expJson, actual: s.lastCommands}))
|
|
613
|
+
}
|
|
614
|
+
s->recordOutcome(o)
|
|
615
|
+
}
|
|
616
|
+
|
|
617
|
+
module AutomationSlice = (
|
|
618
|
+
Spec: Reventless.AutomationSlice.Spec,
|
|
619
|
+
Automation: Reventless.AutomationSlice.Automation with module Spec := Spec,
|
|
620
|
+
) => {
|
|
621
|
+
module A = Automation_GWT.FromSlice(Spec, Automation)
|
|
622
|
+
|
|
623
|
+
let whenReacts = async (flowP: flow) => {
|
|
624
|
+
let s = await flowP
|
|
625
|
+
let routed =
|
|
626
|
+
s.log->Array.flatMap(entry =>
|
|
627
|
+
A.Route.dispatches->Array.filterMap(d =>
|
|
628
|
+
d.handle(entry.json, ~sourceId=entry->sourceIdOf, A.testContext)
|
|
629
|
+
)
|
|
630
|
+
)
|
|
631
|
+
let {commands, _} = A.sweep(routed)
|
|
632
|
+
{
|
|
633
|
+
...s,
|
|
634
|
+
lastCommands: commands->Array.map(((_id, cmd)) => cmd->Message.encode(Spec.commandSchema)),
|
|
635
|
+
lastRefusal: None,
|
|
636
|
+
}
|
|
637
|
+
}
|
|
638
|
+
|
|
639
|
+
let thenIssuesCommands = (flowP, expected: array<Spec.command>) =>
|
|
640
|
+
encodedCommandsMatch(flowP, expected->Array.map(c => c->Message.encode(Spec.commandSchema)))
|
|
641
|
+
let thenIssuesCommand = (flowP, command) => thenIssuesCommands(flowP, [command])
|
|
642
|
+
let thenIssuesNoCommand = flowP => thenIssuesCommands(flowP, [])
|
|
643
|
+
}
|
|
644
|
+
|
|
645
|
+
module OutboundSlice = (
|
|
646
|
+
Spec: Reventless.OutboundTranslationSlice.Spec,
|
|
647
|
+
Translation: Reventless.OutboundTranslationSlice.Translation with module Spec := Spec,
|
|
648
|
+
) => {
|
|
649
|
+
let consumedDecoder = Reventless.DcbDecode.makeDecoder(Spec.consumedEventSchema)
|
|
650
|
+
|
|
651
|
+
let encItems = (arr: array<(string, Spec.outboundItem)>) =>
|
|
652
|
+
arr->Array.map(((id, item)) => (id, item->Message.encode(Spec.outboundItemSchema)))
|
|
653
|
+
|
|
654
|
+
// Asserts what `collect` queues; `translate` is the slice test's to run.
|
|
655
|
+
let thenOutbound = async (flowP: flow, expected: array<(string, Spec.outboundItem)>) => {
|
|
656
|
+
let s = await flowP
|
|
657
|
+
let collected =
|
|
658
|
+
s.log->Array.flatMap(entry =>
|
|
659
|
+
decodeMatching([entry], consumedDecoder, [])->Array.flatMap(e =>
|
|
660
|
+
Translation.collect(e, ~sourceId=entry->sourceIdOf)
|
|
661
|
+
)
|
|
662
|
+
)
|
|
663
|
+
let actual = encItems(collected)
|
|
664
|
+
let expectedJson = encItems(expected)
|
|
665
|
+
let o =
|
|
666
|
+
actual == expectedJson
|
|
667
|
+
? Outcome.pass
|
|
668
|
+
: Outcome.fail(TodoMismatch({expected: expectedJson, actual}))
|
|
669
|
+
s->recordOutcome(o)
|
|
670
|
+
}
|
|
671
|
+
|
|
672
|
+
let thenOutboundNothing = flowP => thenOutbound(flowP, [])
|
|
673
|
+
}
|
|
674
|
+
|
|
675
|
+
module InboundSlice = (
|
|
676
|
+
Spec: Reventless.InboundTranslationSlice.Spec,
|
|
677
|
+
Translation: Reventless.InboundTranslationSlice.Translation with module Spec := Spec,
|
|
678
|
+
) => {
|
|
679
|
+
module I = InboundTranslation_GWT.FromSlice(Spec, Translation)
|
|
680
|
+
|
|
681
|
+
// Received input becomes the flow's next commands, as an automation's do.
|
|
682
|
+
let whenReceived = async (flowP: flow, json: JSON.t) => {
|
|
683
|
+
let s = await flowP
|
|
684
|
+
switch I.whenReceived(json) {
|
|
685
|
+
| Translated(pairs) => {
|
|
686
|
+
...s,
|
|
687
|
+
lastCommands: pairs->Array.map(((_id, cmd)) => cmd->Message.encode(Spec.commandSchema)),
|
|
688
|
+
lastRefusal: None,
|
|
689
|
+
}
|
|
690
|
+
| NotUnderstood(msg) => {...s, lastCommands: [], lastRefusal: Some(`not understood: ${msg}`)}
|
|
691
|
+
| InputRefused(msg) => {...s, lastCommands: [], lastRefusal: Some(`input refused: ${msg}`)}
|
|
692
|
+
}
|
|
693
|
+
}
|
|
694
|
+
|
|
695
|
+
let thenIssuesCommands = (flowP, expected: array<Spec.command>) =>
|
|
696
|
+
encodedCommandsMatch(flowP, expected->Array.map(c => c->Message.encode(Spec.commandSchema)))
|
|
697
|
+
let thenIssuesCommand = (flowP, command) => thenIssuesCommands(flowP, [command])
|
|
698
|
+
let thenIssuesNoCommand = flowP => thenIssuesCommands(flowP, [])
|
|
699
|
+
}
|
|
700
|
+
|
|
590
701
|
// -- Cross-plugin boundary steps (Phase 3) -----------------------------------
|
|
591
702
|
|
|
592
703
|
// Order-independent comparison for published actions — fan-out order is
|
package/src/Flow_GWT.res.mjs
CHANGED
|
@@ -14,8 +14,10 @@ import * as JestBind$ReventlessGwt from "./JestBind.res.mjs";
|
|
|
14
14
|
import * as Message$ReventlessCore from "@reventlessdev/reventless-core/src/Message.res.mjs";
|
|
15
15
|
import * as DcbValidation$Reventless from "@reventlessdev/reventless-spec/src/components/DcbValidation.res.mjs";
|
|
16
16
|
import * as StubRuntime$ReventlessGwt from "./StubRuntime.res.mjs";
|
|
17
|
+
import * as Automation_GWT$ReventlessGwt from "./Automation_GWT.res.mjs";
|
|
17
18
|
import * as DcbScopeInference$Reventless from "@reventlessdev/reventless-spec/src/components/DcbScopeInference.res.mjs";
|
|
18
19
|
import * as Projection_GWT$ReventlessGwt from "./Projection_GWT.res.mjs";
|
|
20
|
+
import * as InboundTranslation_GWT$ReventlessGwt from "./InboundTranslation_GWT.res.mjs";
|
|
19
21
|
|
|
20
22
|
let emptyState_log = [];
|
|
21
23
|
|
|
@@ -32,7 +34,8 @@ let emptyState = {
|
|
|
32
34
|
lastError: undefined,
|
|
33
35
|
lastCommands: emptyState_lastCommands,
|
|
34
36
|
lastPublic: emptyState_lastPublic,
|
|
35
|
-
lastAggregateId: undefined
|
|
37
|
+
lastAggregateId: undefined,
|
|
38
|
+
lastRefusal: undefined
|
|
36
39
|
};
|
|
37
40
|
|
|
38
41
|
let start = Promise.resolve(emptyState);
|
|
@@ -47,7 +50,8 @@ function recordOutcome(s, o) {
|
|
|
47
50
|
lastError: s.lastError,
|
|
48
51
|
lastCommands: s.lastCommands,
|
|
49
52
|
lastPublic: s.lastPublic,
|
|
50
|
-
lastAggregateId: s.lastAggregateId
|
|
53
|
+
lastAggregateId: s.lastAggregateId,
|
|
54
|
+
lastRefusal: s.lastRefusal
|
|
51
55
|
};
|
|
52
56
|
} else {
|
|
53
57
|
return s;
|
|
@@ -179,7 +183,8 @@ function CommandStep(Spec) {
|
|
|
179
183
|
lastError: s.lastError,
|
|
180
184
|
lastCommands: s.lastCommands,
|
|
181
185
|
lastPublic: s.lastPublic,
|
|
182
|
-
lastAggregateId: s.lastAggregateId
|
|
186
|
+
lastAggregateId: s.lastAggregateId,
|
|
187
|
+
lastRefusal: s.lastRefusal
|
|
183
188
|
};
|
|
184
189
|
};
|
|
185
190
|
let scopeShape = DcbTag$Reventless.sliceShapeFromSchemas("", Spec.commandSchema, Spec.consumedEventSchema, Spec.eventSchema, undefined);
|
|
@@ -212,7 +217,8 @@ function CommandStep(Spec) {
|
|
|
212
217
|
lastError: Message$ReventlessCore.encode(events._0, Spec.errorSchema),
|
|
213
218
|
lastCommands: s.lastCommands,
|
|
214
219
|
lastPublic: s.lastPublic,
|
|
215
|
-
lastAggregateId: undefined
|
|
220
|
+
lastAggregateId: undefined,
|
|
221
|
+
lastRefusal: s.lastRefusal
|
|
216
222
|
};
|
|
217
223
|
}
|
|
218
224
|
let events$1 = events._0;
|
|
@@ -223,7 +229,8 @@ function CommandStep(Spec) {
|
|
|
223
229
|
lastError: undefined,
|
|
224
230
|
lastCommands: s.lastCommands,
|
|
225
231
|
lastPublic: s.lastPublic,
|
|
226
|
-
lastAggregateId: undefined
|
|
232
|
+
lastAggregateId: undefined,
|
|
233
|
+
lastRefusal: s.lastRefusal
|
|
227
234
|
};
|
|
228
235
|
};
|
|
229
236
|
let thenEvents = async (flowP, expected) => {
|
|
@@ -292,7 +299,8 @@ function AggregateCommandStep(Spec) {
|
|
|
292
299
|
lastError: s.lastError,
|
|
293
300
|
lastCommands: s.lastCommands,
|
|
294
301
|
lastPublic: s.lastPublic,
|
|
295
|
-
lastAggregateId: s.lastAggregateId
|
|
302
|
+
lastAggregateId: s.lastAggregateId,
|
|
303
|
+
lastRefusal: s.lastRefusal
|
|
296
304
|
};
|
|
297
305
|
};
|
|
298
306
|
let whenCommand = async (flowP, id, command) => {
|
|
@@ -308,7 +316,8 @@ function AggregateCommandStep(Spec) {
|
|
|
308
316
|
lastError: Message$ReventlessCore.encode(events._0, Spec.errorSchema),
|
|
309
317
|
lastCommands: s.lastCommands,
|
|
310
318
|
lastPublic: s.lastPublic,
|
|
311
|
-
lastAggregateId: id
|
|
319
|
+
lastAggregateId: id,
|
|
320
|
+
lastRefusal: s.lastRefusal
|
|
312
321
|
};
|
|
313
322
|
}
|
|
314
323
|
let events$1 = events._0;
|
|
@@ -319,7 +328,8 @@ function AggregateCommandStep(Spec) {
|
|
|
319
328
|
lastError: undefined,
|
|
320
329
|
lastCommands: s.lastCommands,
|
|
321
330
|
lastPublic: s.lastPublic,
|
|
322
|
-
lastAggregateId: id
|
|
331
|
+
lastAggregateId: id,
|
|
332
|
+
lastRefusal: s.lastRefusal
|
|
323
333
|
};
|
|
324
334
|
};
|
|
325
335
|
let thenEvents = async (flowP, expected) => {
|
|
@@ -404,7 +414,8 @@ function AutomationStep(Spec) {
|
|
|
404
414
|
lastError: s.lastError,
|
|
405
415
|
lastCommands: commands.map(param => Message$ReventlessCore.encode(param[1], Spec.commandSchema)),
|
|
406
416
|
lastPublic: s.lastPublic,
|
|
407
|
-
lastAggregateId: s.lastAggregateId
|
|
417
|
+
lastAggregateId: s.lastAggregateId,
|
|
418
|
+
lastRefusal: s.lastRefusal
|
|
408
419
|
};
|
|
409
420
|
};
|
|
410
421
|
let thenIssuesCommands = async (flowP, expected) => {
|
|
@@ -486,6 +497,142 @@ function OutboundStep(Spec) {
|
|
|
486
497
|
};
|
|
487
498
|
}
|
|
488
499
|
|
|
500
|
+
function sourceIdOf(entry) {
|
|
501
|
+
return Stdlib_Option.getOr(entry.aggregateId, "");
|
|
502
|
+
}
|
|
503
|
+
|
|
504
|
+
async function encodedCommandsMatch(flowP, expJson) {
|
|
505
|
+
let s = await flowP;
|
|
506
|
+
let reason = s.lastRefusal;
|
|
507
|
+
let o = reason !== undefined ? Outcome$ReventlessGwt.fail({
|
|
508
|
+
TAG: "TranslateError",
|
|
509
|
+
expected: "(commands)",
|
|
510
|
+
actual: reason
|
|
511
|
+
}) : (
|
|
512
|
+
Primitive_object.equal(s.lastCommands, expJson) ? Outcome$ReventlessGwt.pass : Outcome$ReventlessGwt.fail({
|
|
513
|
+
TAG: "EventsMismatch",
|
|
514
|
+
expected: expJson,
|
|
515
|
+
actual: s.lastCommands
|
|
516
|
+
})
|
|
517
|
+
);
|
|
518
|
+
return recordOutcome(s, o);
|
|
519
|
+
}
|
|
520
|
+
|
|
521
|
+
function AutomationSlice(Spec) {
|
|
522
|
+
return Automation => {
|
|
523
|
+
let A = Automation_GWT$ReventlessGwt.FromSlice(Spec)(Automation);
|
|
524
|
+
let whenReacts = async flowP => {
|
|
525
|
+
let s = await flowP;
|
|
526
|
+
let routed = s.log.flatMap(entry => Stdlib_Array.filterMap(A.Route.dispatches, d => d.handle(entry.json, Stdlib_Option.getOr(entry.aggregateId, ""), A.testContext)));
|
|
527
|
+
let match = A.sweep(routed);
|
|
528
|
+
return {
|
|
529
|
+
log: s.log,
|
|
530
|
+
outcome: s.outcome,
|
|
531
|
+
lastEvents: s.lastEvents,
|
|
532
|
+
lastError: s.lastError,
|
|
533
|
+
lastCommands: match.commands.map(param => Message$ReventlessCore.encode(param[1], Spec.commandSchema)),
|
|
534
|
+
lastPublic: s.lastPublic,
|
|
535
|
+
lastAggregateId: s.lastAggregateId,
|
|
536
|
+
lastRefusal: undefined
|
|
537
|
+
};
|
|
538
|
+
};
|
|
539
|
+
let thenIssuesCommands = (flowP, expected) => encodedCommandsMatch(flowP, expected.map(c => Message$ReventlessCore.encode(c, Spec.commandSchema)));
|
|
540
|
+
let thenIssuesCommand = (flowP, command) => thenIssuesCommands(flowP, [command]);
|
|
541
|
+
let thenIssuesNoCommand = flowP => thenIssuesCommands(flowP, []);
|
|
542
|
+
return {
|
|
543
|
+
A: A,
|
|
544
|
+
whenReacts: whenReacts,
|
|
545
|
+
thenIssuesCommands: thenIssuesCommands,
|
|
546
|
+
thenIssuesCommand: thenIssuesCommand,
|
|
547
|
+
thenIssuesNoCommand: thenIssuesNoCommand
|
|
548
|
+
};
|
|
549
|
+
};
|
|
550
|
+
}
|
|
551
|
+
|
|
552
|
+
function OutboundSlice(Spec) {
|
|
553
|
+
return Translation => {
|
|
554
|
+
let consumedDecoder = DcbDecode$Reventless.makeDecoder(Spec.consumedEventSchema);
|
|
555
|
+
let encItems = arr => arr.map(param => [
|
|
556
|
+
param[0],
|
|
557
|
+
Message$ReventlessCore.encode(param[1], Spec.outboundItemSchema)
|
|
558
|
+
]);
|
|
559
|
+
let thenOutbound = async (flowP, expected) => {
|
|
560
|
+
let s = await flowP;
|
|
561
|
+
let collected = s.log.flatMap(entry => decodeMatching([entry], consumedDecoder, []).flatMap(e => Translation.collect(e, Stdlib_Option.getOr(entry.aggregateId, ""))));
|
|
562
|
+
let actual = encItems(collected);
|
|
563
|
+
let expectedJson = encItems(expected);
|
|
564
|
+
let o = Primitive_object.equal(actual, expectedJson) ? Outcome$ReventlessGwt.pass : Outcome$ReventlessGwt.fail({
|
|
565
|
+
TAG: "TodoMismatch",
|
|
566
|
+
expected: expectedJson,
|
|
567
|
+
actual: actual
|
|
568
|
+
});
|
|
569
|
+
return recordOutcome(s, o);
|
|
570
|
+
};
|
|
571
|
+
let thenOutboundNothing = flowP => thenOutbound(flowP, []);
|
|
572
|
+
return {
|
|
573
|
+
consumedDecoder: consumedDecoder,
|
|
574
|
+
encItems: encItems,
|
|
575
|
+
thenOutbound: thenOutbound,
|
|
576
|
+
thenOutboundNothing: thenOutboundNothing
|
|
577
|
+
};
|
|
578
|
+
};
|
|
579
|
+
}
|
|
580
|
+
|
|
581
|
+
function InboundSlice(Spec) {
|
|
582
|
+
return Translation => {
|
|
583
|
+
let I = InboundTranslation_GWT$ReventlessGwt.FromSlice(Spec)(Translation);
|
|
584
|
+
let whenReceived = async (flowP, json) => {
|
|
585
|
+
let s = await flowP;
|
|
586
|
+
let pairs = I.whenReceived(json);
|
|
587
|
+
switch (pairs.TAG) {
|
|
588
|
+
case "Translated" :
|
|
589
|
+
return {
|
|
590
|
+
log: s.log,
|
|
591
|
+
outcome: s.outcome,
|
|
592
|
+
lastEvents: s.lastEvents,
|
|
593
|
+
lastError: s.lastError,
|
|
594
|
+
lastCommands: pairs._0.map(param => Message$ReventlessCore.encode(param[1], Spec.commandSchema)),
|
|
595
|
+
lastPublic: s.lastPublic,
|
|
596
|
+
lastAggregateId: s.lastAggregateId,
|
|
597
|
+
lastRefusal: undefined
|
|
598
|
+
};
|
|
599
|
+
case "NotUnderstood" :
|
|
600
|
+
return {
|
|
601
|
+
log: s.log,
|
|
602
|
+
outcome: s.outcome,
|
|
603
|
+
lastEvents: s.lastEvents,
|
|
604
|
+
lastError: s.lastError,
|
|
605
|
+
lastCommands: [],
|
|
606
|
+
lastPublic: s.lastPublic,
|
|
607
|
+
lastAggregateId: s.lastAggregateId,
|
|
608
|
+
lastRefusal: `not understood: ` + pairs._0
|
|
609
|
+
};
|
|
610
|
+
case "InputRefused" :
|
|
611
|
+
return {
|
|
612
|
+
log: s.log,
|
|
613
|
+
outcome: s.outcome,
|
|
614
|
+
lastEvents: s.lastEvents,
|
|
615
|
+
lastError: s.lastError,
|
|
616
|
+
lastCommands: [],
|
|
617
|
+
lastPublic: s.lastPublic,
|
|
618
|
+
lastAggregateId: s.lastAggregateId,
|
|
619
|
+
lastRefusal: `input refused: ` + pairs._0
|
|
620
|
+
};
|
|
621
|
+
}
|
|
622
|
+
};
|
|
623
|
+
let thenIssuesCommands = (flowP, expected) => encodedCommandsMatch(flowP, expected.map(c => Message$ReventlessCore.encode(c, Spec.commandSchema)));
|
|
624
|
+
let thenIssuesCommand = (flowP, command) => thenIssuesCommands(flowP, [command]);
|
|
625
|
+
let thenIssuesNoCommand = flowP => thenIssuesCommands(flowP, []);
|
|
626
|
+
return {
|
|
627
|
+
I: I,
|
|
628
|
+
whenReceived: whenReceived,
|
|
629
|
+
thenIssuesCommands: thenIssuesCommands,
|
|
630
|
+
thenIssuesCommand: thenIssuesCommand,
|
|
631
|
+
thenIssuesNoCommand: thenIssuesNoCommand
|
|
632
|
+
};
|
|
633
|
+
};
|
|
634
|
+
}
|
|
635
|
+
|
|
489
636
|
function sortJson(arr) {
|
|
490
637
|
return arr.toSorted((a, b) => Primitive_string.compare(JSON.stringify(a), JSON.stringify(b)));
|
|
491
638
|
}
|
|
@@ -526,7 +673,8 @@ function ExtensionPointStep(M) {
|
|
|
526
673
|
lastError: s.lastError,
|
|
527
674
|
lastCommands: s.lastCommands,
|
|
528
675
|
lastPublic: publicEvents.map(e => Message$ReventlessCore.encode(e, M.ExtensionPoint.eventSchema)),
|
|
529
|
-
lastAggregateId: s.lastAggregateId
|
|
676
|
+
lastAggregateId: s.lastAggregateId,
|
|
677
|
+
lastRefusal: s.lastRefusal
|
|
530
678
|
};
|
|
531
679
|
};
|
|
532
680
|
let thenPublicEvents = async (flowP, expected) => {
|
|
@@ -587,7 +735,8 @@ function ExtensionStep(M) {
|
|
|
587
735
|
lastError: s.lastError,
|
|
588
736
|
lastCommands: nested.flat(),
|
|
589
737
|
lastPublic: s.lastPublic,
|
|
590
|
-
lastAggregateId: s.lastAggregateId
|
|
738
|
+
lastAggregateId: s.lastAggregateId,
|
|
739
|
+
lastRefusal: s.lastRefusal
|
|
591
740
|
};
|
|
592
741
|
};
|
|
593
742
|
let thenIssuesCommands = async (flowP, expected) => {
|
|
@@ -637,6 +786,11 @@ export {
|
|
|
637
786
|
AutomationStep,
|
|
638
787
|
ViewStep,
|
|
639
788
|
OutboundStep,
|
|
789
|
+
sourceIdOf,
|
|
790
|
+
encodedCommandsMatch,
|
|
791
|
+
AutomationSlice,
|
|
792
|
+
OutboundSlice,
|
|
793
|
+
InboundSlice,
|
|
640
794
|
sortJson,
|
|
641
795
|
ExtensionPointStep,
|
|
642
796
|
ExtensionStep,
|