@reventlessdev/reventless-spec 3.0.0-alpha.63 → 3.0.0-alpha.65
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 +16 -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 +2 -20
- package/src/components/DcbDecode.res.mjs +7 -25
- package/src/components/DcbTag.res +34 -104
- package/src/components/DcbTag.res.mjs +56 -120
- package/src/components/DcbValidation.res +1 -10
- package/src/components/DcbValidation.res.mjs +1 -11
- 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/Codegen.res +10 -0
- package/src/generator/Codegen.res.mjs +2 -1
- 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 +111 -41
- package/src/generator/Pairing.res.mjs +93 -33
- package/src/types/Behavior.res +8 -0
|
@@ -14,6 +14,10 @@ let tagSchema = S.schema(s => ({
|
|
|
14
14
|
value: s.m(S.string)
|
|
15
15
|
}));
|
|
16
16
|
|
|
17
|
+
let partitionTagSchema = S.schema(s => ({
|
|
18
|
+
key: s.m(S.string)
|
|
19
|
+
}));
|
|
20
|
+
|
|
17
21
|
let dcbTagId = S.Metadata.Id.make("dcb", "tag");
|
|
18
22
|
|
|
19
23
|
let dcbPartitionTagId = S.Metadata.Id.make("dcb", "partitionTag");
|
|
@@ -48,6 +52,22 @@ function isCompositePartitionMember(fieldSchema) {
|
|
|
48
52
|
return Stdlib_Option.isSome(S.Metadata.get(fieldSchema, dcbCompositePartitionMemberId));
|
|
49
53
|
}
|
|
50
54
|
|
|
55
|
+
let compositePartitionSpecSchema = S.schema(s => ({
|
|
56
|
+
keys: s.m(S.array(S.string)),
|
|
57
|
+
seps: s.m(S.array(S.string))
|
|
58
|
+
}));
|
|
59
|
+
|
|
60
|
+
let derivedPartitionTagSchema = S.union([
|
|
61
|
+
S.schema(s => ({
|
|
62
|
+
TAG: "Simple",
|
|
63
|
+
_0: s.m(partitionTagSchema)
|
|
64
|
+
})),
|
|
65
|
+
S.schema(s => ({
|
|
66
|
+
TAG: "Composite",
|
|
67
|
+
_0: s.m(compositePartitionSpecSchema)
|
|
68
|
+
}))
|
|
69
|
+
]);
|
|
70
|
+
|
|
51
71
|
function isTagged(fieldSchema) {
|
|
52
72
|
return Stdlib_Option.isSome(S.Metadata.get(fieldSchema, dcbTagId));
|
|
53
73
|
}
|
|
@@ -130,6 +150,19 @@ function extractTagsFromProperties(properties, jsonDict) {
|
|
|
130
150
|
});
|
|
131
151
|
}
|
|
132
152
|
|
|
153
|
+
function variantTagName(items) {
|
|
154
|
+
return Stdlib_Option.flatMap(items.find(item => item.location === "TAG"), item => {
|
|
155
|
+
let match = item.schema;
|
|
156
|
+
if (match.type !== "string") {
|
|
157
|
+
return;
|
|
158
|
+
}
|
|
159
|
+
let $$const = match.const;
|
|
160
|
+
if ($$const !== undefined) {
|
|
161
|
+
return $$const;
|
|
162
|
+
}
|
|
163
|
+
});
|
|
164
|
+
}
|
|
165
|
+
|
|
133
166
|
function extractTagsFromJson(schema, json) {
|
|
134
167
|
switch (schema.type) {
|
|
135
168
|
case "object" :
|
|
@@ -152,22 +185,12 @@ function extractTagsFromJson(schema, json) {
|
|
|
152
185
|
return Stdlib_Array.reduce(schema.anyOf, [], (acc, variantSchema) => {
|
|
153
186
|
if (acc.length !== 0) {
|
|
154
187
|
return acc;
|
|
155
|
-
}
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
let match = item.schema;
|
|
161
|
-
if (match.type !== "string") {
|
|
162
|
-
return;
|
|
188
|
+
} else if (variantSchema.type === "object") {
|
|
189
|
+
if (Primitive_object.equal(variantTagName(variantSchema.items), jsonTag)) {
|
|
190
|
+
return extractTagsFromProperties(variantSchema.properties, jsonDict$1);
|
|
191
|
+
} else {
|
|
192
|
+
return [];
|
|
163
193
|
}
|
|
164
|
-
let $$const = match.const;
|
|
165
|
-
if ($$const !== undefined) {
|
|
166
|
-
return $$const;
|
|
167
|
-
}
|
|
168
|
-
});
|
|
169
|
-
if (Primitive_object.equal(variantTag, jsonTag)) {
|
|
170
|
-
return extractTagsFromProperties(variantSchema.properties, jsonDict$1);
|
|
171
194
|
} else {
|
|
172
195
|
return [];
|
|
173
196
|
}
|
|
@@ -185,29 +208,11 @@ function extractTags(schema, value) {
|
|
|
185
208
|
function extractVariantNames(schema) {
|
|
186
209
|
switch (schema.type) {
|
|
187
210
|
case "object" :
|
|
188
|
-
return Stdlib_Option.
|
|
189
|
-
let match = item.schema;
|
|
190
|
-
if (match.type !== "string") {
|
|
191
|
-
return;
|
|
192
|
-
}
|
|
193
|
-
let $$const = match.const;
|
|
194
|
-
if ($$const !== undefined) {
|
|
195
|
-
return [$$const];
|
|
196
|
-
}
|
|
197
|
-
}), []);
|
|
211
|
+
return Stdlib_Option.mapOr(variantTagName(schema.items), [], t => [t]);
|
|
198
212
|
case "union" :
|
|
199
213
|
return Stdlib_Array.filterMap(schema.anyOf, variantSchema => {
|
|
200
214
|
if (variantSchema.type === "object") {
|
|
201
|
-
return
|
|
202
|
-
let match = item.schema;
|
|
203
|
-
if (match.type !== "string") {
|
|
204
|
-
return;
|
|
205
|
-
}
|
|
206
|
-
let $$const = match.const;
|
|
207
|
-
if ($$const !== undefined) {
|
|
208
|
-
return $$const;
|
|
209
|
-
}
|
|
210
|
-
});
|
|
215
|
+
return variantTagName(variantSchema.items);
|
|
211
216
|
}
|
|
212
217
|
});
|
|
213
218
|
default:
|
|
@@ -225,16 +230,7 @@ function extractAllVariantNames(schema) {
|
|
|
225
230
|
return [];
|
|
226
231
|
}
|
|
227
232
|
case "object" :
|
|
228
|
-
return Stdlib_Option.
|
|
229
|
-
let match = item.schema;
|
|
230
|
-
if (match.type !== "string") {
|
|
231
|
-
return;
|
|
232
|
-
}
|
|
233
|
-
let $$const = match.const;
|
|
234
|
-
if ($$const !== undefined) {
|
|
235
|
-
return [$$const];
|
|
236
|
-
}
|
|
237
|
-
}), []);
|
|
233
|
+
return Stdlib_Option.mapOr(variantTagName(schema.items), [], t => [t]);
|
|
238
234
|
case "union" :
|
|
239
235
|
return Stdlib_Array.filterMap(schema.anyOf, variantSchema => {
|
|
240
236
|
switch (variantSchema.type) {
|
|
@@ -246,16 +242,7 @@ function extractAllVariantNames(schema) {
|
|
|
246
242
|
return;
|
|
247
243
|
}
|
|
248
244
|
case "object" :
|
|
249
|
-
return
|
|
250
|
-
let match = item.schema;
|
|
251
|
-
if (match.type !== "string") {
|
|
252
|
-
return;
|
|
253
|
-
}
|
|
254
|
-
let $$const = match.const;
|
|
255
|
-
if ($$const !== undefined) {
|
|
256
|
-
return $$const;
|
|
257
|
-
}
|
|
258
|
-
});
|
|
245
|
+
return variantTagName(variantSchema.items);
|
|
259
246
|
default:
|
|
260
247
|
return;
|
|
261
248
|
}
|
|
@@ -272,29 +259,11 @@ function isVariantPayloadBearing(schema, name) {
|
|
|
272
259
|
}
|
|
273
260
|
switch (schema.type) {
|
|
274
261
|
case "object" :
|
|
275
|
-
return Stdlib_Option.
|
|
276
|
-
let match = item.schema;
|
|
277
|
-
if (match.type !== "string") {
|
|
278
|
-
return;
|
|
279
|
-
}
|
|
280
|
-
let $$const = match.const;
|
|
281
|
-
if ($$const !== undefined) {
|
|
282
|
-
return $$const === name;
|
|
283
|
-
}
|
|
284
|
-
}), false);
|
|
262
|
+
return Stdlib_Option.mapOr(variantTagName(schema.items), false, t => t === name);
|
|
285
263
|
case "union" :
|
|
286
264
|
return schema.anyOf.some(variantSchema => {
|
|
287
265
|
if (variantSchema.type === "object") {
|
|
288
|
-
return Stdlib_Option.
|
|
289
|
-
let match = item.schema;
|
|
290
|
-
if (match.type !== "string") {
|
|
291
|
-
return;
|
|
292
|
-
}
|
|
293
|
-
let $$const = match.const;
|
|
294
|
-
if ($$const !== undefined) {
|
|
295
|
-
return $$const === name;
|
|
296
|
-
}
|
|
297
|
-
}), false);
|
|
266
|
+
return Stdlib_Option.mapOr(variantTagName(variantSchema.items), false, t => t === name);
|
|
298
267
|
} else {
|
|
299
268
|
return false;
|
|
300
269
|
}
|
|
@@ -359,22 +328,12 @@ function extractTagsFromJsonExpanded(schema, json) {
|
|
|
359
328
|
return Stdlib_Array.reduce(schema.anyOf, [], (acc, variantSchema) => {
|
|
360
329
|
if (acc.length !== 0) {
|
|
361
330
|
return acc;
|
|
362
|
-
}
|
|
363
|
-
|
|
364
|
-
|
|
365
|
-
|
|
366
|
-
|
|
367
|
-
let match = item.schema;
|
|
368
|
-
if (match.type !== "string") {
|
|
369
|
-
return;
|
|
331
|
+
} else if (variantSchema.type === "object") {
|
|
332
|
+
if (Primitive_object.equal(variantTagName(variantSchema.items), jsonTag)) {
|
|
333
|
+
return extractTagsFromPropertiesExpanded(variantSchema.properties, jsonDict$1);
|
|
334
|
+
} else {
|
|
335
|
+
return [];
|
|
370
336
|
}
|
|
371
|
-
let $$const = match.const;
|
|
372
|
-
if ($$const !== undefined) {
|
|
373
|
-
return $$const;
|
|
374
|
-
}
|
|
375
|
-
});
|
|
376
|
-
if (Primitive_object.equal(variantTag, jsonTag)) {
|
|
377
|
-
return extractTagsFromPropertiesExpanded(variantSchema.properties, jsonDict$1);
|
|
378
337
|
} else {
|
|
379
338
|
return [];
|
|
380
339
|
}
|
|
@@ -427,16 +386,7 @@ function extractTagKeysByEventType(schema) {
|
|
|
427
386
|
return;
|
|
428
387
|
}
|
|
429
388
|
let properties = variantSchema.properties;
|
|
430
|
-
Stdlib_Option.forEach(
|
|
431
|
-
let match = item.schema;
|
|
432
|
-
if (match.type !== "string") {
|
|
433
|
-
return;
|
|
434
|
-
}
|
|
435
|
-
let $$const = match.const;
|
|
436
|
-
if ($$const !== undefined) {
|
|
437
|
-
return $$const;
|
|
438
|
-
}
|
|
439
|
-
}), eventType => {
|
|
389
|
+
Stdlib_Option.forEach(variantTagName(variantSchema.items), eventType => {
|
|
440
390
|
result[eventType] = tagKeysOfProperties(properties);
|
|
441
391
|
});
|
|
442
392
|
};
|
|
@@ -608,16 +558,7 @@ function eventShapesOfSchema(schema) {
|
|
|
608
558
|
}
|
|
609
559
|
case "object" :
|
|
610
560
|
let properties = variantSchema.properties;
|
|
611
|
-
return Stdlib_Option.map(
|
|
612
|
-
let match = item.schema;
|
|
613
|
-
if (match.type !== "string") {
|
|
614
|
-
return;
|
|
615
|
-
}
|
|
616
|
-
let $$const = match.const;
|
|
617
|
-
if ($$const !== undefined) {
|
|
618
|
-
return $$const;
|
|
619
|
-
}
|
|
620
|
-
}), eventType => ({
|
|
561
|
+
return Stdlib_Option.map(variantTagName(variantSchema.items), eventType => ({
|
|
621
562
|
eventType: eventType,
|
|
622
563
|
idFields: idFieldsOfProperties(properties)
|
|
623
564
|
}));
|
|
@@ -702,16 +643,7 @@ function findMultiTagVariantNames(schema) {
|
|
|
702
643
|
}
|
|
703
644
|
let tagCount = Object.entries(variantSchema.properties).filter(param => isTagged(param[1])).length;
|
|
704
645
|
if (tagCount > 1) {
|
|
705
|
-
return Stdlib_Option.getOr(
|
|
706
|
-
let match = item.schema;
|
|
707
|
-
if (match.type !== "string") {
|
|
708
|
-
return;
|
|
709
|
-
}
|
|
710
|
-
let $$const = match.const;
|
|
711
|
-
if ($$const !== undefined) {
|
|
712
|
-
return $$const;
|
|
713
|
-
}
|
|
714
|
-
}), "(unknown)");
|
|
646
|
+
return Stdlib_Option.getOr(variantTagName(variantSchema.items), "(unknown)");
|
|
715
647
|
}
|
|
716
648
|
};
|
|
717
649
|
if (schema.type === "union") {
|
|
@@ -888,6 +820,7 @@ function getPartitionTagValue(query, pt) {
|
|
|
888
820
|
|
|
889
821
|
export {
|
|
890
822
|
tagSchema,
|
|
823
|
+
partitionTagSchema,
|
|
891
824
|
dcbTagId,
|
|
892
825
|
dcbPartitionTagId,
|
|
893
826
|
dcbCrossPartitionId,
|
|
@@ -900,6 +833,8 @@ export {
|
|
|
900
833
|
crossPartition,
|
|
901
834
|
compositePartitionMember,
|
|
902
835
|
isCompositePartitionMember,
|
|
836
|
+
compositePartitionSpecSchema,
|
|
837
|
+
derivedPartitionTagSchema,
|
|
903
838
|
isTagged,
|
|
904
839
|
isTaggedArray,
|
|
905
840
|
isPartitionTag,
|
|
@@ -909,6 +844,7 @@ export {
|
|
|
909
844
|
resolveArrayTagKey,
|
|
910
845
|
jsonValueToString,
|
|
911
846
|
extractTagsFromProperties,
|
|
847
|
+
variantTagName,
|
|
912
848
|
extractTagsFromJson,
|
|
913
849
|
extractTags,
|
|
914
850
|
extractVariantNames,
|
|
@@ -13,16 +13,7 @@ type variantInfo = {
|
|
|
13
13
|
let extractVariantInfo = (variantSchema: S.t<unknown>): option<variantInfo> =>
|
|
14
14
|
switch variantSchema {
|
|
15
15
|
| Object({items, properties}) =>
|
|
16
|
-
|
|
17
|
-
items
|
|
18
|
-
->Array.find(item => item.location == "TAG")
|
|
19
|
-
->Option.flatMap(item =>
|
|
20
|
-
switch item.schema {
|
|
21
|
-
| String({const}) => Some(const)
|
|
22
|
-
| _ => None
|
|
23
|
-
}
|
|
24
|
-
)
|
|
25
|
-
tagName->Option.map(tagName => {
|
|
16
|
+
DcbTag.variantTagName(items)->Option.map(tagName => {
|
|
26
17
|
let taggedFields =
|
|
27
18
|
properties
|
|
28
19
|
->Dict.toArray
|
|
@@ -11,17 +11,7 @@ function extractVariantInfo(variantSchema) {
|
|
|
11
11
|
return;
|
|
12
12
|
}
|
|
13
13
|
let properties = variantSchema.properties;
|
|
14
|
-
|
|
15
|
-
let match = item.schema;
|
|
16
|
-
if (match.type !== "string") {
|
|
17
|
-
return;
|
|
18
|
-
}
|
|
19
|
-
let $$const = match.const;
|
|
20
|
-
if ($$const !== undefined) {
|
|
21
|
-
return $$const;
|
|
22
|
-
}
|
|
23
|
-
});
|
|
24
|
-
return Stdlib_Option.map(tagName, tagName => {
|
|
14
|
+
return Stdlib_Option.map(DcbTag$Reventless.variantTagName(variantSchema.items), tagName => {
|
|
25
15
|
let taggedFields = Stdlib_Array.filterMap(Object.entries(properties), param => {
|
|
26
16
|
if (DcbTag$Reventless.isTagged(param[1])) {
|
|
27
17
|
return param[0];
|
|
@@ -0,0 +1,39 @@
|
|
|
1
|
+
// Single source of truth for deriving a plugin's PascalCase name from its npm
|
|
2
|
+
// package name, and for resolving the final plugin name from the (optional)
|
|
3
|
+
// plugin.json `name` and package.json `name`. The plugin generator
|
|
4
|
+
// (`generator/Config`) and the external tooling that reconstructs the domain
|
|
5
|
+
// graph (`reventless-gwt`'s `LocalHost`) both derive from this, so the two can't
|
|
6
|
+
// drift — a drift here silently breaks graph plugin keys (the graph would key
|
|
7
|
+
// plugins under names that don't match the ones the generator bakes into
|
|
8
|
+
// `Plugin.res`). See [[reference_ppx_spec_name_single_strip]] for the sibling
|
|
9
|
+
// spec-name derivation.
|
|
10
|
+
|
|
11
|
+
// "@scope/my-catalog" → "MyCatalog", "online-shop" → "OnlineShop".
|
|
12
|
+
let fromPackageName = (packageName: string): string => {
|
|
13
|
+
let base = switch packageName->String.split("/") {
|
|
14
|
+
| [_scope, local] => local
|
|
15
|
+
| [local] => local
|
|
16
|
+
| parts => parts->Array.getUnsafe(parts->Array.length - 1)
|
|
17
|
+
}
|
|
18
|
+
base
|
|
19
|
+
->String.split("-")
|
|
20
|
+
->Array.flatMap(part => part->String.split("_"))
|
|
21
|
+
->Array.map(word =>
|
|
22
|
+
if word === "" {
|
|
23
|
+
""
|
|
24
|
+
} else {
|
|
25
|
+
word->String.slice(~start=0, ~end=1)->String.toUpperCase ++
|
|
26
|
+
word->String.slice(~start=1, ~end=word->String.length)
|
|
27
|
+
}
|
|
28
|
+
)
|
|
29
|
+
->Array.join("")
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
// plugin.json `name` wins; else PascalCase(package.json `name`); else "Plugin".
|
|
33
|
+
// The two callers each read the raw fields with their own node bindings, then
|
|
34
|
+
// share this precedence so the resolution can never diverge.
|
|
35
|
+
let resolve = (~pluginJsonName: option<string>, ~packageJsonName: option<string>): string =>
|
|
36
|
+
switch pluginJsonName {
|
|
37
|
+
| Some(name) => name
|
|
38
|
+
| None => packageJsonName->Option.map(fromPackageName)->Option.getOr("Plugin")
|
|
39
|
+
}
|
|
@@ -0,0 +1,45 @@
|
|
|
1
|
+
// Generated by ReScript, PLEASE EDIT WITH CARE
|
|
2
|
+
|
|
3
|
+
import * as Stdlib_Option from "@rescript/runtime/lib/es6/Stdlib_Option.js";
|
|
4
|
+
|
|
5
|
+
function fromPackageName(packageName) {
|
|
6
|
+
let parts = packageName.split("/");
|
|
7
|
+
let len = parts.length;
|
|
8
|
+
let base;
|
|
9
|
+
if (len >= 3) {
|
|
10
|
+
base = parts[parts.length - 1 | 0];
|
|
11
|
+
} else {
|
|
12
|
+
switch (len) {
|
|
13
|
+
case 0 :
|
|
14
|
+
base = parts[parts.length - 1 | 0];
|
|
15
|
+
break;
|
|
16
|
+
case 1 :
|
|
17
|
+
base = parts[0];
|
|
18
|
+
break;
|
|
19
|
+
case 2 :
|
|
20
|
+
base = parts[1];
|
|
21
|
+
break;
|
|
22
|
+
}
|
|
23
|
+
}
|
|
24
|
+
return base.split("-").flatMap(part => part.split("_")).map(word => {
|
|
25
|
+
if (word === "") {
|
|
26
|
+
return "";
|
|
27
|
+
} else {
|
|
28
|
+
return word.slice(0, 1).toUpperCase() + word.slice(1, word.length);
|
|
29
|
+
}
|
|
30
|
+
}).join("");
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
function resolve(pluginJsonName, packageJsonName) {
|
|
34
|
+
if (pluginJsonName !== undefined) {
|
|
35
|
+
return pluginJsonName;
|
|
36
|
+
} else {
|
|
37
|
+
return Stdlib_Option.getOr(Stdlib_Option.map(packageJsonName, fromPackageName), "Plugin");
|
|
38
|
+
}
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
export {
|
|
42
|
+
fromPackageName,
|
|
43
|
+
resolve,
|
|
44
|
+
}
|
|
45
|
+
/* No side effect */
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
// Per-aggregate persisted-snapshot configuration
|
|
2
|
+
// (docs/plans/aggregate-snapshotting.md).
|
|
3
|
+
//
|
|
4
|
+
// Snapshotting is opt-in and lives on the Behavior module (where `state` is
|
|
5
|
+
// defined): `Behavior.T.snapshot = None` (the default, auto-injected by
|
|
6
|
+
// `@@reventless.behavior`) keeps full replay; `Some(config)` makes the
|
|
7
|
+
// aggregate write a keep-one snapshot every `interval` events and seed cold
|
|
8
|
+
// replays from the latest one. Snapshots are a read optimization only — the
|
|
9
|
+
// OCC append remains the sole consistency primitive, and a missing, corrupt,
|
|
10
|
+
// or schema-drifted snapshot degrades to full replay.
|
|
11
|
+
//
|
|
12
|
+
// Enable via the file-level attribute on a behavior file:
|
|
13
|
+
//
|
|
14
|
+
// @@reventless.snapshots(100)
|
|
15
|
+
//
|
|
16
|
+
// which injects `let snapshot = Some({interval: 100, stateSchema})` (requires
|
|
17
|
+
// `@schema type state` so sury generates the schema), or hand-write the
|
|
18
|
+
// binding for full control.
|
|
19
|
+
|
|
20
|
+
type config<'state> = {
|
|
21
|
+
/** Write a snapshot after every N appended events. Required — no default. */
|
|
22
|
+
interval: int,
|
|
23
|
+
/** Sury schema for the behavior's state — serializes the persisted snapshot
|
|
24
|
+
and (hashed) gates staleness across state-shape changes. */
|
|
25
|
+
stateSchema: S.t<'state>,
|
|
26
|
+
}
|
|
@@ -672,6 +672,16 @@ let renderComposition = (~config: Config.config, ~resolved: Pairing.resolved): s
|
|
|
672
672
|
~moduleSuffix="Slice",
|
|
673
673
|
),
|
|
674
674
|
hasPluginStructure ? Some(" ~pluginStructure=pluginStructure,") : None,
|
|
675
|
+
// Components carrying `@@reventless.systemCallable` — only emitted when at
|
|
676
|
+
// least one opts in, so existing generated Plugin.res files stay identical.
|
|
677
|
+
resolved.systemCallableComponents->Array.length > 0
|
|
678
|
+
? Some(
|
|
679
|
+
" ~systemCallableComponents=[" ++
|
|
680
|
+
resolved.systemCallableComponents
|
|
681
|
+
->Array.map(n => "\"" ++ n ++ "\"")
|
|
682
|
+
->Array.join(", ") ++ "],",
|
|
683
|
+
)
|
|
684
|
+
: None,
|
|
675
685
|
]
|
|
676
686
|
|
|
677
687
|
makeParams->Array.filterMap(x => x)->Array.forEach(line => lines->Array.push(line))
|
|
@@ -428,7 +428,8 @@ function renderComposition(config, resolved) {
|
|
|
428
428
|
renderMakeParam("automationSlices", resolved.automationSlices, "Slice"),
|
|
429
429
|
renderMakeParam("outboundTranslationSlices", resolved.outboundTranslationSlices, "Slice"),
|
|
430
430
|
renderMakeParam("inboundTranslationSlices", resolved.inboundTranslationSlices, "Slice"),
|
|
431
|
-
hasPluginStructure ? " ~pluginStructure=pluginStructure," : undefined
|
|
431
|
+
hasPluginStructure ? " ~pluginStructure=pluginStructure," : undefined,
|
|
432
|
+
resolved.systemCallableComponents.length !== 0 ? " ~systemCallableComponents=[" + resolved.systemCallableComponents.map(n => "\"" + n + "\"").join(", ") + "]," : undefined
|
|
432
433
|
];
|
|
433
434
|
Stdlib_Array.filterMap(makeParams, x => x).forEach(line => {
|
|
434
435
|
lines.push(line);
|
package/src/generator/Config.res
CHANGED
|
@@ -12,25 +12,9 @@ type config = {
|
|
|
12
12
|
|
|
13
13
|
// Convert npm package name to PascalCase plugin name.
|
|
14
14
|
// "@scope/my-catalog" → "MyCatalog", "online-shop" → "OnlineShop"
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
| [local] => local
|
|
19
|
-
| parts => parts->Array.getUnsafe(parts->Array.length - 1)
|
|
20
|
-
}
|
|
21
|
-
base
|
|
22
|
-
->String.split("-")
|
|
23
|
-
->Array.flatMap(part => part->String.split("_"))
|
|
24
|
-
->Array.map(word =>
|
|
25
|
-
if word === "" {
|
|
26
|
-
""
|
|
27
|
-
} else {
|
|
28
|
-
word->String.slice(~start=0, ~end=1)->String.toUpperCase ++
|
|
29
|
-
word->String.slice(~start=1, ~end=word->String.length)
|
|
30
|
-
}
|
|
31
|
-
)
|
|
32
|
-
->Array.join("")
|
|
33
|
-
}
|
|
15
|
+
// Single-sourced with reventless-gwt's LocalHost via `PluginName` so the two
|
|
16
|
+
// can't drift (a drift silently breaks graph plugin keys).
|
|
17
|
+
let packageNameToPluginName = PluginName.fromPackageName
|
|
34
18
|
|
|
35
19
|
let readJson = (path: string): option<JSON.t> =>
|
|
36
20
|
try Some(Generator_Node.readFileSync(path)->JSON.parseOrThrow) catch {
|
|
@@ -58,13 +42,9 @@ let getStrArrayField = (json: JSON.t, key: string): option<array<string>> =>
|
|
|
58
42
|
->Option.map(arr => arr->Array.filterMap(JSON.Decode.string))
|
|
59
43
|
|
|
60
44
|
let read = (~srcDir: string): config => {
|
|
61
|
-
//
|
|
45
|
+
// Read package.json `name` from the parent of srcDir
|
|
62
46
|
let packageJsonPath = Generator_Node.join([Generator_Node.dirname(srcDir), "package.json"])
|
|
63
|
-
let
|
|
64
|
-
readJson(packageJsonPath)
|
|
65
|
-
->Option.flatMap(j => getStrField(j, "name"))
|
|
66
|
-
->Option.map(packageNameToPluginName)
|
|
67
|
-
->Option.getOr("Plugin")
|
|
47
|
+
let packageJsonName = readJson(packageJsonPath)->Option.flatMap(j => getStrField(j, "name"))
|
|
68
48
|
|
|
69
49
|
// Read plugin.json from srcDir (optional)
|
|
70
50
|
let pluginJsonPath = Generator_Node.join([srcDir, "plugin.json"])
|
|
@@ -75,7 +55,10 @@ let read = (~srcDir: string): config => {
|
|
|
75
55
|
}
|
|
76
56
|
|
|
77
57
|
{
|
|
78
|
-
name:
|
|
58
|
+
name: PluginName.resolve(
|
|
59
|
+
~pluginJsonName=pluginJson->Option.flatMap(j => getStrField(j, "name")),
|
|
60
|
+
~packageJsonName,
|
|
61
|
+
),
|
|
79
62
|
heartbeatInterval: pluginJson
|
|
80
63
|
->Option.flatMap(j => getIntField(j, "heartbeatInterval"))
|
|
81
64
|
->Option.getOr(5),
|
|
@@ -5,34 +5,7 @@ import * as Nodepath from "node:path";
|
|
|
5
5
|
import * as Stdlib_JSON from "@rescript/runtime/lib/es6/Stdlib_JSON.js";
|
|
6
6
|
import * as Stdlib_Array from "@rescript/runtime/lib/es6/Stdlib_Array.js";
|
|
7
7
|
import * as Stdlib_Option from "@rescript/runtime/lib/es6/Stdlib_Option.js";
|
|
8
|
-
|
|
9
|
-
function packageNameToPluginName(packageName) {
|
|
10
|
-
let parts = packageName.split("/");
|
|
11
|
-
let len = parts.length;
|
|
12
|
-
let base;
|
|
13
|
-
if (len >= 3) {
|
|
14
|
-
base = parts[parts.length - 1 | 0];
|
|
15
|
-
} else {
|
|
16
|
-
switch (len) {
|
|
17
|
-
case 0 :
|
|
18
|
-
base = parts[parts.length - 1 | 0];
|
|
19
|
-
break;
|
|
20
|
-
case 1 :
|
|
21
|
-
base = parts[0];
|
|
22
|
-
break;
|
|
23
|
-
case 2 :
|
|
24
|
-
base = parts[1];
|
|
25
|
-
break;
|
|
26
|
-
}
|
|
27
|
-
}
|
|
28
|
-
return base.split("-").flatMap(part => part.split("_")).map(word => {
|
|
29
|
-
if (word === "") {
|
|
30
|
-
return "";
|
|
31
|
-
} else {
|
|
32
|
-
return word.slice(0, 1).toUpperCase() + word.slice(1, word.length);
|
|
33
|
-
}
|
|
34
|
-
}).join("");
|
|
35
|
-
}
|
|
8
|
+
import * as PluginName$Reventless from "../components/PluginName.res.mjs";
|
|
36
9
|
|
|
37
10
|
function readJson(path) {
|
|
38
11
|
try {
|
|
@@ -56,17 +29,19 @@ function getStrArrayField(json, key) {
|
|
|
56
29
|
|
|
57
30
|
function read(srcDir) {
|
|
58
31
|
let packageJsonPath = Nodepath.join(Nodepath.dirname(srcDir), "package.json");
|
|
59
|
-
let
|
|
32
|
+
let packageJsonName = Stdlib_Option.flatMap(readJson(packageJsonPath), j => getStrField(j, "name"));
|
|
60
33
|
let pluginJsonPath = Nodepath.join(srcDir, "plugin.json");
|
|
61
34
|
let pluginJson = Nodefs.existsSync(pluginJsonPath) ? readJson(pluginJsonPath) : undefined;
|
|
62
35
|
return {
|
|
63
|
-
name:
|
|
36
|
+
name: PluginName$Reventless.resolve(Stdlib_Option.flatMap(pluginJson, j => getStrField(j, "name")), packageJsonName),
|
|
64
37
|
heartbeatInterval: Stdlib_Option.getOr(Stdlib_Option.flatMap(pluginJson, j => getIntField(j, "heartbeatInterval")), 5),
|
|
65
38
|
exclude: Stdlib_Option.getOr(Stdlib_Option.flatMap(pluginJson, j => getStrArrayField(j, "exclude")), []),
|
|
66
39
|
variant: "Composition"
|
|
67
40
|
};
|
|
68
41
|
}
|
|
69
42
|
|
|
43
|
+
let packageNameToPluginName = PluginName$Reventless.fromPackageName;
|
|
44
|
+
|
|
70
45
|
export {
|
|
71
46
|
packageNameToPluginName,
|
|
72
47
|
readJson,
|
|
@@ -1,6 +1,9 @@
|
|
|
1
1
|
// Directory scanner: walks src/, classifies .res files by parent folder name.
|
|
2
2
|
|
|
3
|
-
|
|
3
|
+
// Re-export the single-source `ComponentKind.t` (same constructors, so the bare
|
|
4
|
+
// pattern matches in `Pairing` keep resolving via type inference) and derive the
|
|
5
|
+
// folder classifier from it — one vocabulary shared with the gwt discovery.
|
|
6
|
+
type componentType = ComponentKind.t =
|
|
4
7
|
| StateChangeSlice
|
|
5
8
|
| StateViewSlice
|
|
6
9
|
| StateViewSliceStream
|
|
@@ -17,31 +20,7 @@ type componentType =
|
|
|
17
20
|
// relPath: path relative to srcDir (e.g. "ReadModel/ProductsProjections.res")
|
|
18
21
|
type discoveredFile = {stem: string, componentType: componentType, epGroup: option<string>, relPath: string}
|
|
19
22
|
|
|
20
|
-
let folderToComponentType =
|
|
21
|
-
switch folder {
|
|
22
|
-
| "StateChange" | "StateChanges" | "StateChangeSlice" | "StateChangeSlices" =>
|
|
23
|
-
Some(StateChangeSlice)
|
|
24
|
-
| "StateView" | "StateViews" | "StateViewSlice" | "StateViewSlices" => Some(StateViewSlice)
|
|
25
|
-
| "StateViewSliceStream" | "StateViewSliceStreams" => Some(StateViewSliceStream)
|
|
26
|
-
| "Automation" | "Automations" | "AutomationSlice" | "AutomationSlices" => Some(AutomationSlice)
|
|
27
|
-
| "InboundTranslation"
|
|
28
|
-
| "InboundTranslations"
|
|
29
|
-
| "InboundTranslationSlice"
|
|
30
|
-
| "InboundTranslationSlices" =>
|
|
31
|
-
Some(InboundTranslationSlice)
|
|
32
|
-
| "OutboundTranslation"
|
|
33
|
-
| "OutboundTranslations"
|
|
34
|
-
| "OutboundTranslationSlice"
|
|
35
|
-
| "OutboundTranslationSlices" =>
|
|
36
|
-
Some(OutboundTranslationSlice)
|
|
37
|
-
| "Aggregate" | "Aggregates" => Some(Aggregate)
|
|
38
|
-
| "ReadModel" | "ReadModels" => Some(ReadModel)
|
|
39
|
-
| "ReadModelStream" | "ReadModelStreams" => Some(ReadModelStream)
|
|
40
|
-
| "Task" | "Tasks" => Some(Task)
|
|
41
|
-
| "ExtensionPoint" | "ExtensionPoints" => Some(ExtensionPoint)
|
|
42
|
-
| "Extension" | "Extensions" => Some(Extension)
|
|
43
|
-
| _ => None
|
|
44
|
-
}
|
|
23
|
+
let folderToComponentType = ComponentKind.folderToKind
|
|
45
24
|
|
|
46
25
|
let isAlwaysExcludedDir = (name: string): bool =>
|
|
47
26
|
name === "Plugin" || name === "tests" || name === "lib"
|