@reventlessdev/reventless-core 3.0.0-alpha.239 → 3.0.0-alpha.241
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 +35 -0
- package/package.json +11 -11
- package/src/Message.res +11 -11
- package/src/Message.res.mjs +15 -14
- package/src/Projection.res +2 -2
- package/src/Projection.res.mjs +5 -4
- package/src/adapter/Monitoring/Monitoring.res +24 -2
- package/src/adapter/Monitoring/Monitoring.res.mjs +3 -3
- package/src/admin/Platform_Admin.res +1 -16
- package/src/admin/Platform_Admin.res.mjs +2 -30
- package/src/admin/Platform_AdminApi.res.mjs +3 -3
- package/src/admin/Platform_Admin_Structure.res +58 -113
- package/src/admin/Platform_Admin_Structure.res.mjs +24 -139
- package/src/admin/UiFragmentRegistry/StateChangeSlice/UiFragmentRegistry.res.mjs +12 -12
- package/src/admin/UiFragmentRegistry/StateViewSlice/UiFragments.res.mjs +14 -14
- package/src/components/Aggregate/Aggregate_Callback.res +2 -2
- package/src/components/Aggregate/Aggregate_Callback.res.mjs +4 -4
- package/src/components/Api/ApiAllowedStatesHelpers.res.mjs +3 -3
- package/src/components/Api/ApiNoApiHelpers.res.mjs +5 -5
- package/src/components/Api/ApiTargetStateHelpers.res.mjs +3 -3
- package/src/components/Api/GraphQL_FragmentGenerator.res +18 -12
- package/src/components/Api/GraphQL_FragmentGenerator.res.mjs +7 -13
- package/src/components/Api/GraphQL_SchemaInspector.res +1 -1
- package/src/components/Api/GraphQL_SchemaInspector.res.mjs +1 -1
- package/src/components/Api/MCP_SchemaGenerator.res +1 -1
- package/src/components/Api/MCP_SchemaGenerator.res.mjs +1 -1
- package/src/components/Api/SchemaType.res +6 -10
- package/src/components/Api/SchemaType.res.mjs +4 -4
- package/src/components/Api/StorageRefFields.res +1 -1
- package/src/components/Api/StorageRefFields.res.mjs +1 -1
- package/src/components/Api/SuryToJsonSchema.res +11 -0
- package/src/components/Api/SuryToJsonSchema.res.mjs +2 -1
- package/src/components/AutomationSlice/AutomationSlice_Callback.res +3 -4
- package/src/components/AutomationSlice/AutomationSlice_Callback.res.mjs +22 -23
- package/src/components/CommandTopic/CommandTopic_Callback.res +1 -2
- package/src/components/CommandTopic/CommandTopic_Callback.res.mjs +3 -4
- package/src/components/CommandTopic/CommandTopic_Helpers.res +1 -1
- package/src/components/CommandTopic/CommandTopic_Helpers.res.mjs +3 -3
- package/src/components/Counter/Counter.res.mjs +2 -2
- package/src/components/Counter/Counter_Callback.res.mjs +4 -4
- package/src/components/Counter/Counter_Operations.res.mjs +4 -4
- package/src/components/Dcb/Dcb_Builder.res +1 -1
- package/src/components/Dcb/Dcb_Builder.res.mjs +8 -6
- package/src/components/DcbEventLog/DcbEventLog_Builder.res.mjs +4 -3
- package/src/components/EventCollector/EventCollector_Builder.res +1 -1
- package/src/components/InboundTranslationSlice/InboundTranslationSlice_Callback.res +1 -2
- package/src/components/InboundTranslationSlice/InboundTranslationSlice_Callback.res.mjs +11 -12
- package/src/components/OutboundTranslationSlice/OutboundTranslationSlice_Callback.res +3 -4
- package/src/components/OutboundTranslationSlice/OutboundTranslationSlice_Callback.res.mjs +24 -25
- package/src/components/SideEffectHandler/SideEffectHandler_Callback.res +1 -1
- package/src/components/SideEffectHandler/SideEffectHandler_Callback.res.mjs +3 -3
- package/src/components/StateChangeSlice/StateChangeSlice_Callback.res +2 -2
- package/src/components/StateChangeSlice/StateChangeSlice_Callback.res.mjs +4 -4
- package/src/components/StateViewSlice/StateViewSlice_Builder.res +1 -1
- package/src/components/StateViewSlice/StateViewSlice_Builder.res.mjs +3 -3
- package/src/plugin/api/PluginBaseFragment.res +12 -29
- package/src/plugin/api/PluginBaseFragment.res.mjs +3 -22
- package/src/plugin/component/Capability_Inference.res +118 -1
- package/src/plugin/component/Capability_Inference.res.mjs +128 -1
- package/src/plugin/component/Plugin_Builder.res +2 -2
- package/src/plugin/component/Plugin_Builder.res.mjs +2 -1
- package/src/plugin/component/Plugin_Helpers.res +11 -11
- package/src/plugin/component/Plugin_Helpers.res.mjs +11 -10
- package/src/plugin/component/Plugin_Structure.res +349 -274
- package/src/plugin/component/Plugin_Structure.res.mjs +212 -175
- package/src/plugin/component/Plugin_SubscriptionSchema.res +1 -1
- package/src/plugin/component/Plugin_SubscriptionSchema.res.mjs +1 -1
- package/src/plugin/component/SchemaWalker.res +11 -11
- package/src/plugin/component/SchemaWalker.res.mjs +8 -9
- package/src/plugin/connect/PluginExtensionPoint_Plugin.res.mjs +15 -15
- package/src/plugin/lifecycle/PluginBehavior.res.mjs +55 -55
- package/src/plugin/lifecycle/PluginSpec.res +22 -7
- package/src/plugin/lifecycle/PluginSpec.res.mjs +91 -36
- package/src/plugin/lifecycle/PluginsReadModelSpec.res +36 -9
- package/src/plugin/lifecycle/PluginsReadModelSpec.res.mjs +33 -22
- package/src/util/Interstack.res +3 -3
- package/src/util/LogFormat.res +1 -2
- package/src/util/LogFormat.res.mjs +2 -2
- package/tests/IdentityTest.res +6 -7
- package/tests/IdentityTest.res.mjs +7 -9
- package/tests/adapter/MonitoringTest.res +30 -3
- package/tests/adapter/MonitoringTest.res.mjs +31 -12
- package/tests/adapter/RuntimeExtensionHookReachTest.res +0 -1
- package/tests/adapter/RuntimeExtensionHookReachTest.res.mjs +5 -7
- package/tests/admin/Platform_Admin_StructureTest.res +254 -0
- package/tests/admin/Platform_Admin_StructureTest.res.mjs +219 -0
- package/tests/aggregate/AggregateCacheTest.res +0 -1
- package/tests/aggregate/AggregateCacheTest.res.mjs +13 -15
- package/tests/aggregate/AggregateConflictTest.res +0 -1
- package/tests/aggregate/AggregateConflictTest.res.mjs +7 -9
- package/tests/aggregate/AggregateFixtures.res +0 -1
- package/tests/aggregate/AggregateFixtures.res.mjs +19 -21
- package/tests/aggregate/AggregateSnapshotTest.res +1 -2
- package/tests/aggregate/AggregateSnapshotTest.res.mjs +15 -16
- package/tests/api/ApiNoApiTest.res.mjs +17 -9
- package/tests/api/GraphQL_FragmentGeneratorTest.res +62 -1
- package/tests/api/GraphQL_FragmentGeneratorTest.res.mjs +102 -58
- package/tests/api/PsInternalFieldsReadModel.res +21 -0
- package/tests/api/PsInternalFieldsReadModel.res.mjs +74 -0
- package/tests/api/StorageRefFieldsTest.res.mjs +13 -13
- package/tests/api/SuryToJsonSchemaTest.res +43 -0
- package/tests/api/SuryToJsonSchemaTest.res.mjs +352 -849
- package/tests/commandgenerator/CommandGeneratorFixtures.res +0 -1
- package/tests/commandgenerator/CommandGeneratorFixtures.res.mjs +19 -21
- package/tests/commandgenerator/OwnerStampingTest.res +0 -1
- package/tests/commandgenerator/OwnerStampingTest.res.mjs +9 -11
- package/tests/commandtopic/CommandTopicCallbackFixtures.res +0 -1
- package/tests/commandtopic/CommandTopicCallbackFixtures.res.mjs +7 -9
- package/tests/counter/CounterFixtures.res +0 -1
- package/tests/counter/CounterFixtures.res.mjs +1 -4
- package/tests/dcb/DcbDecodeTest.res.mjs +24 -24
- package/tests/dcb/DcbEventLogOperationsTest.res +2 -2
- package/tests/dcb/DcbEventLogOperationsTest.res.mjs +3 -3
- package/tests/dcb/DcbEventLogSchemaTest.res.mjs +7 -7
- package/tests/dcb/DcbFixtures.res +0 -1
- package/tests/dcb/DcbFixtures.res.mjs +87 -89
- package/tests/dcb/DcbTagTest.res.mjs +6 -6
- package/tests/dcb/DcbValidationTest.res.mjs +52 -52
- package/tests/eventlog/EventLogFixtures.res +0 -1
- package/tests/eventlog/EventLogFixtures.res.mjs +7 -9
- package/tests/eventmapper/EventMapperFixtures.res +0 -1
- package/tests/eventmapper/EventMapperFixtures.res.mjs +24 -26
- package/tests/eventtopic/EventTopicFixtures.res +0 -1
- package/tests/eventtopic/EventTopicFixtures.res.mjs +7 -9
- package/tests/extensionpoint/ExtensionPointFixtures.res +0 -1
- package/tests/extensionpoint/ExtensionPointFixtures.res.mjs +10 -12
- package/tests/extensionpoint/ExtensionPointOperationsTest.res +1 -2
- package/tests/extensionpoint/ExtensionPointOperationsTest.res.mjs +9 -10
- package/tests/logger/LogFormatTest.res +3 -2
- package/tests/logger/LogFormatTest.res.mjs +7 -9
- package/tests/message/MessageTest.res +2 -2
- package/tests/message/MessageTest.res.mjs +8 -7
- package/tests/message/MetaEnvelopeTest.res +5 -5
- package/tests/message/MetaEnvelopeTest.res.mjs +12 -11
- package/tests/plugin/ManifestVisibilityTest.res.mjs +7 -7
- package/tests/plugin/PluginDefinitionScalars.res +5 -3
- package/tests/plugin/PluginDefinitionScalars.res.mjs +2 -2
- package/tests/plugin/PluginLifecycleCorpusTest.res +4 -3
- package/tests/plugin/PluginLifecycleCorpusTest.res.mjs +3 -6
- package/tests/plugin/PluginSpecExperiment.res +0 -1
- package/tests/plugin/PluginSpecExperiment.res.mjs +12 -14
- package/tests/plugin/PluginStructureTest.res +188 -1
- package/tests/plugin/PluginStructureTest.res.mjs +293 -102
- package/tests/plugin/Plugin_EventQuerySchemaTest.res.mjs +3 -3
- package/tests/plugin/SchemaWalkerTest.res +0 -1
- package/tests/plugin/SchemaWalkerTest.res.mjs +17 -19
- package/tests/plugin/StateChangeSlice/PsAttachInvoice.res.mjs +5 -5
- package/tests/plugin/StateChangeSlice/PsChangePhoto.res.mjs +8 -8
- package/tests/plugin/StateChangeSlice/PsDispatchShipment.res.mjs +5 -5
- package/tests/plugin/StateChangeSlice/PsGatedCommands.res.mjs +9 -9
- package/tests/plugin/StateChangeSlice/PsPlaceOrder.res.mjs +5 -5
- package/tests/plugin/StateChangeSlice/PsReserveStock.res.mjs +8 -8
- package/tests/plugin/StateChangeSlice/PsShipOrder.res.mjs +15 -15
- package/tests/plugin/StateChangeSlice/PsTypoStore.res +31 -0
- package/tests/plugin/StateChangeSlice/PsTypoStore.res.mjs +62 -0
- package/tests/plugin/StateChangeSlice/PsUploadAvatar.res.mjs +8 -8
- package/tests/plugin/StateChangeSlice/PsUploadImages.res +40 -0
- package/tests/plugin/StateChangeSlice/PsUploadImages.res.mjs +66 -0
- package/tests/plugin/StateViewSlice/PsAnnotatedView.res.mjs +13 -12
- package/tests/plugin/StateViewSlice/PsAvailableProductsView.res.mjs +8 -8
- package/tests/plugin/StateViewSlice/PsCategoriesView.res.mjs +6 -6
- package/tests/plugin/StateViewSlice/PsCustomersView.res.mjs +10 -10
- package/tests/plugin/StateViewSlice/PsGatedView.res.mjs +6 -6
- package/tests/plugin/StateViewSlice/PsOrdersView.res.mjs +9 -9
- package/tests/plugin/StateViewSlice/PsShipmentsView.res.mjs +11 -10
- package/tests/plugin/pluginDefinitionRequiredScalars.txt +15 -0
- package/tests/querydb/QueryDbFixtures.res +0 -1
- package/tests/querydb/QueryDbFixtures.res.mjs +5 -7
- package/tests/sideeffecthandler/SideEffectHandlerFixtures.res +0 -1
- package/tests/sideeffecthandler/SideEffectHandlerFixtures.res.mjs +4 -6
- package/tests/util/CommandPublisherTest.res +0 -1
- package/tests/util/CommandPublisherTest.res.mjs +4 -6
|
@@ -1,31 +1,29 @@
|
|
|
1
1
|
// Generated by ReScript, PLEASE EDIT WITH CARE
|
|
2
2
|
|
|
3
|
-
import * as
|
|
3
|
+
import * as Sury from "sury";
|
|
4
4
|
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
let recordSchema = S.schema(s => ({
|
|
8
|
-
a: s.m(S.meta(S.string, {
|
|
5
|
+
let recordSchema = Sury.$schema(s => ({
|
|
6
|
+
a: s.m(Sury.meta(Sury.string, {
|
|
9
7
|
description: "aaa"
|
|
10
8
|
})),
|
|
11
|
-
b: s.m(
|
|
9
|
+
b: s.m(Sury.string)
|
|
12
10
|
}));
|
|
13
11
|
|
|
14
|
-
let variantSchema =
|
|
15
|
-
|
|
12
|
+
let variantSchema = Sury.union([
|
|
13
|
+
Sury.$schema(s => ({
|
|
16
14
|
TAG: "Q",
|
|
17
|
-
_0: s.m(
|
|
15
|
+
_0: s.m(Sury.int)
|
|
18
16
|
})),
|
|
19
|
-
|
|
20
|
-
|
|
17
|
+
Sury.literal("X"),
|
|
18
|
+
Sury.literal("Y")
|
|
21
19
|
]);
|
|
22
20
|
|
|
23
|
-
console.log("Record:", JSON.stringify(
|
|
21
|
+
console.log("Record:", JSON.stringify(Sury.toJSONSchema(recordSchema), undefined, 2));
|
|
24
22
|
|
|
25
|
-
console.log("Variant:", JSON.stringify(
|
|
23
|
+
console.log("Variant:", JSON.stringify(Sury.toJSONSchema(variantSchema), undefined, 2));
|
|
26
24
|
|
|
27
25
|
export {
|
|
28
26
|
recordSchema,
|
|
29
27
|
variantSchema,
|
|
30
28
|
}
|
|
31
|
-
/*
|
|
29
|
+
/* recordSchema Not a pure module */
|
|
@@ -116,6 +116,34 @@ module PsUploadAvatarSlice: ReventlessInfra.StateChangeSlice.T = {
|
|
|
116
116
|
let make = (~dcbEventLog as _, ~publishJsons as _, ~tagKeysByEventType as _=?, ~crossPartitionTagKeys as _=?, ~runtime as _=?, ~opts as _=?): component => Obj.magic(0)
|
|
117
117
|
}
|
|
118
118
|
|
|
119
|
+
module PsUploadImagesSlice: ReventlessInfra.StateChangeSlice.T = {
|
|
120
|
+
module Spec = PsUploadImages
|
|
121
|
+
module Behavior = {
|
|
122
|
+
type state = PsUploadImages.state
|
|
123
|
+
let initialState = PsUploadImages.initialState
|
|
124
|
+
let evolve = PsUploadImages.evolve
|
|
125
|
+
let decide = PsUploadImages.decide
|
|
126
|
+
let moduleUrl = PsUploadImages.moduleUrl
|
|
127
|
+
}
|
|
128
|
+
let isAsync = false
|
|
129
|
+
type component = scsComponent
|
|
130
|
+
let make = (~dcbEventLog as _, ~publishJsons as _, ~tagKeysByEventType as _=?, ~crossPartitionTagKeys as _=?, ~runtime as _=?, ~opts as _=?): component => Obj.magic(0)
|
|
131
|
+
}
|
|
132
|
+
|
|
133
|
+
module PsTypoStoreSlice: ReventlessInfra.StateChangeSlice.T = {
|
|
134
|
+
module Spec = PsTypoStore
|
|
135
|
+
module Behavior = {
|
|
136
|
+
type state = PsTypoStore.state
|
|
137
|
+
let initialState = PsTypoStore.initialState
|
|
138
|
+
let evolve = PsTypoStore.evolve
|
|
139
|
+
let decide = PsTypoStore.decide
|
|
140
|
+
let moduleUrl = PsTypoStore.moduleUrl
|
|
141
|
+
}
|
|
142
|
+
let isAsync = false
|
|
143
|
+
type component = scsComponent
|
|
144
|
+
let make = (~dcbEventLog as _, ~publishJsons as _, ~tagKeysByEventType as _=?, ~crossPartitionTagKeys as _=?, ~runtime as _=?, ~opts as _=?): component => Obj.magic(0)
|
|
145
|
+
}
|
|
146
|
+
|
|
119
147
|
module PsChangePhotoSlice: ReventlessInfra.StateChangeSlice.T = {
|
|
120
148
|
module Spec = PsChangePhoto
|
|
121
149
|
module Behavior = {
|
|
@@ -277,7 +305,7 @@ describe("@transition cross-check", () => {
|
|
|
277
305
|
)->ignore
|
|
278
306
|
None
|
|
279
307
|
} catch {
|
|
280
|
-
|
|
|
308
|
+
| JsExn(e) => Some(JsExn.message(e)->Option.getOr(""))
|
|
281
309
|
| _ => Some("")
|
|
282
310
|
}
|
|
283
311
|
|
|
@@ -1373,6 +1401,165 @@ describe("Plugin_Structure.make — Phase 2 graph fields", () => {
|
|
|
1373
1401
|
})
|
|
1374
1402
|
})
|
|
1375
1403
|
|
|
1404
|
+
// A field typed uploadable declares its store by being named. The collection
|
|
1405
|
+
// walk is unchanged: it matches the `StoredIn` payload, never the semantic id,
|
|
1406
|
+
// so a new id carrying one is provisioned by machinery that knows nothing
|
|
1407
|
+
// about it.
|
|
1408
|
+
describe("uploadable types derive their store from the field name", () => {
|
|
1409
|
+
let withUploads = Plugin_Structure.make(
|
|
1410
|
+
~name="TestPlugin",
|
|
1411
|
+
~stateChangeSlices=[module(PsUploadImagesSlice)],
|
|
1412
|
+
)
|
|
1413
|
+
let stores = withUploads.requiredStores->Option.getOr([])
|
|
1414
|
+
|
|
1415
|
+
testSync("the derived store is the field name, pluralised", () =>
|
|
1416
|
+
expect(stores->Array.includes("TestPlugin.productImages"))->toBe(true)
|
|
1417
|
+
)
|
|
1418
|
+
|
|
1419
|
+
testSync("an optional field still declares its store", () =>
|
|
1420
|
+
expect(stores->Array.includes("TestPlugin.categoryImages"))->toBe(true)
|
|
1421
|
+
)
|
|
1422
|
+
|
|
1423
|
+
// The array marker lives on the element type. Reading the field schema
|
|
1424
|
+
// directly answers `None`, which is the same silence as never declaring —
|
|
1425
|
+
// so this asserts collection, not just that the fixture compiled.
|
|
1426
|
+
testSync("an array field declares through its element", () =>
|
|
1427
|
+
expect(stores->Array.includes("TestPlugin.datasheets"))->toBe(true)
|
|
1428
|
+
)
|
|
1429
|
+
|
|
1430
|
+
testSync("an explicit @storageRef overrides the derived name", () =>
|
|
1431
|
+
expect(stores->Array.includes("branding.logos"))->toBe(true)
|
|
1432
|
+
)
|
|
1433
|
+
|
|
1434
|
+
testSync("nothing else is collected", () => expect(stores->Array.length)->toBe(4))
|
|
1435
|
+
|
|
1436
|
+
// The event field derives the same store as the command field of the same
|
|
1437
|
+
// name, so the two collapse to one declaration site — the behaviour the
|
|
1438
|
+
// annotation form already had, reached without an annotation.
|
|
1439
|
+
testSync("each requirement keeps its declaring sites", () => {
|
|
1440
|
+
let expected: array<Reventless.Plugin.requiredStoreDeclaration> = [
|
|
1441
|
+
{
|
|
1442
|
+
store: "TestPlugin.categoryImages",
|
|
1443
|
+
component: "UploadImages",
|
|
1444
|
+
field: "categoryImage",
|
|
1445
|
+
annotation: Some("categoryImages"),
|
|
1446
|
+
},
|
|
1447
|
+
{
|
|
1448
|
+
store: "TestPlugin.datasheets",
|
|
1449
|
+
component: "UploadImages",
|
|
1450
|
+
field: "datasheets",
|
|
1451
|
+
annotation: Some("datasheets"),
|
|
1452
|
+
},
|
|
1453
|
+
{
|
|
1454
|
+
store: "TestPlugin.productImages",
|
|
1455
|
+
component: "UploadImages",
|
|
1456
|
+
field: "productImage",
|
|
1457
|
+
annotation: Some("productImages"),
|
|
1458
|
+
},
|
|
1459
|
+
{
|
|
1460
|
+
store: "branding.logos",
|
|
1461
|
+
component: "UploadImages",
|
|
1462
|
+
field: "logo",
|
|
1463
|
+
annotation: Some("branding.logos"),
|
|
1464
|
+
},
|
|
1465
|
+
]
|
|
1466
|
+
expect(withUploads.requiredStoreDeclarations)->toEqual(Some(expected))
|
|
1467
|
+
})
|
|
1468
|
+
|
|
1469
|
+
let commandJson =
|
|
1470
|
+
((withUploads.stateChangeSlices->Array.getUnsafe(0)).commands->Array.getUnsafe(0)).schema
|
|
1471
|
+
->JSON.parseOrThrow
|
|
1472
|
+
|
|
1473
|
+
let semanticOf = field =>
|
|
1474
|
+
commandJson
|
|
1475
|
+
->getPropertyOf(field)
|
|
1476
|
+
->Option.flatMap(s => getProperty(s, "x-reventless-semantic"))
|
|
1477
|
+
->Option.flatMap(JSON.Decode.string)
|
|
1478
|
+
|
|
1479
|
+
// The whole point of the family: one declaration states the content type
|
|
1480
|
+
// too, so the UI stops learning "this is an image" from the field's name.
|
|
1481
|
+
testSync("the wire carries the content half, not just the store", () =>
|
|
1482
|
+
expect(semanticOf("productImage"))->toBe(Some("uploadableImage"))
|
|
1483
|
+
)
|
|
1484
|
+
|
|
1485
|
+
// The override replaces the *store*, not the type's semantic: a field
|
|
1486
|
+
// pointing at another plugin's store is still an image.
|
|
1487
|
+
testSync("an overridden field keeps its uploadable semantic", () =>
|
|
1488
|
+
expect(semanticOf("logo"))->toBe(Some("uploadableImage"))
|
|
1489
|
+
)
|
|
1490
|
+
|
|
1491
|
+
testSync("the non-image arm carries its own id, on the element", () =>
|
|
1492
|
+
expect(
|
|
1493
|
+
commandJson
|
|
1494
|
+
->getPropertyOf("datasheets")
|
|
1495
|
+
->Option.flatMap(s => getProperty(s, "items"))
|
|
1496
|
+
->Option.flatMap(s => getProperty(s, "x-reventless-semantic"))
|
|
1497
|
+
->Option.flatMap(JSON.Decode.string),
|
|
1498
|
+
)->toBe(Some("uploadableFile"))
|
|
1499
|
+
)
|
|
1500
|
+
})
|
|
1501
|
+
|
|
1502
|
+
// Deriving the store from the field name turns a typo into a second store
|
|
1503
|
+
// rather than into a compile error, so the plugin has to refuse it.
|
|
1504
|
+
describe("near-duplicate stores are refused", () => {
|
|
1505
|
+
let failureText = () =>
|
|
1506
|
+
try {
|
|
1507
|
+
Plugin_Structure.make(
|
|
1508
|
+
~name="TestPlugin",
|
|
1509
|
+
~stateChangeSlices=[module(PsTypoStoreSlice)],
|
|
1510
|
+
)->ignore
|
|
1511
|
+
""
|
|
1512
|
+
} catch {
|
|
1513
|
+
| JsExn(e) => JsExn.message(e)->Option.getOr("(no message)")
|
|
1514
|
+
| _ => "(not a JS error)"
|
|
1515
|
+
}
|
|
1516
|
+
|
|
1517
|
+
testSync("two stores one transposition apart fail the build", () =>
|
|
1518
|
+
expect(failureText() != "")->toBe(true)
|
|
1519
|
+
)
|
|
1520
|
+
|
|
1521
|
+
testSync("the failure names both stores and both fields", () => {
|
|
1522
|
+
let text = failureText()
|
|
1523
|
+
expect([
|
|
1524
|
+
text->String.includes("TestPlugin.productImages"),
|
|
1525
|
+
text->String.includes("TestPlugin.productImgaes"),
|
|
1526
|
+
text->String.includes("TypoStore.productImage"),
|
|
1527
|
+
text->String.includes("@storageRef"),
|
|
1528
|
+
])->toEqual([true, true, true, true])
|
|
1529
|
+
})
|
|
1530
|
+
|
|
1531
|
+
// Every legitimate pair in the other fixtures has to stay legitimate — a
|
|
1532
|
+
// check that fails on real designs is worse than the typo it catches.
|
|
1533
|
+
testSync("the four stores of the uploadable fixture do not collide", () =>
|
|
1534
|
+
expect(
|
|
1535
|
+
Capability_Inference.collisions(
|
|
1536
|
+
Plugin_Structure.make(
|
|
1537
|
+
~name="TestPlugin",
|
|
1538
|
+
~stateChangeSlices=[module(PsUploadImagesSlice)],
|
|
1539
|
+
).requiredStoreDeclarations->Option.getOr([]),
|
|
1540
|
+
),
|
|
1541
|
+
)->toEqual([])
|
|
1542
|
+
)
|
|
1543
|
+
|
|
1544
|
+
testSync("one edit, transpositions included; two edits not", () =>
|
|
1545
|
+
expect(
|
|
1546
|
+
[
|
|
1547
|
+
("productImages", "productImgaes"),
|
|
1548
|
+
("productImages", "productImage"),
|
|
1549
|
+
("logos", "logo"),
|
|
1550
|
+
("documents", "logos"),
|
|
1551
|
+
("productImages", "productImgeas"),
|
|
1552
|
+
]->Array.map(((a, b)) => Capability_Inference.withinOneEdit(a, b)),
|
|
1553
|
+
)->toEqual([true, true, true, false, false])
|
|
1554
|
+
)
|
|
1555
|
+
|
|
1556
|
+
// Reached only through an explicit override: two *derived* names cannot
|
|
1557
|
+
// differ by number, because each is pluralised through its singular stem.
|
|
1558
|
+
testSync("a singular/plural pair collides even at two edits apart", () =>
|
|
1559
|
+
expect(Capability_Inference.sameStem("productImage", "productImages"))->toBe(true)
|
|
1560
|
+
)
|
|
1561
|
+
})
|
|
1562
|
+
|
|
1376
1563
|
// Making a field optional says the value may be absent. It does not say the
|
|
1377
1564
|
// field stopped being a storage ref or a reference — but both walks read the
|
|
1378
1565
|
// marker through `Semantic.get`, and an optional field's marker sits on the
|