@reventlessdev/reventless-spec 3.0.0-alpha.100

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (139) hide show
  1. package/CHANGELOG.md +931 -0
  2. package/LICENSE +202 -0
  3. package/README.md +109 -0
  4. package/package.json +49 -0
  5. package/rescript.json +32 -0
  6. package/run-generator.mjs +2 -0
  7. package/run-platform-generator.mjs +2 -0
  8. package/scripts/generate-currency.mjs +215 -0
  9. package/scripts/iso-4217-list-one.xml +1956 -0
  10. package/src/AnsiStyle.res +40 -0
  11. package/src/AnsiStyle.res.mjs +54 -0
  12. package/src/LogPrefix.res +192 -0
  13. package/src/LogPrefix.res.mjs +159 -0
  14. package/src/PackageVersion.res +67 -0
  15. package/src/PackageVersion.res.mjs +81 -0
  16. package/src/components/Aggregate.res +64 -0
  17. package/src/components/Aggregate.res.mjs +2 -0
  18. package/src/components/AutomationSlice.res +279 -0
  19. package/src/components/AutomationSlice.res.mjs +30 -0
  20. package/src/components/CapabilityManifest.res +74 -0
  21. package/src/components/CapabilityManifest.res.mjs +61 -0
  22. package/src/components/ComponentKind.res +99 -0
  23. package/src/components/ComponentKind.res.mjs +125 -0
  24. package/src/components/Counter.res +24 -0
  25. package/src/components/Counter.res.mjs +2 -0
  26. package/src/components/DcbDecode.res +118 -0
  27. package/src/components/DcbDecode.res.mjs +100 -0
  28. package/src/components/DcbScopeInference.res +244 -0
  29. package/src/components/DcbScopeInference.res.mjs +177 -0
  30. package/src/components/DcbTag.res +1335 -0
  31. package/src/components/DcbTag.res.mjs +898 -0
  32. package/src/components/DcbValidation.res +427 -0
  33. package/src/components/DcbValidation.res.mjs +423 -0
  34. package/src/components/DisplayName.res +40 -0
  35. package/src/components/DisplayName.res.mjs +26 -0
  36. package/src/components/ExtensionPoint.res +27 -0
  37. package/src/components/ExtensionPoint.res.mjs +2 -0
  38. package/src/components/InboundTranslationSlice.res +85 -0
  39. package/src/components/InboundTranslationSlice.res.mjs +2 -0
  40. package/src/components/OutboundTranslationSlice.res +153 -0
  41. package/src/components/OutboundTranslationSlice.res.mjs +2 -0
  42. package/src/components/Plugin.res +538 -0
  43. package/src/components/Plugin.res.mjs +264 -0
  44. package/src/components/PluginName.res +39 -0
  45. package/src/components/PluginName.res.mjs +45 -0
  46. package/src/components/ReadModel.res +199 -0
  47. package/src/components/ReadModel.res.mjs +18 -0
  48. package/src/components/Reference.res +55 -0
  49. package/src/components/Reference.res.mjs +50 -0
  50. package/src/components/Snapshot.res +26 -0
  51. package/src/components/Snapshot.res.mjs +2 -0
  52. package/src/components/StateAnnotations.res +97 -0
  53. package/src/components/StateAnnotations.res.mjs +15 -0
  54. package/src/components/StateChangeSlice.res +131 -0
  55. package/src/components/StateChangeSlice.res.mjs +2 -0
  56. package/src/components/StateViewSlice.res +123 -0
  57. package/src/components/StateViewSlice.res.mjs +2 -0
  58. package/src/components/Task.res +62 -0
  59. package/src/components/Task.res.mjs +2 -0
  60. package/src/generator/Codegen.res +842 -0
  61. package/src/generator/Codegen.res.mjs +565 -0
  62. package/src/generator/Config.res +106 -0
  63. package/src/generator/Config.res.mjs +69 -0
  64. package/src/generator/Discovery.res +230 -0
  65. package/src/generator/Discovery.res.mjs +198 -0
  66. package/src/generator/Generator_Node.res +14 -0
  67. package/src/generator/Generator_Node.res.mjs +18 -0
  68. package/src/generator/Pairing.res +460 -0
  69. package/src/generator/Pairing.res.mjs +415 -0
  70. package/src/generator/PlatformCodegen.res +207 -0
  71. package/src/generator/PlatformCodegen.res.mjs +154 -0
  72. package/src/generator/PlatformGenerator.res +126 -0
  73. package/src/generator/PlatformGenerator.res.mjs +114 -0
  74. package/src/generator/PlatformManifests.res +203 -0
  75. package/src/generator/PlatformManifests.res.mjs +212 -0
  76. package/src/generator/PluginGenerator.res +57 -0
  77. package/src/generator/PluginGenerator.res.mjs +73 -0
  78. package/src/semantic/Bytes.res +54 -0
  79. package/src/semantic/Bytes.res.mjs +38 -0
  80. package/src/semantic/Capabilities.res +43 -0
  81. package/src/semantic/Capabilities.res.mjs +17 -0
  82. package/src/semantic/Color.res +51 -0
  83. package/src/semantic/Color.res.mjs +29 -0
  84. package/src/semantic/Currency.res +598 -0
  85. package/src/semantic/Currency.res.mjs +743 -0
  86. package/src/semantic/DateRange.res +148 -0
  87. package/src/semantic/DateRange.res.mjs +74 -0
  88. package/src/semantic/Duration.res +53 -0
  89. package/src/semantic/Duration.res.mjs +26 -0
  90. package/src/semantic/Email.res +51 -0
  91. package/src/semantic/Email.res.mjs +31 -0
  92. package/src/semantic/GeoPoint.res +226 -0
  93. package/src/semantic/GeoPoint.res.mjs +190 -0
  94. package/src/semantic/Geocoding.res +127 -0
  95. package/src/semantic/Geocoding.res.mjs +36 -0
  96. package/src/semantic/Money.res +196 -0
  97. package/src/semantic/Money.res.mjs +138 -0
  98. package/src/semantic/Offload.res +294 -0
  99. package/src/semantic/Offload.res.mjs +191 -0
  100. package/src/semantic/Percent.res +53 -0
  101. package/src/semantic/Percent.res.mjs +33 -0
  102. package/src/semantic/Phone.res +55 -0
  103. package/src/semantic/Phone.res.mjs +29 -0
  104. package/src/semantic/Semantic.res +162 -0
  105. package/src/semantic/Semantic.res.mjs +95 -0
  106. package/src/semantic/StorageRef.res +164 -0
  107. package/src/semantic/StorageRef.res.mjs +111 -0
  108. package/src/semantic/Url.res +66 -0
  109. package/src/semantic/Url.res.mjs +48 -0
  110. package/src/types/Authorization.res +23 -0
  111. package/src/types/Authorization.res.mjs +33 -0
  112. package/src/types/Behavior.res +86 -0
  113. package/src/types/Behavior.res.mjs +2 -0
  114. package/src/types/DateTime.res +29 -0
  115. package/src/types/DateTime.res.mjs +16 -0
  116. package/src/types/EventMapping.res +100 -0
  117. package/src/types/EventMapping.res.mjs +15 -0
  118. package/src/types/Handler.res +30 -0
  119. package/src/types/Handler.res.mjs +2 -0
  120. package/src/types/Id.res +75 -0
  121. package/src/types/Id.res.mjs +37 -0
  122. package/src/types/Identity.res +46 -0
  123. package/src/types/Identity.res.mjs +51 -0
  124. package/src/types/Message.res +326 -0
  125. package/src/types/Message.res.mjs +186 -0
  126. package/src/types/Projection.res +220 -0
  127. package/src/types/Projection.res.mjs +44 -0
  128. package/src/types/QueryEngine.res +123 -0
  129. package/src/types/QueryEngine.res.mjs +12 -0
  130. package/src/types/ReadConsistency.res +38 -0
  131. package/src/types/ReadConsistency.res.mjs +29 -0
  132. package/src/types/Schedule.res +65 -0
  133. package/src/types/Schedule.res.mjs +68 -0
  134. package/src/types/SideEffect.res +45 -0
  135. package/src/types/SideEffect.res.mjs +2 -0
  136. package/src/types/StoredEvent.res +46 -0
  137. package/src/types/StoredEvent.res.mjs +32 -0
  138. package/src/types/Visibility.res +24 -0
  139. package/src/types/Visibility.res.mjs +25 -0
