@reventlessdev/reventless-gwt 1.0.0-alpha.114 → 1.0.0-alpha.116

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 (88) hide show
  1. package/CHANGELOG.md +19 -0
  2. package/package.json +5 -12
  3. package/rescript.json +0 -1
  4. package/src/JestBind.res +21 -22
  5. package/src/JestBind.res.mjs +15 -11
  6. package/src/RunnerHook.res +38 -0
  7. package/src/RunnerHook.res.mjs +26 -0
  8. package/bin/reventless-dev.mjs +0 -21
  9. package/src/Bind.res +0 -29
  10. package/src/Bind.res.mjs +0 -22
  11. package/src/BuildClassifier.res +0 -147
  12. package/src/BuildClassifier.res.mjs +0 -136
  13. package/src/Cancellation.res +0 -37
  14. package/src/Cancellation.res.mjs +0 -46
  15. package/src/ChildProcess.res +0 -102
  16. package/src/ChildProcess.res.mjs +0 -107
  17. package/src/Cli.res +0 -905
  18. package/src/Cli.res.mjs +0 -952
  19. package/src/Collector.res +0 -212
  20. package/src/Collector.res.mjs +0 -218
  21. package/src/ComponentMeta.res +0 -77
  22. package/src/ComponentMeta.res.mjs +0 -91
  23. package/src/ComponentScan.res +0 -103
  24. package/src/ComponentScan.res.mjs +0 -105
  25. package/src/Discovery.res +0 -105
  26. package/src/Discovery.res.mjs +0 -99
  27. package/src/DomainDeadCode.res +0 -98
  28. package/src/DomainDeadCode.res.mjs +0 -72
  29. package/src/DomainGraph.res +0 -0
  30. package/src/DomainGraph.res.mjs +0 -0
  31. package/src/Filter.res +0 -45
  32. package/src/Filter.res.mjs +0 -47
  33. package/src/FormatterHuman.res +0 -109
  34. package/src/FormatterHuman.res.mjs +0 -115
  35. package/src/FormatterJson.res +0 -264
  36. package/src/FormatterJson.res.mjs +0 -322
  37. package/src/FormatterJunit.res +0 -93
  38. package/src/FormatterJunit.res.mjs +0 -90
  39. package/src/FormatterTap.res +0 -100
  40. package/src/FormatterTap.res.mjs +0 -131
  41. package/src/FormatterVsCode.res +0 -352
  42. package/src/FormatterVsCode.res.mjs +0 -546
  43. package/src/Loader.res +0 -24
  44. package/src/Loader.res.mjs +0 -23
  45. package/src/PackageScan.res +0 -80
  46. package/src/PackageScan.res.mjs +0 -81
  47. package/src/PlatformRunner.res +0 -191
  48. package/src/PlatformRunner.res.mjs +0 -178
  49. package/src/PlatformScan.res +0 -142
  50. package/src/PlatformScan.res.mjs +0 -132
  51. package/src/ProcessManager.res +0 -135
  52. package/src/ProcessManager.res.mjs +0 -119
  53. package/src/RunWorker.res +0 -24
  54. package/src/RunWorker.res.mjs +0 -16
  55. package/src/RunnerTypes.res +0 -68
  56. package/src/RunnerTypes.res.mjs +0 -60
  57. package/src/Watch.res +0 -108
  58. package/src/Watch.res.mjs +0 -85
  59. package/src/WatcherProbe.res +0 -56
  60. package/src/WatcherProbe.res.mjs +0 -59
  61. package/src/Worker.res +0 -24
  62. package/src/Worker.res.mjs +0 -9
  63. package/tests/BuildClassifierTest.res +0 -133
  64. package/tests/BuildClassifierTest.res.mjs +0 -176
  65. package/tests/CliRunEntryTest.res +0 -57
  66. package/tests/CliRunEntryTest.res.mjs +0 -65
  67. package/tests/CliWatchScopeTest.res +0 -62
  68. package/tests/CliWatchScopeTest.res.mjs +0 -95
  69. package/tests/ComponentMetaTest.res +0 -67
  70. package/tests/ComponentMetaTest.res.mjs +0 -71
  71. package/tests/DiscoveryTest.res +0 -42
  72. package/tests/DiscoveryTest.res.mjs +0 -43
  73. package/tests/DomainDeadCodeTest.res +0 -119
  74. package/tests/DomainDeadCodeTest.res.mjs +0 -158
  75. package/tests/DomainGraphTest.res +0 -448
  76. package/tests/DomainGraphTest.res.mjs +0 -505
  77. package/tests/FormatterGoldenTest.res +0 -125
  78. package/tests/FormatterGoldenTest.res.mjs +0 -162
  79. package/tests/FormatterVsCodeMessageTest.res +0 -41
  80. package/tests/FormatterVsCodeMessageTest.res.mjs +0 -42
  81. package/tests/PlatformRunnerTest.res +0 -66
  82. package/tests/PlatformRunnerTest.res.mjs +0 -85
  83. package/tests/PlatformScanTest.res +0 -61
  84. package/tests/PlatformScanTest.res.mjs +0 -56
  85. package/tests/RunnerUnitTest.res +0 -219
  86. package/tests/RunnerUnitTest.res.mjs +0 -244
  87. package/tests/WatchDebounceTest.res +0 -106
  88. package/tests/WatchDebounceTest.res.mjs +0 -128
