@reventlessdev/reventless-spec 3.0.0-alpha.62 → 3.0.0-alpha.64
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 +15 -0
- package/package.json +15 -3
- package/rescript.json +6 -1
- package/src/components/ComponentKind.res +99 -0
- package/src/components/ComponentKind.res.mjs +125 -0
- package/src/components/DcbDecode.res +11 -21
- package/src/components/DcbDecode.res.mjs +8 -25
- package/src/components/DcbTag.res +31 -104
- package/src/components/DcbTag.res.mjs +33 -120
- package/src/components/DcbValidation.res +32 -13
- package/src/components/DcbValidation.res.mjs +45 -13
- package/src/components/PluginName.res +39 -0
- package/src/components/PluginName.res.mjs +45 -0
- package/src/components/Snapshot.res +26 -0
- package/src/components/Snapshot.res.mjs +2 -0
- package/src/generator/Config.res +9 -26
- package/src/generator/Config.res.mjs +5 -30
- package/src/generator/Discovery.res +5 -26
- package/src/generator/Discovery.res.mjs +4 -54
- package/src/generator/Pairing.res +33 -25
- package/src/generator/Pairing.res.mjs +35 -27
- package/src/generator/PluginGenerator.res +5 -0
- package/src/generator/PluginGenerator.res.mjs +1 -0
- package/src/types/Behavior.res +8 -0
|
@@ -1,61 +1,9 @@
|
|
|
1
1
|
// Generated by ReScript, PLEASE EDIT WITH CARE
|
|
2
2
|
|
|
3
3
|
import * as Nodepath from "node:path";
|
|
4
|
+
import * as ComponentKind$Reventless from "../components/ComponentKind.res.mjs";
|
|
4
5
|
import * as Generator_Node$Reventless from "./Generator_Node.res.mjs";
|
|
5
6
|
|
|
6
|
-
function folderToComponentType(folder) {
|
|
7
|
-
switch (folder) {
|
|
8
|
-
case "Aggregate" :
|
|
9
|
-
case "Aggregates" :
|
|
10
|
-
return "Aggregate";
|
|
11
|
-
case "Automation" :
|
|
12
|
-
case "AutomationSlice" :
|
|
13
|
-
case "AutomationSlices" :
|
|
14
|
-
case "Automations" :
|
|
15
|
-
return "AutomationSlice";
|
|
16
|
-
case "ExtensionPoint" :
|
|
17
|
-
case "ExtensionPoints" :
|
|
18
|
-
return "ExtensionPoint";
|
|
19
|
-
case "Extension" :
|
|
20
|
-
case "Extensions" :
|
|
21
|
-
return "Extension";
|
|
22
|
-
case "InboundTranslation" :
|
|
23
|
-
case "InboundTranslationSlice" :
|
|
24
|
-
case "InboundTranslationSlices" :
|
|
25
|
-
case "InboundTranslations" :
|
|
26
|
-
return "InboundTranslationSlice";
|
|
27
|
-
case "OutboundTranslation" :
|
|
28
|
-
case "OutboundTranslationSlice" :
|
|
29
|
-
case "OutboundTranslationSlices" :
|
|
30
|
-
case "OutboundTranslations" :
|
|
31
|
-
return "OutboundTranslationSlice";
|
|
32
|
-
case "ReadModelStream" :
|
|
33
|
-
case "ReadModelStreams" :
|
|
34
|
-
return "ReadModelStream";
|
|
35
|
-
case "ReadModel" :
|
|
36
|
-
case "ReadModels" :
|
|
37
|
-
return "ReadModel";
|
|
38
|
-
case "StateChange" :
|
|
39
|
-
case "StateChangeSlice" :
|
|
40
|
-
case "StateChangeSlices" :
|
|
41
|
-
case "StateChanges" :
|
|
42
|
-
return "StateChangeSlice";
|
|
43
|
-
case "StateViewSliceStream" :
|
|
44
|
-
case "StateViewSliceStreams" :
|
|
45
|
-
return "StateViewSliceStream";
|
|
46
|
-
case "StateView" :
|
|
47
|
-
case "StateViewSlice" :
|
|
48
|
-
case "StateViewSlices" :
|
|
49
|
-
case "StateViews" :
|
|
50
|
-
return "StateViewSlice";
|
|
51
|
-
case "Task" :
|
|
52
|
-
case "Tasks" :
|
|
53
|
-
return "Task";
|
|
54
|
-
default:
|
|
55
|
-
return;
|
|
56
|
-
}
|
|
57
|
-
}
|
|
58
|
-
|
|
59
7
|
function isAlwaysExcludedDir(name) {
|
|
60
8
|
if (name === "Plugin" || name === "tests") {
|
|
61
9
|
return true;
|
|
@@ -146,7 +94,7 @@ function walkDir(dir, relDir, parentComponentType, epGroup, exclude, acc) {
|
|
|
146
94
|
if (isAlwaysExcludedDir(entryName)) {
|
|
147
95
|
return;
|
|
148
96
|
}
|
|
149
|
-
let ct =
|
|
97
|
+
let ct = ComponentKind$Reventless.folderToKind(entryName);
|
|
150
98
|
if (ct === undefined) {
|
|
151
99
|
return walkDir(Nodepath.join(dir, entryName), relPath, parentComponentType, epGroup, exclude, acc);
|
|
152
100
|
}
|
|
@@ -199,6 +147,8 @@ function scan(srcDir, exclude) {
|
|
|
199
147
|
return acc;
|
|
200
148
|
}
|
|
201
149
|
|
|
150
|
+
let folderToComponentType = ComponentKind$Reventless.folderToKind;
|
|
151
|
+
|
|
202
152
|
export {
|
|
203
153
|
folderToComponentType,
|
|
204
154
|
isAlwaysExcludedDir,
|
|
@@ -165,6 +165,38 @@ let hasAsyncAttribute = (filePath: string): bool => {
|
|
|
165
165
|
}
|
|
166
166
|
}
|
|
167
167
|
|
|
168
|
+
// Partition the ExtensionPoint mapping files into flat (ungrouped) and grouped
|
|
169
|
+
// `extensionPointDef`s: every mapping sharing an `epGroup` collects into one
|
|
170
|
+
// grouped entry; the ungrouped ones share a single flat (`group: None`) entry.
|
|
171
|
+
// Pure (no I/O) so the grouping is unit-testable — in particular the A8 fix:
|
|
172
|
+
// `Option.getOr`'s eager default previously re-created the group's array every
|
|
173
|
+
// iteration, so a group with ≥2 mappings collapsed to `[]` and the generator
|
|
174
|
+
// emitted a `Plugin.res` referencing a never-generated module.
|
|
175
|
+
let groupExtensionPoints = (epFiles: array<Discovery.discoveredFile>): array<extensionPointDef> => {
|
|
176
|
+
let epByGroup: Dict.t<array<string>> = Dict.make()
|
|
177
|
+
let flatEpMappings: array<string> = []
|
|
178
|
+
|
|
179
|
+
epFiles->Array.forEach(({stem, epGroup}) =>
|
|
180
|
+
switch epGroup {
|
|
181
|
+
| None => flatEpMappings->Array.push(stem)
|
|
182
|
+
| Some(g) =>
|
|
183
|
+
switch Dict.get(epByGroup, g) {
|
|
184
|
+
| Some(arr) => arr->Array.push(stem)
|
|
185
|
+
| None => Dict.set(epByGroup, g, [stem])
|
|
186
|
+
}
|
|
187
|
+
}
|
|
188
|
+
)
|
|
189
|
+
|
|
190
|
+
let extensionPoints: array<extensionPointDef> = []
|
|
191
|
+
if flatEpMappings->Array.length > 0 {
|
|
192
|
+
extensionPoints->Array.push({group: None, mappings: flatEpMappings->sortedStems})
|
|
193
|
+
}
|
|
194
|
+
Dict.toArray(epByGroup)->Array.forEach(((group, mappings)) =>
|
|
195
|
+
extensionPoints->Array.push({group: Some(group), mappings: mappings->sortedStems})
|
|
196
|
+
)
|
|
197
|
+
extensionPoints
|
|
198
|
+
}
|
|
199
|
+
|
|
168
200
|
let resolve = (discovered: array<Discovery.discoveredFile>, ~srcDir: string): resolved => {
|
|
169
201
|
let eventMappings = findEventMappings(~srcDir)
|
|
170
202
|
|
|
@@ -309,31 +341,7 @@ let resolve = (discovered: array<Discovery.discoveredFile>, ~srcDir: string): re
|
|
|
309
341
|
)
|
|
310
342
|
|
|
311
343
|
// ── ExtensionPoint grouping ────────────────────────────────────────────────
|
|
312
|
-
let
|
|
313
|
-
let flatEpMappings: array<string> = []
|
|
314
|
-
|
|
315
|
-
epFiles->Array.forEach(({stem, epGroup}) => {
|
|
316
|
-
switch epGroup {
|
|
317
|
-
| None => flatEpMappings->Array.push(stem)
|
|
318
|
-
| Some(g) =>
|
|
319
|
-
let arr = Dict.get(epByGroup, g)->Option.getOr({
|
|
320
|
-
let a: array<string> = []
|
|
321
|
-
Dict.set(epByGroup, g, a)
|
|
322
|
-
a
|
|
323
|
-
})
|
|
324
|
-
arr->Array.push(stem)
|
|
325
|
-
}
|
|
326
|
-
})
|
|
327
|
-
|
|
328
|
-
let extensionPoints: array<extensionPointDef> = []
|
|
329
|
-
|
|
330
|
-
if flatEpMappings->Array.length > 0 {
|
|
331
|
-
extensionPoints->Array.push({group: None, mappings: flatEpMappings->sortedStems})
|
|
332
|
-
}
|
|
333
|
-
|
|
334
|
-
Dict.toArray(epByGroup)->Array.forEach(((group, mappings)) => {
|
|
335
|
-
extensionPoints->Array.push({group: Some(group), mappings: mappings->sortedStems})
|
|
336
|
-
})
|
|
344
|
+
let extensionPoints = groupExtensionPoints(epFiles)
|
|
337
345
|
|
|
338
346
|
// ── targetName extraction ──────────────────────────────────────────────────
|
|
339
347
|
let buildTargets = (stems: array<string>, relPaths: Dict.t<string>): Dict.t<option<string>> => {
|
|
@@ -3,7 +3,6 @@
|
|
|
3
3
|
import * as Nodefs from "node:fs";
|
|
4
4
|
import * as Nodepath from "node:path";
|
|
5
5
|
import * as Stdlib_Array from "@rescript/runtime/lib/es6/Stdlib_Array.js";
|
|
6
|
-
import * as Stdlib_Option from "@rescript/runtime/lib/es6/Stdlib_Option.js";
|
|
7
6
|
import * as Generator_Node$Reventless from "./Generator_Node.res.mjs";
|
|
8
7
|
|
|
9
8
|
let implSuffixForStateChange = "_Behavior";
|
|
@@ -132,6 +131,39 @@ function hasAsyncAttribute(filePath) {
|
|
|
132
131
|
}
|
|
133
132
|
}
|
|
134
133
|
|
|
134
|
+
function groupExtensionPoints(epFiles) {
|
|
135
|
+
let epByGroup = {};
|
|
136
|
+
let flatEpMappings = [];
|
|
137
|
+
epFiles.forEach(param => {
|
|
138
|
+
let epGroup = param.epGroup;
|
|
139
|
+
let stem = param.stem;
|
|
140
|
+
if (epGroup !== undefined) {
|
|
141
|
+
let arr = epByGroup[epGroup];
|
|
142
|
+
if (arr !== undefined) {
|
|
143
|
+
arr.push(stem);
|
|
144
|
+
} else {
|
|
145
|
+
epByGroup[epGroup] = [stem];
|
|
146
|
+
}
|
|
147
|
+
return;
|
|
148
|
+
}
|
|
149
|
+
flatEpMappings.push(stem);
|
|
150
|
+
});
|
|
151
|
+
let extensionPoints = [];
|
|
152
|
+
if (flatEpMappings.length !== 0) {
|
|
153
|
+
extensionPoints.push({
|
|
154
|
+
group: undefined,
|
|
155
|
+
mappings: sortedStems(flatEpMappings)
|
|
156
|
+
});
|
|
157
|
+
}
|
|
158
|
+
Object.entries(epByGroup).forEach(param => {
|
|
159
|
+
extensionPoints.push({
|
|
160
|
+
group: param[0],
|
|
161
|
+
mappings: sortedStems(param[1])
|
|
162
|
+
});
|
|
163
|
+
});
|
|
164
|
+
return extensionPoints;
|
|
165
|
+
}
|
|
166
|
+
|
|
135
167
|
function resolve(discovered, srcDir) {
|
|
136
168
|
let eventMappings = findEventMappings(srcDir);
|
|
137
169
|
let stateChangeSlices = [];
|
|
@@ -276,32 +308,7 @@ function resolve(discovered, srcDir) {
|
|
|
276
308
|
}
|
|
277
309
|
};
|
|
278
310
|
let readModels = Stdlib_Array.filterMap(sortedStems(readModelStems), rm => pairReadModel(false, rm)).concat(Stdlib_Array.filterMap(sortedStems(readModelStreamStems), rm => pairReadModel(true, rm)));
|
|
279
|
-
let
|
|
280
|
-
let flatEpMappings = [];
|
|
281
|
-
epFiles.forEach(param => {
|
|
282
|
-
let epGroup = param.epGroup;
|
|
283
|
-
let stem = param.stem;
|
|
284
|
-
if (epGroup !== undefined) {
|
|
285
|
-
let a = [];
|
|
286
|
-
let arr = Stdlib_Option.getOr(epByGroup[epGroup], (epByGroup[epGroup] = a, a));
|
|
287
|
-
arr.push(stem);
|
|
288
|
-
return;
|
|
289
|
-
}
|
|
290
|
-
flatEpMappings.push(stem);
|
|
291
|
-
});
|
|
292
|
-
let extensionPoints = [];
|
|
293
|
-
if (flatEpMappings.length !== 0) {
|
|
294
|
-
extensionPoints.push({
|
|
295
|
-
group: undefined,
|
|
296
|
-
mappings: sortedStems(flatEpMappings)
|
|
297
|
-
});
|
|
298
|
-
}
|
|
299
|
-
Object.entries(epByGroup).forEach(param => {
|
|
300
|
-
extensionPoints.push({
|
|
301
|
-
group: param[0],
|
|
302
|
-
mappings: sortedStems(param[1])
|
|
303
|
-
});
|
|
304
|
-
});
|
|
311
|
+
let extensionPoints = groupExtensionPoints(epFiles);
|
|
305
312
|
let buildTargets = (stems, relPaths) => {
|
|
306
313
|
let dict = {};
|
|
307
314
|
stems.forEach(stem => {
|
|
@@ -348,6 +355,7 @@ export {
|
|
|
348
355
|
sortedStems,
|
|
349
356
|
extractTargetName,
|
|
350
357
|
hasAsyncAttribute,
|
|
358
|
+
groupExtensionPoints,
|
|
351
359
|
resolve,
|
|
352
360
|
}
|
|
353
361
|
/* node:fs Not a pure module */
|
|
@@ -2,6 +2,8 @@
|
|
|
2
2
|
// Usage: generate-plugin <srcDir>
|
|
3
3
|
// generate-plugin --aws <Namespace> <srcDir>
|
|
4
4
|
|
|
5
|
+
@val external processExit: int => unit = "process.exit"
|
|
6
|
+
|
|
5
7
|
let () = {
|
|
6
8
|
let argv2 = Generator_Node.argv->Array.get(2)->Option.getOr("")
|
|
7
9
|
let argv3 = Generator_Node.argv->Array.get(3)->Option.getOr("")
|
|
@@ -23,6 +25,9 @@ let () = {
|
|
|
23
25
|
Console.error("Usage: generate-plugin <srcDir>")
|
|
24
26
|
Console.error(" generate-plugin --aws <Namespace> <srcDir>")
|
|
25
27
|
}
|
|
28
|
+
// Exit non-zero on a usage error so `prebuild` (and CI) actually fail
|
|
29
|
+
// instead of continuing green with no Plugin.res generated.
|
|
30
|
+
processExit(1)
|
|
26
31
|
} else {
|
|
27
32
|
// Resolve to absolute path (handles relative paths and trailing slashes)
|
|
28
33
|
let srcDir = Generator_Node.resolve([srcDirArg])
|
|
@@ -39,6 +39,7 @@ if (srcDirArg === "") {
|
|
|
39
39
|
console.error("Usage: generate-plugin <srcDir>");
|
|
40
40
|
console.error(" generate-plugin --aws <Namespace> <srcDir>");
|
|
41
41
|
}
|
|
42
|
+
process.exit(1);
|
|
42
43
|
} else {
|
|
43
44
|
let srcDir = Nodepath.resolve(srcDirArg);
|
|
44
45
|
let init = Config$Reventless.read(srcDir);
|
package/src/types/Behavior.res
CHANGED
|
@@ -72,6 +72,14 @@ module type T = {
|
|
|
72
72
|
*/
|
|
73
73
|
let decide: (state, Spec.command) => result<array<Spec.event>, Spec.error>
|
|
74
74
|
|
|
75
|
+
/** Persisted-snapshot configuration (docs/plans/aggregate-snapshotting.md).
|
|
76
|
+
`None` — the default, auto-injected by `@@reventless.behavior` — keeps
|
|
77
|
+
full replay; `Some({interval, stateSchema})` writes a keep-one snapshot
|
|
78
|
+
every `interval` events and seeds cold replays from the latest one.
|
|
79
|
+
Enable with `@@reventless.snapshots(<interval>)` (requires
|
|
80
|
+
`@schema type state`) or a manual binding. */
|
|
81
|
+
let snapshot: option<Snapshot.config<state>>
|
|
82
|
+
|
|
75
83
|
/** File URL of this module (`import.meta.url`). Used by AWS builders to derive
|
|
76
84
|
the npm specifier for runtime dynamic imports. */
|
|
77
85
|
let moduleUrl: string
|