@@ -0,0 +1,279 @@
1
+ /**
2
+ Module types for a DCB automation slice (TODO List Pattern).
3
+
4
+ An `AutomationSlice` listens to the shared `DcbEventLog` event topic, accumulates
5
+ pending work items (TODO list), and processes them exactly once by issuing commands.
6
+ Completion events mark TODO items as done, closing the automation loop.
7
+
8
+ ```
9
+ Event(s) → TODO List (read model) → Processor → Command → Event(s)
10
+ ```
11
+
12
+ Plan 02 splits the merged spec into two module types:
13
+
14
+ - `Spec` — types, identity, schemas, configuration constants. Per D2,
15
+ `todoItem` lives here (the persisted TODO state has a schema queried for
16
+ sweeping pending items — externally-observable, like ReadModel state).
17
+ - `Automation` — the three pure functions `collect`, `resolve`, `process`.
18
+
19
+ @example
20
+ ```rescript
21
+ // ShipOrder.res
22
+ let name = "ShipOrder"
23
+
24
+ @schema type todoItem = {orderId: string, shippingAddress: string}
25
+ @schema type command = CreateShipment({orderId: @s.matches(DcbTag.string) string, address: string})
26
+
27
+ let collect = event => switch event {
28
+ | OrderPlaced({orderId, shippingAddress}) =>
29
+ [(orderId, {orderId, shippingAddress})]
30
+ | _ => []
31
+ }
32
+
33
+ let resolve = event => switch event {
34
+ | ShipmentCreated({orderId}) => Some(orderId)
35
+ | _ => None
36
+ }
37
+
38
+ let process = (id, item) =>
39
+ Some((id, CreateShipment({orderId: item.orderId, address: item.shippingAddress})))
40
+
41
+ let maxRetries = 3
42
+ let heartbeatInterval = 60
43
+ ```
44
+ */
45
+
46
+ /**
47
+ The lean Spec for an AutomationSlice — types, identity, schemas, sweep config.
48
+
49
+ Plan 04 dropped `consumedEvent` from the Spec — the framework now derives the
50
+ consumed-event set from each per-source Mapping's `sourceEventSchema`, so a
51
+ manually-declared union is no longer necessary. Single-source slices have one
52
+ `Mapping` whose `sourceEventSchema` IS the consumed-event schema; multi-source
53
+ slices have several Mappings and the framework walks all of them.
54
+ */
55
+ module type Spec = {
56
+ /** Logical name of this automation slice (used as a component prefix). */
57
+ let name: string
58
+ let moduleUrl: string
59
+
60
+ /** The TODO item state — what data is accumulated for each pending work item. Must carry `@schema`. */
61
+ @schema
62
+ type todoItem
63
+
64
+ /** The command type produced by the processor. Must carry `@schema`. */
65
+ @schema
66
+ type command
67
+
68
+ /** Maximum number of retries for a failed processing attempt. */
69
+ let maxRetries: int
70
+
71
+ /** Heartbeat interval in seconds for sweeping pending/failed items. */
72
+ let heartbeatInterval: int
73
+
74
+ /** Name of the aggregate or StateChangeSlice that receives the produced command. */
75
+ let targetName: string
76
+ }
77
+
78
+ // ── Plan 04: Mixed-source mappings ───────────────────────────────────────────
79
+ //
80
+ // An AutomationSlice can declare per-source mappings that consume Aggregate
81
+ // events alongside the slice's own DcbEventLog events. Each mapping carries its
82
+ // own `collect`/`resolve` (over the source's `event` type) plus a `toTags`
83
+ // validation step run before each command publish. `process` remains shared in
84
+ // the slice's `Automation` module since it operates on `todoItem` regardless of
85
+ // the originating source.
86
+
87
+ /**
88
+ Ambient deployment context plumbed to every mapping function.
89
+
90
+ `Plugin_Builder` constructs this from its existing `~environment`, `~name` and
91
+ related parameters. `collect` and `resolve` use it to complete partial event
92
+ payloads (e.g. when a DCB tag field is supplied by deployment metadata rather
93
+ than the source event); `toTags` uses it to validate that all tag fields on the
94
+ target command will be populated.
95
+
96
+ The record is intentionally narrow — extending it is a deliberate framework
97
+ change, not an open-dict escape hatch. Runtime registry lookups are out of
98
+ scope (see Plan 04 / decision 3).
99
+ */
100
+ type context = {
101
+ environment: string,
102
+ platformName: string,
103
+ pluginName: string,
104
+ sliceName: string,
105
+ }
106
+
107
+ /**
108
+ A compiled per-source-to-AutomationSlice mapping.
109
+
110
+ Created by `AutomationSlice.Mapping.Make(Source, Target, Impl)`. The mapping
111
+ binds `sourceEvent` (decode target) plus `collect`/`resolve` to the slice's
112
+ `todoItem` type. `process` remains in the slice's `Automation` module — it is
113
+ source-agnostic.
114
+
115
+ Validation belongs upstream of the mapping: `collect` should return `[]` for
116
+ events that shouldn't enter the TODO list, and the command schema's
117
+ `@compositePartitionTag` / `@s.matches(DcbTag.string)` annotations enforce
118
+ DCB-tag invariants at encode time (failures mark the item Failed → retry).
119
+ */
120
+ module type Mapping = {
121
+ module SourceId: Id.T
122
+ @schema
123
+ type sourceEvent
124
+ type todoItem
125
+ type command
126
+ let sourceEventSchema: S.t<sourceEvent>
127
+ let sourceName: string
128
+ let collect: (sourceEvent, context) => array<(string, todoItem)>
129
+ let resolve: sourceEvent => option<string>
130
+ }
131
+
132
+ /**
133
+ The Automation — the source-agnostic processing function.
134
+
135
+ Plan 04 moved `collect` and `resolve` to per-source `Mapping` modules (where
136
+ they switch over the source's own `event` type). `process` stays here because
137
+ it operates on `todoItem`, which is uniform across sources.
138
+
139
+ The "close PPX gaps" plan merged the previous `Mappings` shape into this type:
140
+ the same module that exposes `process` also exposes the per-source `mappings`
141
+ array and the inner `module type Mapping`. This collapses the Plan 04 3-arg
142
+ `AutomationSlice.Make(Spec, Automation, Mappings)` into a 2-arg
143
+ `Make(Spec, Automation)` and lets the merged `_Automation.res` file (process +
144
+ per-source `Mapping.Make` + `let mappings`) live as a single source file.
145
+ */
146
+ module type Automation = {
147
+ module Spec: Spec
148
+
149
+ /**
150
+ Process: given a pending TODO item, produce a command.
151
+ The processor calls this for each pending item. Returns the target ID and command.
152
+ May return `None` to skip processing (e.g., wait for more data).
153
+ */
154
+ let process: (string, Spec.todoItem) => option<(string, Spec.command)>
155
+
156
+ /** File URL of this Automation module (`import.meta.url`). */
157
+ let moduleUrl: string
158
+
159
+ /**
160
+ The per-source `Mapping` type — substituted onto the slice's `Spec`. The
161
+ PPX-injected `module M = Reventless.AutomationSlice.Mappings.Make(Spec)`
162
+ + `module type Mapping = M.Mapping` produces exactly this shape; legacy
163
+ 3-file files re-export it via `module type Mapping = <Stem>_Mappings.Mapping`.
164
+ */
165
+ module type Mapping = Mapping
166
+ with type todoItem = Spec.todoItem
167
+ and type command = Spec.command
168
+
169
+ /**
170
+ The per-source mappings registered with this slice. Each entry is a first-class
171
+ module satisfying `Mapping`. The framework walks these to discover source
172
+ topics and dispatch decoded events to the matching `collect`/`resolve`.
173
+ */
174
+ let mappings: array<module(Mapping)>
175
+ }
176
+
177
+ /**
178
+ The implementation passed to `AutomationSlice.Mapping.Make`. Caller-supplied
179
+ `collect`/`resolve` are bound to source/target types via destructive
180
+ substitution in the functor.
181
+ */
182
+ module type MappingImpl = {
183
+ type sourceEvent
184
+ type todoItem
185
+ type command
186
+ let collect: (sourceEvent, context) => array<(string, todoItem)>
187
+ let resolve: sourceEvent => option<string>
188
+ }
189
+
190
+ /**
191
+ A collection of `Mapping` modules for a single AutomationSlice target.
192
+
193
+ Pass a `Mappings` module to the AutomationSlice plugin builder to register all
194
+ source-to-slice mappings. The shape mirrors `Projection.Mappings` for
195
+ ReadModels.
196
+
197
+ @example
198
+ ```rescript
199
+ // AutoFulfillment_Mappings.res
200
+ module M = Reventless.AutomationSlice.Mappings.Make(AutoFulfillmentSpec)
201
+ module type Mapping = M.Mapping
202
+
203
+ let mappings: array<module(Mapping)> = [
204
+ module(FromOrderShipped),
205
+ module(FromStockReserved),
206
+ ]
207
+ ```
208
+ */
209
+ module type Mappings = {
210
+ module Target: Spec
211
+ module type Mapping = Mapping
212
+ with type todoItem = Target.todoItem
213
+ and type command = Target.command
214
+ let moduleUrl: string
215
+ let mappings: array<module(Mapping)>
216
+ }
217
+
218
+ /**
219
+ Builds an `AutomationSlice.Mapping` from a `Source`, the slice's `Spec`, and a
220
+ `MappingImpl`.
221
+
222
+ @example
223
+ ```rescript
224
+ // AutoFulfillment/FromOrderShipped.res
225
+ module FromOrderShipped = Reventless.AutomationSlice.Mapping.Make(
226
+ OrderSpec, // Source: Aggregate spec module
227
+ AutoFulfillmentSpec, // Target: this slice's spec
228
+ {
229
+ let collect = (event, _ctx) =>
230
+ switch event {
231
+ | OrderSpec.OrderShipped({orderId, productId}) =>
232
+ [(orderId ++ ":" ++ productId, {AutoFulfillmentSpec.orderId, productId})]
233
+ | _ => []
234
+ }
235
+
236
+ let resolve = event =>
237
+ switch event {
238
+ | OrderSpec.OrderRefunded({orderId, productId}) =>
239
+ Some(orderId ++ ":" ++ productId)
240
+ | _ => None
241
+ }
242
+ },
243
+ )
244
+ ```
245
+ */
246
+ module Mapping = {
247
+ module Make = (
248
+ Source: Projection.Source,
249
+ Target: Spec,
250
+ Impl: MappingImpl
251
+ with type sourceEvent := Source.event
252
+ and type todoItem := Target.todoItem
253
+ and type command := Target.command,
254
+ ): (
255
+ Mapping
256
+ with type sourceEvent = Source.event
257
+ and type todoItem = Target.todoItem
258
+ and type command = Target.command
259
+ and module SourceId = Source.Id
260
+ ) => {
261
+ module SourceId = Source.Id
262
+ @schema
263
+ type sourceEvent = Source.event
264
+ type todoItem = Target.todoItem
265
+ type command = Target.command
266
+ let sourceName = Source.name
267
+ let collect = Impl.collect
268
+ let resolve = Impl.resolve
269
+ }
270
+ }
271
+
272
+ module Mappings = {
273
+ module Make = (Target: Spec) => {
274
+ module type Mapping = Mapping
275
+ with type todoItem = Target.todoItem
276
+ and type command = Target.command
277
+ }
278
+ }
279
+
@@ -0,0 +1,30 @@
1
+ // Generated by ReScript, PLEASE EDIT WITH CARE
2
+
3
+
4
+ function Make(Source) {
5
+ return Target => (Impl => ({
6
+ SourceId: Source.Id,
7
+ sourceEventSchema: Source.eventSchema,
8
+ sourceName: Source.name,
9
+ collect: Impl.collect,
10
+ resolve: Impl.resolve
11
+ }));
12
+ }
13
+
14
+ let Mapping = {
15
+ Make: Make
16
+ };
17
+
18
+ function Make$1(Target) {
19
+ return {};
20
+ }
21
+
22
+ let Mappings = {
23
+ Make: Make$1
24
+ };
25
+
26
+ export {
27
+ Mapping,
28
+ Mappings,
29
+ }
30
+ /* No side effect */
@@ -0,0 +1,74 @@
1
+ /**
2
+ The per-plugin capability manifest — `capabilities.json`, written beside the
3
+ generated `Plugin.res` by the plugin package's build.
4
+
5
+ Each entry states one capability the plugin's fields declare they need, keyed
6
+ by the store's qualified `{plugin}.{store}` identity, with the declaring
7
+ `(component, field)` sites as provenance. The keys are taken verbatim from
8
+ `pluginStructure.requiredStores` — the manifest is a rendering of the
9
+ structure, never a second scan of the sources, so the two cannot spell one
10
+ fact differently.
11
+
12
+ The platform generator unions these files across a deployment's plugins and
13
+ emits the platform's capability list from them.
14
+ */
15
+
16
+ @schema
17
+ type kind = ObjectStore
18
+
19
+ /** The declaration site: the component's spec name and the field carrying the
20
+ `@storageRef` annotation, plus the store exactly as that field spells it.
21
+
22
+ `annotation` is optional only to keep reading a manifest emitted before it
23
+ existed: a plugin built earlier still parses, and a reader that cannot say
24
+ what the source says omits the claim rather than inventing one. Every
25
+ manifest emitted now carries it. */
26
+ @schema
27
+ type provenance = {component: string, field: string, annotation?: string}
28
+
29
+ @schema
30
+ type entry = {
31
+ kind: kind,
32
+ key: string,
33
+ declaredBy: array<provenance>,
34
+ }
35
+
36
+ @schema
37
+ type t = {capabilities: array<entry>}
38
+
39
+ /**
40
+ Build the manifest from a plugin's structure.
41
+
42
+ Keys iterate `requiredStores` itself, so a manifest's key set is byte-identical
43
+ to what the deployed plugin reports at runtime — the contract the deploy-time
44
+ coverage assertion checks against. A structure with no declarations yields an
45
+ empty `capabilities` list, not an absent file: "declares nothing" is a
46
+ statement, and the generator reading the manifests must be able to tell it
47
+ apart from "was never built".
48
+ */
49
+ let fromStructure = (structure: Plugin.pluginStructure): t => {
50
+ let declarations = structure.requiredStoreDeclarations->Option.getOr([])
51
+ {
52
+ capabilities: structure.requiredStores
53
+ ->Option.getOr([])
54
+ ->Array.map(key => {
55
+ kind: ObjectStore,
56
+ key,
57
+ declaredBy: declarations->Array.filterMap(d =>
58
+ d.store == key
59
+ ? Some({component: d.component, field: d.field, annotation: ?d.annotation})
60
+ : None
61
+ ),
62
+ }),
63
+ }
64
+ }
65
+
66
+ /** Deterministic rendering: 2-space indent, trailing newline. Rebuilding with
67
+ no source change must produce a byte-identical file, so the committed
68
+ manifest never churns. */
69
+ let render = (manifest: t): string =>
70
+ JSON.stringify(manifest->S.reverseConvertToJsonOrThrow(schema), ~space=2) ++ "\n"
71
+
72
+ /** One call for the emit CLI: structure in, `capabilities.json` content out. */
73
+ let renderForStructure = (structure: Plugin.pluginStructure): string =>
74
+ structure->fromStructure->render
@@ -0,0 +1,61 @@
1
+ // Generated by ReScript, PLEASE EDIT WITH CARE
2
+
3
+ import * as S from "sury/src/S.res.mjs";
4
+ import * as Stdlib_Array from "@rescript/runtime/lib/es6/Stdlib_Array.js";
5
+ import * as Stdlib_Option from "@rescript/runtime/lib/es6/Stdlib_Option.js";
6
+
7
+ let kindSchema = S.literal("ObjectStore");
8
+
9
+ let provenanceSchema = S.schema(s => ({
10
+ component: s.m(S.string),
11
+ field: s.m(S.string),
12
+ annotation: s.m(S.option(S.string))
13
+ }));
14
+
15
+ let entrySchema = S.schema(s => ({
16
+ kind: s.m(kindSchema),
17
+ key: s.m(S.string),
18
+ declaredBy: s.m(S.array(provenanceSchema))
19
+ }));
20
+
21
+ let schema = S.schema(s => ({
22
+ capabilities: s.m(S.array(entrySchema))
23
+ }));
24
+
25
+ function fromStructure(structure) {
26
+ let declarations = Stdlib_Option.getOr(structure.requiredStoreDeclarations, []);
27
+ return {
28
+ capabilities: Stdlib_Option.getOr(structure.requiredStores, []).map(key => ({
29
+ kind: "ObjectStore",
30
+ key: key,
31
+ declaredBy: Stdlib_Array.filterMap(declarations, d => {
32
+ if (d.store === key) {
33
+ return {
34
+ component: d.component,
35
+ field: d.field,
36
+ annotation: d.annotation
37
+ };
38
+ }
39
+ })
40
+ }))
41
+ };
42
+ }
43
+
44
+ function render(manifest) {
45
+ return JSON.stringify(S.reverseConvertToJsonOrThrow(manifest, schema), undefined, 2) + "\n";
46
+ }
47
+
48
+ function renderForStructure(structure) {
49
+ return render(fromStructure(structure));
50
+ }
51
+
52
+ export {
53
+ kindSchema,
54
+ provenanceSchema,
55
+ entrySchema,
56
+ schema,
57
+ fromStructure,
58
+ render,
59
+ renderForStructure,
60
+ }
61
+ /* kindSchema Not a pure module */
@@ -0,0 +1,99 @@
1
+ // Single source of truth for the Reventless component-kind vocabulary: the kinds
2
+ // themselves, every accepted folder spelling (singular / plural / short form),
3
+ // the canonical folder name, and the body-file suffixes. The plugin generator
4
+ // (`generator/Discovery`) and the external tooling that classifies files by
5
+ // folder (`reventless-gwt`'s `ComponentMeta`) both derive from this, so the two
6
+ // can't drift — previously the generator accepted plural/short folder names that
7
+ // the gwt discovery silently didn't recognise.
8
+
9
+ type t =
10
+ | StateChangeSlice
11
+ | StateViewSlice
12
+ | StateViewSliceStream
13
+ | AutomationSlice
14
+ | InboundTranslationSlice
15
+ | OutboundTranslationSlice
16
+ | Aggregate
17
+ | ReadModel
18
+ | ReadModelStream
19
+ | Task
20
+ | ExtensionPoint
21
+ | Extension
22
+
23
+ let all = [
24
+ StateChangeSlice,
25
+ StateViewSlice,
26
+ StateViewSliceStream,
27
+ AutomationSlice,
28
+ InboundTranslationSlice,
29
+ OutboundTranslationSlice,
30
+ Aggregate,
31
+ ReadModel,
32
+ ReadModelStream,
33
+ Task,
34
+ ExtensionPoint,
35
+ Extension,
36
+ ]
37
+
38
+ // The canonical (singular) folder name for a kind — the spelling the naming
39
+ // conventions and the graph `kind` field use.
40
+ let folderName = (t: t): string =>
41
+ switch t {
42
+ | StateChangeSlice => "StateChangeSlice"
43
+ | StateViewSlice => "StateViewSlice"
44
+ | StateViewSliceStream => "StateViewSliceStream"
45
+ | AutomationSlice => "AutomationSlice"
46
+ | InboundTranslationSlice => "InboundTranslationSlice"
47
+ | OutboundTranslationSlice => "OutboundTranslationSlice"
48
+ | Aggregate => "Aggregate"
49
+ | ReadModel => "ReadModel"
50
+ | ReadModelStream => "ReadModelStream"
51
+ | Task => "Task"
52
+ | ExtensionPoint => "ExtensionPoint"
53
+ | Extension => "Extension"
54
+ }
55
+
56
+ // Every folder spelling that denotes a kind → the kind. Tolerates the singular,
57
+ // plural, and (for slices) short forms the generator has always accepted.
58
+ let folderToKind = (folder: string): option<t> =>
59
+ switch folder {
60
+ | "StateChange" | "StateChanges" | "StateChangeSlice" | "StateChangeSlices" =>
61
+ Some(StateChangeSlice)
62
+ | "StateView" | "StateViews" | "StateViewSlice" | "StateViewSlices" => Some(StateViewSlice)
63
+ | "StateViewSliceStream" | "StateViewSliceStreams" => Some(StateViewSliceStream)
64
+ | "Automation" | "Automations" | "AutomationSlice" | "AutomationSlices" => Some(AutomationSlice)
65
+ | "InboundTranslation"
66
+ | "InboundTranslations"
67
+ | "InboundTranslationSlice"
68
+ | "InboundTranslationSlices" =>
69
+ Some(InboundTranslationSlice)
70
+ | "OutboundTranslation"
71
+ | "OutboundTranslations"
72
+ | "OutboundTranslationSlice"
73
+ | "OutboundTranslationSlices" =>
74
+ Some(OutboundTranslationSlice)
75
+ | "Aggregate" | "Aggregates" => Some(Aggregate)
76
+ | "ReadModel" | "ReadModels" => Some(ReadModel)
77
+ | "ReadModelStream" | "ReadModelStreams" => Some(ReadModelStream)
78
+ | "Task" | "Tasks" => Some(Task)
79
+ | "ExtensionPoint" | "ExtensionPoints" => Some(ExtensionPoint)
80
+ | "Extension" | "Extensions" => Some(Extension)
81
+ | _ => None
82
+ }
83
+
84
+ let isKindFolder = (folder: string): bool => folderToKind(folder)->Option.isSome
85
+
86
+ // Body-file suffixes stripped to recover a component's spec stem (longest first,
87
+ // so `_ExtensionPointMapping` is removed before `_ExtensionPoint`). Spec and body
88
+ // files in one folder collapse to the same component name.
89
+ let bodySuffixes = [
90
+ "_ExtensionPointMapping",
91
+ "_ExtensionPoint",
92
+ "_Extension",
93
+ "_Projections",
94
+ "_Projection",
95
+ "_Mappings",
96
+ "_Behavior",
97
+ "_Automation",
98
+ "_Translation",
99
+ ]
@@ -0,0 +1,125 @@
1
+ // Generated by ReScript, PLEASE EDIT WITH CARE
2
+
3
+ import * as Stdlib_Option from "@rescript/runtime/lib/es6/Stdlib_Option.js";
4
+
5
+ let all = [
6
+ "StateChangeSlice",
7
+ "StateViewSlice",
8
+ "StateViewSliceStream",
9
+ "AutomationSlice",
10
+ "InboundTranslationSlice",
11
+ "OutboundTranslationSlice",
12
+ "Aggregate",
13
+ "ReadModel",
14
+ "ReadModelStream",
15
+ "Task",
16
+ "ExtensionPoint",
17
+ "Extension"
18
+ ];
19
+
20
+ function folderName(t) {
21
+ switch (t) {
22
+ case "StateChangeSlice" :
23
+ return "StateChangeSlice";
24
+ case "StateViewSlice" :
25
+ return "StateViewSlice";
26
+ case "StateViewSliceStream" :
27
+ return "StateViewSliceStream";
28
+ case "AutomationSlice" :
29
+ return "AutomationSlice";
30
+ case "InboundTranslationSlice" :
31
+ return "InboundTranslationSlice";
32
+ case "OutboundTranslationSlice" :
33
+ return "OutboundTranslationSlice";
34
+ case "Aggregate" :
35
+ return "Aggregate";
36
+ case "ReadModel" :
37
+ return "ReadModel";
38
+ case "ReadModelStream" :
39
+ return "ReadModelStream";
40
+ case "Task" :
41
+ return "Task";
42
+ case "ExtensionPoint" :
43
+ return "ExtensionPoint";
44
+ case "Extension" :
45
+ return "Extension";
46
+ }
47
+ }
48
+
49
+ function folderToKind(folder) {
50
+ switch (folder) {
51
+ case "Aggregate" :
52
+ case "Aggregates" :
53
+ return "Aggregate";
54
+ case "Automation" :
55
+ case "AutomationSlice" :
56
+ case "AutomationSlices" :
57
+ case "Automations" :
58
+ return "AutomationSlice";
59
+ case "ExtensionPoint" :
60
+ case "ExtensionPoints" :
61
+ return "ExtensionPoint";
62
+ case "Extension" :
63
+ case "Extensions" :
64
+ return "Extension";
65
+ case "InboundTranslation" :
66
+ case "InboundTranslationSlice" :
67
+ case "InboundTranslationSlices" :
68
+ case "InboundTranslations" :
69
+ return "InboundTranslationSlice";
70
+ case "OutboundTranslation" :
71
+ case "OutboundTranslationSlice" :
72
+ case "OutboundTranslationSlices" :
73
+ case "OutboundTranslations" :
74
+ return "OutboundTranslationSlice";
75
+ case "ReadModelStream" :
76
+ case "ReadModelStreams" :
77
+ return "ReadModelStream";
78
+ case "ReadModel" :
79
+ case "ReadModels" :
80
+ return "ReadModel";
81
+ case "StateChange" :
82
+ case "StateChangeSlice" :
83
+ case "StateChangeSlices" :
84
+ case "StateChanges" :
85
+ return "StateChangeSlice";
86
+ case "StateViewSliceStream" :
87
+ case "StateViewSliceStreams" :
88
+ return "StateViewSliceStream";
89
+ case "StateView" :
90
+ case "StateViewSlice" :
91
+ case "StateViewSlices" :
92
+ case "StateViews" :
93
+ return "StateViewSlice";
94
+ case "Task" :
95
+ case "Tasks" :
96
+ return "Task";
97
+ default:
98
+ return;
99
+ }
100
+ }
101
+
102
+ function isKindFolder(folder) {
103
+ return Stdlib_Option.isSome(folderToKind(folder));
104
+ }
105
+
106
+ let bodySuffixes = [
107
+ "_ExtensionPointMapping",
108
+ "_ExtensionPoint",
109
+ "_Extension",
110
+ "_Projections",
111
+ "_Projection",
112
+ "_Mappings",
113
+ "_Behavior",
114
+ "_Automation",
115
+ "_Translation"
116
+ ];
117
+
118
+ export {
119
+ all,
120
+ folderName,
121
+ folderToKind,
122
+ isKindFolder,
123
+ bodySuffixes,
124
+ }
125
+ /* No side effect */
@@ -0,0 +1,24 @@
1
+ /**
2
+ A named counter (e.g. `"ProductCount"`). Used as a key in the counts database.
3
+ Multiple counters can exist within the same `Counter` component.
4
+ */
5
+ type counterId = string
6
+
7
+ /**
8
+ An opaque reference string that de-duplicates counter increments.
9
+
10
+ Each unique `reference` is counted at most once per `counterId`.
11
+ Typically set to the event's message ID to make increments idempotent.
12
+ */
13
+ type reference = string
14
+
15
+ /**
16
+ A counter threshold target.
17
+
18
+ When the count for `counterId` reaches `target`, the event mapping
19
+ framework fires the associated command.
20
+ */
21
+ type counterTarget = {
22
+ counterId: counterId,
23
+ target: int,
24
+ }
@@ -0,0 +1,2 @@
1
+ // Generated by ReScript, PLEASE EDIT WITH CARE
2
+ /* This output is empty. Its source's type definitions, externals and/or unused code got optimized away. */