@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,105 @@
|
|
|
1
|
+
// Generated by ReScript, PLEASE EDIT WITH CARE
|
|
2
|
+
|
|
3
|
+
import * as Nodefs from "node:fs";
|
|
4
|
+
import * as Nodepath from "node:path";
|
|
5
|
+
import * as Stdlib_Option from "@rescript/runtime/lib/es6/Stdlib_Option.js";
|
|
6
|
+
import * as Promises from "node:fs/promises";
|
|
7
|
+
import * as ComponentMeta$ReventlessGwt from "./ComponentMeta.res.mjs";
|
|
8
|
+
|
|
9
|
+
let ignoreNames = [
|
|
10
|
+
"node_modules",
|
|
11
|
+
".git",
|
|
12
|
+
"dist",
|
|
13
|
+
"lib",
|
|
14
|
+
".history"
|
|
15
|
+
];
|
|
16
|
+
|
|
17
|
+
function shouldIgnore(name) {
|
|
18
|
+
return ignoreNames.includes(name);
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
let gwtIgnoreFile = ".gwtignore";
|
|
22
|
+
|
|
23
|
+
function isPruned(entries) {
|
|
24
|
+
return entries.some(e => e.name === gwtIgnoreFile);
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
function isSrcResFile(name) {
|
|
28
|
+
return name.endsWith(".res");
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
async function walk(dir, acc) {
|
|
32
|
+
let entries;
|
|
33
|
+
try {
|
|
34
|
+
entries = await Promises.readdir(dir, {
|
|
35
|
+
withFileTypes: true
|
|
36
|
+
});
|
|
37
|
+
} catch (exn) {
|
|
38
|
+
entries = [];
|
|
39
|
+
}
|
|
40
|
+
if (isPruned(entries)) {
|
|
41
|
+
return acc;
|
|
42
|
+
}
|
|
43
|
+
let found = acc;
|
|
44
|
+
for (let i = 0, i_finish = entries.length; i < i_finish; ++i) {
|
|
45
|
+
let entry = entries[i];
|
|
46
|
+
if (!ignoreNames.includes(entry.name)) {
|
|
47
|
+
let full = Nodepath.join(dir, entry.name);
|
|
48
|
+
if (entry.isDirectory()) {
|
|
49
|
+
let nested = await walk(full, []);
|
|
50
|
+
found = found.concat(nested);
|
|
51
|
+
} else if (entry.isFile() && entry.name.endsWith(".res")) {
|
|
52
|
+
found = found.concat([full]);
|
|
53
|
+
}
|
|
54
|
+
}
|
|
55
|
+
}
|
|
56
|
+
return found;
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
async function scan(pkgDirs) {
|
|
60
|
+
let order = [];
|
|
61
|
+
let filesByKey = {};
|
|
62
|
+
for (let i = 0, i_finish = pkgDirs.length; i < i_finish; ++i) {
|
|
63
|
+
let dir = pkgDirs[i];
|
|
64
|
+
let srcDir = Nodepath.join(dir, "src");
|
|
65
|
+
if (Nodefs.existsSync(srcDir)) {
|
|
66
|
+
let files = await walk(srcDir, []);
|
|
67
|
+
files.forEach(file => {
|
|
68
|
+
let c = ComponentMeta$ReventlessGwt.componentOfSrcFile(file);
|
|
69
|
+
if (c === undefined) {
|
|
70
|
+
return;
|
|
71
|
+
}
|
|
72
|
+
let key = dir + "::" + c.kind + "::" + c.name;
|
|
73
|
+
let existing = filesByKey[key];
|
|
74
|
+
if (existing !== undefined) {
|
|
75
|
+
filesByKey[key] = existing.concat([file]);
|
|
76
|
+
} else {
|
|
77
|
+
filesByKey[key] = [file];
|
|
78
|
+
order.push({
|
|
79
|
+
dir: dir,
|
|
80
|
+
kind: c.kind,
|
|
81
|
+
name: c.name,
|
|
82
|
+
key: key
|
|
83
|
+
});
|
|
84
|
+
}
|
|
85
|
+
});
|
|
86
|
+
}
|
|
87
|
+
}
|
|
88
|
+
return order.map(o => ({
|
|
89
|
+
dir: o.dir,
|
|
90
|
+
kind: o.kind,
|
|
91
|
+
name: o.name,
|
|
92
|
+
files: Stdlib_Option.getOr(filesByKey[o.key], [])
|
|
93
|
+
}));
|
|
94
|
+
}
|
|
95
|
+
|
|
96
|
+
export {
|
|
97
|
+
ignoreNames,
|
|
98
|
+
shouldIgnore,
|
|
99
|
+
gwtIgnoreFile,
|
|
100
|
+
isPruned,
|
|
101
|
+
isSrcResFile,
|
|
102
|
+
walk,
|
|
103
|
+
scan,
|
|
104
|
+
}
|
|
105
|
+
/* node:fs Not a pure module */
|
|
@@ -0,0 +1,303 @@
|
|
|
1
|
+
open ReventlessCore
|
|
2
|
+
|
|
3
|
+
// Delegate_GWT — GWT for ExtensionPoint mappings and Extension delegates.
|
|
4
|
+
//
|
|
5
|
+
// Both are pure input → published-actions translations and form the one
|
|
6
|
+
// cross-plugin behavioural seam (per `.claude/rules/app-developer.md`). Each
|
|
7
|
+
// mapping has TWO directions, and each adapter drives both:
|
|
8
|
+
//
|
|
9
|
+
// * an ExtensionPoint mapping turns an internal `Delegate` event into public
|
|
10
|
+
// extension-point EVENTS (`mapOutgoingEvent`), and an incoming protocol
|
|
11
|
+
// COMMAND into a wrapped-aggregate command (`mapIncomingCommand`);
|
|
12
|
+
// * an Extension delegate turns an incoming extension-point EVENT into delegate
|
|
13
|
+
// COMMANDS (`mapIncomingEvent`), and an internal `Delegate` event into an
|
|
14
|
+
// outgoing protocol COMMAND (`mapOutgoingEvent`).
|
|
15
|
+
//
|
|
16
|
+
// The stimulus you inject names what arrives at the mapping, NOT what it emits:
|
|
17
|
+
// * `whenDelegateEvent` — an internal delegate event occurs (both adapters'
|
|
18
|
+
// `mapOutgoingEvent`);
|
|
19
|
+
// * `whenIncomingEvent` — a protocol event arrives (Extension `mapIncomingEvent`);
|
|
20
|
+
// * `whenIncomingCommand`— a protocol command arrives (EP `mapIncomingCommand`).
|
|
21
|
+
//
|
|
22
|
+
// This DSL drives the user-level mapping function with the inert `StubRuntime`
|
|
23
|
+
// handles and asserts the SET of published actions — including one-to-many
|
|
24
|
+
// fan-out (e.g. `OrderPlaced{productIds:[…]}` → N × `ItemOrdered`).
|
|
25
|
+
//
|
|
26
|
+
// `FromExtensionPoint(M)` / `FromExtension(M)` mirror the From* adapter pattern
|
|
27
|
+
// of `Mapping_GWT` / `Query_GWT`: one comparison core per direction.
|
|
28
|
+
//
|
|
29
|
+
// See `docs/plans/done/gwt-flow-and-extension-test-kinds.md` Phase 1.
|
|
30
|
+
|
|
31
|
+
module EPMapping = ReventlessInfra.ExtensionPointMapping
|
|
32
|
+
module ExtMapping = ReventlessInfra.ExtensionMapping
|
|
33
|
+
|
|
34
|
+
// A published action normalised for comparison: a routing target plus the
|
|
35
|
+
// encoded payload. EP events are keyed by entity id; delegate commands by the
|
|
36
|
+
// component (slice/aggregate) or extension-point they route to.
|
|
37
|
+
let encPublished = (~target: string, payload: JSON.t): JSON.t => {
|
|
38
|
+
let d = Dict.make()
|
|
39
|
+
d->Dict.set("target", JSON.Encode.string(target))
|
|
40
|
+
d->Dict.set("payload", payload)
|
|
41
|
+
JSON.Encode.object(d)
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
// -- Comparison core ---------------------------------------------------------
|
|
45
|
+
|
|
46
|
+
module type Delegate = {
|
|
47
|
+
let name: string
|
|
48
|
+
type inbound
|
|
49
|
+
// Drive the underlying mapping with StubRuntime, returning the published
|
|
50
|
+
// actions already normalised to JSON.
|
|
51
|
+
let run: inbound => promise<array<JSON.t>>
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
module type T = {
|
|
55
|
+
type inbound
|
|
56
|
+
|
|
57
|
+
let describe: (string, unit => unit) => unit
|
|
58
|
+
let test: (string, ~timeout: int=?, unit => promise<Outcome.outcome>) => unit
|
|
59
|
+
|
|
60
|
+
// Feed the stimulus into the mapping; returns the normalised published actions.
|
|
61
|
+
// The adapters re-export this under direction-specific names (whenDelegateEvent
|
|
62
|
+
// / whenIncomingEvent / whenIncomingCommand).
|
|
63
|
+
let whenInput: inbound => promise<array<JSON.t>>
|
|
64
|
+
let thenPublishedJson: (promise<array<JSON.t>>, array<JSON.t>) => promise<Outcome.outcome>
|
|
65
|
+
let thenPublishesNothing: promise<array<JSON.t>> => promise<Outcome.outcome>
|
|
66
|
+
// Assert the SET of HANDLED DIRECTIVES (HandleDirective actions, encoded by the
|
|
67
|
+
// EP/Extension directive schema). Disjoint from thenPublishedJson — published
|
|
68
|
+
// events/commands and handled directives are separate channels.
|
|
69
|
+
let thenHandlesDirectivesJson: (promise<array<JSON.t>>, array<JSON.t>) => promise<Outcome.outcome>
|
|
70
|
+
}
|
|
71
|
+
|
|
72
|
+
module Make = (D: Delegate): (T with type inbound = D.inbound) => {
|
|
73
|
+
type inbound = D.inbound
|
|
74
|
+
|
|
75
|
+
S.enableJson()
|
|
76
|
+
|
|
77
|
+
let describe = JestBind.describe
|
|
78
|
+
let test = (name, ~timeout=?, body) =>
|
|
79
|
+
JestBind.testPromise(~slice=D.name, name, ~timeout?, body)
|
|
80
|
+
|
|
81
|
+
let whenInput = ev => D.run(ev)
|
|
82
|
+
|
|
83
|
+
// Published actions form a SET — fan-out order is non-deterministic, so the
|
|
84
|
+
// comparison sorts by stringified JSON before comparing.
|
|
85
|
+
let sortJson = (arr: array<JSON.t>) =>
|
|
86
|
+
arr->Array.toSorted((a, b) => String.compare(JSON.stringify(a), JSON.stringify(b)))
|
|
87
|
+
|
|
88
|
+
// Handled directives ride the same normalised array tagged `target:"directive"`
|
|
89
|
+
// so a single mapping run carries both channels; the publish/directive verbs
|
|
90
|
+
// each project to their own. (Published actions never use that target — EP/Ext
|
|
91
|
+
// events and commands route to an id, a component name, or `<ep>:<id>`.)
|
|
92
|
+
let targetOf = (j: JSON.t): string =>
|
|
93
|
+
j
|
|
94
|
+
->JSON.Decode.object
|
|
95
|
+
->Option.flatMap(d => d->Dict.get("target"))
|
|
96
|
+
->Option.flatMap(JSON.Decode.string)
|
|
97
|
+
->Option.getOr("")
|
|
98
|
+
let dropDirectives = arr => arr->Array.filter(j => targetOf(j) != "directive")
|
|
99
|
+
let onlyDirectives = arr => arr->Array.filter(j => targetOf(j) == "directive")
|
|
100
|
+
|
|
101
|
+
let thenPublishedJson = async (actionsP, expected) => {
|
|
102
|
+
let actual = (await actionsP)->dropDirectives
|
|
103
|
+
if sortJson(actual) == sortJson(expected) {
|
|
104
|
+
Outcome.pass
|
|
105
|
+
} else {
|
|
106
|
+
Outcome.fail(PublishedActionsMismatch({expected, actual}))
|
|
107
|
+
}
|
|
108
|
+
}
|
|
109
|
+
|
|
110
|
+
let thenPublishesNothing = actionsP => thenPublishedJson(actionsP, [])
|
|
111
|
+
|
|
112
|
+
let thenHandlesDirectivesJson = async (actionsP, expected) => {
|
|
113
|
+
let actual = (await actionsP)->onlyDirectives
|
|
114
|
+
if sortJson(actual) == sortJson(expected) {
|
|
115
|
+
Outcome.pass
|
|
116
|
+
} else {
|
|
117
|
+
Outcome.fail(PublishedActionsMismatch({expected, actual}))
|
|
118
|
+
}
|
|
119
|
+
}
|
|
120
|
+
}
|
|
121
|
+
|
|
122
|
+
// -- FromExtensionPoint: an EP mapping (both directions) ---------------------
|
|
123
|
+
|
|
124
|
+
module FromExtensionPoint = (M: EPMapping.Mapping) => {
|
|
125
|
+
let encEvent = (e: M.ExtensionPoint.event) => e->Message.encode(M.ExtensionPoint.eventSchema)
|
|
126
|
+
let encCommand = (c: M.Delegate.command) => c->Message.encode(M.Delegate.commandSchema)
|
|
127
|
+
let encDirective = (d: M.ExtensionPoint.directive) =>
|
|
128
|
+
encPublished(~target="directive", d->Message.encode(M.ExtensionPoint.directiveSchema))
|
|
129
|
+
|
|
130
|
+
// Internal delegate event → outgoing extension-point events (`mapOutgoingEvent`).
|
|
131
|
+
module EvCore = Make({
|
|
132
|
+
let name = M.ExtensionPoint.name
|
|
133
|
+
type inbound = M.Delegate.event
|
|
134
|
+
let run = async (event: M.Delegate.event) =>
|
|
135
|
+
switch M.mapOutgoingEvent {
|
|
136
|
+
| None => []
|
|
137
|
+
| Some(f) =>
|
|
138
|
+
let nested =
|
|
139
|
+
await f("gwt-id", event, StubRuntime.meta, StubRuntime.queryEngine)
|
|
140
|
+
->Array.map(async action =>
|
|
141
|
+
switch action {
|
|
142
|
+
| EPMapping.PublishEvent(id, ev) => [encPublished(~target=id, encEvent(ev))]
|
|
143
|
+
| EPMapping.PublishEventAsync(p) =>
|
|
144
|
+
let (id, ev) = await p
|
|
145
|
+
[encPublished(~target=id, encEvent(ev))]
|
|
146
|
+
| EPMapping.HandleDirective(_, dir) => [encDirective(dir)]
|
|
147
|
+
}
|
|
148
|
+
)
|
|
149
|
+
->Promise.all
|
|
150
|
+
nested->Array.flat
|
|
151
|
+
}
|
|
152
|
+
})
|
|
153
|
+
|
|
154
|
+
// Incoming extension-point command → wrapped-aggregate commands (`mapIncomingCommand`).
|
|
155
|
+
module CmdCore = Make({
|
|
156
|
+
let name = M.ExtensionPoint.name
|
|
157
|
+
type inbound = M.ExtensionPoint.command
|
|
158
|
+
let run = async (command: M.ExtensionPoint.command) =>
|
|
159
|
+
M.mapIncomingCommand("gwt-id", command, StubRuntime.meta)->Array.filterMap(action =>
|
|
160
|
+
switch action {
|
|
161
|
+
| EPMapping.PublishCommand(id, cmd) => Some(encPublished(~target=id, encCommand(cmd)))
|
|
162
|
+
| EPMapping.HandleDirective(_, dir) => Some(encDirective(dir))
|
|
163
|
+
}
|
|
164
|
+
)
|
|
165
|
+
})
|
|
166
|
+
|
|
167
|
+
type inbound = M.Delegate.event
|
|
168
|
+
let describe = EvCore.describe
|
|
169
|
+
let test = EvCore.test
|
|
170
|
+
// `thenPublishesNothing` is direction-agnostic (compares to []), usable after
|
|
171
|
+
// either `whenDelegateEvent` or `whenIncomingCommand`.
|
|
172
|
+
let thenPublishesNothing = EvCore.thenPublishesNothing
|
|
173
|
+
|
|
174
|
+
// Delegate event → outgoing protocol events.
|
|
175
|
+
let whenDelegateEvent = EvCore.whenInput
|
|
176
|
+
let thenPublishesEvent = (actionsP, id, event: M.ExtensionPoint.event) =>
|
|
177
|
+
EvCore.thenPublishedJson(actionsP, [encPublished(~target=id, encEvent(event))])
|
|
178
|
+
let thenPublishesEvents = (actionsP, pairs: array<(string, M.ExtensionPoint.event)>) =>
|
|
179
|
+
EvCore.thenPublishedJson(
|
|
180
|
+
actionsP,
|
|
181
|
+
pairs->Array.map(((id, ev)) => encPublished(~target=id, encEvent(ev))),
|
|
182
|
+
)
|
|
183
|
+
|
|
184
|
+
// Incoming protocol command → wrapped-aggregate commands.
|
|
185
|
+
let whenIncomingCommand = CmdCore.whenInput
|
|
186
|
+
let thenPublishesCommand = (actionsP, id, cmd: M.Delegate.command) =>
|
|
187
|
+
CmdCore.thenPublishedJson(actionsP, [encPublished(~target=id, encCommand(cmd))])
|
|
188
|
+
let thenPublishesCommands = (actionsP, pairs: array<(string, M.Delegate.command)>) =>
|
|
189
|
+
CmdCore.thenPublishedJson(
|
|
190
|
+
actionsP,
|
|
191
|
+
pairs->Array.map(((id, cmd)) => encPublished(~target=id, encCommand(cmd))),
|
|
192
|
+
)
|
|
193
|
+
|
|
194
|
+
// Handled directives — usable after either `when`; both cores tag directives on
|
|
195
|
+
// the same channel, so this projects them out regardless of direction.
|
|
196
|
+
let thenHandlesDirective = (actionsP, directive: M.ExtensionPoint.directive) =>
|
|
197
|
+
EvCore.thenHandlesDirectivesJson(actionsP, [encDirective(directive)])
|
|
198
|
+
let thenHandlesDirectives = (actionsP, directives: array<M.ExtensionPoint.directive>) =>
|
|
199
|
+
EvCore.thenHandlesDirectivesJson(actionsP, directives->Array.map(encDirective))
|
|
200
|
+
let thenHandlesNoDirective = actionsP => EvCore.thenHandlesDirectivesJson(actionsP, [])
|
|
201
|
+
}
|
|
202
|
+
|
|
203
|
+
// -- FromExtension: an Extension delegate (both directions) ------------------
|
|
204
|
+
|
|
205
|
+
module FromExtension = (M: ExtMapping.Mapping) => {
|
|
206
|
+
let encCmd = (c: M.Delegate.command) => c->Message.encode(M.Delegate.commandSchema)
|
|
207
|
+
let encEpCmd = (c: M.ExtensionPoint.command) => c->Message.encode(M.ExtensionPoint.commandSchema)
|
|
208
|
+
let encDirective = (d: M.ExtensionPoint.directive) =>
|
|
209
|
+
encPublished(~target="directive", d->Message.encode(M.ExtensionPoint.directiveSchema))
|
|
210
|
+
|
|
211
|
+
// Incoming extension-point event → delegate commands (`mapIncomingEvent`).
|
|
212
|
+
module EvCore = Make({
|
|
213
|
+
let name = M.Delegate.name
|
|
214
|
+
type inbound = M.ExtensionPoint.event
|
|
215
|
+
let run = async (event: M.ExtensionPoint.event) => {
|
|
216
|
+
let nested =
|
|
217
|
+
await M.mapIncomingEvent(
|
|
218
|
+
"gwt-id",
|
|
219
|
+
event,
|
|
220
|
+
StubRuntime.meta,
|
|
221
|
+
StubRuntime.pluginDefinition,
|
|
222
|
+
StubRuntime.queryEngine,
|
|
223
|
+
)
|
|
224
|
+
->Array.map(async action =>
|
|
225
|
+
switch action {
|
|
226
|
+
| ExtMapping.PublishStateChangeSliceCommand(cmd) => [
|
|
227
|
+
encPublished(~target=M.Delegate.name, encCmd(cmd)),
|
|
228
|
+
]
|
|
229
|
+
| ExtMapping.PublishStateChangeSliceCommandAsync(p) =>
|
|
230
|
+
let cmd = await p
|
|
231
|
+
[encPublished(~target=M.Delegate.name, encCmd(cmd))]
|
|
232
|
+
| ExtMapping.PublishStateChangeSliceCommandsAsync(p) =>
|
|
233
|
+
(await p)->Array.map(cmd => encPublished(~target=M.Delegate.name, encCmd(cmd)))
|
|
234
|
+
| ExtMapping.PublishAggregateCommand(id, cmd) => [encPublished(~target=id, encCmd(cmd))]
|
|
235
|
+
| ExtMapping.PublishAggregateCommandAsync(p) =>
|
|
236
|
+
let (id, cmd) = await p
|
|
237
|
+
[encPublished(~target=id, encCmd(cmd))]
|
|
238
|
+
| ExtMapping.PublishAggregateCommandsAsync(p) =>
|
|
239
|
+
(await p)->Array.map(((id, cmd)) => encPublished(~target=id, encCmd(cmd)))
|
|
240
|
+
| ExtMapping.PublishExtensionPointCommand(id, cmd) => [
|
|
241
|
+
encPublished(~target=id, encEpCmd(cmd)),
|
|
242
|
+
]
|
|
243
|
+
| ExtMapping.ForwardCommand({extensionPointName, id, commandJson}) => [
|
|
244
|
+
encPublished(~target=`${extensionPointName}:${id}`, commandJson),
|
|
245
|
+
]
|
|
246
|
+
| ExtMapping.HandleDirective(_, dir) => [encDirective(dir)]
|
|
247
|
+
}
|
|
248
|
+
)
|
|
249
|
+
->Promise.all
|
|
250
|
+
nested->Array.flat
|
|
251
|
+
}
|
|
252
|
+
})
|
|
253
|
+
|
|
254
|
+
// Internal delegate event → outgoing protocol commands (`mapOutgoingEvent`, optional).
|
|
255
|
+
module OutCore = Make({
|
|
256
|
+
let name = M.Delegate.name
|
|
257
|
+
type inbound = M.Delegate.event
|
|
258
|
+
let run = async (event: M.Delegate.event) =>
|
|
259
|
+
switch M.mapOutgoingEvent {
|
|
260
|
+
| None => []
|
|
261
|
+
| Some(f) =>
|
|
262
|
+
f("gwt-id", event, StubRuntime.meta, StubRuntime.pluginDefinition)->Array.filterMap(action =>
|
|
263
|
+
switch action {
|
|
264
|
+
| ExtMapping.PublishExtensionPointCommand(id, cmd) =>
|
|
265
|
+
Some(encPublished(~target=id, encEpCmd(cmd)))
|
|
266
|
+
| ExtMapping.ForwardCommand({extensionPointName, id, commandJson}) =>
|
|
267
|
+
Some(encPublished(~target=`${extensionPointName}:${id}`, commandJson))
|
|
268
|
+
| ExtMapping.HandleDirective(_, dir) => Some(encDirective(dir))
|
|
269
|
+
}
|
|
270
|
+
)
|
|
271
|
+
}
|
|
272
|
+
})
|
|
273
|
+
|
|
274
|
+
type inbound = M.ExtensionPoint.event
|
|
275
|
+
let describe = EvCore.describe
|
|
276
|
+
let test = EvCore.test
|
|
277
|
+
let thenPublishesNothing = EvCore.thenPublishesNothing
|
|
278
|
+
|
|
279
|
+
// Incoming protocol event → delegate commands.
|
|
280
|
+
let whenIncomingEvent = EvCore.whenInput
|
|
281
|
+
let thenPublishesCommand = (actionsP, cmd: M.Delegate.command) =>
|
|
282
|
+
EvCore.thenPublishedJson(actionsP, [encPublished(~target=M.Delegate.name, encCmd(cmd))])
|
|
283
|
+
let thenPublishesCommands = (actionsP, cmds: array<M.Delegate.command>) =>
|
|
284
|
+
EvCore.thenPublishedJson(
|
|
285
|
+
actionsP,
|
|
286
|
+
cmds->Array.map(cmd => encPublished(~target=M.Delegate.name, encCmd(cmd))),
|
|
287
|
+
)
|
|
288
|
+
let thenPublishesAggregateCommand = (actionsP, id, cmd: M.Delegate.command) =>
|
|
289
|
+
EvCore.thenPublishedJson(actionsP, [encPublished(~target=id, encCmd(cmd))])
|
|
290
|
+
|
|
291
|
+
// Internal delegate event → outgoing protocol commands.
|
|
292
|
+
let whenDelegateEvent = OutCore.whenInput
|
|
293
|
+
let thenPublishesExtensionPointCommand = (actionsP, id, cmd: M.ExtensionPoint.command) =>
|
|
294
|
+
OutCore.thenPublishedJson(actionsP, [encPublished(~target=id, encEpCmd(cmd))])
|
|
295
|
+
|
|
296
|
+
// Handled directives — usable after either `when` (both cores tag directives on
|
|
297
|
+
// the same channel).
|
|
298
|
+
let thenHandlesDirective = (actionsP, directive: M.ExtensionPoint.directive) =>
|
|
299
|
+
EvCore.thenHandlesDirectivesJson(actionsP, [encDirective(directive)])
|
|
300
|
+
let thenHandlesDirectives = (actionsP, directives: array<M.ExtensionPoint.directive>) =>
|
|
301
|
+
EvCore.thenHandlesDirectivesJson(actionsP, directives->Array.map(encDirective))
|
|
302
|
+
let thenHandlesNoDirective = actionsP => EvCore.thenHandlesDirectivesJson(actionsP, [])
|
|
303
|
+
}
|