domaintrail 0.1.0 → 0.2.0

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/dist/dt.js CHANGED
@@ -49,6 +49,9 @@ function isEventDecl(item) {
49
49
  function isExistsExpr(item) {
50
50
  return reflection.isInstance(item, ExistsExpr.$type);
51
51
  }
52
+ function isFieldSet(item) {
53
+ return reflection.isInstance(item, FieldSet.$type);
54
+ }
52
55
  function isIdType(item) {
53
56
  return reflection.isInstance(item, IdType.$type);
54
57
  }
@@ -103,10 +106,11 @@ function isUnionDecl(item) {
103
106
  function isValueObject(item) {
104
107
  return reflection.isInstance(item, ValueObject.$type);
105
108
  }
106
- var Aggregate, AggregateMember, BinaryExpr, BoolLiteral, Command, Context, ContextElement, CountExpr, DataMember, DecimalLiteral, Entity, EnumDecl, EnumValue, ErrorDecl, EventDecl, ExistsExpr, Expression, Field, IdType, IntLiteral, Invariant, LambdaParam, LengthExpr, MatchesExpr, MemberAccess, Model, Multiplicity, NameRef, NotExpr, OwnsField, Parameter, PrimitiveDecl, QuantifierExpr, RangeExpr, ReferenceField, State, StringLiteral, TermEntry, Terms, TypeDecl, TypeRef, UnionDecl, ValueObject, Variant, DomainAstReflection, reflection;
109
+ var Aggregate, AggregateMember, BinaryExpr, BoolLiteral, Command, Context, ContextElement, CountExpr, DataMember, DecimalLiteral, Entity, EnumDecl, EnumValue, ErrorDecl, EventDecl, ExistsExpr, Expression, Field, FieldSet, IdType, IntLiteral, Invariant, LambdaParam, LengthExpr, MatchesExpr, MemberAccess, Model, Multiplicity, NameRef, NotExpr, OwnsField, Parameter, PrimitiveDecl, QuantifierExpr, RangeExpr, ReferenceField, State, StringLiteral, TermEntry, Terms, TypeDecl, TypeRef, UnionDecl, ValueObject, Variant, DomainAstReflection, reflection;
107
110
  var init_ast = __esm(() => {
108
111
  Aggregate = {
109
112
  $type: "Aggregate",
113
+ fieldSets: "fieldSets",
110
114
  label: "label",
111
115
  members: "members",
112
116
  name: "name"
@@ -160,6 +164,7 @@ var init_ast = __esm(() => {
160
164
  };
161
165
  Entity = {
162
166
  $type: "Entity",
167
+ fieldSets: "fieldSets",
163
168
  label: "label",
164
169
  members: "members",
165
170
  name: "name"
@@ -177,12 +182,14 @@ var init_ast = __esm(() => {
177
182
  };
178
183
  ErrorDecl = {
179
184
  $type: "ErrorDecl",
185
+ fieldSets: "fieldSets",
180
186
  label: "label",
181
187
  members: "members",
182
188
  name: "name"
183
189
  };
184
190
  EventDecl = {
185
191
  $type: "EventDecl",
192
+ fieldSets: "fieldSets",
186
193
  label: "label",
187
194
  members: "members",
188
195
  name: "name",
@@ -202,6 +209,13 @@ var init_ast = __esm(() => {
202
209
  name: "name",
203
210
  type: "type"
204
211
  };
212
+ FieldSet = {
213
+ $type: "FieldSet",
214
+ fieldSets: "fieldSets",
215
+ label: "label",
216
+ members: "members",
217
+ name: "name"
218
+ };
205
219
  IdType = {
206
220
  $type: "IdType",
207
221
  base: "base",
@@ -338,6 +352,7 @@ var init_ast = __esm(() => {
338
352
  };
339
353
  ValueObject = {
340
354
  $type: "ValueObject",
355
+ fieldSets: "fieldSets",
341
356
  label: "label",
342
357
  members: "members",
343
358
  name: "name"
@@ -353,6 +368,12 @@ var init_ast = __esm(() => {
353
368
  Aggregate: {
354
369
  name: Aggregate.$type,
355
370
  properties: {
371
+ fieldSets: {
372
+ name: Aggregate.fieldSets,
373
+ defaultValue: [],
374
+ referenceType: FieldSet.$type,
375
+ optional: true
376
+ },
356
377
  label: {
357
378
  name: Aggregate.label,
358
379
  optional: true
@@ -508,6 +529,12 @@ var init_ast = __esm(() => {
508
529
  Entity: {
509
530
  name: Entity.$type,
510
531
  properties: {
532
+ fieldSets: {
533
+ name: Entity.fieldSets,
534
+ defaultValue: [],
535
+ referenceType: FieldSet.$type,
536
+ optional: true
537
+ },
511
538
  label: {
512
539
  name: Entity.label,
513
540
  optional: true
@@ -557,6 +584,12 @@ var init_ast = __esm(() => {
557
584
  ErrorDecl: {
558
585
  name: ErrorDecl.$type,
559
586
  properties: {
587
+ fieldSets: {
588
+ name: ErrorDecl.fieldSets,
589
+ defaultValue: [],
590
+ referenceType: FieldSet.$type,
591
+ optional: true
592
+ },
560
593
  label: {
561
594
  name: ErrorDecl.label,
562
595
  optional: true
@@ -575,6 +608,12 @@ var init_ast = __esm(() => {
575
608
  EventDecl: {
576
609
  name: EventDecl.$type,
577
610
  properties: {
611
+ fieldSets: {
612
+ name: EventDecl.fieldSets,
613
+ defaultValue: [],
614
+ referenceType: FieldSet.$type,
615
+ optional: true
616
+ },
578
617
  label: {
579
618
  name: EventDecl.label,
580
619
  optional: true
@@ -629,6 +668,30 @@ var init_ast = __esm(() => {
629
668
  },
630
669
  superTypes: [DataMember.$type]
631
670
  },
671
+ FieldSet: {
672
+ name: FieldSet.$type,
673
+ properties: {
674
+ fieldSets: {
675
+ name: FieldSet.fieldSets,
676
+ defaultValue: [],
677
+ referenceType: FieldSet.$type,
678
+ optional: true
679
+ },
680
+ label: {
681
+ name: FieldSet.label,
682
+ optional: true
683
+ },
684
+ members: {
685
+ name: FieldSet.members,
686
+ defaultValue: [],
687
+ optional: true
688
+ },
689
+ name: {
690
+ name: FieldSet.name
691
+ }
692
+ },
693
+ superTypes: [ContextElement.$type]
694
+ },
632
695
  IdType: {
633
696
  name: IdType.$type,
634
697
  properties: {
@@ -1001,6 +1064,12 @@ var init_ast = __esm(() => {
1001
1064
  ValueObject: {
1002
1065
  name: ValueObject.$type,
1003
1066
  properties: {
1067
+ fieldSets: {
1068
+ name: ValueObject.fieldSets,
1069
+ defaultValue: [],
1070
+ referenceType: FieldSet.$type,
1071
+ optional: true
1072
+ },
1004
1073
  label: {
1005
1074
  name: ValueObject.label,
1006
1075
  optional: true
@@ -1093,7 +1162,7 @@ var loadedDomainGrammar, DomainGrammar = () => loadedDomainGrammar ?? (loadedDom
1093
1162
  "terminal": {
1094
1163
  "$type": "RuleCall",
1095
1164
  "rule": {
1096
- "$ref": "#/rules@44"
1165
+ "$ref": "#/rules@46"
1097
1166
  },
1098
1167
  "arguments": []
1099
1168
  }
@@ -1105,7 +1174,7 @@ var loadedDomainGrammar, DomainGrammar = () => loadedDomainGrammar ?? (loadedDom
1105
1174
  "terminal": {
1106
1175
  "$type": "RuleCall",
1107
1176
  "rule": {
1108
- "$ref": "#/rules@43"
1177
+ "$ref": "#/rules@45"
1109
1178
  },
1110
1179
  "arguments": []
1111
1180
  },
@@ -1205,7 +1274,7 @@ var loadedDomainGrammar, DomainGrammar = () => loadedDomainGrammar ?? (loadedDom
1205
1274
  "terminal": {
1206
1275
  "$type": "RuleCall",
1207
1276
  "rule": {
1208
- "$ref": "#/rules@38"
1277
+ "$ref": "#/rules@40"
1209
1278
  },
1210
1279
  "arguments": []
1211
1280
  }
@@ -1221,7 +1290,7 @@ var loadedDomainGrammar, DomainGrammar = () => loadedDomainGrammar ?? (loadedDom
1221
1290
  "terminal": {
1222
1291
  "$type": "RuleCall",
1223
1292
  "rule": {
1224
- "$ref": "#/rules@43"
1293
+ "$ref": "#/rules@45"
1225
1294
  },
1226
1295
  "arguments": []
1227
1296
  }
@@ -1269,35 +1338,42 @@ var loadedDomainGrammar, DomainGrammar = () => loadedDomainGrammar ?? (loadedDom
1269
1338
  {
1270
1339
  "$type": "RuleCall",
1271
1340
  "rule": {
1272
- "$ref": "#/rules@11"
1341
+ "$ref": "#/rules@13"
1273
1342
  },
1274
1343
  "arguments": []
1275
1344
  },
1276
1345
  {
1277
1346
  "$type": "RuleCall",
1278
1347
  "rule": {
1279
- "$ref": "#/rules@13"
1348
+ "$ref": "#/rules@15"
1349
+ },
1350
+ "arguments": []
1351
+ },
1352
+ {
1353
+ "$type": "RuleCall",
1354
+ "rule": {
1355
+ "$ref": "#/rules@16"
1280
1356
  },
1281
1357
  "arguments": []
1282
1358
  },
1283
1359
  {
1284
1360
  "$type": "RuleCall",
1285
1361
  "rule": {
1286
- "$ref": "#/rules@14"
1362
+ "$ref": "#/rules@25"
1287
1363
  },
1288
1364
  "arguments": []
1289
1365
  },
1290
1366
  {
1291
1367
  "$type": "RuleCall",
1292
1368
  "rule": {
1293
- "$ref": "#/rules@23"
1369
+ "$ref": "#/rules@26"
1294
1370
  },
1295
1371
  "arguments": []
1296
1372
  },
1297
1373
  {
1298
1374
  "$type": "RuleCall",
1299
1375
  "rule": {
1300
- "$ref": "#/rules@24"
1376
+ "$ref": "#/rules@11"
1301
1377
  },
1302
1378
  "arguments": []
1303
1379
  }
@@ -1324,7 +1400,7 @@ var loadedDomainGrammar, DomainGrammar = () => loadedDomainGrammar ?? (loadedDom
1324
1400
  "terminal": {
1325
1401
  "$type": "RuleCall",
1326
1402
  "rule": {
1327
- "$ref": "#/rules@44"
1403
+ "$ref": "#/rules@46"
1328
1404
  },
1329
1405
  "arguments": []
1330
1406
  }
@@ -1336,7 +1412,7 @@ var loadedDomainGrammar, DomainGrammar = () => loadedDomainGrammar ?? (loadedDom
1336
1412
  "terminal": {
1337
1413
  "$type": "RuleCall",
1338
1414
  "rule": {
1339
- "$ref": "#/rules@43"
1415
+ "$ref": "#/rules@45"
1340
1416
  },
1341
1417
  "arguments": []
1342
1418
  },
@@ -1353,7 +1429,7 @@ var loadedDomainGrammar, DomainGrammar = () => loadedDomainGrammar ?? (loadedDom
1353
1429
  "terminal": {
1354
1430
  "$type": "RuleCall",
1355
1431
  "rule": {
1356
- "$ref": "#/rules@26"
1432
+ "$ref": "#/rules@28"
1357
1433
  },
1358
1434
  "arguments": []
1359
1435
  }
@@ -1389,7 +1465,7 @@ var loadedDomainGrammar, DomainGrammar = () => loadedDomainGrammar ?? (loadedDom
1389
1465
  "terminal": {
1390
1466
  "$type": "RuleCall",
1391
1467
  "rule": {
1392
- "$ref": "#/rules@44"
1468
+ "$ref": "#/rules@46"
1393
1469
  },
1394
1470
  "arguments": []
1395
1471
  }
@@ -1401,7 +1477,7 @@ var loadedDomainGrammar, DomainGrammar = () => loadedDomainGrammar ?? (loadedDom
1401
1477
  "terminal": {
1402
1478
  "$type": "RuleCall",
1403
1479
  "rule": {
1404
- "$ref": "#/rules@43"
1480
+ "$ref": "#/rules@45"
1405
1481
  },
1406
1482
  "arguments": []
1407
1483
  },
@@ -1418,7 +1494,7 @@ var loadedDomainGrammar, DomainGrammar = () => loadedDomainGrammar ?? (loadedDom
1418
1494
  "terminal": {
1419
1495
  "$type": "RuleCall",
1420
1496
  "rule": {
1421
- "$ref": "#/rules@26"
1497
+ "$ref": "#/rules@28"
1422
1498
  },
1423
1499
  "arguments": []
1424
1500
  }
@@ -1458,7 +1534,7 @@ var loadedDomainGrammar, DomainGrammar = () => loadedDomainGrammar ?? (loadedDom
1458
1534
  "terminal": {
1459
1535
  "$type": "RuleCall",
1460
1536
  "rule": {
1461
- "$ref": "#/rules@28"
1537
+ "$ref": "#/rules@30"
1462
1538
  },
1463
1539
  "arguments": []
1464
1540
  },
@@ -1471,7 +1547,7 @@ var loadedDomainGrammar, DomainGrammar = () => loadedDomainGrammar ?? (loadedDom
1471
1547
  "terminal": {
1472
1548
  "$type": "RuleCall",
1473
1549
  "rule": {
1474
- "$ref": "#/rules@29"
1550
+ "$ref": "#/rules@31"
1475
1551
  },
1476
1552
  "arguments": []
1477
1553
  }
@@ -1504,7 +1580,7 @@ var loadedDomainGrammar, DomainGrammar = () => loadedDomainGrammar ?? (loadedDom
1504
1580
  "terminal": {
1505
1581
  "$type": "RuleCall",
1506
1582
  "rule": {
1507
- "$ref": "#/rules@44"
1583
+ "$ref": "#/rules@46"
1508
1584
  },
1509
1585
  "arguments": []
1510
1586
  }
@@ -1516,7 +1592,7 @@ var loadedDomainGrammar, DomainGrammar = () => loadedDomainGrammar ?? (loadedDom
1516
1592
  "terminal": {
1517
1593
  "$type": "RuleCall",
1518
1594
  "rule": {
1519
- "$ref": "#/rules@43"
1595
+ "$ref": "#/rules@45"
1520
1596
  },
1521
1597
  "arguments": []
1522
1598
  },
@@ -1590,7 +1666,7 @@ var loadedDomainGrammar, DomainGrammar = () => loadedDomainGrammar ?? (loadedDom
1590
1666
  "terminal": {
1591
1667
  "$type": "RuleCall",
1592
1668
  "rule": {
1593
- "$ref": "#/rules@44"
1669
+ "$ref": "#/rules@46"
1594
1670
  },
1595
1671
  "arguments": []
1596
1672
  }
@@ -1602,7 +1678,7 @@ var loadedDomainGrammar, DomainGrammar = () => loadedDomainGrammar ?? (loadedDom
1602
1678
  "terminal": {
1603
1679
  "$type": "RuleCall",
1604
1680
  "rule": {
1605
- "$ref": "#/rules@43"
1681
+ "$ref": "#/rules@45"
1606
1682
  },
1607
1683
  "arguments": []
1608
1684
  },
@@ -1631,7 +1707,7 @@ var loadedDomainGrammar, DomainGrammar = () => loadedDomainGrammar ?? (loadedDom
1631
1707
  "terminal": {
1632
1708
  "$type": "RuleCall",
1633
1709
  "rule": {
1634
- "$ref": "#/rules@44"
1710
+ "$ref": "#/rules@46"
1635
1711
  },
1636
1712
  "arguments": []
1637
1713
  }
@@ -1643,12 +1719,20 @@ var loadedDomainGrammar, DomainGrammar = () => loadedDomainGrammar ?? (loadedDom
1643
1719
  "terminal": {
1644
1720
  "$type": "RuleCall",
1645
1721
  "rule": {
1646
- "$ref": "#/rules@43"
1722
+ "$ref": "#/rules@45"
1647
1723
  },
1648
1724
  "arguments": []
1649
1725
  },
1650
1726
  "cardinality": "?"
1651
1727
  },
1728
+ {
1729
+ "$type": "RuleCall",
1730
+ "rule": {
1731
+ "$ref": "#/rules@12"
1732
+ },
1733
+ "arguments": [],
1734
+ "cardinality": "?"
1735
+ },
1652
1736
  {
1653
1737
  "$type": "Group",
1654
1738
  "elements": [
@@ -1663,7 +1747,7 @@ var loadedDomainGrammar, DomainGrammar = () => loadedDomainGrammar ?? (loadedDom
1663
1747
  "terminal": {
1664
1748
  "$type": "RuleCall",
1665
1749
  "rule": {
1666
- "$ref": "#/rules@16"
1750
+ "$ref": "#/rules@18"
1667
1751
  },
1668
1752
  "arguments": []
1669
1753
  },
@@ -1682,6 +1766,142 @@ var loadedDomainGrammar, DomainGrammar = () => loadedDomainGrammar ?? (loadedDom
1682
1766
  "fragment": false,
1683
1767
  "parameters": []
1684
1768
  },
1769
+ {
1770
+ "$type": "ParserRule",
1771
+ "name": "FieldSet",
1772
+ "definition": {
1773
+ "$type": "Group",
1774
+ "elements": [
1775
+ {
1776
+ "$type": "Keyword",
1777
+ "value": "fields"
1778
+ },
1779
+ {
1780
+ "$type": "Assignment",
1781
+ "feature": "name",
1782
+ "operator": "=",
1783
+ "terminal": {
1784
+ "$type": "RuleCall",
1785
+ "rule": {
1786
+ "$ref": "#/rules@46"
1787
+ },
1788
+ "arguments": []
1789
+ }
1790
+ },
1791
+ {
1792
+ "$type": "Assignment",
1793
+ "feature": "label",
1794
+ "operator": "=",
1795
+ "terminal": {
1796
+ "$type": "RuleCall",
1797
+ "rule": {
1798
+ "$ref": "#/rules@45"
1799
+ },
1800
+ "arguments": []
1801
+ },
1802
+ "cardinality": "?"
1803
+ },
1804
+ {
1805
+ "$type": "RuleCall",
1806
+ "rule": {
1807
+ "$ref": "#/rules@12"
1808
+ },
1809
+ "arguments": [],
1810
+ "cardinality": "?"
1811
+ },
1812
+ {
1813
+ "$type": "Keyword",
1814
+ "value": "{"
1815
+ },
1816
+ {
1817
+ "$type": "Assignment",
1818
+ "feature": "members",
1819
+ "operator": "+=",
1820
+ "terminal": {
1821
+ "$type": "RuleCall",
1822
+ "rule": {
1823
+ "$ref": "#/rules@18"
1824
+ },
1825
+ "arguments": []
1826
+ },
1827
+ "cardinality": "*"
1828
+ },
1829
+ {
1830
+ "$type": "Keyword",
1831
+ "value": "}"
1832
+ }
1833
+ ]
1834
+ },
1835
+ "entry": false,
1836
+ "fragment": false,
1837
+ "parameters": []
1838
+ },
1839
+ {
1840
+ "$type": "ParserRule",
1841
+ "fragment": true,
1842
+ "name": "WithFieldSets",
1843
+ "definition": {
1844
+ "$type": "Group",
1845
+ "elements": [
1846
+ {
1847
+ "$type": "Keyword",
1848
+ "value": "with"
1849
+ },
1850
+ {
1851
+ "$type": "Assignment",
1852
+ "feature": "fieldSets",
1853
+ "operator": "+=",
1854
+ "terminal": {
1855
+ "$type": "CrossReference",
1856
+ "type": {
1857
+ "$ref": "#/rules@11"
1858
+ },
1859
+ "terminal": {
1860
+ "$type": "RuleCall",
1861
+ "rule": {
1862
+ "$ref": "#/rules@41"
1863
+ },
1864
+ "arguments": []
1865
+ },
1866
+ "deprecatedSyntax": false,
1867
+ "isMulti": false
1868
+ }
1869
+ },
1870
+ {
1871
+ "$type": "Group",
1872
+ "elements": [
1873
+ {
1874
+ "$type": "Keyword",
1875
+ "value": ","
1876
+ },
1877
+ {
1878
+ "$type": "Assignment",
1879
+ "feature": "fieldSets",
1880
+ "operator": "+=",
1881
+ "terminal": {
1882
+ "$type": "CrossReference",
1883
+ "type": {
1884
+ "$ref": "#/rules@11"
1885
+ },
1886
+ "terminal": {
1887
+ "$type": "RuleCall",
1888
+ "rule": {
1889
+ "$ref": "#/rules@41"
1890
+ },
1891
+ "arguments": []
1892
+ },
1893
+ "deprecatedSyntax": false,
1894
+ "isMulti": false
1895
+ }
1896
+ }
1897
+ ],
1898
+ "cardinality": "*"
1899
+ }
1900
+ ]
1901
+ },
1902
+ "entry": false,
1903
+ "parameters": []
1904
+ },
1685
1905
  {
1686
1906
  "$type": "ParserRule",
1687
1907
  "name": "UnionDecl",
@@ -1699,7 +1919,7 @@ var loadedDomainGrammar, DomainGrammar = () => loadedDomainGrammar ?? (loadedDom
1699
1919
  "terminal": {
1700
1920
  "$type": "RuleCall",
1701
1921
  "rule": {
1702
- "$ref": "#/rules@44"
1922
+ "$ref": "#/rules@46"
1703
1923
  },
1704
1924
  "arguments": []
1705
1925
  }
@@ -1711,7 +1931,7 @@ var loadedDomainGrammar, DomainGrammar = () => loadedDomainGrammar ?? (loadedDom
1711
1931
  "terminal": {
1712
1932
  "$type": "RuleCall",
1713
1933
  "rule": {
1714
- "$ref": "#/rules@43"
1934
+ "$ref": "#/rules@45"
1715
1935
  },
1716
1936
  "arguments": []
1717
1937
  },
@@ -1731,7 +1951,7 @@ var loadedDomainGrammar, DomainGrammar = () => loadedDomainGrammar ?? (loadedDom
1731
1951
  "terminal": {
1732
1952
  "$type": "RuleCall",
1733
1953
  "rule": {
1734
- "$ref": "#/rules@38"
1954
+ "$ref": "#/rules@40"
1735
1955
  },
1736
1956
  "arguments": []
1737
1957
  }
@@ -1755,7 +1975,7 @@ var loadedDomainGrammar, DomainGrammar = () => loadedDomainGrammar ?? (loadedDom
1755
1975
  "terminal": {
1756
1976
  "$type": "RuleCall",
1757
1977
  "rule": {
1758
- "$ref": "#/rules@39"
1978
+ "$ref": "#/rules@41"
1759
1979
  },
1760
1980
  "arguments": []
1761
1981
  },
@@ -1780,7 +2000,7 @@ var loadedDomainGrammar, DomainGrammar = () => loadedDomainGrammar ?? (loadedDom
1780
2000
  "terminal": {
1781
2001
  "$type": "RuleCall",
1782
2002
  "rule": {
1783
- "$ref": "#/rules@12"
2003
+ "$ref": "#/rules@14"
1784
2004
  },
1785
2005
  "arguments": []
1786
2006
  },
@@ -1809,7 +2029,7 @@ var loadedDomainGrammar, DomainGrammar = () => loadedDomainGrammar ?? (loadedDom
1809
2029
  "terminal": {
1810
2030
  "$type": "RuleCall",
1811
2031
  "rule": {
1812
- "$ref": "#/rules@44"
2032
+ "$ref": "#/rules@46"
1813
2033
  },
1814
2034
  "arguments": []
1815
2035
  }
@@ -1821,7 +2041,7 @@ var loadedDomainGrammar, DomainGrammar = () => loadedDomainGrammar ?? (loadedDom
1821
2041
  "terminal": {
1822
2042
  "$type": "RuleCall",
1823
2043
  "rule": {
1824
- "$ref": "#/rules@43"
2044
+ "$ref": "#/rules@45"
1825
2045
  },
1826
2046
  "arguments": []
1827
2047
  },
@@ -1841,7 +2061,7 @@ var loadedDomainGrammar, DomainGrammar = () => loadedDomainGrammar ?? (loadedDom
1841
2061
  "terminal": {
1842
2062
  "$type": "RuleCall",
1843
2063
  "rule": {
1844
- "$ref": "#/rules@16"
2064
+ "$ref": "#/rules@18"
1845
2065
  },
1846
2066
  "arguments": []
1847
2067
  },
@@ -1877,7 +2097,7 @@ var loadedDomainGrammar, DomainGrammar = () => loadedDomainGrammar ?? (loadedDom
1877
2097
  "terminal": {
1878
2098
  "$type": "RuleCall",
1879
2099
  "rule": {
1880
- "$ref": "#/rules@44"
2100
+ "$ref": "#/rules@46"
1881
2101
  },
1882
2102
  "arguments": []
1883
2103
  }
@@ -1889,12 +2109,20 @@ var loadedDomainGrammar, DomainGrammar = () => loadedDomainGrammar ?? (loadedDom
1889
2109
  "terminal": {
1890
2110
  "$type": "RuleCall",
1891
2111
  "rule": {
1892
- "$ref": "#/rules@43"
2112
+ "$ref": "#/rules@45"
1893
2113
  },
1894
2114
  "arguments": []
1895
2115
  },
1896
2116
  "cardinality": "?"
1897
2117
  },
2118
+ {
2119
+ "$type": "RuleCall",
2120
+ "rule": {
2121
+ "$ref": "#/rules@12"
2122
+ },
2123
+ "arguments": [],
2124
+ "cardinality": "?"
2125
+ },
1898
2126
  {
1899
2127
  "$type": "Keyword",
1900
2128
  "value": "{"
@@ -1906,7 +2134,7 @@ var loadedDomainGrammar, DomainGrammar = () => loadedDomainGrammar ?? (loadedDom
1906
2134
  "terminal": {
1907
2135
  "$type": "RuleCall",
1908
2136
  "rule": {
1909
- "$ref": "#/rules@16"
2137
+ "$ref": "#/rules@18"
1910
2138
  },
1911
2139
  "arguments": []
1912
2140
  },
@@ -1939,7 +2167,7 @@ var loadedDomainGrammar, DomainGrammar = () => loadedDomainGrammar ?? (loadedDom
1939
2167
  "terminal": {
1940
2168
  "$type": "RuleCall",
1941
2169
  "rule": {
1942
- "$ref": "#/rules@44"
2170
+ "$ref": "#/rules@46"
1943
2171
  },
1944
2172
  "arguments": []
1945
2173
  }
@@ -1951,12 +2179,20 @@ var loadedDomainGrammar, DomainGrammar = () => loadedDomainGrammar ?? (loadedDom
1951
2179
  "terminal": {
1952
2180
  "$type": "RuleCall",
1953
2181
  "rule": {
1954
- "$ref": "#/rules@43"
2182
+ "$ref": "#/rules@45"
1955
2183
  },
1956
2184
  "arguments": []
1957
2185
  },
1958
2186
  "cardinality": "?"
1959
2187
  },
2188
+ {
2189
+ "$type": "RuleCall",
2190
+ "rule": {
2191
+ "$ref": "#/rules@12"
2192
+ },
2193
+ "arguments": [],
2194
+ "cardinality": "?"
2195
+ },
1960
2196
  {
1961
2197
  "$type": "Keyword",
1962
2198
  "value": "{"
@@ -1968,7 +2204,7 @@ var loadedDomainGrammar, DomainGrammar = () => loadedDomainGrammar ?? (loadedDom
1968
2204
  "terminal": {
1969
2205
  "$type": "RuleCall",
1970
2206
  "rule": {
1971
- "$ref": "#/rules@15"
2207
+ "$ref": "#/rules@17"
1972
2208
  },
1973
2209
  "arguments": []
1974
2210
  },
@@ -1993,21 +2229,21 @@ var loadedDomainGrammar, DomainGrammar = () => loadedDomainGrammar ?? (loadedDom
1993
2229
  {
1994
2230
  "$type": "RuleCall",
1995
2231
  "rule": {
1996
- "$ref": "#/rules@16"
2232
+ "$ref": "#/rules@18"
1997
2233
  },
1998
2234
  "arguments": []
1999
2235
  },
2000
2236
  {
2001
2237
  "$type": "RuleCall",
2002
2238
  "rule": {
2003
- "$ref": "#/rules@17"
2239
+ "$ref": "#/rules@19"
2004
2240
  },
2005
2241
  "arguments": []
2006
2242
  },
2007
2243
  {
2008
2244
  "$type": "RuleCall",
2009
2245
  "rule": {
2010
- "$ref": "#/rules@21"
2246
+ "$ref": "#/rules@23"
2011
2247
  },
2012
2248
  "arguments": []
2013
2249
  }
@@ -2026,28 +2262,28 @@ var loadedDomainGrammar, DomainGrammar = () => loadedDomainGrammar ?? (loadedDom
2026
2262
  {
2027
2263
  "$type": "RuleCall",
2028
2264
  "rule": {
2029
- "$ref": "#/rules@18"
2265
+ "$ref": "#/rules@20"
2030
2266
  },
2031
2267
  "arguments": []
2032
2268
  },
2033
2269
  {
2034
2270
  "$type": "RuleCall",
2035
2271
  "rule": {
2036
- "$ref": "#/rules@19"
2272
+ "$ref": "#/rules@21"
2037
2273
  },
2038
2274
  "arguments": []
2039
2275
  },
2040
2276
  {
2041
2277
  "$type": "RuleCall",
2042
2278
  "rule": {
2043
- "$ref": "#/rules@20"
2279
+ "$ref": "#/rules@22"
2044
2280
  },
2045
2281
  "arguments": []
2046
2282
  },
2047
2283
  {
2048
2284
  "$type": "RuleCall",
2049
2285
  "rule": {
2050
- "$ref": "#/rules@28"
2286
+ "$ref": "#/rules@30"
2051
2287
  },
2052
2288
  "arguments": []
2053
2289
  }
@@ -2074,7 +2310,7 @@ var loadedDomainGrammar, DomainGrammar = () => loadedDomainGrammar ?? (loadedDom
2074
2310
  "terminal": {
2075
2311
  "$type": "RuleCall",
2076
2312
  "rule": {
2077
- "$ref": "#/rules@44"
2313
+ "$ref": "#/rules@46"
2078
2314
  },
2079
2315
  "arguments": []
2080
2316
  }
@@ -2086,7 +2322,7 @@ var loadedDomainGrammar, DomainGrammar = () => loadedDomainGrammar ?? (loadedDom
2086
2322
  "terminal": {
2087
2323
  "$type": "RuleCall",
2088
2324
  "rule": {
2089
- "$ref": "#/rules@43"
2325
+ "$ref": "#/rules@45"
2090
2326
  },
2091
2327
  "arguments": []
2092
2328
  },
@@ -2106,7 +2342,7 @@ var loadedDomainGrammar, DomainGrammar = () => loadedDomainGrammar ?? (loadedDom
2106
2342
  "terminal": {
2107
2343
  "$type": "RuleCall",
2108
2344
  "rule": {
2109
- "$ref": "#/rules@16"
2345
+ "$ref": "#/rules@18"
2110
2346
  },
2111
2347
  "arguments": []
2112
2348
  },
@@ -2138,7 +2374,7 @@ var loadedDomainGrammar, DomainGrammar = () => loadedDomainGrammar ?? (loadedDom
2138
2374
  "terminal": {
2139
2375
  "$type": "RuleCall",
2140
2376
  "rule": {
2141
- "$ref": "#/rules@38"
2377
+ "$ref": "#/rules@40"
2142
2378
  },
2143
2379
  "arguments": []
2144
2380
  }
@@ -2154,7 +2390,7 @@ var loadedDomainGrammar, DomainGrammar = () => loadedDomainGrammar ?? (loadedDom
2154
2390
  "terminal": {
2155
2391
  "$type": "RuleCall",
2156
2392
  "rule": {
2157
- "$ref": "#/rules@25"
2393
+ "$ref": "#/rules@27"
2158
2394
  },
2159
2395
  "arguments": []
2160
2396
  }
@@ -2166,7 +2402,7 @@ var loadedDomainGrammar, DomainGrammar = () => loadedDomainGrammar ?? (loadedDom
2166
2402
  "terminal": {
2167
2403
  "$type": "RuleCall",
2168
2404
  "rule": {
2169
- "$ref": "#/rules@27"
2405
+ "$ref": "#/rules@29"
2170
2406
  },
2171
2407
  "arguments": []
2172
2408
  },
@@ -2179,7 +2415,7 @@ var loadedDomainGrammar, DomainGrammar = () => loadedDomainGrammar ?? (loadedDom
2179
2415
  "terminal": {
2180
2416
  "$type": "RuleCall",
2181
2417
  "rule": {
2182
- "$ref": "#/rules@43"
2418
+ "$ref": "#/rules@45"
2183
2419
  },
2184
2420
  "arguments": []
2185
2421
  },
@@ -2208,7 +2444,7 @@ var loadedDomainGrammar, DomainGrammar = () => loadedDomainGrammar ?? (loadedDom
2208
2444
  "terminal": {
2209
2445
  "$type": "RuleCall",
2210
2446
  "rule": {
2211
- "$ref": "#/rules@38"
2447
+ "$ref": "#/rules@40"
2212
2448
  },
2213
2449
  "arguments": []
2214
2450
  }
@@ -2224,7 +2460,7 @@ var loadedDomainGrammar, DomainGrammar = () => loadedDomainGrammar ?? (loadedDom
2224
2460
  "terminal": {
2225
2461
  "$type": "RuleCall",
2226
2462
  "rule": {
2227
- "$ref": "#/rules@25"
2463
+ "$ref": "#/rules@27"
2228
2464
  },
2229
2465
  "arguments": []
2230
2466
  }
@@ -2236,7 +2472,7 @@ var loadedDomainGrammar, DomainGrammar = () => loadedDomainGrammar ?? (loadedDom
2236
2472
  "terminal": {
2237
2473
  "$type": "RuleCall",
2238
2474
  "rule": {
2239
- "$ref": "#/rules@27"
2475
+ "$ref": "#/rules@29"
2240
2476
  },
2241
2477
  "arguments": []
2242
2478
  },
@@ -2249,7 +2485,7 @@ var loadedDomainGrammar, DomainGrammar = () => loadedDomainGrammar ?? (loadedDom
2249
2485
  "terminal": {
2250
2486
  "$type": "RuleCall",
2251
2487
  "rule": {
2252
- "$ref": "#/rules@43"
2488
+ "$ref": "#/rules@45"
2253
2489
  },
2254
2490
  "arguments": []
2255
2491
  },
@@ -2278,7 +2514,7 @@ var loadedDomainGrammar, DomainGrammar = () => loadedDomainGrammar ?? (loadedDom
2278
2514
  "terminal": {
2279
2515
  "$type": "RuleCall",
2280
2516
  "rule": {
2281
- "$ref": "#/rules@38"
2517
+ "$ref": "#/rules@40"
2282
2518
  },
2283
2519
  "arguments": []
2284
2520
  }
@@ -2294,7 +2530,7 @@ var loadedDomainGrammar, DomainGrammar = () => loadedDomainGrammar ?? (loadedDom
2294
2530
  "terminal": {
2295
2531
  "$type": "RuleCall",
2296
2532
  "rule": {
2297
- "$ref": "#/rules@25"
2533
+ "$ref": "#/rules@27"
2298
2534
  },
2299
2535
  "arguments": []
2300
2536
  }
@@ -2306,7 +2542,7 @@ var loadedDomainGrammar, DomainGrammar = () => loadedDomainGrammar ?? (loadedDom
2306
2542
  "terminal": {
2307
2543
  "$type": "RuleCall",
2308
2544
  "rule": {
2309
- "$ref": "#/rules@27"
2545
+ "$ref": "#/rules@29"
2310
2546
  },
2311
2547
  "arguments": []
2312
2548
  },
@@ -2323,12 +2559,12 @@ var loadedDomainGrammar, DomainGrammar = () => loadedDomainGrammar ?? (loadedDom
2323
2559
  "terminal": {
2324
2560
  "$type": "CrossReference",
2325
2561
  "type": {
2326
- "$ref": "#/rules@14"
2562
+ "$ref": "#/rules@16"
2327
2563
  },
2328
2564
  "terminal": {
2329
2565
  "$type": "RuleCall",
2330
2566
  "rule": {
2331
- "$ref": "#/rules@39"
2567
+ "$ref": "#/rules@41"
2332
2568
  },
2333
2569
  "arguments": []
2334
2570
  },
@@ -2343,7 +2579,7 @@ var loadedDomainGrammar, DomainGrammar = () => loadedDomainGrammar ?? (loadedDom
2343
2579
  "terminal": {
2344
2580
  "$type": "RuleCall",
2345
2581
  "rule": {
2346
- "$ref": "#/rules@43"
2582
+ "$ref": "#/rules@45"
2347
2583
  },
2348
2584
  "arguments": []
2349
2585
  },
@@ -2382,7 +2618,7 @@ var loadedDomainGrammar, DomainGrammar = () => loadedDomainGrammar ?? (loadedDom
2382
2618
  "terminal": {
2383
2619
  "$type": "RuleCall",
2384
2620
  "rule": {
2385
- "$ref": "#/rules@38"
2621
+ "$ref": "#/rules@40"
2386
2622
  },
2387
2623
  "arguments": []
2388
2624
  }
@@ -2401,7 +2637,7 @@ var loadedDomainGrammar, DomainGrammar = () => loadedDomainGrammar ?? (loadedDom
2401
2637
  "terminal": {
2402
2638
  "$type": "RuleCall",
2403
2639
  "rule": {
2404
- "$ref": "#/rules@22"
2640
+ "$ref": "#/rules@24"
2405
2641
  },
2406
2642
  "arguments": []
2407
2643
  }
@@ -2420,7 +2656,7 @@ var loadedDomainGrammar, DomainGrammar = () => loadedDomainGrammar ?? (loadedDom
2420
2656
  "terminal": {
2421
2657
  "$type": "RuleCall",
2422
2658
  "rule": {
2423
- "$ref": "#/rules@22"
2659
+ "$ref": "#/rules@24"
2424
2660
  },
2425
2661
  "arguments": []
2426
2662
  }
@@ -2442,7 +2678,7 @@ var loadedDomainGrammar, DomainGrammar = () => loadedDomainGrammar ?? (loadedDom
2442
2678
  "terminal": {
2443
2679
  "$type": "RuleCall",
2444
2680
  "rule": {
2445
- "$ref": "#/rules@43"
2681
+ "$ref": "#/rules@45"
2446
2682
  },
2447
2683
  "arguments": []
2448
2684
  },
@@ -2462,12 +2698,12 @@ var loadedDomainGrammar, DomainGrammar = () => loadedDomainGrammar ?? (loadedDom
2462
2698
  "terminal": {
2463
2699
  "$type": "CrossReference",
2464
2700
  "type": {
2465
- "$ref": "#/rules@17"
2701
+ "$ref": "#/rules@19"
2466
2702
  },
2467
2703
  "terminal": {
2468
2704
  "$type": "RuleCall",
2469
2705
  "rule": {
2470
- "$ref": "#/rules@44"
2706
+ "$ref": "#/rules@46"
2471
2707
  },
2472
2708
  "arguments": []
2473
2709
  },
@@ -2489,12 +2725,12 @@ var loadedDomainGrammar, DomainGrammar = () => loadedDomainGrammar ?? (loadedDom
2489
2725
  "terminal": {
2490
2726
  "$type": "CrossReference",
2491
2727
  "type": {
2492
- "$ref": "#/rules@17"
2728
+ "$ref": "#/rules@19"
2493
2729
  },
2494
2730
  "terminal": {
2495
2731
  "$type": "RuleCall",
2496
2732
  "rule": {
2497
- "$ref": "#/rules@44"
2733
+ "$ref": "#/rules@46"
2498
2734
  },
2499
2735
  "arguments": []
2500
2736
  },
@@ -2522,12 +2758,12 @@ var loadedDomainGrammar, DomainGrammar = () => loadedDomainGrammar ?? (loadedDom
2522
2758
  "terminal": {
2523
2759
  "$type": "CrossReference",
2524
2760
  "type": {
2525
- "$ref": "#/rules@17"
2761
+ "$ref": "#/rules@19"
2526
2762
  },
2527
2763
  "terminal": {
2528
2764
  "$type": "RuleCall",
2529
2765
  "rule": {
2530
- "$ref": "#/rules@44"
2766
+ "$ref": "#/rules@46"
2531
2767
  },
2532
2768
  "arguments": []
2533
2769
  },
@@ -2549,12 +2785,12 @@ var loadedDomainGrammar, DomainGrammar = () => loadedDomainGrammar ?? (loadedDom
2549
2785
  "terminal": {
2550
2786
  "$type": "CrossReference",
2551
2787
  "type": {
2552
- "$ref": "#/rules@17"
2788
+ "$ref": "#/rules@19"
2553
2789
  },
2554
2790
  "terminal": {
2555
2791
  "$type": "RuleCall",
2556
2792
  "rule": {
2557
- "$ref": "#/rules@44"
2793
+ "$ref": "#/rules@46"
2558
2794
  },
2559
2795
  "arguments": []
2560
2796
  },
@@ -2582,12 +2818,12 @@ var loadedDomainGrammar, DomainGrammar = () => loadedDomainGrammar ?? (loadedDom
2582
2818
  "terminal": {
2583
2819
  "$type": "CrossReference",
2584
2820
  "type": {
2585
- "$ref": "#/rules@23"
2821
+ "$ref": "#/rules@25"
2586
2822
  },
2587
2823
  "terminal": {
2588
2824
  "$type": "RuleCall",
2589
2825
  "rule": {
2590
- "$ref": "#/rules@39"
2826
+ "$ref": "#/rules@41"
2591
2827
  },
2592
2828
  "arguments": []
2593
2829
  },
@@ -2609,12 +2845,12 @@ var loadedDomainGrammar, DomainGrammar = () => loadedDomainGrammar ?? (loadedDom
2609
2845
  "terminal": {
2610
2846
  "$type": "CrossReference",
2611
2847
  "type": {
2612
- "$ref": "#/rules@23"
2848
+ "$ref": "#/rules@25"
2613
2849
  },
2614
2850
  "terminal": {
2615
2851
  "$type": "RuleCall",
2616
2852
  "rule": {
2617
- "$ref": "#/rules@39"
2853
+ "$ref": "#/rules@41"
2618
2854
  },
2619
2855
  "arguments": []
2620
2856
  },
@@ -2642,12 +2878,12 @@ var loadedDomainGrammar, DomainGrammar = () => loadedDomainGrammar ?? (loadedDom
2642
2878
  "terminal": {
2643
2879
  "$type": "CrossReference",
2644
2880
  "type": {
2645
- "$ref": "#/rules@24"
2881
+ "$ref": "#/rules@26"
2646
2882
  },
2647
2883
  "terminal": {
2648
2884
  "$type": "RuleCall",
2649
2885
  "rule": {
2650
- "$ref": "#/rules@39"
2886
+ "$ref": "#/rules@41"
2651
2887
  },
2652
2888
  "arguments": []
2653
2889
  },
@@ -2669,12 +2905,12 @@ var loadedDomainGrammar, DomainGrammar = () => loadedDomainGrammar ?? (loadedDom
2669
2905
  "terminal": {
2670
2906
  "$type": "CrossReference",
2671
2907
  "type": {
2672
- "$ref": "#/rules@24"
2908
+ "$ref": "#/rules@26"
2673
2909
  },
2674
2910
  "terminal": {
2675
2911
  "$type": "RuleCall",
2676
2912
  "rule": {
2677
- "$ref": "#/rules@39"
2913
+ "$ref": "#/rules@41"
2678
2914
  },
2679
2915
  "arguments": []
2680
2916
  },
@@ -2707,7 +2943,7 @@ var loadedDomainGrammar, DomainGrammar = () => loadedDomainGrammar ?? (loadedDom
2707
2943
  "terminal": {
2708
2944
  "$type": "RuleCall",
2709
2945
  "rule": {
2710
- "$ref": "#/rules@38"
2946
+ "$ref": "#/rules@40"
2711
2947
  },
2712
2948
  "arguments": []
2713
2949
  }
@@ -2723,7 +2959,7 @@ var loadedDomainGrammar, DomainGrammar = () => loadedDomainGrammar ?? (loadedDom
2723
2959
  "terminal": {
2724
2960
  "$type": "RuleCall",
2725
2961
  "rule": {
2726
- "$ref": "#/rules@25"
2962
+ "$ref": "#/rules@27"
2727
2963
  },
2728
2964
  "arguments": []
2729
2965
  }
@@ -2735,7 +2971,7 @@ var loadedDomainGrammar, DomainGrammar = () => loadedDomainGrammar ?? (loadedDom
2735
2971
  "terminal": {
2736
2972
  "$type": "RuleCall",
2737
2973
  "rule": {
2738
- "$ref": "#/rules@27"
2974
+ "$ref": "#/rules@29"
2739
2975
  },
2740
2976
  "arguments": []
2741
2977
  },
@@ -2748,7 +2984,7 @@ var loadedDomainGrammar, DomainGrammar = () => loadedDomainGrammar ?? (loadedDom
2748
2984
  "terminal": {
2749
2985
  "$type": "RuleCall",
2750
2986
  "rule": {
2751
- "$ref": "#/rules@43"
2987
+ "$ref": "#/rules@45"
2752
2988
  },
2753
2989
  "arguments": []
2754
2990
  },
@@ -2787,7 +3023,7 @@ var loadedDomainGrammar, DomainGrammar = () => loadedDomainGrammar ?? (loadedDom
2787
3023
  "terminal": {
2788
3024
  "$type": "RuleCall",
2789
3025
  "rule": {
2790
- "$ref": "#/rules@44"
3026
+ "$ref": "#/rules@46"
2791
3027
  },
2792
3028
  "arguments": []
2793
3029
  }
@@ -2799,12 +3035,20 @@ var loadedDomainGrammar, DomainGrammar = () => loadedDomainGrammar ?? (loadedDom
2799
3035
  "terminal": {
2800
3036
  "$type": "RuleCall",
2801
3037
  "rule": {
2802
- "$ref": "#/rules@43"
3038
+ "$ref": "#/rules@45"
2803
3039
  },
2804
3040
  "arguments": []
2805
3041
  },
2806
3042
  "cardinality": "?"
2807
3043
  },
3044
+ {
3045
+ "$type": "RuleCall",
3046
+ "rule": {
3047
+ "$ref": "#/rules@12"
3048
+ },
3049
+ "arguments": [],
3050
+ "cardinality": "?"
3051
+ },
2808
3052
  {
2809
3053
  "$type": "Group",
2810
3054
  "elements": [
@@ -2819,7 +3063,7 @@ var loadedDomainGrammar, DomainGrammar = () => loadedDomainGrammar ?? (loadedDom
2819
3063
  "terminal": {
2820
3064
  "$type": "RuleCall",
2821
3065
  "rule": {
2822
- "$ref": "#/rules@18"
3066
+ "$ref": "#/rules@20"
2823
3067
  },
2824
3068
  "arguments": []
2825
3069
  },
@@ -2855,7 +3099,7 @@ var loadedDomainGrammar, DomainGrammar = () => loadedDomainGrammar ?? (loadedDom
2855
3099
  "terminal": {
2856
3100
  "$type": "RuleCall",
2857
3101
  "rule": {
2858
- "$ref": "#/rules@44"
3102
+ "$ref": "#/rules@46"
2859
3103
  },
2860
3104
  "arguments": []
2861
3105
  }
@@ -2867,12 +3111,20 @@ var loadedDomainGrammar, DomainGrammar = () => loadedDomainGrammar ?? (loadedDom
2867
3111
  "terminal": {
2868
3112
  "$type": "RuleCall",
2869
3113
  "rule": {
2870
- "$ref": "#/rules@43"
3114
+ "$ref": "#/rules@45"
2871
3115
  },
2872
3116
  "arguments": []
2873
3117
  },
2874
3118
  "cardinality": "?"
2875
3119
  },
3120
+ {
3121
+ "$type": "RuleCall",
3122
+ "rule": {
3123
+ "$ref": "#/rules@12"
3124
+ },
3125
+ "arguments": [],
3126
+ "cardinality": "?"
3127
+ },
2876
3128
  {
2877
3129
  "$type": "Group",
2878
3130
  "elements": [
@@ -2887,7 +3139,7 @@ var loadedDomainGrammar, DomainGrammar = () => loadedDomainGrammar ?? (loadedDom
2887
3139
  "terminal": {
2888
3140
  "$type": "RuleCall",
2889
3141
  "rule": {
2890
- "$ref": "#/rules@18"
3142
+ "$ref": "#/rules@20"
2891
3143
  },
2892
3144
  "arguments": []
2893
3145
  },
@@ -2919,7 +3171,7 @@ var loadedDomainGrammar, DomainGrammar = () => loadedDomainGrammar ?? (loadedDom
2919
3171
  "terminal": {
2920
3172
  "$type": "RuleCall",
2921
3173
  "rule": {
2922
- "$ref": "#/rules@26"
3174
+ "$ref": "#/rules@28"
2923
3175
  },
2924
3176
  "arguments": []
2925
3177
  }
@@ -2936,7 +3188,7 @@ var loadedDomainGrammar, DomainGrammar = () => loadedDomainGrammar ?? (loadedDom
2936
3188
  "terminal": {
2937
3189
  "$type": "RuleCall",
2938
3190
  "rule": {
2939
- "$ref": "#/rules@39"
3191
+ "$ref": "#/rules@41"
2940
3192
  },
2941
3193
  "arguments": []
2942
3194
  },
@@ -3016,7 +3268,7 @@ var loadedDomainGrammar, DomainGrammar = () => loadedDomainGrammar ?? (loadedDom
3016
3268
  "terminal": {
3017
3269
  "$type": "RuleCall",
3018
3270
  "rule": {
3019
- "$ref": "#/rules@42"
3271
+ "$ref": "#/rules@44"
3020
3272
  },
3021
3273
  "arguments": []
3022
3274
  }
@@ -3035,7 +3287,7 @@ var loadedDomainGrammar, DomainGrammar = () => loadedDomainGrammar ?? (loadedDom
3035
3287
  "terminal": {
3036
3288
  "$type": "RuleCall",
3037
3289
  "rule": {
3038
- "$ref": "#/rules@42"
3290
+ "$ref": "#/rules@44"
3039
3291
  },
3040
3292
  "arguments": []
3041
3293
  }
@@ -3080,7 +3332,7 @@ var loadedDomainGrammar, DomainGrammar = () => loadedDomainGrammar ?? (loadedDom
3080
3332
  "terminal": {
3081
3333
  "$type": "RuleCall",
3082
3334
  "rule": {
3083
- "$ref": "#/rules@44"
3335
+ "$ref": "#/rules@46"
3084
3336
  },
3085
3337
  "arguments": []
3086
3338
  }
@@ -3092,7 +3344,7 @@ var loadedDomainGrammar, DomainGrammar = () => loadedDomainGrammar ?? (loadedDom
3092
3344
  "terminal": {
3093
3345
  "$type": "RuleCall",
3094
3346
  "rule": {
3095
- "$ref": "#/rules@43"
3347
+ "$ref": "#/rules@45"
3096
3348
  },
3097
3349
  "arguments": []
3098
3350
  },
@@ -3109,7 +3361,7 @@ var loadedDomainGrammar, DomainGrammar = () => loadedDomainGrammar ?? (loadedDom
3109
3361
  "terminal": {
3110
3362
  "$type": "RuleCall",
3111
3363
  "rule": {
3112
- "$ref": "#/rules@29"
3364
+ "$ref": "#/rules@31"
3113
3365
  },
3114
3366
  "arguments": []
3115
3367
  }
@@ -3130,7 +3382,7 @@ var loadedDomainGrammar, DomainGrammar = () => loadedDomainGrammar ?? (loadedDom
3130
3382
  "definition": {
3131
3383
  "$type": "RuleCall",
3132
3384
  "rule": {
3133
- "$ref": "#/rules@30"
3385
+ "$ref": "#/rules@32"
3134
3386
  },
3135
3387
  "arguments": []
3136
3388
  },
@@ -3151,7 +3403,7 @@ var loadedDomainGrammar, DomainGrammar = () => loadedDomainGrammar ?? (loadedDom
3151
3403
  {
3152
3404
  "$type": "RuleCall",
3153
3405
  "rule": {
3154
- "$ref": "#/rules@31"
3406
+ "$ref": "#/rules@33"
3155
3407
  },
3156
3408
  "arguments": []
3157
3409
  },
@@ -3183,7 +3435,7 @@ var loadedDomainGrammar, DomainGrammar = () => loadedDomainGrammar ?? (loadedDom
3183
3435
  "terminal": {
3184
3436
  "$type": "RuleCall",
3185
3437
  "rule": {
3186
- "$ref": "#/rules@31"
3438
+ "$ref": "#/rules@33"
3187
3439
  },
3188
3440
  "arguments": []
3189
3441
  }
@@ -3210,7 +3462,7 @@ var loadedDomainGrammar, DomainGrammar = () => loadedDomainGrammar ?? (loadedDom
3210
3462
  {
3211
3463
  "$type": "RuleCall",
3212
3464
  "rule": {
3213
- "$ref": "#/rules@32"
3465
+ "$ref": "#/rules@34"
3214
3466
  },
3215
3467
  "arguments": []
3216
3468
  },
@@ -3242,7 +3494,7 @@ var loadedDomainGrammar, DomainGrammar = () => loadedDomainGrammar ?? (loadedDom
3242
3494
  "terminal": {
3243
3495
  "$type": "RuleCall",
3244
3496
  "rule": {
3245
- "$ref": "#/rules@32"
3497
+ "$ref": "#/rules@34"
3246
3498
  },
3247
3499
  "arguments": []
3248
3500
  }
@@ -3269,7 +3521,7 @@ var loadedDomainGrammar, DomainGrammar = () => loadedDomainGrammar ?? (loadedDom
3269
3521
  {
3270
3522
  "$type": "RuleCall",
3271
3523
  "rule": {
3272
- "$ref": "#/rules@33"
3524
+ "$ref": "#/rules@35"
3273
3525
  },
3274
3526
  "arguments": []
3275
3527
  },
@@ -3301,7 +3553,7 @@ var loadedDomainGrammar, DomainGrammar = () => loadedDomainGrammar ?? (loadedDom
3301
3553
  "terminal": {
3302
3554
  "$type": "RuleCall",
3303
3555
  "rule": {
3304
- "$ref": "#/rules@33"
3556
+ "$ref": "#/rules@35"
3305
3557
  },
3306
3558
  "arguments": []
3307
3559
  }
@@ -3328,7 +3580,7 @@ var loadedDomainGrammar, DomainGrammar = () => loadedDomainGrammar ?? (loadedDom
3328
3580
  {
3329
3581
  "$type": "RuleCall",
3330
3582
  "rule": {
3331
- "$ref": "#/rules@34"
3583
+ "$ref": "#/rules@36"
3332
3584
  },
3333
3585
  "arguments": []
3334
3586
  },
@@ -3388,7 +3640,7 @@ var loadedDomainGrammar, DomainGrammar = () => loadedDomainGrammar ?? (loadedDom
3388
3640
  "terminal": {
3389
3641
  "$type": "RuleCall",
3390
3642
  "rule": {
3391
- "$ref": "#/rules@34"
3643
+ "$ref": "#/rules@36"
3392
3644
  },
3393
3645
  "arguments": []
3394
3646
  }
@@ -3418,7 +3670,7 @@ var loadedDomainGrammar, DomainGrammar = () => loadedDomainGrammar ?? (loadedDom
3418
3670
  "terminal": {
3419
3671
  "$type": "RuleCall",
3420
3672
  "rule": {
3421
- "$ref": "#/rules@34"
3673
+ "$ref": "#/rules@36"
3422
3674
  },
3423
3675
  "arguments": []
3424
3676
  }
@@ -3434,7 +3686,7 @@ var loadedDomainGrammar, DomainGrammar = () => loadedDomainGrammar ?? (loadedDom
3434
3686
  "terminal": {
3435
3687
  "$type": "RuleCall",
3436
3688
  "rule": {
3437
- "$ref": "#/rules@34"
3689
+ "$ref": "#/rules@36"
3438
3690
  },
3439
3691
  "arguments": []
3440
3692
  }
@@ -3481,7 +3733,7 @@ var loadedDomainGrammar, DomainGrammar = () => loadedDomainGrammar ?? (loadedDom
3481
3733
  "terminal": {
3482
3734
  "$type": "RuleCall",
3483
3735
  "rule": {
3484
- "$ref": "#/rules@34"
3736
+ "$ref": "#/rules@36"
3485
3737
  },
3486
3738
  "arguments": []
3487
3739
  }
@@ -3491,7 +3743,7 @@ var loadedDomainGrammar, DomainGrammar = () => loadedDomainGrammar ?? (loadedDom
3491
3743
  {
3492
3744
  "$type": "RuleCall",
3493
3745
  "rule": {
3494
- "$ref": "#/rules@35"
3746
+ "$ref": "#/rules@37"
3495
3747
  },
3496
3748
  "arguments": []
3497
3749
  }
@@ -3514,7 +3766,7 @@ var loadedDomainGrammar, DomainGrammar = () => loadedDomainGrammar ?? (loadedDom
3514
3766
  {
3515
3767
  "$type": "RuleCall",
3516
3768
  "rule": {
3517
- "$ref": "#/rules@36"
3769
+ "$ref": "#/rules@38"
3518
3770
  },
3519
3771
  "arguments": []
3520
3772
  },
@@ -3541,7 +3793,7 @@ var loadedDomainGrammar, DomainGrammar = () => loadedDomainGrammar ?? (loadedDom
3541
3793
  "terminal": {
3542
3794
  "$type": "RuleCall",
3543
3795
  "rule": {
3544
- "$ref": "#/rules@38"
3796
+ "$ref": "#/rules@40"
3545
3797
  },
3546
3798
  "arguments": []
3547
3799
  }
@@ -3575,7 +3827,7 @@ var loadedDomainGrammar, DomainGrammar = () => loadedDomainGrammar ?? (loadedDom
3575
3827
  {
3576
3828
  "$type": "RuleCall",
3577
3829
  "rule": {
3578
- "$ref": "#/rules@29"
3830
+ "$ref": "#/rules@31"
3579
3831
  },
3580
3832
  "arguments": []
3581
3833
  },
@@ -3610,7 +3862,7 @@ var loadedDomainGrammar, DomainGrammar = () => loadedDomainGrammar ?? (loadedDom
3610
3862
  "terminal": {
3611
3863
  "$type": "RuleCall",
3612
3864
  "rule": {
3613
- "$ref": "#/rules@29"
3865
+ "$ref": "#/rules@31"
3614
3866
  },
3615
3867
  "arguments": []
3616
3868
  }
@@ -3646,7 +3898,7 @@ var loadedDomainGrammar, DomainGrammar = () => loadedDomainGrammar ?? (loadedDom
3646
3898
  "terminal": {
3647
3899
  "$type": "RuleCall",
3648
3900
  "rule": {
3649
- "$ref": "#/rules@29"
3901
+ "$ref": "#/rules@31"
3650
3902
  },
3651
3903
  "arguments": []
3652
3904
  }
@@ -3682,7 +3934,7 @@ var loadedDomainGrammar, DomainGrammar = () => loadedDomainGrammar ?? (loadedDom
3682
3934
  "terminal": {
3683
3935
  "$type": "RuleCall",
3684
3936
  "rule": {
3685
- "$ref": "#/rules@29"
3937
+ "$ref": "#/rules@31"
3686
3938
  },
3687
3939
  "arguments": []
3688
3940
  }
@@ -3718,7 +3970,7 @@ var loadedDomainGrammar, DomainGrammar = () => loadedDomainGrammar ?? (loadedDom
3718
3970
  "terminal": {
3719
3971
  "$type": "RuleCall",
3720
3972
  "rule": {
3721
- "$ref": "#/rules@29"
3973
+ "$ref": "#/rules@31"
3722
3974
  },
3723
3975
  "arguments": []
3724
3976
  }
@@ -3734,7 +3986,7 @@ var loadedDomainGrammar, DomainGrammar = () => loadedDomainGrammar ?? (loadedDom
3734
3986
  "terminal": {
3735
3987
  "$type": "RuleCall",
3736
3988
  "rule": {
3737
- "$ref": "#/rules@43"
3989
+ "$ref": "#/rules@45"
3738
3990
  },
3739
3991
  "arguments": []
3740
3992
  }
@@ -3784,7 +4036,7 @@ var loadedDomainGrammar, DomainGrammar = () => loadedDomainGrammar ?? (loadedDom
3784
4036
  "terminal": {
3785
4037
  "$type": "RuleCall",
3786
4038
  "rule": {
3787
- "$ref": "#/rules@29"
4039
+ "$ref": "#/rules@31"
3788
4040
  },
3789
4041
  "arguments": []
3790
4042
  }
@@ -3800,7 +4052,7 @@ var loadedDomainGrammar, DomainGrammar = () => loadedDomainGrammar ?? (loadedDom
3800
4052
  "terminal": {
3801
4053
  "$type": "RuleCall",
3802
4054
  "rule": {
3803
- "$ref": "#/rules@37"
4055
+ "$ref": "#/rules@39"
3804
4056
  },
3805
4057
  "arguments": []
3806
4058
  }
@@ -3816,7 +4068,7 @@ var loadedDomainGrammar, DomainGrammar = () => loadedDomainGrammar ?? (loadedDom
3816
4068
  "terminal": {
3817
4069
  "$type": "RuleCall",
3818
4070
  "rule": {
3819
- "$ref": "#/rules@29"
4071
+ "$ref": "#/rules@31"
3820
4072
  },
3821
4073
  "arguments": []
3822
4074
  }
@@ -3884,7 +4136,7 @@ var loadedDomainGrammar, DomainGrammar = () => loadedDomainGrammar ?? (loadedDom
3884
4136
  "terminal": {
3885
4137
  "$type": "RuleCall",
3886
4138
  "rule": {
3887
- "$ref": "#/rules@41"
4139
+ "$ref": "#/rules@43"
3888
4140
  },
3889
4141
  "arguments": []
3890
4142
  }
@@ -3918,7 +4170,7 @@ var loadedDomainGrammar, DomainGrammar = () => loadedDomainGrammar ?? (loadedDom
3918
4170
  "terminal": {
3919
4171
  "$type": "RuleCall",
3920
4172
  "rule": {
3921
- "$ref": "#/rules@42"
4173
+ "$ref": "#/rules@44"
3922
4174
  },
3923
4175
  "arguments": []
3924
4176
  }
@@ -3942,7 +4194,7 @@ var loadedDomainGrammar, DomainGrammar = () => loadedDomainGrammar ?? (loadedDom
3942
4194
  "terminal": {
3943
4195
  "$type": "RuleCall",
3944
4196
  "rule": {
3945
- "$ref": "#/rules@43"
4197
+ "$ref": "#/rules@45"
3946
4198
  },
3947
4199
  "arguments": []
3948
4200
  }
@@ -3966,7 +4218,7 @@ var loadedDomainGrammar, DomainGrammar = () => loadedDomainGrammar ?? (loadedDom
3966
4218
  "terminal": {
3967
4219
  "$type": "RuleCall",
3968
4220
  "rule": {
3969
- "$ref": "#/rules@38"
4221
+ "$ref": "#/rules@40"
3970
4222
  },
3971
4223
  "arguments": []
3972
4224
  }
@@ -3989,7 +4241,7 @@ var loadedDomainGrammar, DomainGrammar = () => loadedDomainGrammar ?? (loadedDom
3989
4241
  "terminal": {
3990
4242
  "$type": "RuleCall",
3991
4243
  "rule": {
3992
- "$ref": "#/rules@38"
4244
+ "$ref": "#/rules@40"
3993
4245
  },
3994
4246
  "arguments": []
3995
4247
  }
@@ -4008,7 +4260,7 @@ var loadedDomainGrammar, DomainGrammar = () => loadedDomainGrammar ?? (loadedDom
4008
4260
  {
4009
4261
  "$type": "RuleCall",
4010
4262
  "rule": {
4011
- "$ref": "#/rules@44"
4263
+ "$ref": "#/rules@46"
4012
4264
  },
4013
4265
  "arguments": []
4014
4266
  },
@@ -4027,6 +4279,14 @@ var loadedDomainGrammar, DomainGrammar = () => loadedDomainGrammar ?? (loadedDom
4027
4279
  {
4028
4280
  "$type": "Keyword",
4029
4281
  "value": "persistent"
4282
+ },
4283
+ {
4284
+ "$type": "Keyword",
4285
+ "value": "fields"
4286
+ },
4287
+ {
4288
+ "$type": "Keyword",
4289
+ "value": "with"
4030
4290
  }
4031
4291
  ]
4032
4292
  },
@@ -4044,7 +4304,7 @@ var loadedDomainGrammar, DomainGrammar = () => loadedDomainGrammar ?? (loadedDom
4044
4304
  {
4045
4305
  "$type": "RuleCall",
4046
4306
  "rule": {
4047
- "$ref": "#/rules@44"
4307
+ "$ref": "#/rules@46"
4048
4308
  },
4049
4309
  "arguments": []
4050
4310
  },
@@ -4058,7 +4318,7 @@ var loadedDomainGrammar, DomainGrammar = () => loadedDomainGrammar ?? (loadedDom
4058
4318
  {
4059
4319
  "$type": "RuleCall",
4060
4320
  "rule": {
4061
- "$ref": "#/rules@44"
4321
+ "$ref": "#/rules@46"
4062
4322
  },
4063
4323
  "arguments": []
4064
4324
  }
@@ -4191,19 +4451,19 @@ var loadedDomainGrammar, DomainGrammar = () => loadedDomainGrammar ?? (loadedDom
4191
4451
  {
4192
4452
  "$type": "SimpleType",
4193
4453
  "typeRef": {
4194
- "$ref": "#/rules@11"
4454
+ "$ref": "#/rules@13"
4195
4455
  }
4196
4456
  },
4197
4457
  {
4198
4458
  "$type": "SimpleType",
4199
4459
  "typeRef": {
4200
- "$ref": "#/rules@13"
4460
+ "$ref": "#/rules@15"
4201
4461
  }
4202
4462
  },
4203
4463
  {
4204
4464
  "$type": "SimpleType",
4205
4465
  "typeRef": {
4206
- "$ref": "#/rules@14"
4466
+ "$ref": "#/rules@16"
4207
4467
  }
4208
4468
  }
4209
4469
  ]
@@ -4555,6 +4815,17 @@ class ModelIndex {
4555
4815
  get errors() {
4556
4816
  return this.elements.filter(isErrorDecl);
4557
4817
  }
4818
+ get fieldSets() {
4819
+ return this.elements.filter(isFieldSet);
4820
+ }
4821
+ }
4822
+ function fieldSetsOf(el) {
4823
+ return [...new Set(el.fieldSets.map((r) => r.ref).filter((f) => !!f))];
4824
+ }
4825
+ function includedFields(el) {
4826
+ if (isFieldSet(el))
4827
+ return [];
4828
+ return fieldSetsOf(el).flatMap((fieldSet) => fieldsOf(fieldSet.members).map((field) => ({ field, fieldSet })));
4558
4829
  }
4559
4830
  function primitiveInvariants(p) {
4560
4831
  if (p.constraint)
@@ -4613,6 +4884,11 @@ function buildModel(index, fileOf) {
4613
4884
  line: (node.$cstNode?.range.start.line ?? 0) + 1,
4614
4885
  endLine: (node.$cstNode?.range.end.line ?? 0) + 1
4615
4886
  });
4887
+ const included = (el) => includedFields(el).map(({ field: f, fieldSet }) => ({ ...field(f), fieldSet: elementId(fieldSet.$container.name, fieldSet.name) }));
4888
+ const withFieldSets = (el) => {
4889
+ const sets = fieldSetsOf(el);
4890
+ return sets.length && !isFieldSet(el) ? { fieldSets: sets.map((s) => elementId(s.$container.name, s.name)) } : {};
4891
+ };
4616
4892
  for (const el of index.elements) {
4617
4893
  const id = elementId(el.$container.name, el.name);
4618
4894
  if (elements[id])
@@ -4656,14 +4932,16 @@ function buildModel(index, fileOf) {
4656
4932
  };
4657
4933
  });
4658
4934
  } else if (isAggregate(el)) {
4659
- base.fields = commonFields(el).map(field);
4935
+ Object.assign(base, withFieldSets(el));
4936
+ base.fields = [...included(el), ...commonFields(el).map(field)];
4660
4937
  base.invariants = invariantsOf(el.members).map(invariant);
4661
4938
  base.states = statesOf(el).map((s) => state(id, s, loc, field));
4662
4939
  base.commands = commandsOf(el).map((c) => command(id, c, loc, field));
4663
4940
  } else {
4941
+ Object.assign(base, withFieldSets(el));
4664
4942
  if (isEventDecl(el) && el.persistent)
4665
4943
  base.persistent = true;
4666
- base.fields = fieldsOf(el.members).map(field);
4944
+ base.fields = [...included(el), ...fieldsOf(el.members).map(field)];
4667
4945
  base.invariants = invariantsOf(el.members).map(invariant);
4668
4946
  }
4669
4947
  elements[id] = base;
@@ -4704,6 +4982,8 @@ function kindOf(el) {
4704
4982
  return "event";
4705
4983
  if (isErrorDecl(el))
4706
4984
  return "error";
4985
+ if (isFieldSet(el))
4986
+ return "fieldSet";
4707
4987
  throw new Error(`unknown element ${el.$type}`);
4708
4988
  }
4709
4989
  function typeExpr(ref) {
@@ -4817,6 +5097,227 @@ var init_commands = __esm(() => {
4817
5097
  init_model_index();
4818
5098
  });
4819
5099
 
5100
+ // src/generator/naming.ts
5101
+ function generatedNames(index, ctx) {
5102
+ const out = [];
5103
+ const seen = new Set;
5104
+ for (const el of index.elementsOf(ctx)) {
5105
+ if (seen.has(el.name))
5106
+ continue;
5107
+ seen.add(el.name);
5108
+ if (!isAggregate(el)) {
5109
+ out.push({ name: el.name, origin: `${KIND_LABELS[el.$type]} '${el.name}'`, node: el });
5110
+ if (isIdType(el) || isPrimitiveDecl(el)) {
5111
+ out.push({ name: makeTypeName(el), origin: `the constructor of '${el.name}'`, node: el });
5112
+ if (primitiveInvariants(el).length)
5113
+ out.push({ name: invalidTypeName(el), origin: `the error of '${el.name}'`, node: el });
5114
+ }
5115
+ continue;
5116
+ }
5117
+ const states = firstByName(statesOf(el));
5118
+ out.push({ name: el.name, origin: `aggregate '${el.name}'`, node: el });
5119
+ if (states.length > 0) {
5120
+ out.push({ name: commonTypeName(el), origin: `common fields of '${el.name}'`, node: el });
5121
+ for (const s of states) {
5122
+ out.push({ name: stateTypeName(el, s), origin: `state '${el.name}.${s.name}'`, node: s });
5123
+ }
5124
+ }
5125
+ const commands = firstByName(commandsOf(el));
5126
+ if (commands.length > 0) {
5127
+ out.push({ name: commandsInterfaceName(el), origin: `commands of '${el.name}'`, node: el });
5128
+ }
5129
+ for (const c of commands) {
5130
+ out.push({ name: commandTypeName(el, c), origin: `command '${el.name}.${c.name}'`, node: c });
5131
+ }
5132
+ if (commands.some((c) => c.emits.length > 0)) {
5133
+ out.push({ name: aggregateEventTypeName(el), origin: `the union of the events of '${el.name}'`, node: el });
5134
+ }
5135
+ }
5136
+ const persistent = index.elementsOf(ctx).find((el) => isEventDecl(el) && el.persistent);
5137
+ if (persistent)
5138
+ out.push({ name: PERSISTENT_EVENT_TYPE, origin: "the union of persistent events", node: persistent });
5139
+ const event = index.elementsOf(ctx).find(isEventDecl);
5140
+ if (event)
5141
+ out.push({ name: DOMAIN_EVENT_TYPE, origin: "the union of the events", node: event });
5142
+ const aggregate = index.elementsOf(ctx).find(isAggregate);
5143
+ if (aggregate)
5144
+ out.push({ name: AGGREGATE_TYPE, origin: "the union of the aggregates", node: aggregate });
5145
+ return out;
5146
+ }
5147
+ function firstByName(items) {
5148
+ const seen = new Set;
5149
+ return items.filter((i) => !seen.has(i.name) && seen.add(i.name));
5150
+ }
5151
+ var RUNTIME_NAMES, EVENT_TAG = "type", STATE_TAG = "state", pascal = (s) => s.charAt(0).toUpperCase() + s.slice(1), camel = (s) => s.charAt(0).toLowerCase() + s.slice(1), commonTypeName = (agg) => `${agg.name}Common`, stateTypeName = (agg, state) => `${typeof state === "string" ? state : state.name}${agg.name}`, commandTypeName = (agg, cmd) => `${pascal(cmd.name)}${agg.name}`, commandsInterfaceName = (agg) => `${agg.name}Commands`, aggregateParamName = (agg) => camel(agg.name), makeTypeName = (p) => `Make${p.name}`, invalidTypeName = (p) => `Invalid${p.name}`, PERSISTENT_EVENT_TYPE = "PersistentEvent", DOMAIN_EVENT_TYPE = "DomainEvent", AGGREGATE_TYPE = "Aggregate", aggregateEventTypeName = (agg) => `${agg.name}Event`, KIND_LABELS, TS_RESERVED;
5152
+ var init_naming = __esm(() => {
5153
+ init_ast();
5154
+ init_model_index();
5155
+ RUNTIME_NAMES = ["Result", "Ok", "Err", "Decimal", "Timestamp", "ok", "err"];
5156
+ KIND_LABELS = {
5157
+ IdType: "id",
5158
+ PrimitiveDecl: "primitive",
5159
+ EnumDecl: "enum",
5160
+ ValueObject: "value object",
5161
+ UnionDecl: "union",
5162
+ Entity: "entity",
5163
+ EventDecl: "event",
5164
+ ErrorDecl: "error",
5165
+ FieldSet: "field set"
5166
+ };
5167
+ TS_RESERVED = new Set([
5168
+ "break",
5169
+ "case",
5170
+ "catch",
5171
+ "class",
5172
+ "const",
5173
+ "continue",
5174
+ "debugger",
5175
+ "default",
5176
+ "delete",
5177
+ "do",
5178
+ "else",
5179
+ "enum",
5180
+ "export",
5181
+ "extends",
5182
+ "false",
5183
+ "finally",
5184
+ "for",
5185
+ "function",
5186
+ "if",
5187
+ "import",
5188
+ "in",
5189
+ "instanceof",
5190
+ "new",
5191
+ "null",
5192
+ "return",
5193
+ "super",
5194
+ "switch",
5195
+ "this",
5196
+ "throw",
5197
+ "true",
5198
+ "try",
5199
+ "typeof",
5200
+ "var",
5201
+ "void",
5202
+ "while",
5203
+ "with",
5204
+ "yield",
5205
+ "let",
5206
+ "static",
5207
+ "implements",
5208
+ "interface",
5209
+ "package",
5210
+ "private",
5211
+ "protected",
5212
+ "public",
5213
+ "await",
5214
+ "any",
5215
+ "boolean",
5216
+ "number",
5217
+ "string",
5218
+ "symbol",
5219
+ "never",
5220
+ "unknown",
5221
+ "object",
5222
+ "undefined",
5223
+ "bigint"
5224
+ ]);
5225
+ });
5226
+
5227
+ // src/core/checker/events.ts
5228
+ function checkEventIds(index, sink) {
5229
+ for (const agg of index.aggregates) {
5230
+ const idType = identityField(agg)?.type?.decl?.ref;
5231
+ if (!idType || !isIdType(idType))
5232
+ continue;
5233
+ const checked = new Set;
5234
+ for (const cmd of commandsOf(agg)) {
5235
+ cmd.emits.forEach((r, i) => {
5236
+ const ev = r.ref;
5237
+ if (!ev || checked.has(ev))
5238
+ return;
5239
+ checked.add(ev);
5240
+ const fields = [...includedFields(ev).map((x) => x.field), ...ev.members];
5241
+ if (fields.some((f) => f.type?.decl?.ref === idType))
5242
+ return;
5243
+ const typeName = idType.$container.name === ev.$container.name ? idType.name : `${idType.$container.name}.${idType.name}`;
5244
+ sink.warning("M017", `Event '${ev.name}' emitted by '${agg.name}.${cmd.name}' has no field of type '${idType.name}' to tell which '${agg.name}' it is about (e.g. '${camel(agg.name)}Id: ${typeName}').`, cmd, "emits", i);
5245
+ });
5246
+ }
5247
+ }
5248
+ }
5249
+ var init_events = __esm(() => {
5250
+ init_ast();
5251
+ init_naming();
5252
+ init_model_index();
5253
+ });
5254
+
5255
+ // src/core/checker/field-sets.ts
5256
+ function checkFieldSets(index, sink) {
5257
+ for (const fs of index.fieldSets) {
5258
+ for (const m of fs.members) {
5259
+ if (isInvariant(m)) {
5260
+ sink.error("M016", `Field set '${fs.name}' cannot hold invariants; write invariant '${m.name}' in the elements that use it.`, m, "name");
5261
+ } else if (isOwnsField(m) || isReferenceField(m)) {
5262
+ const keyword = isOwnsField(m) ? "owns" : "references";
5263
+ sink.error("M016", `A field set holds plain fields only; '${m.name}' is declared with '${keyword}'.`, m, "name");
5264
+ } else if (m.name === "id") {
5265
+ sink.error("M016", `Field set '${fs.name}' cannot declare 'id'; the identity is declared by each aggregate and entity itself.`, m, "name");
5266
+ }
5267
+ }
5268
+ }
5269
+ for (const el of index.elements) {
5270
+ if (!("fieldSets" in el) || el.fieldSets.length === 0)
5271
+ continue;
5272
+ if (isFieldSet(el) || isValueObject(el) || isErrorDecl(el)) {
5273
+ const what = isFieldSet(el) ? `field set '${el.name}' cannot include other field sets` : `${isValueObject(el) ? "value object" : "error"} '${el.name}' cannot take field sets`;
5274
+ sink.error("M016", `'with' is only for aggregates, entities and events; ${what}.`, el, "fieldSets");
5275
+ continue;
5276
+ }
5277
+ if (isAggregate(el) || isEntity(el) || isEventDecl(el))
5278
+ checkUses(el, sink);
5279
+ }
5280
+ }
5281
+ function checkUses(el, sink) {
5282
+ const seen = new Set;
5283
+ el.fieldSets.forEach((r, i) => {
5284
+ if (!r.ref)
5285
+ return;
5286
+ if (seen.has(r.ref))
5287
+ sink.warning("M016", `Field set '${r.$refText}' is listed more than once.`, el, "fieldSets", i);
5288
+ seen.add(r.ref);
5289
+ });
5290
+ const from = new Map;
5291
+ for (const { field, fieldSet } of includedFields(el)) {
5292
+ const first = from.get(field.name);
5293
+ if (first === undefined) {
5294
+ from.set(field.name, fieldSet.name);
5295
+ } else if (first !== fieldSet.name) {
5296
+ const at = el.fieldSets.findIndex((r) => r.ref === fieldSet);
5297
+ sink.error("M016", `Field '${field.name}' of field set '${fieldSet.name}' is also declared in field set '${first}', both used by '${el.name}'.`, el, "fieldSets", at);
5298
+ }
5299
+ }
5300
+ const own = isAggregate(el) ? commonFields(el) : fieldsOf(el.members);
5301
+ for (const f of own) {
5302
+ const fs = from.get(f.name);
5303
+ if (fs)
5304
+ sink.error("M016", `Field '${f.name}' of '${el.name}' is already taken from field set '${fs}'.`, f, "name");
5305
+ }
5306
+ if (isAggregate(el)) {
5307
+ for (const s of statesOf(el)) {
5308
+ for (const f of fieldsOf(s.members)) {
5309
+ const fs = from.get(f.name);
5310
+ if (fs)
5311
+ sink.error("M016", `Field '${f.name}' of state '${s.name}' shadows the field of field set '${fs}' in '${el.name}'.`, f, "name");
5312
+ }
5313
+ }
5314
+ }
5315
+ }
5316
+ var init_field_sets = __esm(() => {
5317
+ init_ast();
5318
+ init_model_index();
5319
+ });
5320
+
4820
5321
  // src/core/checker/expressions.ts
4821
5322
  import { GrammarUtils } from "langium";
4822
5323
  function checkInvariants(index, sink) {
@@ -4826,7 +5327,7 @@ function checkInvariants(index, sink) {
4826
5327
  checkAggregate(el, ctx, index, sink);
4827
5328
  } else if (isEntity(el) || isValueObject(el)) {
4828
5329
  const members = el.members;
4829
- const fields = new Map(fieldsOf(members).map((f) => [f.name, f]));
5330
+ const fields = new Map([...includedFields(el).map((x) => x.field), ...fieldsOf(members)].map((f) => [f.name, f]));
4830
5331
  for (const inv of invariantsOf(members)) {
4831
5332
  checkInvariant(inv, { ctx, fields, stateOnly: new Map, lambdas: [], present: new Set }, index, sink);
4832
5333
  }
@@ -4863,7 +5364,7 @@ function checkPrimitive(p, ctx, index, sink) {
4863
5364
  }
4864
5365
  }
4865
5366
  function checkAggregate(agg, ctx, index, sink) {
4866
- const common = new Map(commonFields(agg).map((f) => [f.name, f]));
5367
+ const common = new Map([...includedFields(agg).map((x) => x.field), ...commonFields(agg)].map((f) => [f.name, f]));
4867
5368
  const states = statesOf(agg);
4868
5369
  const stateOnly = (except) => {
4869
5370
  const m = new Map;
@@ -5085,7 +5586,7 @@ class ExprChecker {
5085
5586
  return ERROR;
5086
5587
  }
5087
5588
  case "struct": {
5088
- const f = fieldsOf(recv.decl.members).find((x) => x.name === m);
5589
+ const f = [...includedFields(recv.decl).map((x) => x.field), ...fieldsOf(recv.decl.members)].find((x) => x.name === m);
5089
5590
  if (f)
5090
5591
  return narrow(memberType(f), pathOf(e) ?? "", scope);
5091
5592
  this.sink.error("M001", `'${recv.decl.name}' has no field '${m}'.`, e, "member");
@@ -5214,11 +5715,12 @@ function checkLabels(index, sink) {
5214
5715
  sameLabel(invariantsOf(v.members).map((i) => ({ node: i, name: i.name, label: i.label })), `the invariants of '${el.name}.${v.name}'`, sink);
5215
5716
  }
5216
5717
  } else if (isAggregate(el)) {
5718
+ const included = includedFields(el).map((x) => x.field);
5217
5719
  const common = commonFields(el);
5218
5720
  const states = statesOf(el);
5219
- fieldScope(common, `'${el.name}'`);
5721
+ fieldScope(common, `'${el.name}'`, included);
5220
5722
  for (const s of states)
5221
- fieldScope(fieldsOf(s.members), `state '${el.name}.${s.name}'`, common);
5723
+ fieldScope(fieldsOf(s.members), `state '${el.name}.${s.name}'`, [...included, ...common]);
5222
5724
  sameLabel(states.map((s) => ({ node: s, name: s.name, label: s.label })), `the states of '${el.name}'`, sink);
5223
5725
  sameLabel(commandsOf(el).map((c) => ({ node: c, name: c.name, label: c.label })), `the commands of '${el.name}'`, sink);
5224
5726
  const invariants = [...invariantsOf(el.members), ...states.flatMap((s) => invariantsOf(s.members))];
@@ -5226,7 +5728,7 @@ function checkLabels(index, sink) {
5226
5728
  for (const c of commandsOf(el))
5227
5729
  fieldScope(c.params, `command '${el.name}.${c.name}'`);
5228
5730
  } else if ("members" in el) {
5229
- fieldScope(fieldsOf(el.members), `'${el.name}'`);
5731
+ fieldScope(fieldsOf(el.members), `'${el.name}'`, includedFields(el).map((x) => x.field));
5230
5732
  if (isEntity(el) || isValueObject(el)) {
5231
5733
  sameLabel(invariantsOf(el.members).map((i) => ({ node: i, name: i.name, label: i.label })), `the invariants of '${el.name}'`, sink);
5232
5734
  }
@@ -5355,7 +5857,7 @@ function checkShared(index, sink) {
5355
5857
  const ctx = el.$container.name;
5356
5858
  if (!shared.has(ctx))
5357
5859
  continue;
5358
- if (!isPrimitiveDecl(el) && !isEnumDecl(el) && !isValueObject(el) && !isUnionDecl(el)) {
5860
+ if (!isPrimitiveDecl(el) && !isEnumDecl(el) && !isValueObject(el) && !isUnionDecl(el) && !isFieldSet(el)) {
5359
5861
  sink.error("M014", `Shared context '${ctx}' can only contain ${ALLOWED}; found ${kind(el)} '${el.name}'.`, el, "name");
5360
5862
  }
5361
5863
  for (const ref of AstUtils4.streamAllContents(el).filter(isTypeRef)) {
@@ -5384,7 +5886,7 @@ function kind(el) {
5384
5886
  const names = { Aggregate: "aggregate", Entity: "entity", IdType: "ID", EventDecl: "event", ErrorDecl: "error" };
5385
5887
  return names[el.$type] ?? el.$type;
5386
5888
  }
5387
- var ALLOWED = "domain primitives, enums, value objects, unions and terms";
5889
+ var ALLOWED = "domain primitives, enums, value objects, unions, field sets and terms";
5388
5890
  var init_shared = __esm(() => {
5389
5891
  init_ast();
5390
5892
  });
@@ -5403,6 +5905,11 @@ function checkStructure(index, sink) {
5403
5905
  for (const f of allFields2(el))
5404
5906
  checkFieldKind(el, f, sink);
5405
5907
  }
5908
+ for (const fs of index.fieldSets) {
5909
+ for (const f of fieldsOf(fs.members))
5910
+ if (f.$type === "Field")
5911
+ checkFieldKind(fs, f, sink);
5912
+ }
5406
5913
  checkPayloads(index, sink);
5407
5914
  checkIdentity(index, sink);
5408
5915
  checkOwningAggregates(index, sink);
@@ -5561,123 +6068,6 @@ var init_structure = __esm(() => {
5561
6068
  init_model_index();
5562
6069
  });
5563
6070
 
5564
- // src/generator/naming.ts
5565
- function generatedNames(index, ctx) {
5566
- const out = [];
5567
- const seen = new Set;
5568
- for (const el of index.elementsOf(ctx)) {
5569
- if (seen.has(el.name))
5570
- continue;
5571
- seen.add(el.name);
5572
- if (!isAggregate(el)) {
5573
- out.push({ name: el.name, origin: `${KIND_LABELS[el.$type]} '${el.name}'`, node: el });
5574
- if (isIdType(el) || isPrimitiveDecl(el)) {
5575
- out.push({ name: makeTypeName(el), origin: `the constructor of '${el.name}'`, node: el });
5576
- if (primitiveInvariants(el).length)
5577
- out.push({ name: invalidTypeName(el), origin: `the error of '${el.name}'`, node: el });
5578
- }
5579
- continue;
5580
- }
5581
- const states = firstByName(statesOf(el));
5582
- out.push({ name: el.name, origin: `aggregate '${el.name}'`, node: el });
5583
- if (states.length > 0) {
5584
- out.push({ name: commonTypeName(el), origin: `common fields of '${el.name}'`, node: el });
5585
- for (const s of states) {
5586
- out.push({ name: stateTypeName(el, s), origin: `state '${el.name}.${s.name}'`, node: s });
5587
- }
5588
- }
5589
- const commands = firstByName(commandsOf(el));
5590
- if (commands.length > 0) {
5591
- out.push({ name: commandsInterfaceName(el), origin: `commands of '${el.name}'`, node: el });
5592
- }
5593
- for (const c of commands) {
5594
- out.push({ name: commandTypeName(el, c), origin: `command '${el.name}.${c.name}'`, node: c });
5595
- }
5596
- }
5597
- const persistent = index.elementsOf(ctx).find((el) => isEventDecl(el) && el.persistent);
5598
- if (persistent)
5599
- out.push({ name: PERSISTENT_EVENT_TYPE, origin: "the union of persistent events", node: persistent });
5600
- return out;
5601
- }
5602
- function firstByName(items) {
5603
- const seen = new Set;
5604
- return items.filter((i) => !seen.has(i.name) && seen.add(i.name));
5605
- }
5606
- var RUNTIME_NAMES, EVENT_TAG = "type", STATE_TAG = "state", pascal = (s) => s.charAt(0).toUpperCase() + s.slice(1), camel = (s) => s.charAt(0).toLowerCase() + s.slice(1), commonTypeName = (agg) => `${agg.name}Common`, stateTypeName = (agg, state) => `${typeof state === "string" ? state : state.name}${agg.name}`, commandTypeName = (agg, cmd) => `${pascal(cmd.name)}${agg.name}`, commandsInterfaceName = (agg) => `${agg.name}Commands`, aggregateParamName = (agg) => camel(agg.name), makeTypeName = (p) => `Make${p.name}`, invalidTypeName = (p) => `Invalid${p.name}`, PERSISTENT_EVENT_TYPE = "PersistentEvent", KIND_LABELS, TS_RESERVED;
5607
- var init_naming = __esm(() => {
5608
- init_ast();
5609
- init_model_index();
5610
- RUNTIME_NAMES = ["Result", "Ok", "Err", "Decimal", "Timestamp", "ok", "err"];
5611
- KIND_LABELS = {
5612
- IdType: "id",
5613
- PrimitiveDecl: "primitive",
5614
- EnumDecl: "enum",
5615
- ValueObject: "value object",
5616
- UnionDecl: "union",
5617
- Entity: "entity",
5618
- EventDecl: "event",
5619
- ErrorDecl: "error"
5620
- };
5621
- TS_RESERVED = new Set([
5622
- "break",
5623
- "case",
5624
- "catch",
5625
- "class",
5626
- "const",
5627
- "continue",
5628
- "debugger",
5629
- "default",
5630
- "delete",
5631
- "do",
5632
- "else",
5633
- "enum",
5634
- "export",
5635
- "extends",
5636
- "false",
5637
- "finally",
5638
- "for",
5639
- "function",
5640
- "if",
5641
- "import",
5642
- "in",
5643
- "instanceof",
5644
- "new",
5645
- "null",
5646
- "return",
5647
- "super",
5648
- "switch",
5649
- "this",
5650
- "throw",
5651
- "true",
5652
- "try",
5653
- "typeof",
5654
- "var",
5655
- "void",
5656
- "while",
5657
- "with",
5658
- "yield",
5659
- "let",
5660
- "static",
5661
- "implements",
5662
- "interface",
5663
- "package",
5664
- "private",
5665
- "protected",
5666
- "public",
5667
- "await",
5668
- "any",
5669
- "boolean",
5670
- "number",
5671
- "string",
5672
- "symbol",
5673
- "never",
5674
- "unknown",
5675
- "object",
5676
- "undefined",
5677
- "bigint"
5678
- ]);
5679
- });
5680
-
5681
6071
  // src/core/checker/tsnames.ts
5682
6072
  function checkTsNames(index, sink) {
5683
6073
  const contexts = index.contextNames;
@@ -5702,11 +6092,18 @@ function checkTsNames(index, sink) {
5702
6092
  }
5703
6093
  }
5704
6094
  for (const el of [...index.events, ...index.errors]) {
6095
+ const kind = el.$type === "EventDecl" ? "event" : "error";
5705
6096
  for (const f of el.members) {
5706
6097
  if (f.name === EVENT_TAG) {
5707
- sink.error("M011", `Field '${EVENT_TAG}' is reserved for the discriminant of generated ${el.$type === "EventDecl" ? "event" : "error"} types.`, f, "name");
6098
+ sink.error("M011", `Field '${EVENT_TAG}' is reserved for the discriminant of generated ${kind} types.`, f, "name");
5708
6099
  }
5709
6100
  }
6101
+ for (const { field, fieldSet } of includedFields(el)) {
6102
+ if (field.name !== EVENT_TAG)
6103
+ continue;
6104
+ const at = el.fieldSets.findIndex((r) => r.ref === fieldSet);
6105
+ sink.error("M011", `Field '${EVENT_TAG}' of field set '${fieldSet.name}' is reserved for the discriminant of generated ${kind} types.`, el, "fieldSets", at);
6106
+ }
5710
6107
  }
5711
6108
  for (const agg of index.elements.filter(isAggregate)) {
5712
6109
  const self = aggregateParamName(agg);
@@ -5857,7 +6254,9 @@ async function analyze(sources) {
5857
6254
  checkShared(index, sink);
5858
6255
  checkStructure(index, sink);
5859
6256
  checkUnions(index, sink);
6257
+ checkFieldSets(index, sink);
5860
6258
  checkCommands(index, sink);
6259
+ checkEventIds(index, sink);
5861
6260
  checkInvariants(index, sink);
5862
6261
  checkTsNames(index, sink);
5863
6262
  checkLabels(index, sink);
@@ -5910,6 +6309,8 @@ var init_analyze = __esm(() => {
5910
6309
  init_build();
5911
6310
  init_ids();
5912
6311
  init_commands();
6312
+ init_events();
6313
+ init_field_sets();
5913
6314
  init_expressions();
5914
6315
  init_labels2();
5915
6316
  init_names();
@@ -5923,13 +6324,15 @@ var init_analyze = __esm(() => {
5923
6324
  from: "M006",
5924
6325
  to: "M006",
5925
6326
  emits: "M007",
5926
- errors: "M007"
6327
+ errors: "M007",
6328
+ fieldSets: "M016"
5927
6329
  };
5928
6330
  LINK_KINDS = {
5929
6331
  from: "state",
5930
6332
  to: "state",
5931
6333
  emits: "event",
5932
6334
  errors: "error",
6335
+ fieldSets: "field set",
5933
6336
  target: "aggregate",
5934
6337
  decl: "type"
5935
6338
  };
@@ -6134,7 +6537,7 @@ var init_files = __esm(() => {
6134
6537
  });
6135
6538
 
6136
6539
  // src/model/model.ts
6137
- var elementsIn = (model, ctx) => Object.values(model.elements).filter((e) => e.context === ctx), elementList = (model) => Object.values(model.elements), allFieldsOf = (el) => [
6540
+ var elementsIn = (model, ctx) => Object.values(model.elements).filter((e) => e.context === ctx), elementList = (model) => Object.values(model.elements), ownFields = (el) => el.fields.filter((f) => !f.fieldSet), allFieldsOf = (el) => [
6138
6541
  ...el.fields,
6139
6542
  ...(el.states ?? []).flatMap((s) => s.fields),
6140
6543
  ...(el.variants ?? []).flatMap((v) => v.fields)
@@ -6308,8 +6711,10 @@ function contextDependencies(model) {
6308
6711
  else if (f.type.kind === "ref")
6309
6712
  add(f.type.ref, path);
6310
6713
  };
6311
- for (const f of el.fields)
6714
+ for (const f of ownFields(el))
6312
6715
  field(f, f.name);
6716
+ for (const fs of el.fieldSets ?? [])
6717
+ add(fs, "with");
6313
6718
  for (const s of el.states ?? [])
6314
6719
  for (const f of s.fields)
6315
6720
  field(f, `${s.name}.${f.name}`);
@@ -6382,13 +6787,14 @@ function fieldLine(f, ctx, model, indent = "") {
6382
6787
  label: `${marker}${f.label ?? f.name}`,
6383
6788
  both: `${marker}${f.label ? `${f.label} ` : ""}${f.name}`
6384
6789
  }),
6385
- value: anyLang({ name: byName + f.multiplicity, label: byLabel + f.multiplicity, both: byName + f.multiplicity })
6790
+ value: anyLang({ name: byName + f.multiplicity, label: byLabel + f.multiplicity, both: byName + f.multiplicity }),
6791
+ ...f.fieldSet && { origin: named(typeText({ kind: "ref", ref: f.fieldSet, text: "" }, ctx, model.sharedContexts), lookupLabel(model, f.fieldSet), (l) => l) }
6386
6792
  };
6387
6793
  }
6388
6794
  function bodyUnits(lines) {
6389
6795
  return Math.max(0, ...TEXT_VARIANTS.map(([g, m]) => {
6390
6796
  const key = Math.max(0, ...lines.filter((l) => l.value).map((l) => textUnits(l.key[g][m])));
6391
- const value = Math.max(0, ...lines.map((l) => l.value ? textUnits(l.value[g][m]) : 0));
6797
+ const value = Math.max(0, ...lines.map((l) => l.value ? textUnits(l.value[g][m]) + (l.origin ? COLUMN_GAP + textUnits(l.origin[g][m]) : 0) : 0));
6392
6798
  const keyOnly = Math.max(0, ...lines.filter((l) => !l.value).map((l) => textUnits(l.key[g][m])));
6393
6799
  return Math.max(value ? key + COLUMN_GAP + value : 0, keyOnly);
6394
6800
  }));
@@ -6784,7 +7190,8 @@ var init_build2 = __esm(() => {
6784
7190
  primitive: stereotype("ドメインプリミティブ", "primitive"),
6785
7191
  id: stereotype("ID", "id"),
6786
7192
  event: stereotype("ドメインイベント", "event"),
6787
- error: stereotype("エラー", "error")
7193
+ error: stereotype("エラー", "error"),
7194
+ fieldSet: stereotype("項目セット", "field set")
6788
7195
  };
6789
7196
  });
6790
7197
 
@@ -7398,7 +7805,11 @@ class ContextEmitter {
7398
7805
  case "valueObject":
7399
7806
  case "entity":
7400
7807
  this.jsdoc([...describedLines(el), ...invariantLines(el.invariants)]);
7401
- this.iface(el.name, undefined, [], el.fields);
7808
+ this.iface(el.name, this.fieldSets(el), [], ownFields(el));
7809
+ break;
7810
+ case "fieldSet":
7811
+ this.jsdoc([...describedLines(el), `Fields taken on with \`with ${el.name}\`.`]);
7812
+ this.iface(el.name, [], [], el.fields);
7402
7813
  break;
7403
7814
  case "union":
7404
7815
  this.union(el);
@@ -7406,7 +7817,7 @@ class ContextEmitter {
7406
7817
  case "event":
7407
7818
  case "error":
7408
7819
  this.jsdoc([...describedLines(el), ...el.persistent ? [PERSISTENT_LINE] : []]);
7409
- this.iface(el.name, undefined, [`readonly ${EVENT_TAG}: '${el.name}';`], el.fields);
7820
+ this.iface(el.name, this.fieldSets(el), [`readonly ${EVENT_TAG}: '${el.name}';`], ownFields(el));
7410
7821
  break;
7411
7822
  case "aggregate":
7412
7823
  this.aggregate(el);
@@ -7415,6 +7826,7 @@ class ContextEmitter {
7415
7826
  this.out.push("");
7416
7827
  }
7417
7828
  this.persistentEvents();
7829
+ this.unions();
7418
7830
  const body = this.out.join(`
7419
7831
  `);
7420
7832
  const runtime = ["Decimal", "Result", "Timestamp"].filter((n) => new RegExp(`\\b${n}\\b`).test(body));
@@ -7433,6 +7845,24 @@ class ContextEmitter {
7433
7845
  this.line(`export type ${PERSISTENT_EVENT_TYPE} = ${events.map((e) => e.name).join(" | ")};`);
7434
7846
  this.out.push("");
7435
7847
  }
7848
+ unions() {
7849
+ const els = elementsIn(this.model, this.ctx);
7850
+ const events = els.filter((el) => el.kind === "event");
7851
+ if (events.length) {
7852
+ this.jsdoc([`Events of ${this.ctx}.`]);
7853
+ this.line(`export type ${DOMAIN_EVENT_TYPE} = ${events.map((e) => e.name).join(" | ")};`);
7854
+ this.out.push("");
7855
+ }
7856
+ const aggregates = els.filter((el) => el.kind === "aggregate");
7857
+ if (aggregates.length) {
7858
+ this.jsdoc([`Aggregates of ${this.ctx}.`]);
7859
+ this.line(`export type ${AGGREGATE_TYPE} = ${aggregates.map((e) => e.name).join(" | ")};`);
7860
+ this.out.push("");
7861
+ }
7862
+ }
7863
+ fieldSets(el) {
7864
+ return (el.fieldSets ?? []).map((f) => this.ref(f));
7865
+ }
7436
7866
  primitive(p) {
7437
7867
  const base = PRIMITIVES[p.base ?? "String"];
7438
7868
  const summary = p.kind === "id" && !p.label ? [`Identifier of ${p.name}.`] : [];
@@ -7487,14 +7917,14 @@ class ContextEmitter {
7487
7917
  const states = agg.states ?? [];
7488
7918
  if (states.length === 0) {
7489
7919
  this.jsdoc([...describedLines(agg), ...invariantLines(agg.invariants)]);
7490
- this.iface(agg.name, undefined, [], agg.fields);
7920
+ this.iface(agg.name, this.fieldSets(agg), [], ownFields(agg));
7491
7921
  } else {
7492
7922
  this.jsdoc([`Fields shared by every state of ${agg.label ? `${agg.label} (${agg.name})` : agg.name}.`, ...invariantLines(agg.invariants)]);
7493
- this.iface(commonTypeName(agg), undefined, [], agg.fields);
7923
+ this.iface(commonTypeName(agg), this.fieldSets(agg), [], ownFields(agg));
7494
7924
  for (const s of states) {
7495
7925
  this.out.push("");
7496
7926
  this.jsdoc([...describedLines(s), ...invariantLines(s.invariants)]);
7497
- this.iface(stateTypeName(agg, s), commonTypeName(agg), [`readonly ${STATE_TAG}: '${s.name}';`], s.fields);
7927
+ this.iface(stateTypeName(agg, s), [commonTypeName(agg)], [`readonly ${STATE_TAG}: '${s.name}';`], s.fields);
7498
7928
  }
7499
7929
  this.out.push("");
7500
7930
  this.jsdoc(describedLines(agg));
@@ -7516,6 +7946,12 @@ class ContextEmitter {
7516
7946
  }
7517
7947
  this.line("}");
7518
7948
  }
7949
+ const events = [...new Set(commands.flatMap((c) => c.emits))];
7950
+ if (events.length > 0) {
7951
+ this.out.push("");
7952
+ this.jsdoc([`Events that the commands of ${agg.name} may emit.`]);
7953
+ this.line(`export type ${aggregateEventTypeName(agg)} = ${events.map((e) => this.ref(e)).join(" | ")};`);
7954
+ }
7519
7955
  }
7520
7956
  command(agg, c) {
7521
7957
  const stateful = (agg.states ?? []).length > 0;
@@ -7540,9 +7976,9 @@ class ContextEmitter {
7540
7976
  this.line(` ${p},`);
7541
7977
  this.line(`) => Result<readonly [${output}, ${eventArray}], ${errors}>;`);
7542
7978
  }
7543
- iface(name, base, extra, fields) {
7979
+ iface(name, bases, extra, fields) {
7544
7980
  const lines = [...extra, ...fields.flatMap((f) => this.property(f))];
7545
- const ext = base ? ` extends ${base}` : "";
7981
+ const ext = bases.length ? ` extends ${bases.join(", ")}` : "";
7546
7982
  if (lines.length === 0) {
7547
7983
  this.line(`export interface ${name}${ext} {}`);
7548
7984
  return;
@@ -7599,7 +8035,7 @@ class ContextEmitter {
7599
8035
  }
7600
8036
 
7601
8037
  // docs/guide.md
7602
- var guide_default = "# DomainTrail guide\n\n`dt` checks domain models written in the DomainTrail DSL (`.dt` files) and generates TypeScript types and command\ncontracts from them. The DSL describes domain **structure and contracts** only — never business logic, which is written\nby hand against the generated types.\n\nThis guide is what `dt guide` prints. It is written for people and AI agents using `dt` without other documentation.\n\n## Workflow\n\n1. Write or edit `.dt` files (see [DSL](#dsl) and [File layout](#file-layout-recommended)).\n2. Run `dt check` and fix every reported problem until it exits 0.\n3. Run `dt generate ts` to write the TypeScript (it runs `check` first and writes nothing on errors).\n4. Implement the generated contracts in your own code, and type-check that code with your own TypeScript setup\n (e.g. `tsc --noEmit`). `dt` does not run the TypeScript compiler.\n\n`dt view` starts the Live View, a browser page where people watch the model update as files are saved. It is a server\nthat keeps running and never exits by itself (stop it with Ctrl+C), so do not wait for it to finish: run it in the\nbackground, or use `dt check` for a result.\n\n`dt --help` and `dt <command> --help` list the options with examples.\n\n```bash\ndt check # every *.dt file below the current directory\ndt -r domain check # below domain/ (or as configured by a domaintrail.jsonc found there or above)\ndt generate ts # into <root>/generated/domain\ndt generate ts --out src/domain/generated\ndt view --port 8080 # http://127.0.0.1:8080, until Ctrl+C\n```\n\n## Output and exit codes\n\n`check` (and `generate ts`, which checks first) prints one line per problem, sorted by file and position, then a\nsummary:\n\n```text\nsales/order.dt:2:11 - warning L002: Term 'note' (\"備考\") is not used by any field or parameter in context 'Sales'.\nsales/order.dt:8:32 - error M009: count() requires a collection, but got 'Money'.\n1 file(s) checked: 1 error(s), 1 warning(s).\n```\n\nPaths are relative to the root, lines and columns 1-based. Errors go to stderr, warnings to stdout. Fix errors first;\nwarnings do not fail the check. Other failures (missing root, invalid config, port in use, …) are one line on stderr.\n\n| Exit code | Meaning |\n|---|---|\n| 0 | success (`check`: no errors; warnings are allowed) |\n| 1 | the model has errors, no `.dt` file was found, generation was refused, or the root / a file could not be read |\n| 2 | invalid configuration (`domaintrail.jsonc` / `--config`, including a context name in `generate.ts.contexts` that the model does not have) or an unknown `generate` target |\n\nCommands that use the model look for a config file first; `--root` (`-r`, default `.`) is where that search starts.\n\n## Configuration\n\n`domaintrail.jsonc` (comments and trailing commas allowed) or `domaintrail.json` is looked up in `--root` and its\nparents, like `tsconfig.json`; `--config <file>` (`-c`) picks one explicitly. All paths in it are relative to the config\nfile, and its directory becomes the root. Without a config file, the defaults apply with `--root` as the root.\nEvery key is optional.\n\n```jsonc\n{\n \"$schema\": \"./node_modules/domaintrail/schema/domaintrail.schema.json\",\n // globs of DSL files; \"!\" excludes (node_modules, .git, .domaintrail are never scanned)\n \"sources\": [\"domain/**/*.dt\", \"!domain/drafts/**\"], // default: [\"**/*.dt\"]\n \"generate\": {\n \"ts\": {\n \"out\": \"src/domain/generated\", // default: \"generated/domain\"\n // contexts written elsewhere than \"out\" (optional)\n \"contexts\": { \"Common\": { \"out\": \"packages/shared/src/generated\" } }\n }\n },\n \"view\": { \"port\": 4321, \"host\": \"127.0.0.1\" } // defaults shown\n}\n```\n\nCLI options win over the file: `generate ts --out`, `view --port`, `view --host`. `--out` replaces `generate.ts.out`\nonly; contexts listed in `generate.ts.contexts` keep their own directories. Sources and output directories, `--out`\nincluded, must stay inside the config file's directory (the root without a config file): an absolute path or one with\n`..` is a config error, and an output directory reached through a symlink stops generation. A name in `generate.ts.contexts` that is not a context of the model is a config\nerror, reported by `generate ts` once the model has been checked.\n\n## File layout (recommended)\n\nFile names and directories carry no meaning: every matching `.dt` file belongs to the workspace, and a context may be\nsplit across any files. The recommended layout is one directory per context and one file per aggregate:\n\n```text\ncommon/context.dt shared context Common \"共通\" { ... } // a shared context has no aggregates\nsales/context.dt /// 説明 context Sales \"販売\" { terms { ... } }\nsales/order.dt context Sales { id OrderId ... aggregate Order { ... } entity OrderItem ... event OrderPlaced ... }\nsales/customer.dt context Sales { id CustomerId ... aggregate Customer { ... } }\nbilling/context.dt /// 説明 context Billing \"請求\" { terms { ... } }\nbilling/invoice.dt context Billing { id InvoiceId ... aggregate Invoice { ... } }\n```\n\n- `<context>/<aggregate>.dt` holds the aggregate and what only it uses: its ID, entities, events, errors, enums,\n primitives and values.\n- `<context>/context.dt` holds the context's name (表示名), description and `terms`, and the elements used by several\n of its aggregates or by none. The other files open the context without a name: `context Sales { ... }`.\n- An aggregate's ID stays in the aggregate's file even when other aggregates reference it.\n- Directory and file names are kebab-case: `PurchaseOrder` → `purchase-order.dt`, `OrderFulfillment` →\n `order-fulfillment/`.\n\nThis is a convention, not a rule: `check` neither requires nor warns about any layout.\n\n## DSL\n\nThe examples below are the files of one valid workspace (the file name is in the first comment).\n\n### Contexts and aggregates\n\n```dt\n// sales/order.dt\ncontext Sales { // a bounded context; may be split across files\n id OrderId: UUID // ID type with a base primitive type\n id OrderItemId: UUID\n enum CancelReason { Requested Other } // commas between values are optional\n value Address { city: String street: String }\n\n aggregate Order {\n id: OrderId // identity field of its own ID type (required)\n owns items: OrderItem[0..*] // owned entity / value inside the aggregate\n references customer: CustomerId -> Customer // another aggregate, by ID\n owns shipTo: Address? // ? = optional\n note: String?\n\n invariant quantitiesPositive { // applies to every state; sees the common fields\n all(items, item => item.quantity > 0)\n }\n\n create command place(customer: CustomerId) to Draft emits OrderPlaced // factory: no `from`\n\n state Draft\n state Confirmed {\n confirmedAt: Timestamp // exists only in this state\n invariant hasItems { count(items) > 0 and count(items) <= 100 } // sees common + Confirmed fields\n }\n state Cancelled {\n reason: CancelReason\n invariant otherNeedsNote { reason == CancelReason.Other implies exists(note) }\n }\n\n command confirm(at: Timestamp)\n from Draft\n to Confirmed // several: `to A | B`\n emits OrderConfirmed // events that MAY be emitted (0..n)\n errors EmptyOrder // errors that MAY be returned\n\n command cancel(reason: CancelReason) from Draft | Confirmed to Cancelled emits OrderCancelled\n }\n\n entity OrderItem { id: OrderItemId quantity: Quantity owns unitPrice: Money }\n\n persistent event OrderPlaced { orderId: OrderId } // storing it is part of its contract\n persistent event OrderConfirmed { orderId: OrderId confirmedAt: Timestamp }\n event OrderCancelled { orderId: OrderId reason: CancelReason } // not persisted (default)\n error EmptyOrder // payload optional: error E { field: Type }\n}\n```\n\n```dt\n// sales/customer.dt\ncontext Sales {\n id CustomerId: UUID\n\n aggregate Customer { // no states: commands have no `from` / `to`\n id: CustomerId\n email: EmailAddress // from the shared context Common\n active: Bool\n owns addresses: Address[0..*]\n\n invariant activeHasAddress { active == true implies count(addresses) > 0 }\n invariant servedArea { active == false or any(addresses, a => a.city == \"Tokyo\" or not (a.city == \"Osaka\")) }\n\n command changeEmail(email: EmailAddress) errors EmailTaken\n }\n\n error EmailTaken { email: EmailAddress }\n}\n```\n\n- Context elements: `id`, `primitive`, `enum`, `value`, `union`, `entity`, `aggregate`, `event`, `error`.\n- Fields: `name: Type`, `owns name: Type` (entities and values held by the aggregate),\n `references name: IdType -> Aggregate` (other aggregates, by ID only). Entities are owned by exactly one aggregate.\n- Primitive types: `String`, `Int`, `Decimal`, `Bool`, `Timestamp`, `UUID`.\n- Multiplicity after the type: `?`, `[0..1]`, `[0..*]`, `[1..*]`, `[n..m]`.\n- Aggregate members: fields, `invariant`, `state` (with its own fields and invariants), `command`.\n An aggregate with states needs `to` on every command and `from` on every non-`create` one; without states, neither.\n- `create command` makes a new aggregate; other commands take the aggregate in one of their `from` states.\n- `value`, `state`, `event` and `error` bodies are optional (`state Draft`, `error EmptyOrder`).\n- Other contexts' elements are referenced with qualified names: `Sales.OrderId`, `-> Sales.Order`.\n- Comments: `// …` and `/* … */`; `///` is a description (see [Names](#names-labels-and-descriptions)).\n\n### Domain primitives\n\nA single value with domain meaning and constraints, wrapping a primitive type. Values combining several fields are\nvalue objects.\n\n```dt\n// sales/primitives.dt\ncontext Sales {\n primitive Quantity \"数量\": Int { value in 1..999 } // one anonymous constraint\n primitive Sku: String { // or named invariants\n invariant format \"形式\" { matches(value, \"^[A-Z]{3}-\\d{4}$\") }\n invariant maxLength { length(value) <= 8 }\n }\n id InvoiceNo: String { matches(value, \"^INV-\\d{8}$\") } // an ID is a domain primitive used as identity\n}\n```\n\n- The base is always a primitive type; a domain primitive cannot refine another one or an enum.\n- Inside the constraint only `value` (of the base type) is visible; `length(value)`, `matches(value, \"regex\")` and\n ranges `value in 1..999` (negative literals allowed) are available there.\n- Regular expressions are written as in JavaScript: backslashes are not string escapes (`\"\\d\"` means `\\d`).\n- Elsewhere a domain primitive compares with literals and with the same domain primitive, not with another domain\n primitive or a plain field of its base type (M009).\n- Only IDs can be identity fields and reference types. Domain primitives cannot be owned.\n\n### Unions\n\nA value whose shape depends on a kind fixed when it is made (a tagged union). Use a union for a classification that\nnever changes, and aggregate states for a lifecycle that commands move through.\n\n```dt\n// sales/payment.dt\ncontext Sales {\n union Payer \"支払者\" { // discriminator `kind` by default\n CUSTOMER \"顧客\" { customerId: CustomerId }\n COMPANY \"法人\" { name: String billingEmail: EmailAddress? }\n }\n enum PaymentMethod { CARD TRANSFER }\n union PaymentDetails by method: PaymentMethod { // `by name`, optionally bound to an enum\n CARD { last4: String } // exactly the enum's values (M015)\n TRANSFER { bankCode: String }\n }\n}\n```\n\n- A union is a value type: usable like a value object (fields, `owns`, parameters, payloads, shared contexts).\n Variants hold value fields and invariants (seeing their own fields); entities and aggregates are not allowed.\n- In invariants, `payer.kind` compares with `Payer.COMPANY` (or the bound enum's values); variant fields are not\n accessible from outside the union.\n\n### Shared contexts\n\n```dt\n// common/context.dt\nshared context Common \"共通\" { // shared kernel: usable by simple name from every context\n terms { currency: \"通貨\" }\n enum Currency { JPY USD }\n value Money { amount: Decimal currency: Currency }\n primitive EmailAddress: String { matches(value, \"^[^@\\s]+@[^@\\s]+$\") }\n}\n```\n\n- `Money` and `Common.Money` both work in other contexts. A context's own element with the same name wins (M014 warning).\n- A shared context holds only domain primitives, enums, value objects, unions and terms, and depends only on shared\n contexts. Its `terms` apply to fields of every context that has no term of its own for the name.\n\n### Names (labels and descriptions)\n\n```dt\n// billing/context.dt\n/// 注文への請求と支払いを扱う。\ncontext Billing \"請求\" {\n terms { // field / parameter names, defined once per context\n /// 請求書が支払われた日時。\n paidAt: \"支払日時\"\n }\n}\n```\n\n```dt\n// billing/invoice.dt\ncontext Billing { // other files open the context without a name\n id InvoiceId \"請求書ID\": UUID\n\n /// 注文1件に対する請求。\n aggregate Invoice \"請求書\" { // declarations: a string after the name\n id: InvoiceId\n references order: Sales.OrderId -> Sales.Order \"請求対象\" // an inline label on a field\n owns amount: Money \"請求金額\"\n state Open \"未払い\"\n state Paid \"支払済み\" { paidAt: Timestamp } // → 支払日時 (from terms)\n invariant positive \"金額が正\" { amount.amount > 0 }\n create command issue(order: Sales.OrderId, amount: Money) \"請求書を発行する\" to Open\n command pay(at: Timestamp \"支払日時\") \"支払う\" from Open to Paid emits InvoicePaid\n }\n enum InvoiceKind \"請求区分\" { Regular \"通常\" Refund \"返金\" }\n event InvoicePaid \"支払完了\" { invoiceId: InvoiceId paidAt: Timestamp }\n}\n```\n\n- Declarations (context, id, primitive, enum and its values, value, union and its variants, entity, aggregate, state,\n command, invariant, event, error) take an optional string label after the name.\n- A field or parameter is named by, in order: its inline string → the context's `terms` → the name of its type\n (for `references`, the target aggregate) → the English name.\n- `///` lines directly above a declaration or term are its description.\n- Labels appear in the Live View and as JSDoc in the generated TypeScript; identifiers and generated type names stay\n English.\n\n### Invariant expressions\n\n- Literals: `true`, `false`, `42`, `-1`, `3.14`, `\"text\"`; enum values `CancelReason.Other`.\n- Field paths: `note`, `item.quantity`, `amount.amount`.\n- Operators, loosest first: `implies`, `or`, `and`, `== != < <= > >=`, `x in 1..9`, `not`.\n- Functions: `exists(x)` (an optional is present; narrows `x` on the right of `and` / `implies`), `count(c)`,\n `all(c, x => …)`, `any(c, x => …)`, and in domain primitives `length(value)`, `matches(value, \"regex\")`.\n- An invariant must be a Bool expression. Only its type is checked, not whether it holds.\n\n## Rules\n\n| Code | Check |\n|---|---|\n| SYNTAX | lexer / parser errors |\n| M001 | types, aggregates and names in invariants resolve |\n| M002 | names are unique in their scope (also across files of one context) |\n| M003 | an entity is owned by exactly one aggregate (warning when owned by none) |\n| M004 | no ownership across aggregate boundaries (entities need `owns`, aggregates need `references`, …) |\n| M005 | a reference's ID type matches the identity of the target aggregate |\n| M006 | command input/output states exist and fit the aggregate (factory / stateful / stateless) |\n| M007 | `emits` / `errors` refer to existing events / errors |\n| M008 | an invariant is a Bool expression |\n| M009 | operators and operands have compatible types |\n| M010 | state-specific fields are used only in their own state's invariants |\n| M011 | generated TypeScript names do not collide |\n| M012 | the ownership graph has no cycles |\n| M013 | aggregates and entities have an `id` field of their own ID type |\n| M014 | shared contexts: only value types, no dependency on other contexts, consistent `shared`, unambiguous names (shadowing is a warning) |\n| M015 | unions: at least one variant, variants match the bound enum exactly, no variant field named like the discriminator |\n| L001 | (warning) an inline field label disagrees with the term, or context fragments disagree on the context name |\n| L002 | (warning) a term is not used by any field or parameter |\n| L003 | (warning) different things in one scope share a Japanese name |\n\n## Generated TypeScript\n\nPer context a module (`Sales.ts`, …) with ID brands, enums, value objects, entities, unions, a discriminated union per\nstateful aggregate (`DraftOrder | ConfirmedOrder | …`), event / error types with a `type` tag, a function type per\ncommand and an `<Aggregate>Commands` interface to implement, plus `index.ts` and `_runtime.ts`. A domain primitive\ngets a branded type and a constructor contract `Make<Name>` to implement by hand.\n\n```ts\nexport type ConfirmOrder = (\n order: DraftOrder,\n at: Timestamp,\n) => Result<readonly [ConfirmedOrder, readonly OrderConfirmed[]], EmptyOrder>;\n```\n\n### Generated code and your code\n\nThe generated files are the **contract**, your code is the **implementation**:\n\n- Generated: types only — the shapes of the model, the command signatures (`ConfirmOrder`, `OrderCommands`) and the\n constructor signatures of domain primitives (`MakeQuantity`). Invariants appear as JSDoc (`@invariant`); nothing in\n the generated code checks them.\n- Yours: everything that runs — command implementations, `Make<Name>` constructors, invariant checks — in your own\n files, which import the generated modules (never the other way round) and are type-checked against them.\n\n```ts\n// src/primitives.ts — your code\nimport { err, ok, type Sales } from '../generated/domain/index.js';\n\nexport const makeQuantity: Sales.MakeQuantity = (value) =>\n Number.isInteger(value) && value >= 1 && value <= 999 ? ok(value as Sales.Quantity) : err({ type: 'InvalidQuantity', value, invariant: 'valid' });\n```\n\nDo not edit generated files: change the `.dt` sources and generate again. Adding properties or methods to generated\ntypes (declaration merging, editing the output) is not supported; write functions that take the generated types.\n\n### Output directories\n\nBy default every context goes to `generate.ts.out`. Contexts listed in `generate.ts.contexts` go to their own\ndirectory instead, e.g. a shared context into a package used by several applications. Each directory written to gets\nits own `_runtime.ts` and an `index.ts` re-exporting only the contexts in it; a module imports other contexts by\nrelative path (`import type * as Common from '../../packages/shared/src/generated/Common.js'`). The runtimes are\nidentical, so values typed with one are accepted where the other is expected.\n\nEach run replaces the files generated before (recognized by their header). The files written are recorded in\n`.domaintrail/generated.json` under the root, and generated files of earlier runs that are no longer written (an output\ndirectory moved, a context removed) are deleted, along with a directory left empty. Only recorded paths inside the root\nand not reached through a symlink are deleted; other entries in that file are ignored. Other files are never deleted —\nneither hand-written files nor generated files you edited — and generation stops instead of overwriting one.\n";
8038
+ var guide_default = "# DomainTrail guide\n\n`dt` checks domain models written in the DomainTrail DSL (`.dt` files) and generates TypeScript types and command\ncontracts from them. The DSL describes domain **structure and contracts** only — never business logic, which is written\nby hand against the generated types.\n\nThis guide is what `dt guide` prints. It is written for people and AI agents using `dt` without other documentation.\n\n## Workflow\n\n1. Write or edit `.dt` files (see [DSL](#dsl) and [File layout](#file-layout-recommended)).\n2. Run `dt check` and fix every reported problem until it exits 0.\n3. Run `dt generate ts` to write the TypeScript (it runs `check` first and writes nothing on errors).\n4. Implement the generated contracts in your own code, and type-check that code with your own TypeScript setup\n (e.g. `tsc --noEmit`). `dt` does not run the TypeScript compiler.\n\n`dt view` starts the Live View, a browser page where people watch the model update as files are saved. It is a server\nthat keeps running and never exits by itself (stop it with Ctrl+C), so do not wait for it to finish: run it in the\nbackground, or use `dt check` for a result.\n\n`dt --help` and `dt <command> --help` list the options with examples.\n\n```bash\ndt check # every *.dt file below the current directory\ndt -r domain check # below domain/ (or as configured by a domaintrail.jsonc found there or above)\ndt generate ts # into <root>/generated/domain\ndt generate ts --out src/domain/generated\ndt view --port 8080 # http://127.0.0.1:8080, until Ctrl+C\n```\n\n## Output and exit codes\n\n`check` (and `generate ts`, which checks first) prints one line per problem, sorted by file and position, then a\nsummary:\n\n```text\nsales/order.dt:2:11 - warning L002: Term 'note' (\"備考\") is not used by any field or parameter in context 'Sales'.\nsales/order.dt:8:32 - error M009: count() requires a collection, but got 'Money'.\n1 file(s) checked: 1 error(s), 1 warning(s).\n```\n\nPaths are relative to the root, lines and columns 1-based. Errors go to stderr, warnings to stdout. Fix errors first;\nwarnings do not fail the check. Other failures (missing root, invalid config, port in use, …) are one line on stderr.\n\n| Exit code | Meaning |\n|---|---|\n| 0 | success (`check`: no errors; warnings are allowed) |\n| 1 | the model has errors, no `.dt` file was found, generation was refused, or the root / a file could not be read |\n| 2 | invalid configuration (`domaintrail.jsonc` / `--config`, including a context name in `generate.ts.contexts` that the model does not have) or an unknown `generate` target |\n\nCommands that use the model look for a config file first; `--root` (`-r`, default `.`) is where that search starts.\n\n## Configuration\n\n`domaintrail.jsonc` (comments and trailing commas allowed) or `domaintrail.json` is looked up in `--root` and its\nparents, like `tsconfig.json`; `--config <file>` (`-c`) picks one explicitly. All paths in it are relative to the config\nfile, and its directory becomes the root. Without a config file, the defaults apply with `--root` as the root.\nEvery key is optional.\n\n```jsonc\n{\n \"$schema\": \"./node_modules/domaintrail/schema/domaintrail.schema.json\",\n // globs of DSL files; \"!\" excludes (node_modules, .git, .domaintrail are never scanned)\n \"sources\": [\"domain/**/*.dt\", \"!domain/drafts/**\"], // default: [\"**/*.dt\"]\n \"generate\": {\n \"ts\": {\n \"out\": \"src/domain/generated\", // default: \"generated/domain\"\n // contexts written elsewhere than \"out\" (optional)\n \"contexts\": { \"Common\": { \"out\": \"packages/shared/src/generated\" } }\n }\n },\n \"view\": { \"port\": 4321, \"host\": \"127.0.0.1\" } // defaults shown\n}\n```\n\nCLI options win over the file: `generate ts --out`, `view --port`, `view --host`. `--out` replaces `generate.ts.out`\nonly; contexts listed in `generate.ts.contexts` keep their own directories. Sources and output directories, `--out`\nincluded, must stay inside the config file's directory (the root without a config file): an absolute path or one with\n`..` is a config error, and an output directory reached through a symlink stops generation. A name in `generate.ts.contexts` that is not a context of the model is a config\nerror, reported by `generate ts` once the model has been checked.\n\n## File layout (recommended)\n\nFile names and directories carry no meaning: every matching `.dt` file belongs to the workspace, and a context may be\nsplit across any files. The recommended layout is one directory per context and one file per aggregate:\n\n```text\ncommon/context.dt shared context Common \"共通\" { ... } // a shared context has no aggregates\nsales/context.dt /// 説明 context Sales \"販売\" { terms { ... } }\nsales/order.dt context Sales { id OrderId ... aggregate Order { ... } entity OrderItem ... event OrderPlaced ... }\nsales/customer.dt context Sales { id CustomerId ... aggregate Customer { ... } }\nbilling/context.dt /// 説明 context Billing \"請求\" { terms { ... } }\nbilling/invoice.dt context Billing { id InvoiceId ... aggregate Invoice { ... } }\n```\n\n- `<context>/<aggregate>.dt` holds the aggregate and what only it uses: its ID, entities, events, errors, enums,\n primitives and values.\n- `<context>/context.dt` holds the context's name (表示名), description and `terms`, and the elements used by several\n of its aggregates or by none (field sets, for example). The other files open the context without a name: `context Sales { ... }`.\n- An aggregate's ID stays in the aggregate's file even when other aggregates reference it.\n- Directory and file names are kebab-case: `PurchaseOrder` → `purchase-order.dt`, `OrderFulfillment` →\n `order-fulfillment/`.\n\nThis is a convention, not a rule: `check` neither requires nor warns about any layout.\n\n## DSL\n\nThe examples below are the files of one valid workspace (the file name is in the first comment).\n\n### Contexts and aggregates\n\n```dt\n// sales/order.dt\ncontext Sales { // a bounded context; may be split across files\n id OrderId: UUID // ID type with a base primitive type\n id OrderItemId: UUID\n enum CancelReason { Requested Other } // commas between values are optional\n value Address { city: String street: String }\n\n aggregate Order {\n id: OrderId // identity field of its own ID type (required)\n owns items: OrderItem[0..*] // owned entity / value inside the aggregate\n references customer: CustomerId -> Customer // another aggregate, by ID\n owns shipTo: Address? // ? = optional\n note: String?\n\n invariant quantitiesPositive { // applies to every state; sees the common fields\n all(items, item => item.quantity > 0)\n }\n\n create command place(customer: CustomerId) to Draft emits OrderPlaced // factory: no `from`\n\n state Draft\n state Confirmed {\n confirmedAt: Timestamp // exists only in this state\n invariant hasItems { count(items) > 0 and count(items) <= 100 } // sees common + Confirmed fields\n }\n state Cancelled {\n reason: CancelReason\n invariant otherNeedsNote { reason == CancelReason.Other implies exists(note) }\n }\n\n command confirm(at: Timestamp)\n from Draft\n to Confirmed // several: `to A | B`\n emits OrderConfirmed // events that MAY be emitted (0..n)\n errors EmptyOrder // errors that MAY be returned\n\n command cancel(reason: CancelReason) from Draft | Confirmed to Cancelled emits OrderCancelled\n }\n\n entity OrderItem { id: OrderItemId quantity: Quantity owns unitPrice: Money }\n\n persistent event OrderPlaced { orderId: OrderId } // storing it is part of its contract\n persistent event OrderConfirmed { orderId: OrderId confirmedAt: Timestamp }\n event OrderCancelled { orderId: OrderId reason: CancelReason } // not persisted (default)\n error EmptyOrder // payload optional: error E { field: Type }\n}\n```\n\n```dt\n// sales/customer.dt\ncontext Sales {\n id CustomerId: UUID\n\n aggregate Customer { // no states: commands have no `from` / `to`\n id: CustomerId\n email: EmailAddress // from the shared context Common\n active: Bool\n owns addresses: Address[0..*]\n\n invariant activeHasAddress { active == true implies count(addresses) > 0 }\n invariant servedArea { active == false or any(addresses, a => a.city == \"Tokyo\" or not (a.city == \"Osaka\")) }\n\n command changeEmail(email: EmailAddress) errors EmailTaken\n }\n\n error EmailTaken { email: EmailAddress }\n}\n```\n\n- Context elements: `id`, `primitive`, `enum`, `value`, `union`, `entity`, `aggregate`, `event`, `error`, and `fields`\n (see [Field sets](#field-sets)).\n- Fields: `name: Type`, `owns name: Type` (entities and values held by the aggregate),\n `references name: IdType -> Aggregate` (other aggregates, by ID only). Entities are owned by exactly one aggregate.\n- Primitive types: `String`, `Int`, `Decimal`, `Bool`, `Timestamp`, `UUID`.\n- Multiplicity after the type: `?`, `[0..1]`, `[0..*]`, `[1..*]`, `[n..m]`.\n- Aggregate members: fields, `invariant`, `state` (with its own fields and invariants), `command`.\n An aggregate with states needs `to` on every command and `from` on every non-`create` one; without states, neither.\n- `create command` makes a new aggregate; other commands take the aggregate in one of their `from` states.\n- `value`, `state`, `event` and `error` bodies are optional (`state Draft`, `error EmptyOrder`).\n- Other contexts' elements are referenced with qualified names: `Sales.OrderId`, `-> Sales.Order`.\n- Comments: `// …` and `/* … */`; `///` is a description (see [Names](#names-labels-and-descriptions)).\n\n### Domain primitives\n\nA single value with domain meaning and constraints, wrapping a primitive type. Values combining several fields are\nvalue objects.\n\n```dt\n// sales/primitives.dt\ncontext Sales {\n primitive Quantity \"数量\": Int { value in 1..999 } // one anonymous constraint\n primitive Sku: String { // or named invariants\n invariant format \"形式\" { matches(value, \"^[A-Z]{3}-\\d{4}$\") }\n invariant maxLength { length(value) <= 8 }\n }\n id InvoiceNo: String { matches(value, \"^INV-\\d{8}$\") } // an ID is a domain primitive used as identity\n}\n```\n\n- The base is always a primitive type; a domain primitive cannot refine another one or an enum.\n- Inside the constraint only `value` (of the base type) is visible; `length(value)`, `matches(value, \"regex\")` and\n ranges `value in 1..999` (negative literals allowed) are available there.\n- Regular expressions are written as in JavaScript: backslashes are not string escapes (`\"\\d\"` means `\\d`).\n- Elsewhere a domain primitive compares with literals and with the same domain primitive, not with another domain\n primitive or a plain field of its base type (M009).\n- Only IDs can be identity fields and reference types. Domain primitives cannot be owned.\n\n### Unions\n\nA value whose shape depends on a kind fixed when it is made (a tagged union). Use a union for a classification that\nnever changes, and aggregate states for a lifecycle that commands move through.\n\n```dt\n// sales/payment.dt\ncontext Sales {\n union Payer \"支払者\" { // discriminator `kind` by default\n CUSTOMER \"顧客\" { customerId: CustomerId }\n COMPANY \"法人\" { name: String billingEmail: EmailAddress? }\n }\n enum PaymentMethod { CARD TRANSFER }\n union PaymentDetails by method: PaymentMethod { // `by name`, optionally bound to an enum\n CARD { last4: String } // exactly the enum's values (M015)\n TRANSFER { bankCode: String }\n }\n}\n```\n\n- A union is a value type: usable like a value object (fields, `owns`, parameters, payloads, shared contexts).\n Variants hold value fields and invariants (seeing their own fields); entities and aggregates are not allowed.\n- In invariants, `payer.kind` compares with `Payer.COMPANY` (or the bound enum's values); variant fields are not\n accessible from outside the union.\n\n### Shared contexts\n\n```dt\n// common/context.dt\nshared context Common \"共通\" { // shared kernel: usable by simple name from every context\n terms { currency: \"通貨\" }\n enum Currency { JPY USD }\n value Money { amount: Decimal currency: Currency }\n primitive EmailAddress: String { matches(value, \"^[^@\\s]+@[^@\\s]+$\") }\n}\n```\n\n- `Money` and `Common.Money` both work in other contexts. A context's own element with the same name wins (M014 warning).\n- A shared context holds only domain primitives, enums, value objects, unions, field sets and terms, and depends only on\n shared contexts. Its `terms` apply to fields of every context that has no term of its own for the name.\n\n### Field sets\n\nFields that several aggregates, entities or events have for the same domain reason are written once as a field set\nand taken on with `with`.\n\n```dt\n// common/tenancy.dt\nshared context Common {\n /// 契約者(テナント)。業務データはテナントごとに分かれる。\n primitive TenantId \"テナントID\": UUID\n fields Tenanted \"テナント所属\" { // a field set: plain fields only\n tenant: TenantId \"テナント\"\n }\n}\n```\n\n```dt\n// expenses/expense.dt\ncontext Expenses \"経費\" {\n id ExpenseId \"経費申請ID\": UUID\n id StaffId \"職員ID\": UUID\n\n /// 規程により、申請の受付には実施者を記録する。\n fields Performed \"実施記録\" {\n performedBy: StaffId \"実施者\"\n }\n\n aggregate Expense \"経費申請\" with Tenanted { // tenant first, then its own fields\n id: ExpenseId\n applicant: StaffId \"申請者\"\n approver: StaffId? \"承認者\"\n invariant notSelfApproved \"申請者は承認できない\" { exists(approver) implies approver != applicant }\n\n create command submit(applicant: StaffId \"申請者\") \"申請する\" emits ExpenseSubmitted\n command approve(approver: StaffId \"承認者\", approvedAt: Timestamp \"承認日時\") \"承認する\" emits ExpenseApproved\n }\n\n event ExpenseSubmitted \"申請受付\" with Tenanted, Performed { expenseId: ExpenseId }\n event ExpenseApproved \"承認\" with Tenanted {\n expenseId: ExpenseId\n approver: StaffId \"承認者\" // a business role, named by the role\n approvedAt: Timestamp \"承認日時\" // when it happened in business terms\n }\n}\n```\n\n- `fields Name \"label\" { ... }` holds plain fields, written like any other field (type, multiplicity, label, `///`).\n No `owns`, `references`, invariants, `with` or `id` inside (M016).\n- `with A, B` after the name and label of an `aggregate`, `entity` or `event` (only those, M016). A field set is\n referenced like a type: by name in its own context and from shared contexts, as `Context.Name` otherwise.\n- The fields come first, in the order of `with`, and then count as the element's own: invariants see them, and an\n aggregate's states share them. A name may come from one place only, the element or one of its field sets (M016).\n- The identity of aggregates and entities is never a field set: every aggregate and entity declares `id` itself (M013).\n- A command's event should say which aggregate it is about: it needs a field of the aggregate's ID type, its own or\n from a field set (M017 warning). An event emitted by several aggregates needs the ID type of each (optional fields\n count).\n\n### Domain fields and technical fields\n\nWrite a field in the DSL when **domain experts talk about it, or a business rule (an invariant, a transition, a\ncommand's decision) refers to it**. A field that is neither is technical: leave it out of the DSL and of the generated\ncode, and add it in your own code around the generated types (see [Technical metadata](#technical-metadata)).\n\n- **Required by the kind of element** (the ID of an aggregate or entity): enforced by the language (M013), not a field\n set.\n- **Chosen for some elements** (a tenant, a recorded performer): a field set and `with`.\n- **Technical**: event ID, the time the system recorded something (`recordedAt`), optimistic-lock `version`,\n `createdAt` / `updatedAt`, correlation / causation IDs, the system's acting account, schema versions.\n\nTwo cases look alike but are not:\n\n- **When**: the time something happened in business terms is domain — rules refer to it (\"within 30 days of\n confirmation\"). Name it by its meaning (`confirmedAt: Timestamp \"確定日時\"`). If every event is to carry its business\n time, say so with a field set: `fields Occurred { occurredAt: Timestamp \"発生日時\" }`. The time the system recorded it\n is technical. The two differ with late entry, offline work and imports.\n- **Who**: a business role (approver, person in charge) is domain — rules refer to it (\"the applicant cannot\n approve\"). Name it by the role (`approvedBy: StaffId \"承認者\"`), usually passed from the command's parameters to the\n event. If regulations require recording the performer of every operation,\n `fields Performed { performedBy: StaffId \"実施者\" }`. The login account, service account or IP address is technical; it differs with proxy entry and batches.\n\n### Names (labels and descriptions)\n\n```dt\n// billing/context.dt\n/// 注文への請求と支払いを扱う。\ncontext Billing \"請求\" {\n terms { // field / parameter names, defined once per context\n /// 請求書が支払われた日時。\n paidAt: \"支払日時\"\n }\n}\n```\n\n```dt\n// billing/invoice.dt\ncontext Billing { // other files open the context without a name\n id InvoiceId \"請求書ID\": UUID\n\n /// 注文1件に対する請求。\n aggregate Invoice \"請求書\" { // declarations: a string after the name\n id: InvoiceId\n references order: Sales.OrderId -> Sales.Order \"請求対象\" // an inline label on a field\n owns amount: Money \"請求金額\"\n state Open \"未払い\"\n state Paid \"支払済み\" { paidAt: Timestamp } // → 支払日時 (from terms)\n invariant positive \"金額が正\" { amount.amount > 0 }\n create command issue(order: Sales.OrderId, amount: Money) \"請求書を発行する\" to Open\n command pay(at: Timestamp \"支払日時\") \"支払う\" from Open to Paid emits InvoicePaid\n }\n enum InvoiceKind \"請求区分\" { Regular \"通常\" Refund \"返金\" }\n event InvoicePaid \"支払完了\" { invoiceId: InvoiceId paidAt: Timestamp }\n}\n```\n\n- Declarations (context, id, primitive, enum and its values, value, union and its variants, entity, aggregate, state,\n command, invariant, event, error) take an optional string label after the name.\n- A field or parameter is named by, in order: its inline string → the context's `terms` → the name of its type\n (for `references`, the target aggregate) → the English name.\n- `///` lines directly above a declaration or term are its description.\n- Labels appear in the Live View and as JSDoc in the generated TypeScript; identifiers and generated type names stay\n English.\n\n### Invariant expressions\n\n- Literals: `true`, `false`, `42`, `-1`, `3.14`, `\"text\"`; enum values `CancelReason.Other`.\n- Field paths: `note`, `item.quantity`, `amount.amount`.\n- Operators, loosest first: `implies`, `or`, `and`, `== != < <= > >=`, `x in 1..9`, `not`.\n- Functions: `exists(x)` (an optional is present; narrows `x` on the right of `and` / `implies`), `count(c)`,\n `all(c, x => …)`, `any(c, x => …)`, and in domain primitives `length(value)`, `matches(value, \"regex\")`.\n- An invariant must be a Bool expression. Only its type is checked, not whether it holds.\n\n## Rules\n\n| Code | Check |\n|---|---|\n| SYNTAX | lexer / parser errors |\n| M001 | types, aggregates and names in invariants resolve |\n| M002 | names are unique in their scope (also across files of one context) |\n| M003 | an entity is owned by exactly one aggregate (warning when owned by none) |\n| M004 | no ownership across aggregate boundaries (entities need `owns`, aggregates need `references`, …) |\n| M005 | a reference's ID type matches the identity of the target aggregate |\n| M006 | command input/output states exist and fit the aggregate (factory / stateful / stateless) |\n| M007 | `emits` / `errors` refer to existing events / errors |\n| M008 | an invariant is a Bool expression |\n| M009 | operators and operands have compatible types |\n| M010 | state-specific fields are used only in their own state's invariants |\n| M011 | generated TypeScript names do not collide |\n| M012 | the ownership graph has no cycles |\n| M013 | aggregates and entities have an `id` field of their own ID type |\n| M014 | shared contexts: only value types, no dependency on other contexts, consistent `shared`, unambiguous names (shadowing is a warning) |\n| M015 | unions: at least one variant, variants match the bound enum exactly, no variant field named like the discriminator |\n| M016 | field sets: plain fields only (no `id`), `with` only on aggregates, entities and events, each field name from one place |\n| M017 | (warning) an event emitted by an aggregate's command has a field of that aggregate's ID type |\n| L001 | (warning) an inline field label disagrees with the term, or context fragments disagree on the context name |\n| L002 | (warning) a term is not used by any field or parameter |\n| L003 | (warning) different things in one scope share a Japanese name |\n\n## Generated TypeScript\n\nPer context a module (`Sales.ts`, …) with ID brands, enums, value objects, entities, unions, a discriminated union per\nstateful aggregate (`DraftOrder | ConfirmedOrder | …`), event / error types with a `type` tag, a function type per\ncommand and an `<Aggregate>Commands` interface to implement, plus `index.ts` and `_runtime.ts`. A domain primitive\ngets a branded type and a constructor contract `Make<Name>` to implement by hand. A field set is an interface that the\nelements using it extend (`interface Expense extends Common.Tenanted`; for a stateful aggregate, its `…Common`).\n\nUnions to name groups of them, each generated only when it has a member:\n\n| Type | Members |\n|---|---|\n| `DomainEvent` | every event of the context |\n| `PersistentEvent` | the events declared `persistent` |\n| `Aggregate` | every aggregate of the context |\n| `<Aggregate>Event` (`OrderEvent`) | the events the aggregate's commands may emit (also of other contexts) |\n\n```ts\nexport type ConfirmOrder = (\n order: DraftOrder,\n at: Timestamp,\n) => Result<readonly [ConfirmedOrder, readonly OrderConfirmed[]], EmptyOrder>;\n```\n\n### Generated code and your code\n\nThe generated files are the **contract**, your code is the **implementation**:\n\n- Generated: types only — the shapes of the model, the command signatures (`ConfirmOrder`, `OrderCommands`) and the\n constructor signatures of domain primitives (`MakeQuantity`). Invariants appear as JSDoc (`@invariant`); nothing in\n the generated code checks them.\n- Yours: everything that runs — command implementations, `Make<Name>` constructors, invariant checks — in your own\n files, which import the generated modules (never the other way round) and are type-checked against them.\n\n```ts\n// src/primitives.ts — your code\nimport { err, ok, type Sales } from '../generated/domain/index.js';\n\nexport const makeQuantity: Sales.MakeQuantity = (value) =>\n Number.isInteger(value) && value >= 1 && value <= 999 ? ok(value as Sales.Quantity) : err({ type: 'InvalidQuantity', value, invariant: 'valid' });\n```\n\nDo not edit generated files: change the `.dt` sources and generate again. Adding properties or methods to generated\ntypes (declaration merging, editing the output) is not supported; write functions that take the generated types.\n\n### Technical metadata\n\nTechnical fields (see [Domain fields and technical fields](#domain-fields-and-technical-fields)) are added by your code,\naround the generated types. Keep the two apart in an envelope, `{ event, meta }`, rather than an intersection\n(`E & Meta`): names cannot clash, and domain and technical fields stay separate. `dt` generates no envelope type.\n\n```ts\n// src/stored.ts — your code: metadata of stored events and aggregates\nimport type { Sales } from '../generated/domain/index.js';\n\nexport interface EventMeta {\n readonly eventId: string;\n readonly recordedAt: Date;\n readonly correlationId?: string;\n readonly causationId?: string;\n}\n\n/** What Sales records in addition. */\nexport interface SalesEventMeta extends EventMeta {\n readonly accountId: string;\n}\n\nexport type Stored<E, M extends EventMeta = EventMeta> = { readonly event: E; readonly meta: M };\n\nexport type StoredSalesEvent = Stored<Sales.PersistentEvent, SalesEventMeta>;\n\nexport interface AggregateMeta {\n readonly version: number;\n readonly createdAt: Date;\n readonly updatedAt: Date;\n}\n\nexport type Versioned<A, M extends AggregateMeta = AggregateMeta> = { readonly aggregate: A; readonly meta: M };\n\nexport interface OrderRepository {\n load(id: Sales.OrderId): Promise<Versioned<Sales.Order> | undefined>;\n save(order: Versioned<Sales.Order>, events: readonly Sales.OrderEvent[]): Promise<void>;\n}\n```\n\nMetadata that only some kinds of event carry can be keyed by the event's `type`:\n\n```ts\n// src/meta-by-event.ts — your code\nimport type { Sales } from '../generated/domain/index.js';\nimport type { EventMeta } from './stored.js';\n\ninterface MetaByEvent {\n OrderPlaced: { readonly channel: 'web' | 'store' };\n}\n\nexport type MetaOf<E extends { type: string }> = EventMeta & (E['type'] extends keyof MetaByEvent ? MetaByEvent[E['type']] : {});\n\n/** One envelope per kind of event, so that a union of events gives a union of envelopes. */\nexport type StoredEvent<E extends { type: string }> = E extends unknown ? { readonly event: E; readonly meta: MetaOf<E> } : never;\n\nexport const channelOf = (s: StoredEvent<Sales.OrderPlaced>): 'web' | 'store' => s.meta.channel;\nexport type StoredSalesEvents = StoredEvent<Sales.DomainEvent>;\n```\n\n### Output directories\n\nBy default every context goes to `generate.ts.out`. Contexts listed in `generate.ts.contexts` go to their own\ndirectory instead, e.g. a shared context into a package used by several applications. Each directory written to gets\nits own `_runtime.ts` and an `index.ts` re-exporting only the contexts in it; a module imports other contexts by\nrelative path (`import type * as Common from '../../packages/shared/src/generated/Common.js'`). The runtimes are\nidentical, so values typed with one are accepted where the other is expected.\n\nEach run replaces the files generated before (recognized by their header). The files written are recorded in\n`.domaintrail/generated.json` under the root, and generated files of earlier runs that are no longer written (an output\ndirectory moved, a context removed) are deleted, along with a directory left empty. Only recorded paths inside the root\nand not reached through a symlink are deleted; other entries in that file are ignored. Other files are never deleted —\nneither hand-written files nor generated files you edited — and generation stops instead of overwriting one.\n";
7603
8039
 
7604
8040
  // src/cli/main.ts
7605
8041
  var defaultIO = {