@reventlessdev/reventless-gwt 1.0.0-alpha.100
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +916 -0
- package/LICENSE +202 -0
- package/bin/reventless-dev.mjs +21 -0
- package/package.json +54 -0
- package/rescript.json +36 -0
- package/src/.gwtignore +10 -0
- package/src/Automation_GWT.res +207 -0
- package/src/Automation_GWT.res.mjs +160 -0
- package/src/Behavior_GWT.res +569 -0
- package/src/Behavior_GWT.res.mjs +523 -0
- package/src/Bind.res +29 -0
- package/src/Bind.res.mjs +22 -0
- package/src/BuildClassifier.res +147 -0
- package/src/BuildClassifier.res.mjs +136 -0
- package/src/Cancellation.res +37 -0
- package/src/Cancellation.res.mjs +46 -0
- package/src/ChildProcess.res +102 -0
- package/src/ChildProcess.res.mjs +107 -0
- package/src/Cli.res +905 -0
- package/src/Cli.res.mjs +952 -0
- package/src/Collector.res +212 -0
- package/src/Collector.res.mjs +218 -0
- package/src/ComponentMeta.res +77 -0
- package/src/ComponentMeta.res.mjs +91 -0
- package/src/ComponentScan.res +103 -0
- package/src/ComponentScan.res.mjs +105 -0
- package/src/Delegate_GWT.res +303 -0
- package/src/Delegate_GWT.res.mjs +372 -0
- package/src/Diff.res +91 -0
- package/src/Diff.res.mjs +98 -0
- package/src/Discovery.res +105 -0
- package/src/Discovery.res.mjs +99 -0
- package/src/DomainDeadCode.res +98 -0
- package/src/DomainDeadCode.res.mjs +72 -0
- package/src/DomainGraph.res +0 -0
- package/src/DomainGraph.res.mjs +0 -0
- package/src/EventMapping_GWT.res +29 -0
- package/src/EventMapping_GWT.res.mjs +44 -0
- package/src/Filter.res +45 -0
- package/src/Filter.res.mjs +47 -0
- package/src/Flow_GWT.res +664 -0
- package/src/Flow_GWT.res.mjs +604 -0
- package/src/FormatterHuman.res +109 -0
- package/src/FormatterHuman.res.mjs +115 -0
- package/src/FormatterJson.res +264 -0
- package/src/FormatterJson.res.mjs +322 -0
- package/src/FormatterJunit.res +93 -0
- package/src/FormatterJunit.res.mjs +90 -0
- package/src/FormatterTap.res +100 -0
- package/src/FormatterTap.res.mjs +131 -0
- package/src/FormatterVsCode.res +352 -0
- package/src/FormatterVsCode.res.mjs +546 -0
- package/src/Hint.res +119 -0
- package/src/Hint.res.mjs +124 -0
- package/src/InboundTranslation_GWT.res +83 -0
- package/src/InboundTranslation_GWT.res.mjs +94 -0
- package/src/JestBind.res +70 -0
- package/src/JestBind.res.mjs +63 -0
- package/src/Loader.res +24 -0
- package/src/Loader.res.mjs +23 -0
- package/src/LocalHost.res +119 -0
- package/src/LocalHost.res.mjs +99 -0
- package/src/Mapping_GWT.res +474 -0
- package/src/Mapping_GWT.res.mjs +322 -0
- package/src/MismatchRender.res +72 -0
- package/src/MismatchRender.res.mjs +127 -0
- package/src/MultiSourceProjection_GWT.res +316 -0
- package/src/MultiSourceProjection_GWT.res.mjs +354 -0
- package/src/OutboundTranslation_GWT.res +238 -0
- package/src/OutboundTranslation_GWT.res.mjs +186 -0
- package/src/Outcome.res +97 -0
- package/src/Outcome.res.mjs +93 -0
- package/src/PackageScan.res +80 -0
- package/src/PackageScan.res.mjs +81 -0
- package/src/PlatformRunner.res +181 -0
- package/src/PlatformRunner.res.mjs +176 -0
- package/src/PlatformScan.res +142 -0
- package/src/PlatformScan.res.mjs +132 -0
- package/src/ProcessManager.res +135 -0
- package/src/ProcessManager.res.mjs +119 -0
- package/src/Projection_GWT.res +312 -0
- package/src/Projection_GWT.res.mjs +332 -0
- package/src/Query_GWT.res +379 -0
- package/src/Query_GWT.res.mjs +367 -0
- package/src/RenderRescript.res +125 -0
- package/src/RenderRescript.res.mjs +141 -0
- package/src/RunWorker.res +24 -0
- package/src/RunWorker.res.mjs +16 -0
- package/src/RunnerTypes.res +68 -0
- package/src/RunnerTypes.res.mjs +60 -0
- package/src/SideEffect_GWT.res +157 -0
- package/src/SideEffect_GWT.res.mjs +113 -0
- package/src/StateChange/ExternalAddCategorySlice.res +25 -0
- package/src/StateChange/ExternalAddCategorySlice.res.mjs +34 -0
- package/src/StateChange/ExternalAddCategorySlice_Behavior.res +19 -0
- package/src/StateChange/ExternalAddCategorySlice_Behavior.res.mjs +46 -0
- package/src/StateChange/WithFixtures.res +22 -0
- package/src/StateChange/WithFixtures.res.mjs +31 -0
- package/src/StateChange/WithFixtures_Behavior.res +17 -0
- package/src/StateChange/WithFixtures_Behavior.res.mjs +37 -0
- package/src/StateChange/WithManualOpen.res +23 -0
- package/src/StateChange/WithManualOpen.res.mjs +31 -0
- package/src/StateChange/WithManualOpen_Behavior.res +17 -0
- package/src/StateChange/WithManualOpen_Behavior.res.mjs +37 -0
- package/src/StubRuntime.res +54 -0
- package/src/StubRuntime.res.mjs +55 -0
- package/src/TestFixtures.res +16 -0
- package/src/TestFixtures.res.mjs +34 -0
- package/src/Watch.res +108 -0
- package/src/Watch.res.mjs +85 -0
- package/src/WatcherProbe.res +56 -0
- package/src/WatcherProbe.res.mjs +59 -0
- package/src/Worker.res +24 -0
- package/src/Worker.res.mjs +9 -0
- package/tests/AutomationGwtTest.res +71 -0
- package/tests/AutomationGwtTest.res.mjs +189 -0
- package/tests/BuildClassifierTest.res +133 -0
- package/tests/BuildClassifierTest.res.mjs +176 -0
- package/tests/CliRunEntryTest.res +57 -0
- package/tests/CliRunEntryTest.res.mjs +65 -0
- package/tests/CliWatchScopeTest.res +62 -0
- package/tests/CliWatchScopeTest.res.mjs +95 -0
- package/tests/ComponentMetaTest.res +67 -0
- package/tests/ComponentMetaTest.res.mjs +71 -0
- package/tests/DelegateGwtTest.res +487 -0
- package/tests/DelegateGwtTest.res.mjs +891 -0
- package/tests/DiscoveryTest.res +42 -0
- package/tests/DiscoveryTest.res.mjs +43 -0
- package/tests/DomainDeadCodeTest.res +119 -0
- package/tests/DomainDeadCodeTest.res.mjs +158 -0
- package/tests/DomainGraphTest.res +448 -0
- package/tests/DomainGraphTest.res.mjs +505 -0
- package/tests/FlowAggregateGwtTest.res +171 -0
- package/tests/FlowAggregateGwtTest.res.mjs +273 -0
- package/tests/FlowCrossPluginGwtTest.res +340 -0
- package/tests/FlowCrossPluginGwtTest.res.mjs +798 -0
- package/tests/FlowGwtTest.res +222 -0
- package/tests/FlowGwtTest.res.mjs +433 -0
- package/tests/FormatterGoldenTest.res +125 -0
- package/tests/FormatterGoldenTest.res.mjs +162 -0
- package/tests/FormatterVsCodeMessageTest.res +41 -0
- package/tests/FormatterVsCodeMessageTest.res.mjs +42 -0
- package/tests/InboundTranslationGwtTest.res +34 -0
- package/tests/InboundTranslationGwtTest.res.mjs +99 -0
- package/tests/LocalHostIntegration.res +70 -0
- package/tests/LocalHostIntegration.res.mjs +64 -0
- package/tests/LocalHostTest.res +71 -0
- package/tests/LocalHostTest.res.mjs +63 -0
- package/tests/MappingGwtTest.res +350 -0
- package/tests/MappingGwtTest.res.mjs +596 -0
- package/tests/OutboundTranslationGwtTest.res +59 -0
- package/tests/OutboundTranslationGwtTest.res.mjs +139 -0
- package/tests/PlatformRunnerTest.res +66 -0
- package/tests/PlatformRunnerTest.res.mjs +85 -0
- package/tests/PlatformScanTest.res +61 -0
- package/tests/PlatformScanTest.res.mjs +56 -0
- package/tests/QueryGwtTest.res +161 -0
- package/tests/QueryGwtTest.res.mjs +314 -0
- package/tests/QueryResolverGwtTest.res +71 -0
- package/tests/QueryResolverGwtTest.res.mjs +136 -0
- package/tests/RunnerUnitTest.res +219 -0
- package/tests/RunnerUnitTest.res.mjs +244 -0
- package/tests/SideEffect/FakeOrderNotification.res +23 -0
- package/tests/SideEffect/FakeOrderNotification.res.mjs +36 -0
- package/tests/SideEffect/FakeOrderNotificationGwtTest.res +35 -0
- package/tests/SideEffect/FakeOrderNotificationGwtTest.res.mjs +73 -0
- package/tests/SideEffect/MockEmail.res +18 -0
- package/tests/SideEffect/MockEmail.res.mjs +47 -0
- package/tests/StateChange/ExternalAddCategorySlice_GWT.res +27 -0
- package/tests/StateChange/ExternalAddCategorySlice_GWT.res.mjs +70 -0
- package/tests/StateChange/WithFixtures_Fixtures.res +9 -0
- package/tests/StateChange/WithFixtures_Fixtures.res.mjs +20 -0
- package/tests/StateChange/WithFixtures_GWT.res +23 -0
- package/tests/StateChange/WithFixtures_GWT.res.mjs +56 -0
- package/tests/StateChange/WithManualOpen_Fixtures.res +7 -0
- package/tests/StateChange/WithManualOpen_Fixtures.res.mjs +20 -0
- package/tests/StateChange/WithManualOpen_GWT.res +17 -0
- package/tests/StateChange/WithManualOpen_GWT.res.mjs +56 -0
- package/tests/StateChangeSliceGwtTest.res +160 -0
- package/tests/StateChangeSliceGwtTest.res.mjs +280 -0
- package/tests/StateViewSliceGwtTest.res +64 -0
- package/tests/StateViewSliceGwtTest.res.mjs +161 -0
- package/tests/WatchDebounceTest.res +106 -0
- package/tests/WatchDebounceTest.res.mjs +128 -0
|
@@ -0,0 +1,47 @@
|
|
|
1
|
+
// Generated by ReScript, PLEASE EDIT WITH CARE
|
|
2
|
+
|
|
3
|
+
import * as S from "sury/src/S.res.mjs";
|
|
4
|
+
|
|
5
|
+
let callSchema = S.schema(s => ({
|
|
6
|
+
TAG: "SendConfirmation",
|
|
7
|
+
email: s.m(S.string),
|
|
8
|
+
orderId: s.m(S.string)
|
|
9
|
+
}));
|
|
10
|
+
|
|
11
|
+
let calls = {
|
|
12
|
+
contents: []
|
|
13
|
+
};
|
|
14
|
+
|
|
15
|
+
function reset() {
|
|
16
|
+
calls.contents = [];
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
function recordSend(email, orderId) {
|
|
20
|
+
calls.contents = calls.contents.concat([{
|
|
21
|
+
TAG: "SendConfirmation",
|
|
22
|
+
email: email,
|
|
23
|
+
orderId: orderId
|
|
24
|
+
}]);
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
function mock_snapshot() {
|
|
28
|
+
return calls.contents;
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
function mock_encode(c) {
|
|
32
|
+
return S.reverseConvertToJsonOrThrow(c, callSchema);
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
let mock = {
|
|
36
|
+
snapshot: mock_snapshot,
|
|
37
|
+
encode: mock_encode
|
|
38
|
+
};
|
|
39
|
+
|
|
40
|
+
export {
|
|
41
|
+
callSchema,
|
|
42
|
+
calls,
|
|
43
|
+
reset,
|
|
44
|
+
recordSend,
|
|
45
|
+
mock,
|
|
46
|
+
}
|
|
47
|
+
/* callSchema Not a pure module */
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
// External-Spec verification test for @@reventless.gwt.
|
|
2
|
+
//
|
|
3
|
+
// Zero payload, no local module, no alias. The PPX resolves:
|
|
4
|
+
// - Kind from the folder segment "StateChange" -> Behavior
|
|
5
|
+
// - Spec from the filename stem (strip "_GWT") -> ExternalAddCategorySlice
|
|
6
|
+
// - Impl derived as ExternalAddCategorySlice_Behavior
|
|
7
|
+
// - open ExternalAddCategorySlice +
|
|
8
|
+
// include Behavior_GWT.Make(ExternalAddCategorySlice, ExternalAddCategorySlice_Behavior)
|
|
9
|
+
//
|
|
10
|
+
// Mirrors the canonical consumer pattern documented in
|
|
11
|
+
// docs/guides/given-when-then.md § 4.10.
|
|
12
|
+
|
|
13
|
+
@@reventless.gwt
|
|
14
|
+
|
|
15
|
+
describe("ExternalAddCategory StateChangeSlice (external Spec)", () => {
|
|
16
|
+
test("empty event log produces CategoryAdded", () =>
|
|
17
|
+
givenEvents([])
|
|
18
|
+
->whenCmd(AddCategory({categoryId: "c1", name: "Electronics"}))
|
|
19
|
+
->thenEvent(CategoryAdded({categoryId: "c1", name: "Electronics"}))
|
|
20
|
+
)
|
|
21
|
+
|
|
22
|
+
test("existing category returns CategoryAlreadyExists", () =>
|
|
23
|
+
givenEvents([CategoryAdded])
|
|
24
|
+
->whenCmd(AddCategory({categoryId: "c1", name: "X"}))
|
|
25
|
+
->thenError(CategoryAlreadyExists)
|
|
26
|
+
)
|
|
27
|
+
})
|
|
@@ -0,0 +1,70 @@
|
|
|
1
|
+
// Generated by ReScript, PLEASE EDIT WITH CARE
|
|
2
|
+
|
|
3
|
+
import * as Behavior_GWT$ReventlessGwt from "../../src/Behavior_GWT.res.mjs";
|
|
4
|
+
import * as ExternalAddCategorySlice$ReventlessGwt from "../../src/StateChange/ExternalAddCategorySlice.res.mjs";
|
|
5
|
+
import * as ExternalAddCategorySlice_Behavior$ReventlessGwt from "../../src/StateChange/ExternalAddCategorySlice_Behavior.res.mjs";
|
|
6
|
+
|
|
7
|
+
let include = Behavior_GWT$ReventlessGwt.Make(ExternalAddCategorySlice$ReventlessGwt)(ExternalAddCategorySlice_Behavior$ReventlessGwt);
|
|
8
|
+
|
|
9
|
+
let describe = include.describe;
|
|
10
|
+
|
|
11
|
+
let test = include.test;
|
|
12
|
+
|
|
13
|
+
let givenEvents = include.givenEvents;
|
|
14
|
+
|
|
15
|
+
let whenCmd = include.whenCmd;
|
|
16
|
+
|
|
17
|
+
let thenEvent = include.thenEvent;
|
|
18
|
+
|
|
19
|
+
let thenError = include.thenError;
|
|
20
|
+
|
|
21
|
+
describe("ExternalAddCategory StateChangeSlice (external Spec)", () => {
|
|
22
|
+
test("empty event log produces CategoryAdded", () => thenEvent(whenCmd(givenEvents([]), {
|
|
23
|
+
TAG: "AddCategory",
|
|
24
|
+
categoryId: "c1",
|
|
25
|
+
name: "Electronics"
|
|
26
|
+
}), {
|
|
27
|
+
TAG: "CategoryAdded",
|
|
28
|
+
categoryId: "c1",
|
|
29
|
+
name: "Electronics"
|
|
30
|
+
}));
|
|
31
|
+
test("existing category returns CategoryAlreadyExists", () => thenError(whenCmd(givenEvents(["CategoryAdded"]), {
|
|
32
|
+
TAG: "AddCategory",
|
|
33
|
+
categoryId: "c1",
|
|
34
|
+
name: "X"
|
|
35
|
+
}), "CategoryAlreadyExists"));
|
|
36
|
+
});
|
|
37
|
+
|
|
38
|
+
let Spec = include.Spec;
|
|
39
|
+
|
|
40
|
+
let todo = include.todo;
|
|
41
|
+
|
|
42
|
+
let thenEvents = include.thenEvents;
|
|
43
|
+
|
|
44
|
+
let thenNoEvent = include.thenNoEvent;
|
|
45
|
+
|
|
46
|
+
let thenEventWithError = include.thenEventWithError;
|
|
47
|
+
|
|
48
|
+
let thenEventsWithError = include.thenEventsWithError;
|
|
49
|
+
|
|
50
|
+
let thenAppendsConditionedOn = include.thenAppendsConditionedOn;
|
|
51
|
+
|
|
52
|
+
let thenAppendsConditionedOnExactly = include.thenAppendsConditionedOnExactly;
|
|
53
|
+
|
|
54
|
+
export {
|
|
55
|
+
Spec,
|
|
56
|
+
describe,
|
|
57
|
+
todo,
|
|
58
|
+
test,
|
|
59
|
+
givenEvents,
|
|
60
|
+
whenCmd,
|
|
61
|
+
thenEvent,
|
|
62
|
+
thenEvents,
|
|
63
|
+
thenNoEvent,
|
|
64
|
+
thenEventWithError,
|
|
65
|
+
thenEventsWithError,
|
|
66
|
+
thenError,
|
|
67
|
+
thenAppendsConditionedOn,
|
|
68
|
+
thenAppendsConditionedOnExactly,
|
|
69
|
+
}
|
|
70
|
+
/* include Not a pure module */
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
// Companion fixtures module for [WithFixtures_GWT.res]. The PPX detects this
|
|
2
|
+
// sibling by filename and auto-injects [open WithFixtures_Fixtures] into the
|
|
3
|
+
// GWT test body, so the test can reference [addCategoryElectronics] /
|
|
4
|
+
// [electronicsCategoryAdded] unqualified.
|
|
5
|
+
|
|
6
|
+
open WithFixtures
|
|
7
|
+
|
|
8
|
+
let addCategoryElectronics = AddCategory({categoryId: "c1", name: "Electronics"})
|
|
9
|
+
let electronicsCategoryAdded = CategoryAdded({categoryId: "c1", name: "Electronics"})
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
// Generated by ReScript, PLEASE EDIT WITH CARE
|
|
2
|
+
|
|
3
|
+
|
|
4
|
+
let addCategoryElectronics = {
|
|
5
|
+
TAG: "AddCategory",
|
|
6
|
+
categoryId: "c1",
|
|
7
|
+
name: "Electronics"
|
|
8
|
+
};
|
|
9
|
+
|
|
10
|
+
let electronicsCategoryAdded = {
|
|
11
|
+
TAG: "CategoryAdded",
|
|
12
|
+
categoryId: "c1",
|
|
13
|
+
name: "Electronics"
|
|
14
|
+
};
|
|
15
|
+
|
|
16
|
+
export {
|
|
17
|
+
addCategoryElectronics,
|
|
18
|
+
electronicsCategoryAdded,
|
|
19
|
+
}
|
|
20
|
+
/* No side effect */
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
// Companion-fixtures auto-open verification test for @@reventless.gwt.
|
|
2
|
+
//
|
|
3
|
+
// Zero payload, no local module, no manual open. The PPX resolves:
|
|
4
|
+
// - Kind from the folder segment "StateChange" -> StateChangeSlice
|
|
5
|
+
// - Spec from the filename stem (strip "_GWT") -> WithFixtures
|
|
6
|
+
// - Companion fixtures: sibling [WithFixtures_Fixtures.res] is detected on
|
|
7
|
+
// disk, so the PPX emits both [open WithFixtures] and
|
|
8
|
+
// [open WithFixtures_Fixtures] before the [include].
|
|
9
|
+
//
|
|
10
|
+
// The test body uses [addCategoryElectronics] / [electronicsCategoryAdded]
|
|
11
|
+
// unqualified — resolution only succeeds if the companion fixtures open was
|
|
12
|
+
// injected.
|
|
13
|
+
|
|
14
|
+
@@reventless.gwt
|
|
15
|
+
|
|
16
|
+
describe("WithFixtures StateChangeSlice (companion fixtures auto-open)", () => {
|
|
17
|
+
test("uses companion fixtures unqualified", () =>
|
|
18
|
+
givenEvents([])
|
|
19
|
+
->whenCmd(addCategoryElectronics)
|
|
20
|
+
->thenEvent((electronicsCategoryAdded :> event))
|
|
21
|
+
)
|
|
22
|
+
})
|
|
23
|
+
|
|
@@ -0,0 +1,56 @@
|
|
|
1
|
+
// Generated by ReScript, PLEASE EDIT WITH CARE
|
|
2
|
+
|
|
3
|
+
import * as Behavior_GWT$ReventlessGwt from "../../src/Behavior_GWT.res.mjs";
|
|
4
|
+
import * as WithFixtures$ReventlessGwt from "../../src/StateChange/WithFixtures.res.mjs";
|
|
5
|
+
import * as WithFixtures_Behavior$ReventlessGwt from "../../src/StateChange/WithFixtures_Behavior.res.mjs";
|
|
6
|
+
import * as WithFixtures_Fixtures$ReventlessGwt from "./WithFixtures_Fixtures.res.mjs";
|
|
7
|
+
|
|
8
|
+
let include = Behavior_GWT$ReventlessGwt.Make(WithFixtures$ReventlessGwt)(WithFixtures_Behavior$ReventlessGwt);
|
|
9
|
+
|
|
10
|
+
let describe = include.describe;
|
|
11
|
+
|
|
12
|
+
let test = include.test;
|
|
13
|
+
|
|
14
|
+
let givenEvents = include.givenEvents;
|
|
15
|
+
|
|
16
|
+
let whenCmd = include.whenCmd;
|
|
17
|
+
|
|
18
|
+
let thenEvent = include.thenEvent;
|
|
19
|
+
|
|
20
|
+
describe("WithFixtures StateChangeSlice (companion fixtures auto-open)", () => test("uses companion fixtures unqualified", () => thenEvent(whenCmd(givenEvents([]), WithFixtures_Fixtures$ReventlessGwt.addCategoryElectronics), WithFixtures_Fixtures$ReventlessGwt.electronicsCategoryAdded)));
|
|
21
|
+
|
|
22
|
+
let Spec = include.Spec;
|
|
23
|
+
|
|
24
|
+
let todo = include.todo;
|
|
25
|
+
|
|
26
|
+
let thenEvents = include.thenEvents;
|
|
27
|
+
|
|
28
|
+
let thenNoEvent = include.thenNoEvent;
|
|
29
|
+
|
|
30
|
+
let thenEventWithError = include.thenEventWithError;
|
|
31
|
+
|
|
32
|
+
let thenEventsWithError = include.thenEventsWithError;
|
|
33
|
+
|
|
34
|
+
let thenError = include.thenError;
|
|
35
|
+
|
|
36
|
+
let thenAppendsConditionedOn = include.thenAppendsConditionedOn;
|
|
37
|
+
|
|
38
|
+
let thenAppendsConditionedOnExactly = include.thenAppendsConditionedOnExactly;
|
|
39
|
+
|
|
40
|
+
export {
|
|
41
|
+
Spec,
|
|
42
|
+
describe,
|
|
43
|
+
todo,
|
|
44
|
+
test,
|
|
45
|
+
givenEvents,
|
|
46
|
+
whenCmd,
|
|
47
|
+
thenEvent,
|
|
48
|
+
thenEvents,
|
|
49
|
+
thenNoEvent,
|
|
50
|
+
thenEventWithError,
|
|
51
|
+
thenEventsWithError,
|
|
52
|
+
thenError,
|
|
53
|
+
thenAppendsConditionedOn,
|
|
54
|
+
thenAppendsConditionedOnExactly,
|
|
55
|
+
}
|
|
56
|
+
/* include Not a pure module */
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
// Companion fixtures module for [WithManualOpen_GWT.res]. The test file
|
|
2
|
+
// opens this module manually, so the PPX must NOT duplicate the open.
|
|
3
|
+
|
|
4
|
+
open WithManualOpen
|
|
5
|
+
|
|
6
|
+
let addCategoryBooks = AddCategory({categoryId: "c2", name: "Books"})
|
|
7
|
+
let booksCategoryAdded = CategoryAdded({categoryId: "c2", name: "Books"})
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
// Generated by ReScript, PLEASE EDIT WITH CARE
|
|
2
|
+
|
|
3
|
+
|
|
4
|
+
let addCategoryBooks = {
|
|
5
|
+
TAG: "AddCategory",
|
|
6
|
+
categoryId: "c2",
|
|
7
|
+
name: "Books"
|
|
8
|
+
};
|
|
9
|
+
|
|
10
|
+
let booksCategoryAdded = {
|
|
11
|
+
TAG: "CategoryAdded",
|
|
12
|
+
categoryId: "c2",
|
|
13
|
+
name: "Books"
|
|
14
|
+
};
|
|
15
|
+
|
|
16
|
+
export {
|
|
17
|
+
addCategoryBooks,
|
|
18
|
+
booksCategoryAdded,
|
|
19
|
+
}
|
|
20
|
+
/* No side effect */
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
// Manual-open dedup verification for @@reventless.gwt companion fixtures.
|
|
2
|
+
//
|
|
3
|
+
// The sibling [WithManualOpen_Fixtures.res] exists AND the test body opens
|
|
4
|
+
// it manually. The PPX detects the existing open via [Util.has_open] and
|
|
5
|
+
// skips the duplicate injection — the file compiles without shadow warnings.
|
|
6
|
+
|
|
7
|
+
@@reventless.gwt
|
|
8
|
+
|
|
9
|
+
open WithManualOpen_Fixtures
|
|
10
|
+
|
|
11
|
+
describe("WithManualOpen (manual open not duplicated by PPX)", () => {
|
|
12
|
+
test("manual open resolves fixture identifiers", () =>
|
|
13
|
+
givenEvents([])
|
|
14
|
+
->whenCmd(addCategoryBooks)
|
|
15
|
+
->thenEvent((booksCategoryAdded :> event))
|
|
16
|
+
)
|
|
17
|
+
})
|
|
@@ -0,0 +1,56 @@
|
|
|
1
|
+
// Generated by ReScript, PLEASE EDIT WITH CARE
|
|
2
|
+
|
|
3
|
+
import * as Behavior_GWT$ReventlessGwt from "../../src/Behavior_GWT.res.mjs";
|
|
4
|
+
import * as WithManualOpen$ReventlessGwt from "../../src/StateChange/WithManualOpen.res.mjs";
|
|
5
|
+
import * as WithManualOpen_Behavior$ReventlessGwt from "../../src/StateChange/WithManualOpen_Behavior.res.mjs";
|
|
6
|
+
import * as WithManualOpen_Fixtures$ReventlessGwt from "./WithManualOpen_Fixtures.res.mjs";
|
|
7
|
+
|
|
8
|
+
let include = Behavior_GWT$ReventlessGwt.Make(WithManualOpen$ReventlessGwt)(WithManualOpen_Behavior$ReventlessGwt);
|
|
9
|
+
|
|
10
|
+
let describe = include.describe;
|
|
11
|
+
|
|
12
|
+
let test = include.test;
|
|
13
|
+
|
|
14
|
+
let givenEvents = include.givenEvents;
|
|
15
|
+
|
|
16
|
+
let whenCmd = include.whenCmd;
|
|
17
|
+
|
|
18
|
+
let thenEvent = include.thenEvent;
|
|
19
|
+
|
|
20
|
+
describe("WithManualOpen (manual open not duplicated by PPX)", () => test("manual open resolves fixture identifiers", () => thenEvent(whenCmd(givenEvents([]), WithManualOpen_Fixtures$ReventlessGwt.addCategoryBooks), WithManualOpen_Fixtures$ReventlessGwt.booksCategoryAdded)));
|
|
21
|
+
|
|
22
|
+
let Spec = include.Spec;
|
|
23
|
+
|
|
24
|
+
let todo = include.todo;
|
|
25
|
+
|
|
26
|
+
let thenEvents = include.thenEvents;
|
|
27
|
+
|
|
28
|
+
let thenNoEvent = include.thenNoEvent;
|
|
29
|
+
|
|
30
|
+
let thenEventWithError = include.thenEventWithError;
|
|
31
|
+
|
|
32
|
+
let thenEventsWithError = include.thenEventsWithError;
|
|
33
|
+
|
|
34
|
+
let thenError = include.thenError;
|
|
35
|
+
|
|
36
|
+
let thenAppendsConditionedOn = include.thenAppendsConditionedOn;
|
|
37
|
+
|
|
38
|
+
let thenAppendsConditionedOnExactly = include.thenAppendsConditionedOnExactly;
|
|
39
|
+
|
|
40
|
+
export {
|
|
41
|
+
Spec,
|
|
42
|
+
describe,
|
|
43
|
+
todo,
|
|
44
|
+
test,
|
|
45
|
+
givenEvents,
|
|
46
|
+
whenCmd,
|
|
47
|
+
thenEvent,
|
|
48
|
+
thenEvents,
|
|
49
|
+
thenNoEvent,
|
|
50
|
+
thenEventWithError,
|
|
51
|
+
thenEventsWithError,
|
|
52
|
+
thenError,
|
|
53
|
+
thenAppendsConditionedOn,
|
|
54
|
+
thenAppendsConditionedOnExactly,
|
|
55
|
+
}
|
|
56
|
+
/* include Not a pure module */
|
|
@@ -0,0 +1,160 @@
|
|
|
1
|
+
// Worked example for Behavior_GWT (slice flavor).
|
|
2
|
+
// Uses the canonical "AddCategory" DCB slice shape — payload-less consumed
|
|
3
|
+
// events, decide that appends `CategoryAdded` unless the category already
|
|
4
|
+
// exists. Command carries a `@s.matches(DcbTag.string)` annotated ID so the
|
|
5
|
+
// DCB optimistic-concurrency query resolves to a single-entity read.
|
|
6
|
+
//
|
|
7
|
+
// Plan 02 Phase 6: split-form Spec/Behavior; PPX inference resolves the
|
|
8
|
+
// folder kind from the test path's "StateChangeSlice" substring → Behavior
|
|
9
|
+
// DSL → emits [include Behavior_GWT.Make(Spec, Behavior)].
|
|
10
|
+
|
|
11
|
+
@@reventless.gwt
|
|
12
|
+
|
|
13
|
+
module AddCategorySlice = {
|
|
14
|
+
let name = "AddCategory"
|
|
15
|
+
|
|
16
|
+
@schema
|
|
17
|
+
type consumedEvent =
|
|
18
|
+
| CategoryAdded
|
|
19
|
+
| CategoryArchived
|
|
20
|
+
|
|
21
|
+
@schema
|
|
22
|
+
type command =
|
|
23
|
+
AddCategory({categoryId: @s.matches(Reventless.DcbTag.string) string, name: string})
|
|
24
|
+
|
|
25
|
+
@schema
|
|
26
|
+
type error = CategoryAlreadyExists
|
|
27
|
+
|
|
28
|
+
@schema
|
|
29
|
+
type event =
|
|
30
|
+
CategoryAdded({categoryId: @s.matches(Reventless.DcbTag.string) string, name: string})
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
module AddCategorySliceBehavior = {
|
|
34
|
+
module Spec = AddCategorySlice
|
|
35
|
+
open AddCategorySlice
|
|
36
|
+
|
|
37
|
+
type state = {exists: bool, archived: bool}
|
|
38
|
+
let initialState: state = {exists: false, archived: false}
|
|
39
|
+
|
|
40
|
+
let evolve = (state: state, event: consumedEvent): state =>
|
|
41
|
+
switch event {
|
|
42
|
+
| CategoryAdded => {exists: true, archived: false}
|
|
43
|
+
| CategoryArchived => {...state, archived: true}
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
let decide = (state: state, command: command): result<array<event>, error> =>
|
|
47
|
+
switch command {
|
|
48
|
+
| AddCategory({categoryId, name}) =>
|
|
49
|
+
state.exists ? Error(CategoryAlreadyExists) : Ok([CategoryAdded({categoryId, name})])
|
|
50
|
+
}
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
describe("AddCategory StateChangeSlice", () => {
|
|
54
|
+
test("on empty event log produces CategoryAdded", () =>
|
|
55
|
+
givenEvents([])
|
|
56
|
+
->whenCmd(AddCategory({categoryId: "c1", name: "Electronics"}))
|
|
57
|
+
->thenEvent(CategoryAdded({categoryId: "c1", name: "Electronics"}))
|
|
58
|
+
)
|
|
59
|
+
|
|
60
|
+
test("on existing category returns CategoryAlreadyExists", () =>
|
|
61
|
+
givenEvents([CategoryAdded])
|
|
62
|
+
->whenCmd(AddCategory({categoryId: "c1", name: "X"}))
|
|
63
|
+
->thenError(CategoryAlreadyExists)
|
|
64
|
+
)
|
|
65
|
+
|
|
66
|
+
test("append condition is single-entity query over consumed event types", () =>
|
|
67
|
+
givenEvents([])
|
|
68
|
+
->whenCmd(AddCategory({categoryId: "c1", name: "Electronics"}))
|
|
69
|
+
->thenAppendsConditionedOn([
|
|
70
|
+
{
|
|
71
|
+
eventTypes: ["CategoryAdded", "CategoryArchived"],
|
|
72
|
+
tags: [{key: "categoryId", value: "c1"}],
|
|
73
|
+
},
|
|
74
|
+
])
|
|
75
|
+
)
|
|
76
|
+
|
|
77
|
+
test("exact condition matches no prior position (new entity)", () =>
|
|
78
|
+
givenEvents([])
|
|
79
|
+
->whenCmd(AddCategory({categoryId: "c2", name: "Books"}))
|
|
80
|
+
->thenAppendsConditionedOnExactly({
|
|
81
|
+
query: [
|
|
82
|
+
{
|
|
83
|
+
eventTypes: ["CategoryAdded", "CategoryArchived"],
|
|
84
|
+
tags: [{key: "categoryId", value: "c2"}],
|
|
85
|
+
},
|
|
86
|
+
],
|
|
87
|
+
})
|
|
88
|
+
)
|
|
89
|
+
})
|
|
90
|
+
|
|
91
|
+
// A second slice whose command has no `@s.matches(DcbTag.string)` annotation —
|
|
92
|
+
// verifies the implicit Stage 4 check fires with `AppendConditionMismatch`
|
|
93
|
+
// before any subsequent `then*` runs its own assertion.
|
|
94
|
+
module MissingTagSlice = {
|
|
95
|
+
let name = "MissingTagSlice"
|
|
96
|
+
|
|
97
|
+
@schema
|
|
98
|
+
type consumedEvent = Noop
|
|
99
|
+
|
|
100
|
+
@schema
|
|
101
|
+
type command = Do({id: string})
|
|
102
|
+
|
|
103
|
+
@schema
|
|
104
|
+
type error = Rejected
|
|
105
|
+
|
|
106
|
+
@schema
|
|
107
|
+
type event = Done({id: string})
|
|
108
|
+
}
|
|
109
|
+
|
|
110
|
+
module MissingTagBehavior = {
|
|
111
|
+
// Qualify references through [Spec] to avoid shadowing the file-scope
|
|
112
|
+
// [consumedEvent] / [command] / [event] / [error] brought in by the PPX-
|
|
113
|
+
// injected [open AddCategorySlice].
|
|
114
|
+
module Spec = MissingTagSlice
|
|
115
|
+
|
|
116
|
+
type state = unit
|
|
117
|
+
let initialState: state = ()
|
|
118
|
+
|
|
119
|
+
let evolve = (state: state, _event: Spec.consumedEvent): state => state
|
|
120
|
+
|
|
121
|
+
let decide = (
|
|
122
|
+
_state: state,
|
|
123
|
+
cmd: Spec.command,
|
|
124
|
+
): result<array<Spec.event>, Spec.error> =>
|
|
125
|
+
switch cmd {
|
|
126
|
+
| Do({id}) => Ok([Spec.Done({id: id})])
|
|
127
|
+
}
|
|
128
|
+
}
|
|
129
|
+
|
|
130
|
+
module MissingTagGwt = Behavior_GWT.Make(MissingTagSlice, MissingTagBehavior)
|
|
131
|
+
|
|
132
|
+
MissingTagGwt.describe("MissingTag slice implicit check", () => {
|
|
133
|
+
MissingTagGwt.test("thenEvent surfaces AppendConditionMismatch when command lacks DCB tag", () => {
|
|
134
|
+
let outcome =
|
|
135
|
+
MissingTagGwt.givenEvents([])
|
|
136
|
+
->MissingTagGwt.whenCmd(Do({id: "x1"}))
|
|
137
|
+
->MissingTagGwt.thenEvent(Done({id: "x1"}))
|
|
138
|
+
switch outcome {
|
|
139
|
+
| Error(AppendConditionMismatch(_)) => Outcome.pass
|
|
140
|
+
| Error(other) =>
|
|
141
|
+
Outcome.fail(
|
|
142
|
+
Throw({error: "expected AppendConditionMismatch, got: " ++ Outcome.kindName(other), stack: ""}),
|
|
143
|
+
)
|
|
144
|
+
| Ok() =>
|
|
145
|
+
Outcome.fail(
|
|
146
|
+
Throw({error: "expected AppendConditionMismatch, got pass", stack: ""}),
|
|
147
|
+
)
|
|
148
|
+
}
|
|
149
|
+
})
|
|
150
|
+
|
|
151
|
+
MissingTagGwt.test(
|
|
152
|
+
"thenAppendsConditionedOnExactly bypasses implicit check (still passes with derived)",
|
|
153
|
+
() =>
|
|
154
|
+
MissingTagGwt.givenEvents([])
|
|
155
|
+
->MissingTagGwt.whenCmd(Do({id: "x1"}))
|
|
156
|
+
->MissingTagGwt.thenAppendsConditionedOnExactly({
|
|
157
|
+
query: [{eventTypes: ["Noop"], tags: []}],
|
|
158
|
+
}),
|
|
159
|
+
)
|
|
160
|
+
})
|