@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,565 @@
1
+ // Generated by ReScript, PLEASE EDIT WITH CARE
2
+
3
+ import * as Stdlib_Array from "@rescript/runtime/lib/es6/Stdlib_Array.js";
4
+ import * as Stdlib_Option from "@rescript/runtime/lib/es6/Stdlib_Option.js";
5
+ import * as Stdlib_JsError from "@rescript/runtime/lib/es6/Stdlib_JsError.js";
6
+ import * as Pairing$Reventless from "./Pairing.res.mjs";
7
+ import * as Discovery$Reventless from "./Discovery.res.mjs";
8
+
9
+ function stripSuffix(s, suffix) {
10
+ if (s.endsWith(suffix)) {
11
+ return s.slice(0, s.length - suffix.length | 0);
12
+ } else {
13
+ return s;
14
+ }
15
+ }
16
+
17
+ function epModuleName(mappingStem) {
18
+ return stripSuffix(mappingStem, "Mapping");
19
+ }
20
+
21
+ function renderSlices(platformFactory, suffix, implSuffix, stems) {
22
+ return stems.map(stem => " module " + stem + suffix + " = Platform." + platformFactory + ".Make(" + stem + ", " + stem + implSuffix + ")");
23
+ }
24
+
25
+ function renderStateChangeSlices(stems, asyncStems) {
26
+ return stems.map(stem => {
27
+ let match = asyncStems[stem];
28
+ let factory = match !== undefined && match ? "MakeAsync" : "Make";
29
+ return " module " + stem + "Slice = Platform.StateChangeSlice." + factory + "(" + stem + ", " + stem + Pairing$Reventless.implSuffixForStateChange + ")";
30
+ });
31
+ }
32
+
33
+ function renderAutomationSlices(stems) {
34
+ return stems.map(stem => " module " + stem + "Slice = Platform.AutomationSlice.Make(" + stem + ", " + stem + "_Automation)");
35
+ }
36
+
37
+ function renderAggregates(aggregates) {
38
+ return aggregates.flatMap(param => {
39
+ let spec = param.spec;
40
+ let em = Stdlib_Option.getOr(param.eventMappings, "ReventlessInfra.NoEventMappings.Make(" + spec + ")");
41
+ let factory = param.isAsync ? "MakeAsync" : "Make";
42
+ return [
43
+ " module " + spec + "Aggregate = Platform.Aggregate." + factory + "(",
44
+ " " + spec + ",",
45
+ " " + param.behavior + ",",
46
+ " " + em + ",",
47
+ " )"
48
+ ];
49
+ });
50
+ }
51
+
52
+ function renderReadModels(readModels) {
53
+ return readModels.flatMap(param => {
54
+ let readModel = param.readModel;
55
+ let wrapperName = readModel.endsWith("ReadModel") ? readModel : readModel + "ReadModel";
56
+ let factory = param.stream ? "Platform.ReadModelStream.Make" : "Platform.ReadModel.Make";
57
+ return [" module " + wrapperName + " = " + factory + "(" + readModel + ", " + param.projections + ")"];
58
+ });
59
+ }
60
+
61
+ function renderTasks(tasks) {
62
+ return tasks.map(stem => " module " + stem + "Task = Platform.Task.Make(" + stem + ")");
63
+ }
64
+
65
+ function renderExtensionPoints(extensionPoints) {
66
+ return extensionPoints.flatMap(param => {
67
+ let mappings = param.mappings;
68
+ let group = param.group;
69
+ let count = mappings.length;
70
+ let firstMapping = mappings[0];
71
+ let moduleName = group !== undefined ? group : stripSuffix(firstMapping, "Mapping");
72
+ switch (count) {
73
+ case 0 :
74
+ return [];
75
+ case 1 :
76
+ return [" module " + moduleName + " = Platform.ExtensionPoint.Make(" + firstMapping + ")"];
77
+ case 2 :
78
+ let m2 = mappings[1];
79
+ return [
80
+ " module " + moduleName + " = Platform.ExtensionPoint.Make2(",
81
+ " " + firstMapping + ",",
82
+ " " + m2 + ",",
83
+ " )"
84
+ ];
85
+ case 3 :
86
+ let m2$1 = mappings[1];
87
+ let m3 = mappings[2];
88
+ return [
89
+ " module " + moduleName + " = Platform.ExtensionPoint.Make3(",
90
+ " " + firstMapping + ",",
91
+ " " + m2$1 + ",",
92
+ " " + m3 + ",",
93
+ " )"
94
+ ];
95
+ default:
96
+ let mappingLines = mappings.map(m => " module(" + m + "),");
97
+ return [
98
+ [
99
+ " module " + moduleName + " = Platform.ExtensionPoint.MakeMulti({",
100
+ " module Spec = " + firstMapping + ".ExtensionPoint",
101
+ " module type Mapping = ReventlessInfra.ExtensionPointMapping.T with module ExtensionPoint := Spec",
102
+ " let name = Spec.name",
103
+ " let moduleUrl: string = %raw(`import.meta.url`)",
104
+ " let mappings: array<module(Mapping)> = ["
105
+ ],
106
+ mappingLines,
107
+ [
108
+ " ]",
109
+ " })"
110
+ ]
111
+ ].flat();
112
+ }
113
+ });
114
+ }
115
+
116
+ function renderExtensions(extensions) {
117
+ return extensions.map(stem => " module " + stem + " = Platform.Extension.Make(" + stem + ".Mapping)");
118
+ }
119
+
120
+ function renderMakeParam(param, items, moduleSuffix) {
121
+ if (items.length === 0) {
122
+ return;
123
+ }
124
+ let entries = items.map(s => "module(" + s + moduleSuffix + ")");
125
+ return " ~" + param + "=[" + entries.join(", ") + "],";
126
+ }
127
+
128
+ function renderStateViewSlicesMakeParam(slices, streamSlices) {
129
+ let entries = [
130
+ slices.map(s => "module(" + s + "Slice)"),
131
+ streamSlices.map(s => "module(" + s + "StreamSlice)")
132
+ ].flat();
133
+ if (entries.length === 0) {
134
+ return;
135
+ } else {
136
+ return " ~stateViewSlices=[" + entries.join(", ") + "],";
137
+ }
138
+ }
139
+
140
+ function renderReadModelMakeParam(readModels) {
141
+ if (readModels.length === 0) {
142
+ return;
143
+ }
144
+ let entries = readModels.map(param => {
145
+ let readModel = param.readModel;
146
+ let wrapperName = readModel.endsWith("ReadModel") ? readModel : readModel + "ReadModel";
147
+ return "module(" + wrapperName + ")";
148
+ });
149
+ return " ~readModels=[" + entries.join(", ") + "],";
150
+ }
151
+
152
+ function renderAggregateMakeParam(aggregates) {
153
+ if (aggregates.length === 0) {
154
+ return;
155
+ }
156
+ let entries = aggregates.map(param => "module(" + param.spec + "Aggregate)");
157
+ return " ~aggregates=[" + entries.join(", ") + "],";
158
+ }
159
+
160
+ function renderEpMakeParam(extensionPoints) {
161
+ if (extensionPoints.length === 0) {
162
+ return;
163
+ }
164
+ let entries = extensionPoints.map(param => {
165
+ let group = param.group;
166
+ let firstMapping = param.mappings[0];
167
+ let moduleName = group !== undefined ? group : stripSuffix(firstMapping, "Mapping");
168
+ return "module(" + moduleName + ")";
169
+ });
170
+ return " ~extensionPoints=[" + entries.join(", ") + "],";
171
+ }
172
+
173
+ function renderExtensionMakeParam(extensions) {
174
+ if (extensions.length === 0) {
175
+ return;
176
+ }
177
+ let entries = extensions.map(s => "module(" + s + ")");
178
+ return " ~extensions=[" + entries.join(", ") + "],";
179
+ }
180
+
181
+ function renderRuntimeHints(h) {
182
+ let optInt = o => {
183
+ if (o !== undefined) {
184
+ return "Some(" + o.toString() + ")";
185
+ } else {
186
+ return "None";
187
+ }
188
+ };
189
+ return "{ReventlessInfra.RuntimeHints.memorySize: " + optInt(h.memorySize) + ", timeout: " + optInt(h.timeout) + "}";
190
+ }
191
+
192
+ function collectComponentNames(resolved) {
193
+ return [
194
+ resolved.aggregates.map(param => param.spec),
195
+ resolved.readModels.map(param => param.readModel),
196
+ resolved.stateChangeSlices,
197
+ resolved.stateViewSlices,
198
+ resolved.stateViewSlicesStream,
199
+ resolved.automationSlices,
200
+ resolved.outboundTranslationSlices,
201
+ resolved.inboundTranslationSlices,
202
+ resolved.tasks,
203
+ resolved.extensions,
204
+ resolved.extensionPoints.map(param => {
205
+ let group = param.group;
206
+ if (group !== undefined) {
207
+ return group;
208
+ } else {
209
+ return stripSuffix(param.mappings[0], "Mapping");
210
+ }
211
+ })
212
+ ].flat();
213
+ }
214
+
215
+ function validateComponentRuntimeKeys(resolved, componentRuntime) {
216
+ let known = collectComponentNames(resolved);
217
+ Object.keys(componentRuntime).forEach(name => {
218
+ if (!known.includes(name)) {
219
+ console.warn("Generator: plugin.json `runtime` override for `" + name + "` matches no component in this plugin. Known components: " + known.join(", "));
220
+ return;
221
+ }
222
+ });
223
+ }
224
+
225
+ function renderComponentRuntimeParam(componentRuntime) {
226
+ let entries = Object.entries(componentRuntime);
227
+ if (entries.length === 0) {
228
+ return;
229
+ }
230
+ let rendered = entries.map(param => "(\"" + param[0] + "\", " + renderRuntimeHints(param[1]) + ")").join(", ");
231
+ return " ~componentRuntime=Dict.fromArray([" + rendered + "]),";
232
+ }
233
+
234
+ function renderTaskMakeParam(tasks) {
235
+ if (tasks.length === 0) {
236
+ return;
237
+ }
238
+ let entries = tasks.map(s => "module(" + s + "Task)");
239
+ return " ~tasks=[" + entries.join(", ") + "],";
240
+ }
241
+
242
+ function renderPluginStructureCall(name, aggregates, readModels, stateViewSlices, stateViewSlicesStream, stateChangeSlices, automationSlices, outboundTranslationSlices, inboundTranslationSlices, extensions, extensionPoints, componentChapters) {
243
+ let epMappingStems = extensionPoints.flatMap(param => param.mappings);
244
+ let hasComponents = aggregates.length !== 0 || readModels.length !== 0 || stateViewSlices.length !== 0 || stateViewSlicesStream.length !== 0 || stateChangeSlices.length !== 0 || automationSlices.length !== 0 || outboundTranslationSlices.length !== 0 || inboundTranslationSlices.length !== 0 || extensions.length !== 0 || epMappingStems.length !== 0;
245
+ if (!hasComponents) {
246
+ return;
247
+ }
248
+ let ls = [];
249
+ ls.push(" let pluginStructure = Platform.Plugin.makePluginDefinition(");
250
+ ls.push(" ~name=\"" + name + "\",");
251
+ if (aggregates.length !== 0) {
252
+ let entries = aggregates.map(param => "module(" + param.spec + "Aggregate)");
253
+ ls.push(" ~aggregates=[" + entries.join(", ") + "],");
254
+ }
255
+ if (readModels.length !== 0) {
256
+ let entries$1 = readModels.map(param => {
257
+ let readModel = param.readModel;
258
+ let wrapperName = readModel.endsWith("ReadModel") ? readModel : readModel + "ReadModel";
259
+ return "module(" + wrapperName + ")";
260
+ });
261
+ ls.push(" ~readModels=[" + entries$1.join(", ") + "],");
262
+ }
263
+ let allStateViewEntries = [
264
+ stateViewSlices.map(s => "module(" + s + "Slice)"),
265
+ stateViewSlicesStream.map(s => "module(" + s + "StreamSlice)")
266
+ ].flat();
267
+ if (allStateViewEntries.length !== 0) {
268
+ ls.push(" ~stateViewSlices=[" + allStateViewEntries.join(", ") + "],");
269
+ }
270
+ if (stateChangeSlices.length !== 0) {
271
+ let entries$2 = stateChangeSlices.map(s => "module(" + s + "Slice)");
272
+ ls.push(" ~stateChangeSlices=[" + entries$2.join(", ") + "],");
273
+ }
274
+ if (automationSlices.length !== 0) {
275
+ let entries$3 = automationSlices.map(s => "module(" + s + "Slice)");
276
+ ls.push(" ~automationSlices=[" + entries$3.join(", ") + "],");
277
+ }
278
+ if (outboundTranslationSlices.length !== 0) {
279
+ let entries$4 = outboundTranslationSlices.map(s => "module(" + s + "Slice)");
280
+ ls.push(" ~outboundTranslationSlices=[" + entries$4.join(", ") + "],");
281
+ }
282
+ if (inboundTranslationSlices.length !== 0) {
283
+ let entries$5 = inboundTranslationSlices.map(s => "module(" + s + "Slice)");
284
+ ls.push(" ~inboundTranslationSlices=[" + entries$5.join(", ") + "],");
285
+ }
286
+ if (extensions.length !== 0) {
287
+ let entries$6 = extensions.map(s => "module(" + s + ")");
288
+ ls.push(" ~extensions=[" + entries$6.join(", ") + "],");
289
+ }
290
+ if (epMappingStems.length !== 0) {
291
+ let entries$7 = epMappingStems.map(s => "module(" + s + ")");
292
+ ls.push(" ~extensionPoints=[" + entries$7.join(", ") + "],");
293
+ }
294
+ if (componentChapters.length !== 0) {
295
+ let entries$8 = componentChapters.map(param => "(\"" + param[0] + "\", \"" + param[1] + "\")");
296
+ ls.push(" ~componentChapters=Dict.fromArray([" + entries$8.join(", ") + "]),");
297
+ }
298
+ ls.push(" )");
299
+ return ls;
300
+ }
301
+
302
+ function validateUniqueSpecStems(discovered) {
303
+ let byStem = {};
304
+ discovered.forEach(d => {
305
+ let existing = Stdlib_Option.getOr(byStem[d.stem], []);
306
+ existing.push(d.relPath);
307
+ byStem[d.stem] = existing;
308
+ });
309
+ Object.entries(byStem).forEach(param => {
310
+ let paths = param[1];
311
+ if (paths.length <= 1) {
312
+ return;
313
+ }
314
+ let pathList = paths.toSorted((a, b) => {
315
+ if (a < b) {
316
+ return -1.0;
317
+ } else if (a > b) {
318
+ return 1.0;
319
+ } else {
320
+ return 0.0;
321
+ }
322
+ }).join("\n - ");
323
+ Stdlib_JsError.throwWithMessage("Generator: stem `" + param[0] + "` is used by multiple files. Filename stems must be unique across a plugin so the generated module names don't collide:\n - " + pathList);
324
+ });
325
+ }
326
+
327
+ function validateSliceTargets(resolved) {
328
+ let knownReceivers = resolved.aggregates.map(param => param.spec).concat(resolved.stateChangeSlices);
329
+ let check = (kind, stem, target) => {
330
+ if (target !== undefined) {
331
+ if (!knownReceivers.includes(target)) {
332
+ return Stdlib_JsError.throwWithMessage("Generator: " + kind + " `" + stem + "` declares targetName = \"" + target + "\" but no such command receiver exists. Valid targets: " + knownReceivers.join(", "));
333
+ } else {
334
+ return;
335
+ }
336
+ } else {
337
+ return Stdlib_JsError.throwWithMessage("Generator: " + kind + " `" + stem + "` is missing `let targetName = \"...\"`. Valid targets: " + knownReceivers.join(", "));
338
+ }
339
+ };
340
+ resolved.automationSlices.forEach(stem => check("AutomationSlice", stem, Stdlib_Option.getOr(resolved.automationSliceTargets[stem], undefined)));
341
+ resolved.inboundTranslationSlices.forEach(stem => check("InboundTranslationSlice", stem, Stdlib_Option.getOr(resolved.inboundTranslationSliceTargets[stem], undefined)));
342
+ resolved.outboundTranslationSlices.forEach(stem => {
343
+ let t = Stdlib_Option.getOr(resolved.outboundTranslationSliceTargets[stem], undefined);
344
+ if (t !== undefined && !knownReceivers.includes(t)) {
345
+ return Stdlib_JsError.throwWithMessage("Generator: OutboundTranslationSlice `" + stem + "` declares targetName = Some(\"" + t + "\") but no such command receiver exists. Valid targets: " + knownReceivers.join(", "));
346
+ }
347
+ });
348
+ }
349
+
350
+ function renderMain(config) {
351
+ let name = config.name;
352
+ return [
353
+ "// AUTO-GENERATED — do not edit. Run `npm run generate` to update.",
354
+ "// " + name + " plugin — AWS deployment.",
355
+ "",
356
+ "ReventlessInfra.DeployBootstrap.run(PreDeploy)",
357
+ "",
358
+ "module Platform = ReventlessAws.Platform.Make()",
359
+ "module " + name + " = Plugin.Make(Platform)",
360
+ "",
361
+ "let default = Platform.deployPlugin(",
362
+ " ~plugin=module(" + name + "),",
363
+ ")",
364
+ "",
365
+ "ReventlessInfra.DeployBootstrap.run(PostDeploy)",
366
+ ""
367
+ ].join("\n");
368
+ }
369
+
370
+ function pluginNameToEnvBase(name) {
371
+ return name.split("").map((ch, i) => {
372
+ let isUpper = ch !== "" && ch === ch.toUpperCase() && ch !== ch.toLowerCase();
373
+ if (i > 0 && isUpper) {
374
+ return "_" + ch;
375
+ } else {
376
+ return ch;
377
+ }
378
+ }).join("").toUpperCase();
379
+ }
380
+
381
+ function renderAwsWrapper(compositionNamespace) {
382
+ return [
383
+ "// AUTO-GENERATED — do not edit. Run `npm run generate` to update.",
384
+ "",
385
+ "module Make = (",
386
+ " Platform: ReventlessInfra.Platform.T",
387
+ " with type api = ReventlessAws.Types.AppSync.api",
388
+ " and type role = ReventlessAws.Types.AppSync.role,",
389
+ ") => {",
390
+ " module Composition = " + compositionNamespace + ".Plugin.Make(Platform)",
391
+ " let make = () => Composition.make()",
392
+ "}",
393
+ ""
394
+ ].join("\n");
395
+ }
396
+
397
+ function renderComposition(config, resolved, componentChapters) {
398
+ let lines = [];
399
+ lines.push("// AUTO-GENERATED — do not edit. Run `npm run generate` to update.");
400
+ lines.push("");
401
+ lines.push("@val external uiBundleUrl: option<string> = \"process.env." + pluginNameToEnvBase(config.name) + "_UI_BUNDLE_URL\"");
402
+ lines.push("");
403
+ lines.push("module Make = (Platform: ReventlessInfra.Platform.T) => {");
404
+ let push = sectionLines => {
405
+ sectionLines.forEach(l => {
406
+ lines.push(l);
407
+ });
408
+ lines.push("");
409
+ };
410
+ if (resolved.stateChangeSlices.length !== 0) {
411
+ lines.push(" // StateChangeSlices");
412
+ push(renderStateChangeSlices(resolved.stateChangeSlices, resolved.asyncStateChangeSlices));
413
+ }
414
+ if (resolved.stateViewSlices.length !== 0) {
415
+ lines.push(" // StateViewSlices");
416
+ push(renderSlices("StateViewSlice", "Slice", Pairing$Reventless.implSuffixForStateView, resolved.stateViewSlices));
417
+ }
418
+ if (resolved.stateViewSlicesStream.length !== 0) {
419
+ lines.push(" // StateViewSliceStreams");
420
+ push(renderSlices("StateViewSliceStream", "StreamSlice", Pairing$Reventless.implSuffixForStateView, resolved.stateViewSlicesStream));
421
+ }
422
+ if (resolved.automationSlices.length !== 0) {
423
+ lines.push(" // AutomationSlices");
424
+ push(renderAutomationSlices(resolved.automationSlices));
425
+ }
426
+ if (resolved.outboundTranslationSlices.length !== 0) {
427
+ lines.push(" // OutboundTranslationSlices");
428
+ push(renderSlices("OutboundTranslationSlice", "Slice", Pairing$Reventless.implSuffixForTranslation, resolved.outboundTranslationSlices));
429
+ }
430
+ if (resolved.inboundTranslationSlices.length !== 0) {
431
+ lines.push(" // InboundTranslationSlices");
432
+ push(renderSlices("InboundTranslationSlice", "Slice", Pairing$Reventless.implSuffixForTranslation, resolved.inboundTranslationSlices));
433
+ }
434
+ if (resolved.aggregates.length !== 0) {
435
+ lines.push(" // Aggregates");
436
+ push(renderAggregates(resolved.aggregates));
437
+ }
438
+ if (resolved.readModels.length !== 0) {
439
+ lines.push(" // ReadModels");
440
+ push(renderReadModels(resolved.readModels));
441
+ }
442
+ if (resolved.tasks.length !== 0) {
443
+ lines.push(" // Tasks");
444
+ push(renderTasks(resolved.tasks));
445
+ }
446
+ if (resolved.extensionPoints.length !== 0) {
447
+ lines.push(" // ExtensionPoints");
448
+ push(renderExtensionPoints(resolved.extensionPoints));
449
+ }
450
+ if (resolved.extensions.length !== 0) {
451
+ lines.push(" // Extensions");
452
+ push(renderExtensions(resolved.extensions));
453
+ }
454
+ let pluginStructureLines = renderPluginStructureCall(config.name, resolved.aggregates, resolved.readModels, resolved.stateViewSlices, resolved.stateViewSlicesStream, resolved.stateChangeSlices, resolved.automationSlices, resolved.outboundTranslationSlices, resolved.inboundTranslationSlices, resolved.extensions, resolved.extensionPoints, componentChapters);
455
+ let hasPluginStructure = Stdlib_Option.isSome(pluginStructureLines);
456
+ if (pluginStructureLines !== undefined) {
457
+ pluginStructureLines.forEach(l => {
458
+ lines.push(l);
459
+ });
460
+ lines.push("");
461
+ }
462
+ lines.push(" let make = () =>");
463
+ lines.push(" Platform.Plugin.make(");
464
+ lines.push(" ~name=\"" + config.name + "\",");
465
+ lines.push(" ~heartbeatInterval=" + config.heartbeatInterval.toString() + ",");
466
+ let uiFragmentsParam;
467
+ if (hasPluginStructure) {
468
+ let ls = [];
469
+ ls.push(" ~uiFragments=?uiBundleUrl->Option.map(url =>");
470
+ ls.push(" Platform.Plugin.makeAutoUIManifest(");
471
+ ls.push(" ~remoteEntryUrl=url,");
472
+ ls.push(" ~name=\"" + config.name + "\",");
473
+ ls.push(" ~pluginStructure,");
474
+ ls.push(" ~readModelPositions=[\"platform-summary\"],");
475
+ ls.push(" ~aggregatePositions=[\"resource-detail\"],");
476
+ ls.push(" )");
477
+ ls.push(" ),");
478
+ uiFragmentsParam = ls;
479
+ } else {
480
+ uiFragmentsParam = undefined;
481
+ }
482
+ let makeParams = [
483
+ renderEpMakeParam(resolved.extensionPoints),
484
+ renderExtensionMakeParam(resolved.extensions),
485
+ renderAggregateMakeParam(resolved.aggregates),
486
+ renderReadModelMakeParam(resolved.readModels),
487
+ renderTaskMakeParam(resolved.tasks),
488
+ renderMakeParam("stateChangeSlices", resolved.stateChangeSlices, "Slice"),
489
+ renderStateViewSlicesMakeParam(resolved.stateViewSlices, resolved.stateViewSlicesStream),
490
+ renderMakeParam("automationSlices", resolved.automationSlices, "Slice"),
491
+ renderMakeParam("outboundTranslationSlices", resolved.outboundTranslationSlices, "Slice"),
492
+ renderMakeParam("inboundTranslationSlices", resolved.inboundTranslationSlices, "Slice"),
493
+ hasPluginStructure ? " ~pluginStructure=pluginStructure," : undefined,
494
+ resolved.systemCallableComponents.length !== 0 ? " ~systemCallableComponents=[" + resolved.systemCallableComponents.map(n => "\"" + n + "\"").join(", ") + "]," : undefined,
495
+ renderComponentRuntimeParam(config.componentRuntime)
496
+ ];
497
+ validateComponentRuntimeKeys(resolved, config.componentRuntime);
498
+ Stdlib_Array.filterMap(makeParams, x => x).forEach(line => {
499
+ lines.push(line);
500
+ });
501
+ if (uiFragmentsParam !== undefined) {
502
+ uiFragmentsParam.forEach(line => {
503
+ lines.push(line);
504
+ });
505
+ }
506
+ lines.push(" )");
507
+ lines.push("}");
508
+ lines.push("");
509
+ return lines.join("\n");
510
+ }
511
+
512
+ function render(config, resolved, discovered) {
513
+ validateUniqueSpecStems(discovered);
514
+ validateSliceTargets(resolved);
515
+ let componentStems = [
516
+ resolved.aggregates.map(param => param.spec),
517
+ resolved.readModels.map(param => param.readModel),
518
+ resolved.stateChangeSlices,
519
+ resolved.stateViewSlices,
520
+ resolved.stateViewSlicesStream,
521
+ resolved.automationSlices,
522
+ resolved.outboundTranslationSlices,
523
+ resolved.inboundTranslationSlices
524
+ ].flat();
525
+ let componentChapters = Discovery$Reventless.chaptersByStem(discovered).filter(param => componentStems.includes(param[0]));
526
+ let match = config.variant;
527
+ if (typeof match !== "object") {
528
+ return renderComposition(config, resolved, componentChapters);
529
+ } else {
530
+ return renderAwsWrapper(match.compositionNamespace);
531
+ }
532
+ }
533
+
534
+ export {
535
+ stripSuffix,
536
+ epModuleName,
537
+ renderSlices,
538
+ renderStateChangeSlices,
539
+ renderAutomationSlices,
540
+ renderAggregates,
541
+ renderReadModels,
542
+ renderTasks,
543
+ renderExtensionPoints,
544
+ renderExtensions,
545
+ renderMakeParam,
546
+ renderStateViewSlicesMakeParam,
547
+ renderReadModelMakeParam,
548
+ renderAggregateMakeParam,
549
+ renderEpMakeParam,
550
+ renderExtensionMakeParam,
551
+ renderRuntimeHints,
552
+ collectComponentNames,
553
+ validateComponentRuntimeKeys,
554
+ renderComponentRuntimeParam,
555
+ renderTaskMakeParam,
556
+ renderPluginStructureCall,
557
+ validateUniqueSpecStems,
558
+ validateSliceTargets,
559
+ renderMain,
560
+ pluginNameToEnvBase,
561
+ renderAwsWrapper,
562
+ renderComposition,
563
+ render,
564
+ }
565
+ /* Pairing-Reventless Not a pure module */
@@ -0,0 +1,106 @@
1
+ // Plugin configuration reader.
2
+ // Reads plugin.json from srcDir (optional) and derives defaults from package.json.
3
+
4
+ type variant = Composition | Aws({compositionNamespace: string})
5
+
6
+ // Per-component runtime resource hints, parsed from the optional `runtime`
7
+ // block in plugin.json and keyed by component name. Both fields are optional;
8
+ // an omitted field falls through to the per-kind builder default. See
9
+ // docs/plans/configurable-component-runtime-resources.md.
10
+ type runtimeHints = {
11
+ memorySize: option<int>,
12
+ timeout: option<int>,
13
+ }
14
+
15
+ type config = {
16
+ name: string,
17
+ heartbeatInterval: int,
18
+ exclude: array<string>,
19
+ // Keyed by component name (e.g. "Customers", "PlaceOrder"). Empty when the
20
+ // plugin.json has no `runtime` block.
21
+ componentRuntime: dict<runtimeHints>,
22
+ variant: variant,
23
+ }
24
+
25
+ // Convert npm package name to PascalCase plugin name.
26
+ // "@scope/my-catalog" → "MyCatalog", "online-shop" → "OnlineShop"
27
+ // Single-sourced with reventless-gwt's LocalHost via `PluginName` so the two
28
+ // can't drift (a drift silently breaks graph plugin keys).
29
+ let packageNameToPluginName = PluginName.fromPackageName
30
+
31
+ let readJson = (path: string): option<JSON.t> =>
32
+ try Some(NodeFs.readFileSync(path)->JSON.parseOrThrow) catch {
33
+ | _ => None
34
+ }
35
+
36
+ let getStrField = (json: JSON.t, key: string): option<string> =>
37
+ json
38
+ ->JSON.Decode.object
39
+ ->Option.flatMap(d => d->Dict.get(key))
40
+ ->Option.flatMap(JSON.Decode.string)
41
+
42
+ let getIntField = (json: JSON.t, key: string): option<int> =>
43
+ json
44
+ ->JSON.Decode.object
45
+ ->Option.flatMap(d => d->Dict.get(key))
46
+ ->Option.flatMap(JSON.Decode.float)
47
+ ->Option.map(Float.toInt)
48
+
49
+ let getStrArrayField = (json: JSON.t, key: string): option<array<string>> =>
50
+ json
51
+ ->JSON.Decode.object
52
+ ->Option.flatMap(d => d->Dict.get(key))
53
+ ->Option.flatMap(JSON.Decode.array)
54
+ ->Option.map(arr => arr->Array.filterMap(JSON.Decode.string))
55
+
56
+ // Parse the optional `runtime` object: each key is a component name, each value
57
+ // an object with optional `memorySize` / `timeout` ints. A missing block yields
58
+ // an empty dict; a non-object entry is skipped.
59
+ let getComponentRuntime = (json: JSON.t): dict<runtimeHints> => {
60
+ let result: dict<runtimeHints> = Dict.make()
61
+ json
62
+ ->JSON.Decode.object
63
+ ->Option.flatMap(d => d->Dict.get("runtime"))
64
+ ->Option.flatMap(JSON.Decode.object)
65
+ ->Option.forEach(runtimeObj =>
66
+ runtimeObj
67
+ ->Dict.toArray
68
+ ->Array.forEach(((componentName, entry)) =>
69
+ result->Dict.set(
70
+ componentName,
71
+ {
72
+ memorySize: getIntField(entry, "memorySize"),
73
+ timeout: getIntField(entry, "timeout"),
74
+ },
75
+ )
76
+ )
77
+ )
78
+ result
79
+ }
80
+
81
+ let read = (~srcDir: string): config => {
82
+ // Read package.json `name` from the parent of srcDir
83
+ let packageJsonPath = NodePath.join([NodePath.dirname(srcDir), "package.json"])
84
+ let packageJsonName = readJson(packageJsonPath)->Option.flatMap(j => getStrField(j, "name"))
85
+
86
+ // Read plugin.json from srcDir (optional)
87
+ let pluginJsonPath = NodePath.join([srcDir, "plugin.json"])
88
+ let pluginJson = if NodeFs.existsSync(pluginJsonPath) {
89
+ readJson(pluginJsonPath)
90
+ } else {
91
+ None
92
+ }
93
+
94
+ {
95
+ name: PluginName.resolve(
96
+ ~pluginJsonName=pluginJson->Option.flatMap(j => getStrField(j, "name")),
97
+ ~packageJsonName,
98
+ ),
99
+ heartbeatInterval: pluginJson
100
+ ->Option.flatMap(j => getIntField(j, "heartbeatInterval"))
101
+ ->Option.getOr(5),
102
+ exclude: pluginJson->Option.flatMap(j => getStrArrayField(j, "exclude"))->Option.getOr([]),
103
+ componentRuntime: pluginJson->Option.map(getComponentRuntime)->Option.getOr(Dict.make()),
104
+ variant: Composition,
105
+ }
106
+ }