@reventlessdev/reventless-core 3.0.0-alpha.278 → 3.0.0-alpha.279
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 +7 -0
- package/package.json +8 -8
- package/src/plugin/component/Plugin.res +1 -0
- package/src/plugin/component/Plugin_Builder.res +2 -0
- package/src/plugin/component/Plugin_Builder.res.mjs +3 -2
- package/src/plugin/component/Plugin_Structure.res +20 -7
- package/src/plugin/component/Plugin_Structure.res.mjs +13 -8
- package/tests/plugin/IdentityReferenceTest.res +24 -1
- package/tests/plugin/IdentityReferenceTest.res.mjs +30 -10
- package/tests/plugin/ManifestVisibilityTest.res.mjs +1 -1
- package/tests/plugin/PluginStructureAccessTest.res.mjs +1 -1
- package/tests/plugin/PluginStructureTest.res.mjs +19 -19
package/CHANGELOG.md
CHANGED
|
@@ -3,6 +3,13 @@
|
|
|
3
3
|
All notable changes to this project will be documented in this file.
|
|
4
4
|
See [Conventional Commits](https://conventionalcommits.org) for commit guidelines.
|
|
5
5
|
|
|
6
|
+
# 3.0.0-alpha.279 (2026-09-27)
|
|
7
|
+
|
|
8
|
+
### Features
|
|
9
|
+
|
|
10
|
+
* **core,spec:** an identity the plugin declares is information, not a dangling reference ([30d7917](https://github.com/ReventlessDev/reventless-core/commit/30d7917669ff062439f9c65e5274ab63a2e20de0))
|
|
11
|
+
|
|
12
|
+
|
|
6
13
|
# 3.0.0-alpha.278 (2026-09-25)
|
|
7
14
|
|
|
8
15
|
### Bug Fixes
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@reventlessdev/reventless-core",
|
|
3
|
-
"version": "3.0.0-alpha.
|
|
3
|
+
"version": "3.0.0-alpha.279",
|
|
4
4
|
"description": "Core package for Reventless framework",
|
|
5
5
|
"license": "Apache-2.0",
|
|
6
6
|
"jest": {
|
|
@@ -29,16 +29,16 @@
|
|
|
29
29
|
"sury": "11.0.0",
|
|
30
30
|
"uuid": "^13.0.0",
|
|
31
31
|
"@reventlessdev/rescript-effect": "0.1.0-alpha.34",
|
|
32
|
-
"@reventlessdev/rescript-fast-csv": "2.0.0-alpha.15",
|
|
33
|
-
"@reventlessdev/rescript-jest": "1.0.0-alpha.11",
|
|
34
32
|
"@reventlessdev/rescript-hash-object": "1.2.0-alpha.15",
|
|
35
|
-
"@reventlessdev/rescript-
|
|
36
|
-
"@reventlessdev/rescript-ssh2": "2.0.0-alpha.15",
|
|
33
|
+
"@reventlessdev/rescript-fast-csv": "2.0.0-alpha.16",
|
|
37
34
|
"@reventlessdev/rescript-pulumi-pulumi": "2.3.0-alpha.22",
|
|
35
|
+
"@reventlessdev/rescript-jest": "1.0.0-alpha.11",
|
|
36
|
+
"@reventlessdev/rescript-node": "2.0.0-alpha.16",
|
|
38
37
|
"@reventlessdev/rescript-uuid": "2.0.0-alpha.1",
|
|
39
|
-
"@reventlessdev/
|
|
40
|
-
"@reventlessdev/reventless-infra": "3.0.0-alpha.
|
|
41
|
-
"@reventlessdev/reventless-interop": "3.0.0-alpha.38"
|
|
38
|
+
"@reventlessdev/rescript-ssh2": "2.0.0-alpha.16",
|
|
39
|
+
"@reventlessdev/reventless-infra": "3.0.0-alpha.178",
|
|
40
|
+
"@reventlessdev/reventless-interop": "3.0.0-alpha.38",
|
|
41
|
+
"@reventlessdev/reventless-spec": "3.0.0-alpha.150"
|
|
42
42
|
},
|
|
43
43
|
"devDependencies": {
|
|
44
44
|
"rescript": "12.3.1",
|
|
@@ -55,6 +55,7 @@ module type T = {
|
|
|
55
55
|
~extensionPoints: array<module(ReventlessInfra.ExtensionPointMapping.Mapping)>=?,
|
|
56
56
|
~componentChapters: dict<string>=?,
|
|
57
57
|
~lifecycleModel: array<Reventless.Plugin.derivedEdge>=?,
|
|
58
|
+
~identities: array<string>=?,
|
|
58
59
|
) => Reventless.Plugin.pluginStructure
|
|
59
60
|
}
|
|
60
61
|
|
|
@@ -1109,6 +1109,7 @@ module Make = (
|
|
|
1109
1109
|
~extensionPoints: array<module(ReventlessInfra.ExtensionPointMapping.Mapping)>=[],
|
|
1110
1110
|
~componentChapters: dict<string>=Dict.make(),
|
|
1111
1111
|
~lifecycleModel: array<Reventless.Plugin.derivedEdge>=[],
|
|
1112
|
+
~identities: array<string>=[],
|
|
1112
1113
|
): Reventless.Plugin.pluginStructure =>
|
|
1113
1114
|
Plugin_Structure.make(
|
|
1114
1115
|
~name,
|
|
@@ -1123,6 +1124,7 @@ module Make = (
|
|
|
1123
1124
|
~extensionPoints,
|
|
1124
1125
|
~componentChapters,
|
|
1125
1126
|
~lifecycleModel,
|
|
1127
|
+
~identities,
|
|
1126
1128
|
)
|
|
1127
1129
|
|
|
1128
1130
|
let make = (
|
|
@@ -95,7 +95,7 @@ function Make(Spec) {
|
|
|
95
95
|
pages: pages
|
|
96
96
|
};
|
|
97
97
|
};
|
|
98
|
-
let makePluginDefinition = (name, aggregatesOpt, readModelsOpt, stateViewSlicesOpt, stateChangeSlicesOpt, automationSlicesOpt, outboundTranslationSlicesOpt, inboundTranslationSlicesOpt, extensionsOpt, extensionPointsOpt, componentChaptersOpt, lifecycleModelOpt) => {
|
|
98
|
+
let makePluginDefinition = (name, aggregatesOpt, readModelsOpt, stateViewSlicesOpt, stateChangeSlicesOpt, automationSlicesOpt, outboundTranslationSlicesOpt, inboundTranslationSlicesOpt, extensionsOpt, extensionPointsOpt, componentChaptersOpt, lifecycleModelOpt, identitiesOpt) => {
|
|
99
99
|
let aggregates = aggregatesOpt !== undefined ? aggregatesOpt : [];
|
|
100
100
|
let readModels = readModelsOpt !== undefined ? readModelsOpt : [];
|
|
101
101
|
let stateViewSlices = stateViewSlicesOpt !== undefined ? stateViewSlicesOpt : [];
|
|
@@ -107,7 +107,8 @@ function Make(Spec) {
|
|
|
107
107
|
let extensionPoints = extensionPointsOpt !== undefined ? extensionPointsOpt : [];
|
|
108
108
|
let componentChapters = componentChaptersOpt !== undefined ? componentChaptersOpt : ({});
|
|
109
109
|
let lifecycleModel = lifecycleModelOpt !== undefined ? lifecycleModelOpt : [];
|
|
110
|
-
|
|
110
|
+
let identities = identitiesOpt !== undefined ? identitiesOpt : [];
|
|
111
|
+
return Plugin_Structure$ReventlessCore.make(name, aggregates, readModels, stateViewSlices, stateChangeSlices, automationSlices, outboundTranslationSlices, inboundTranslationSlices, extensions, extensionPoints, componentChapters, lifecycleModel, identities);
|
|
111
112
|
};
|
|
112
113
|
let make = (name, heartbeatInterval, extensionPointsOpt, extensionsOpt, aggregatesOpt, readModelsOpt, tasksOpt, stateChangeSlicesOpt, stateViewSlicesOpt, automationSlicesOpt, outboundTranslationSlicesOpt, inboundTranslationSlicesOpt, systemCallableComponentsOpt, componentRuntimeOpt, uiFragments, pluginStructure, opts) => {
|
|
113
114
|
let extensionPoints = extensionPointsOpt !== undefined ? extensionPointsOpt : [];
|
|
@@ -591,12 +591,15 @@ let labelFieldsFromStateSchema = (
|
|
|
591
591
|
The plugin's views by the identity each is keyed by, which is what lets a typed
|
|
592
592
|
id find the view that lists it without an `@ref`. `report` says where the type
|
|
593
593
|
cannot decide: several views keyed by the identity, none, or an `@ref` naming a
|
|
594
|
-
view keyed by another.
|
|
594
|
+
view keyed by another. `inform` takes the one case that is not a fault: an
|
|
595
|
+
identity in `ownIdentities`, declared by this plugin, that no view lists yet.
|
|
595
596
|
*/
|
|
596
597
|
type identityViews = {
|
|
597
598
|
viewsByKey: dict<array<string>>,
|
|
598
599
|
viewNames: array<string>,
|
|
600
|
+
ownIdentities: array<string>,
|
|
599
601
|
report: string => unit,
|
|
602
|
+
inform: string => unit,
|
|
600
603
|
}
|
|
601
604
|
|
|
602
605
|
// The reference a typed id implies, and the check on one it declares.
|
|
@@ -615,7 +618,11 @@ let identityReference = (
|
|
|
615
618
|
switch keyed {
|
|
616
619
|
| [view] => [(fieldName, {Reventless.Semantic.entity: view, plugin: None, identity: key})]
|
|
617
620
|
| [] =>
|
|
618
|
-
|
|
621
|
+
let say =
|
|
622
|
+
identityViews.ownIdentities->Array.includes(key)
|
|
623
|
+
? identityViews.inform
|
|
624
|
+
: identityViews.report
|
|
625
|
+
say(
|
|
619
626
|
`${fieldName} is a ${key}, and no view in this plugin is keyed by it, so it references nothing. List the identity in a view, or reference another plugin's with @ref("Plugin.View").`,
|
|
620
627
|
)
|
|
621
628
|
[]
|
|
@@ -1110,6 +1117,9 @@ let make = (
|
|
|
1110
1117
|
// What the plugin's own scenarios say about each command's lifecycle edge,
|
|
1111
1118
|
// harvested by `check:lifecycle` and committed as `src/LifecycleModel.res`.
|
|
1112
1119
|
~lifecycleModel: array<Reventless.Plugin.derivedEdge>=[],
|
|
1120
|
+
// The keys of the identities the plugin declares in its own `src/`, passed by
|
|
1121
|
+
// the plugin generator. One no view lists is reported as information.
|
|
1122
|
+
~identities: array<string>=[],
|
|
1113
1123
|
): Reventless.Plugin.pluginStructure => {
|
|
1114
1124
|
let chapterOf = (compName: string): option<string> => componentChapters->Dict.get(compName)
|
|
1115
1125
|
// The harvest compares its own reading of the corpus with the DECLARATION, so
|
|
@@ -1648,14 +1658,17 @@ let make = (
|
|
|
1648
1658
|
// Warned rather than refused, like the key-field gap: the field still decodes,
|
|
1649
1659
|
// it just links nowhere. Once per message, since a field recurs across variants.
|
|
1650
1660
|
let reported: Set.t<string> = Set.make()
|
|
1661
|
+
let once = (logFn: Logger.logFn, message) =>
|
|
1662
|
+
if !(reported->Set.has(message)) {
|
|
1663
|
+
reported->Set.add(message)
|
|
1664
|
+
logFn(~comp="Plugin_Structure", `${name}: ${message}`)
|
|
1665
|
+
}
|
|
1651
1666
|
let identityViews = {
|
|
1652
1667
|
viewsByKey,
|
|
1653
1668
|
viewNames: viewKeys->Array.map(((view, _)) => view),
|
|
1654
|
-
|
|
1655
|
-
|
|
1656
|
-
|
|
1657
|
-
log.warn(~comp="Plugin_Structure", `${name}: ${message}`)
|
|
1658
|
-
},
|
|
1669
|
+
ownIdentities: identities,
|
|
1670
|
+
report: message => once(log.warn, message),
|
|
1671
|
+
inform: message => once(log.info, message),
|
|
1659
1672
|
}
|
|
1660
1673
|
|
|
1661
1674
|
let stateChangeDefs =
|
|
@@ -465,10 +465,10 @@ function identityReference(identityViews, fieldName, fieldSchema, declared) {
|
|
|
465
465
|
if (len !== 0) {
|
|
466
466
|
identityViews.report(fieldName + ` is a ` + key + `, and ` + keyed.join(" and ") + ` are all keyed by it. Say which it references with @ref.`);
|
|
467
467
|
return [];
|
|
468
|
-
} else {
|
|
469
|
-
identityViews.report(fieldName + ` is a ` + key + `, and no view in this plugin is keyed by it, so it references nothing. List the identity in a view, or reference another plugin's with @ref("Plugin.View").`);
|
|
470
|
-
return [];
|
|
471
468
|
}
|
|
469
|
+
let say = identityViews.ownIdentities.includes(key) ? identityViews.inform : identityViews.report;
|
|
470
|
+
say(fieldName + ` is a ` + key + `, and no view in this plugin is keyed by it, so it references nothing. List the identity in a view, or reference another plugin's with @ref("Plugin.View").`);
|
|
471
|
+
return [];
|
|
472
472
|
}
|
|
473
473
|
let view = keyed[0];
|
|
474
474
|
return [[
|
|
@@ -774,7 +774,7 @@ function queryableDefFromSpec(plugin, name, stateSchema, authorization, visibili
|
|
|
774
774
|
};
|
|
775
775
|
}
|
|
776
776
|
|
|
777
|
-
function make(name, aggregatesOpt, readModelsOpt, stateViewSlicesOpt, stateChangeSlicesOpt, automationSlicesOpt, outboundTranslationSlicesOpt, inboundTranslationSlicesOpt, extensionsOpt, extensionPointsOpt, componentChaptersOpt, lifecycleModelOpt) {
|
|
777
|
+
function make(name, aggregatesOpt, readModelsOpt, stateViewSlicesOpt, stateChangeSlicesOpt, automationSlicesOpt, outboundTranslationSlicesOpt, inboundTranslationSlicesOpt, extensionsOpt, extensionPointsOpt, componentChaptersOpt, lifecycleModelOpt, identitiesOpt) {
|
|
778
778
|
let aggregates = aggregatesOpt !== undefined ? aggregatesOpt : [];
|
|
779
779
|
let readModels = readModelsOpt !== undefined ? readModelsOpt : [];
|
|
780
780
|
let stateViewSlices = stateViewSlicesOpt !== undefined ? stateViewSlicesOpt : [];
|
|
@@ -786,6 +786,7 @@ function make(name, aggregatesOpt, readModelsOpt, stateViewSlicesOpt, stateChang
|
|
|
786
786
|
let extensionPoints = extensionPointsOpt !== undefined ? extensionPointsOpt : [];
|
|
787
787
|
let componentChapters = componentChaptersOpt !== undefined ? componentChaptersOpt : ({});
|
|
788
788
|
let lifecycleModel = lifecycleModelOpt !== undefined ? lifecycleModelOpt : [];
|
|
789
|
+
let identities = identitiesOpt !== undefined ? identitiesOpt : [];
|
|
789
790
|
let model = declaredTransitionsOnly ? [] : lifecycleModel;
|
|
790
791
|
let derivedEdgeFor = (component, command) => model.find(e => {
|
|
791
792
|
if (e.component === component) {
|
|
@@ -1173,17 +1174,21 @@ function make(name, aggregatesOpt, readModelsOpt, stateViewSlicesOpt, stateChang
|
|
|
1173
1174
|
});
|
|
1174
1175
|
});
|
|
1175
1176
|
let reported = new Set();
|
|
1176
|
-
let
|
|
1177
|
-
let identityViews_report = message => {
|
|
1177
|
+
let once = (logFn, message) => {
|
|
1178
1178
|
if (!reported.has(message)) {
|
|
1179
1179
|
reported.add(message);
|
|
1180
|
-
return
|
|
1180
|
+
return logFn("Plugin_Structure", undefined, name + `: ` + message);
|
|
1181
1181
|
}
|
|
1182
1182
|
};
|
|
1183
|
+
let identityViews_viewNames = viewKeys.map(param => param[0]);
|
|
1184
|
+
let identityViews_report = message => once(log.warn, message);
|
|
1185
|
+
let identityViews_inform = message => once(log.info, message);
|
|
1183
1186
|
let identityViews = {
|
|
1184
1187
|
viewsByKey: viewsByKey,
|
|
1185
1188
|
viewNames: identityViews_viewNames,
|
|
1186
|
-
|
|
1189
|
+
ownIdentities: identities,
|
|
1190
|
+
report: identityViews_report,
|
|
1191
|
+
inform: identityViews_inform
|
|
1187
1192
|
};
|
|
1188
1193
|
let stateChangeDefs = stateChangeSlices.map((SCS, i) => {
|
|
1189
1194
|
let match = scsProduced[i];
|
|
@@ -11,12 +11,14 @@ module CustomerId = Reventless.Id.Make({
|
|
|
11
11
|
let key = "customerId"
|
|
12
12
|
})
|
|
13
13
|
|
|
14
|
-
let refsOf = (~viewsByKey, ~minted=?, schema: S.t<'a>) => {
|
|
14
|
+
let refsOf = (~viewsByKey, ~ownIdentities=[], ~minted=?, schema: S.t<'a>) => {
|
|
15
15
|
let reports = []
|
|
16
16
|
let identityViews: Plugin_Structure.identityViews = {
|
|
17
17
|
viewsByKey: Dict.fromArray(viewsByKey),
|
|
18
18
|
viewNames: viewsByKey->Array.flatMap(((_, views)) => views),
|
|
19
|
+
ownIdentities,
|
|
19
20
|
report: message => reports->Array.push(message),
|
|
21
|
+
inform: message => reports->Array.push(`info: ${message}`),
|
|
20
22
|
}
|
|
21
23
|
let properties = switch schema->S.castToUnknown {
|
|
22
24
|
| Object({properties}) => properties
|
|
@@ -63,6 +65,27 @@ describe("a reference derived from the type", () => {
|
|
|
63
65
|
expect(reports->Array.some(r => r->String.includes("no view in this plugin")))->toBe(true)
|
|
64
66
|
})
|
|
65
67
|
|
|
68
|
+
// A site other parts name but no screen lists: declared on purpose, not a fault.
|
|
69
|
+
testSync("an identity the plugin declares, with no view, is information", () => {
|
|
70
|
+
let (_, reports) = refsOf(
|
|
71
|
+
~viewsByKey=[("productId", ["AvailableProducts"])],
|
|
72
|
+
~ownIdentities=["customerId"],
|
|
73
|
+
order,
|
|
74
|
+
)
|
|
75
|
+
expect(reports)->toEqual([
|
|
76
|
+
`info: buyer is a customerId, and no view in this plugin is keyed by it, so it references nothing. List the identity in a view, or reference another plugin's with @ref("Plugin.View").`,
|
|
77
|
+
])
|
|
78
|
+
})
|
|
79
|
+
|
|
80
|
+
testSync("one it does not declare still warns", () => {
|
|
81
|
+
let (_, reports) = refsOf(
|
|
82
|
+
~viewsByKey=[("productId", ["AvailableProducts"])],
|
|
83
|
+
~ownIdentities=["orderId"],
|
|
84
|
+
order,
|
|
85
|
+
)
|
|
86
|
+
expect(reports->Array.some(r => r->String.startsWith("buyer is a customerId")))->toBe(true)
|
|
87
|
+
})
|
|
88
|
+
|
|
66
89
|
// A create form mints this id; a list of the rows that already exist is the
|
|
67
90
|
// wrong control for it.
|
|
68
91
|
testSync("the id a creating command mints references nothing", () => {
|
|
@@ -13,17 +13,23 @@ let CustomerId = Id$Reventless.Make({
|
|
|
13
13
|
key: "customerId"
|
|
14
14
|
});
|
|
15
15
|
|
|
16
|
-
function refsOf(viewsByKey, minted, schema) {
|
|
16
|
+
function refsOf(viewsByKey, ownIdentitiesOpt, minted, schema) {
|
|
17
|
+
let ownIdentities = ownIdentitiesOpt !== undefined ? ownIdentitiesOpt : [];
|
|
17
18
|
let reports = [];
|
|
18
19
|
let identityViews_viewsByKey = Object.fromEntries(viewsByKey);
|
|
19
20
|
let identityViews_viewNames = viewsByKey.flatMap(param => param[1]);
|
|
20
21
|
let identityViews_report = message => {
|
|
21
22
|
reports.push(message);
|
|
22
23
|
};
|
|
24
|
+
let identityViews_inform = message => {
|
|
25
|
+
reports.push(`info: ` + message);
|
|
26
|
+
};
|
|
23
27
|
let identityViews = {
|
|
24
28
|
viewsByKey: identityViews_viewsByKey,
|
|
25
29
|
viewNames: identityViews_viewNames,
|
|
26
|
-
|
|
30
|
+
ownIdentities: ownIdentities,
|
|
31
|
+
report: identityViews_report,
|
|
32
|
+
inform: identityViews_inform
|
|
27
33
|
};
|
|
28
34
|
let properties;
|
|
29
35
|
properties = schema.type === "object" ? schema.properties : ({});
|
|
@@ -54,7 +60,7 @@ globalThis.describe("a reference derived from the type", () => {
|
|
|
54
60
|
"productId",
|
|
55
61
|
["AvailableProducts"]
|
|
56
62
|
]
|
|
57
|
-
], undefined, order);
|
|
63
|
+
], undefined, undefined, order);
|
|
58
64
|
globalThis.expect(match[0]).toEqual([
|
|
59
65
|
[
|
|
60
66
|
"buyer",
|
|
@@ -80,7 +86,7 @@ globalThis.describe("a reference derived from the type", () => {
|
|
|
80
86
|
"ProductDemand"
|
|
81
87
|
]
|
|
82
88
|
]
|
|
83
|
-
], undefined, order);
|
|
89
|
+
], undefined, undefined, order);
|
|
84
90
|
globalThis.expect(match[0]).toEqual([[
|
|
85
91
|
"buyer",
|
|
86
92
|
"Customers"
|
|
@@ -91,13 +97,27 @@ globalThis.describe("a reference derived from the type", () => {
|
|
|
91
97
|
let match = refsOf([[
|
|
92
98
|
"productId",
|
|
93
99
|
["AvailableProducts"]
|
|
94
|
-
]], undefined, order);
|
|
100
|
+
]], undefined, undefined, order);
|
|
95
101
|
globalThis.expect(match[0]).toEqual([[
|
|
96
102
|
"productIds",
|
|
97
103
|
"AvailableProducts"
|
|
98
104
|
]]);
|
|
99
105
|
globalThis.expect(match[1].some(r => r.includes("no view in this plugin"))).toBe(true);
|
|
100
106
|
});
|
|
107
|
+
globalThis.test("an identity the plugin declares, with no view, is information", () => {
|
|
108
|
+
let match = refsOf([[
|
|
109
|
+
"productId",
|
|
110
|
+
["AvailableProducts"]
|
|
111
|
+
]], ["customerId"], undefined, order);
|
|
112
|
+
globalThis.expect(match[1]).toEqual([`info: buyer is a customerId, and no view in this plugin is keyed by it, so it references nothing. List the identity in a view, or reference another plugin's with @ref("Plugin.View").`]);
|
|
113
|
+
});
|
|
114
|
+
globalThis.test("one it does not declare still warns", () => {
|
|
115
|
+
let match = refsOf([[
|
|
116
|
+
"productId",
|
|
117
|
+
["AvailableProducts"]
|
|
118
|
+
]], ["orderId"], undefined, order);
|
|
119
|
+
globalThis.expect(match[1].some(r => r.startsWith("buyer is a customerId"))).toBe(true);
|
|
120
|
+
});
|
|
101
121
|
globalThis.test("the id a creating command mints references nothing", () => {
|
|
102
122
|
let match = refsOf([
|
|
103
123
|
[
|
|
@@ -108,7 +128,7 @@ globalThis.describe("a reference derived from the type", () => {
|
|
|
108
128
|
"productId",
|
|
109
129
|
["AvailableProducts"]
|
|
110
130
|
]
|
|
111
|
-
], "buyer", order);
|
|
131
|
+
], undefined, "buyer", order);
|
|
112
132
|
globalThis.expect([
|
|
113
133
|
match[0],
|
|
114
134
|
match[1]
|
|
@@ -124,7 +144,7 @@ globalThis.describe("a reference derived from the type", () => {
|
|
|
124
144
|
let match = refsOf([[
|
|
125
145
|
"customerId",
|
|
126
146
|
["Customers"]
|
|
127
|
-
]], undefined, Sury.$schema(s => ({
|
|
147
|
+
]], undefined, undefined, Sury.$schema(s => ({
|
|
128
148
|
customerId: s.m(Sury.string)
|
|
129
149
|
})));
|
|
130
150
|
globalThis.expect([
|
|
@@ -151,7 +171,7 @@ globalThis.describe("a declared @ref on a typed id", () => {
|
|
|
151
171
|
"productId",
|
|
152
172
|
["Products"]
|
|
153
173
|
]
|
|
154
|
-
], undefined, referenced);
|
|
174
|
+
], undefined, undefined, referenced);
|
|
155
175
|
globalThis.expect(match[0]).toEqual([[
|
|
156
176
|
"buyer",
|
|
157
177
|
"Products"
|
|
@@ -168,7 +188,7 @@ globalThis.describe("a declared @ref on a typed id", () => {
|
|
|
168
188
|
"Customers",
|
|
169
189
|
"VipCustomers"
|
|
170
190
|
]
|
|
171
|
-
]], undefined, chosen);
|
|
191
|
+
]], undefined, undefined, chosen);
|
|
172
192
|
globalThis.expect([
|
|
173
193
|
match[0],
|
|
174
194
|
match[1]
|
|
@@ -187,7 +207,7 @@ globalThis.describe("a declared @ref on a typed id", () => {
|
|
|
187
207
|
let match = refsOf([[
|
|
188
208
|
"customerId",
|
|
189
209
|
["Customers"]
|
|
190
|
-
]], "buyer", chosen);
|
|
210
|
+
]], undefined, "buyer", chosen);
|
|
191
211
|
globalThis.expect(match[0]).toEqual([[
|
|
192
212
|
"buyer",
|
|
193
213
|
"Customers"
|
|
@@ -177,7 +177,7 @@ globalThis.describe("ReadModel visibility filter", () => {
|
|
|
177
177
|
});
|
|
178
178
|
|
|
179
179
|
globalThis.describe("Plugin_Structure.make — visibility tagging", () => {
|
|
180
|
-
let structure = Plugin_Structure$ReventlessCore.make("VisibilityPlugin", undefined, readModels, undefined, undefined, undefined, undefined, undefined, undefined, undefined, undefined, undefined);
|
|
180
|
+
let structure = Plugin_Structure$ReventlessCore.make("VisibilityPlugin", undefined, readModels, undefined, undefined, undefined, undefined, undefined, undefined, undefined, undefined, undefined, undefined);
|
|
181
181
|
globalThis.test("readModels carries both Public and Internal entries", () => {
|
|
182
182
|
globalThis.expect(structure.readModels.length).toBe(2);
|
|
183
183
|
});
|
|
@@ -108,7 +108,7 @@ let PsOrdersViewSlice = {
|
|
|
108
108
|
let structure = Plugin_Structure$ReventlessCore.make("AccessPlugin", undefined, undefined, [
|
|
109
109
|
PsGatedViewSlice,
|
|
110
110
|
PsOrdersViewSlice
|
|
111
|
-
], [PsGatedCommandsSlice], undefined, undefined, undefined, undefined, undefined, undefined, undefined);
|
|
111
|
+
], [PsGatedCommandsSlice], undefined, undefined, undefined, undefined, undefined, undefined, undefined, undefined);
|
|
112
112
|
|
|
113
113
|
function commandNamed(name) {
|
|
114
114
|
return Stdlib_Option.flatMap(structure.stateChangeSlices.flatMap(w => w.commands).find(c => c.name === name), c => c.requiredAccess);
|
|
@@ -551,7 +551,7 @@ let structure = Plugin_Structure$ReventlessCore.make("TestPlugin", undefined, un
|
|
|
551
551
|
], [
|
|
552
552
|
PsPlaceOrderSlice,
|
|
553
553
|
PsShipOrderSlice
|
|
554
|
-
], undefined, undefined, undefined, undefined, undefined, undefined, undefined);
|
|
554
|
+
], undefined, undefined, undefined, undefined, undefined, undefined, undefined, undefined);
|
|
555
555
|
|
|
556
556
|
globalThis.describe("lifecycle topology", () => {
|
|
557
557
|
let ordersStates = Object.fromEntries([[
|
|
@@ -615,7 +615,7 @@ globalThis.describe("lifecycle topology", () => {
|
|
|
615
615
|
});
|
|
616
616
|
|
|
617
617
|
globalThis.describe("commandTransition — the edge as a switch", () => {
|
|
618
|
-
let structure = Plugin_Structure$ReventlessCore.make("TransitionSwitchPlugin", undefined, undefined, [], [PsTransitionSwitchSlice], undefined, undefined, undefined, undefined, undefined, undefined, undefined);
|
|
618
|
+
let structure = Plugin_Structure$ReventlessCore.make("TransitionSwitchPlugin", undefined, undefined, [], [PsTransitionSwitchSlice], undefined, undefined, undefined, undefined, undefined, undefined, undefined, undefined);
|
|
619
619
|
let slice = structure.stateChangeSlices[0];
|
|
620
620
|
let byName = name => slice.commands.find(c => c.name === name);
|
|
621
621
|
globalThis.test("the switch fills allowedStates and targetState", () => {
|
|
@@ -659,7 +659,7 @@ globalThis.describe("the harvested model against the switch", () => {
|
|
|
659
659
|
targets: targets
|
|
660
660
|
};
|
|
661
661
|
};
|
|
662
|
-
let build = lifecycleModel => Plugin_Structure$ReventlessCore.make("HarvestPlugin", undefined, undefined, [], [PsTransitionSwitchSlice], undefined, undefined, undefined, undefined, undefined, undefined, lifecycleModel);
|
|
662
|
+
let build = lifecycleModel => Plugin_Structure$ReventlessCore.make("HarvestPlugin", undefined, undefined, [], [PsTransitionSwitchSlice], undefined, undefined, undefined, undefined, undefined, undefined, lifecycleModel, undefined);
|
|
663
663
|
let edgeOf = (model, name) => {
|
|
664
664
|
let slice = build(model).stateChangeSlices[0];
|
|
665
665
|
return Stdlib_Option.map(slice.commands.find(c => c.name === name), c => [
|
|
@@ -726,7 +726,7 @@ globalThis.describe("the harvested model against the switch", () => {
|
|
|
726
726
|
command: "PlaceOrder",
|
|
727
727
|
allowedStates: ["Draft"],
|
|
728
728
|
targets: ["Placed"]
|
|
729
|
-
}]);
|
|
729
|
+
}], undefined);
|
|
730
730
|
let slice = structure.stateChangeSlices[0];
|
|
731
731
|
globalThis.expect(Stdlib_Option.map(slice.commands.find(c => c.name === "PlaceOrder"), c => [
|
|
732
732
|
c.allowedStates,
|
|
@@ -754,7 +754,7 @@ globalThis.describe("traitDeclarations — a graft leaves a trace", () => {
|
|
|
754
754
|
let structure = Plugin_Structure$ReventlessCore.make("TraitPlugin", undefined, undefined, [], [
|
|
755
755
|
PsTransitionSwitchSlice,
|
|
756
756
|
PsShipOrderSlice
|
|
757
|
-
], undefined, undefined, undefined, undefined, undefined, undefined, undefined);
|
|
757
|
+
], undefined, undefined, undefined, undefined, undefined, undefined, undefined, undefined);
|
|
758
758
|
globalThis.test("a declaring component's trait reaches the structure", () => {
|
|
759
759
|
globalThis.expect(Stdlib_Option.getOr(structure.traitDeclarations, []).map(d => [
|
|
760
760
|
d.trait,
|
|
@@ -783,7 +783,7 @@ globalThis.describe("traitDeclarations — a graft leaves a trace", () => {
|
|
|
783
783
|
globalThis.describe("declared-edge cross-check", () => {
|
|
784
784
|
let buildBad = () => {
|
|
785
785
|
try {
|
|
786
|
-
Plugin_Structure$ReventlessCore.make("TransitionPlugin", undefined, undefined, [PsShipmentsViewSlice], [PsDispatchShipmentSlice], undefined, undefined, undefined, undefined, undefined, undefined, undefined);
|
|
786
|
+
Plugin_Structure$ReventlessCore.make("TransitionPlugin", undefined, undefined, [PsShipmentsViewSlice], [PsDispatchShipmentSlice], undefined, undefined, undefined, undefined, undefined, undefined, undefined, undefined);
|
|
787
787
|
return;
|
|
788
788
|
} catch (raw_e) {
|
|
789
789
|
let e = Primitive_exceptions.internalToException(raw_e);
|
|
@@ -1230,7 +1230,7 @@ globalThis.describe("Plugin_Structure.make — Phase 2 graph fields", () => {
|
|
|
1230
1230
|
});
|
|
1231
1231
|
});
|
|
1232
1232
|
globalThis.describe("singleQueryField — the singular the schema actually serves", () => {
|
|
1233
|
-
let withIrregularPlural = Plugin_Structure$ReventlessCore.make("TestPlugin", undefined, undefined, [PsCategoriesViewSlice], [], undefined, undefined, undefined, undefined, undefined, undefined, undefined);
|
|
1233
|
+
let withIrregularPlural = Plugin_Structure$ReventlessCore.make("TestPlugin", undefined, undefined, [PsCategoriesViewSlice], [], undefined, undefined, undefined, undefined, undefined, undefined, undefined, undefined);
|
|
1234
1234
|
let categories = withIrregularPlural.stateViewSlices[0];
|
|
1235
1235
|
globalThis.test("an `-ies` plural publishes the `y` singular, not a truncation", () => {
|
|
1236
1236
|
globalThis.expect([
|
|
@@ -1251,7 +1251,7 @@ globalThis.describe("Plugin_Structure.make — Phase 2 graph fields", () => {
|
|
|
1251
1251
|
q.idField,
|
|
1252
1252
|
q.idFieldSource
|
|
1253
1253
|
];
|
|
1254
|
-
let withCategories = Plugin_Structure$ReventlessCore.make("TestPlugin", undefined, undefined, [PsCategoriesViewSlice], [], undefined, undefined, undefined, undefined, undefined, undefined, undefined);
|
|
1254
|
+
let withCategories = Plugin_Structure$ReventlessCore.make("TestPlugin", undefined, undefined, [PsCategoriesViewSlice], [], undefined, undefined, undefined, undefined, undefined, undefined, undefined, undefined);
|
|
1255
1255
|
globalThis.test("a name-matching `*Id` field is a guess the consumer can also make", () => {
|
|
1256
1256
|
globalThis.expect(keyOf(structure.stateViewSlices[0])).toEqual([
|
|
1257
1257
|
"orderId",
|
|
@@ -1641,7 +1641,7 @@ globalThis.describe("Plugin_Structure.make — Phase 2 graph fields", () => {
|
|
|
1641
1641
|
"Orders",
|
|
1642
1642
|
"Order"
|
|
1643
1643
|
]
|
|
1644
|
-
]), undefined);
|
|
1644
|
+
]), undefined, undefined);
|
|
1645
1645
|
globalThis.test("a chaptered state-change slice carries Some(chapter)", () => {
|
|
1646
1646
|
let placeOrder = chaptered.stateChangeSlices[0];
|
|
1647
1647
|
globalThis.expect(placeOrder.chapter).toEqual("Order");
|
|
@@ -1660,7 +1660,7 @@ globalThis.describe("Plugin_Structure.make — Phase 2 graph fields", () => {
|
|
|
1660
1660
|
});
|
|
1661
1661
|
});
|
|
1662
1662
|
globalThis.describe("requiredStores", () => {
|
|
1663
|
-
let withStores = Plugin_Structure$ReventlessCore.make("TestPlugin", undefined, undefined, undefined, [PsAttachInvoiceSlice], undefined, undefined, undefined, undefined, undefined, undefined, undefined);
|
|
1663
|
+
let withStores = Plugin_Structure$ReventlessCore.make("TestPlugin", undefined, undefined, undefined, [PsAttachInvoiceSlice], undefined, undefined, undefined, undefined, undefined, undefined, undefined, undefined);
|
|
1664
1664
|
let stores = Stdlib_Option.getOr(withStores.requiredStores, []);
|
|
1665
1665
|
globalThis.test("an unqualified store resolves against the declaring plugin", () => {
|
|
1666
1666
|
globalThis.expect(stores.includes("TestPlugin.documents")).toBe(true);
|
|
@@ -1816,7 +1816,7 @@ globalThis.describe("Plugin_Structure.make — Phase 2 graph fields", () => {
|
|
|
1816
1816
|
});
|
|
1817
1817
|
});
|
|
1818
1818
|
globalThis.describe("uploadable types derive their store from the field name", () => {
|
|
1819
|
-
let withUploads = Plugin_Structure$ReventlessCore.make("TestPlugin", undefined, undefined, undefined, [PsUploadImagesSlice], undefined, undefined, undefined, undefined, undefined, undefined, undefined);
|
|
1819
|
+
let withUploads = Plugin_Structure$ReventlessCore.make("TestPlugin", undefined, undefined, undefined, [PsUploadImagesSlice], undefined, undefined, undefined, undefined, undefined, undefined, undefined, undefined);
|
|
1820
1820
|
let stores = Stdlib_Option.getOr(withUploads.requiredStores, []);
|
|
1821
1821
|
globalThis.test("the derived store is the field name, pluralised", () => {
|
|
1822
1822
|
globalThis.expect(stores.includes("TestPlugin.productImages")).toBe(true);
|
|
@@ -1877,7 +1877,7 @@ globalThis.describe("Plugin_Structure.make — Phase 2 graph fields", () => {
|
|
|
1877
1877
|
globalThis.describe("near-duplicate stores are refused", () => {
|
|
1878
1878
|
let failureText = () => {
|
|
1879
1879
|
try {
|
|
1880
|
-
Plugin_Structure$ReventlessCore.make("TestPlugin", undefined, undefined, undefined, [PsTypoStoreSlice], undefined, undefined, undefined, undefined, undefined, undefined, undefined);
|
|
1880
|
+
Plugin_Structure$ReventlessCore.make("TestPlugin", undefined, undefined, undefined, [PsTypoStoreSlice], undefined, undefined, undefined, undefined, undefined, undefined, undefined, undefined);
|
|
1881
1881
|
return "";
|
|
1882
1882
|
} catch (raw_e) {
|
|
1883
1883
|
let e = Primitive_exceptions.internalToException(raw_e);
|
|
@@ -1906,7 +1906,7 @@ globalThis.describe("Plugin_Structure.make — Phase 2 graph fields", () => {
|
|
|
1906
1906
|
]);
|
|
1907
1907
|
});
|
|
1908
1908
|
globalThis.test("the four stores of the uploadable fixture do not collide", () => {
|
|
1909
|
-
globalThis.expect(Capability_Inference$ReventlessCore.collisions(Stdlib_Option.getOr(Plugin_Structure$ReventlessCore.make("TestPlugin", undefined, undefined, undefined, [PsUploadImagesSlice], undefined, undefined, undefined, undefined, undefined, undefined, undefined).requiredStoreDeclarations, []))).toEqual([]);
|
|
1909
|
+
globalThis.expect(Capability_Inference$ReventlessCore.collisions(Stdlib_Option.getOr(Plugin_Structure$ReventlessCore.make("TestPlugin", undefined, undefined, undefined, [PsUploadImagesSlice], undefined, undefined, undefined, undefined, undefined, undefined, undefined, undefined).requiredStoreDeclarations, []))).toEqual([]);
|
|
1910
1910
|
});
|
|
1911
1911
|
globalThis.test("one edit, transpositions included; two edits not", () => {
|
|
1912
1912
|
globalThis.expect([
|
|
@@ -1943,7 +1943,7 @@ globalThis.describe("Plugin_Structure.make — Phase 2 graph fields", () => {
|
|
|
1943
1943
|
});
|
|
1944
1944
|
});
|
|
1945
1945
|
globalThis.describe("optional carriers keep their declarations", () => {
|
|
1946
|
-
let withOptional = Plugin_Structure$ReventlessCore.make("TestPlugin", undefined, undefined, undefined, [PsUploadAvatarSlice], undefined, undefined, undefined, undefined, undefined, undefined, undefined);
|
|
1946
|
+
let withOptional = Plugin_Structure$ReventlessCore.make("TestPlugin", undefined, undefined, undefined, [PsUploadAvatarSlice], undefined, undefined, undefined, undefined, undefined, undefined, undefined, undefined);
|
|
1947
1947
|
globalThis.test("an optional storage ref still requires its store", () => {
|
|
1948
1948
|
globalThis.expect(withOptional.requiredStores).toEqual(["TestPlugin.avatars"]);
|
|
1949
1949
|
});
|
|
@@ -1994,7 +1994,7 @@ globalThis.describe("Plugin_Structure.make — Phase 2 graph fields", () => {
|
|
|
1994
1994
|
globalThis.expect(eventWarnings).toEqual(expected);
|
|
1995
1995
|
});
|
|
1996
1996
|
globalThis.test("a heuristic-only match reaches no manifest entry", () => {
|
|
1997
|
-
let withHeuristicField = Plugin_Structure$ReventlessCore.make("TestPlugin", undefined, undefined, undefined, [PsChangePhotoSlice], undefined, undefined, undefined, undefined, undefined, undefined, undefined);
|
|
1997
|
+
let withHeuristicField = Plugin_Structure$ReventlessCore.make("TestPlugin", undefined, undefined, undefined, [PsChangePhotoSlice], undefined, undefined, undefined, undefined, undefined, undefined, undefined, undefined);
|
|
1998
1998
|
globalThis.expect(withHeuristicField.requiredStores).toEqual(["TestPlugin.productPhotos"]);
|
|
1999
1999
|
let manifest = CapabilityManifest$Reventless.fromStructure(withHeuristicField);
|
|
2000
2000
|
globalThis.expect(manifest.capabilities.every(entry => entry.declaredBy.every(site => Primitive_object.notequal(site.field, "photoUrl")))).toBe(true);
|
|
@@ -2021,7 +2021,7 @@ globalThis.describe("Plugin_Structure.make — Phase 2 graph fields", () => {
|
|
|
2021
2021
|
});
|
|
2022
2022
|
});
|
|
2023
2023
|
globalThis.describe("plural references reach the manifest", () => {
|
|
2024
|
-
let withPluralRefs = Plugin_Structure$ReventlessCore.make("TestPlugin", undefined, undefined, undefined, [PsReserveStockSlice], undefined, undefined, undefined, undefined, undefined, undefined, undefined);
|
|
2024
|
+
let withPluralRefs = Plugin_Structure$ReventlessCore.make("TestPlugin", undefined, undefined, undefined, [PsReserveStockSlice], undefined, undefined, undefined, undefined, undefined, undefined, undefined, undefined);
|
|
2025
2025
|
let slice = withPluralRefs.stateChangeSlices[0];
|
|
2026
2026
|
let referencesOf = refs => refs.map(param => [
|
|
2027
2027
|
param.fieldName,
|
|
@@ -2261,7 +2261,7 @@ globalThis.describe("duplicate DCB command names", () => {
|
|
|
2261
2261
|
Plugin_Structure$ReventlessCore.make("TestPlugin", undefined, undefined, undefined, [
|
|
2262
2262
|
PsShipOrderSlice,
|
|
2263
2263
|
PsShipOrderSlice
|
|
2264
|
-
], undefined, undefined, undefined, undefined, undefined, undefined, undefined);
|
|
2264
|
+
], undefined, undefined, undefined, undefined, undefined, undefined, undefined, undefined);
|
|
2265
2265
|
tmp = false;
|
|
2266
2266
|
} catch (exn) {
|
|
2267
2267
|
tmp = true;
|
|
@@ -2274,7 +2274,7 @@ globalThis.describe("duplicate DCB command names", () => {
|
|
|
2274
2274
|
val = Plugin_Structure$ReventlessCore.make("TestPlugin", undefined, undefined, undefined, [
|
|
2275
2275
|
PsShipOrderSlice,
|
|
2276
2276
|
PsShipOrderSlice
|
|
2277
|
-
], undefined, undefined, undefined, undefined, undefined, undefined, undefined);
|
|
2277
|
+
], undefined, undefined, undefined, undefined, undefined, undefined, undefined, undefined);
|
|
2278
2278
|
} catch (raw_e) {
|
|
2279
2279
|
let e = Primitive_exceptions.internalToException(raw_e);
|
|
2280
2280
|
if (e.RE_EXN_ID === "JsExn") {
|
|
@@ -2298,7 +2298,7 @@ globalThis.describe("duplicate DCB command names", () => {
|
|
|
2298
2298
|
Plugin_Structure$ReventlessCore.make("TestPlugin", undefined, undefined, undefined, [
|
|
2299
2299
|
PsPlaceOrderSlice,
|
|
2300
2300
|
PsShipOrderSlice
|
|
2301
|
-
], undefined, undefined, undefined, undefined, undefined, undefined, undefined);
|
|
2301
|
+
], undefined, undefined, undefined, undefined, undefined, undefined, undefined, undefined);
|
|
2302
2302
|
tmp = true;
|
|
2303
2303
|
} catch (exn) {
|
|
2304
2304
|
tmp = false;
|