@reventlessdev/reventless-spec 3.0.0-alpha.129 → 3.0.0-alpha.131
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 +23 -0
- package/package.json +3 -2
- package/run-check-lifecycle.mjs +2 -0
- package/schema/platform-api.graphql +1 -0
- package/src/components/DcbTag.res +229 -32
- package/src/components/DcbTag.res.mjs +232 -41
- package/src/components/Plugin.res +47 -4
- package/src/components/Plugin.res.mjs +1 -0
- package/src/components/Reference.res +48 -0
- package/src/components/Reference.res.mjs +28 -0
- package/src/generator/Codegen.res +14 -1
- package/src/generator/Codegen.res.mjs +9 -5
- package/src/generator/PluginGenerator.res +4 -1
- package/src/generator/PluginGenerator.res.mjs +2 -1
- package/src/lifecycle/CheckLifecycleModel.res +1337 -0
- package/src/lifecycle/CheckLifecycleModel.res.mjs +1107 -0
- package/src/lifecycle/loadPluginStructure.mjs +66 -0
- package/src/types/Transition.res +30 -3
- package/src/types/Transition.res.mjs +13 -4
package/CHANGELOG.md
CHANGED
|
@@ -3,6 +3,29 @@
|
|
|
3
3
|
All notable changes to this project will be documented in this file.
|
|
4
4
|
See [Conventional Commits](https://conventionalcommits.org) for commit guidelines.
|
|
5
5
|
|
|
6
|
+
# 3.0.0-alpha.131 (2026-09-07)
|
|
7
|
+
|
|
8
|
+
### Features
|
|
9
|
+
|
|
10
|
+
* **spec:** the lifecycle check reports as fields, and runs against any app ([c4cf78b](https://github.com/ReventlessDev/reventless-core/commit/c4cf78bff24384d876755c8e6677c1d2865014b0))
|
|
11
|
+
|
|
12
|
+
|
|
13
|
+
# 3.0.0-alpha.130 (2026-09-07)
|
|
14
|
+
|
|
15
|
+
* feat(dcb)!: a record inside an array is still a reference and a key ([bcb9b13](https://github.com/ReventlessDev/reventless-core/commit/bcb9b13958323d8319d7fcf25c055800e84150f3))
|
|
16
|
+
### Features
|
|
17
|
+
|
|
18
|
+
* **core:** a command's lifecycle edge comes from its scenarios, not its claim ([1879d05](https://github.com/ReventlessDev/reventless-core/commit/1879d0570a981e7fae5bcd3808f8a36e898bd0fd))
|
|
19
|
+
|
|
20
|
+
### BREAKING CHANGES
|
|
21
|
+
|
|
22
|
+
* an `int` field is now `Int` in the generated SDL and
|
|
23
|
+
`"integer"` in JSON Schema, where it was `Float`/`"number"`. A client
|
|
24
|
+
declaring `$retryCount: Float!` against one of these fields must move to
|
|
25
|
+
`Int!`.
|
|
26
|
+
|
|
27
|
+
|
|
28
|
+
|
|
6
29
|
# 3.0.0-alpha.129 (2026-09-04)
|
|
7
30
|
|
|
8
31
|
### Bug Fixes
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@reventlessdev/reventless-spec",
|
|
3
|
-
"version": "3.0.0-alpha.
|
|
3
|
+
"version": "3.0.0-alpha.131",
|
|
4
4
|
"description": "Specifications for Reventless",
|
|
5
5
|
"license": "Apache-2.0",
|
|
6
6
|
"bin": {
|
|
@@ -8,7 +8,8 @@
|
|
|
8
8
|
"generate-platform": "./run-platform-generator.mjs",
|
|
9
9
|
"graft-trait": "./run-graft-trait.mjs",
|
|
10
10
|
"certify-trait": "./run-certify-trait.mjs",
|
|
11
|
-
"trait-manifest": "./run-trait-manifest.mjs"
|
|
11
|
+
"trait-manifest": "./run-trait-manifest.mjs",
|
|
12
|
+
"check-lifecycle": "./run-check-lifecycle.mjs"
|
|
12
13
|
},
|
|
13
14
|
"jest": {
|
|
14
15
|
"testMatch": [
|
|
@@ -273,6 +273,56 @@ let isTaggedArray = (fieldSchema: S.t<unknown>) =>
|
|
|
273
273
|
| _ => false
|
|
274
274
|
}
|
|
275
275
|
|
|
276
|
+
/**
|
|
277
|
+
The properties of the record a field's value holds, when it holds records rather
|
|
278
|
+
than scalars — `record`, `option<record>`, `array<record>`, `option<array<record>>`
|
|
279
|
+
— with `true` for the array forms, which fan out into one contribution per element.
|
|
280
|
+
|
|
281
|
+
This is the single wrapper walk the nested-marker walks share, so a marker means
|
|
282
|
+
the same thing whichever of them finds it. It follows exactly the wrappers a
|
|
283
|
+
field's own value can wear and stops at the first record: a marker two records
|
|
284
|
+
deep is a shape no domain here has, and reaching it is a different and much more
|
|
285
|
+
expensive walk than this one.
|
|
286
|
+
*/
|
|
287
|
+
let nestedRecordProperties = (fieldSchema: S.t<unknown>): option<(dict<S.t<unknown>>, bool)> => {
|
|
288
|
+
let unwrapped = fieldSchema->Semantic.unwrapOptional->Option.getOr(fieldSchema)
|
|
289
|
+
let (candidate, isList) = switch unwrapped {
|
|
290
|
+
| Array({additionalItems: Schema(item)}) => (
|
|
291
|
+
item->Semantic.unwrapOptional->Option.getOr(item),
|
|
292
|
+
true,
|
|
293
|
+
)
|
|
294
|
+
| other => (other, false)
|
|
295
|
+
}
|
|
296
|
+
switch candidate {
|
|
297
|
+
| Object({properties}) => Some((properties, isList))
|
|
298
|
+
| _ => None
|
|
299
|
+
}
|
|
300
|
+
}
|
|
301
|
+
|
|
302
|
+
/** Returns `true` if a record's own properties carry at least one DCB tag. */
|
|
303
|
+
let propertiesCarryTags = (properties: dict<S.t<unknown>>): bool =>
|
|
304
|
+
properties->Dict.toArray->Array.some(((_, s)) => isTagged(s) || isTaggedArray(s))
|
|
305
|
+
|
|
306
|
+
/**
|
|
307
|
+
Returns `true` if the schema is an array of records at least one of whose fields
|
|
308
|
+
is DCB-tagged — `array<lineItem>` where `lineItem` carries a `@ref` or a `*Id`.
|
|
309
|
+
|
|
310
|
+
Distinguished from [`hasNestedTags`] because an array is the case that *fans out*:
|
|
311
|
+
it decides the query mode, exactly as a tagged scalar array does.
|
|
312
|
+
*/
|
|
313
|
+
let isTaggedRecordArray = (fieldSchema: S.t<unknown>): bool =>
|
|
314
|
+
switch nestedRecordProperties(fieldSchema) {
|
|
315
|
+
| Some((properties, true)) => propertiesCarryTags(properties)
|
|
316
|
+
| _ => false
|
|
317
|
+
}
|
|
318
|
+
|
|
319
|
+
/** Returns `true` if the schema holds a record — in an array or not — carrying tags. */
|
|
320
|
+
let hasNestedTags = (fieldSchema: S.t<unknown>): bool =>
|
|
321
|
+
switch nestedRecordProperties(fieldSchema) {
|
|
322
|
+
| Some((properties, _)) => propertiesCarryTags(properties)
|
|
323
|
+
| None => false
|
|
324
|
+
}
|
|
325
|
+
|
|
276
326
|
/** Returns `true` if the schema was annotated with `DcbTag.partition`. */
|
|
277
327
|
let isPartitionTag = (fieldSchema: S.t<unknown>) =>
|
|
278
328
|
S.Metadata.get(fieldSchema, ~id=dcbPartitionTagId)->Option.isSome
|
|
@@ -318,25 +368,127 @@ let jsonValueToString = json =>
|
|
|
318
368
|
| _ => json->JSON.stringify
|
|
319
369
|
}
|
|
320
370
|
|
|
371
|
+
/**
|
|
372
|
+
Collapses repeated `(key, value)` pairs, keeping the first of each.
|
|
373
|
+
|
|
374
|
+
Two order lines for the same product carry the same tag twice. A flat field could
|
|
375
|
+
never produce that, which is why nothing downstream guards against it: a repeated
|
|
376
|
+
clause in a decision query and a repeated entry in a write index are both created
|
|
377
|
+
here, so both are collapsed here. The key is JSON-quoted before the value is
|
|
378
|
+
appended, so the boundary between the two is unambiguous.
|
|
379
|
+
*/
|
|
380
|
+
let dedupeTags = (tags: array<tag>): array<tag> => {
|
|
381
|
+
let seen = Set.make()
|
|
382
|
+
tags->Array.filter(({key, value}) => {
|
|
383
|
+
let identity = key->JSON.Encode.string->JSON.stringify ++ value
|
|
384
|
+
if seen->Set.has(identity) {
|
|
385
|
+
false
|
|
386
|
+
} else {
|
|
387
|
+
seen->Set.add(identity)
|
|
388
|
+
true
|
|
389
|
+
}
|
|
390
|
+
})
|
|
391
|
+
}
|
|
392
|
+
|
|
393
|
+
/**
|
|
394
|
+
The tags one object's *own* properties carry: every scalar tagged field, and one
|
|
395
|
+
tag per element of every tagged scalar array.
|
|
396
|
+
|
|
397
|
+
Shared by the top-level expanded walk and by the nested-record descent below, so
|
|
398
|
+
a marker means the same thing at either depth.
|
|
399
|
+
*/
|
|
400
|
+
let flatFieldTagsExpanded = (
|
|
401
|
+
fieldName: string,
|
|
402
|
+
fieldSchema: S.t<unknown>,
|
|
403
|
+
jsonDict: dict<JSON.t>,
|
|
404
|
+
): array<tag> =>
|
|
405
|
+
if isTagged(fieldSchema) {
|
|
406
|
+
switch jsonDict->Dict.get(fieldName) {
|
|
407
|
+
| Some(jsonValue) => [
|
|
408
|
+
{key: resolveTagKey(fieldName, fieldSchema), value: jsonValue->jsonValueToString},
|
|
409
|
+
]
|
|
410
|
+
| None => []
|
|
411
|
+
}
|
|
412
|
+
} else if isTaggedArray(fieldSchema) {
|
|
413
|
+
switch jsonDict->Dict.get(fieldName) {
|
|
414
|
+
| Some(JSON.Array(elements)) =>
|
|
415
|
+
let tagKey = resolveArrayTagKey(fieldName, fieldSchema)
|
|
416
|
+
elements->Array.map(element => {key: tagKey, value: element->jsonValueToString})
|
|
417
|
+
| _ => []
|
|
418
|
+
}
|
|
419
|
+
} else {
|
|
420
|
+
[]
|
|
421
|
+
}
|
|
422
|
+
|
|
423
|
+
let flatTagsExpanded = (properties: dict<S.t<unknown>>, jsonDict: dict<JSON.t>): array<tag> =>
|
|
424
|
+
properties
|
|
425
|
+
->Dict.toArray
|
|
426
|
+
->Array.flatMap(((fieldName, fieldSchema)) =>
|
|
427
|
+
flatFieldTagsExpanded(fieldName, fieldSchema, jsonDict)
|
|
428
|
+
)
|
|
429
|
+
|
|
430
|
+
/**
|
|
431
|
+
The tags carried by the records a field holds — one contribution per element for
|
|
432
|
+
an array, one for a plain nested record.
|
|
433
|
+
|
|
434
|
+
**The key comes from the nested field's name, never the enclosing one.**
|
|
435
|
+
`lineItems[].productId` produces `productId`, which is what makes it the *same*
|
|
436
|
+
tag the catalog's own events write. A key derived from `lineItems` would name a
|
|
437
|
+
tag no producer has ever written, and the decision read would come back empty —
|
|
438
|
+
the identical symptom to extracting no tags at all, from a different cause. An
|
|
439
|
+
author who wants another key still writes `DcbTag.stringForKey` on the nested
|
|
440
|
+
field, which `resolveTagKey` honours here as it does at the top level.
|
|
441
|
+
*/
|
|
442
|
+
let nestedRecordTags = (fieldSchema: S.t<unknown>, jsonValue: JSON.t): array<tag> =>
|
|
443
|
+
switch nestedRecordProperties(fieldSchema) {
|
|
444
|
+
| None => []
|
|
445
|
+
| Some((properties, isList)) =>
|
|
446
|
+
let ofObject = json =>
|
|
447
|
+
switch json->JSON.Decode.object {
|
|
448
|
+
| Some(elementDict) => flatTagsExpanded(properties, elementDict)
|
|
449
|
+
| None => []
|
|
450
|
+
}
|
|
451
|
+
if isList {
|
|
452
|
+
switch jsonValue {
|
|
453
|
+
| JSON.Array(elements) => elements->Array.flatMap(ofObject)
|
|
454
|
+
| _ => []
|
|
455
|
+
}
|
|
456
|
+
} else {
|
|
457
|
+
ofObject(jsonValue)
|
|
458
|
+
}
|
|
459
|
+
}
|
|
460
|
+
|
|
321
461
|
/**
|
|
322
462
|
Extracts tags from a flat JSON object given a map of field schemas.
|
|
323
463
|
Only fields whose schema is tagged (via `DcbTag.string` / `DcbTag.int`) are extracted.
|
|
464
|
+
|
|
465
|
+
A field holding *records* is descended into, and this is the one case where this
|
|
466
|
+
walk and [`extractTagsFromPropertiesExpanded`] agree: they differ on a scalar
|
|
467
|
+
array (one stringified tag here, one tag per element there) because a stringified
|
|
468
|
+
array is at least a value, whereas a stringified line-item list is nothing any
|
|
469
|
+
producer could match. A reader must not generalise the difference.
|
|
324
470
|
*/
|
|
325
471
|
let extractTagsFromProperties = (properties: dict<S.t<unknown>>, jsonDict: dict<JSON.t>) =>
|
|
326
472
|
properties
|
|
327
473
|
->Dict.toArray
|
|
328
|
-
->Array.
|
|
474
|
+
->Array.flatMap(((fieldName, fieldSchema)) =>
|
|
329
475
|
if isTagged(fieldSchema) {
|
|
330
|
-
jsonDict
|
|
331
|
-
|
|
332
|
-
|
|
333
|
-
|
|
334
|
-
|
|
335
|
-
}
|
|
476
|
+
switch jsonDict->Dict.get(fieldName) {
|
|
477
|
+
| Some(jsonValue) => [
|
|
478
|
+
{key: resolveTagKey(fieldName, fieldSchema), value: jsonValue->jsonValueToString},
|
|
479
|
+
]
|
|
480
|
+
| None => []
|
|
481
|
+
}
|
|
482
|
+
} else if hasNestedTags(fieldSchema) {
|
|
483
|
+
switch jsonDict->Dict.get(fieldName) {
|
|
484
|
+
| Some(jsonValue) => nestedRecordTags(fieldSchema, jsonValue)
|
|
485
|
+
| None => []
|
|
486
|
+
}
|
|
336
487
|
} else {
|
|
337
|
-
|
|
488
|
+
[]
|
|
338
489
|
}
|
|
339
490
|
)
|
|
491
|
+
->dedupeTags
|
|
340
492
|
|
|
341
493
|
// Extract the discriminating TAG constructor name from a variant Object schema's
|
|
342
494
|
// `properties`. sury (11) compiles a record-payload variant `Foo({...})` to an
|
|
@@ -517,6 +669,10 @@ For scalar tagged fields, behaves identically to `extractTagsFromProperties`.
|
|
|
517
669
|
For array tagged fields, produces one tag per element. Tag keys honour an optional
|
|
518
670
|
`DcbTag.stringForKey(~key=...)` override on the (inner) schema; otherwise the field
|
|
519
671
|
name is used.
|
|
672
|
+
|
|
673
|
+
Fields holding records are descended into on the same terms as in
|
|
674
|
+
`extractTagsFromProperties` — the two walks agree there and differ only on scalar
|
|
675
|
+
arrays; see that function.
|
|
520
676
|
*/
|
|
521
677
|
let extractTagsFromPropertiesExpanded = (
|
|
522
678
|
properties: dict<S.t<unknown>>,
|
|
@@ -525,25 +681,18 @@ let extractTagsFromPropertiesExpanded = (
|
|
|
525
681
|
properties
|
|
526
682
|
->Dict.toArray
|
|
527
683
|
->Array.flatMap(((fieldName, fieldSchema)) =>
|
|
528
|
-
if isTagged(fieldSchema) {
|
|
684
|
+
if isTagged(fieldSchema) || isTaggedArray(fieldSchema) {
|
|
685
|
+
flatFieldTagsExpanded(fieldName, fieldSchema, jsonDict)
|
|
686
|
+
} else if hasNestedTags(fieldSchema) {
|
|
529
687
|
switch jsonDict->Dict.get(fieldName) {
|
|
530
|
-
| Some(jsonValue) =>
|
|
531
|
-
{key: resolveTagKey(fieldName, fieldSchema), value: jsonValue->jsonValueToString},
|
|
532
|
-
]
|
|
688
|
+
| Some(jsonValue) => nestedRecordTags(fieldSchema, jsonValue)
|
|
533
689
|
| None => []
|
|
534
690
|
}
|
|
535
|
-
} else if isTaggedArray(fieldSchema) {
|
|
536
|
-
switch jsonDict->Dict.get(fieldName) {
|
|
537
|
-
| Some(JSON.Array(elements)) => {
|
|
538
|
-
let tagKey = resolveArrayTagKey(fieldName, fieldSchema)
|
|
539
|
-
elements->Array.map(element => {key: tagKey, value: element->jsonValueToString})
|
|
540
|
-
}
|
|
541
|
-
| _ => []
|
|
542
|
-
}
|
|
543
691
|
} else {
|
|
544
692
|
[]
|
|
545
693
|
}
|
|
546
694
|
)
|
|
695
|
+
->dedupeTags
|
|
547
696
|
|
|
548
697
|
/**
|
|
549
698
|
Extracts DCB tags from an event JSON value, expanding array values into per-element tags.
|
|
@@ -605,8 +754,9 @@ let extractTagsExpanded = (schema: S.t<'a>, value: 'a): array<tag> =>
|
|
|
605
754
|
// --- Automatic query construction from command schema ---
|
|
606
755
|
|
|
607
756
|
/**
|
|
608
|
-
Returns `true` if any field in the schema
|
|
609
|
-
(`array<@s.matches(DcbTag.string) string>`)
|
|
757
|
+
Returns `true` if any field in the schema fans out into several tags — a tagged
|
|
758
|
+
scalar array (`array<@s.matches(DcbTag.string) string>`) or an array of records
|
|
759
|
+
carrying tags (`array<lineItem>`).
|
|
610
760
|
Used to automatically determine whether to build single-clause or multi-clause queries.
|
|
611
761
|
*/
|
|
612
762
|
let hasTaggedArrayFields = (schema: S.t<'a>): bool =>
|
|
@@ -615,21 +765,30 @@ let hasTaggedArrayFields = (schema: S.t<'a>): bool =>
|
|
|
615
765
|
anyOf->Array.some(variantSchema =>
|
|
616
766
|
switch variantSchema {
|
|
617
767
|
| Object({properties}) =>
|
|
618
|
-
properties
|
|
768
|
+
properties
|
|
769
|
+
->Dict.toArray
|
|
770
|
+
->Array.some(((_, fieldSchema)) =>
|
|
771
|
+
isTaggedArray(fieldSchema) || isTaggedRecordArray(fieldSchema)
|
|
772
|
+
)
|
|
619
773
|
| _ => false
|
|
620
774
|
}
|
|
621
775
|
)
|
|
622
776
|
| Object({properties}) =>
|
|
623
|
-
properties
|
|
777
|
+
properties
|
|
778
|
+
->Dict.toArray
|
|
779
|
+
->Array.some(((_, fieldSchema)) =>
|
|
780
|
+
isTaggedArray(fieldSchema) || isTaggedRecordArray(fieldSchema)
|
|
781
|
+
)
|
|
624
782
|
| _ => false
|
|
625
783
|
}
|
|
626
784
|
|
|
627
785
|
/**
|
|
628
786
|
Collects the produced tag keys of one event-schema variant: the resolved tag key
|
|
629
|
-
of every scalar tagged field
|
|
630
|
-
tagged-array field
|
|
787
|
+
of every scalar tagged field, the resolved (override-aware) tag key of every
|
|
788
|
+
tagged-array field, and the keys of the tagged fields of any records the variant
|
|
789
|
+
holds — under the nested field's own name, as the extraction resolves them.
|
|
631
790
|
*/
|
|
632
|
-
let
|
|
791
|
+
let flatTagKeysOfProperties = (properties: dict<S.t<unknown>>): array<string> =>
|
|
633
792
|
properties
|
|
634
793
|
->Dict.toArray
|
|
635
794
|
->Array.filterMap(((fieldName, fieldSchema)) =>
|
|
@@ -642,6 +801,22 @@ let tagKeysOfProperties = (properties: dict<S.t<unknown>>): array<string> =>
|
|
|
642
801
|
}
|
|
643
802
|
)
|
|
644
803
|
|
|
804
|
+
let tagKeysOfProperties = (properties: dict<S.t<unknown>>): array<string> =>
|
|
805
|
+
properties
|
|
806
|
+
->Dict.toArray
|
|
807
|
+
->Array.flatMap(((fieldName, fieldSchema)) =>
|
|
808
|
+
if isTagged(fieldSchema) {
|
|
809
|
+
[resolveTagKey(fieldName, fieldSchema)]
|
|
810
|
+
} else if isTaggedArray(fieldSchema) {
|
|
811
|
+
[resolveArrayTagKey(fieldName, fieldSchema)]
|
|
812
|
+
} else {
|
|
813
|
+
switch nestedRecordProperties(fieldSchema) {
|
|
814
|
+
| Some((nested, _)) => flatTagKeysOfProperties(nested)
|
|
815
|
+
| None => []
|
|
816
|
+
}
|
|
817
|
+
}
|
|
818
|
+
)
|
|
819
|
+
|
|
645
820
|
/**
|
|
646
821
|
Maps each event-type (variant constructor name) to the set of DCB tag keys that
|
|
647
822
|
type can carry, read from a *produced* event-log schema.
|
|
@@ -882,21 +1057,43 @@ let extractCrossPartitionTagKeys = (schema: S.t<'event>): array<string> => {
|
|
|
882
1057
|
Collects the `*Id` / `*Ids`-shaped fields of one object-variant's properties as
|
|
883
1058
|
`DcbScopeInference.idField`s — by **name**, independent of any DCB tag flag. This
|
|
884
1059
|
is the un-annotated structural view the scope inference consumes.
|
|
1060
|
+
|
|
1061
|
+
A field holding records contributes the `*Id`-shaped fields of those records
|
|
1062
|
+
under their **own** names, and a field reached through an array is reported as a
|
|
1063
|
+
list whichever container it came from: the inference reasons about keys, and a
|
|
1064
|
+
key reached per line fans out exactly as a key reached per array element does.
|
|
1065
|
+
Reporting it as single-valued would derive the wrong partition for the slice.
|
|
1066
|
+
|
|
1067
|
+
That `DcbScopeInference.idField` needs no change to carry this is the evidence
|
|
1068
|
+
the boundary was drawn in the right place — the descent is a fact about schemas,
|
|
1069
|
+
which is this module's half of the split.
|
|
885
1070
|
*/
|
|
886
|
-
let idFieldsOfProperties = (properties: dict<S.t<unknown>>): array<DcbScopeInference.idField> =>
|
|
1071
|
+
let idFieldsOfProperties = (properties: dict<S.t<unknown>>): array<DcbScopeInference.idField> => {
|
|
1072
|
+
let isIdName = (name: string) => name->String.endsWith("Ids") || name->String.endsWith("Id")
|
|
887
1073
|
properties
|
|
888
1074
|
->Dict.toArray
|
|
889
|
-
->Array.
|
|
890
|
-
if
|
|
1075
|
+
->Array.flatMap(((name, fieldSchema)) =>
|
|
1076
|
+
if isIdName(name) {
|
|
891
1077
|
let isList = switch fieldSchema {
|
|
892
1078
|
| Array(_) => true
|
|
893
1079
|
| _ => false
|
|
894
1080
|
}
|
|
895
|
-
|
|
1081
|
+
[{DcbScopeInference.name, isList}]
|
|
896
1082
|
} else {
|
|
897
|
-
|
|
1083
|
+
switch nestedRecordProperties(fieldSchema) {
|
|
1084
|
+
| Some((nested, nestedIsList)) =>
|
|
1085
|
+
nested
|
|
1086
|
+
->Dict.toArray
|
|
1087
|
+
->Array.filterMap(((nestedName, _)) =>
|
|
1088
|
+
isIdName(nestedName)
|
|
1089
|
+
? Some({DcbScopeInference.name: nestedName, isList: nestedIsList})
|
|
1090
|
+
: None
|
|
1091
|
+
)
|
|
1092
|
+
| None => []
|
|
1093
|
+
}
|
|
898
1094
|
}
|
|
899
1095
|
)
|
|
1096
|
+
}
|
|
900
1097
|
|
|
901
1098
|
/**
|
|
902
1099
|
Extracts the `DcbScopeInference.eventShape`s (variant name + `*Id` fields) from a
|