@reventlessdev/reventless-gwt 1.0.0-alpha.74
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +698 -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 +603 -0
- package/src/Behavior_GWT.res.mjs +426 -0
- package/src/Bind.res +29 -0
- package/src/Bind.res.mjs +22 -0
- package/src/BuildClassifier.res +137 -0
- package/src/BuildClassifier.res.mjs +136 -0
- package/src/Cancellation.res +31 -0
- package/src/Cancellation.res.mjs +45 -0
- package/src/ChildProcess.res +84 -0
- package/src/ChildProcess.res.mjs +92 -0
- package/src/Cli.res +671 -0
- package/src/Cli.res.mjs +754 -0
- package/src/Collector.res +201 -0
- package/src/Collector.res.mjs +215 -0
- package/src/ComponentMeta.res +104 -0
- package/src/ComponentMeta.res.mjs +120 -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 +103 -0
- package/src/DomainDeadCode.res +93 -0
- package/src/DomainDeadCode.res.mjs +69 -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 +36 -0
- package/src/Filter.res.mjs +40 -0
- package/src/Flow_GWT.res +664 -0
- package/src/Flow_GWT.res.mjs +604 -0
- package/src/FormatterHuman.res +138 -0
- package/src/FormatterHuman.res.mjs +122 -0
- package/src/FormatterJson.res +257 -0
- package/src/FormatterJson.res.mjs +320 -0
- package/src/FormatterJunit.res +93 -0
- package/src/FormatterJunit.res.mjs +90 -0
- package/src/FormatterTap.res +139 -0
- package/src/FormatterTap.res.mjs +149 -0
- package/src/FormatterVsCode.res +362 -0
- package/src/FormatterVsCode.res.mjs +564 -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 +135 -0
- package/src/LocalHost.res.mjs +127 -0
- package/src/Mapping_GWT.res +474 -0
- package/src/Mapping_GWT.res.mjs +322 -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 +161 -0
- package/src/Outcome.res.mjs +140 -0
- package/src/PackageScan.res +80 -0
- package/src/PackageScan.res.mjs +81 -0
- package/src/PlatformRunner.res +160 -0
- package/src/PlatformRunner.res.mjs +155 -0
- package/src/PlatformScan.res +138 -0
- package/src/PlatformScan.res.mjs +131 -0
- package/src/ProcessManager.res +91 -0
- package/src/ProcessManager.res.mjs +80 -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/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 +53 -0
- package/src/StubRuntime.res.mjs +54 -0
- package/src/TestFixtures.res +16 -0
- package/src/TestFixtures.res.mjs +34 -0
- package/src/Watch.res +92 -0
- package/src/Watch.res.mjs +83 -0
- package/src/WatcherProbe.res +48 -0
- package/src/WatcherProbe.res.mjs +46 -0
- package/tests/AutomationGwtTest.res +71 -0
- package/tests/AutomationGwtTest.res.mjs +189 -0
- package/tests/BuildClassifierTest.res +94 -0
- package/tests/BuildClassifierTest.res.mjs +132 -0
- package/tests/ComponentMetaTest.res +52 -0
- package/tests/ComponentMetaTest.res.mjs +57 -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 +116 -0
- package/tests/DomainDeadCodeTest.res.mjs +155 -0
- package/tests/DomainGraphTest.res +365 -0
- package/tests/DomainGraphTest.res.mjs +413 -0
- package/tests/FlowAggregateGwtTest.res +169 -0
- package/tests/FlowAggregateGwtTest.res.mjs +269 -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 +432 -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 +98 -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 +348 -0
- package/tests/MappingGwtTest.res.mjs +592 -0
- package/tests/OutboundTranslationGwtTest.res +59 -0
- package/tests/OutboundTranslationGwtTest.res.mjs +138 -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 +78 -0
- package/tests/WatchDebounceTest.res.mjs +97 -0
|
@@ -0,0 +1,42 @@
|
|
|
1
|
+
// Unit test for the `.gwtignore` subtree prune in `Discovery.discover`. Builds a
|
|
2
|
+
// throwaway tree under the OS temp dir: a `keep/` directory with a GWT test, and
|
|
3
|
+
// a `skip/` directory carrying a `.gwtignore` sentinel alongside its own GWT
|
|
4
|
+
// test. Discovery must return the former and prune the latter — the guarantee
|
|
5
|
+
// the codegen golden fixtures rely on (they ship compiled `*_GWT.res.mjs` on
|
|
6
|
+
// disk that must never surface as live tests).
|
|
7
|
+
|
|
8
|
+
open JestGlobals
|
|
9
|
+
|
|
10
|
+
@module("node:os") external tmpdir: unit => string = "tmpdir"
|
|
11
|
+
@module("node:path") external join: (string, string) => string = "join"
|
|
12
|
+
|
|
13
|
+
type mkdirOpts = {recursive: bool}
|
|
14
|
+
@module("node:fs/promises") external mkdir: (string, mkdirOpts) => promise<Nullable.t<string>> = "mkdir"
|
|
15
|
+
@module("node:fs/promises") external writeFile: (string, string) => promise<unit> = "writeFile"
|
|
16
|
+
|
|
17
|
+
type rmOpts = {recursive: bool, force: bool}
|
|
18
|
+
@module("node:fs/promises") external rm: (string, rmOpts) => promise<unit> = "rm"
|
|
19
|
+
|
|
20
|
+
let endsWith = (paths: array<string>, suffix: string) =>
|
|
21
|
+
paths->Array.some(p => String.endsWith(p, suffix))
|
|
22
|
+
|
|
23
|
+
describe("Discovery .gwtignore prune", () => {
|
|
24
|
+
testPromise("keeps sibling GWT tests but prunes a subtree carrying .gwtignore", async () => {
|
|
25
|
+
let root = join(tmpdir(), "reventless-gwt-gwtignore-test")
|
|
26
|
+
let _ = await rm(root, {recursive: true, force: true})
|
|
27
|
+
let keep = join(root, "keep")
|
|
28
|
+
let skip = join(root, "skip")
|
|
29
|
+
let _ = await mkdir(keep, {recursive: true})
|
|
30
|
+
let _ = await mkdir(skip, {recursive: true})
|
|
31
|
+
let _ = await writeFile(join(keep, "Keep_GWT.res.mjs"), "")
|
|
32
|
+
let _ = await writeFile(join(skip, "Skip_GWT.res.mjs"), "")
|
|
33
|
+
let _ = await writeFile(join(skip, ".gwtignore"), "")
|
|
34
|
+
|
|
35
|
+
let found = await Discovery.discover([root])
|
|
36
|
+
|
|
37
|
+
expect(found->endsWith("keep/Keep_GWT.res.mjs"))->toBe(true)
|
|
38
|
+
expect(found->endsWith("skip/Skip_GWT.res.mjs"))->toBe(false)
|
|
39
|
+
|
|
40
|
+
let _ = await rm(root, {recursive: true, force: true})
|
|
41
|
+
})
|
|
42
|
+
})
|
|
@@ -0,0 +1,43 @@
|
|
|
1
|
+
// Generated by ReScript, PLEASE EDIT WITH CARE
|
|
2
|
+
|
|
3
|
+
import * as Nodeos from "node:os";
|
|
4
|
+
import * as Nodepath from "node:path";
|
|
5
|
+
import * as Promises from "node:fs/promises";
|
|
6
|
+
import * as Discovery$ReventlessGwt from "../src/Discovery.res.mjs";
|
|
7
|
+
|
|
8
|
+
function endsWith(paths, suffix) {
|
|
9
|
+
return paths.some(p => p.endsWith(suffix));
|
|
10
|
+
}
|
|
11
|
+
|
|
12
|
+
globalThis.describe("Discovery .gwtignore prune", () => {
|
|
13
|
+
globalThis.test("keeps sibling GWT tests but prunes a subtree carrying .gwtignore", async () => {
|
|
14
|
+
let root = Nodepath.join(Nodeos.tmpdir(), "reventless-gwt-gwtignore-test");
|
|
15
|
+
await Promises.rm(root, {
|
|
16
|
+
recursive: true,
|
|
17
|
+
force: true
|
|
18
|
+
});
|
|
19
|
+
let keep = Nodepath.join(root, "keep");
|
|
20
|
+
let skip = Nodepath.join(root, "skip");
|
|
21
|
+
await Promises.mkdir(keep, {
|
|
22
|
+
recursive: true
|
|
23
|
+
});
|
|
24
|
+
await Promises.mkdir(skip, {
|
|
25
|
+
recursive: true
|
|
26
|
+
});
|
|
27
|
+
await Promises.writeFile(Nodepath.join(keep, "Keep_GWT.res.mjs"), "");
|
|
28
|
+
await Promises.writeFile(Nodepath.join(skip, "Skip_GWT.res.mjs"), "");
|
|
29
|
+
await Promises.writeFile(Nodepath.join(skip, ".gwtignore"), "");
|
|
30
|
+
let found = await Discovery$ReventlessGwt.discover([root]);
|
|
31
|
+
globalThis.expect(endsWith(found, "keep/Keep_GWT.res.mjs")).toBe(true);
|
|
32
|
+
globalThis.expect(endsWith(found, "skip/Skip_GWT.res.mjs")).toBe(false);
|
|
33
|
+
await Promises.rm(root, {
|
|
34
|
+
recursive: true,
|
|
35
|
+
force: true
|
|
36
|
+
});
|
|
37
|
+
});
|
|
38
|
+
});
|
|
39
|
+
|
|
40
|
+
export {
|
|
41
|
+
endsWith,
|
|
42
|
+
}
|
|
43
|
+
/* Not a pure module */
|
|
@@ -0,0 +1,116 @@
|
|
|
1
|
+
// Unit tests for DomainDeadCode.analyze — orphan-event reachability over synthetic
|
|
2
|
+
// pluginStructures. Pure (no reventless-local import), so it runs under Jest. The
|
|
3
|
+
// real end-to-end pass over the example plugins is exercised by the LocalHost
|
|
4
|
+
// integration test; here we drive the analysis with hand-built fixtures to pin the
|
|
5
|
+
// orphan / not-orphan boundary precisely.
|
|
6
|
+
|
|
7
|
+
open JestGlobals
|
|
8
|
+
|
|
9
|
+
// ── terse builders for the verbose pluginStructure sub-records ──
|
|
10
|
+
let writable = (~name, ~produces=[], ~consumes=[], ~linkedViews=[]): Reventless.Plugin.writableDef => {
|
|
11
|
+
name,
|
|
12
|
+
commands: [],
|
|
13
|
+
producedEventTypes: produces,
|
|
14
|
+
consumedEventTypes: consumes,
|
|
15
|
+
linkedViews,
|
|
16
|
+
consistencyRead: None,
|
|
17
|
+
events: [],
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
let queryable = (~name, ~consumes=[]): Reventless.Plugin.queryableDef => {
|
|
21
|
+
name,
|
|
22
|
+
queryField: "",
|
|
23
|
+
schema: "",
|
|
24
|
+
consumedEventTypes: consumes,
|
|
25
|
+
linkedWriteSide: [],
|
|
26
|
+
labelField: "id",
|
|
27
|
+
searchableFields: [],
|
|
28
|
+
statusField: None,
|
|
29
|
+
visibility: None,
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
let automation = (~name, ~consumes=[]): Reventless.Plugin.automationSliceDef => {
|
|
33
|
+
name,
|
|
34
|
+
consumedEventTypes: consumes,
|
|
35
|
+
producedCommandTypes: [],
|
|
36
|
+
targetName: "",
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
let structure = (
|
|
40
|
+
~aggregates=[],
|
|
41
|
+
~readModels=[],
|
|
42
|
+
~stateViewSlices=[],
|
|
43
|
+
~stateChangeSlices=[],
|
|
44
|
+
~automationSlices=[],
|
|
45
|
+
~outboundTranslationSlices=[],
|
|
46
|
+
~extensions=[],
|
|
47
|
+
): Reventless.Plugin.pluginStructure => {
|
|
48
|
+
readModels,
|
|
49
|
+
stateViewSlices,
|
|
50
|
+
stateChangeSlices,
|
|
51
|
+
aggregates,
|
|
52
|
+
automationSlices,
|
|
53
|
+
outboundTranslationSlices,
|
|
54
|
+
inboundTranslationSlices: [],
|
|
55
|
+
extensions,
|
|
56
|
+
extensionPoints: None,
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
describe("DomainDeadCode.analyze — orphan events", () => {
|
|
60
|
+
testPromise("flags a produced event no component consumes", async () => {
|
|
61
|
+
let shop = structure(
|
|
62
|
+
~aggregates=[writable(~name="Order", ~produces=["Shop.Placed", "Shop.Archived"])],
|
|
63
|
+
~readModels=[queryable(~name="Orders", ~consumes=["Shop.Placed"])],
|
|
64
|
+
)
|
|
65
|
+
let findings = DomainDeadCode.analyze(~structures=[("Shop", shop)])
|
|
66
|
+
expect(findings->Array.map(f => f.detail))->toEqual(["Shop.Archived"])
|
|
67
|
+
let f = findings->Array.getUnsafe(0)
|
|
68
|
+
expect((f.kind, f.pluginName, f.componentName))->toEqual(("OrphanEvent", "Shop", "Order"))
|
|
69
|
+
})
|
|
70
|
+
|
|
71
|
+
testPromise("a consumer in ANY plugin clears the orphan (cross-plugin)", async () => {
|
|
72
|
+
let shop = structure(~aggregates=[writable(~name="Order", ~produces=["Shop.Placed"])])
|
|
73
|
+
let analytics = structure(~automationSlices=[automation(~name="OnPlaced", ~consumes=["Shop.Placed"])])
|
|
74
|
+
let findings = DomainDeadCode.analyze(
|
|
75
|
+
~structures=[("Shop", shop), ("Analytics", analytics)]
|
|
76
|
+
)
|
|
77
|
+
expect(findings->Array.length)->toBe(0)
|
|
78
|
+
})
|
|
79
|
+
|
|
80
|
+
testPromise("consumption via a state-view slice and a state-change DCB read both count", async () => {
|
|
81
|
+
let s = structure(
|
|
82
|
+
~aggregates=[writable(~name="Order", ~produces=["Shop.Placed", "Shop.Shipped"])],
|
|
83
|
+
~stateViewSlices=[queryable(~name="OrderView", ~consumes=["Shop.Placed"])],
|
|
84
|
+
~stateChangeSlices=[writable(~name="Ship", ~consumes=["Shop.Shipped"])],
|
|
85
|
+
)
|
|
86
|
+
let findings = DomainDeadCode.analyze(~structures=[("Shop", s)])
|
|
87
|
+
expect(findings->Array.length)->toBe(0)
|
|
88
|
+
})
|
|
89
|
+
|
|
90
|
+
testPromise("a linked classic read model clears all the aggregate's events (rule 2)", async () => {
|
|
91
|
+
// Classic aggregate → read-model link lives on the producer (`linkedViews`); the
|
|
92
|
+
// read model's consumedEventTypes is empty. The aggregate must not be flagged.
|
|
93
|
+
let shop = structure(
|
|
94
|
+
~aggregates=[
|
|
95
|
+
writable(~name="Order", ~produces=["Shop.Placed", "Shop.Archived"], ~linkedViews=["Orders"]),
|
|
96
|
+
],
|
|
97
|
+
~readModels=[queryable(~name="Orders")],
|
|
98
|
+
)
|
|
99
|
+
let findings = DomainDeadCode.analyze(~structures=[("Shop", shop)])
|
|
100
|
+
expect(findings->Array.length)->toBe(0)
|
|
101
|
+
})
|
|
102
|
+
|
|
103
|
+
testPromise("an aggregate with no view and no consumer is fully orphaned", async () => {
|
|
104
|
+
let shop = structure(~aggregates=[writable(~name="Audit", ~produces=["Shop.Logged"])])
|
|
105
|
+
let findings = DomainDeadCode.analyze(~structures=[("Shop", shop)])
|
|
106
|
+
expect(findings->Array.map(f => f.detail))->toEqual(["Shop.Logged"])
|
|
107
|
+
})
|
|
108
|
+
|
|
109
|
+
testPromise("state-change slices are scanned as producers too", async () => {
|
|
110
|
+
let s = structure(
|
|
111
|
+
~stateChangeSlices=[writable(~name="Reserve", ~produces=["Shop.Reserved"])],
|
|
112
|
+
)
|
|
113
|
+
let findings = DomainDeadCode.analyze(~structures=[("Shop", s)])
|
|
114
|
+
expect(findings->Array.map(f => (f.componentName, f.detail)))->toEqual([("Reserve", "Shop.Reserved")])
|
|
115
|
+
})
|
|
116
|
+
})
|
|
@@ -0,0 +1,155 @@
|
|
|
1
|
+
// Generated by ReScript, PLEASE EDIT WITH CARE
|
|
2
|
+
|
|
3
|
+
import * as DomainDeadCode$ReventlessGwt from "../src/DomainDeadCode.res.mjs";
|
|
4
|
+
|
|
5
|
+
function writable(name, producesOpt, consumesOpt, linkedViewsOpt) {
|
|
6
|
+
let produces = producesOpt !== undefined ? producesOpt : [];
|
|
7
|
+
let consumes = consumesOpt !== undefined ? consumesOpt : [];
|
|
8
|
+
let linkedViews = linkedViewsOpt !== undefined ? linkedViewsOpt : [];
|
|
9
|
+
return {
|
|
10
|
+
name: name,
|
|
11
|
+
commands: [],
|
|
12
|
+
producedEventTypes: produces,
|
|
13
|
+
consumedEventTypes: consumes,
|
|
14
|
+
linkedViews: linkedViews,
|
|
15
|
+
consistencyRead: undefined,
|
|
16
|
+
events: []
|
|
17
|
+
};
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
function queryable(name, consumesOpt) {
|
|
21
|
+
let consumes = consumesOpt !== undefined ? consumesOpt : [];
|
|
22
|
+
return {
|
|
23
|
+
name: name,
|
|
24
|
+
queryField: "",
|
|
25
|
+
schema: "",
|
|
26
|
+
consumedEventTypes: consumes,
|
|
27
|
+
linkedWriteSide: [],
|
|
28
|
+
labelField: "id",
|
|
29
|
+
searchableFields: [],
|
|
30
|
+
statusField: undefined,
|
|
31
|
+
visibility: undefined
|
|
32
|
+
};
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
function automation(name, consumesOpt) {
|
|
36
|
+
let consumes = consumesOpt !== undefined ? consumesOpt : [];
|
|
37
|
+
return {
|
|
38
|
+
name: name,
|
|
39
|
+
consumedEventTypes: consumes,
|
|
40
|
+
producedCommandTypes: [],
|
|
41
|
+
targetName: ""
|
|
42
|
+
};
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
function structure(aggregatesOpt, readModelsOpt, stateViewSlicesOpt, stateChangeSlicesOpt, automationSlicesOpt, outboundTranslationSlicesOpt, extensionsOpt) {
|
|
46
|
+
let aggregates = aggregatesOpt !== undefined ? aggregatesOpt : [];
|
|
47
|
+
let readModels = readModelsOpt !== undefined ? readModelsOpt : [];
|
|
48
|
+
let stateViewSlices = stateViewSlicesOpt !== undefined ? stateViewSlicesOpt : [];
|
|
49
|
+
let stateChangeSlices = stateChangeSlicesOpt !== undefined ? stateChangeSlicesOpt : [];
|
|
50
|
+
let automationSlices = automationSlicesOpt !== undefined ? automationSlicesOpt : [];
|
|
51
|
+
let outboundTranslationSlices = outboundTranslationSlicesOpt !== undefined ? outboundTranslationSlicesOpt : [];
|
|
52
|
+
let extensions = extensionsOpt !== undefined ? extensionsOpt : [];
|
|
53
|
+
return {
|
|
54
|
+
readModels: readModels,
|
|
55
|
+
stateViewSlices: stateViewSlices,
|
|
56
|
+
stateChangeSlices: stateChangeSlices,
|
|
57
|
+
aggregates: aggregates,
|
|
58
|
+
automationSlices: automationSlices,
|
|
59
|
+
outboundTranslationSlices: outboundTranslationSlices,
|
|
60
|
+
inboundTranslationSlices: [],
|
|
61
|
+
extensions: extensions,
|
|
62
|
+
extensionPoints: undefined
|
|
63
|
+
};
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
globalThis.describe("DomainDeadCode.analyze — orphan events", () => {
|
|
67
|
+
globalThis.test("flags a produced event no component consumes", async () => {
|
|
68
|
+
let shop = structure([writable("Order", [
|
|
69
|
+
"Shop.Placed",
|
|
70
|
+
"Shop.Archived"
|
|
71
|
+
], undefined, undefined)], [queryable("Orders", ["Shop.Placed"])], undefined, undefined, undefined, undefined, undefined);
|
|
72
|
+
let findings = DomainDeadCode$ReventlessGwt.analyze([[
|
|
73
|
+
"Shop",
|
|
74
|
+
shop
|
|
75
|
+
]]);
|
|
76
|
+
globalThis.expect(findings.map(f => f.detail)).toEqual(["Shop.Archived"]);
|
|
77
|
+
let f = findings[0];
|
|
78
|
+
globalThis.expect([
|
|
79
|
+
f.kind,
|
|
80
|
+
f.pluginName,
|
|
81
|
+
f.componentName
|
|
82
|
+
]).toEqual([
|
|
83
|
+
"OrphanEvent",
|
|
84
|
+
"Shop",
|
|
85
|
+
"Order"
|
|
86
|
+
]);
|
|
87
|
+
});
|
|
88
|
+
globalThis.test("a consumer in ANY plugin clears the orphan (cross-plugin)", async () => {
|
|
89
|
+
let shop = structure([writable("Order", ["Shop.Placed"], undefined, undefined)], undefined, undefined, undefined, undefined, undefined, undefined);
|
|
90
|
+
let analytics = structure(undefined, undefined, undefined, undefined, [automation("OnPlaced", ["Shop.Placed"])], undefined, undefined);
|
|
91
|
+
let findings = DomainDeadCode$ReventlessGwt.analyze([
|
|
92
|
+
[
|
|
93
|
+
"Shop",
|
|
94
|
+
shop
|
|
95
|
+
],
|
|
96
|
+
[
|
|
97
|
+
"Analytics",
|
|
98
|
+
analytics
|
|
99
|
+
]
|
|
100
|
+
]);
|
|
101
|
+
globalThis.expect(findings.length).toBe(0);
|
|
102
|
+
});
|
|
103
|
+
globalThis.test("consumption via a state-view slice and a state-change DCB read both count", async () => {
|
|
104
|
+
let s = structure([writable("Order", [
|
|
105
|
+
"Shop.Placed",
|
|
106
|
+
"Shop.Shipped"
|
|
107
|
+
], undefined, undefined)], undefined, [queryable("OrderView", ["Shop.Placed"])], [writable("Ship", undefined, ["Shop.Shipped"], undefined)], undefined, undefined, undefined);
|
|
108
|
+
let findings = DomainDeadCode$ReventlessGwt.analyze([[
|
|
109
|
+
"Shop",
|
|
110
|
+
s
|
|
111
|
+
]]);
|
|
112
|
+
globalThis.expect(findings.length).toBe(0);
|
|
113
|
+
});
|
|
114
|
+
globalThis.test("a linked classic read model clears all the aggregate's events (rule 2)", async () => {
|
|
115
|
+
let shop = structure([writable("Order", [
|
|
116
|
+
"Shop.Placed",
|
|
117
|
+
"Shop.Archived"
|
|
118
|
+
], undefined, ["Orders"])], [queryable("Orders", undefined)], undefined, undefined, undefined, undefined, undefined);
|
|
119
|
+
let findings = DomainDeadCode$ReventlessGwt.analyze([[
|
|
120
|
+
"Shop",
|
|
121
|
+
shop
|
|
122
|
+
]]);
|
|
123
|
+
globalThis.expect(findings.length).toBe(0);
|
|
124
|
+
});
|
|
125
|
+
globalThis.test("an aggregate with no view and no consumer is fully orphaned", async () => {
|
|
126
|
+
let shop = structure([writable("Audit", ["Shop.Logged"], undefined, undefined)], undefined, undefined, undefined, undefined, undefined, undefined);
|
|
127
|
+
let findings = DomainDeadCode$ReventlessGwt.analyze([[
|
|
128
|
+
"Shop",
|
|
129
|
+
shop
|
|
130
|
+
]]);
|
|
131
|
+
globalThis.expect(findings.map(f => f.detail)).toEqual(["Shop.Logged"]);
|
|
132
|
+
});
|
|
133
|
+
globalThis.test("state-change slices are scanned as producers too", async () => {
|
|
134
|
+
let s = structure(undefined, undefined, undefined, [writable("Reserve", ["Shop.Reserved"], undefined, undefined)], undefined, undefined, undefined);
|
|
135
|
+
let findings = DomainDeadCode$ReventlessGwt.analyze([[
|
|
136
|
+
"Shop",
|
|
137
|
+
s
|
|
138
|
+
]]);
|
|
139
|
+
globalThis.expect(findings.map(f => [
|
|
140
|
+
f.componentName,
|
|
141
|
+
f.detail
|
|
142
|
+
])).toEqual([[
|
|
143
|
+
"Reserve",
|
|
144
|
+
"Shop.Reserved"
|
|
145
|
+
]]);
|
|
146
|
+
});
|
|
147
|
+
});
|
|
148
|
+
|
|
149
|
+
export {
|
|
150
|
+
writable,
|
|
151
|
+
queryable,
|
|
152
|
+
automation,
|
|
153
|
+
structure,
|
|
154
|
+
}
|
|
155
|
+
/* Not a pure module */
|