@@ -1,505 +0,0 @@
1
- // Generated by ReScript, PLEASE EDIT WITH CARE
2
-
3
- import * as Stdlib_Option from "@rescript/runtime/lib/es6/Stdlib_Option.js";
4
- import * as Primitive_object from "@rescript/runtime/lib/es6/Primitive_object.js";
5
- import * as Primitive_option from "@rescript/runtime/lib/es6/Primitive_option.js";
6
- import * as DomainGraph$ReventlessGwt from "../src/DomainGraph.res.mjs";
7
-
8
- function command(name, mutationField, apiExposedOpt) {
9
- let apiExposed = apiExposedOpt !== undefined ? Primitive_option.valFromOption(apiExposedOpt) : undefined;
10
- return {
11
- name: name,
12
- schema: "",
13
- level: "Instance",
14
- aggregateIdField: undefined,
15
- mutationField: mutationField,
16
- references: [],
17
- allowedStates: undefined,
18
- apiExposed: apiExposed
19
- };
20
- }
21
-
22
- function evt(name) {
23
- return {
24
- name: name,
25
- schema: "",
26
- references: []
27
- };
28
- }
29
-
30
- function writable(name, commandsOpt, producesOpt, consumesOpt, linkedViewsOpt, eventsOpt, chapterOpt) {
31
- let commands = commandsOpt !== undefined ? commandsOpt : [];
32
- let produces = producesOpt !== undefined ? producesOpt : [];
33
- let consumes = consumesOpt !== undefined ? consumesOpt : [];
34
- let linkedViews = linkedViewsOpt !== undefined ? linkedViewsOpt : [];
35
- let events = eventsOpt !== undefined ? eventsOpt : [];
36
- let chapter = chapterOpt !== undefined ? Primitive_option.valFromOption(chapterOpt) : undefined;
37
- return {
38
- name: name,
39
- commands: commands,
40
- producedEventTypes: produces,
41
- consumedEventTypes: consumes,
42
- linkedViews: linkedViews,
43
- consistencyRead: undefined,
44
- events: events,
45
- chapter: chapter
46
- };
47
- }
48
-
49
- function queryable(name, consumesOpt, visibilityOpt, chapterOpt) {
50
- let consumes = consumesOpt !== undefined ? consumesOpt : [];
51
- let visibility = visibilityOpt !== undefined ? Primitive_option.valFromOption(visibilityOpt) : undefined;
52
- let chapter = chapterOpt !== undefined ? Primitive_option.valFromOption(chapterOpt) : undefined;
53
- return {
54
- name: name,
55
- queryField: "",
56
- schema: "",
57
- consumedEventTypes: consumes,
58
- linkedWriteSide: [],
59
- labelField: "id",
60
- searchableFields: [],
61
- statusField: undefined,
62
- visibility: visibility,
63
- chapter: chapter
64
- };
65
- }
66
-
67
- function automation(name, consumesOpt, producesOpt, targetOpt, chapterOpt) {
68
- let consumes = consumesOpt !== undefined ? consumesOpt : [];
69
- let produces = producesOpt !== undefined ? producesOpt : [];
70
- let target = targetOpt !== undefined ? targetOpt : "";
71
- let chapter = chapterOpt !== undefined ? Primitive_option.valFromOption(chapterOpt) : undefined;
72
- return {
73
- name: name,
74
- consumedEventTypes: consumes,
75
- producedCommandTypes: produces,
76
- targetName: target,
77
- chapter: chapter
78
- };
79
- }
80
-
81
- function inbound(name, producesOpt, targetOpt, extOpt, chapterOpt) {
82
- let produces = producesOpt !== undefined ? producesOpt : [];
83
- let target = targetOpt !== undefined ? targetOpt : "";
84
- let ext = extOpt !== undefined ? Primitive_option.valFromOption(extOpt) : undefined;
85
- let chapter = chapterOpt !== undefined ? Primitive_option.valFromOption(chapterOpt) : undefined;
86
- return {
87
- name: name,
88
- commandTypes: produces,
89
- targetName: target,
90
- externalSystem: ext,
91
- chapter: chapter
92
- };
93
- }
94
-
95
- function outbound(name, consumesOpt, producesOpt, targetOpt, extOpt, chapterOpt) {
96
- let consumes = consumesOpt !== undefined ? consumesOpt : [];
97
- let produces = producesOpt !== undefined ? producesOpt : [];
98
- let target = targetOpt !== undefined ? Primitive_option.valFromOption(targetOpt) : undefined;
99
- let ext = extOpt !== undefined ? Primitive_option.valFromOption(extOpt) : undefined;
100
- let chapter = chapterOpt !== undefined ? Primitive_option.valFromOption(chapterOpt) : undefined;
101
- return {
102
- name: name,
103
- consumedEventTypes: consumes,
104
- inboundCommandTypes: produces,
105
- targetName: target,
106
- externalSystem: ext,
107
- chapter: chapter
108
- };
109
- }
110
-
111
- function structure(aggregatesOpt, readModelsOpt, stateViewSlicesOpt, stateChangeSlicesOpt, automationSlicesOpt, outboundTranslationSlicesOpt, inboundTranslationSlicesOpt, extensionPointsOpt) {
112
- let aggregates = aggregatesOpt !== undefined ? aggregatesOpt : [];
113
- let readModels = readModelsOpt !== undefined ? readModelsOpt : [];
114
- let stateViewSlices = stateViewSlicesOpt !== undefined ? stateViewSlicesOpt : [];
115
- let stateChangeSlices = stateChangeSlicesOpt !== undefined ? stateChangeSlicesOpt : [];
116
- let automationSlices = automationSlicesOpt !== undefined ? automationSlicesOpt : [];
117
- let outboundTranslationSlices = outboundTranslationSlicesOpt !== undefined ? outboundTranslationSlicesOpt : [];
118
- let inboundTranslationSlices = inboundTranslationSlicesOpt !== undefined ? inboundTranslationSlicesOpt : [];
119
- let extensionPoints = extensionPointsOpt !== undefined ? extensionPointsOpt : [];
120
- return {
121
- readModels: readModels,
122
- stateViewSlices: stateViewSlices,
123
- stateChangeSlices: stateChangeSlices,
124
- aggregates: aggregates,
125
- automationSlices: automationSlices,
126
- outboundTranslationSlices: outboundTranslationSlices,
127
- inboundTranslationSlices: inboundTranslationSlices,
128
- extensions: [],
129
- extensionPoints: extensionPoints
130
- };
131
- }
132
-
133
- function hasEdge(g, from, to, kind) {
134
- return g.edges.some(e => {
135
- if (e.from === from && e.to === to) {
136
- return Primitive_object.equal(e.kind, kind);
137
- } else {
138
- return false;
139
- }
140
- });
141
- }
142
-
143
- function edgeLabel(g, from, to, kind) {
144
- return Stdlib_Option.flatMap(g.edges.find(e => {
145
- if (e.from === from && e.to === to) {
146
- return Primitive_object.equal(e.kind, kind);
147
- } else {
148
- return false;
149
- }
150
- }), e => e.label);
151
- }
152
-
153
- function nodeKind(g, id) {
154
- return Stdlib_Option.map(g.nodes.find(n => n.id === id), n => n.kind);
155
- }
156
-
157
- globalThis.describe("DomainGraph.build", () => {
158
- globalThis.test("Command → Aggregate → Event → ReadModel (DCB consumedEventTypes)", async () => {
159
- let shop = structure([writable("Order", [command("Place", "Shop_Order_Place", undefined)], ["Shop.Placed"], undefined, undefined, undefined, undefined)], undefined, [queryable("OrderView", ["Shop.Placed"], undefined, undefined)], undefined, undefined, undefined, undefined, undefined);
160
- let g = DomainGraph$ReventlessGwt.build([[
161
- "Shop",
162
- shop
163
- ]]);
164
- globalThis.expect(nodeKind(g, "Shop_Order_Place")).toEqual("Command");
165
- globalThis.expect(nodeKind(g, "Shop:Order")).toEqual("Aggregate");
166
- globalThis.expect(nodeKind(g, "Shop.Placed")).toEqual("Event");
167
- globalThis.expect(nodeKind(g, "Shop:OrderView")).toEqual("StateViewSlice");
168
- globalThis.expect(hasEdge(g, "Shop_Order_Place", "Shop:Order", "Handles")).toBe(true);
169
- globalThis.expect(hasEdge(g, "Shop:Order", "Shop.Placed", "Emits")).toBe(true);
170
- globalThis.expect(hasEdge(g, "Shop.Placed", "Shop:OrderView", "Projects")).toBe(true);
171
- });
172
- globalThis.test("payload-less events (in `events`, not producedEventTypes) still get an emitted node", async () => {
173
- let shop = structure([writable("Category", undefined, ["Catalog.Added"], undefined, undefined, [
174
- {
175
- name: "Added",
176
- schema: "",
177
- references: []
178
- },
179
- {
180
- name: "Archived",
181
- schema: "",
182
- references: []
183
- }
184
- ], undefined)], undefined, undefined, undefined, undefined, undefined, undefined, undefined);
185
- let g = DomainGraph$ReventlessGwt.build([[
186
- "Catalog",
187
- shop
188
- ]]);
189
- globalThis.expect(nodeKind(g, "Catalog.Added")).toEqual("Event");
190
- globalThis.expect(nodeKind(g, "Catalog.Archived")).toEqual("Event");
191
- globalThis.expect(hasEdge(g, "Catalog:Category", "Catalog.Added", "Emits")).toBe(true);
192
- globalThis.expect(hasEdge(g, "Catalog:Category", "Catalog.Archived", "Emits")).toBe(true);
193
- });
194
- globalThis.test("a payload-less event also projects into the aggregate's linked view", async () => {
195
- let shop = structure([writable("Category", undefined, ["Catalog.Added"], undefined, ["Categories"], [
196
- {
197
- name: "Added",
198
- schema: "",
199
- references: []
200
- },
201
- {
202
- name: "Archived",
203
- schema: "",
204
- references: []
205
- }
206
- ], undefined)], undefined, undefined, undefined, undefined, undefined, undefined, undefined);
207
- let g = DomainGraph$ReventlessGwt.build([[
208
- "Catalog",
209
- shop
210
- ]]);
211
- globalThis.expect(hasEdge(g, "Catalog.Added", "Catalog:Categories", "Projects")).toBe(true);
212
- globalThis.expect(hasEdge(g, "Catalog.Archived", "Catalog:Categories", "Projects")).toBe(true);
213
- });
214
- globalThis.test("an Internal StateViewSlice still gets a node + projects edge (dev graph shows it)", async () => {
215
- let shop = structure([writable("Order", undefined, ["Shop.Placed"], undefined, undefined, undefined, undefined)], undefined, [queryable("AvailableView", ["Shop.Placed"], "Internal", undefined)], undefined, undefined, undefined, undefined, undefined);
216
- let g = DomainGraph$ReventlessGwt.build([[
217
- "Shop",
218
- shop
219
- ]]);
220
- globalThis.expect(nodeKind(g, "Shop:AvailableView")).toEqual("StateViewSlice");
221
- globalThis.expect(hasEdge(g, "Shop.Placed", "Shop:AvailableView", "Projects")).toBe(true);
222
- });
223
- globalThis.test("classic linkedViews draws each produced event into the linked read model", async () => {
224
- let shop = structure([writable("Order", undefined, [
225
- "Shop.Placed",
226
- "Shop.Shipped"
227
- ], undefined, ["Orders"], undefined, undefined)], [queryable("Orders", undefined, undefined, undefined)], undefined, undefined, undefined, undefined, undefined, undefined);
228
- let g = DomainGraph$ReventlessGwt.build([[
229
- "Shop",
230
- shop
231
- ]]);
232
- globalThis.expect(hasEdge(g, "Shop.Placed", "Shop:Orders", "Projects")).toBe(true);
233
- globalThis.expect(hasEdge(g, "Shop.Shipped", "Shop:Orders", "Projects")).toBe(true);
234
- });
235
- globalThis.test("automation slices are triggered by their consumed events", async () => {
236
- let shop = structure([writable("Order", undefined, ["Shop.Placed"], undefined, undefined, undefined, undefined)], undefined, undefined, undefined, [automation("Notify", ["Shop.Placed"], undefined, undefined, undefined)], undefined, undefined, undefined);
237
- let g = DomainGraph$ReventlessGwt.build([[
238
- "Shop",
239
- shop
240
- ]]);
241
- globalThis.expect(nodeKind(g, "Shop:Notify")).toEqual("AutomationSlice");
242
- globalThis.expect(hasEdge(g, "Shop.Placed", "Shop:Notify", "Triggers")).toBe(true);
243
- });
244
- globalThis.test("an automation routes to the specific command it raises on its target", async () => {
245
- let shop = structure(undefined, undefined, undefined, [writable("Ship", [
246
- command("ShipOrder", "Shop_Ship_ShipOrder", undefined),
247
- command("Place", "Shop_Ship_Place", undefined)
248
- ], ["Shop.Shipped"], undefined, undefined, undefined, undefined)], [automation("AutoShip", ["Shop.Placed"], ["AutoShip.ShipOrder"], "Ship", undefined)], undefined, undefined, undefined);
249
- let g = DomainGraph$ReventlessGwt.build([[
250
- "Shop",
251
- shop
252
- ]]);
253
- globalThis.expect(hasEdge(g, "Shop:AutoShip", "Shop_Ship_ShipOrder", "DelegatesTo")).toBe(true);
254
- globalThis.expect(hasEdge(g, "Shop:AutoShip", "Shop_Ship_Place", "DelegatesTo")).toBe(false);
255
- });
256
- globalThis.test("an inbound translation routes to the command it raises on its target", async () => {
257
- let shop = structure(undefined, undefined, undefined, [writable("Product", [command("Add", "Shop_Product_Add", undefined)], undefined, undefined, undefined, undefined, undefined)], undefined, undefined, [inbound("ImportProduct", ["ImportProduct.Add"], "Product", undefined, undefined)], undefined);
258
- let g = DomainGraph$ReventlessGwt.build([[
259
- "Shop",
260
- shop
261
- ]]);
262
- globalThis.expect(nodeKind(g, "Shop:ImportProduct")).toEqual("InboundTranslationSlice");
263
- globalThis.expect(hasEdge(g, "Shop:ImportProduct", "Shop_Product_Add", "DelegatesTo")).toBe(true);
264
- });
265
- globalThis.test("an outbound translation with a target routes to the command it raises", async () => {
266
- let shop = structure(undefined, undefined, undefined, [writable("Product", [command("Sync", "Shop_Product_Sync", undefined)], undefined, undefined, undefined, undefined, undefined)], undefined, [outbound("ExportProduct", ["Shop.Added"], ["ExportProduct.Sync"], "Product", undefined, undefined)], undefined, undefined);
267
- let g = DomainGraph$ReventlessGwt.build([[
268
- "Shop",
269
- shop
270
- ]]);
271
- globalThis.expect(hasEdge(g, "Shop:ExportProduct", "Shop_Product_Sync", "DelegatesTo")).toBe(true);
272
- });
273
- globalThis.test("an inbound translation naming an external system draws a box feeding it", async () => {
274
- let shop = structure(undefined, undefined, undefined, undefined, undefined, undefined, [inbound("ImportProduct", ["ImportProduct.Add"], "Product", "SupplierFeed", undefined)], undefined);
275
- let g = DomainGraph$ReventlessGwt.build([[
276
- "Shop",
277
- shop
278
- ]]);
279
- globalThis.expect(nodeKind(g, "ext:SupplierFeed")).toEqual("ExternalSystem");
280
- globalThis.expect(Stdlib_Option.map(g.nodes.find(n => n.id === "ext:SupplierFeed"), n => n.plugin)).toEqual("");
281
- globalThis.expect(hasEdge(g, "ext:SupplierFeed", "Shop:ImportProduct", "TranslatesIn")).toBe(true);
282
- globalThis.expect(edgeLabel(g, "ext:SupplierFeed", "Shop:ImportProduct", "TranslatesIn")).toEqual(undefined);
283
- });
284
- globalThis.test("an outbound translation naming an external system feeds the box", async () => {
285
- let shop = structure(undefined, undefined, undefined, undefined, undefined, [outbound("SendEmail", ["Shop.Placed"], undefined, Primitive_option.some(undefined), "EmailService", undefined)], undefined, undefined);
286
- let g = DomainGraph$ReventlessGwt.build([[
287
- "Shop",
288
- shop
289
- ]]);
290
- globalThis.expect(nodeKind(g, "ext:EmailService")).toEqual("ExternalSystem");
291
- globalThis.expect(hasEdge(g, "Shop:SendEmail", "ext:EmailService", "TranslatesOut")).toBe(true);
292
- globalThis.expect(edgeLabel(g, "Shop:SendEmail", "ext:EmailService", "TranslatesOut")).toEqual(undefined);
293
- });
294
- globalThis.test("translation slices with no external system draw no box (opt-in)", async () => {
295
- let shop = structure(undefined, undefined, undefined, undefined, undefined, undefined, [inbound("ImportProduct", undefined, "Product", undefined, undefined)], undefined);
296
- let g = DomainGraph$ReventlessGwt.build([[
297
- "Shop",
298
- shop
299
- ]]);
300
- globalThis.expect(g.nodes.some(n => n.kind === "ExternalSystem")).toBe(false);
301
- });
302
- globalThis.test("two slices naming the same external system share one deduped box", async () => {
303
- let a = structure(undefined, undefined, undefined, undefined, undefined, [outbound("SendEmailA", ["A.X"], undefined, Primitive_option.some(undefined), "EmailService", undefined)], undefined, undefined);
304
- let b = structure(undefined, undefined, undefined, undefined, undefined, undefined, [inbound("FromEmail", ["FromEmail.Record"], "Inbox", "EmailService", undefined)], undefined);
305
- let g = DomainGraph$ReventlessGwt.build([
306
- [
307
- "PluginA",
308
- a
309
- ],
310
- [
311
- "PluginB",
312
- b
313
- ]
314
- ]);
315
- globalThis.expect(g.nodes.filter(n => n.id === "ext:EmailService").length).toBe(1);
316
- globalThis.expect(hasEdge(g, "PluginA:SendEmailA", "ext:EmailService", "TranslatesOut")).toBe(true);
317
- globalThis.expect(hasEdge(g, "ext:EmailService", "PluginB:FromEmail", "TranslatesIn")).toBe(true);
318
- });
319
- globalThis.test("an event produced by two write-sides is one node with two emit edges", async () => {
320
- let shop = structure([
321
- writable("A", undefined, ["Shop.Touched"], undefined, undefined, undefined, undefined),
322
- writable("B", undefined, ["Shop.Touched"], undefined, undefined, undefined, undefined)
323
- ], undefined, undefined, undefined, undefined, undefined, undefined, undefined);
324
- let g = DomainGraph$ReventlessGwt.build([[
325
- "Shop",
326
- shop
327
- ]]);
328
- globalThis.expect(g.nodes.filter(n => n.id === "Shop.Touched").length).toBe(1);
329
- globalThis.expect(hasEdge(g, "Shop:A", "Shop.Touched", "Emits")).toBe(true);
330
- globalThis.expect(hasEdge(g, "Shop:B", "Shop.Touched", "Emits")).toBe(true);
331
- });
332
- globalThis.test("an extension renders the cross-plugin event flow EP→event→Extension→delegate", async () => {
333
- let extension_delegateNames = ["ProductDemand"];
334
- let extension_eventTypes = ["Ordering.Orders.ItemOrdered"];
335
- let extension_commandTypes = [];
336
- let extension = {
337
- name: "Ordering.Orders",
338
- delegateNames: extension_delegateNames,
339
- eventTypes: extension_eventTypes,
340
- commandTypes: extension_commandTypes
341
- };
342
- let init = structure([writable("ProductDemand", undefined, ["Catalog.Recorded"], undefined, undefined, undefined, undefined)], undefined, undefined, undefined, undefined, undefined, undefined, undefined);
343
- let catalog_readModels = init.readModels;
344
- let catalog_stateViewSlices = init.stateViewSlices;
345
- let catalog_stateChangeSlices = init.stateChangeSlices;
346
- let catalog_aggregates = init.aggregates;
347
- let catalog_automationSlices = init.automationSlices;
348
- let catalog_outboundTranslationSlices = init.outboundTranslationSlices;
349
- let catalog_inboundTranslationSlices = init.inboundTranslationSlices;
350
- let catalog_extensions = [extension];
351
- let catalog_extensionPoints = init.extensionPoints;
352
- let catalog = {
353
- readModels: catalog_readModels,
354
- stateViewSlices: catalog_stateViewSlices,
355
- stateChangeSlices: catalog_stateChangeSlices,
356
- aggregates: catalog_aggregates,
357
- automationSlices: catalog_automationSlices,
358
- outboundTranslationSlices: catalog_outboundTranslationSlices,
359
- inboundTranslationSlices: catalog_inboundTranslationSlices,
360
- extensions: catalog_extensions,
361
- extensionPoints: catalog_extensionPoints
362
- };
363
- let g = DomainGraph$ReventlessGwt.build([[
364
- "Catalog",
365
- catalog
366
- ]]);
367
- globalThis.expect(nodeKind(g, "Ordering:ep:Ordering.Orders")).toEqual("ExtensionPoint");
368
- globalThis.expect(hasEdge(g, "Ordering:ep:Ordering.Orders", "Ordering.Orders.ItemOrdered", "Publishes")).toBe(true);
369
- globalThis.expect(hasEdge(g, "Ordering.Orders.ItemOrdered", "Catalog:ext:Ordering.Orders", "Consumes")).toBe(true);
370
- globalThis.expect(hasEdge(g, "Catalog:ext:Ordering.Orders", "Catalog:ProductDemand", "DelegatesTo")).toBe(true);
371
- let protoEvent = Stdlib_Option.getOrThrow(g.nodes.find(n => n.id === "Ordering.Orders.ItemOrdered"), undefined);
372
- globalThis.expect(protoEvent.plugin).toBe("");
373
- let ext = Stdlib_Option.getOrThrow(g.nodes.find(n => n.id === "Catalog:ext:Ordering.Orders"), undefined);
374
- globalThis.expect(ext.label).toBe("Ordering.Orders.Catalog");
375
- });
376
- globalThis.test("an extension wires to the command(s) it creates, not straight to the delegate", async () => {
377
- let extension_delegateNames = ["ProductDemand"];
378
- let extension_eventTypes = ["Ordering.Orders.ItemOrdered"];
379
- let extension_commandTypes = [];
380
- let extension = {
381
- name: "Ordering.Orders",
382
- delegateNames: extension_delegateNames,
383
- eventTypes: extension_eventTypes,
384
- commandTypes: extension_commandTypes
385
- };
386
- let init = structure(undefined, undefined, undefined, [writable("ProductDemand", [command("RecordDemand", "Catalog_ProductDemand_RecordDemand", undefined)], ["Catalog.Recorded"], undefined, undefined, undefined, undefined)], undefined, undefined, undefined, undefined);
387
- let catalog_readModels = init.readModels;
388
- let catalog_stateViewSlices = init.stateViewSlices;
389
- let catalog_stateChangeSlices = init.stateChangeSlices;
390
- let catalog_aggregates = init.aggregates;
391
- let catalog_automationSlices = init.automationSlices;
392
- let catalog_outboundTranslationSlices = init.outboundTranslationSlices;
393
- let catalog_inboundTranslationSlices = init.inboundTranslationSlices;
394
- let catalog_extensions = [extension];
395
- let catalog_extensionPoints = init.extensionPoints;
396
- let catalog = {
397
- readModels: catalog_readModels,
398
- stateViewSlices: catalog_stateViewSlices,
399
- stateChangeSlices: catalog_stateChangeSlices,
400
- aggregates: catalog_aggregates,
401
- automationSlices: catalog_automationSlices,
402
- outboundTranslationSlices: catalog_outboundTranslationSlices,
403
- inboundTranslationSlices: catalog_inboundTranslationSlices,
404
- extensions: catalog_extensions,
405
- extensionPoints: catalog_extensionPoints
406
- };
407
- let g = DomainGraph$ReventlessGwt.build([[
408
- "Catalog",
409
- catalog
410
- ]]);
411
- globalThis.expect(hasEdge(g, "Catalog:ext:Ordering.Orders", "Catalog_ProductDemand_RecordDemand", "DelegatesTo")).toBe(true);
412
- globalThis.expect(hasEdge(g, "Catalog_ProductDemand_RecordDemand", "Catalog:ProductDemand", "Handles")).toBe(true);
413
- globalThis.expect(hasEdge(g, "Catalog:ext:Ordering.Orders", "Catalog:ProductDemand", "DelegatesTo")).toBe(false);
414
- });
415
- globalThis.test("an extension with no commands falls back to delegating to the write-side", async () => {
416
- let extension_delegateNames = ["ProductDemand"];
417
- let extension_eventTypes = ["Ordering.Orders.ItemOrdered"];
418
- let extension_commandTypes = [];
419
- let extension = {
420
- name: "Ordering.Orders",
421
- delegateNames: extension_delegateNames,
422
- eventTypes: extension_eventTypes,
423
- commandTypes: extension_commandTypes
424
- };
425
- let init = structure([writable("ProductDemand", undefined, ["Catalog.Recorded"], undefined, undefined, undefined, undefined)], undefined, undefined, undefined, undefined, undefined, undefined, undefined);
426
- let catalog_readModels = init.readModels;
427
- let catalog_stateViewSlices = init.stateViewSlices;
428
- let catalog_stateChangeSlices = init.stateChangeSlices;
429
- let catalog_aggregates = init.aggregates;
430
- let catalog_automationSlices = init.automationSlices;
431
- let catalog_outboundTranslationSlices = init.outboundTranslationSlices;
432
- let catalog_inboundTranslationSlices = init.inboundTranslationSlices;
433
- let catalog_extensions = [extension];
434
- let catalog_extensionPoints = init.extensionPoints;
435
- let catalog = {
436
- readModels: catalog_readModels,
437
- stateViewSlices: catalog_stateViewSlices,
438
- stateChangeSlices: catalog_stateChangeSlices,
439
- aggregates: catalog_aggregates,
440
- automationSlices: catalog_automationSlices,
441
- outboundTranslationSlices: catalog_outboundTranslationSlices,
442
- inboundTranslationSlices: catalog_inboundTranslationSlices,
443
- extensions: catalog_extensions,
444
- extensionPoints: catalog_extensionPoints
445
- };
446
- let g = DomainGraph$ReventlessGwt.build([[
447
- "Catalog",
448
- catalog
449
- ]]);
450
- globalThis.expect(hasEdge(g, "Catalog:ext:Ordering.Orders", "Catalog:ProductDemand", "DelegatesTo")).toBe(true);
451
- });
452
- globalThis.test("an owned extension point is fed by the producers of its source events", async () => {
453
- let ep_delegateNames = ["CatalogDcbEventLog"];
454
- let ep_sourceEventTypes = ["Catalog.ProductAdded"];
455
- let ep_commandTypes = [];
456
- let ep = {
457
- name: "Catalog.Products",
458
- delegateNames: ep_delegateNames,
459
- sourceEventTypes: ep_sourceEventTypes,
460
- commandTypes: ep_commandTypes
461
- };
462
- let catalog = structure(undefined, undefined, undefined, [writable("AddProduct", [command("AddProduct", "Catalog_AddProduct", undefined)], ["Catalog.ProductAdded"], undefined, undefined, undefined, undefined)], undefined, undefined, undefined, [ep]);
463
- let g = DomainGraph$ReventlessGwt.build([[
464
- "Catalog",
465
- catalog
466
- ]]);
467
- globalThis.expect(nodeKind(g, "Catalog:ep:Catalog.Products")).toEqual("ExtensionPoint");
468
- globalThis.expect(hasEdge(g, "Catalog:AddProduct", "Catalog.ProductAdded", "Emits")).toBe(true);
469
- globalThis.expect(hasEdge(g, "Catalog.ProductAdded", "Catalog:ep:Catalog.Products", "Feeds")).toBe(true);
470
- globalThis.expect(hasEdge(g, "Catalog:ep:Catalog.Products", "Catalog_AddProduct", "RoutesTo")).toBe(false);
471
- });
472
- globalThis.test("an extension point with an inbound command protocol routes to its delegate's commands", async () => {
473
- let ep_delegateNames = ["AddProduct"];
474
- let ep_sourceEventTypes = ["Catalog.ProductAdded"];
475
- let ep_commandTypes = ["Catalog.Products.RequestAddProduct"];
476
- let ep = {
477
- name: "Catalog.Products",
478
- delegateNames: ep_delegateNames,
479
- sourceEventTypes: ep_sourceEventTypes,
480
- commandTypes: ep_commandTypes
481
- };
482
- let catalog = structure(undefined, undefined, undefined, [writable("AddProduct", [command("AddProduct", "Catalog_AddProduct", undefined)], ["Catalog.ProductAdded"], undefined, undefined, undefined, undefined)], undefined, undefined, undefined, [ep]);
483
- let g = DomainGraph$ReventlessGwt.build([[
484
- "Catalog",
485
- catalog
486
- ]]);
487
- globalThis.expect(hasEdge(g, "Catalog:ep:Catalog.Products", "Catalog_AddProduct", "RoutesTo")).toBe(true);
488
- globalThis.expect(hasEdge(g, "Catalog_AddProduct", "Catalog:AddProduct", "Handles")).toBe(true);
489
- });
490
- });
491
-
492
- export {
493
- command,
494
- evt,
495
- writable,
496
- queryable,
497
- automation,
498
- inbound,
499
- outbound,
500
- structure,
501
- hasEdge,
502
- edgeLabel,
503
- nodeKind,
504
- }
505
- /* Not a pure module */
@@ -1,125 +0,0 @@
1
- // Golden-output tests pinning the per-mismatch rendering of the three
2
- // string-emitting formatters:
3
- // - `Outcome.format` (used by the JUnit `<failure>` body)
4
- // - `FormatterHuman.renderMismatch` (terminal output)
5
- // - `FormatterTap.renderMismatchYaml` (TAP YAML diagnostic block)
6
- //
7
- // These three functions are exactly what the deferred `Outcome.mismatch`
8
- // normalization (plan C4) will unify. Pinning their current output byte-for-byte
9
- // lets that refactor prove it preserved Human/TAP rendering — and makes the
10
- // deliberate JUnit change (it currently renders via raw `Outcome.format`, unlike
11
- // the RenderRescript-based Human/TAP) explicit and reviewable rather than silent.
12
- //
13
- // The fixtures cover all 10 mismatch kinds — the full structural variety the
14
- // normalization must preserve: array expected/actual (Events/QueryRows/
15
- // PublishedActions), the Error()/Ok() wrapping with a `None` actual
16
- // (ErrorMismatch), the `key` extra + option rendering (StateMismatch), a
17
- // single-sided actual (NoEventExpected), plain-string (non-JSON) sides
18
- // (TranslateError), the `(id, value)` pair rendering (TodoMismatch), a nested
19
- // JSON value (AppendConditionMismatch), and the `Throw` stack special case.
20
-
21
- open JestGlobals
22
-
23
- let evA = JSON.parseOrThrow(`{"TAG":"ProductAdded","_0":{"productId":"p1","name":"Widget"}}`)
24
- let evB = JSON.parseOrThrow(`{"TAG":"ProductRenamed","_0":{"productId":"p1","name":"Gadget"}}`)
25
- let stateActive = JSON.parseOrThrow(`{"status":"active"}`)
26
- let stateArchived = JSON.parseOrThrow(`{"status":"archived"}`)
27
- let appendExpected = JSON.parseOrThrow(`{"query":[]}`)
28
- let appendActual = JSON.parseOrThrow(`{"query":[{"eventTypes":["ProductAdded"]}]}`)
29
-
30
- type golden = {
31
- name: string,
32
- mismatch: Outcome.mismatch,
33
- format: string,
34
- human: string,
35
- tap: string,
36
- }
37
-
38
- let goldens: array<golden> = [
39
- {
40
- name: "EventsMismatch",
41
- mismatch: EventsMismatch({expected: [evA], actual: [evB]}),
42
- format: "EventsMismatch:\n expected: [{\n \"TAG\": \"ProductAdded\",\n \"_0\": {\n \"productId\": \"p1\",\n \"name\": \"Widget\"\n }\n}]\n actual: [{\n \"TAG\": \"ProductRenamed\",\n \"_0\": {\n \"productId\": \"p1\",\n \"name\": \"Gadget\"\n }\n}]",
43
- human: " expected: [ProductAdded({productId: \"p1\", name: \"Widget\"})]\n actual: [ProductRenamed({productId: \"p1\", name: \"Gadget\"})]",
44
- tap: " kind: \"EventsMismatch\"\n expected: \"[ProductAdded({productId: \\\"p1\\\", name: \\\"Widget\\\"})]\"\n actual: \"[ProductRenamed({productId: \\\"p1\\\", name: \\\"Gadget\\\"})]\"",
45
- },
46
- {
47
- name: "ErrorMismatch",
48
- mismatch: ErrorMismatch({
49
- expected: JSON.String("CategoryAlreadyExists"),
50
- actual: None,
51
- actualEvents: [evA],
52
- }),
53
- format: "ErrorMismatch:\n expected error: \"CategoryAlreadyExists\"\n actual error: (none)\n actual events: [{\n \"TAG\": \"ProductAdded\",\n \"_0\": {\n \"productId\": \"p1\",\n \"name\": \"Widget\"\n }\n}]",
54
- human: " expected: Error(\"CategoryAlreadyExists\")\n actual: Ok([ProductAdded({productId: \"p1\", name: \"Widget\"})])",
55
- tap: " kind: \"ErrorMismatch\"\n expected: \"Error(\\\"CategoryAlreadyExists\\\")\"\n actual: \"Ok([ProductAdded({productId: \\\"p1\\\", name: \\\"Widget\\\"})])\"",
56
- },
57
- {
58
- name: "StateMismatch",
59
- mismatch: StateMismatch({key: "p1", expected: Some(stateActive), actual: Some(stateArchived)}),
60
- format: "StateMismatch (key: p1):\n expected: {\n \"status\": \"active\"\n}\n actual: {\n \"status\": \"archived\"\n}",
61
- human: " key: \"p1\"\n expected: {status: \"active\"}\n actual: {status: \"archived\"}",
62
- tap: " kind: \"StateMismatch\"\n key: \"p1\"\n expected: \"{status: \\\"active\\\"}\"\n actual: \"{status: \\\"archived\\\"}\"",
63
- },
64
- {
65
- name: "NoEventExpected",
66
- mismatch: NoEventExpected({actual: [evA]}),
67
- format: "NoEventExpected: expected no events, got:\n [{\n \"TAG\": \"ProductAdded\",\n \"_0\": {\n \"productId\": \"p1\",\n \"name\": \"Widget\"\n }\n}]",
68
- human: " expected no events\n actual: [ProductAdded({productId: \"p1\", name: \"Widget\"})]",
69
- tap: " kind: \"NoEventExpected\"\n actual: \"[ProductAdded({productId: \\\"p1\\\", name: \\\"Widget\\\"})]\"",
70
- },
71
- {
72
- name: "TranslateError",
73
- mismatch: TranslateError({expected: "boom", actual: Some("kaboom")}),
74
- format: "TranslateError:\n expected: boom\n actual: kaboom",
75
- human: " expected: boom\n actual: kaboom",
76
- tap: " kind: \"TranslateError\"\n expected: \"boom\"\n actual: \"kaboom\"",
77
- },
78
- {
79
- name: "Throw",
80
- mismatch: Throw({error: "unexpected", stack: "at foo"}),
81
- format: "Throw: unexpected\nat foo",
82
- human: " error: unexpected\nat foo",
83
- tap: " kind: \"Throw\"\n error: \"unexpected\"\n stack: \"at foo\"",
84
- },
85
- {
86
- name: "TodoMismatch",
87
- mismatch: TodoMismatch({expected: [("case-1", evA)], actual: [("case-2", evB)]}),
88
- format: "TodoMismatch:\n expected: [(case-1, {\n \"TAG\": \"ProductAdded\",\n \"_0\": {\n \"productId\": \"p1\",\n \"name\": \"Widget\"\n }\n})]\n actual: [(case-2, {\n \"TAG\": \"ProductRenamed\",\n \"_0\": {\n \"productId\": \"p1\",\n \"name\": \"Gadget\"\n }\n})]",
89
- human: " expected: [(case-1, ProductAdded({productId: \"p1\", name: \"Widget\"}))]\n actual: [(case-2, ProductRenamed({productId: \"p1\", name: \"Gadget\"}))]",
90
- tap: " kind: \"TodoMismatch\"\n expected: \"[(case-1, ProductAdded({productId: \\\"p1\\\", name: \\\"Widget\\\"}))]\"\n actual: \"[(case-2, ProductRenamed({productId: \\\"p1\\\", name: \\\"Gadget\\\"}))]\"",
91
- },
92
- {
93
- name: "AppendConditionMismatch",
94
- mismatch: AppendConditionMismatch({expected: appendExpected, actual: appendActual}),
95
- format: "AppendConditionMismatch:\n expected: {\n \"query\": []\n}\n actual: {\n \"query\": [\n {\n \"eventTypes\": [\n \"ProductAdded\"\n ]\n }\n ]\n}",
96
- human: " expected: {query: []}\n actual: {query: [{eventTypes: [\"ProductAdded\"]}]}",
97
- tap: " kind: \"AppendConditionMismatch\"\n expected: \"{query: []}\"\n actual: \"{query: [{eventTypes: [\\\"ProductAdded\\\"]}]}\"",
98
- },
99
- {
100
- name: "QueryRowsMismatch",
101
- mismatch: QueryRowsMismatch({expected: [evA], actual: [evB]}),
102
- format: "QueryRowsMismatch:\n expected: [{\n \"TAG\": \"ProductAdded\",\n \"_0\": {\n \"productId\": \"p1\",\n \"name\": \"Widget\"\n }\n}]\n actual: [{\n \"TAG\": \"ProductRenamed\",\n \"_0\": {\n \"productId\": \"p1\",\n \"name\": \"Gadget\"\n }\n}]",
103
- human: " expected: [ProductAdded({productId: \"p1\", name: \"Widget\"})]\n actual: [ProductRenamed({productId: \"p1\", name: \"Gadget\"})]",
104
- tap: " kind: \"QueryRowsMismatch\"\n expected: \"[ProductAdded({productId: \\\"p1\\\", name: \\\"Widget\\\"})]\"\n actual: \"[ProductRenamed({productId: \\\"p1\\\", name: \\\"Gadget\\\"})]\"",
105
- },
106
- {
107
- name: "PublishedActionsMismatch",
108
- mismatch: PublishedActionsMismatch({expected: [evA], actual: [evB]}),
109
- format: "PublishedActionsMismatch:\n expected: [{\n \"TAG\": \"ProductAdded\",\n \"_0\": {\n \"productId\": \"p1\",\n \"name\": \"Widget\"\n }\n}]\n actual: [{\n \"TAG\": \"ProductRenamed\",\n \"_0\": {\n \"productId\": \"p1\",\n \"name\": \"Gadget\"\n }\n}]",
110
- human: " expected: [ProductAdded({productId: \"p1\", name: \"Widget\"})]\n actual: [ProductRenamed({productId: \"p1\", name: \"Gadget\"})]",
111
- tap: " kind: \"PublishedActionsMismatch\"\n expected: \"[ProductAdded({productId: \\\"p1\\\", name: \\\"Widget\\\"})]\"\n actual: \"[ProductRenamed({productId: \\\"p1\\\", name: \\\"Gadget\\\"})]\"",
112
- },
113
- ]
114
-
115
- describe("Formatter golden outputs (per-mismatch rendering)", () => {
116
- goldens->Array.forEach(g => {
117
- testSync(`${g.name} — Outcome.format`, () => expect(Outcome.format(g.mismatch))->toEqual(g.format))
118
- testSync(`${g.name} — FormatterHuman.renderMismatch`, () =>
119
- expect(FormatterHuman.renderMismatch(g.mismatch))->toEqual(g.human)
120
- )
121
- testSync(`${g.name} — FormatterTap.renderMismatchYaml`, () =>
122
- expect(FormatterTap.renderMismatchYaml(g.mismatch))->toEqual(g.tap)
123
- )
124
- })
125
- })