@reventlessdev/reventless-core 3.0.0-alpha.191 → 3.0.0-alpha.193
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 +19 -0
- package/package.json +6 -6
- package/src/admin/Platform_Admin.res.mjs +4 -0
- package/src/admin/Platform_Admin_Structure.res +1 -0
- package/src/admin/Platform_Admin_Structure.res.mjs +2 -1
- package/src/components/Aggregate/Aggregate.res +7 -7
- package/src/components/Aggregate/Aggregate.res.mjs +7 -2
- package/src/components/Aggregate/Aggregate_Builder.res +4 -1
- package/src/components/Aggregate/Aggregate_Builder.res.mjs +11 -3
- package/src/components/Builder_Helpers.res +37 -4
- package/src/components/Builder_Helpers.res.mjs +24 -2
- package/src/components/SideEffectHandler/SideEffectHandler.res +11 -0
- package/src/components/SideEffectHandler/SideEffectHandler_Builder.res +2 -0
- package/src/components/SideEffectHandler/SideEffectHandler_Builder.res.mjs +3 -1
- package/src/components/Task/Task_Builder.res +11 -0
- package/src/components/Task/Task_Builder.res.mjs +2 -0
- package/src/plugin/component/Capability_Inference.res +68 -0
- package/src/plugin/component/Capability_Inference.res.mjs +79 -0
- package/src/plugin/component/Plugin_Helpers.res +18 -7
- package/src/plugin/component/Plugin_Helpers.res.mjs +20 -1
- package/src/plugin/component/Plugin_Structure.res +91 -34
- package/src/plugin/component/Plugin_Structure.res.mjs +82 -12
- package/tests/admin/Platform_ComponentDefinitionsApiTest.res +2 -0
- package/tests/admin/Platform_ComponentDefinitionsApiTest.res.mjs +8 -4
- package/tests/api/SuryToJsonSchemaTest.res +42 -0
- package/tests/api/SuryToJsonSchemaTest.res.mjs +36 -0
- package/tests/message/MessageTest.res +1 -0
- package/tests/message/MessageTest.res.mjs +2 -1
- package/tests/plugin/PluginStructureTest.res +145 -0
- package/tests/plugin/PluginStructureTest.res.mjs +138 -0
- package/tests/plugin/StateChangeSlice/PsChangePhoto.res +33 -0
- package/tests/plugin/StateChangeSlice/PsChangePhoto.res.mjs +64 -0
|
@@ -11,10 +11,13 @@ import * as StorageRef$Reventless from "@reventlessdev/reventless-spec/src/seman
|
|
|
11
11
|
import * as PsShipOrder$ReventlessCore from "./StateChangeSlice/PsShipOrder.res.mjs";
|
|
12
12
|
import * as PsOrdersView$ReventlessCore from "./StateViewSlice/PsOrdersView.res.mjs";
|
|
13
13
|
import * as PsPlaceOrder$ReventlessCore from "./StateChangeSlice/PsPlaceOrder.res.mjs";
|
|
14
|
+
import * as PsChangePhoto$ReventlessCore from "./StateChangeSlice/PsChangePhoto.res.mjs";
|
|
15
|
+
import * as CapabilityManifest$Reventless from "@reventlessdev/reventless-spec/src/components/CapabilityManifest.res.mjs";
|
|
14
16
|
import * as PsAnnotatedView$ReventlessCore from "./StateViewSlice/PsAnnotatedView.res.mjs";
|
|
15
17
|
import * as PsAttachInvoice$ReventlessCore from "./StateChangeSlice/PsAttachInvoice.res.mjs";
|
|
16
18
|
import * as PsCustomersView$ReventlessCore from "./StateViewSlice/PsCustomersView.res.mjs";
|
|
17
19
|
import * as Plugin_Structure$ReventlessCore from "../../src/plugin/component/Plugin_Structure.res.mjs";
|
|
20
|
+
import * as Capability_Inference$ReventlessCore from "../../src/plugin/component/Capability_Inference.res.mjs";
|
|
18
21
|
import * as PsAvailableProductsView$ReventlessCore from "./StateViewSlice/PsAvailableProductsView.res.mjs";
|
|
19
22
|
|
|
20
23
|
let Behavior = {
|
|
@@ -211,6 +214,36 @@ let PsAttachInvoiceSlice = {
|
|
|
211
214
|
make: make$6
|
|
212
215
|
};
|
|
213
216
|
|
|
217
|
+
let Behavior$3 = {
|
|
218
|
+
initialState: false,
|
|
219
|
+
evolve: PsChangePhoto$ReventlessCore.evolve,
|
|
220
|
+
decide: PsChangePhoto$ReventlessCore.decide,
|
|
221
|
+
moduleUrl: PsChangePhoto$ReventlessCore.moduleUrl
|
|
222
|
+
};
|
|
223
|
+
|
|
224
|
+
function make$7(param, param$1, param$2, param$3, param$4, param$5) {
|
|
225
|
+
return 0;
|
|
226
|
+
}
|
|
227
|
+
|
|
228
|
+
let PsChangePhotoSlice_Spec = {
|
|
229
|
+
name: PsChangePhoto$ReventlessCore.name,
|
|
230
|
+
moduleUrl: PsChangePhoto$ReventlessCore.moduleUrl,
|
|
231
|
+
Id: Id$Reventless.$$String,
|
|
232
|
+
consumedEventSchema: PsChangePhoto$ReventlessCore.consumedEventSchema,
|
|
233
|
+
errorSchema: PsChangePhoto$ReventlessCore.errorSchema,
|
|
234
|
+
eventSchema: PsChangePhoto$ReventlessCore.eventSchema,
|
|
235
|
+
commandSchema: PsChangePhoto$ReventlessCore.commandSchema,
|
|
236
|
+
commandAuthorization: PsChangePhoto$ReventlessCore.commandAuthorization,
|
|
237
|
+
readConsistency: PsChangePhoto$ReventlessCore.readConsistency
|
|
238
|
+
};
|
|
239
|
+
|
|
240
|
+
let PsChangePhotoSlice = {
|
|
241
|
+
Spec: PsChangePhotoSlice_Spec,
|
|
242
|
+
Behavior: Behavior$3,
|
|
243
|
+
isAsync: false,
|
|
244
|
+
make: make$7
|
|
245
|
+
};
|
|
246
|
+
|
|
214
247
|
let structure = Plugin_Structure$ReventlessCore.make("TestPlugin", undefined, undefined, [
|
|
215
248
|
PsOrdersViewSlice,
|
|
216
249
|
PsAvailableProductsViewSlice,
|
|
@@ -719,6 +752,110 @@ globalThis.describe("Plugin_Structure.make — Phase 2 graph fields", () => {
|
|
|
719
752
|
globalThis.test("a plugin declaring no stores collects none — not None", () => {
|
|
720
753
|
globalThis.expect(structure.requiredStores).toEqual([]);
|
|
721
754
|
});
|
|
755
|
+
globalThis.test("each requirement keeps its declaring (component, field) sites", () => {
|
|
756
|
+
let expected = [
|
|
757
|
+
{
|
|
758
|
+
store: "TestPlugin.documents",
|
|
759
|
+
component: "AttachInvoice",
|
|
760
|
+
field: "documentUrl"
|
|
761
|
+
},
|
|
762
|
+
{
|
|
763
|
+
store: "branding.logos",
|
|
764
|
+
component: "AttachInvoice",
|
|
765
|
+
field: "logoUrl"
|
|
766
|
+
}
|
|
767
|
+
];
|
|
768
|
+
globalThis.expect(withStores.requiredStoreDeclarations).toEqual(expected);
|
|
769
|
+
});
|
|
770
|
+
globalThis.describe("capability manifest", () => {
|
|
771
|
+
let manifest = CapabilityManifest$Reventless.fromStructure(withStores);
|
|
772
|
+
globalThis.test("keys are byte-identical to requiredStores", () => {
|
|
773
|
+
globalThis.expect(manifest.capabilities.map(c => c.key)).toEqual(Stdlib_Option.getOr(withStores.requiredStores, []));
|
|
774
|
+
});
|
|
775
|
+
globalThis.test("each entry carries its provenance", () => {
|
|
776
|
+
let entry = Stdlib_Option.getOrThrow(manifest.capabilities.find(c => c.key === "TestPlugin.documents"), undefined);
|
|
777
|
+
let expected = [{
|
|
778
|
+
component: "AttachInvoice",
|
|
779
|
+
field: "documentUrl"
|
|
780
|
+
}];
|
|
781
|
+
globalThis.expect(entry.declaredBy).toEqual(expected);
|
|
782
|
+
});
|
|
783
|
+
globalThis.test("a structure declaring nothing yields an empty list, not a missing manifest", () => {
|
|
784
|
+
globalThis.expect(CapabilityManifest$Reventless.fromStructure(structure).capabilities).toEqual([]);
|
|
785
|
+
});
|
|
786
|
+
globalThis.test("rendering is deterministic and newline-terminated", () => {
|
|
787
|
+
let rendered = CapabilityManifest$Reventless.renderForStructure(withStores);
|
|
788
|
+
globalThis.expect(rendered).toBe(`{
|
|
789
|
+
"capabilities": [
|
|
790
|
+
{
|
|
791
|
+
"kind": "ObjectStore",
|
|
792
|
+
"key": "TestPlugin.documents",
|
|
793
|
+
"declaredBy": [
|
|
794
|
+
{
|
|
795
|
+
"component": "AttachInvoice",
|
|
796
|
+
"field": "documentUrl"
|
|
797
|
+
}
|
|
798
|
+
]
|
|
799
|
+
},
|
|
800
|
+
{
|
|
801
|
+
"kind": "ObjectStore",
|
|
802
|
+
"key": "branding.logos",
|
|
803
|
+
"declaredBy": [
|
|
804
|
+
{
|
|
805
|
+
"component": "AttachInvoice",
|
|
806
|
+
"field": "logoUrl"
|
|
807
|
+
}
|
|
808
|
+
]
|
|
809
|
+
}
|
|
810
|
+
]
|
|
811
|
+
}
|
|
812
|
+
`);
|
|
813
|
+
});
|
|
814
|
+
});
|
|
815
|
+
});
|
|
816
|
+
globalThis.describe("capability inference", () => {
|
|
817
|
+
let commandWarnings = Capability_Inference$ReventlessCore.scanSchema("ChangePhoto", PsChangePhoto$ReventlessCore.commandSchema);
|
|
818
|
+
let eventWarnings = Capability_Inference$ReventlessCore.scanSchema("ChangePhoto", PsChangePhoto$ReventlessCore.eventSchema);
|
|
819
|
+
globalThis.test("a heuristic-only match produces a warning", () => {
|
|
820
|
+
let expected = [{
|
|
821
|
+
component: "ChangePhoto",
|
|
822
|
+
field: "photoUrl"
|
|
823
|
+
}];
|
|
824
|
+
globalThis.expect(commandWarnings).toEqual(expected);
|
|
825
|
+
});
|
|
826
|
+
globalThis.test("a declared field with a heuristic name does not warn", () => {
|
|
827
|
+
let expected = [{
|
|
828
|
+
component: "ChangePhoto",
|
|
829
|
+
field: "photoUrl"
|
|
830
|
+
}];
|
|
831
|
+
globalThis.expect(eventWarnings).toEqual(expected);
|
|
832
|
+
});
|
|
833
|
+
globalThis.test("a heuristic-only match reaches no manifest entry", () => {
|
|
834
|
+
let withHeuristicField = Plugin_Structure$ReventlessCore.make("TestPlugin", undefined, undefined, undefined, [PsChangePhotoSlice], undefined, undefined, undefined, undefined, undefined, undefined);
|
|
835
|
+
globalThis.expect(withHeuristicField.requiredStores).toEqual(["TestPlugin.productPhotos"]);
|
|
836
|
+
let manifest = CapabilityManifest$Reventless.fromStructure(withHeuristicField);
|
|
837
|
+
globalThis.expect(manifest.capabilities.every(entry => entry.declaredBy.every(site => site.field !== "photoUrl"))).toBe(true);
|
|
838
|
+
});
|
|
839
|
+
globalThis.test("the warning names the field and the settling annotation", () => {
|
|
840
|
+
let text = Capability_Inference$ReventlessCore.message(commandWarnings[0]);
|
|
841
|
+
globalThis.expect(text.includes("ChangePhoto.photoUrl")).toBe(true);
|
|
842
|
+
globalThis.expect(text.includes("@storageRef")).toBe(true);
|
|
843
|
+
});
|
|
844
|
+
globalThis.test("suffix and exact name rules match; ordinary names do not", () => {
|
|
845
|
+
globalThis.expect([
|
|
846
|
+
"invoiceFileRef",
|
|
847
|
+
"upload",
|
|
848
|
+
"thumbnail",
|
|
849
|
+
"customerName",
|
|
850
|
+
"documentUrl"
|
|
851
|
+
].map(Capability_Inference$ReventlessCore.nameMatches)).toEqual([
|
|
852
|
+
true,
|
|
853
|
+
true,
|
|
854
|
+
true,
|
|
855
|
+
false,
|
|
856
|
+
false
|
|
857
|
+
]);
|
|
858
|
+
});
|
|
722
859
|
});
|
|
723
860
|
});
|
|
724
861
|
|
|
@@ -730,6 +867,7 @@ export {
|
|
|
730
867
|
PsCustomersViewSlice,
|
|
731
868
|
PsAnnotatedViewSlice,
|
|
732
869
|
PsAttachInvoiceSlice,
|
|
870
|
+
PsChangePhotoSlice,
|
|
733
871
|
structure,
|
|
734
872
|
}
|
|
735
873
|
/* structure Not a pure module */
|
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
// Test fixture spec for heuristic capability inference.
|
|
2
|
+
//
|
|
3
|
+
// `photoUrl` matches the stored-object name heuristic but carries no
|
|
4
|
+
// `@storageRef` — the case that must produce a warning and no manifest entry.
|
|
5
|
+
// `caption` matches nothing, so the scan's silence on it is also exercised.
|
|
6
|
+
|
|
7
|
+
@@reventless.spec("ChangePhoto")
|
|
8
|
+
|
|
9
|
+
type state = bool
|
|
10
|
+
let initialState = false
|
|
11
|
+
|
|
12
|
+
@schema
|
|
13
|
+
type consumedEvent = OrderPlaced
|
|
14
|
+
|
|
15
|
+
let evolve = (_state, _event) => true
|
|
16
|
+
|
|
17
|
+
@schema
|
|
18
|
+
type command = ChangePhoto({productId: string, photoUrl: string, caption: string})
|
|
19
|
+
|
|
20
|
+
@schema
|
|
21
|
+
type error = ProductNotFound
|
|
22
|
+
|
|
23
|
+
// `thumbnail` matches the same name heuristic but IS declared — the case the
|
|
24
|
+
// lint must stay silent on, because the declaration already provisions it.
|
|
25
|
+
@schema
|
|
26
|
+
type event =
|
|
27
|
+
| PhotoChanged({
|
|
28
|
+
productId: string,
|
|
29
|
+
photoUrl: string,
|
|
30
|
+
@storageRef("productPhotos") thumbnail: string,
|
|
31
|
+
})
|
|
32
|
+
|
|
33
|
+
let decide = (_state, _command): result<array<event>, error> => Ok([])
|
|
@@ -0,0 +1,64 @@
|
|
|
1
|
+
// Generated by ReScript, PLEASE EDIT WITH CARE
|
|
2
|
+
|
|
3
|
+
import * as S from "sury/src/S.res.mjs";
|
|
4
|
+
import * as DcbTag$Reventless from "@reventlessdev/reventless-spec/src/components/DcbTag.res.mjs";
|
|
5
|
+
import * as StorageRef$Reventless from "@reventlessdev/reventless-spec/src/semantic/StorageRef.res.mjs";
|
|
6
|
+
|
|
7
|
+
let consumedEventSchema = S.literal("OrderPlaced");
|
|
8
|
+
|
|
9
|
+
function evolve(_state, _event) {
|
|
10
|
+
return true;
|
|
11
|
+
}
|
|
12
|
+
|
|
13
|
+
let commandSchema = S.schema(s => ({
|
|
14
|
+
TAG: "ChangePhoto",
|
|
15
|
+
productId: s.m(DcbTag$Reventless.string),
|
|
16
|
+
photoUrl: s.m(S.string),
|
|
17
|
+
caption: s.m(S.string)
|
|
18
|
+
}));
|
|
19
|
+
|
|
20
|
+
let errorSchema = S.literal("ProductNotFound");
|
|
21
|
+
|
|
22
|
+
let eventSchema = S.schema(s => ({
|
|
23
|
+
TAG: "PhotoChanged",
|
|
24
|
+
productId: s.m(DcbTag$Reventless.string),
|
|
25
|
+
photoUrl: s.m(S.string),
|
|
26
|
+
thumbnail: s.m(StorageRef$Reventless.forStore(undefined, "productPhotos"))
|
|
27
|
+
}));
|
|
28
|
+
|
|
29
|
+
function decide(_state, _command) {
|
|
30
|
+
return {
|
|
31
|
+
TAG: "Ok",
|
|
32
|
+
_0: []
|
|
33
|
+
};
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
function commandAuthorization(param) {
|
|
37
|
+
return "AllowAuthenticated";
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
let name = "ChangePhoto";
|
|
41
|
+
|
|
42
|
+
let Id;
|
|
43
|
+
|
|
44
|
+
let initialState = false;
|
|
45
|
+
|
|
46
|
+
let moduleUrl = "@reventlessdev/reventless-core/tests/plugin/StateChangeSlice/PsChangePhoto.res.mjs";
|
|
47
|
+
|
|
48
|
+
let readConsistency = "EscalateOnRetry";
|
|
49
|
+
|
|
50
|
+
export {
|
|
51
|
+
name,
|
|
52
|
+
Id,
|
|
53
|
+
initialState,
|
|
54
|
+
consumedEventSchema,
|
|
55
|
+
evolve,
|
|
56
|
+
commandSchema,
|
|
57
|
+
errorSchema,
|
|
58
|
+
eventSchema,
|
|
59
|
+
decide,
|
|
60
|
+
moduleUrl,
|
|
61
|
+
commandAuthorization,
|
|
62
|
+
readConsistency,
|
|
63
|
+
}
|
|
64
|
+
/* consumedEventSchema Not a pure module */
|