@mmmnt/cli 0.4.0 → 0.5.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/moment.mjs +2008 -631
- package/dist/moment.mjs.map +4 -4
- package/package.json +10 -11
package/dist/moment.mjs
CHANGED
|
@@ -35652,6 +35652,173 @@ ${obj.gpgsig ? obj.gpgsig : ""}`;
|
|
|
35652
35652
|
import { parseArgs } from "node:util";
|
|
35653
35653
|
import { resolve as resolve5 } from "node:path";
|
|
35654
35654
|
|
|
35655
|
+
// ../core/dist/services/schema-validator.js
|
|
35656
|
+
var SchemaValidator = class {
|
|
35657
|
+
/**
|
|
35658
|
+
* Validates structural correctness of an IntermediateRepresentation.
|
|
35659
|
+
* Enforces SP-01 through SP-04 (pure IR checks, no I/O).
|
|
35660
|
+
* SP-05 (manifest file references) requires filesystem access —
|
|
35661
|
+
* use `validateManifestFiles()` separately.
|
|
35662
|
+
*/
|
|
35663
|
+
validate(ir) {
|
|
35664
|
+
const diagnostics = [];
|
|
35665
|
+
this.checkSP01(ir, diagnostics);
|
|
35666
|
+
this.checkSP02(ir, diagnostics);
|
|
35667
|
+
this.checkSP03(ir, diagnostics);
|
|
35668
|
+
this.checkSP04(ir, diagnostics);
|
|
35669
|
+
return { valid: diagnostics.length === 0, diagnostics };
|
|
35670
|
+
}
|
|
35671
|
+
/**
|
|
35672
|
+
* Validates that all file references in the manifest exist on disk (SP-05).
|
|
35673
|
+
* Requires an injected `fileExists` function for filesystem access.
|
|
35674
|
+
*/
|
|
35675
|
+
validateManifestFiles(files, fileExists) {
|
|
35676
|
+
const diagnostics = [];
|
|
35677
|
+
for (const file of files) {
|
|
35678
|
+
if (!fileExists(file.path)) {
|
|
35679
|
+
diagnostics.push({
|
|
35680
|
+
severity: "error",
|
|
35681
|
+
message: `SP-05: File '${file.path}' referenced in manifest does not exist.`,
|
|
35682
|
+
ruleId: "SP-05"
|
|
35683
|
+
});
|
|
35684
|
+
}
|
|
35685
|
+
}
|
|
35686
|
+
return { valid: diagnostics.length === 0, diagnostics };
|
|
35687
|
+
}
|
|
35688
|
+
checkSP01(ir, diagnostics) {
|
|
35689
|
+
const contextIds = new Set(ir.contexts.map((c) => c.id));
|
|
35690
|
+
for (const flow of ir.flows) {
|
|
35691
|
+
for (const conn of flow.connections) {
|
|
35692
|
+
if (conn.connectionType === "crosses-to" && !contextIds.has(conn.targetContextId)) {
|
|
35693
|
+
diagnostics.push({
|
|
35694
|
+
severity: "error",
|
|
35695
|
+
message: `SP-01: Connection '${conn.id}' references unknown context '${conn.targetContextId}'.`,
|
|
35696
|
+
ruleId: "SP-01"
|
|
35697
|
+
});
|
|
35698
|
+
}
|
|
35699
|
+
}
|
|
35700
|
+
}
|
|
35701
|
+
}
|
|
35702
|
+
/**
|
|
35703
|
+
* SP-02: A crossing's event must be declared on the boundary it crosses —
|
|
35704
|
+
* by the source context (the emitter, the convention the shipped examples
|
|
35705
|
+
* follow) or by the target context (consumer-side re-declaration). The
|
|
35706
|
+
* original target-only rule flagged every crossing in the canonical
|
|
35707
|
+
* examples, because events are declared once, in the emitting context.
|
|
35708
|
+
*/
|
|
35709
|
+
checkSP02(ir, diagnostics) {
|
|
35710
|
+
const contextEventsMap = /* @__PURE__ */ new Map();
|
|
35711
|
+
for (const ctx of ir.contexts) {
|
|
35712
|
+
const eventIds = new Set(ctx.events.map((e) => e.id));
|
|
35713
|
+
contextEventsMap.set(ctx.id, eventIds);
|
|
35714
|
+
}
|
|
35715
|
+
for (const flow of ir.flows) {
|
|
35716
|
+
for (const conn of flow.connections) {
|
|
35717
|
+
if (conn.connectionType === "crosses-to") {
|
|
35718
|
+
this.checkCrossingEventDeclared(flow, conn, contextEventsMap, diagnostics);
|
|
35719
|
+
}
|
|
35720
|
+
}
|
|
35721
|
+
}
|
|
35722
|
+
}
|
|
35723
|
+
checkCrossingEventDeclared(flow, conn, contextEventsMap, diagnostics) {
|
|
35724
|
+
const targetEvents = contextEventsMap.get(conn.targetContextId);
|
|
35725
|
+
const sourceContextId = this.resolveSourceContextId(flow, conn);
|
|
35726
|
+
const sourceEvents = sourceContextId !== void 0 ? contextEventsMap.get(sourceContextId) : void 0;
|
|
35727
|
+
if (!targetEvents && !sourceEvents)
|
|
35728
|
+
return;
|
|
35729
|
+
if (!targetEvents?.has(conn.eventId) && !sourceEvents?.has(conn.eventId)) {
|
|
35730
|
+
diagnostics.push({
|
|
35731
|
+
severity: "error",
|
|
35732
|
+
message: `SP-02: Connection '${conn.id}' references event '${conn.eventId}' which is declared neither by its source context nor by target context '${conn.targetContextId}'.`,
|
|
35733
|
+
ruleId: "SP-02"
|
|
35734
|
+
});
|
|
35735
|
+
}
|
|
35736
|
+
}
|
|
35737
|
+
/** Context that owns the connection's declaring node, via its moment entry. */
|
|
35738
|
+
resolveSourceContextId(flow, conn) {
|
|
35739
|
+
if (conn.sourceNodeName === void 0)
|
|
35740
|
+
return void 0;
|
|
35741
|
+
const moment = flow.moments.find((m) => m.id === conn.sourceMomentId);
|
|
35742
|
+
if (!moment)
|
|
35743
|
+
return void 0;
|
|
35744
|
+
const entries = [
|
|
35745
|
+
...moment.contextEntries,
|
|
35746
|
+
...moment.branches?.flatMap((b) => b.entries) ?? []
|
|
35747
|
+
];
|
|
35748
|
+
return entries.find((e) => e.nodeName === conn.sourceNodeName)?.contextId;
|
|
35749
|
+
}
|
|
35750
|
+
checkSP03(ir, diagnostics) {
|
|
35751
|
+
for (const flow of ir.flows) {
|
|
35752
|
+
for (const conn of flow.connections) {
|
|
35753
|
+
if (conn.connectionType === "crosses-to") {
|
|
35754
|
+
if (conn.schemaContract.fields.length === 0) {
|
|
35755
|
+
diagnostics.push({
|
|
35756
|
+
severity: "error",
|
|
35757
|
+
message: `SP-03: Crossing connection '${conn.id}' has an empty schema contract.`,
|
|
35758
|
+
ruleId: "SP-03"
|
|
35759
|
+
});
|
|
35760
|
+
}
|
|
35761
|
+
}
|
|
35762
|
+
}
|
|
35763
|
+
}
|
|
35764
|
+
}
|
|
35765
|
+
/**
|
|
35766
|
+
* SP-04: returns-to must land on a prior moment in the same flow.
|
|
35767
|
+
*
|
|
35768
|
+
* Resolution uses the connection's `targetMomentId` (with a
|
|
35769
|
+
* `targetMomentLabel` name-match fallback) — the moment the spec actually
|
|
35770
|
+
* names. The original implementation resolved via `targetContextId`, which
|
|
35771
|
+
* is the SOURCE node's own lane (audit M-P10) and flagged every moment that
|
|
35772
|
+
* merely shared that context — semantically wrong in both directions.
|
|
35773
|
+
*/
|
|
35774
|
+
checkSP04(ir, diagnostics) {
|
|
35775
|
+
for (const flow of ir.flows) {
|
|
35776
|
+
const momentIndexMap = /* @__PURE__ */ new Map();
|
|
35777
|
+
flow.moments.forEach((m, index) => {
|
|
35778
|
+
momentIndexMap.set(m.id, index);
|
|
35779
|
+
});
|
|
35780
|
+
for (const conn of flow.connections) {
|
|
35781
|
+
if (conn.connectionType === "returns-to") {
|
|
35782
|
+
this.checkReturnsToIsPrior(flow, conn, momentIndexMap, diagnostics);
|
|
35783
|
+
}
|
|
35784
|
+
}
|
|
35785
|
+
}
|
|
35786
|
+
}
|
|
35787
|
+
checkReturnsToIsPrior(flow, conn, momentIndexMap, diagnostics) {
|
|
35788
|
+
const sourceIndex = momentIndexMap.get(conn.sourceMomentId);
|
|
35789
|
+
if (sourceIndex === void 0) {
|
|
35790
|
+
diagnostics.push({
|
|
35791
|
+
severity: "error",
|
|
35792
|
+
message: `SP-04: Connection '${conn.id}' references unresolvable source moment '${conn.sourceMomentId}'.`,
|
|
35793
|
+
ruleId: "SP-04"
|
|
35794
|
+
});
|
|
35795
|
+
return;
|
|
35796
|
+
}
|
|
35797
|
+
const targetMomentId = conn.targetMomentId ?? this.resolveMomentIdByLabel(flow, conn.targetMomentLabel);
|
|
35798
|
+
const targetIndex = targetMomentId !== void 0 ? momentIndexMap.get(targetMomentId) : void 0;
|
|
35799
|
+
if (targetIndex === void 0) {
|
|
35800
|
+
diagnostics.push({
|
|
35801
|
+
severity: "error",
|
|
35802
|
+
message: `SP-04: Connection '${conn.id}' returns-to target moment '${conn.targetMomentLabel ?? conn.targetMomentId ?? "unknown"}' which cannot be resolved in this flow.`,
|
|
35803
|
+
ruleId: "SP-04"
|
|
35804
|
+
});
|
|
35805
|
+
return;
|
|
35806
|
+
}
|
|
35807
|
+
if (targetIndex >= sourceIndex) {
|
|
35808
|
+
diagnostics.push({
|
|
35809
|
+
severity: "error",
|
|
35810
|
+
message: `SP-04: Connection '${conn.id}' returns-to a moment that is not prior (source moment index ${sourceIndex}, target moment index ${targetIndex}).`,
|
|
35811
|
+
ruleId: "SP-04"
|
|
35812
|
+
});
|
|
35813
|
+
}
|
|
35814
|
+
}
|
|
35815
|
+
resolveMomentIdByLabel(flow, label) {
|
|
35816
|
+
if (label === void 0)
|
|
35817
|
+
return void 0;
|
|
35818
|
+
return flow.moments.find((m) => m.name === label)?.id;
|
|
35819
|
+
}
|
|
35820
|
+
};
|
|
35821
|
+
|
|
35655
35822
|
// ../core/dist/manifest/manifest-reader.js
|
|
35656
35823
|
var import_yaml = __toESM(require_dist(), 1);
|
|
35657
35824
|
import { readFileSync as readFileSync2, existsSync } from "node:fs";
|
|
@@ -57272,6 +57439,9 @@ var MomentFile = {
|
|
|
57272
57439
|
contexts: "contexts",
|
|
57273
57440
|
flows: "flows"
|
|
57274
57441
|
};
|
|
57442
|
+
function isMomentFile(item) {
|
|
57443
|
+
return reflection2.isInstance(item, MomentFile.$type);
|
|
57444
|
+
}
|
|
57275
57445
|
var Multiplicity = {
|
|
57276
57446
|
$type: "Multiplicity",
|
|
57277
57447
|
count: "count",
|
|
@@ -57320,9 +57490,10 @@ function isReturnsTo(item) {
|
|
|
57320
57490
|
var SagaDeclaration = {
|
|
57321
57491
|
$type: "SagaDeclaration",
|
|
57322
57492
|
compensation: "compensation",
|
|
57493
|
+
initialState: "initialState",
|
|
57323
57494
|
name: "name",
|
|
57324
|
-
states: "states",
|
|
57325
57495
|
timeout: "timeout",
|
|
57496
|
+
transitions: "transitions",
|
|
57326
57497
|
trigger: "trigger"
|
|
57327
57498
|
};
|
|
57328
57499
|
function isSagaDeclaration(item) {
|
|
@@ -57333,6 +57504,11 @@ var SagaTimeout = {
|
|
|
57333
57504
|
duration: "duration",
|
|
57334
57505
|
none: "none"
|
|
57335
57506
|
};
|
|
57507
|
+
var SagaTransition = {
|
|
57508
|
+
$type: "SagaTransition",
|
|
57509
|
+
event: "event",
|
|
57510
|
+
target: "target"
|
|
57511
|
+
};
|
|
57336
57512
|
var TriggeredBy = {
|
|
57337
57513
|
$type: "TriggeredBy",
|
|
57338
57514
|
nodeName: "nodeName"
|
|
@@ -57774,16 +57950,19 @@ var MomentAstReflection = class extends AbstractAstReflection {
|
|
|
57774
57950
|
compensation: {
|
|
57775
57951
|
name: SagaDeclaration.compensation
|
|
57776
57952
|
},
|
|
57953
|
+
initialState: {
|
|
57954
|
+
name: SagaDeclaration.initialState
|
|
57955
|
+
},
|
|
57777
57956
|
name: {
|
|
57778
57957
|
name: SagaDeclaration.name
|
|
57779
57958
|
},
|
|
57780
|
-
states: {
|
|
57781
|
-
name: SagaDeclaration.states,
|
|
57782
|
-
defaultValue: []
|
|
57783
|
-
},
|
|
57784
57959
|
timeout: {
|
|
57785
57960
|
name: SagaDeclaration.timeout
|
|
57786
57961
|
},
|
|
57962
|
+
transitions: {
|
|
57963
|
+
name: SagaDeclaration.transitions,
|
|
57964
|
+
defaultValue: []
|
|
57965
|
+
},
|
|
57787
57966
|
trigger: {
|
|
57788
57967
|
name: SagaDeclaration.trigger
|
|
57789
57968
|
}
|
|
@@ -57802,6 +57981,18 @@ var MomentAstReflection = class extends AbstractAstReflection {
|
|
|
57802
57981
|
},
|
|
57803
57982
|
superTypes: []
|
|
57804
57983
|
},
|
|
57984
|
+
SagaTransition: {
|
|
57985
|
+
name: SagaTransition.$type,
|
|
57986
|
+
properties: {
|
|
57987
|
+
event: {
|
|
57988
|
+
name: SagaTransition.event
|
|
57989
|
+
},
|
|
57990
|
+
target: {
|
|
57991
|
+
name: SagaTransition.target
|
|
57992
|
+
}
|
|
57993
|
+
},
|
|
57994
|
+
superTypes: []
|
|
57995
|
+
},
|
|
57805
57996
|
TriggeredBy: {
|
|
57806
57997
|
name: TriggeredBy.$type,
|
|
57807
57998
|
properties: {
|
|
@@ -57899,7 +58090,7 @@ var MomentGrammar = () => loadedMomentGrammar ?? (loadedMomentGrammar = loadGram
|
|
|
57899
58090
|
"terminal": {
|
|
57900
58091
|
"$type": "RuleCall",
|
|
57901
58092
|
"rule": {
|
|
57902
|
-
"$ref": "#/rules@
|
|
58093
|
+
"$ref": "#/rules@20"
|
|
57903
58094
|
},
|
|
57904
58095
|
"arguments": []
|
|
57905
58096
|
}
|
|
@@ -57927,7 +58118,7 @@ var MomentGrammar = () => loadedMomentGrammar ?? (loadedMomentGrammar = loadGram
|
|
|
57927
58118
|
"terminal": {
|
|
57928
58119
|
"$type": "RuleCall",
|
|
57929
58120
|
"rule": {
|
|
57930
|
-
"$ref": "#/rules@
|
|
58121
|
+
"$ref": "#/rules@42"
|
|
57931
58122
|
},
|
|
57932
58123
|
"arguments": []
|
|
57933
58124
|
}
|
|
@@ -57939,7 +58130,7 @@ var MomentGrammar = () => loadedMomentGrammar ?? (loadedMomentGrammar = loadGram
|
|
|
57939
58130
|
"terminal": {
|
|
57940
58131
|
"$type": "RuleCall",
|
|
57941
58132
|
"rule": {
|
|
57942
|
-
"$ref": "#/rules@
|
|
58133
|
+
"$ref": "#/rules@38"
|
|
57943
58134
|
},
|
|
57944
58135
|
"arguments": []
|
|
57945
58136
|
},
|
|
@@ -57959,7 +58150,7 @@ var MomentGrammar = () => loadedMomentGrammar ?? (loadedMomentGrammar = loadGram
|
|
|
57959
58150
|
"terminal": {
|
|
57960
58151
|
"$type": "RuleCall",
|
|
57961
58152
|
"rule": {
|
|
57962
|
-
"$ref": "#/rules@
|
|
58153
|
+
"$ref": "#/rules@42"
|
|
57963
58154
|
},
|
|
57964
58155
|
"arguments": []
|
|
57965
58156
|
}
|
|
@@ -58023,7 +58214,7 @@ var MomentGrammar = () => loadedMomentGrammar ?? (loadedMomentGrammar = loadGram
|
|
|
58023
58214
|
{
|
|
58024
58215
|
"$type": "RuleCall",
|
|
58025
58216
|
"rule": {
|
|
58026
|
-
"$ref": "#/rules@
|
|
58217
|
+
"$ref": "#/rules@19"
|
|
58027
58218
|
},
|
|
58028
58219
|
"arguments": []
|
|
58029
58220
|
},
|
|
@@ -58057,7 +58248,7 @@ var MomentGrammar = () => loadedMomentGrammar ?? (loadedMomentGrammar = loadGram
|
|
|
58057
58248
|
"terminal": {
|
|
58058
58249
|
"$type": "RuleCall",
|
|
58059
58250
|
"rule": {
|
|
58060
|
-
"$ref": "#/rules@
|
|
58251
|
+
"$ref": "#/rules@41"
|
|
58061
58252
|
},
|
|
58062
58253
|
"arguments": []
|
|
58063
58254
|
}
|
|
@@ -58098,14 +58289,14 @@ var MomentGrammar = () => loadedMomentGrammar ?? (loadedMomentGrammar = loadGram
|
|
|
58098
58289
|
{
|
|
58099
58290
|
"$type": "RuleCall",
|
|
58100
58291
|
"rule": {
|
|
58101
|
-
"$ref": "#/rules@
|
|
58292
|
+
"$ref": "#/rules@41"
|
|
58102
58293
|
},
|
|
58103
58294
|
"arguments": []
|
|
58104
58295
|
},
|
|
58105
58296
|
{
|
|
58106
58297
|
"$type": "RuleCall",
|
|
58107
58298
|
"rule": {
|
|
58108
|
-
"$ref": "#/rules@
|
|
58299
|
+
"$ref": "#/rules@42"
|
|
58109
58300
|
},
|
|
58110
58301
|
"arguments": []
|
|
58111
58302
|
}
|
|
@@ -58132,7 +58323,7 @@ var MomentGrammar = () => loadedMomentGrammar ?? (loadedMomentGrammar = loadGram
|
|
|
58132
58323
|
"terminal": {
|
|
58133
58324
|
"$type": "RuleCall",
|
|
58134
58325
|
"rule": {
|
|
58135
|
-
"$ref": "#/rules@
|
|
58326
|
+
"$ref": "#/rules@42"
|
|
58136
58327
|
},
|
|
58137
58328
|
"arguments": []
|
|
58138
58329
|
}
|
|
@@ -58148,7 +58339,7 @@ var MomentGrammar = () => loadedMomentGrammar ?? (loadedMomentGrammar = loadGram
|
|
|
58148
58339
|
"terminal": {
|
|
58149
58340
|
"$type": "RuleCall",
|
|
58150
58341
|
"rule": {
|
|
58151
|
-
"$ref": "#/rules@
|
|
58342
|
+
"$ref": "#/rules@34"
|
|
58152
58343
|
},
|
|
58153
58344
|
"arguments": []
|
|
58154
58345
|
}
|
|
@@ -58236,7 +58427,7 @@ var MomentGrammar = () => loadedMomentGrammar ?? (loadedMomentGrammar = loadGram
|
|
|
58236
58427
|
"terminal": {
|
|
58237
58428
|
"$type": "RuleCall",
|
|
58238
58429
|
"rule": {
|
|
58239
|
-
"$ref": "#/rules@
|
|
58430
|
+
"$ref": "#/rules@41"
|
|
58240
58431
|
},
|
|
58241
58432
|
"arguments": []
|
|
58242
58433
|
}
|
|
@@ -58309,7 +58500,7 @@ var MomentGrammar = () => loadedMomentGrammar ?? (loadedMomentGrammar = loadGram
|
|
|
58309
58500
|
"terminal": {
|
|
58310
58501
|
"$type": "RuleCall",
|
|
58311
58502
|
"rule": {
|
|
58312
|
-
"$ref": "#/rules@
|
|
58503
|
+
"$ref": "#/rules@41"
|
|
58313
58504
|
},
|
|
58314
58505
|
"arguments": []
|
|
58315
58506
|
}
|
|
@@ -58333,7 +58524,7 @@ var MomentGrammar = () => loadedMomentGrammar ?? (loadedMomentGrammar = loadGram
|
|
|
58333
58524
|
"terminal": {
|
|
58334
58525
|
"$type": "RuleCall",
|
|
58335
58526
|
"rule": {
|
|
58336
|
-
"$ref": "#/rules@
|
|
58527
|
+
"$ref": "#/rules@41"
|
|
58337
58528
|
},
|
|
58338
58529
|
"arguments": []
|
|
58339
58530
|
}
|
|
@@ -58349,7 +58540,7 @@ var MomentGrammar = () => loadedMomentGrammar ?? (loadedMomentGrammar = loadGram
|
|
|
58349
58540
|
"terminal": {
|
|
58350
58541
|
"$type": "RuleCall",
|
|
58351
58542
|
"rule": {
|
|
58352
|
-
"$ref": "#/rules@
|
|
58543
|
+
"$ref": "#/rules@36"
|
|
58353
58544
|
},
|
|
58354
58545
|
"arguments": []
|
|
58355
58546
|
}
|
|
@@ -58361,7 +58552,7 @@ var MomentGrammar = () => loadedMomentGrammar ?? (loadedMomentGrammar = loadGram
|
|
|
58361
58552
|
"terminal": {
|
|
58362
58553
|
"$type": "RuleCall",
|
|
58363
58554
|
"rule": {
|
|
58364
|
-
"$ref": "#/rules@
|
|
58555
|
+
"$ref": "#/rules@35"
|
|
58365
58556
|
},
|
|
58366
58557
|
"arguments": []
|
|
58367
58558
|
},
|
|
@@ -58390,7 +58581,7 @@ var MomentGrammar = () => loadedMomentGrammar ?? (loadedMomentGrammar = loadGram
|
|
|
58390
58581
|
"terminal": {
|
|
58391
58582
|
"$type": "RuleCall",
|
|
58392
58583
|
"rule": {
|
|
58393
|
-
"$ref": "#/rules@
|
|
58584
|
+
"$ref": "#/rules@41"
|
|
58394
58585
|
},
|
|
58395
58586
|
"arguments": []
|
|
58396
58587
|
}
|
|
@@ -58406,7 +58597,7 @@ var MomentGrammar = () => loadedMomentGrammar ?? (loadedMomentGrammar = loadGram
|
|
|
58406
58597
|
"terminal": {
|
|
58407
58598
|
"$type": "RuleCall",
|
|
58408
58599
|
"rule": {
|
|
58409
|
-
"$ref": "#/rules@
|
|
58600
|
+
"$ref": "#/rules@42"
|
|
58410
58601
|
},
|
|
58411
58602
|
"arguments": []
|
|
58412
58603
|
}
|
|
@@ -58434,7 +58625,7 @@ var MomentGrammar = () => loadedMomentGrammar ?? (loadedMomentGrammar = loadGram
|
|
|
58434
58625
|
"terminal": {
|
|
58435
58626
|
"$type": "RuleCall",
|
|
58436
58627
|
"rule": {
|
|
58437
|
-
"$ref": "#/rules@
|
|
58628
|
+
"$ref": "#/rules@41"
|
|
58438
58629
|
},
|
|
58439
58630
|
"arguments": []
|
|
58440
58631
|
}
|
|
@@ -58446,7 +58637,7 @@ var MomentGrammar = () => loadedMomentGrammar ?? (loadedMomentGrammar = loadGram
|
|
|
58446
58637
|
"terminal": {
|
|
58447
58638
|
"$type": "RuleCall",
|
|
58448
58639
|
"rule": {
|
|
58449
|
-
"$ref": "#/rules@
|
|
58640
|
+
"$ref": "#/rules@34"
|
|
58450
58641
|
},
|
|
58451
58642
|
"arguments": []
|
|
58452
58643
|
},
|
|
@@ -58475,7 +58666,7 @@ var MomentGrammar = () => loadedMomentGrammar ?? (loadedMomentGrammar = loadGram
|
|
|
58475
58666
|
"terminal": {
|
|
58476
58667
|
"$type": "RuleCall",
|
|
58477
58668
|
"rule": {
|
|
58478
|
-
"$ref": "#/rules@
|
|
58669
|
+
"$ref": "#/rules@41"
|
|
58479
58670
|
},
|
|
58480
58671
|
"arguments": []
|
|
58481
58672
|
}
|
|
@@ -58487,7 +58678,7 @@ var MomentGrammar = () => loadedMomentGrammar ?? (loadedMomentGrammar = loadGram
|
|
|
58487
58678
|
"terminal": {
|
|
58488
58679
|
"$type": "RuleCall",
|
|
58489
58680
|
"rule": {
|
|
58490
|
-
"$ref": "#/rules@
|
|
58681
|
+
"$ref": "#/rules@34"
|
|
58491
58682
|
},
|
|
58492
58683
|
"arguments": []
|
|
58493
58684
|
},
|
|
@@ -58516,7 +58707,7 @@ var MomentGrammar = () => loadedMomentGrammar ?? (loadedMomentGrammar = loadGram
|
|
|
58516
58707
|
"terminal": {
|
|
58517
58708
|
"$type": "RuleCall",
|
|
58518
58709
|
"rule": {
|
|
58519
|
-
"$ref": "#/rules@
|
|
58710
|
+
"$ref": "#/rules@41"
|
|
58520
58711
|
},
|
|
58521
58712
|
"arguments": []
|
|
58522
58713
|
}
|
|
@@ -58528,7 +58719,7 @@ var MomentGrammar = () => loadedMomentGrammar ?? (loadedMomentGrammar = loadGram
|
|
|
58528
58719
|
"terminal": {
|
|
58529
58720
|
"$type": "RuleCall",
|
|
58530
58721
|
"rule": {
|
|
58531
|
-
"$ref": "#/rules@
|
|
58722
|
+
"$ref": "#/rules@42"
|
|
58532
58723
|
},
|
|
58533
58724
|
"arguments": []
|
|
58534
58725
|
}
|
|
@@ -58544,7 +58735,7 @@ var MomentGrammar = () => loadedMomentGrammar ?? (loadedMomentGrammar = loadGram
|
|
|
58544
58735
|
"terminal": {
|
|
58545
58736
|
"$type": "RuleCall",
|
|
58546
58737
|
"rule": {
|
|
58547
|
-
"$ref": "#/rules@
|
|
58738
|
+
"$ref": "#/rules@41"
|
|
58548
58739
|
},
|
|
58549
58740
|
"arguments": []
|
|
58550
58741
|
}
|
|
@@ -58572,7 +58763,7 @@ var MomentGrammar = () => loadedMomentGrammar ?? (loadedMomentGrammar = loadGram
|
|
|
58572
58763
|
"terminal": {
|
|
58573
58764
|
"$type": "RuleCall",
|
|
58574
58765
|
"rule": {
|
|
58575
|
-
"$ref": "#/rules@
|
|
58766
|
+
"$ref": "#/rules@41"
|
|
58576
58767
|
},
|
|
58577
58768
|
"arguments": []
|
|
58578
58769
|
}
|
|
@@ -58588,7 +58779,7 @@ var MomentGrammar = () => loadedMomentGrammar ?? (loadedMomentGrammar = loadGram
|
|
|
58588
58779
|
"terminal": {
|
|
58589
58780
|
"$type": "RuleCall",
|
|
58590
58781
|
"rule": {
|
|
58591
|
-
"$ref": "#/rules@
|
|
58782
|
+
"$ref": "#/rules@41"
|
|
58592
58783
|
},
|
|
58593
58784
|
"arguments": []
|
|
58594
58785
|
}
|
|
@@ -58604,7 +58795,7 @@ var MomentGrammar = () => loadedMomentGrammar ?? (loadedMomentGrammar = loadGram
|
|
|
58604
58795
|
"terminal": {
|
|
58605
58796
|
"$type": "RuleCall",
|
|
58606
58797
|
"rule": {
|
|
58607
|
-
"$ref": "#/rules@
|
|
58798
|
+
"$ref": "#/rules@41"
|
|
58608
58799
|
},
|
|
58609
58800
|
"arguments": []
|
|
58610
58801
|
}
|
|
@@ -58620,7 +58811,7 @@ var MomentGrammar = () => loadedMomentGrammar ?? (loadedMomentGrammar = loadGram
|
|
|
58620
58811
|
"terminal": {
|
|
58621
58812
|
"$type": "RuleCall",
|
|
58622
58813
|
"rule": {
|
|
58623
|
-
"$ref": "#/rules@
|
|
58814
|
+
"$ref": "#/rules@42"
|
|
58624
58815
|
},
|
|
58625
58816
|
"arguments": []
|
|
58626
58817
|
}
|
|
@@ -58648,7 +58839,7 @@ var MomentGrammar = () => loadedMomentGrammar ?? (loadedMomentGrammar = loadGram
|
|
|
58648
58839
|
"terminal": {
|
|
58649
58840
|
"$type": "RuleCall",
|
|
58650
58841
|
"rule": {
|
|
58651
|
-
"$ref": "#/rules@
|
|
58842
|
+
"$ref": "#/rules@41"
|
|
58652
58843
|
},
|
|
58653
58844
|
"arguments": []
|
|
58654
58845
|
}
|
|
@@ -58680,7 +58871,7 @@ var MomentGrammar = () => loadedMomentGrammar ?? (loadedMomentGrammar = loadGram
|
|
|
58680
58871
|
"terminal": {
|
|
58681
58872
|
"$type": "RuleCall",
|
|
58682
58873
|
"rule": {
|
|
58683
|
-
"$ref": "#/rules@
|
|
58874
|
+
"$ref": "#/rules@42"
|
|
58684
58875
|
},
|
|
58685
58876
|
"arguments": []
|
|
58686
58877
|
}
|
|
@@ -58699,7 +58890,7 @@ var MomentGrammar = () => loadedMomentGrammar ?? (loadedMomentGrammar = loadGram
|
|
|
58699
58890
|
"terminal": {
|
|
58700
58891
|
"$type": "RuleCall",
|
|
58701
58892
|
"rule": {
|
|
58702
|
-
"$ref": "#/rules@
|
|
58893
|
+
"$ref": "#/rules@41"
|
|
58703
58894
|
},
|
|
58704
58895
|
"arguments": []
|
|
58705
58896
|
}
|
|
@@ -58726,7 +58917,7 @@ var MomentGrammar = () => loadedMomentGrammar ?? (loadedMomentGrammar = loadGram
|
|
|
58726
58917
|
"terminal": {
|
|
58727
58918
|
"$type": "RuleCall",
|
|
58728
58919
|
"rule": {
|
|
58729
|
-
"$ref": "#/rules@
|
|
58920
|
+
"$ref": "#/rules@41"
|
|
58730
58921
|
},
|
|
58731
58922
|
"arguments": []
|
|
58732
58923
|
}
|
|
@@ -58763,7 +58954,7 @@ var MomentGrammar = () => loadedMomentGrammar ?? (loadedMomentGrammar = loadGram
|
|
|
58763
58954
|
"terminal": {
|
|
58764
58955
|
"$type": "RuleCall",
|
|
58765
58956
|
"rule": {
|
|
58766
|
-
"$ref": "#/rules@
|
|
58957
|
+
"$ref": "#/rules@41"
|
|
58767
58958
|
},
|
|
58768
58959
|
"arguments": []
|
|
58769
58960
|
}
|
|
@@ -58779,7 +58970,7 @@ var MomentGrammar = () => loadedMomentGrammar ?? (loadedMomentGrammar = loadGram
|
|
|
58779
58970
|
"terminal": {
|
|
58780
58971
|
"$type": "RuleCall",
|
|
58781
58972
|
"rule": {
|
|
58782
|
-
"$ref": "#/rules@
|
|
58973
|
+
"$ref": "#/rules@41"
|
|
58783
58974
|
},
|
|
58784
58975
|
"arguments": []
|
|
58785
58976
|
}
|
|
@@ -58790,36 +58981,27 @@ var MomentGrammar = () => loadedMomentGrammar ?? (loadedMomentGrammar = loadGram
|
|
|
58790
58981
|
},
|
|
58791
58982
|
{
|
|
58792
58983
|
"$type": "Assignment",
|
|
58793
|
-
"feature": "
|
|
58794
|
-
"operator": "
|
|
58984
|
+
"feature": "initialState",
|
|
58985
|
+
"operator": "=",
|
|
58795
58986
|
"terminal": {
|
|
58796
58987
|
"$type": "RuleCall",
|
|
58797
58988
|
"rule": {
|
|
58798
|
-
"$ref": "#/rules@
|
|
58989
|
+
"$ref": "#/rules@41"
|
|
58799
58990
|
},
|
|
58800
58991
|
"arguments": []
|
|
58801
58992
|
}
|
|
58802
58993
|
},
|
|
58803
58994
|
{
|
|
58804
|
-
"$type": "
|
|
58805
|
-
"
|
|
58806
|
-
|
|
58807
|
-
|
|
58808
|
-
|
|
58995
|
+
"$type": "Assignment",
|
|
58996
|
+
"feature": "transitions",
|
|
58997
|
+
"operator": "+=",
|
|
58998
|
+
"terminal": {
|
|
58999
|
+
"$type": "RuleCall",
|
|
59000
|
+
"rule": {
|
|
59001
|
+
"$ref": "#/rules@17"
|
|
58809
59002
|
},
|
|
58810
|
-
|
|
58811
|
-
|
|
58812
|
-
"feature": "states",
|
|
58813
|
-
"operator": "+=",
|
|
58814
|
-
"terminal": {
|
|
58815
|
-
"$type": "RuleCall",
|
|
58816
|
-
"rule": {
|
|
58817
|
-
"$ref": "#/rules@40"
|
|
58818
|
-
},
|
|
58819
|
-
"arguments": []
|
|
58820
|
-
}
|
|
58821
|
-
}
|
|
58822
|
-
],
|
|
59003
|
+
"arguments": []
|
|
59004
|
+
},
|
|
58823
59005
|
"cardinality": "*"
|
|
58824
59006
|
},
|
|
58825
59007
|
{
|
|
@@ -58833,7 +59015,7 @@ var MomentGrammar = () => loadedMomentGrammar ?? (loadedMomentGrammar = loadGram
|
|
|
58833
59015
|
"terminal": {
|
|
58834
59016
|
"$type": "RuleCall",
|
|
58835
59017
|
"rule": {
|
|
58836
|
-
"$ref": "#/rules@
|
|
59018
|
+
"$ref": "#/rules@42"
|
|
58837
59019
|
},
|
|
58838
59020
|
"arguments": []
|
|
58839
59021
|
}
|
|
@@ -58849,10 +59031,60 @@ var MomentGrammar = () => loadedMomentGrammar ?? (loadedMomentGrammar = loadGram
|
|
|
58849
59031
|
"terminal": {
|
|
58850
59032
|
"$type": "RuleCall",
|
|
58851
59033
|
"rule": {
|
|
58852
|
-
"$ref": "#/rules@
|
|
59034
|
+
"$ref": "#/rules@18"
|
|
59035
|
+
},
|
|
59036
|
+
"arguments": []
|
|
59037
|
+
}
|
|
59038
|
+
}
|
|
59039
|
+
]
|
|
59040
|
+
},
|
|
59041
|
+
"entry": false,
|
|
59042
|
+
"fragment": false,
|
|
59043
|
+
"parameters": []
|
|
59044
|
+
},
|
|
59045
|
+
{
|
|
59046
|
+
"$type": "ParserRule",
|
|
59047
|
+
"name": "SagaTransition",
|
|
59048
|
+
"definition": {
|
|
59049
|
+
"$type": "Group",
|
|
59050
|
+
"elements": [
|
|
59051
|
+
{
|
|
59052
|
+
"$type": "Keyword",
|
|
59053
|
+
"value": "->"
|
|
59054
|
+
},
|
|
59055
|
+
{
|
|
59056
|
+
"$type": "Assignment",
|
|
59057
|
+
"feature": "target",
|
|
59058
|
+
"operator": "=",
|
|
59059
|
+
"terminal": {
|
|
59060
|
+
"$type": "RuleCall",
|
|
59061
|
+
"rule": {
|
|
59062
|
+
"$ref": "#/rules@41"
|
|
58853
59063
|
},
|
|
58854
59064
|
"arguments": []
|
|
58855
59065
|
}
|
|
59066
|
+
},
|
|
59067
|
+
{
|
|
59068
|
+
"$type": "Group",
|
|
59069
|
+
"elements": [
|
|
59070
|
+
{
|
|
59071
|
+
"$type": "Keyword",
|
|
59072
|
+
"value": "on"
|
|
59073
|
+
},
|
|
59074
|
+
{
|
|
59075
|
+
"$type": "Assignment",
|
|
59076
|
+
"feature": "event",
|
|
59077
|
+
"operator": "=",
|
|
59078
|
+
"terminal": {
|
|
59079
|
+
"$type": "RuleCall",
|
|
59080
|
+
"rule": {
|
|
59081
|
+
"$ref": "#/rules@41"
|
|
59082
|
+
},
|
|
59083
|
+
"arguments": []
|
|
59084
|
+
}
|
|
59085
|
+
}
|
|
59086
|
+
],
|
|
59087
|
+
"cardinality": "?"
|
|
58856
59088
|
}
|
|
58857
59089
|
]
|
|
58858
59090
|
},
|
|
@@ -58873,7 +59105,7 @@ var MomentGrammar = () => loadedMomentGrammar ?? (loadedMomentGrammar = loadGram
|
|
|
58873
59105
|
"terminal": {
|
|
58874
59106
|
"$type": "RuleCall",
|
|
58875
59107
|
"rule": {
|
|
58876
|
-
"$ref": "#/rules@
|
|
59108
|
+
"$ref": "#/rules@41"
|
|
58877
59109
|
},
|
|
58878
59110
|
"arguments": []
|
|
58879
59111
|
}
|
|
@@ -58910,7 +59142,7 @@ var MomentGrammar = () => loadedMomentGrammar ?? (loadedMomentGrammar = loadGram
|
|
|
58910
59142
|
"terminal": {
|
|
58911
59143
|
"$type": "RuleCall",
|
|
58912
59144
|
"rule": {
|
|
58913
|
-
"$ref": "#/rules@
|
|
59145
|
+
"$ref": "#/rules@41"
|
|
58914
59146
|
},
|
|
58915
59147
|
"arguments": []
|
|
58916
59148
|
}
|
|
@@ -58926,7 +59158,7 @@ var MomentGrammar = () => loadedMomentGrammar ?? (loadedMomentGrammar = loadGram
|
|
|
58926
59158
|
"terminal": {
|
|
58927
59159
|
"$type": "RuleCall",
|
|
58928
59160
|
"rule": {
|
|
58929
|
-
"$ref": "#/rules@
|
|
59161
|
+
"$ref": "#/rules@41"
|
|
58930
59162
|
},
|
|
58931
59163
|
"arguments": []
|
|
58932
59164
|
}
|
|
@@ -58942,7 +59174,7 @@ var MomentGrammar = () => loadedMomentGrammar ?? (loadedMomentGrammar = loadGram
|
|
|
58942
59174
|
"terminal": {
|
|
58943
59175
|
"$type": "RuleCall",
|
|
58944
59176
|
"rule": {
|
|
58945
|
-
"$ref": "#/rules@
|
|
59177
|
+
"$ref": "#/rules@40"
|
|
58946
59178
|
},
|
|
58947
59179
|
"arguments": []
|
|
58948
59180
|
}
|
|
@@ -58958,7 +59190,7 @@ var MomentGrammar = () => loadedMomentGrammar ?? (loadedMomentGrammar = loadGram
|
|
|
58958
59190
|
"terminal": {
|
|
58959
59191
|
"$type": "RuleCall",
|
|
58960
59192
|
"rule": {
|
|
58961
|
-
"$ref": "#/rules@
|
|
59193
|
+
"$ref": "#/rules@42"
|
|
58962
59194
|
},
|
|
58963
59195
|
"arguments": []
|
|
58964
59196
|
}
|
|
@@ -58986,7 +59218,7 @@ var MomentGrammar = () => loadedMomentGrammar ?? (loadedMomentGrammar = loadGram
|
|
|
58986
59218
|
"terminal": {
|
|
58987
59219
|
"$type": "RuleCall",
|
|
58988
59220
|
"rule": {
|
|
58989
|
-
"$ref": "#/rules@
|
|
59221
|
+
"$ref": "#/rules@42"
|
|
58990
59222
|
},
|
|
58991
59223
|
"arguments": []
|
|
58992
59224
|
}
|
|
@@ -59005,7 +59237,7 @@ var MomentGrammar = () => loadedMomentGrammar ?? (loadedMomentGrammar = loadGram
|
|
|
59005
59237
|
"terminal": {
|
|
59006
59238
|
"$type": "RuleCall",
|
|
59007
59239
|
"rule": {
|
|
59008
|
-
"$ref": "#/rules@
|
|
59240
|
+
"$ref": "#/rules@42"
|
|
59009
59241
|
},
|
|
59010
59242
|
"arguments": []
|
|
59011
59243
|
}
|
|
@@ -59020,7 +59252,7 @@ var MomentGrammar = () => loadedMomentGrammar ?? (loadedMomentGrammar = loadGram
|
|
|
59020
59252
|
"terminal": {
|
|
59021
59253
|
"$type": "RuleCall",
|
|
59022
59254
|
"rule": {
|
|
59023
|
-
"$ref": "#/rules@
|
|
59255
|
+
"$ref": "#/rules@21"
|
|
59024
59256
|
},
|
|
59025
59257
|
"arguments": []
|
|
59026
59258
|
},
|
|
@@ -59033,7 +59265,7 @@ var MomentGrammar = () => loadedMomentGrammar ?? (loadedMomentGrammar = loadGram
|
|
|
59033
59265
|
"terminal": {
|
|
59034
59266
|
"$type": "RuleCall",
|
|
59035
59267
|
"rule": {
|
|
59036
|
-
"$ref": "#/rules@
|
|
59268
|
+
"$ref": "#/rules@22"
|
|
59037
59269
|
},
|
|
59038
59270
|
"arguments": []
|
|
59039
59271
|
},
|
|
@@ -59076,7 +59308,7 @@ var MomentGrammar = () => loadedMomentGrammar ?? (loadedMomentGrammar = loadGram
|
|
|
59076
59308
|
"terminal": {
|
|
59077
59309
|
"$type": "RuleCall",
|
|
59078
59310
|
"rule": {
|
|
59079
|
-
"$ref": "#/rules@
|
|
59311
|
+
"$ref": "#/rules@41"
|
|
59080
59312
|
},
|
|
59081
59313
|
"arguments": []
|
|
59082
59314
|
}
|
|
@@ -59088,7 +59320,7 @@ var MomentGrammar = () => loadedMomentGrammar ?? (loadedMomentGrammar = loadGram
|
|
|
59088
59320
|
"terminal": {
|
|
59089
59321
|
"$type": "RuleCall",
|
|
59090
59322
|
"rule": {
|
|
59091
|
-
"$ref": "#/rules@
|
|
59323
|
+
"$ref": "#/rules@42"
|
|
59092
59324
|
},
|
|
59093
59325
|
"arguments": []
|
|
59094
59326
|
}
|
|
@@ -59100,7 +59332,7 @@ var MomentGrammar = () => loadedMomentGrammar ?? (loadedMomentGrammar = loadGram
|
|
|
59100
59332
|
"terminal": {
|
|
59101
59333
|
"$type": "RuleCall",
|
|
59102
59334
|
"rule": {
|
|
59103
|
-
"$ref": "#/rules@
|
|
59335
|
+
"$ref": "#/rules@38"
|
|
59104
59336
|
},
|
|
59105
59337
|
"arguments": []
|
|
59106
59338
|
},
|
|
@@ -59129,7 +59361,7 @@ var MomentGrammar = () => loadedMomentGrammar ?? (loadedMomentGrammar = loadGram
|
|
|
59129
59361
|
"terminal": {
|
|
59130
59362
|
"$type": "RuleCall",
|
|
59131
59363
|
"rule": {
|
|
59132
|
-
"$ref": "#/rules@
|
|
59364
|
+
"$ref": "#/rules@42"
|
|
59133
59365
|
},
|
|
59134
59366
|
"arguments": []
|
|
59135
59367
|
}
|
|
@@ -59154,7 +59386,7 @@ var MomentGrammar = () => loadedMomentGrammar ?? (loadedMomentGrammar = loadGram
|
|
|
59154
59386
|
"terminal": {
|
|
59155
59387
|
"$type": "RuleCall",
|
|
59156
59388
|
"rule": {
|
|
59157
|
-
"$ref": "#/rules@
|
|
59389
|
+
"$ref": "#/rules@24"
|
|
59158
59390
|
},
|
|
59159
59391
|
"arguments": []
|
|
59160
59392
|
}
|
|
@@ -59166,7 +59398,7 @@ var MomentGrammar = () => loadedMomentGrammar ?? (loadedMomentGrammar = loadGram
|
|
|
59166
59398
|
"terminal": {
|
|
59167
59399
|
"$type": "RuleCall",
|
|
59168
59400
|
"rule": {
|
|
59169
|
-
"$ref": "#/rules@
|
|
59401
|
+
"$ref": "#/rules@23"
|
|
59170
59402
|
},
|
|
59171
59403
|
"arguments": []
|
|
59172
59404
|
}
|
|
@@ -59197,7 +59429,7 @@ var MomentGrammar = () => loadedMomentGrammar ?? (loadedMomentGrammar = loadGram
|
|
|
59197
59429
|
"terminal": {
|
|
59198
59430
|
"$type": "RuleCall",
|
|
59199
59431
|
"rule": {
|
|
59200
|
-
"$ref": "#/rules@
|
|
59432
|
+
"$ref": "#/rules@41"
|
|
59201
59433
|
},
|
|
59202
59434
|
"arguments": []
|
|
59203
59435
|
}
|
|
@@ -59216,7 +59448,7 @@ var MomentGrammar = () => loadedMomentGrammar ?? (loadedMomentGrammar = loadGram
|
|
|
59216
59448
|
"terminal": {
|
|
59217
59449
|
"$type": "RuleCall",
|
|
59218
59450
|
"rule": {
|
|
59219
|
-
"$ref": "#/rules@
|
|
59451
|
+
"$ref": "#/rules@41"
|
|
59220
59452
|
},
|
|
59221
59453
|
"arguments": []
|
|
59222
59454
|
}
|
|
@@ -59235,7 +59467,7 @@ var MomentGrammar = () => loadedMomentGrammar ?? (loadedMomentGrammar = loadGram
|
|
|
59235
59467
|
"terminal": {
|
|
59236
59468
|
"$type": "RuleCall",
|
|
59237
59469
|
"rule": {
|
|
59238
|
-
"$ref": "#/rules@
|
|
59470
|
+
"$ref": "#/rules@24"
|
|
59239
59471
|
},
|
|
59240
59472
|
"arguments": []
|
|
59241
59473
|
},
|
|
@@ -59260,7 +59492,7 @@ var MomentGrammar = () => loadedMomentGrammar ?? (loadedMomentGrammar = loadGram
|
|
|
59260
59492
|
"terminal": {
|
|
59261
59493
|
"$type": "RuleCall",
|
|
59262
59494
|
"rule": {
|
|
59263
|
-
"$ref": "#/rules@
|
|
59495
|
+
"$ref": "#/rules@41"
|
|
59264
59496
|
},
|
|
59265
59497
|
"arguments": []
|
|
59266
59498
|
}
|
|
@@ -59276,7 +59508,7 @@ var MomentGrammar = () => loadedMomentGrammar ?? (loadedMomentGrammar = loadGram
|
|
|
59276
59508
|
"terminal": {
|
|
59277
59509
|
"$type": "RuleCall",
|
|
59278
59510
|
"rule": {
|
|
59279
|
-
"$ref": "#/rules@
|
|
59511
|
+
"$ref": "#/rules@41"
|
|
59280
59512
|
},
|
|
59281
59513
|
"arguments": []
|
|
59282
59514
|
}
|
|
@@ -59288,7 +59520,7 @@ var MomentGrammar = () => loadedMomentGrammar ?? (loadedMomentGrammar = loadGram
|
|
|
59288
59520
|
"terminal": {
|
|
59289
59521
|
"$type": "RuleCall",
|
|
59290
59522
|
"rule": {
|
|
59291
|
-
"$ref": "#/rules@
|
|
59523
|
+
"$ref": "#/rules@25"
|
|
59292
59524
|
},
|
|
59293
59525
|
"arguments": []
|
|
59294
59526
|
},
|
|
@@ -59301,7 +59533,7 @@ var MomentGrammar = () => loadedMomentGrammar ?? (loadedMomentGrammar = loadGram
|
|
|
59301
59533
|
"terminal": {
|
|
59302
59534
|
"$type": "RuleCall",
|
|
59303
59535
|
"rule": {
|
|
59304
|
-
"$ref": "#/rules@
|
|
59536
|
+
"$ref": "#/rules@26"
|
|
59305
59537
|
},
|
|
59306
59538
|
"arguments": []
|
|
59307
59539
|
},
|
|
@@ -59314,7 +59546,7 @@ var MomentGrammar = () => loadedMomentGrammar ?? (loadedMomentGrammar = loadGram
|
|
|
59314
59546
|
"terminal": {
|
|
59315
59547
|
"$type": "RuleCall",
|
|
59316
59548
|
"rule": {
|
|
59317
|
-
"$ref": "#/rules@
|
|
59549
|
+
"$ref": "#/rules@29"
|
|
59318
59550
|
},
|
|
59319
59551
|
"arguments": []
|
|
59320
59552
|
},
|
|
@@ -59327,7 +59559,7 @@ var MomentGrammar = () => loadedMomentGrammar ?? (loadedMomentGrammar = loadGram
|
|
|
59327
59559
|
"terminal": {
|
|
59328
59560
|
"$type": "RuleCall",
|
|
59329
59561
|
"rule": {
|
|
59330
|
-
"$ref": "#/rules@
|
|
59562
|
+
"$ref": "#/rules@28"
|
|
59331
59563
|
},
|
|
59332
59564
|
"arguments": []
|
|
59333
59565
|
},
|
|
@@ -59363,7 +59595,7 @@ var MomentGrammar = () => loadedMomentGrammar ?? (loadedMomentGrammar = loadGram
|
|
|
59363
59595
|
"terminal": {
|
|
59364
59596
|
"$type": "RuleCall",
|
|
59365
59597
|
"rule": {
|
|
59366
|
-
"$ref": "#/rules@
|
|
59598
|
+
"$ref": "#/rules@43"
|
|
59367
59599
|
},
|
|
59368
59600
|
"arguments": []
|
|
59369
59601
|
}
|
|
@@ -59375,7 +59607,7 @@ var MomentGrammar = () => loadedMomentGrammar ?? (loadedMomentGrammar = loadGram
|
|
|
59375
59607
|
"terminal": {
|
|
59376
59608
|
"$type": "RuleCall",
|
|
59377
59609
|
"rule": {
|
|
59378
|
-
"$ref": "#/rules@
|
|
59610
|
+
"$ref": "#/rules@41"
|
|
59379
59611
|
},
|
|
59380
59612
|
"arguments": []
|
|
59381
59613
|
}
|
|
@@ -59409,7 +59641,7 @@ var MomentGrammar = () => loadedMomentGrammar ?? (loadedMomentGrammar = loadGram
|
|
|
59409
59641
|
"terminal": {
|
|
59410
59642
|
"$type": "RuleCall",
|
|
59411
59643
|
"rule": {
|
|
59412
|
-
"$ref": "#/rules@
|
|
59644
|
+
"$ref": "#/rules@27"
|
|
59413
59645
|
},
|
|
59414
59646
|
"arguments": []
|
|
59415
59647
|
}
|
|
@@ -59454,21 +59686,21 @@ var MomentGrammar = () => loadedMomentGrammar ?? (loadedMomentGrammar = loadGram
|
|
|
59454
59686
|
{
|
|
59455
59687
|
"$type": "RuleCall",
|
|
59456
59688
|
"rule": {
|
|
59457
|
-
"$ref": "#/rules@
|
|
59689
|
+
"$ref": "#/rules@31"
|
|
59458
59690
|
},
|
|
59459
59691
|
"arguments": []
|
|
59460
59692
|
},
|
|
59461
59693
|
{
|
|
59462
59694
|
"$type": "RuleCall",
|
|
59463
59695
|
"rule": {
|
|
59464
|
-
"$ref": "#/rules@
|
|
59696
|
+
"$ref": "#/rules@32"
|
|
59465
59697
|
},
|
|
59466
59698
|
"arguments": []
|
|
59467
59699
|
},
|
|
59468
59700
|
{
|
|
59469
59701
|
"$type": "RuleCall",
|
|
59470
59702
|
"rule": {
|
|
59471
|
-
"$ref": "#/rules@
|
|
59703
|
+
"$ref": "#/rules@33"
|
|
59472
59704
|
},
|
|
59473
59705
|
"arguments": []
|
|
59474
59706
|
}
|
|
@@ -59495,7 +59727,7 @@ var MomentGrammar = () => loadedMomentGrammar ?? (loadedMomentGrammar = loadGram
|
|
|
59495
59727
|
"terminal": {
|
|
59496
59728
|
"$type": "RuleCall",
|
|
59497
59729
|
"rule": {
|
|
59498
|
-
"$ref": "#/rules@
|
|
59730
|
+
"$ref": "#/rules@41"
|
|
59499
59731
|
},
|
|
59500
59732
|
"arguments": []
|
|
59501
59733
|
}
|
|
@@ -59511,7 +59743,7 @@ var MomentGrammar = () => loadedMomentGrammar ?? (loadedMomentGrammar = loadGram
|
|
|
59511
59743
|
"terminal": {
|
|
59512
59744
|
"$type": "RuleCall",
|
|
59513
59745
|
"rule": {
|
|
59514
|
-
"$ref": "#/rules@
|
|
59746
|
+
"$ref": "#/rules@40"
|
|
59515
59747
|
},
|
|
59516
59748
|
"arguments": []
|
|
59517
59749
|
}
|
|
@@ -59527,7 +59759,7 @@ var MomentGrammar = () => loadedMomentGrammar ?? (loadedMomentGrammar = loadGram
|
|
|
59527
59759
|
"terminal": {
|
|
59528
59760
|
"$type": "RuleCall",
|
|
59529
59761
|
"rule": {
|
|
59530
|
-
"$ref": "#/rules@
|
|
59762
|
+
"$ref": "#/rules@30"
|
|
59531
59763
|
},
|
|
59532
59764
|
"arguments": []
|
|
59533
59765
|
},
|
|
@@ -59552,7 +59784,7 @@ var MomentGrammar = () => loadedMomentGrammar ?? (loadedMomentGrammar = loadGram
|
|
|
59552
59784
|
"terminal": {
|
|
59553
59785
|
"$type": "RuleCall",
|
|
59554
59786
|
"rule": {
|
|
59555
|
-
"$ref": "#/rules@
|
|
59787
|
+
"$ref": "#/rules@41"
|
|
59556
59788
|
},
|
|
59557
59789
|
"arguments": []
|
|
59558
59790
|
}
|
|
@@ -59568,7 +59800,7 @@ var MomentGrammar = () => loadedMomentGrammar ?? (loadedMomentGrammar = loadGram
|
|
|
59568
59800
|
"terminal": {
|
|
59569
59801
|
"$type": "RuleCall",
|
|
59570
59802
|
"rule": {
|
|
59571
|
-
"$ref": "#/rules@
|
|
59803
|
+
"$ref": "#/rules@36"
|
|
59572
59804
|
},
|
|
59573
59805
|
"arguments": []
|
|
59574
59806
|
}
|
|
@@ -59606,7 +59838,7 @@ var MomentGrammar = () => loadedMomentGrammar ?? (loadedMomentGrammar = loadGram
|
|
|
59606
59838
|
"terminal": {
|
|
59607
59839
|
"$type": "RuleCall",
|
|
59608
59840
|
"rule": {
|
|
59609
|
-
"$ref": "#/rules@
|
|
59841
|
+
"$ref": "#/rules@41"
|
|
59610
59842
|
},
|
|
59611
59843
|
"arguments": []
|
|
59612
59844
|
}
|
|
@@ -59634,7 +59866,7 @@ var MomentGrammar = () => loadedMomentGrammar ?? (loadedMomentGrammar = loadGram
|
|
|
59634
59866
|
"terminal": {
|
|
59635
59867
|
"$type": "RuleCall",
|
|
59636
59868
|
"rule": {
|
|
59637
|
-
"$ref": "#/rules@
|
|
59869
|
+
"$ref": "#/rules@41"
|
|
59638
59870
|
},
|
|
59639
59871
|
"arguments": []
|
|
59640
59872
|
}
|
|
@@ -59662,7 +59894,7 @@ var MomentGrammar = () => loadedMomentGrammar ?? (loadedMomentGrammar = loadGram
|
|
|
59662
59894
|
"terminal": {
|
|
59663
59895
|
"$type": "RuleCall",
|
|
59664
59896
|
"rule": {
|
|
59665
|
-
"$ref": "#/rules@
|
|
59897
|
+
"$ref": "#/rules@42"
|
|
59666
59898
|
},
|
|
59667
59899
|
"arguments": []
|
|
59668
59900
|
}
|
|
@@ -59686,7 +59918,7 @@ var MomentGrammar = () => loadedMomentGrammar ?? (loadedMomentGrammar = loadGram
|
|
|
59686
59918
|
"terminal": {
|
|
59687
59919
|
"$type": "RuleCall",
|
|
59688
59920
|
"rule": {
|
|
59689
|
-
"$ref": "#/rules@
|
|
59921
|
+
"$ref": "#/rules@41"
|
|
59690
59922
|
},
|
|
59691
59923
|
"arguments": []
|
|
59692
59924
|
}
|
|
@@ -59702,7 +59934,7 @@ var MomentGrammar = () => loadedMomentGrammar ?? (loadedMomentGrammar = loadGram
|
|
|
59702
59934
|
"terminal": {
|
|
59703
59935
|
"$type": "RuleCall",
|
|
59704
59936
|
"rule": {
|
|
59705
|
-
"$ref": "#/rules@
|
|
59937
|
+
"$ref": "#/rules@36"
|
|
59706
59938
|
},
|
|
59707
59939
|
"arguments": []
|
|
59708
59940
|
}
|
|
@@ -59714,7 +59946,7 @@ var MomentGrammar = () => loadedMomentGrammar ?? (loadedMomentGrammar = loadGram
|
|
|
59714
59946
|
"terminal": {
|
|
59715
59947
|
"$type": "RuleCall",
|
|
59716
59948
|
"rule": {
|
|
59717
|
-
"$ref": "#/rules@
|
|
59949
|
+
"$ref": "#/rules@35"
|
|
59718
59950
|
},
|
|
59719
59951
|
"arguments": []
|
|
59720
59952
|
},
|
|
@@ -59747,7 +59979,7 @@ var MomentGrammar = () => loadedMomentGrammar ?? (loadedMomentGrammar = loadGram
|
|
|
59747
59979
|
"terminal": {
|
|
59748
59980
|
"$type": "RuleCall",
|
|
59749
59981
|
"rule": {
|
|
59750
|
-
"$ref": "#/rules@
|
|
59982
|
+
"$ref": "#/rules@42"
|
|
59751
59983
|
},
|
|
59752
59984
|
"arguments": []
|
|
59753
59985
|
}
|
|
@@ -59763,7 +59995,7 @@ var MomentGrammar = () => loadedMomentGrammar ?? (loadedMomentGrammar = loadGram
|
|
|
59763
59995
|
"terminal": {
|
|
59764
59996
|
"$type": "RuleCall",
|
|
59765
59997
|
"rule": {
|
|
59766
|
-
"$ref": "#/rules@
|
|
59998
|
+
"$ref": "#/rules@42"
|
|
59767
59999
|
},
|
|
59768
60000
|
"arguments": []
|
|
59769
60001
|
}
|
|
@@ -59791,7 +60023,7 @@ var MomentGrammar = () => loadedMomentGrammar ?? (loadedMomentGrammar = loadGram
|
|
|
59791
60023
|
"terminal": {
|
|
59792
60024
|
"$type": "RuleCall",
|
|
59793
60025
|
"rule": {
|
|
59794
|
-
"$ref": "#/rules@
|
|
60026
|
+
"$ref": "#/rules@37"
|
|
59795
60027
|
},
|
|
59796
60028
|
"arguments": []
|
|
59797
60029
|
}
|
|
@@ -59850,7 +60082,7 @@ var MomentGrammar = () => loadedMomentGrammar ?? (loadedMomentGrammar = loadGram
|
|
|
59850
60082
|
{
|
|
59851
60083
|
"$type": "RuleCall",
|
|
59852
60084
|
"rule": {
|
|
59853
|
-
"$ref": "#/rules@
|
|
60085
|
+
"$ref": "#/rules@41"
|
|
59854
60086
|
},
|
|
59855
60087
|
"arguments": []
|
|
59856
60088
|
}
|
|
@@ -59877,7 +60109,7 @@ var MomentGrammar = () => loadedMomentGrammar ?? (loadedMomentGrammar = loadGram
|
|
|
59877
60109
|
"terminal": {
|
|
59878
60110
|
"$type": "RuleCall",
|
|
59879
60111
|
"rule": {
|
|
59880
|
-
"$ref": "#/rules@
|
|
60112
|
+
"$ref": "#/rules@39"
|
|
59881
60113
|
},
|
|
59882
60114
|
"arguments": []
|
|
59883
60115
|
}
|
|
@@ -59959,7 +60191,7 @@ var MomentGrammar = () => loadedMomentGrammar ?? (loadedMomentGrammar = loadGram
|
|
|
59959
60191
|
{
|
|
59960
60192
|
"$type": "RuleCall",
|
|
59961
60193
|
"rule": {
|
|
59962
|
-
"$ref": "#/rules@
|
|
60194
|
+
"$ref": "#/rules@41"
|
|
59963
60195
|
},
|
|
59964
60196
|
"arguments": []
|
|
59965
60197
|
}
|
|
@@ -60061,25 +60293,90 @@ var MomentGeneratedModule = {
|
|
|
60061
60293
|
parser: {}
|
|
60062
60294
|
};
|
|
60063
60295
|
|
|
60296
|
+
// ../core/dist/parser/moment-sequence.js
|
|
60297
|
+
function buildMomentSequence(moment) {
|
|
60298
|
+
const positioned = [];
|
|
60299
|
+
moment.nodes.forEach((node, index) => {
|
|
60300
|
+
positioned.push({ item: { kind: "entry", index }, offset: node.$cstNode?.offset });
|
|
60301
|
+
});
|
|
60302
|
+
moment.whenBlocks.forEach((block2, index) => {
|
|
60303
|
+
positioned.push({ item: { kind: "branch", index }, offset: block2.$cstNode?.offset });
|
|
60304
|
+
});
|
|
60305
|
+
const fromCst = positioned.every((p) => p.offset !== void 0);
|
|
60306
|
+
if (!fromCst) {
|
|
60307
|
+
return { sequence: positioned.map((p) => p.item), fromCst: false };
|
|
60308
|
+
}
|
|
60309
|
+
const sequence = positioned.slice().sort((a, b) => a.offset - b.offset).map((p) => p.item);
|
|
60310
|
+
return { sequence, fromCst: true };
|
|
60311
|
+
}
|
|
60312
|
+
|
|
60064
60313
|
// ../core/dist/validation/moment-validator.js
|
|
60314
|
+
function unquote(s) {
|
|
60315
|
+
return s.startsWith('"') && s.endsWith('"') ? s.slice(1, -1) : s;
|
|
60316
|
+
}
|
|
60317
|
+
function buildCrossFileContext(file) {
|
|
60318
|
+
const declaredContextNames = [];
|
|
60319
|
+
const declaredEvents = /* @__PURE__ */ new Map();
|
|
60320
|
+
const declaredBuildingBlocks = /* @__PURE__ */ new Map();
|
|
60321
|
+
const declaredSagas = [];
|
|
60322
|
+
for (const ctx of file.contexts) {
|
|
60323
|
+
const contextName = unquote(ctx.name);
|
|
60324
|
+
declaredContextNames.push(contextName);
|
|
60325
|
+
const events = [];
|
|
60326
|
+
const blocks = [];
|
|
60327
|
+
for (const member of ctx.members) {
|
|
60328
|
+
if (isAggregateDeclaration(member)) {
|
|
60329
|
+
for (const aggMember of member.members) {
|
|
60330
|
+
if (isCommandDeclaration(aggMember)) {
|
|
60331
|
+
blocks.push({ name: aggMember.name, kind: "command" });
|
|
60332
|
+
} else if (isDomainEventDeclaration(aggMember)) {
|
|
60333
|
+
events.push(aggMember.name);
|
|
60334
|
+
blocks.push({ name: aggMember.name, kind: "event" });
|
|
60335
|
+
} else if (isValueObjectDeclaration(aggMember)) {
|
|
60336
|
+
blocks.push({ name: aggMember.name, kind: "value-object" });
|
|
60337
|
+
}
|
|
60338
|
+
}
|
|
60339
|
+
} else if (isPolicyDeclaration(member)) {
|
|
60340
|
+
blocks.push({ name: member.name, kind: "policy" });
|
|
60341
|
+
} else if (isSagaDeclaration(member)) {
|
|
60342
|
+
blocks.push({ name: member.name, kind: "saga" });
|
|
60343
|
+
declaredSagas.push(member.name);
|
|
60344
|
+
}
|
|
60345
|
+
}
|
|
60346
|
+
declaredEvents.set(contextName, events);
|
|
60347
|
+
declaredBuildingBlocks.set(contextName, blocks);
|
|
60348
|
+
}
|
|
60349
|
+
return { declaredContextNames, declaredEvents, declaredBuildingBlocks, declaredSagas };
|
|
60350
|
+
}
|
|
60065
60351
|
function registerMomentValidationChecks(services) {
|
|
60066
60352
|
const registry = services.validation.ValidationRegistry;
|
|
60067
60353
|
const validator = services.validation.MomentValidator;
|
|
60068
60354
|
const checks = {
|
|
60069
60355
|
MomentDeclaration: validator.checkMoment,
|
|
60070
60356
|
FieldDeclaration: validator.checkDeprecatedReplacement,
|
|
60357
|
+
InputField: validator.checkDeprecatedReplacement,
|
|
60071
60358
|
AnnotationDeclaration: validator.checkAnnotationName,
|
|
60359
|
+
ContextDeclaration: validator.checkTrailingAnnotation,
|
|
60360
|
+
AggregateDeclaration: validator.checkTrailingAnnotation,
|
|
60361
|
+
SagaDeclaration: validator.checkSagaTransitionEvents,
|
|
60072
60362
|
NodePlacement: [
|
|
60073
60363
|
validator.checkNodePlacement,
|
|
60074
60364
|
validator.checkOptionalWithCrossing,
|
|
60075
60365
|
validator.checkTerminalIsLast,
|
|
60076
|
-
validator.checkLaneIdExists
|
|
60366
|
+
validator.checkLaneIdExists,
|
|
60367
|
+
validator.checkTriggerDirection
|
|
60077
60368
|
],
|
|
60078
60369
|
ContextCrossing: [
|
|
60079
60370
|
validator.checkCrossingEmptyContract,
|
|
60080
|
-
validator.checkCrossingTargetBranchLane
|
|
60371
|
+
validator.checkCrossingTargetBranchLane,
|
|
60372
|
+
validator.checkCrossingCrossFileRules
|
|
60081
60373
|
],
|
|
60082
|
-
FlowDeclaration: [
|
|
60374
|
+
FlowDeclaration: [
|
|
60375
|
+
validator.checkReturnsToDepth,
|
|
60376
|
+
validator.checkBranchLaneReferenced,
|
|
60377
|
+
validator.checkV14,
|
|
60378
|
+
validator.checkFlowCrossFileRules
|
|
60379
|
+
]
|
|
60083
60380
|
};
|
|
60084
60381
|
registry.register(checks, validator);
|
|
60085
60382
|
}
|
|
@@ -60095,7 +60392,24 @@ function getFlowFromNode(node) {
|
|
|
60095
60392
|
}
|
|
60096
60393
|
function collectSiblingNames(field) {
|
|
60097
60394
|
const container = field.$container;
|
|
60098
|
-
|
|
60395
|
+
const siblings = container.fields ?? container.inputs;
|
|
60396
|
+
return siblings ? new Set(siblings.map((f) => f.name)) : void 0;
|
|
60397
|
+
}
|
|
60398
|
+
function laneDeclaresEvent(lane, eventName, ctx) {
|
|
60399
|
+
if (!lane)
|
|
60400
|
+
return false;
|
|
60401
|
+
const events = ctx.declaredEvents.get(unquote(lane.label)) ?? [];
|
|
60402
|
+
return events.includes(eventName);
|
|
60403
|
+
}
|
|
60404
|
+
function getMomentFileFromNode(node) {
|
|
60405
|
+
let current = node;
|
|
60406
|
+
while (current) {
|
|
60407
|
+
if (isMomentFile(current)) {
|
|
60408
|
+
return current;
|
|
60409
|
+
}
|
|
60410
|
+
current = current.$container;
|
|
60411
|
+
}
|
|
60412
|
+
return void 0;
|
|
60099
60413
|
}
|
|
60100
60414
|
function getMomentFromNode(node) {
|
|
60101
60415
|
let current = node;
|
|
@@ -60123,6 +60437,8 @@ var MomentValidator = class {
|
|
|
60123
60437
|
return;
|
|
60124
60438
|
const replacement = field.deprecation.replacement.replace(/^"|"$/g, "");
|
|
60125
60439
|
const siblings = collectSiblingNames(field);
|
|
60440
|
+
if (siblings === void 0)
|
|
60441
|
+
return;
|
|
60126
60442
|
if (!siblings.has(replacement)) {
|
|
60127
60443
|
accept("warning", `V12: Deprecated field '${field.name}' references replacement '${replacement}' which does not exist on this type.`, {
|
|
60128
60444
|
node: field.deprecation,
|
|
@@ -60180,6 +60496,13 @@ var MomentValidator = class {
|
|
|
60180
60496
|
}
|
|
60181
60497
|
// =========================================================================
|
|
60182
60498
|
// V8: [terminal] must be last node in branch/when block -> error
|
|
60499
|
+
//
|
|
60500
|
+
// M-P13 blind spot: the sibling-array check cannot see `when` blocks that
|
|
60501
|
+
// textually follow a terminal node in the same moment (grammar splits nodes
|
|
60502
|
+
// and whenBlocks into separate arrays). CST offsets recover the textual
|
|
60503
|
+
// order; a main-list terminal followed by a when block gets a warning.
|
|
60504
|
+
// A terminal INSIDE a when block followed by later when blocks is legal —
|
|
60505
|
+
// those are alternative branch arms, not continuations.
|
|
60183
60506
|
// =========================================================================
|
|
60184
60507
|
checkTerminalIsLast(node, accept) {
|
|
60185
60508
|
if (node.modifier?.type !== "terminal")
|
|
@@ -60193,6 +60516,17 @@ var MomentValidator = class {
|
|
|
60193
60516
|
property: "modifier"
|
|
60194
60517
|
});
|
|
60195
60518
|
}
|
|
60519
|
+
if (isMomentDeclaration(container)) {
|
|
60520
|
+
const { sequence, fromCst } = buildMomentSequence(container);
|
|
60521
|
+
if (!fromCst)
|
|
60522
|
+
return;
|
|
60523
|
+
const nodeIndex = container.nodes.indexOf(node);
|
|
60524
|
+
const position = sequence.findIndex((s) => s.kind === "entry" && s.index === nodeIndex);
|
|
60525
|
+
const followedByWhenBlock = position >= 0 && sequence.slice(position + 1).some((s) => s.kind === "branch");
|
|
60526
|
+
if (followedByWhenBlock) {
|
|
60527
|
+
accept("warning", "V8: Terminal node is textually followed by a when block in the same moment; the flow would continue past the terminal.", { node, property: "modifier" });
|
|
60528
|
+
}
|
|
60529
|
+
}
|
|
60196
60530
|
}
|
|
60197
60531
|
// =========================================================================
|
|
60198
60532
|
// V13: Lane ID in node placement not matching any declared lane -> error
|
|
@@ -60230,6 +60564,110 @@ var MomentValidator = class {
|
|
|
60230
60564
|
}
|
|
60231
60565
|
}
|
|
60232
60566
|
// =========================================================================
|
|
60567
|
+
// V19: trailing annotation classifies nothing -> warning (M-P4)
|
|
60568
|
+
// An annotation applies to the NEXT declaration in the member list; when
|
|
60569
|
+
// nothing follows it, it silently classifies nothing.
|
|
60570
|
+
// =========================================================================
|
|
60571
|
+
checkTrailingAnnotation(container, accept) {
|
|
60572
|
+
const members = container.members;
|
|
60573
|
+
for (let i = members.length - 1; i >= 0; i--) {
|
|
60574
|
+
const member = members[i];
|
|
60575
|
+
if (!isAnnotationDeclaration(member))
|
|
60576
|
+
break;
|
|
60577
|
+
accept("warning", `V19: Annotation '@${member.name}' is not followed by a declaration and has no effect.`, { node: member, property: "name" });
|
|
60578
|
+
}
|
|
60579
|
+
}
|
|
60580
|
+
// =========================================================================
|
|
60581
|
+
// V20: declared trigger direction vs flow order -> warning (M-S10)
|
|
60582
|
+
// `N triggers X` declares N as the cause of X, so X must not be placed
|
|
60583
|
+
// before N's moment; `N triggered-by X` declares X as the cause, so X must
|
|
60584
|
+
// not be placed after N's moment. Dangling references (X not placed in the
|
|
60585
|
+
// flow at all) are V1's job and are skipped here.
|
|
60586
|
+
// =========================================================================
|
|
60587
|
+
checkTriggerDirection(node, accept) {
|
|
60588
|
+
const flow = getFlowFromNode(node);
|
|
60589
|
+
const moment = getMomentFromNode(node);
|
|
60590
|
+
if (!flow || !moment)
|
|
60591
|
+
return;
|
|
60592
|
+
const currentIndex = flow.moments.indexOf(moment);
|
|
60593
|
+
if (currentIndex < 0)
|
|
60594
|
+
return;
|
|
60595
|
+
const placementIndex = this.buildPlacementIndex(flow);
|
|
60596
|
+
for (const conn of node.connections) {
|
|
60597
|
+
if (isTriggers(conn)) {
|
|
60598
|
+
this.warnIfPlacedBefore(conn, node, placementIndex, currentIndex, accept);
|
|
60599
|
+
} else if (isTriggeredBy(conn)) {
|
|
60600
|
+
this.warnIfPlacedAfter(conn, node, placementIndex, currentIndex, accept);
|
|
60601
|
+
}
|
|
60602
|
+
}
|
|
60603
|
+
}
|
|
60604
|
+
warnIfPlacedBefore(conn, node, placementIndex, currentIndex, accept) {
|
|
60605
|
+
const targetIndex = placementIndex.get(conn.nodeName);
|
|
60606
|
+
if (targetIndex !== void 0 && targetIndex < currentIndex) {
|
|
60607
|
+
accept("warning", `V20: declared trigger direction contradicts flow order: '${conn.nodeName}' occurs before '${node.nodeName}'.`, { node: conn, property: "nodeName" });
|
|
60608
|
+
}
|
|
60609
|
+
}
|
|
60610
|
+
warnIfPlacedAfter(conn, node, placementIndex, currentIndex, accept) {
|
|
60611
|
+
const sourceIndex = placementIndex.get(conn.nodeName);
|
|
60612
|
+
if (sourceIndex !== void 0 && sourceIndex > currentIndex) {
|
|
60613
|
+
accept("warning", `V20: declared trigger direction contradicts flow order: trigger '${conn.nodeName}' occurs after '${node.nodeName}'.`, { node: conn, property: "nodeName" });
|
|
60614
|
+
}
|
|
60615
|
+
}
|
|
60616
|
+
// =========================================================================
|
|
60617
|
+
// V21: saga transition event unknown -> warning (M-S6)
|
|
60618
|
+
// A `-> Target on Event` mapping whose event is neither declared by any
|
|
60619
|
+
// context in the file nor placed in any flow is probably a typo. Guarded
|
|
60620
|
+
// like the other cross-file checks: only meaningful when the file declares
|
|
60621
|
+
// contexts (sagas always live inside one); an `on` event that only appears
|
|
60622
|
+
// as a flow node placement is accepted, so mixed/flow-heavy specs that
|
|
60623
|
+
// never re-declare events in contexts do not warn.
|
|
60624
|
+
// =========================================================================
|
|
60625
|
+
checkSagaTransitionEvents(saga, accept) {
|
|
60626
|
+
const file = getMomentFileFromNode(saga);
|
|
60627
|
+
if (!file || file.contexts.length === 0)
|
|
60628
|
+
return;
|
|
60629
|
+
const knownEvents = this.collectDeclaredEventNames(file);
|
|
60630
|
+
const placedNodeNames = this.collectPlacedNodeNames(file);
|
|
60631
|
+
for (const transition of saga.transitions) {
|
|
60632
|
+
const event = transition.event;
|
|
60633
|
+
if (event === void 0)
|
|
60634
|
+
continue;
|
|
60635
|
+
if (!knownEvents.has(event) && !placedNodeNames.has(event)) {
|
|
60636
|
+
accept("warning", `V21: Saga transition event '${event}' is not declared by any context in this file and is not placed in any flow \u2014 possible typo.`, { node: transition, property: "event" });
|
|
60637
|
+
}
|
|
60638
|
+
}
|
|
60639
|
+
}
|
|
60640
|
+
/** Event names declared by any aggregate in any context of the file. */
|
|
60641
|
+
collectDeclaredEventNames(file) {
|
|
60642
|
+
const names = /* @__PURE__ */ new Set();
|
|
60643
|
+
for (const ctx of file.contexts) {
|
|
60644
|
+
for (const member of ctx.members) {
|
|
60645
|
+
if (!isAggregateDeclaration(member))
|
|
60646
|
+
continue;
|
|
60647
|
+
for (const aggMember of member.members) {
|
|
60648
|
+
if (isDomainEventDeclaration(aggMember))
|
|
60649
|
+
names.add(aggMember.name);
|
|
60650
|
+
}
|
|
60651
|
+
}
|
|
60652
|
+
}
|
|
60653
|
+
return names;
|
|
60654
|
+
}
|
|
60655
|
+
/** Node names placed anywhere in the file's flows (main lists and when blocks). */
|
|
60656
|
+
collectPlacedNodeNames(file) {
|
|
60657
|
+
const names = /* @__PURE__ */ new Set();
|
|
60658
|
+
for (const flow of file.flows) {
|
|
60659
|
+
for (const moment of flow.moments) {
|
|
60660
|
+
for (const node of moment.nodes)
|
|
60661
|
+
names.add(node.nodeName);
|
|
60662
|
+
for (const wb of moment.whenBlocks) {
|
|
60663
|
+
for (const node of wb.nodes)
|
|
60664
|
+
names.add(node.nodeName);
|
|
60665
|
+
}
|
|
60666
|
+
}
|
|
60667
|
+
}
|
|
60668
|
+
return names;
|
|
60669
|
+
}
|
|
60670
|
+
// =========================================================================
|
|
60233
60671
|
// V17: returns-to depth capped at 1 -> warning
|
|
60234
60672
|
// =========================================================================
|
|
60235
60673
|
checkReturnsToDepth(flow, accept) {
|
|
@@ -60260,11 +60698,29 @@ var MomentValidator = class {
|
|
|
60260
60698
|
}
|
|
60261
60699
|
}
|
|
60262
60700
|
// =========================================================================
|
|
60701
|
+
// Registered cross-file entry points: no-ops unless a CrossFileContext has
|
|
60702
|
+
// been set (single-file mode sets it only when the file declares contexts),
|
|
60703
|
+
// so flow-only specs are never spammed with cross-file diagnostics.
|
|
60704
|
+
// =========================================================================
|
|
60705
|
+
checkFlowCrossFileRules(flow, accept) {
|
|
60706
|
+
if (!this.crossFileContext)
|
|
60707
|
+
return;
|
|
60708
|
+
this.checkSP01(flow, accept, this.crossFileContext);
|
|
60709
|
+
}
|
|
60710
|
+
checkCrossingCrossFileRules(crossing, accept) {
|
|
60711
|
+
if (!this.crossFileContext)
|
|
60712
|
+
return;
|
|
60713
|
+
this.checkSP02(crossing, accept, this.crossFileContext);
|
|
60714
|
+
}
|
|
60715
|
+
// =========================================================================
|
|
60263
60716
|
// Cross-file validators (SP-01, SP-02, V1, V9, V11, V14)
|
|
60264
60717
|
// =========================================================================
|
|
60265
|
-
// SP-01: Flow lane references must match declared context names
|
|
60718
|
+
// SP-01: Flow lane references must match declared context names.
|
|
60719
|
+
// Branch-lanes are outcome routes (e.g. "Refusals"), not contexts — skipped.
|
|
60266
60720
|
checkSP01(flow, accept, ctx) {
|
|
60267
60721
|
for (const lane of flow.lanes) {
|
|
60722
|
+
if (lane.isBranch)
|
|
60723
|
+
continue;
|
|
60268
60724
|
if (!ctx.declaredContextNames.includes(lane.label.replace(/^"|"$/g, ""))) {
|
|
60269
60725
|
accept("error", "SP-01: Lane label does not match any declared context name.", {
|
|
60270
60726
|
node: lane,
|
|
@@ -60273,7 +60729,11 @@ var MomentValidator = class {
|
|
|
60273
60729
|
}
|
|
60274
60730
|
}
|
|
60275
60731
|
}
|
|
60276
|
-
// SP-02: Crossing event names must be declared events
|
|
60732
|
+
// SP-02: Crossing event names must be declared events on the boundary —
|
|
60733
|
+
// in the source context (the emitter, the convention every shipped example
|
|
60734
|
+
// follows) or in the target context (a consumer-side re-declaration).
|
|
60735
|
+
// The original target-only rule flagged every crossing in the canonical
|
|
60736
|
+
// examples, because events are declared once, in the emitting context.
|
|
60277
60737
|
checkSP02(crossing, accept, ctx) {
|
|
60278
60738
|
const flow = getFlowFromNode(crossing);
|
|
60279
60739
|
if (!flow)
|
|
@@ -60281,23 +60741,27 @@ var MomentValidator = class {
|
|
|
60281
60741
|
const targetLane = flow.lanes.find((l) => l.id === crossing.targetLaneId);
|
|
60282
60742
|
if (!targetLane)
|
|
60283
60743
|
return;
|
|
60284
|
-
const contextName = targetLane.label.replace(/^"|"$/g, "");
|
|
60285
|
-
const events = ctx.declaredEvents.get(contextName) ?? [];
|
|
60286
60744
|
const parentNode = crossing.$container;
|
|
60287
|
-
|
|
60288
|
-
|
|
60745
|
+
const sourceLane = flow.lanes.find((l) => l.id === parentNode.laneId);
|
|
60746
|
+
if (targetLane.isBranch || sourceLane?.isBranch)
|
|
60747
|
+
return;
|
|
60748
|
+
const declaredOnBoundary = [sourceLane, targetLane].some((lane) => laneDeclaresEvent(lane, parentNode.nodeName, ctx));
|
|
60749
|
+
if (!declaredOnBoundary) {
|
|
60750
|
+
accept("error", "SP-02: Crossing event is not declared in the source or target context.", {
|
|
60289
60751
|
node: crossing,
|
|
60290
60752
|
property: "targetLaneId"
|
|
60291
60753
|
});
|
|
60292
60754
|
}
|
|
60293
60755
|
}
|
|
60294
|
-
// V1: Node names must resolve to declared building blocks via lane context
|
|
60756
|
+
// V1: Node names must resolve to declared building blocks via lane context.
|
|
60757
|
+
// Branch-lane placements are skipped: those lanes route outcomes and do not
|
|
60758
|
+
// correspond to a declared context.
|
|
60295
60759
|
checkV1(node, accept, ctx) {
|
|
60296
60760
|
const flow = getFlowFromNode(node);
|
|
60297
60761
|
if (!flow)
|
|
60298
60762
|
return;
|
|
60299
60763
|
const lane = flow.lanes.find((l) => l.id === node.laneId);
|
|
60300
|
-
if (!lane)
|
|
60764
|
+
if (!lane || lane.isBranch)
|
|
60301
60765
|
return;
|
|
60302
60766
|
const contextName = lane.label.replace(/^"|"$/g, "");
|
|
60303
60767
|
const blocks = ctx.declaredBuildingBlocks.get(contextName) ?? [];
|
|
@@ -60335,7 +60799,7 @@ var MomentValidator = class {
|
|
|
60335
60799
|
if (!flow)
|
|
60336
60800
|
return;
|
|
60337
60801
|
const lane = flow.lanes.find((l) => l.id === node.laneId);
|
|
60338
|
-
if (!lane)
|
|
60802
|
+
if (!lane || lane.isBranch)
|
|
60339
60803
|
return;
|
|
60340
60804
|
const contextName = lane.label.replace(/^"|"$/g, "");
|
|
60341
60805
|
const blocks = ctx.declaredBuildingBlocks.get(contextName) ?? [];
|
|
@@ -60355,7 +60819,7 @@ var MomentValidator = class {
|
|
|
60355
60819
|
if (!flow)
|
|
60356
60820
|
return;
|
|
60357
60821
|
const lane = flow.lanes.find((l) => l.id === node.laneId);
|
|
60358
|
-
if (!lane)
|
|
60822
|
+
if (!lane || lane.isBranch)
|
|
60359
60823
|
return;
|
|
60360
60824
|
const contextName = lane.label.replace(/^"|"$/g, "");
|
|
60361
60825
|
const blocks = ctx.declaredBuildingBlocks.get(contextName) ?? [];
|
|
@@ -60443,6 +60907,19 @@ var MomentValidator = class {
|
|
|
60443
60907
|
}
|
|
60444
60908
|
return labels;
|
|
60445
60909
|
}
|
|
60910
|
+
/** Earliest moment index at which each node name is placed in the flow. */
|
|
60911
|
+
buildPlacementIndex(flow) {
|
|
60912
|
+
const index = /* @__PURE__ */ new Map();
|
|
60913
|
+
flow.moments.forEach((moment, momentIndex) => {
|
|
60914
|
+
const record = (n) => {
|
|
60915
|
+
if (!index.has(n.nodeName))
|
|
60916
|
+
index.set(n.nodeName, momentIndex);
|
|
60917
|
+
};
|
|
60918
|
+
moment.nodes.forEach(record);
|
|
60919
|
+
moment.whenBlocks.forEach((wb) => wb.nodes.forEach(record));
|
|
60920
|
+
});
|
|
60921
|
+
return index;
|
|
60922
|
+
}
|
|
60446
60923
|
collectPriorNodeNames(flow, currentMoment) {
|
|
60447
60924
|
const names = /* @__PURE__ */ new Set();
|
|
60448
60925
|
for (const moment of flow.moments) {
|
|
@@ -60544,26 +61021,31 @@ var MomentModule = {
|
|
|
60544
61021
|
};
|
|
60545
61022
|
|
|
60546
61023
|
// ../core/dist/parser/ast-to-ir.js
|
|
60547
|
-
function
|
|
61024
|
+
function unquote2(s) {
|
|
60548
61025
|
if (s.startsWith('"') && s.endsWith('"')) {
|
|
60549
61026
|
return s.slice(1, -1);
|
|
60550
61027
|
}
|
|
60551
61028
|
return s;
|
|
60552
61029
|
}
|
|
60553
|
-
function astToIr(file) {
|
|
61030
|
+
function astToIr(file, metadata) {
|
|
60554
61031
|
const contexts = file.contexts.map(transformContext);
|
|
60555
|
-
const
|
|
61032
|
+
const nodeKindMap = buildNodeKindMap(contexts);
|
|
61033
|
+
const flows = file.flows.map((flow) => transformFlow(flow, nodeKindMap));
|
|
60556
61034
|
const relationships = file.contexts.flatMap(extractRelationships);
|
|
60557
61035
|
return {
|
|
60558
61036
|
contexts,
|
|
60559
61037
|
flows,
|
|
60560
61038
|
glossary: [],
|
|
60561
61039
|
relationships,
|
|
60562
|
-
metadata: {
|
|
61040
|
+
metadata: {
|
|
61041
|
+
name: metadata?.name ?? "",
|
|
61042
|
+
version: metadata?.version ?? "0.0.0",
|
|
61043
|
+
...metadata?.description !== void 0 ? { description: metadata.description } : {}
|
|
61044
|
+
}
|
|
60563
61045
|
};
|
|
60564
61046
|
}
|
|
60565
61047
|
function transformContext(ctx) {
|
|
60566
|
-
const name =
|
|
61048
|
+
const name = unquote2(ctx.name);
|
|
60567
61049
|
const aggregates = [];
|
|
60568
61050
|
const domainServices = [];
|
|
60569
61051
|
const policies = [];
|
|
@@ -60588,18 +61070,18 @@ function transformContext(ctx) {
|
|
|
60588
61070
|
allValueObjects.push(...aggDef.valueObjects);
|
|
60589
61071
|
allInvariants.push(...aggDef.invariants);
|
|
60590
61072
|
} else if (isDomainServiceDeclaration(member)) {
|
|
60591
|
-
domainServices.push(transformService(member));
|
|
61073
|
+
domainServices.push(transformService(member, annotations));
|
|
60592
61074
|
} else if (isPolicyDeclaration(member)) {
|
|
60593
|
-
policies.push(transformPolicy(member));
|
|
61075
|
+
policies.push(transformPolicy(member, annotations));
|
|
60594
61076
|
} else if (isSagaDeclaration(member)) {
|
|
60595
|
-
sagas.push(transformSaga(member));
|
|
61077
|
+
sagas.push(transformSaga(member, annotations));
|
|
60596
61078
|
}
|
|
60597
61079
|
}
|
|
60598
61080
|
return {
|
|
60599
61081
|
id: `ctx-${name}`,
|
|
60600
61082
|
name,
|
|
60601
61083
|
classification: ctx.classification?.value,
|
|
60602
|
-
description: ctx.description ?
|
|
61084
|
+
description: ctx.description ? unquote2(ctx.description) : void 0,
|
|
60603
61085
|
aggregates,
|
|
60604
61086
|
domainServices,
|
|
60605
61087
|
commands: allCommands,
|
|
@@ -60614,11 +61096,11 @@ function transformAnnotation(ann) {
|
|
|
60614
61096
|
const raw = ann.value;
|
|
60615
61097
|
return {
|
|
60616
61098
|
name: ann.name,
|
|
60617
|
-
value: raw.startsWith('"') ?
|
|
61099
|
+
value: raw.startsWith('"') ? unquote2(raw) : raw
|
|
60618
61100
|
};
|
|
60619
61101
|
}
|
|
60620
61102
|
function transformAggregate(agg, annotations) {
|
|
60621
|
-
const name =
|
|
61103
|
+
const name = unquote2(agg.name);
|
|
60622
61104
|
const commands = [];
|
|
60623
61105
|
const events = [];
|
|
60624
61106
|
const valueObjects = [];
|
|
@@ -60638,7 +61120,7 @@ function transformAggregate(agg, annotations) {
|
|
|
60638
61120
|
} else if (isValueObjectDeclaration(member)) {
|
|
60639
61121
|
valueObjects.push(transformValueObject(member, memberAnnotations));
|
|
60640
61122
|
} else if (isInvariantDeclaration(member)) {
|
|
60641
|
-
invariants.push(transformInvariant(member));
|
|
61123
|
+
invariants.push(transformInvariant(member, memberAnnotations));
|
|
60642
61124
|
}
|
|
60643
61125
|
}
|
|
60644
61126
|
return {
|
|
@@ -60665,7 +61147,7 @@ function transformCommand(cmd, annotations) {
|
|
|
60665
61147
|
function transformPrecondition(pre) {
|
|
60666
61148
|
return {
|
|
60667
61149
|
name: pre.name,
|
|
60668
|
-
description:
|
|
61150
|
+
description: unquote2(pre.description)
|
|
60669
61151
|
};
|
|
60670
61152
|
}
|
|
60671
61153
|
function transformEvent(evt, annotations) {
|
|
@@ -60693,62 +61175,104 @@ function transformFieldDeclaration(field) {
|
|
|
60693
61175
|
};
|
|
60694
61176
|
if ("deprecation" in field && field.deprecation) {
|
|
60695
61177
|
result.deprecated = {
|
|
60696
|
-
reason:
|
|
60697
|
-
replacement:
|
|
61178
|
+
reason: unquote2(field.deprecation.reason),
|
|
61179
|
+
replacement: unquote2(field.deprecation.replacement)
|
|
60698
61180
|
};
|
|
60699
61181
|
}
|
|
60700
61182
|
return result;
|
|
60701
61183
|
}
|
|
60702
|
-
function transformInvariant(inv) {
|
|
61184
|
+
function transformInvariant(inv, annotations) {
|
|
60703
61185
|
return {
|
|
60704
61186
|
id: inv.id,
|
|
60705
|
-
description:
|
|
60706
|
-
scope: inv.scope
|
|
61187
|
+
description: unquote2(inv.description),
|
|
61188
|
+
scope: inv.scope,
|
|
61189
|
+
...annotations ? { annotations } : {}
|
|
60707
61190
|
};
|
|
60708
61191
|
}
|
|
60709
|
-
function transformService(svc) {
|
|
61192
|
+
function transformService(svc, annotations) {
|
|
60710
61193
|
return {
|
|
60711
61194
|
id: `svc-${svc.name}`,
|
|
60712
61195
|
name: svc.name,
|
|
61196
|
+
...annotations ? { annotations } : {},
|
|
60713
61197
|
consumes: svc.consumes,
|
|
60714
61198
|
produces: svc.produces,
|
|
60715
|
-
description:
|
|
61199
|
+
description: unquote2(svc.description)
|
|
60716
61200
|
};
|
|
60717
61201
|
}
|
|
60718
|
-
function transformPolicy(pol) {
|
|
61202
|
+
function transformPolicy(pol, annotations) {
|
|
60719
61203
|
const trigger = pol.trigger.eventName ?? "file-watcher";
|
|
60720
61204
|
return {
|
|
60721
61205
|
id: `pol-${pol.name}`,
|
|
60722
61206
|
name: pol.name,
|
|
61207
|
+
...annotations ? { annotations } : {},
|
|
60723
61208
|
trigger,
|
|
60724
|
-
action:
|
|
61209
|
+
action: unquote2(pol.action),
|
|
60725
61210
|
chainsTo: pol.chainsTo ?? void 0
|
|
60726
61211
|
};
|
|
60727
61212
|
}
|
|
60728
|
-
function transformSaga(saga) {
|
|
61213
|
+
function transformSaga(saga, annotations) {
|
|
60729
61214
|
const timeout = saga.timeout.duration ?? "none";
|
|
61215
|
+
const states = [saga.initialState, ...saga.transitions.map((t) => t.target)];
|
|
61216
|
+
const transitions = saga.transitions.map((t, i) => ({
|
|
61217
|
+
from: states[i],
|
|
61218
|
+
to: t.target,
|
|
61219
|
+
...t.event !== void 0 ? { onEvent: t.event } : {}
|
|
61220
|
+
}));
|
|
60730
61221
|
return {
|
|
60731
61222
|
id: `saga-${saga.name}`,
|
|
60732
61223
|
name: saga.name,
|
|
61224
|
+
...annotations ? { annotations } : {},
|
|
60733
61225
|
trigger: saga.trigger,
|
|
60734
|
-
states
|
|
60735
|
-
|
|
61226
|
+
states,
|
|
61227
|
+
transitions,
|
|
61228
|
+
compensation: unquote2(saga.compensation),
|
|
60736
61229
|
timeout
|
|
60737
61230
|
};
|
|
60738
61231
|
}
|
|
60739
61232
|
function buildLaneContextMap(flow) {
|
|
60740
61233
|
const map2 = /* @__PURE__ */ new Map();
|
|
60741
61234
|
for (const lane of flow.lanes) {
|
|
60742
|
-
map2.set(lane.id, `ctx-${
|
|
61235
|
+
map2.set(lane.id, `ctx-${unquote2(lane.label)}`);
|
|
61236
|
+
}
|
|
61237
|
+
return map2;
|
|
61238
|
+
}
|
|
61239
|
+
function buildNodeKindMap(contexts) {
|
|
61240
|
+
const map2 = /* @__PURE__ */ new Map();
|
|
61241
|
+
for (const ctx of contexts) {
|
|
61242
|
+
for (const cmd of ctx.commands)
|
|
61243
|
+
map2.set(cmd.name, "command");
|
|
61244
|
+
for (const evt of ctx.events)
|
|
61245
|
+
map2.set(evt.name, "event");
|
|
61246
|
+
for (const policy of ctx.policies)
|
|
61247
|
+
map2.set(policy.name, "policy");
|
|
61248
|
+
for (const saga of ctx.sagas)
|
|
61249
|
+
map2.set(saga.name, "saga");
|
|
61250
|
+
}
|
|
61251
|
+
return map2;
|
|
61252
|
+
}
|
|
61253
|
+
function buildNodeLaneMap(flow) {
|
|
61254
|
+
const map2 = /* @__PURE__ */ new Map();
|
|
61255
|
+
const record = (node) => {
|
|
61256
|
+
if (!map2.has(node.nodeName)) {
|
|
61257
|
+
map2.set(node.nodeName, node.laneId);
|
|
61258
|
+
}
|
|
61259
|
+
};
|
|
61260
|
+
for (const moment of flow.moments) {
|
|
61261
|
+
for (const node of moment.nodes)
|
|
61262
|
+
record(node);
|
|
61263
|
+
for (const when of moment.whenBlocks) {
|
|
61264
|
+
for (const node of when.nodes)
|
|
61265
|
+
record(node);
|
|
61266
|
+
}
|
|
60743
61267
|
}
|
|
60744
61268
|
return map2;
|
|
60745
61269
|
}
|
|
60746
|
-
function transformFlow(flow) {
|
|
60747
|
-
const name =
|
|
61270
|
+
function transformFlow(flow, nodeKindMap) {
|
|
61271
|
+
const name = unquote2(flow.name);
|
|
60748
61272
|
const laneContextMap = buildLaneContextMap(flow);
|
|
60749
61273
|
const lanes = flow.lanes.map((lane) => ({
|
|
60750
61274
|
id: lane.id,
|
|
60751
|
-
label:
|
|
61275
|
+
label: unquote2(lane.label),
|
|
60752
61276
|
contextId: laneContextMap.get(lane.id) ?? lane.id,
|
|
60753
61277
|
classification: lane.classification?.value,
|
|
60754
61278
|
isBranch: lane.isBranch ?? false
|
|
@@ -60756,47 +61280,58 @@ function transformFlow(flow) {
|
|
|
60756
61280
|
return {
|
|
60757
61281
|
id: `flow-${name}`,
|
|
60758
61282
|
name,
|
|
60759
|
-
description: flow.description ?
|
|
61283
|
+
description: flow.description ? unquote2(flow.description) : void 0,
|
|
60760
61284
|
lanes,
|
|
60761
|
-
moments: flow.moments.map((moment, idx) => transformMoment(moment, idx, laneContextMap)),
|
|
61285
|
+
moments: flow.moments.map((moment, idx) => transformMoment(moment, idx, laneContextMap, nodeKindMap)),
|
|
60762
61286
|
connections: extractConnections(flow, laneContextMap)
|
|
60763
61287
|
};
|
|
60764
61288
|
}
|
|
60765
|
-
function transformMoment(moment, index, laneContextMap) {
|
|
60766
|
-
const name =
|
|
60767
|
-
const contextEntries = moment.nodes.map((n) => transformNodeToEntry(n, laneContextMap));
|
|
60768
|
-
const branches = moment.whenBlocks.length > 0 ? moment.whenBlocks.map((wb) => transformWhenBlock(wb, laneContextMap)) : void 0;
|
|
60769
|
-
const hasTerminal = contextEntries.some((e) => e.terminal === true);
|
|
61289
|
+
function transformMoment(moment, index, laneContextMap, nodeKindMap) {
|
|
61290
|
+
const name = unquote2(moment.label);
|
|
61291
|
+
const contextEntries = moment.nodes.map((n) => transformNodeToEntry(n, laneContextMap, nodeKindMap));
|
|
61292
|
+
const branches = moment.whenBlocks.length > 0 ? moment.whenBlocks.map((wb) => transformWhenBlock(wb, laneContextMap, nodeKindMap)) : void 0;
|
|
61293
|
+
const hasTerminal = contextEntries.some((e) => e.terminal === true) || (branches?.some((b) => b.entries.some((e) => e.terminal === true)) ?? false);
|
|
60770
61294
|
return {
|
|
60771
61295
|
id: `moment-${index}-${name.replace(/\s+/g, "-")}`,
|
|
60772
61296
|
name,
|
|
60773
61297
|
contextEntries,
|
|
60774
61298
|
branches,
|
|
60775
|
-
terminal: hasTerminal || void 0
|
|
61299
|
+
terminal: hasTerminal || void 0,
|
|
61300
|
+
isBranch: moment.isBranch || void 0,
|
|
61301
|
+
// Textual order of entries/branches from CST offsets (M-P13); falls back
|
|
61302
|
+
// to entries-then-branches when the AST carries no CST.
|
|
61303
|
+
sequence: buildMomentSequence(moment).sequence
|
|
60776
61304
|
};
|
|
60777
61305
|
}
|
|
60778
|
-
function transformWhenBlock(when, laneContextMap) {
|
|
61306
|
+
function transformWhenBlock(when, laneContextMap, nodeKindMap) {
|
|
60779
61307
|
return {
|
|
60780
61308
|
condition: when.condition,
|
|
60781
61309
|
...when.lane ? { lane: when.lane } : {},
|
|
60782
|
-
entries: when.nodes.map((n) => transformNodeToEntry(n, laneContextMap))
|
|
61310
|
+
entries: when.nodes.map((n) => transformNodeToEntry(n, laneContextMap, nodeKindMap))
|
|
60783
61311
|
};
|
|
60784
61312
|
}
|
|
60785
|
-
function
|
|
61313
|
+
function multiplicityOf(node) {
|
|
61314
|
+
if (!node.multiplicity)
|
|
61315
|
+
return void 0;
|
|
61316
|
+
return node.multiplicity.count ?? node.multiplicity.countVar;
|
|
61317
|
+
}
|
|
61318
|
+
function transformNodeToEntry(node, laneContextMap, nodeKindMap) {
|
|
60786
61319
|
const contextId = laneContextMap?.get(node.laneId) ?? node.laneId;
|
|
60787
61320
|
const entry = {
|
|
60788
61321
|
contextId,
|
|
60789
61322
|
nodeName: node.nodeName,
|
|
60790
|
-
|
|
60791
|
-
//
|
|
61323
|
+
// Resolved from same-file context declarations; 'event' when the spec is
|
|
61324
|
+
// flow-only and the kind is genuinely unknown (MMNT-27).
|
|
61325
|
+
nodeKind: nodeKindMap?.get(node.nodeName) ?? "event"
|
|
60792
61326
|
};
|
|
60793
|
-
|
|
60794
|
-
|
|
61327
|
+
const multiplicity = multiplicityOf(node);
|
|
61328
|
+
if (multiplicity !== void 0) {
|
|
61329
|
+
entry.multiplicity = multiplicity;
|
|
60795
61330
|
}
|
|
60796
|
-
|
|
61331
|
+
const modifierType = node.modifier?.type;
|
|
61332
|
+
if (modifierType === "optional") {
|
|
60797
61333
|
entry.optional = true;
|
|
60798
|
-
}
|
|
60799
|
-
if (node.modifier?.type === "terminal") {
|
|
61334
|
+
} else if (modifierType === "terminal") {
|
|
60800
61335
|
entry.terminal = true;
|
|
60801
61336
|
}
|
|
60802
61337
|
return entry;
|
|
@@ -60805,10 +61340,21 @@ function extractConnections(flow, laneContextMap) {
|
|
|
60805
61340
|
const connections = [];
|
|
60806
61341
|
let connectionCounter = 0;
|
|
60807
61342
|
const resolveCtx = (laneId) => laneContextMap?.get(laneId) ?? laneId;
|
|
61343
|
+
const nodeLaneMap = buildNodeLaneMap(flow);
|
|
61344
|
+
const resolveNodeCtx = (nodeName, fallbackLaneId) => {
|
|
61345
|
+
const laneId = nodeLaneMap.get(nodeName) ?? fallbackLaneId;
|
|
61346
|
+
return resolveCtx(laneId);
|
|
61347
|
+
};
|
|
61348
|
+
const momentLabelToId = /* @__PURE__ */ new Map();
|
|
61349
|
+
for (let momentIdx = 0; momentIdx < flow.moments.length; momentIdx++) {
|
|
61350
|
+
const label = unquote2(flow.moments[momentIdx].label);
|
|
61351
|
+
momentLabelToId.set(label, `moment-${momentIdx}-${label.replace(/\s+/g, "-")}`);
|
|
61352
|
+
}
|
|
60808
61353
|
for (let momentIdx = 0; momentIdx < flow.moments.length; momentIdx++) {
|
|
60809
61354
|
const moment = flow.moments[momentIdx];
|
|
60810
|
-
const momentId = `moment-${momentIdx}-${
|
|
60811
|
-
const processNode = (node) => {
|
|
61355
|
+
const momentId = `moment-${momentIdx}-${unquote2(moment.label).replace(/\s+/g, "-")}`;
|
|
61356
|
+
const processNode = (node, branchCondition) => {
|
|
61357
|
+
const branchFields = branchCondition ? { branchCondition } : {};
|
|
60812
61358
|
if (node.crossing) {
|
|
60813
61359
|
const contract = transformCrossingToContract(node);
|
|
60814
61360
|
connections.push({
|
|
@@ -60816,8 +61362,10 @@ function extractConnections(flow, laneContextMap) {
|
|
|
60816
61362
|
sourceMomentId: momentId,
|
|
60817
61363
|
targetContextId: resolveCtx(node.crossing.targetLaneId),
|
|
60818
61364
|
eventId: `evt-${node.nodeName}`,
|
|
61365
|
+
sourceNodeName: node.nodeName,
|
|
60819
61366
|
connectionType: "crosses-to",
|
|
60820
|
-
schemaContract: contract
|
|
61367
|
+
schemaContract: contract,
|
|
61368
|
+
...branchFields
|
|
60821
61369
|
});
|
|
60822
61370
|
}
|
|
60823
61371
|
for (const conn of node.connections) {
|
|
@@ -60827,24 +61375,34 @@ function extractConnections(flow, laneContextMap) {
|
|
|
60827
61375
|
sourceMomentId: momentId,
|
|
60828
61376
|
targetContextId: resolveCtx(node.laneId),
|
|
60829
61377
|
eventId: `evt-${conn.nodeName}`,
|
|
60830
|
-
|
|
61378
|
+
sourceNodeName: conn.nodeName,
|
|
61379
|
+
targetNodeName: node.nodeName,
|
|
61380
|
+
connectionType: "triggered-by",
|
|
61381
|
+
...branchFields
|
|
60831
61382
|
});
|
|
60832
61383
|
} else if (isTriggers(conn)) {
|
|
60833
61384
|
connections.push({
|
|
60834
61385
|
id: `conn-${connectionCounter++}`,
|
|
60835
61386
|
sourceMomentId: momentId,
|
|
60836
|
-
targetContextId:
|
|
61387
|
+
targetContextId: resolveNodeCtx(conn.nodeName, node.laneId),
|
|
60837
61388
|
eventId: `evt-${conn.nodeName}`,
|
|
60838
|
-
|
|
61389
|
+
sourceNodeName: node.nodeName,
|
|
61390
|
+
targetNodeName: conn.nodeName,
|
|
61391
|
+
connectionType: "triggers",
|
|
61392
|
+
...branchFields
|
|
60839
61393
|
});
|
|
60840
61394
|
} else if (isReturnsTo(conn)) {
|
|
61395
|
+
const targetLabel = unquote2(conn.frameLabel);
|
|
60841
61396
|
connections.push({
|
|
60842
61397
|
id: `conn-${connectionCounter++}`,
|
|
60843
61398
|
sourceMomentId: momentId,
|
|
60844
61399
|
targetContextId: resolveCtx(node.laneId),
|
|
60845
61400
|
eventId: `evt-${node.nodeName}`,
|
|
61401
|
+
sourceNodeName: node.nodeName,
|
|
60846
61402
|
connectionType: "returns-to",
|
|
60847
|
-
targetMomentLabel:
|
|
61403
|
+
targetMomentLabel: targetLabel,
|
|
61404
|
+
...momentLabelToId.has(targetLabel) ? { targetMomentId: momentLabelToId.get(targetLabel) } : {},
|
|
61405
|
+
...branchFields
|
|
60848
61406
|
});
|
|
60849
61407
|
}
|
|
60850
61408
|
}
|
|
@@ -60854,7 +61412,7 @@ function extractConnections(flow, laneContextMap) {
|
|
|
60854
61412
|
}
|
|
60855
61413
|
for (const when of moment.whenBlocks) {
|
|
60856
61414
|
for (const node of when.nodes) {
|
|
60857
|
-
processNode(node);
|
|
61415
|
+
processNode(node, when.condition);
|
|
60858
61416
|
}
|
|
60859
61417
|
}
|
|
60860
61418
|
}
|
|
@@ -60879,10 +61437,11 @@ function extractRelationships(ctx) {
|
|
|
60879
61437
|
if (isContextRelationshipDeclaration(member)) {
|
|
60880
61438
|
const rel = member;
|
|
60881
61439
|
relationships.push({
|
|
60882
|
-
|
|
60883
|
-
|
|
61440
|
+
// ctx- prefix matches ContextDefinition.id so consumers can join on id.
|
|
61441
|
+
sourceContextId: `ctx-${rel.source}`,
|
|
61442
|
+
targetContextId: `ctx-${rel.target}`,
|
|
60884
61443
|
relationshipType: rel.type,
|
|
60885
|
-
contract:
|
|
61444
|
+
contract: unquote2(rel.contract)
|
|
60886
61445
|
});
|
|
60887
61446
|
}
|
|
60888
61447
|
}
|
|
@@ -60890,6 +61449,11 @@ function extractRelationships(ctx) {
|
|
|
60890
61449
|
}
|
|
60891
61450
|
|
|
60892
61451
|
// ../core/dist/parser/moment-parser.js
|
|
61452
|
+
function specNameFromPath(filePath) {
|
|
61453
|
+
const segments = filePath.split(/[/\\]/);
|
|
61454
|
+
const base = segments[segments.length - 1];
|
|
61455
|
+
return base.replace(/\.[^.]+$/, "");
|
|
61456
|
+
}
|
|
60893
61457
|
var MomentParser = class {
|
|
60894
61458
|
services;
|
|
60895
61459
|
constructor() {
|
|
@@ -60900,7 +61464,20 @@ var MomentParser = class {
|
|
|
60900
61464
|
}
|
|
60901
61465
|
async parseContent(content, filePath) {
|
|
60902
61466
|
const doc = this.services.shared.workspace.LangiumDocumentFactory.fromString(content, URI2.parse("memory:///parse.moment"));
|
|
60903
|
-
|
|
61467
|
+
const ast = doc.parseResult.value;
|
|
61468
|
+
const validator = this.services.validation.MomentValidator;
|
|
61469
|
+
const declaresContexts = ast.contexts.length > 0;
|
|
61470
|
+
const useCrossFileContext = declaresContexts && ast.flows.length > 0;
|
|
61471
|
+
if (useCrossFileContext) {
|
|
61472
|
+
validator.setCrossFileContext(buildCrossFileContext(ast));
|
|
61473
|
+
}
|
|
61474
|
+
try {
|
|
61475
|
+
await this.services.shared.workspace.DocumentBuilder.build([doc], { validation: true });
|
|
61476
|
+
} finally {
|
|
61477
|
+
if (useCrossFileContext) {
|
|
61478
|
+
validator.clearCrossFileContext();
|
|
61479
|
+
}
|
|
61480
|
+
}
|
|
60904
61481
|
const file = filePath ?? "parse.moment";
|
|
60905
61482
|
const diagnostics = [
|
|
60906
61483
|
// Chevrotain lexer errors carry 1-based line/column when available.
|
|
@@ -60938,7 +61515,17 @@ var MomentParser = class {
|
|
|
60938
61515
|
if (hasError) {
|
|
60939
61516
|
return { success: false, diagnostics };
|
|
60940
61517
|
}
|
|
60941
|
-
const ir = astToIr(
|
|
61518
|
+
const ir = astToIr(ast, filePath ? { name: specNameFromPath(filePath) } : void 0);
|
|
61519
|
+
if (declaresContexts) {
|
|
61520
|
+
const schemaResult = new SchemaValidator().validate(ir);
|
|
61521
|
+
diagnostics.push(
|
|
61522
|
+
...schemaResult.diagnostics.map((d) => ({
|
|
61523
|
+
severity: "warning",
|
|
61524
|
+
message: d.message,
|
|
61525
|
+
ruleId: d.ruleId
|
|
61526
|
+
}))
|
|
61527
|
+
);
|
|
61528
|
+
}
|
|
60942
61529
|
return { success: true, ir, diagnostics };
|
|
60943
61530
|
}
|
|
60944
61531
|
};
|
|
@@ -63007,18 +63594,48 @@ import { parseArgs as parseArgs2 } from "node:util";
|
|
|
63007
63594
|
import { createHash as createHash2 } from "node:crypto";
|
|
63008
63595
|
function deriveTopology(ir, derivedAt) {
|
|
63009
63596
|
const ctxMap = new Map(ir.contexts.map((c) => [c.id, c]));
|
|
63010
|
-
const suites = ir.flows.map((flow) => deriveTestSuite(flow, ctxMap));
|
|
63597
|
+
const suites = ir.flows.map((flow, idx) => deriveTestSuite(flow, ctxMap, resolveSharedCaseFlow(ir.flows, ctxMap, idx)));
|
|
63011
63598
|
const sourceIrHash = computeHash(ir);
|
|
63012
63599
|
return {
|
|
63013
63600
|
suites,
|
|
63014
63601
|
metadata: { sourceIrHash, derivedAt: derivedAt ?? (/* @__PURE__ */ new Date()).toISOString() }
|
|
63015
63602
|
};
|
|
63016
63603
|
}
|
|
63017
|
-
function
|
|
63604
|
+
function resolveSharedCaseFlow(flows, ctxMap, flowIdx) {
|
|
63605
|
+
const sagas = /* @__PURE__ */ new Set();
|
|
63606
|
+
const policies = /* @__PURE__ */ new Set();
|
|
63607
|
+
const owningFlowIdx = (trigger) => {
|
|
63608
|
+
const idx = flows.findIndex((f) => flowContainsNode(f, trigger));
|
|
63609
|
+
return idx === -1 ? 0 : idx;
|
|
63610
|
+
};
|
|
63611
|
+
for (const [, ctx] of ctxMap) {
|
|
63612
|
+
for (const saga of ctx.sagas) {
|
|
63613
|
+
if (owningFlowIdx(saga.trigger) === flowIdx)
|
|
63614
|
+
sagas.add(saga.id);
|
|
63615
|
+
}
|
|
63616
|
+
for (const pol of ctx.policies) {
|
|
63617
|
+
if (pol.chainsTo && owningFlowIdx(pol.trigger) === flowIdx)
|
|
63618
|
+
policies.add(pol.id);
|
|
63619
|
+
}
|
|
63620
|
+
}
|
|
63621
|
+
return { sagas, policies };
|
|
63622
|
+
}
|
|
63623
|
+
function flowContainsNode(flow, nodeName) {
|
|
63624
|
+
for (const moment of flow.moments) {
|
|
63625
|
+
if (moment.contextEntries.some((e) => e.nodeName === nodeName))
|
|
63626
|
+
return true;
|
|
63627
|
+
for (const branch of moment.branches ?? []) {
|
|
63628
|
+
if (branch.entries.some((e) => e.nodeName === nodeName))
|
|
63629
|
+
return true;
|
|
63630
|
+
}
|
|
63631
|
+
}
|
|
63632
|
+
return false;
|
|
63633
|
+
}
|
|
63634
|
+
function deriveTestSuite(flow, ctxMap, sharedCases) {
|
|
63018
63635
|
const testCases = flow.moments.flatMap((moment) => deriveTestCases(moment, flow));
|
|
63019
|
-
const sagaCases = deriveSagaTestCases(ctxMap);
|
|
63636
|
+
const sagaCases = deriveSagaTestCases(ctxMap, sharedCases.sagas);
|
|
63020
63637
|
testCases.push(...sagaCases);
|
|
63021
|
-
const policyCases = derivePolicyChainTestCases(ctxMap);
|
|
63638
|
+
const policyCases = derivePolicyChainTestCases(ctxMap, sharedCases.policies);
|
|
63022
63639
|
testCases.push(...policyCases);
|
|
63023
63640
|
return {
|
|
63024
63641
|
flowId: flow.id,
|
|
@@ -63027,10 +63644,12 @@ function deriveTestSuite(flow, ctxMap) {
|
|
|
63027
63644
|
contextsCovered: collectContextIds(flow)
|
|
63028
63645
|
};
|
|
63029
63646
|
}
|
|
63030
|
-
function deriveSagaTestCases(ctxMap) {
|
|
63647
|
+
function deriveSagaTestCases(ctxMap, assignedSagaIds) {
|
|
63031
63648
|
const cases = [];
|
|
63032
63649
|
for (const [, ctx] of ctxMap) {
|
|
63033
63650
|
for (const saga of ctx.sagas) {
|
|
63651
|
+
if (!assignedSagaIds.has(saga.id))
|
|
63652
|
+
continue;
|
|
63034
63653
|
cases.push(buildSagaInitCase(ctx, saga));
|
|
63035
63654
|
cases.push(...buildSagaTransitionCases(ctx, saga));
|
|
63036
63655
|
cases.push(buildSagaCompensationCase(ctx, saga));
|
|
@@ -63041,7 +63660,7 @@ function deriveSagaTestCases(ctxMap) {
|
|
|
63041
63660
|
function buildSagaInitCase(ctx, saga) {
|
|
63042
63661
|
return {
|
|
63043
63662
|
momentId: `saga-${saga.name}-initiated`,
|
|
63044
|
-
momentName: `
|
|
63663
|
+
momentName: `saga ${saga.name} starts on ${saga.trigger}`,
|
|
63045
63664
|
assertions: [{
|
|
63046
63665
|
crossingId: `saga-init-${saga.name}`,
|
|
63047
63666
|
sourceContext: ctx.id,
|
|
@@ -63057,7 +63676,7 @@ function buildSagaTransitionCases(ctx, saga) {
|
|
|
63057
63676
|
for (let i = 0; i < saga.states.length - 1; i++) {
|
|
63058
63677
|
cases.push({
|
|
63059
63678
|
momentId: `saga-${saga.name}-${saga.states[i]}-to-${saga.states[i + 1]}`,
|
|
63060
|
-
momentName: `
|
|
63679
|
+
momentName: `saga ${saga.name} transitions ${saga.states[i]} \u2192 ${saga.states[i + 1]}`,
|
|
63061
63680
|
assertions: [{
|
|
63062
63681
|
crossingId: `saga-transition-${saga.name}-${i}`,
|
|
63063
63682
|
sourceContext: ctx.id,
|
|
@@ -63073,7 +63692,7 @@ function buildSagaTransitionCases(ctx, saga) {
|
|
|
63073
63692
|
function buildSagaCompensationCase(ctx, saga) {
|
|
63074
63693
|
return {
|
|
63075
63694
|
momentId: `saga-${saga.name}-compensation`,
|
|
63076
|
-
momentName: `
|
|
63695
|
+
momentName: `saga ${saga.name} compensates via ${saga.compensation} after ${saga.timeout}`,
|
|
63077
63696
|
assertions: [{
|
|
63078
63697
|
crossingId: `saga-comp-${saga.name}`,
|
|
63079
63698
|
sourceContext: ctx.id,
|
|
@@ -63084,15 +63703,17 @@ function buildSagaCompensationCase(ctx, saga) {
|
|
|
63084
63703
|
setupSteps: [{ contextName: ctx.name, aggregateName: saga.name, precondition: saga.compensation }]
|
|
63085
63704
|
};
|
|
63086
63705
|
}
|
|
63087
|
-
function derivePolicyChainTestCases(ctxMap) {
|
|
63706
|
+
function derivePolicyChainTestCases(ctxMap, assignedPolicyIds) {
|
|
63088
63707
|
const cases = [];
|
|
63089
63708
|
for (const [, ctx] of ctxMap) {
|
|
63090
63709
|
for (const pol of ctx.policies) {
|
|
63091
63710
|
if (!pol.chainsTo)
|
|
63092
63711
|
continue;
|
|
63712
|
+
if (!assignedPolicyIds.has(pol.id))
|
|
63713
|
+
continue;
|
|
63093
63714
|
cases.push({
|
|
63094
63715
|
momentId: `policy-${pol.name}`,
|
|
63095
|
-
momentName: `
|
|
63716
|
+
momentName: `policy ${pol.name} chains ${pol.trigger} \u2192 ${pol.chainsTo}`,
|
|
63096
63717
|
assertions: [{
|
|
63097
63718
|
crossingId: `policy-chain-${pol.name}`,
|
|
63098
63719
|
sourceContext: ctx.id,
|
|
@@ -63112,20 +63733,21 @@ function derivePolicyChainTestCases(ctxMap) {
|
|
|
63112
63733
|
}
|
|
63113
63734
|
function deriveTestCases(moment, flow) {
|
|
63114
63735
|
const crossings = flow.connections.filter((c) => c.sourceMomentId === moment.id && c.connectionType === "crosses-to");
|
|
63115
|
-
const assertions = crossings.map((conn) => mapCrossingToAssertion(conn, moment));
|
|
63116
|
-
const baseCase = {
|
|
63117
|
-
momentId: moment.id,
|
|
63118
|
-
momentName: moment.name,
|
|
63119
|
-
assertions,
|
|
63120
|
-
setupSteps: []
|
|
63121
|
-
};
|
|
63122
63736
|
if (moment.branches && moment.branches.length > 0) {
|
|
63123
63737
|
return moment.branches.map((branch) => ({
|
|
63124
|
-
|
|
63738
|
+
momentId: moment.id,
|
|
63739
|
+
momentName: moment.name,
|
|
63740
|
+
assertions: crossings.filter((c) => c.branchCondition === void 0 || c.branchCondition === branch.condition).map((conn) => mapCrossingToAssertion(conn, moment)),
|
|
63741
|
+
setupSteps: [],
|
|
63125
63742
|
variant: branch.condition
|
|
63126
63743
|
}));
|
|
63127
63744
|
}
|
|
63128
|
-
return [
|
|
63745
|
+
return [{
|
|
63746
|
+
momentId: moment.id,
|
|
63747
|
+
momentName: moment.name,
|
|
63748
|
+
assertions: crossings.map((conn) => mapCrossingToAssertion(conn, moment)),
|
|
63749
|
+
setupSteps: []
|
|
63750
|
+
}];
|
|
63129
63751
|
}
|
|
63130
63752
|
function mapCrossingToAssertion(conn, moment) {
|
|
63131
63753
|
const sourceContextId = resolveSourceContextId(conn, moment);
|
|
@@ -63177,13 +63799,52 @@ function computeHash(ir) {
|
|
|
63177
63799
|
return createHash2("sha256").update(JSON.stringify(ir)).digest("hex");
|
|
63178
63800
|
}
|
|
63179
63801
|
|
|
63802
|
+
// ../derive/dist/engine/moment-children.js
|
|
63803
|
+
function orderedMomentChildren(moment, fallback) {
|
|
63804
|
+
const entries = moment.contextEntries;
|
|
63805
|
+
const branches = moment.branches ?? [];
|
|
63806
|
+
const seq = moment.sequence;
|
|
63807
|
+
if (seq && isUsableSequence(seq, entries.length, branches.length)) {
|
|
63808
|
+
return seq.map((item) => item.kind === "entry" ? { kind: "entry", entry: entries[item.index], entryIndex: item.index } : { kind: "branch", branch: branches[item.index], branchIndex: item.index });
|
|
63809
|
+
}
|
|
63810
|
+
const entryChildren = entries.map((entry, i) => ({
|
|
63811
|
+
kind: "entry",
|
|
63812
|
+
entry,
|
|
63813
|
+
entryIndex: i
|
|
63814
|
+
}));
|
|
63815
|
+
const branchChildren = branches.map((branch, i) => ({
|
|
63816
|
+
kind: "branch",
|
|
63817
|
+
branch,
|
|
63818
|
+
branchIndex: i
|
|
63819
|
+
}));
|
|
63820
|
+
return fallback === "entries-first" ? [...entryChildren, ...branchChildren] : [...branchChildren, ...entryChildren];
|
|
63821
|
+
}
|
|
63822
|
+
function isUsableSequence(seq, entryCount, branchCount) {
|
|
63823
|
+
if (seq.length !== entryCount + branchCount)
|
|
63824
|
+
return false;
|
|
63825
|
+
const seenEntries = /* @__PURE__ */ new Set();
|
|
63826
|
+
const seenBranches = /* @__PURE__ */ new Set();
|
|
63827
|
+
for (const item of seq) {
|
|
63828
|
+
if (item.kind === "entry") {
|
|
63829
|
+
if (item.index < 0 || item.index >= entryCount || seenEntries.has(item.index))
|
|
63830
|
+
return false;
|
|
63831
|
+
seenEntries.add(item.index);
|
|
63832
|
+
} else {
|
|
63833
|
+
if (item.index < 0 || item.index >= branchCount || seenBranches.has(item.index))
|
|
63834
|
+
return false;
|
|
63835
|
+
seenBranches.add(item.index);
|
|
63836
|
+
}
|
|
63837
|
+
}
|
|
63838
|
+
return true;
|
|
63839
|
+
}
|
|
63840
|
+
|
|
63180
63841
|
// ../derive/dist/engine/simulation-scenario-generator.js
|
|
63181
63842
|
function resolveNodeKind(nodeName, contextId, contextMap) {
|
|
63182
63843
|
const ctx = contextMap.get(contextId);
|
|
63183
63844
|
if (!ctx)
|
|
63184
63845
|
return "event";
|
|
63185
|
-
const
|
|
63186
|
-
if (
|
|
63846
|
+
const isCommand = findCommand(ctx, nodeName) !== void 0;
|
|
63847
|
+
if (isCommand)
|
|
63187
63848
|
return "command";
|
|
63188
63849
|
const isEvent = findEvent(ctx, nodeName) !== void 0;
|
|
63189
63850
|
if (isEvent)
|
|
@@ -63203,17 +63864,31 @@ function resolveOptions(flow, options) {
|
|
|
63203
63864
|
function generateSimulationScenario(ir, flow, options) {
|
|
63204
63865
|
const opts = resolveOptions(flow, options);
|
|
63205
63866
|
const contextMap = buildContextMap(ir);
|
|
63206
|
-
const
|
|
63207
|
-
const
|
|
63208
|
-
const
|
|
63867
|
+
const walk = walkPath(flow, opts.branchSelections);
|
|
63868
|
+
const nodes = walk.nodes;
|
|
63869
|
+
const seenActivations = /* @__PURE__ */ new Set();
|
|
63870
|
+
const activeBranches = [];
|
|
63871
|
+
for (const a of walk.activations) {
|
|
63872
|
+
const key = `${a.momentName}\0${a.condition}`;
|
|
63873
|
+
if (seenActivations.has(key))
|
|
63874
|
+
continue;
|
|
63875
|
+
seenActivations.add(key);
|
|
63876
|
+
activeBranches.push({
|
|
63877
|
+
momentName: a.momentName,
|
|
63878
|
+
condition: a.condition,
|
|
63879
|
+
routeChosen: a.condition
|
|
63880
|
+
});
|
|
63881
|
+
}
|
|
63882
|
+
const rawEvents = generateEvents(nodes, flow, contextMap, opts.sessionId, opts.correlationId, opts.baseTime);
|
|
63209
63883
|
const events = injectSagaTransitions(rawEvents, ir, opts.sessionId, opts.correlationId);
|
|
63210
63884
|
const contextNames = [...new Set(nodes.map((n) => n.contextName))];
|
|
63211
|
-
const label = resolveScenarioLabel(flow,
|
|
63885
|
+
const label = resolveScenarioLabel(flow, walk.reachedBranches);
|
|
63212
63886
|
return {
|
|
63213
63887
|
scenarioId: opts.scenarioId,
|
|
63214
63888
|
flowId: flow.id,
|
|
63215
63889
|
flowName: flow.name,
|
|
63216
63890
|
scenarioLabel: label,
|
|
63891
|
+
kind: resolveScenarioKind(walk.reachedBranches),
|
|
63217
63892
|
description: flow.description ?? `Full lifecycle flow: ${flow.name}`,
|
|
63218
63893
|
given: `A ${(flow.moments[0]?.name ?? "").toLowerCase()} scenario is initiated`,
|
|
63219
63894
|
when: buildWhenClause(flow, nodes),
|
|
@@ -63228,105 +63903,184 @@ function generateAllScenarios(ir, flow, options) {
|
|
|
63228
63903
|
if (combinations.length === 0) {
|
|
63229
63904
|
return [generateSimulationScenario(ir, flow, options)];
|
|
63230
63905
|
}
|
|
63231
|
-
|
|
63232
|
-
|
|
63233
|
-
|
|
63234
|
-
|
|
63235
|
-
|
|
63906
|
+
const seenPaths = /* @__PURE__ */ new Set();
|
|
63907
|
+
const scenarios = [];
|
|
63908
|
+
for (const selections of combinations) {
|
|
63909
|
+
const pathKey = walkPath(flow, selections).nodes.map((n) => n.nodeId).join("|");
|
|
63910
|
+
if (seenPaths.has(pathKey))
|
|
63911
|
+
continue;
|
|
63912
|
+
seenPaths.add(pathKey);
|
|
63913
|
+
const idx = scenarios.length;
|
|
63914
|
+
scenarios.push(generateSimulationScenario(ir, flow, {
|
|
63915
|
+
...options,
|
|
63916
|
+
scenarioId: options?.scenarioId ? `${options.scenarioId}-${idx}` : `scenario-${flow.id}-${idx}`,
|
|
63917
|
+
branchSelections: selections
|
|
63918
|
+
}));
|
|
63919
|
+
}
|
|
63920
|
+
return scenarios;
|
|
63236
63921
|
}
|
|
63237
63922
|
function enumerateBranchCombinations(flow) {
|
|
63238
|
-
const
|
|
63239
|
-
if (
|
|
63923
|
+
const hasBranchPoints = flow.moments.some((m) => m.branches && m.branches.length > 0);
|
|
63924
|
+
if (!hasBranchPoints)
|
|
63240
63925
|
return [];
|
|
63241
|
-
|
|
63242
|
-
|
|
63243
|
-
const
|
|
63244
|
-
|
|
63245
|
-
|
|
63246
|
-
|
|
63247
|
-
|
|
63926
|
+
const results = [];
|
|
63927
|
+
const expand = (selections) => {
|
|
63928
|
+
const walk = walkPath(flow, selections);
|
|
63929
|
+
const next = walk.reachedBranches.find((b) => !(b.momentName in selections));
|
|
63930
|
+
if (!next) {
|
|
63931
|
+
results.push(selections);
|
|
63932
|
+
return;
|
|
63248
63933
|
}
|
|
63249
|
-
|
|
63250
|
-
|
|
63251
|
-
|
|
63934
|
+
const moment = flow.moments.find((m) => m.name === next.momentName);
|
|
63935
|
+
for (const branch of moment?.branches ?? []) {
|
|
63936
|
+
expand({ ...selections, [next.momentName]: branch.condition });
|
|
63937
|
+
}
|
|
63938
|
+
};
|
|
63939
|
+
expand({});
|
|
63940
|
+
return results;
|
|
63252
63941
|
}
|
|
63253
|
-
function resolveScenarioLabel(flow,
|
|
63254
|
-
const
|
|
63255
|
-
if (
|
|
63256
|
-
return `Happy Path: ${flow.name}`;
|
|
63257
|
-
const terminalConditions = collectTerminalConditions(branchMoments, branchSelections);
|
|
63258
|
-
const isAllFirstBranch = checkAllFirstBranch(branchMoments, branchSelections);
|
|
63259
|
-
if (isAllFirstBranch)
|
|
63942
|
+
function resolveScenarioLabel(flow, reachedBranches) {
|
|
63943
|
+
const deviations = reachedBranches.filter((b) => !b.isFirstArm);
|
|
63944
|
+
if (deviations.length === 0)
|
|
63260
63945
|
return `Happy Path: ${flow.name}`;
|
|
63261
|
-
|
|
63262
|
-
|
|
63263
|
-
}
|
|
63264
|
-
const selectedConditions = branchMoments.map((m) => branchSelections[m.name]).filter(Boolean);
|
|
63265
|
-
return `Variant: ${flow.name} [${selectedConditions.join(", ")}]`;
|
|
63266
|
-
}
|
|
63267
|
-
function collectTerminalConditions(branchMoments, branchSelections) {
|
|
63268
|
-
const conditions = [];
|
|
63269
|
-
for (const moment of branchMoments) {
|
|
63270
|
-
const selected = branchSelections[moment.name];
|
|
63271
|
-
if (!selected)
|
|
63272
|
-
continue;
|
|
63273
|
-
const branch = moment.branches.find((b) => b.condition === selected);
|
|
63274
|
-
if (branch && branch.entries.some((e) => e.terminal)) {
|
|
63275
|
-
conditions.push(selected);
|
|
63276
|
-
}
|
|
63277
|
-
}
|
|
63278
|
-
return conditions;
|
|
63946
|
+
const bracket = deviations.map((b) => b.condition).join(", ");
|
|
63947
|
+
const hasTerminalArm = deviations.some((b) => b.armHasTerminal);
|
|
63948
|
+
return hasTerminalArm ? `Failure Path: ${flow.name} [${bracket}]` : `Variant: ${flow.name} [${bracket}]`;
|
|
63279
63949
|
}
|
|
63280
|
-
function
|
|
63281
|
-
|
|
63282
|
-
|
|
63283
|
-
|
|
63284
|
-
|
|
63285
|
-
return false;
|
|
63286
|
-
}
|
|
63287
|
-
return true;
|
|
63950
|
+
function resolveScenarioKind(reachedBranches) {
|
|
63951
|
+
const deviations = reachedBranches.filter((b) => !b.isFirstArm);
|
|
63952
|
+
if (deviations.length === 0)
|
|
63953
|
+
return "happy";
|
|
63954
|
+
return deviations.some((b) => b.armHasTerminal) ? "failure" : "variant";
|
|
63288
63955
|
}
|
|
63289
63956
|
function buildContextMap(ir) {
|
|
63290
63957
|
return new Map(ir.contexts.map((c) => [c.id, c]));
|
|
63291
63958
|
}
|
|
63292
|
-
function
|
|
63959
|
+
function walkPath(flow, branchSelections) {
|
|
63293
63960
|
const laneIndex = new Map(flow.lanes.map((l) => [l.contextId, l.id]));
|
|
63294
|
-
const
|
|
63295
|
-
|
|
63296
|
-
|
|
63297
|
-
|
|
63298
|
-
|
|
63961
|
+
const momentIndexById = new Map(flow.moments.map((m, idx2) => [m.id, idx2]));
|
|
63962
|
+
const returnsToCount = flow.connections.filter((c) => c.connectionType === "returns-to").length;
|
|
63963
|
+
const maxMomentVisits = flow.moments.length * (returnsToCount + 2);
|
|
63964
|
+
const state = {
|
|
63965
|
+
nodes: [],
|
|
63966
|
+
reachedBranches: [],
|
|
63967
|
+
activations: [],
|
|
63968
|
+
reachedNames: /* @__PURE__ */ new Set(),
|
|
63969
|
+
forcedFirstArm: /* @__PURE__ */ new Set(),
|
|
63970
|
+
usedReturns: /* @__PURE__ */ new Set()
|
|
63971
|
+
};
|
|
63972
|
+
let idx = 0;
|
|
63973
|
+
let visits = 0;
|
|
63974
|
+
while (idx < flow.moments.length && visits < maxMomentVisits) {
|
|
63975
|
+
visits++;
|
|
63976
|
+
const moment = flow.moments[idx];
|
|
63977
|
+
const step = moment.branches && moment.branches.length > 0 ? walkBranchedMoment(moment, idx, flow, branchSelections, laneIndex, momentIndexById, state) : walkPlainMoment(moment, idx, laneIndex, state);
|
|
63978
|
+
if (step.stop)
|
|
63299
63979
|
break;
|
|
63980
|
+
idx = step.jumpTo ?? idx + 1;
|
|
63300
63981
|
}
|
|
63301
|
-
return
|
|
63982
|
+
return {
|
|
63983
|
+
nodes: state.nodes,
|
|
63984
|
+
reachedBranches: state.reachedBranches,
|
|
63985
|
+
activations: state.activations
|
|
63986
|
+
};
|
|
63302
63987
|
}
|
|
63303
|
-
function
|
|
63304
|
-
|
|
63305
|
-
|
|
63306
|
-
|
|
63307
|
-
|
|
63308
|
-
|
|
63988
|
+
function walkPlainMoment(moment, momentIndex, laneIndex, state) {
|
|
63989
|
+
for (const child of orderedMomentChildren(moment, "entries-first")) {
|
|
63990
|
+
if (child.kind !== "entry")
|
|
63991
|
+
continue;
|
|
63992
|
+
pushEntryNodes(state.nodes, child.entry, moment, momentIndex, laneIndex, "main", void 0);
|
|
63993
|
+
if (child.entry.terminal)
|
|
63994
|
+
return { stop: true };
|
|
63995
|
+
}
|
|
63996
|
+
return { stop: false };
|
|
63997
|
+
}
|
|
63998
|
+
function walkBranchedMoment(moment, momentIndex, flow, branchSelections, laneIndex, momentIndexById, state) {
|
|
63999
|
+
const branches = moment.branches;
|
|
64000
|
+
const { branch, forced } = selectBranch(moment, branchSelections, state);
|
|
64001
|
+
if (!branch)
|
|
64002
|
+
return walkPlainMoment(moment, momentIndex, laneIndex, state);
|
|
64003
|
+
const branchIdx = branches.indexOf(branch);
|
|
64004
|
+
recordBranchPoint(state, moment, branch, branchIdx, forced);
|
|
64005
|
+
let emittedAny = false;
|
|
64006
|
+
let branchEmitted = false;
|
|
64007
|
+
for (const child of orderedMomentChildren(moment, "branches-first")) {
|
|
64008
|
+
if (child.kind === "branch") {
|
|
64009
|
+
if (branchEmitted)
|
|
64010
|
+
continue;
|
|
64011
|
+
branchEmitted = true;
|
|
64012
|
+
const step = emitSelectedArm(moment, momentIndex, flow, branch, branchIdx, laneIndex, momentIndexById, state);
|
|
64013
|
+
if (step)
|
|
64014
|
+
return step;
|
|
64015
|
+
if (branch.entries.length > 0)
|
|
64016
|
+
emittedAny = true;
|
|
64017
|
+
} else {
|
|
64018
|
+
const outcome = emittedAny ? void 0 : branch.condition;
|
|
64019
|
+
pushEntryNodes(state.nodes, child.entry, moment, momentIndex, laneIndex, "main", outcome);
|
|
64020
|
+
emittedAny = true;
|
|
64021
|
+
if (child.entry.terminal)
|
|
64022
|
+
return { stop: true };
|
|
64023
|
+
}
|
|
64024
|
+
}
|
|
64025
|
+
return { stop: false };
|
|
64026
|
+
}
|
|
64027
|
+
function selectBranch(moment, branchSelections, state) {
|
|
64028
|
+
const branches = moment.branches;
|
|
64029
|
+
const forced = state.forcedFirstArm.has(moment.name);
|
|
64030
|
+
const selected = forced ? branches[0]?.condition : branchSelections[moment.name];
|
|
64031
|
+
const branch = (selected ? branches.find((b) => b.condition === selected) : void 0) ?? branches[0];
|
|
64032
|
+
return { branch, forced };
|
|
64033
|
+
}
|
|
64034
|
+
function recordBranchPoint(state, moment, branch, branchIdx, forced) {
|
|
64035
|
+
state.activations.push({ momentName: moment.name, condition: branch.condition });
|
|
64036
|
+
if (!forced && !state.reachedNames.has(moment.name)) {
|
|
64037
|
+
state.reachedNames.add(moment.name);
|
|
64038
|
+
state.reachedBranches.push({
|
|
64039
|
+
momentName: moment.name,
|
|
64040
|
+
condition: branch.condition,
|
|
64041
|
+
isFirstArm: branchIdx === 0,
|
|
64042
|
+
armHasTerminal: branch.entries.some((e) => e.terminal)
|
|
64043
|
+
});
|
|
63309
64044
|
}
|
|
63310
|
-
return false;
|
|
63311
64045
|
}
|
|
63312
|
-
function
|
|
63313
|
-
const
|
|
63314
|
-
|
|
63315
|
-
|
|
63316
|
-
|
|
63317
|
-
|
|
63318
|
-
|
|
63319
|
-
|
|
63320
|
-
|
|
63321
|
-
|
|
64046
|
+
function emitSelectedArm(moment, momentIndex, flow, branch, branchIdx, laneIndex, momentIndexById, state) {
|
|
64047
|
+
for (const entry of branch.entries) {
|
|
64048
|
+
pushEntryNodes(state.nodes, entry, moment, momentIndex, laneIndex, `br${branchIdx}`, branch.condition);
|
|
64049
|
+
if (entry.terminal)
|
|
64050
|
+
return { stop: true };
|
|
64051
|
+
}
|
|
64052
|
+
const returnsTo = findReturnsToConnection(flow, moment, branch);
|
|
64053
|
+
if (returnsTo?.targetMomentId !== void 0 && !state.usedReturns.has(returnsTo.id)) {
|
|
64054
|
+
const targetIdx = momentIndexById.get(returnsTo.targetMomentId);
|
|
64055
|
+
if (targetIdx !== void 0) {
|
|
64056
|
+
state.usedReturns.add(returnsTo.id);
|
|
64057
|
+
state.forcedFirstArm.add(moment.name);
|
|
64058
|
+
return { stop: false, jumpTo: targetIdx };
|
|
63322
64059
|
}
|
|
63323
64060
|
}
|
|
63324
|
-
|
|
63325
|
-
|
|
64061
|
+
return null;
|
|
64062
|
+
}
|
|
64063
|
+
function findReturnsToConnection(flow, moment, branch) {
|
|
64064
|
+
return flow.connections.find((c) => c.connectionType === "returns-to" && c.sourceMomentId === moment.id && (c.branchCondition === branch.condition || c.branchCondition === void 0 && branch.entries.some((e) => e.nodeName === c.sourceNodeName)));
|
|
64065
|
+
}
|
|
64066
|
+
function pushEntryNodes(nodes, entry, moment, momentIndex, laneIndex, scope, outcome) {
|
|
64067
|
+
const count = resolveMultiplicity(entry.multiplicity);
|
|
64068
|
+
for (let k = 0; k < count; k++) {
|
|
64069
|
+
nodes.push(entryToNode(entry, moment, momentIndex, laneIndex, scope, outcome));
|
|
64070
|
+
}
|
|
64071
|
+
}
|
|
64072
|
+
function resolveMultiplicity(multiplicity) {
|
|
64073
|
+
if (typeof multiplicity === "number" && Number.isFinite(multiplicity) && multiplicity > 1) {
|
|
64074
|
+
return Math.floor(multiplicity);
|
|
64075
|
+
}
|
|
64076
|
+
if (typeof multiplicity === "string" && /^\d+$/.test(multiplicity)) {
|
|
64077
|
+
const n = parseInt(multiplicity, 10);
|
|
64078
|
+
if (n > 1)
|
|
64079
|
+
return n;
|
|
63326
64080
|
}
|
|
63327
|
-
return
|
|
64081
|
+
return 1;
|
|
63328
64082
|
}
|
|
63329
|
-
function entryToNode(entry, moment, momentIndex, laneIndex, scope) {
|
|
64083
|
+
function entryToNode(entry, moment, momentIndex, laneIndex, scope, outcome) {
|
|
63330
64084
|
const contextName = entry.contextId.replace(/^ctx-/, "");
|
|
63331
64085
|
const laneId = laneIndex.get(entry.contextId) ?? entry.contextId;
|
|
63332
64086
|
return {
|
|
@@ -63336,42 +64090,24 @@ function entryToNode(entry, moment, momentIndex, laneIndex, scope) {
|
|
|
63336
64090
|
contextName,
|
|
63337
64091
|
nodeKind: entry.nodeKind,
|
|
63338
64092
|
momentName: moment.name,
|
|
63339
|
-
|
|
64093
|
+
momentId: moment.id,
|
|
64094
|
+
momentIndex,
|
|
64095
|
+
...outcome !== void 0 ? { outcome } : {}
|
|
63340
64096
|
};
|
|
63341
64097
|
}
|
|
63342
|
-
function
|
|
63343
|
-
const branches = [];
|
|
63344
|
-
for (const moment of flow.moments) {
|
|
63345
|
-
if (moment.branches && moment.branches.length > 0) {
|
|
63346
|
-
const selected = branchSelections[moment.name] ?? moment.branches[0]?.condition;
|
|
63347
|
-
if (selected) {
|
|
63348
|
-
branches.push({
|
|
63349
|
-
momentName: moment.name,
|
|
63350
|
-
condition: selected,
|
|
63351
|
-
routeChosen: selected
|
|
63352
|
-
});
|
|
63353
|
-
}
|
|
63354
|
-
}
|
|
63355
|
-
}
|
|
63356
|
-
return branches;
|
|
63357
|
-
}
|
|
63358
|
-
function generateEvents(nodes, flow, contextMap, ir, sessionId, correlationId, baseTime) {
|
|
64098
|
+
function generateEvents(nodes, flow, contextMap, sessionId, correlationId, baseTime) {
|
|
63359
64099
|
const events = [];
|
|
63360
|
-
const
|
|
63361
|
-
let eventCounter = 0;
|
|
64100
|
+
const eventIds = nodes.map((_, i) => `evt-${String(i + 1).padStart(3, "0")}`);
|
|
63362
64101
|
for (let i = 0; i < nodes.length; i++) {
|
|
63363
64102
|
const node = nodes[i];
|
|
63364
|
-
eventCounter++;
|
|
63365
|
-
const eventId = `evt-${String(eventCounter).padStart(3, "0")}`;
|
|
63366
|
-
nodeToEventId.set(node.nodeId, eventId);
|
|
63367
64103
|
const timestamp = new Date(baseTime.getTime() + i * 1e3).toISOString();
|
|
63368
|
-
const causationEventIds = findCausationEvents(node, nodes, flow,
|
|
64104
|
+
const causationEventIds = findCausationEvents(node, nodes, flow, eventIds, i);
|
|
63369
64105
|
const effectiveKind = resolveNodeKind(node.nodeName, node.contextId, contextMap);
|
|
63370
64106
|
const eventType = resolveEventType(node, effectiveKind);
|
|
63371
64107
|
const productSource = resolveProductSource(node, effectiveKind, contextMap);
|
|
63372
|
-
const payload = buildPayload(node, effectiveKind, contextMap,
|
|
64108
|
+
const payload = buildPayload(node, effectiveKind, contextMap, flow);
|
|
63373
64109
|
events.push({
|
|
63374
|
-
eventId,
|
|
64110
|
+
eventId: eventIds[i],
|
|
63375
64111
|
eventType,
|
|
63376
64112
|
productSource,
|
|
63377
64113
|
sessionId,
|
|
@@ -63384,34 +64120,40 @@ function generateEvents(nodes, flow, contextMap, ir, sessionId, correlationId, b
|
|
|
63384
64120
|
}
|
|
63385
64121
|
return events;
|
|
63386
64122
|
}
|
|
63387
|
-
function findCausationEvents(node, allNodes, flow,
|
|
64123
|
+
function findCausationEvents(node, allNodes, flow, eventIds, currentIndex) {
|
|
63388
64124
|
const causation = [];
|
|
63389
64125
|
for (const conn of flow.connections) {
|
|
63390
|
-
if (conn
|
|
63391
|
-
|
|
63392
|
-
|
|
64126
|
+
if (!isCausationConnectionFor(conn, node))
|
|
64127
|
+
continue;
|
|
64128
|
+
const triggerName = conn.sourceNodeName ?? conn.eventId.replace(/^evt-/, "");
|
|
64129
|
+
const causeId = findLatestPriorEmission(triggerName, allNodes, eventIds, currentIndex);
|
|
64130
|
+
if (causeId !== void 0)
|
|
64131
|
+
causation.push(causeId);
|
|
63393
64132
|
}
|
|
63394
|
-
|
|
63395
|
-
|
|
63396
|
-
|
|
63397
|
-
if (prevEvtId)
|
|
63398
|
-
causation.push(prevEvtId);
|
|
64133
|
+
const deduped = [...new Set(causation)];
|
|
64134
|
+
if (deduped.length === 0 && currentIndex > 0) {
|
|
64135
|
+
deduped.push(eventIds[currentIndex - 1]);
|
|
63399
64136
|
}
|
|
63400
|
-
return
|
|
64137
|
+
return deduped;
|
|
63401
64138
|
}
|
|
63402
|
-
function
|
|
63403
|
-
|
|
63404
|
-
|
|
63405
|
-
if (
|
|
63406
|
-
return;
|
|
64139
|
+
function isCausationConnectionFor(conn, node) {
|
|
64140
|
+
if (conn.connectionType !== "triggered-by")
|
|
64141
|
+
return false;
|
|
64142
|
+
if (conn.targetNodeName !== node.nodeName)
|
|
64143
|
+
return false;
|
|
64144
|
+
if (conn.sourceMomentId !== node.momentId)
|
|
64145
|
+
return false;
|
|
64146
|
+
if (conn.branchCondition !== void 0 && conn.branchCondition !== node.outcome)
|
|
64147
|
+
return false;
|
|
64148
|
+
return true;
|
|
64149
|
+
}
|
|
64150
|
+
function findLatestPriorEmission(triggerName, allNodes, eventIds, currentIndex) {
|
|
63407
64151
|
for (let j = currentIndex - 1; j >= 0; j--) {
|
|
63408
|
-
if (allNodes[j].nodeName ===
|
|
63409
|
-
|
|
63410
|
-
if (evtId)
|
|
63411
|
-
causation.push(evtId);
|
|
63412
|
-
break;
|
|
64152
|
+
if (allNodes[j].nodeName === triggerName) {
|
|
64153
|
+
return eventIds[j];
|
|
63413
64154
|
}
|
|
63414
64155
|
}
|
|
64156
|
+
return void 0;
|
|
63415
64157
|
}
|
|
63416
64158
|
function resolveEventType(node, effectiveKind) {
|
|
63417
64159
|
if (effectiveKind === "command") {
|
|
@@ -63431,99 +64173,112 @@ function resolveProductSource(node, effectiveKind, contextMap) {
|
|
|
63431
64173
|
}
|
|
63432
64174
|
return "moment:simulation";
|
|
63433
64175
|
}
|
|
63434
|
-
function buildPayload(node, effectiveKind, contextMap,
|
|
64176
|
+
function buildPayload(node, effectiveKind, contextMap, flow) {
|
|
63435
64177
|
const payload = {
|
|
63436
64178
|
nodeId: node.nodeId
|
|
63437
64179
|
};
|
|
63438
64180
|
const ctx = contextMap.get(node.contextId);
|
|
63439
|
-
|
|
63440
|
-
|
|
63441
|
-
if (effectiveKind === "command") {
|
|
63442
|
-
return buildCommandPayload(payload, ctx, node);
|
|
63443
|
-
}
|
|
63444
|
-
if (effectiveKind === "event") {
|
|
63445
|
-
return buildEventPayload(payload, ctx, node);
|
|
63446
|
-
}
|
|
63447
|
-
return payload;
|
|
63448
|
-
}
|
|
63449
|
-
function buildCommandPayload(payload, ctx, node) {
|
|
63450
|
-
payload.processName = node.nodeName;
|
|
63451
|
-
const cmd = findCommand(ctx, node.nodeName);
|
|
64181
|
+
const cmd = ctx && effectiveKind === "command" ? findCommand(ctx, node.nodeName) : void 0;
|
|
64182
|
+
const evt = ctx && effectiveKind === "event" ? findEvent(ctx, node.nodeName) : void 0;
|
|
63452
64183
|
if (cmd) {
|
|
64184
|
+
payload.processName = node.nodeName;
|
|
63453
64185
|
for (const input of cmd.inputs) {
|
|
63454
64186
|
payload[input.name] = generatePlaceholder(input.type, input.name);
|
|
63455
64187
|
}
|
|
64188
|
+
} else if (evt) {
|
|
64189
|
+
for (const field of evt.fields) {
|
|
64190
|
+
payload[field.name] = generatePlaceholder(field.type, field.name);
|
|
64191
|
+
}
|
|
64192
|
+
}
|
|
64193
|
+
addContractFields(payload, node, flow);
|
|
64194
|
+
if (node.outcome !== void 0) {
|
|
64195
|
+
payload.outcome = node.outcome;
|
|
63456
64196
|
}
|
|
63457
64197
|
return payload;
|
|
63458
64198
|
}
|
|
63459
|
-
function
|
|
63460
|
-
const
|
|
63461
|
-
|
|
63462
|
-
|
|
64199
|
+
function addContractFields(payload, node, flow) {
|
|
64200
|
+
for (const conn of flow.connections) {
|
|
64201
|
+
if (conn.connectionType !== "crosses-to")
|
|
64202
|
+
continue;
|
|
64203
|
+
if (conn.sourceNodeName !== node.nodeName)
|
|
64204
|
+
continue;
|
|
64205
|
+
if (!("schemaContract" in conn))
|
|
64206
|
+
continue;
|
|
64207
|
+
for (const field of conn.schemaContract.fields) {
|
|
64208
|
+
if (field.name in payload)
|
|
64209
|
+
continue;
|
|
63463
64210
|
payload[field.name] = generatePlaceholder(field.type, field.name);
|
|
63464
64211
|
}
|
|
63465
64212
|
}
|
|
63466
|
-
return payload;
|
|
63467
64213
|
}
|
|
63468
64214
|
function injectSagaTransitions(events, ir, sessionId, correlationId) {
|
|
63469
|
-
const
|
|
63470
|
-
if (
|
|
64215
|
+
const sagas = collectSagas(ir);
|
|
64216
|
+
if (sagas.length === 0 || events.length === 0)
|
|
63471
64217
|
return events;
|
|
63472
|
-
const
|
|
63473
|
-
const
|
|
63474
|
-
|
|
63475
|
-
|
|
63476
|
-
|
|
63477
|
-
|
|
63478
|
-
|
|
63479
|
-
|
|
63480
|
-
|
|
63481
|
-
|
|
63482
|
-
|
|
63483
|
-
|
|
63484
|
-
|
|
64218
|
+
const sagaEvents = [];
|
|
64219
|
+
const lastPathTime = new Date(events[events.length - 1].timestamp).getTime();
|
|
64220
|
+
for (const saga of sagas) {
|
|
64221
|
+
for (const step of computeSagaProgression(saga, events)) {
|
|
64222
|
+
const eventCounter = events.length + sagaEvents.length + 1;
|
|
64223
|
+
const timestamp = new Date(lastPathTime + (sagaEvents.length + 1) * 1e3).toISOString();
|
|
64224
|
+
sagaEvents.push({
|
|
64225
|
+
eventId: `evt-${String(eventCounter).padStart(3, "0")}`,
|
|
64226
|
+
eventType: `SimSaga.${saga.name}.${step.state}`,
|
|
64227
|
+
productSource: "moment:simulation",
|
|
64228
|
+
sessionId,
|
|
64229
|
+
causationEventIds: [step.cause.eventId],
|
|
64230
|
+
correlationId,
|
|
64231
|
+
timestamp,
|
|
64232
|
+
version: 1,
|
|
64233
|
+
payload: {
|
|
64234
|
+
sagaName: saga.name,
|
|
64235
|
+
state: step.state,
|
|
64236
|
+
triggeredBy: step.cause.eventType
|
|
64237
|
+
}
|
|
64238
|
+
});
|
|
63485
64239
|
}
|
|
63486
64240
|
}
|
|
63487
|
-
return
|
|
64241
|
+
return [...events, ...sagaEvents];
|
|
63488
64242
|
}
|
|
63489
|
-
function
|
|
63490
|
-
|
|
63491
|
-
|
|
63492
|
-
|
|
63493
|
-
|
|
63494
|
-
|
|
63495
|
-
|
|
63496
|
-
|
|
64243
|
+
function collectSagas(ir) {
|
|
64244
|
+
return ir.contexts.flatMap((ctx) => ctx.sagas);
|
|
64245
|
+
}
|
|
64246
|
+
function computeSagaProgression(saga, events) {
|
|
64247
|
+
if (saga.states.length === 0)
|
|
64248
|
+
return [];
|
|
64249
|
+
const triggerIdx = events.findIndex((e) => e.eventType === saga.trigger);
|
|
64250
|
+
if (triggerIdx === -1)
|
|
64251
|
+
return [];
|
|
64252
|
+
const steps = [{ state: saga.states[0], cause: events[triggerIdx] }];
|
|
64253
|
+
let cursor = triggerIdx;
|
|
64254
|
+
for (const transition of sagaTransitionChain(saga)) {
|
|
64255
|
+
if (!transition.onEvent)
|
|
64256
|
+
break;
|
|
64257
|
+
const fireIdx = findEventAfter(events, transition.onEvent, cursor);
|
|
64258
|
+
if (fireIdx === -1)
|
|
64259
|
+
break;
|
|
64260
|
+
steps.push({ state: transition.to, cause: events[fireIdx] });
|
|
64261
|
+
cursor = fireIdx;
|
|
63497
64262
|
}
|
|
63498
|
-
return
|
|
64263
|
+
return steps;
|
|
63499
64264
|
}
|
|
63500
|
-
function
|
|
63501
|
-
|
|
63502
|
-
|
|
63503
|
-
|
|
63504
|
-
|
|
63505
|
-
|
|
63506
|
-
|
|
63507
|
-
|
|
63508
|
-
|
|
63509
|
-
productSource: "moment:simulation",
|
|
63510
|
-
sessionId,
|
|
63511
|
-
causationEventIds: [triggerEvent.eventId],
|
|
63512
|
-
correlationId,
|
|
63513
|
-
timestamp: triggerEvent.timestamp,
|
|
63514
|
-
version: 1,
|
|
63515
|
-
payload: {
|
|
63516
|
-
sagaName: saga.name,
|
|
63517
|
-
state: nextState,
|
|
63518
|
-
triggeredBy: triggerEvent.eventType
|
|
63519
|
-
}
|
|
63520
|
-
};
|
|
64265
|
+
function sagaTransitionChain(saga) {
|
|
64266
|
+
return saga.transitions ?? [];
|
|
64267
|
+
}
|
|
64268
|
+
function findEventAfter(events, eventType, afterIndex) {
|
|
64269
|
+
for (let i = afterIndex + 1; i < events.length; i++) {
|
|
64270
|
+
if (events[i].eventType === eventType)
|
|
64271
|
+
return i;
|
|
64272
|
+
}
|
|
64273
|
+
return -1;
|
|
63521
64274
|
}
|
|
63522
64275
|
function deriveNegativeScenarios(ir, flow, options) {
|
|
63523
64276
|
const contextMap = buildContextMap(ir);
|
|
63524
64277
|
const opts = resolveOptions(flow, options);
|
|
63525
|
-
const
|
|
64278
|
+
const walk = walkPath(flow, opts.branchSelections);
|
|
64279
|
+
const nodes = walk.nodes;
|
|
63526
64280
|
const scenarios = [];
|
|
64281
|
+
const usedIds = /* @__PURE__ */ new Set();
|
|
63527
64282
|
for (let i = 0; i < nodes.length; i++) {
|
|
63528
64283
|
const node = nodes[i];
|
|
63529
64284
|
const kind = resolveNodeKind(node.nodeName, node.contextId, contextMap);
|
|
@@ -63531,7 +64286,11 @@ function deriveNegativeScenarios(ir, flow, options) {
|
|
|
63531
64286
|
continue;
|
|
63532
64287
|
const preconditions = findPreconditions(node, contextMap);
|
|
63533
64288
|
for (const pre of preconditions) {
|
|
63534
|
-
|
|
64289
|
+
const baseId = `${opts.scenarioId}-neg-${node.nodeName}-${pre.name}`;
|
|
64290
|
+
const scenarioId = usedIds.has(baseId) ? `${baseId}-${i}` : baseId;
|
|
64291
|
+
usedIds.add(scenarioId);
|
|
64292
|
+
usedIds.add(baseId);
|
|
64293
|
+
scenarios.push(buildNegativeScenario(ir, flow, walk, i, pre, contextMap, opts, scenarioId));
|
|
63535
64294
|
}
|
|
63536
64295
|
}
|
|
63537
64296
|
return scenarios;
|
|
@@ -63543,23 +64302,41 @@ function findPreconditions(node, contextMap) {
|
|
|
63543
64302
|
const cmd = findCommand(ctx, node.nodeName);
|
|
63544
64303
|
return cmd?.preconditions ?? [];
|
|
63545
64304
|
}
|
|
63546
|
-
function buildNegativeScenario(ir, flow,
|
|
64305
|
+
function buildNegativeScenario(ir, flow, walk, failIndex, precondition, contextMap, opts, scenarioId) {
|
|
64306
|
+
const allNodes = walk.nodes;
|
|
63547
64307
|
const precedingNodes = allNodes.slice(0, failIndex + 1);
|
|
63548
64308
|
const failNode = allNodes[failIndex];
|
|
63549
|
-
const
|
|
64309
|
+
const reachedMoments = new Set(precedingNodes.map((n) => n.momentName));
|
|
64310
|
+
const seenActivations = /* @__PURE__ */ new Set();
|
|
64311
|
+
const activeBranches = [];
|
|
64312
|
+
for (const a of walk.activations) {
|
|
64313
|
+
if (!reachedMoments.has(a.momentName))
|
|
64314
|
+
continue;
|
|
64315
|
+
const key = `${a.momentName} ${a.condition}`;
|
|
64316
|
+
if (seenActivations.has(key))
|
|
64317
|
+
continue;
|
|
64318
|
+
seenActivations.add(key);
|
|
64319
|
+
activeBranches.push({
|
|
64320
|
+
momentName: a.momentName,
|
|
64321
|
+
condition: a.condition,
|
|
64322
|
+
routeChosen: a.condition
|
|
64323
|
+
});
|
|
64324
|
+
}
|
|
64325
|
+
const events = generateEvents(precedingNodes, flow, contextMap, opts.sessionId, opts.correlationId, opts.baseTime);
|
|
63550
64326
|
const failureEvent = buildFailureEvent(failNode, precondition, events, opts);
|
|
63551
|
-
const allEvents = [...events, failureEvent];
|
|
64327
|
+
const allEvents = injectSagaTransitions([...events, failureEvent], ir, opts.sessionId, opts.correlationId);
|
|
63552
64328
|
return {
|
|
63553
|
-
scenarioId
|
|
64329
|
+
scenarioId,
|
|
63554
64330
|
flowId: flow.id,
|
|
63555
64331
|
flowName: flow.name,
|
|
63556
64332
|
scenarioLabel: `Failure: ${precondition.description} not met`,
|
|
64333
|
+
kind: "negative",
|
|
63557
64334
|
description: `Negative scenario: ${precondition.description} precondition violation at ${failNode.nodeName}`,
|
|
63558
64335
|
given: `A ${(flow.moments[0]?.name ?? "").toLowerCase()} scenario is initiated`,
|
|
63559
64336
|
when: `${failNode.nodeName} is invoked without satisfying ${precondition.name}`,
|
|
63560
64337
|
then: `The command ${failNode.nodeName} is rejected`,
|
|
63561
64338
|
expectedPath: precedingNodes.map((n) => n.nodeId),
|
|
63562
|
-
activeBranches
|
|
64339
|
+
activeBranches,
|
|
63563
64340
|
events: allEvents
|
|
63564
64341
|
};
|
|
63565
64342
|
}
|
|
@@ -63582,6 +64359,111 @@ function buildFailureEvent(failNode, precondition, precedingEvents, opts) {
|
|
|
63582
64359
|
}
|
|
63583
64360
|
};
|
|
63584
64361
|
}
|
|
64362
|
+
function deriveTimeoutScenarios(ir, flow, options) {
|
|
64363
|
+
const opts = resolveOptions(flow, options);
|
|
64364
|
+
const contextMap = buildContextMap(ir);
|
|
64365
|
+
const scenarios = [];
|
|
64366
|
+
for (const saga of collectSagas(ir)) {
|
|
64367
|
+
if (saga.timeout === "none" || saga.timeout === "")
|
|
64368
|
+
continue;
|
|
64369
|
+
if (saga.states.length === 0)
|
|
64370
|
+
continue;
|
|
64371
|
+
const owner = ir.flows.find((f) => flowContainsNodeName(f, saga.trigger)) ?? ir.flows[0];
|
|
64372
|
+
if (!owner || owner.id !== flow.id)
|
|
64373
|
+
continue;
|
|
64374
|
+
const scenario = buildTimeoutScenario(flow, saga, contextMap, opts);
|
|
64375
|
+
if (scenario)
|
|
64376
|
+
scenarios.push(scenario);
|
|
64377
|
+
}
|
|
64378
|
+
return scenarios;
|
|
64379
|
+
}
|
|
64380
|
+
function flowContainsNodeName(flow, nodeName) {
|
|
64381
|
+
for (const moment of flow.moments) {
|
|
64382
|
+
if (moment.contextEntries.some((e) => e.nodeName === nodeName))
|
|
64383
|
+
return true;
|
|
64384
|
+
for (const branch of moment.branches ?? []) {
|
|
64385
|
+
if (branch.entries.some((e) => e.nodeName === nodeName))
|
|
64386
|
+
return true;
|
|
64387
|
+
}
|
|
64388
|
+
}
|
|
64389
|
+
return false;
|
|
64390
|
+
}
|
|
64391
|
+
function buildTimeoutScenario(flow, saga, contextMap, opts) {
|
|
64392
|
+
const walk = walkPath(flow, {});
|
|
64393
|
+
const triggerIdx = walk.nodes.findIndex((n) => n.nodeName === saga.trigger);
|
|
64394
|
+
if (triggerIdx === -1)
|
|
64395
|
+
return null;
|
|
64396
|
+
const nodes = truncateAfterTriggerMoment(walk.nodes, triggerIdx);
|
|
64397
|
+
const pathEvents = generateEvents(nodes, flow, contextMap, opts.sessionId, opts.correlationId, opts.baseTime);
|
|
64398
|
+
const events = appendTimeoutMarkers(pathEvents, saga, triggerIdx, opts);
|
|
64399
|
+
const activeBranches = collectTruncatedActiveBranches(walk.activations, nodes);
|
|
64400
|
+
const hasCompensation = saga.compensation !== "none" && saga.compensation !== "";
|
|
64401
|
+
const lastMomentName = nodes[nodes.length - 1]?.momentName ?? flow.name;
|
|
64402
|
+
return {
|
|
64403
|
+
scenarioId: `${opts.scenarioId}-timeout-${saga.name}`,
|
|
64404
|
+
flowId: flow.id,
|
|
64405
|
+
flowName: flow.name,
|
|
64406
|
+
scenarioLabel: `Timeout: ${flow.name} [${saga.name}.${saga.timeout}]`,
|
|
64407
|
+
kind: "timeout",
|
|
64408
|
+
description: `Timeout scenario: saga ${saga.name} timeout ${saga.timeout} elapses after ${saga.trigger}; the domain flow stops at ${lastMomentName}`,
|
|
64409
|
+
given: `A ${(flow.moments[0]?.name ?? "").toLowerCase()} scenario is initiated`,
|
|
64410
|
+
when: `Saga ${saga.name} timeout ${saga.timeout} elapses after ${saga.trigger}`,
|
|
64411
|
+
then: hasCompensation ? `Saga ${saga.name} times out and compensates: ${saga.compensation}` : `Saga ${saga.name} times out`,
|
|
64412
|
+
expectedPath: nodes.map((n) => n.nodeId),
|
|
64413
|
+
activeBranches,
|
|
64414
|
+
events
|
|
64415
|
+
};
|
|
64416
|
+
}
|
|
64417
|
+
function truncateAfterTriggerMoment(walkNodes, triggerIdx) {
|
|
64418
|
+
let cut = triggerIdx;
|
|
64419
|
+
while (cut + 1 < walkNodes.length && walkNodes[cut + 1].momentId === walkNodes[triggerIdx].momentId) {
|
|
64420
|
+
cut++;
|
|
64421
|
+
}
|
|
64422
|
+
return walkNodes.slice(0, cut + 1);
|
|
64423
|
+
}
|
|
64424
|
+
function collectTruncatedActiveBranches(activations, nodes) {
|
|
64425
|
+
const includedMoments = new Set(nodes.map((n) => n.momentName));
|
|
64426
|
+
const seenActivations = /* @__PURE__ */ new Set();
|
|
64427
|
+
const activeBranches = [];
|
|
64428
|
+
for (const a of activations) {
|
|
64429
|
+
if (!includedMoments.has(a.momentName))
|
|
64430
|
+
continue;
|
|
64431
|
+
const key = `${a.momentName} ${a.condition}`;
|
|
64432
|
+
if (seenActivations.has(key))
|
|
64433
|
+
continue;
|
|
64434
|
+
seenActivations.add(key);
|
|
64435
|
+
activeBranches.push({ momentName: a.momentName, condition: a.condition, routeChosen: a.condition });
|
|
64436
|
+
}
|
|
64437
|
+
return activeBranches;
|
|
64438
|
+
}
|
|
64439
|
+
function appendTimeoutMarkers(pathEvents, saga, triggerIdx, opts) {
|
|
64440
|
+
const lastPathTime = pathEvents.length > 0 ? new Date(pathEvents[pathEvents.length - 1].timestamp).getTime() : opts.baseTime.getTime();
|
|
64441
|
+
const markers = [];
|
|
64442
|
+
const push = (eventType, payload, causeEventId) => {
|
|
64443
|
+
const counter = pathEvents.length + markers.length + 1;
|
|
64444
|
+
const marker = {
|
|
64445
|
+
eventId: `evt-${String(counter).padStart(3, "0")}`,
|
|
64446
|
+
eventType,
|
|
64447
|
+
productSource: "moment:simulation",
|
|
64448
|
+
sessionId: opts.sessionId,
|
|
64449
|
+
causationEventIds: causeEventId ? [causeEventId] : [],
|
|
64450
|
+
correlationId: opts.correlationId,
|
|
64451
|
+
timestamp: new Date(lastPathTime + (markers.length + 1) * 1e3).toISOString(),
|
|
64452
|
+
version: 1,
|
|
64453
|
+
payload
|
|
64454
|
+
};
|
|
64455
|
+
markers.push(marker);
|
|
64456
|
+
return marker;
|
|
64457
|
+
};
|
|
64458
|
+
const triggerEvent = pathEvents[triggerIdx];
|
|
64459
|
+
const initialState = saga.states[0];
|
|
64460
|
+
const initial = push(`SimSaga.${saga.name}.${initialState}`, { sagaName: saga.name, state: initialState, triggeredBy: triggerEvent?.eventType ?? saga.trigger }, triggerEvent?.eventId);
|
|
64461
|
+
const timedOut = push(`SimSaga.${saga.name}.TimedOut`, { timeoutName: saga.timeout }, initial.eventId);
|
|
64462
|
+
if (saga.compensation !== "none" && saga.compensation !== "") {
|
|
64463
|
+
push(`SimSaga.${saga.name}.Compensated`, { description: saga.compensation }, timedOut.eventId);
|
|
64464
|
+
}
|
|
64465
|
+
return [...pathEvents, ...markers];
|
|
64466
|
+
}
|
|
63585
64467
|
function findCommand(ctx, name) {
|
|
63586
64468
|
const topLevel = ctx.commands.find((c) => c.name === name);
|
|
63587
64469
|
if (topLevel)
|
|
@@ -63632,6 +64514,30 @@ function buildThenClause(flow, nodes, contextNames) {
|
|
|
63632
64514
|
return `The flow completes at ${lastNode?.momentName ?? "end"} across ${contextNames.join(", ")}`;
|
|
63633
64515
|
}
|
|
63634
64516
|
|
|
64517
|
+
// ../derive/dist/engine/policy-definitions-generator.js
|
|
64518
|
+
function generatePolicyDefinitions(ir) {
|
|
64519
|
+
const definitions = [];
|
|
64520
|
+
for (const context of ir.contexts) {
|
|
64521
|
+
for (const policy of context.policies) {
|
|
64522
|
+
definitions.push({
|
|
64523
|
+
name: policy.name,
|
|
64524
|
+
contextId: context.id,
|
|
64525
|
+
trigger: policy.trigger,
|
|
64526
|
+
...policy.action ? { actionDescription: policy.action } : {},
|
|
64527
|
+
chainsTo: normalizeChainsTo(policy.chainsTo)
|
|
64528
|
+
});
|
|
64529
|
+
}
|
|
64530
|
+
}
|
|
64531
|
+
return definitions;
|
|
64532
|
+
}
|
|
64533
|
+
function normalizeChainsTo(chainsTo) {
|
|
64534
|
+
if (chainsTo === void 0 || chainsTo === null)
|
|
64535
|
+
return [];
|
|
64536
|
+
if (Array.isArray(chainsTo))
|
|
64537
|
+
return chainsTo.filter((c) => typeof c === "string");
|
|
64538
|
+
return [chainsTo];
|
|
64539
|
+
}
|
|
64540
|
+
|
|
63635
64541
|
// ../derive/dist/engine/event-catalog-generator.js
|
|
63636
64542
|
function generateEventCatalog(ir) {
|
|
63637
64543
|
const entries = [];
|
|
@@ -63643,6 +64549,7 @@ function generateEventCatalog(ir) {
|
|
|
63643
64549
|
}
|
|
63644
64550
|
}
|
|
63645
64551
|
}
|
|
64552
|
+
addFlowFallbackEntries(ir, entries);
|
|
63646
64553
|
return {
|
|
63647
64554
|
events: entries,
|
|
63648
64555
|
metadata: {
|
|
@@ -63651,12 +64558,94 @@ function generateEventCatalog(ir) {
|
|
|
63651
64558
|
}
|
|
63652
64559
|
};
|
|
63653
64560
|
}
|
|
64561
|
+
function allMomentEntries(flow) {
|
|
64562
|
+
const out = [];
|
|
64563
|
+
for (let i = 0; i < flow.moments.length; i++) {
|
|
64564
|
+
const moment = flow.moments[i];
|
|
64565
|
+
for (const entry of entriesInSequenceOrder(moment)) {
|
|
64566
|
+
out.push({ entry, momentName: moment.name, momentIndex: i });
|
|
64567
|
+
}
|
|
64568
|
+
}
|
|
64569
|
+
return out;
|
|
64570
|
+
}
|
|
64571
|
+
function entriesInSequenceOrder(moment) {
|
|
64572
|
+
const entries = [];
|
|
64573
|
+
for (const child of orderedMomentChildren(moment, "entries-first")) {
|
|
64574
|
+
if (child.kind === "entry") {
|
|
64575
|
+
entries.push(child.entry);
|
|
64576
|
+
} else {
|
|
64577
|
+
entries.push(...child.branch.entries);
|
|
64578
|
+
}
|
|
64579
|
+
}
|
|
64580
|
+
return entries;
|
|
64581
|
+
}
|
|
64582
|
+
function contextDisplayName(contextId, ir) {
|
|
64583
|
+
const ctx = ir.contexts.find((c) => c.id === contextId);
|
|
64584
|
+
return ctx?.name ?? contextId.replace(/^ctx-/, "");
|
|
64585
|
+
}
|
|
64586
|
+
function addFlowFallbackEntries(ir, entries) {
|
|
64587
|
+
const known = new Set(entries.map((e) => e.eventName));
|
|
64588
|
+
for (const flow of ir.flows) {
|
|
64589
|
+
for (const { entry, momentName, momentIndex } of allMomentEntries(flow)) {
|
|
64590
|
+
if (known.has(entry.nodeName))
|
|
64591
|
+
continue;
|
|
64592
|
+
known.add(entry.nodeName);
|
|
64593
|
+
entries.push(buildFlowEntry(entry, momentName, momentIndex, ir));
|
|
64594
|
+
}
|
|
64595
|
+
}
|
|
64596
|
+
}
|
|
64597
|
+
function buildFlowEntry(entry, momentName, momentIndex, ir) {
|
|
64598
|
+
const contractFields = [];
|
|
64599
|
+
const consumers = [];
|
|
64600
|
+
const seenConsumers = /* @__PURE__ */ new Set();
|
|
64601
|
+
let producerCommand = "";
|
|
64602
|
+
for (const flow of ir.flows) {
|
|
64603
|
+
for (const conn of flow.connections) {
|
|
64604
|
+
const connEventName = conn.eventId.replace(/^evt-/, "");
|
|
64605
|
+
if (conn.connectionType === "crosses-to" && connEventName === entry.nodeName) {
|
|
64606
|
+
recordCrossingConsumer(conn, ir, contractFields, consumers, seenConsumers);
|
|
64607
|
+
}
|
|
64608
|
+
if (conn.connectionType === "triggers" && conn.targetNodeName === entry.nodeName && conn.sourceNodeName && producerCommand === "") {
|
|
64609
|
+
producerCommand = conn.sourceNodeName;
|
|
64610
|
+
}
|
|
64611
|
+
}
|
|
64612
|
+
}
|
|
64613
|
+
return {
|
|
64614
|
+
eventName: entry.nodeName,
|
|
64615
|
+
kind: entry.nodeKind,
|
|
64616
|
+
schema: { fields: contractFields },
|
|
64617
|
+
producer: {
|
|
64618
|
+
context: contextDisplayName(entry.contextId, ir),
|
|
64619
|
+
aggregate: "",
|
|
64620
|
+
command: producerCommand
|
|
64621
|
+
},
|
|
64622
|
+
consumers,
|
|
64623
|
+
temporalLocation: { moment: momentName, momentIndex }
|
|
64624
|
+
};
|
|
64625
|
+
}
|
|
64626
|
+
function recordCrossingConsumer(conn, ir, contractFields, consumers, seenConsumers) {
|
|
64627
|
+
if (contractFields.length === 0) {
|
|
64628
|
+
for (const f of conn.schemaContract.fields) {
|
|
64629
|
+
contractFields.push({ name: f.name, type: f.type, isArray: false });
|
|
64630
|
+
}
|
|
64631
|
+
}
|
|
64632
|
+
const consumerName = contextDisplayName(conn.targetContextId, ir);
|
|
64633
|
+
const key = `${consumerName}|${conn.schemaContract.relationshipType}`;
|
|
64634
|
+
if (!seenConsumers.has(key)) {
|
|
64635
|
+
seenConsumers.add(key);
|
|
64636
|
+
consumers.push({
|
|
64637
|
+
context: consumerName,
|
|
64638
|
+
relationshipType: conn.schemaContract.relationshipType
|
|
64639
|
+
});
|
|
64640
|
+
}
|
|
64641
|
+
}
|
|
63654
64642
|
function buildCatalogEntry(event, aggregate, context, ir) {
|
|
63655
64643
|
const producer = findProducerCommand(event, aggregate, context);
|
|
63656
64644
|
const consumers = findConsumers(event, ir);
|
|
63657
64645
|
const temporalLocation = findTemporalLocation(event, ir);
|
|
63658
64646
|
return {
|
|
63659
64647
|
eventName: event.name,
|
|
64648
|
+
kind: "event",
|
|
63660
64649
|
schema: {
|
|
63661
64650
|
fields: event.fields.map((f) => ({
|
|
63662
64651
|
name: f.name,
|
|
@@ -63690,13 +64679,14 @@ function findConsumers(event, ir) {
|
|
|
63690
64679
|
const targetCtx = ir.contexts.find((c) => c.id === conn.targetContextId);
|
|
63691
64680
|
if (!targetCtx)
|
|
63692
64681
|
continue;
|
|
63693
|
-
const
|
|
64682
|
+
const relationshipType = conn.schemaContract.relationshipType;
|
|
64683
|
+
const key = `${targetCtx.name}|${relationshipType}`;
|
|
63694
64684
|
if (seen.has(key))
|
|
63695
64685
|
continue;
|
|
63696
64686
|
seen.add(key);
|
|
63697
64687
|
consumers.push({
|
|
63698
64688
|
context: targetCtx.name,
|
|
63699
|
-
relationshipType
|
|
64689
|
+
relationshipType
|
|
63700
64690
|
});
|
|
63701
64691
|
}
|
|
63702
64692
|
}
|
|
@@ -63706,7 +64696,7 @@ function findTemporalLocation(event, ir) {
|
|
|
63706
64696
|
for (const flow of ir.flows) {
|
|
63707
64697
|
for (let i = 0; i < flow.moments.length; i++) {
|
|
63708
64698
|
const moment = flow.moments[i];
|
|
63709
|
-
for (const entry of moment
|
|
64699
|
+
for (const entry of entriesInSequenceOrder(moment)) {
|
|
63710
64700
|
if (entry.nodeKind === "event" && entry.nodeName === event.name) {
|
|
63711
64701
|
return { moment: moment.name, momentIndex: i };
|
|
63712
64702
|
}
|
|
@@ -63730,9 +64720,10 @@ function generateImpactAnalysis(ir) {
|
|
|
63730
64720
|
for (const context of ir.contexts) {
|
|
63731
64721
|
addCommandNodes(context, nodeMap);
|
|
63732
64722
|
addEventNodes(context, nodeMap);
|
|
63733
|
-
addPolicyNodes(context, nodeMap);
|
|
63734
|
-
addSagaNodes(context, nodeMap);
|
|
64723
|
+
addPolicyNodes(context, nodeMap, ir);
|
|
64724
|
+
addSagaNodes(context, nodeMap, ir);
|
|
63735
64725
|
}
|
|
64726
|
+
addFlowNodes(ir, nodeMap);
|
|
63736
64727
|
addCrossingNodes(ir, nodeMap);
|
|
63737
64728
|
const nodes = Array.from(nodeMap.values()).map((n) => ({
|
|
63738
64729
|
type: n.type,
|
|
@@ -63777,59 +64768,145 @@ function addEventNodes(context, nodeMap) {
|
|
|
63777
64768
|
}
|
|
63778
64769
|
}
|
|
63779
64770
|
}
|
|
63780
|
-
function
|
|
64771
|
+
function findDeclaringContextForEvent(eventName, ir) {
|
|
64772
|
+
for (const ctx of ir.contexts) {
|
|
64773
|
+
if (ctx.events.some((e) => e.name === eventName))
|
|
64774
|
+
return ctx;
|
|
64775
|
+
for (const agg of ctx.aggregates) {
|
|
64776
|
+
if (agg.events.some((e) => e.name === eventName))
|
|
64777
|
+
return ctx;
|
|
64778
|
+
}
|
|
64779
|
+
}
|
|
64780
|
+
return void 0;
|
|
64781
|
+
}
|
|
64782
|
+
function findDeclaringContextForCommand(commandName, ir) {
|
|
64783
|
+
for (const ctx of ir.contexts) {
|
|
64784
|
+
if (ctx.commands.some((c) => c.name === commandName))
|
|
64785
|
+
return ctx;
|
|
64786
|
+
for (const agg of ctx.aggregates) {
|
|
64787
|
+
if (agg.commands.some((c) => c.name === commandName))
|
|
64788
|
+
return ctx;
|
|
64789
|
+
}
|
|
64790
|
+
}
|
|
64791
|
+
return void 0;
|
|
64792
|
+
}
|
|
64793
|
+
function addPolicyNodes(context, nodeMap, ir) {
|
|
63781
64794
|
for (const policy of context.policies) {
|
|
63782
64795
|
const policyNode = getOrCreate(nodeMap, "policy", policy.name, context.name);
|
|
63783
64796
|
if (policy.trigger) {
|
|
63784
|
-
const
|
|
63785
|
-
|
|
64797
|
+
const evtCtxName = (findDeclaringContextForEvent(policy.trigger, ir) ?? context).name;
|
|
64798
|
+
const evtNode = getOrCreate(nodeMap, "event", policy.trigger, evtCtxName);
|
|
64799
|
+
policyNode.dependsOn.push(nodeKey("event", policy.trigger, evtCtxName));
|
|
63786
64800
|
evtNode.triggers.push(nodeKey("policy", policy.name, context.name));
|
|
63787
64801
|
}
|
|
63788
64802
|
if (policy.chainsTo) {
|
|
63789
|
-
const
|
|
63790
|
-
|
|
64803
|
+
const cmdCtxName = (findDeclaringContextForCommand(policy.chainsTo, ir) ?? context).name;
|
|
64804
|
+
const cmdNode = getOrCreate(nodeMap, "command", policy.chainsTo, cmdCtxName);
|
|
64805
|
+
policyNode.triggers.push(nodeKey("command", policy.chainsTo, cmdCtxName));
|
|
63791
64806
|
cmdNode.dependsOn.push(nodeKey("policy", policy.name, context.name));
|
|
63792
64807
|
}
|
|
63793
64808
|
}
|
|
63794
64809
|
}
|
|
63795
|
-
function addSagaNodes(context, nodeMap) {
|
|
64810
|
+
function addSagaNodes(context, nodeMap, ir) {
|
|
63796
64811
|
for (const saga of context.sagas) {
|
|
63797
64812
|
const sagaNode = getOrCreate(nodeMap, "saga", saga.name, context.name);
|
|
63798
64813
|
if (saga.trigger) {
|
|
63799
|
-
const
|
|
63800
|
-
|
|
64814
|
+
const evtCtxName = (findDeclaringContextForEvent(saga.trigger, ir) ?? context).name;
|
|
64815
|
+
const evtNode = getOrCreate(nodeMap, "event", saga.trigger, evtCtxName);
|
|
64816
|
+
sagaNode.dependsOn.push(nodeKey("event", saga.trigger, evtCtxName));
|
|
63801
64817
|
evtNode.triggers.push(nodeKey("saga", saga.name, context.name));
|
|
63802
64818
|
}
|
|
63803
64819
|
}
|
|
63804
64820
|
}
|
|
64821
|
+
function contextDisplayName2(contextId, ir) {
|
|
64822
|
+
const ctx = ir.contexts.find((c) => c.id === contextId);
|
|
64823
|
+
return ctx?.name ?? contextId.replace(/^ctx-/, "");
|
|
64824
|
+
}
|
|
64825
|
+
function addFlowNodes(ir, nodeMap) {
|
|
64826
|
+
for (const flow of ir.flows) {
|
|
64827
|
+
addFlowMomentNodes(flow, nodeMap, ir);
|
|
64828
|
+
addFlowTriggerEdges(flow, nodeMap);
|
|
64829
|
+
}
|
|
64830
|
+
}
|
|
64831
|
+
function addFlowMomentNodes(flow, nodeMap, ir) {
|
|
64832
|
+
for (const moment of flow.moments) {
|
|
64833
|
+
const entries = [
|
|
64834
|
+
...moment.contextEntries,
|
|
64835
|
+
...(moment.branches ?? []).flatMap((b) => b.entries)
|
|
64836
|
+
];
|
|
64837
|
+
for (const entry of entries) {
|
|
64838
|
+
getOrCreate(nodeMap, entry.nodeKind, entry.nodeName, contextDisplayName2(entry.contextId, ir));
|
|
64839
|
+
}
|
|
64840
|
+
}
|
|
64841
|
+
}
|
|
64842
|
+
function addFlowTriggerEdges(flow, nodeMap) {
|
|
64843
|
+
for (const conn of flow.connections) {
|
|
64844
|
+
if (conn.connectionType !== "triggers" && conn.connectionType !== "triggered-by")
|
|
64845
|
+
continue;
|
|
64846
|
+
if (!conn.sourceNodeName || !conn.targetNodeName)
|
|
64847
|
+
continue;
|
|
64848
|
+
const cause = findNodeByName(nodeMap, conn.sourceNodeName);
|
|
64849
|
+
const effect = findNodeByName(nodeMap, conn.targetNodeName);
|
|
64850
|
+
if (!cause || !effect)
|
|
64851
|
+
continue;
|
|
64852
|
+
const causeKey = nodeKey(cause.type, cause.name, cause.context);
|
|
64853
|
+
const effectKey = nodeKey(effect.type, effect.name, effect.context);
|
|
64854
|
+
if (!cause.triggers.includes(effectKey))
|
|
64855
|
+
cause.triggers.push(effectKey);
|
|
64856
|
+
if (!effect.dependsOn.includes(causeKey))
|
|
64857
|
+
effect.dependsOn.push(causeKey);
|
|
64858
|
+
}
|
|
64859
|
+
}
|
|
64860
|
+
function findNodeByName(nodeMap, name) {
|
|
64861
|
+
for (const node of nodeMap.values()) {
|
|
64862
|
+
if (node.name === name)
|
|
64863
|
+
return node;
|
|
64864
|
+
}
|
|
64865
|
+
return void 0;
|
|
64866
|
+
}
|
|
63805
64867
|
function addCrossingNodes(ir, nodeMap) {
|
|
63806
64868
|
for (const flow of ir.flows) {
|
|
63807
64869
|
for (const conn of flow.connections) {
|
|
63808
64870
|
if (conn.connectionType !== "crosses-to")
|
|
63809
64871
|
continue;
|
|
63810
|
-
|
|
63811
|
-
const targetCtx = ir.contexts.find((c) => c.id === conn.targetContextId);
|
|
63812
|
-
if (!sourceCtx || !targetCtx)
|
|
63813
|
-
continue;
|
|
63814
|
-
const eventName = resolveEventName(conn.eventId, ir);
|
|
63815
|
-
if (!eventName)
|
|
63816
|
-
continue;
|
|
63817
|
-
const crossingName = `${eventName}->${targetCtx.name}`;
|
|
63818
|
-
const crossingNode = getOrCreate(nodeMap, "crossing", crossingName, sourceCtx.name);
|
|
63819
|
-
const evtKey = nodeKey("event", eventName, sourceCtx.name);
|
|
63820
|
-
if (!crossingNode.dependsOn.includes(evtKey)) {
|
|
63821
|
-
crossingNode.dependsOn.push(evtKey);
|
|
63822
|
-
}
|
|
63823
|
-
const evtNode = nodeMap.get(evtKey);
|
|
63824
|
-
if (evtNode) {
|
|
63825
|
-
const crossKey = nodeKey("crossing", crossingName, sourceCtx.name);
|
|
63826
|
-
if (!evtNode.triggers.includes(crossKey)) {
|
|
63827
|
-
evtNode.triggers.push(crossKey);
|
|
63828
|
-
}
|
|
63829
|
-
}
|
|
64872
|
+
addCrossingNode(conn, flow, nodeMap, ir);
|
|
63830
64873
|
}
|
|
63831
64874
|
}
|
|
63832
64875
|
}
|
|
64876
|
+
function addCrossingNode(conn, flow, nodeMap, ir) {
|
|
64877
|
+
const eventName = resolveEventName(conn.eventId, ir) ?? conn.schemaContract.eventType;
|
|
64878
|
+
if (!eventName)
|
|
64879
|
+
return;
|
|
64880
|
+
const sourceCtx = findSourceContextForEvent(conn.eventId, ir);
|
|
64881
|
+
const sourceCtxName = sourceCtx?.name ?? findProducingEntryContext(eventName, conn.sourceMomentId, flow, ir);
|
|
64882
|
+
if (!sourceCtxName)
|
|
64883
|
+
return;
|
|
64884
|
+
const targetCtxName = contextDisplayName2(conn.targetContextId, ir);
|
|
64885
|
+
const crossingName = `${eventName}->${targetCtxName}`;
|
|
64886
|
+
const crossingNode = getOrCreate(nodeMap, "crossing", crossingName, sourceCtxName);
|
|
64887
|
+
const evtKey = nodeKey("event", eventName, sourceCtxName);
|
|
64888
|
+
if (!crossingNode.dependsOn.includes(evtKey)) {
|
|
64889
|
+
crossingNode.dependsOn.push(evtKey);
|
|
64890
|
+
}
|
|
64891
|
+
const evtNode = nodeMap.get(evtKey);
|
|
64892
|
+
if (evtNode) {
|
|
64893
|
+
const crossKey = nodeKey("crossing", crossingName, sourceCtxName);
|
|
64894
|
+
if (!evtNode.triggers.includes(crossKey)) {
|
|
64895
|
+
evtNode.triggers.push(crossKey);
|
|
64896
|
+
}
|
|
64897
|
+
}
|
|
64898
|
+
}
|
|
64899
|
+
function findProducingEntryContext(eventName, sourceMomentId, flow, ir) {
|
|
64900
|
+
const moment = flow.moments.find((m) => m.id === sourceMomentId);
|
|
64901
|
+
if (!moment)
|
|
64902
|
+
return void 0;
|
|
64903
|
+
const entries = [
|
|
64904
|
+
...moment.contextEntries,
|
|
64905
|
+
...(moment.branches ?? []).flatMap((b) => b.entries)
|
|
64906
|
+
];
|
|
64907
|
+
const producing = entries.find((e) => e.nodeName === eventName);
|
|
64908
|
+
return producing ? contextDisplayName2(producing.contextId, ir) : void 0;
|
|
64909
|
+
}
|
|
63833
64910
|
function findSourceContextForEvent(eventId, ir) {
|
|
63834
64911
|
for (const ctx of ir.contexts) {
|
|
63835
64912
|
if (ctx.events.some((e) => e.id === eventId))
|
|
@@ -63873,9 +64950,8 @@ function buildStateMachine(saga, contextName) {
|
|
|
63873
64950
|
const initialState = sagaStates.length > 0 ? sagaStates[0] : "";
|
|
63874
64951
|
const finalState = sagaStates.length > 0 ? sagaStates[sagaStates.length - 1] : "";
|
|
63875
64952
|
const states = buildStates(sagaStates, initialState, finalState);
|
|
63876
|
-
const transitions = buildTransitions(
|
|
64953
|
+
const transitions = buildTransitions(saga);
|
|
63877
64954
|
const reachability = computeReachability(states, transitions, initialState);
|
|
63878
|
-
const earlyExitStates = sagaStates.filter((s) => s !== initialState && s !== finalState);
|
|
63879
64955
|
return {
|
|
63880
64956
|
sagaName: saga.name,
|
|
63881
64957
|
context: contextName,
|
|
@@ -63885,7 +64961,6 @@ function buildStateMachine(saga, contextName) {
|
|
|
63885
64961
|
transitions,
|
|
63886
64962
|
compensation: saga.compensation,
|
|
63887
64963
|
timeout: saga.timeout,
|
|
63888
|
-
earlyExitStates,
|
|
63889
64964
|
reachability
|
|
63890
64965
|
};
|
|
63891
64966
|
}
|
|
@@ -63896,7 +64971,15 @@ function buildStates(stateNames, initialState, finalState) {
|
|
|
63896
64971
|
isFinal: name === finalState
|
|
63897
64972
|
}));
|
|
63898
64973
|
}
|
|
63899
|
-
function buildTransitions(
|
|
64974
|
+
function buildTransitions(saga) {
|
|
64975
|
+
if (saga.transitions) {
|
|
64976
|
+
return saga.transitions.map((t) => ({
|
|
64977
|
+
from: t.from,
|
|
64978
|
+
to: t.to,
|
|
64979
|
+
...t.onEvent !== void 0 ? { onEvent: t.onEvent } : {}
|
|
64980
|
+
}));
|
|
64981
|
+
}
|
|
64982
|
+
const stateNames = saga.states;
|
|
63900
64983
|
const transitions = [];
|
|
63901
64984
|
for (let i = 0; i < stateNames.length - 1; i++) {
|
|
63902
64985
|
transitions.push({
|
|
@@ -63977,15 +65060,14 @@ function buildFrames(flow, ctxMap, laneIndex) {
|
|
|
63977
65060
|
}
|
|
63978
65061
|
function buildFrameNodes(moment, ctxMap, laneIndex) {
|
|
63979
65062
|
const nodes = [];
|
|
63980
|
-
|
|
63981
|
-
|
|
63982
|
-
|
|
63983
|
-
|
|
63984
|
-
|
|
63985
|
-
|
|
63986
|
-
|
|
65063
|
+
for (const child of orderedMomentChildren(moment, "entries-first")) {
|
|
65064
|
+
if (child.kind === "entry") {
|
|
65065
|
+
nodes.push(entryToNode2(child.entry, moment, ctxMap, laneIndex, "main"));
|
|
65066
|
+
} else {
|
|
65067
|
+
for (const entry of child.branch.entries) {
|
|
65068
|
+
nodes.push(entryToNode2(entry, moment, ctxMap, laneIndex, `br${child.branchIndex}`));
|
|
65069
|
+
}
|
|
63987
65070
|
}
|
|
63988
|
-
branchIdx++;
|
|
63989
65071
|
}
|
|
63990
65072
|
return nodes;
|
|
63991
65073
|
}
|
|
@@ -64031,15 +65113,43 @@ function findAggregate(nodeName, ctx) {
|
|
|
64031
65113
|
}
|
|
64032
65114
|
function buildConnections(flow) {
|
|
64033
65115
|
return flow.connections.map((conn) => {
|
|
65116
|
+
const eventType = conn.eventId.replace(/^evt-/, "");
|
|
65117
|
+
const endpoints = {
|
|
65118
|
+
eventType,
|
|
65119
|
+
sourceNodeName: conn.sourceNodeName,
|
|
65120
|
+
targetNodeName: conn.targetNodeName
|
|
65121
|
+
};
|
|
65122
|
+
if (conn.connectionType === "returns-to") {
|
|
65123
|
+
if (conn.targetMomentId) {
|
|
65124
|
+
return {
|
|
65125
|
+
from: conn.sourceMomentId,
|
|
65126
|
+
to: conn.targetMomentId,
|
|
65127
|
+
style: "return",
|
|
65128
|
+
targetMomentLabel: conn.targetMomentLabel,
|
|
65129
|
+
...endpoints
|
|
65130
|
+
};
|
|
65131
|
+
}
|
|
65132
|
+
return {
|
|
65133
|
+
from: conn.sourceMomentId,
|
|
65134
|
+
to: conn.targetContextId,
|
|
65135
|
+
label: `unresolved returns-to target: ${conn.targetMomentLabel ?? "(unknown)"}`,
|
|
65136
|
+
style: "return",
|
|
65137
|
+
targetMomentLabel: conn.targetMomentLabel,
|
|
65138
|
+
...endpoints
|
|
65139
|
+
};
|
|
65140
|
+
}
|
|
64034
65141
|
const isCrossing2 = conn.connectionType === "crosses-to";
|
|
64035
65142
|
return {
|
|
64036
65143
|
from: conn.sourceMomentId,
|
|
65144
|
+
// For 'triggers' the core now resolves targetContextId to the context
|
|
65145
|
+
// where the TARGET node is placed (not the source's own lane).
|
|
64037
65146
|
to: conn.targetContextId,
|
|
64038
|
-
label: isCrossing2 ?
|
|
65147
|
+
label: isCrossing2 ? eventType : void 0,
|
|
64039
65148
|
style: mapConnectionStyle(conn),
|
|
64040
65149
|
crossBoundary: isCrossing2 || void 0,
|
|
64041
65150
|
relationship: isCrossing2 ? conn.schemaContract.relationshipType : void 0,
|
|
64042
|
-
schemaContract: isCrossing2 ? mapSchemaContract(conn) : void 0
|
|
65151
|
+
schemaContract: isCrossing2 ? mapSchemaContract(conn) : void 0,
|
|
65152
|
+
...endpoints
|
|
64043
65153
|
};
|
|
64044
65154
|
});
|
|
64045
65155
|
}
|
|
@@ -64069,7 +65179,6 @@ function mapSchemaContract(conn) {
|
|
|
64069
65179
|
function buildEventRouting(flow, ctxMap, laneIndex) {
|
|
64070
65180
|
const routing = {};
|
|
64071
65181
|
for (const moment of flow.moments) {
|
|
64072
|
-
let branchIdx = 0;
|
|
64073
65182
|
const addEntry = (entry, scope) => {
|
|
64074
65183
|
const ctx = ctxMap.get(entry.contextId);
|
|
64075
65184
|
const kind = resolveNodeKind2(entry, ctx);
|
|
@@ -64088,14 +65197,14 @@ function buildEventRouting(flow, ctxMap, laneIndex) {
|
|
|
64088
65197
|
routing[key] = existing;
|
|
64089
65198
|
}
|
|
64090
65199
|
};
|
|
64091
|
-
for (const
|
|
64092
|
-
|
|
64093
|
-
|
|
64094
|
-
|
|
64095
|
-
|
|
64096
|
-
|
|
65200
|
+
for (const child of orderedMomentChildren(moment, "entries-first")) {
|
|
65201
|
+
if (child.kind === "entry") {
|
|
65202
|
+
addEntry(child.entry, "main");
|
|
65203
|
+
} else {
|
|
65204
|
+
for (const entry of child.branch.entries) {
|
|
65205
|
+
addEntry(entry, `br${child.branchIndex}`);
|
|
65206
|
+
}
|
|
64097
65207
|
}
|
|
64098
|
-
branchIdx++;
|
|
64099
65208
|
}
|
|
64100
65209
|
}
|
|
64101
65210
|
const result = {};
|
|
@@ -64111,8 +65220,7 @@ function buildBranchPredicates(flow) {
|
|
|
64111
65220
|
continue;
|
|
64112
65221
|
const routes = {};
|
|
64113
65222
|
for (const branch of moment.branches) {
|
|
64114
|
-
|
|
64115
|
-
routes[branch.condition] = hasTerminal ? "terminal" : "happy";
|
|
65223
|
+
routes[branch.condition] = branch.condition;
|
|
64116
65224
|
}
|
|
64117
65225
|
predicates[moment.id] = {
|
|
64118
65226
|
field: "outcome",
|
|
@@ -64124,7 +65232,8 @@ function buildBranchPredicates(flow) {
|
|
|
64124
65232
|
}
|
|
64125
65233
|
function buildContextMap2(flow, ctxMap) {
|
|
64126
65234
|
const contexts = buildBoundedContexts(flow, ctxMap);
|
|
64127
|
-
const
|
|
65235
|
+
const known = new Set(contexts.map((c) => c.contextId));
|
|
65236
|
+
const relationships = buildContextRelationships(flow).filter((r) => known.has(r.sourceContextId) && known.has(r.targetContextId));
|
|
64128
65237
|
return { contexts, relationships };
|
|
64129
65238
|
}
|
|
64130
65239
|
function buildBoundedContexts(flow, ctxMap) {
|
|
@@ -64176,8 +65285,7 @@ function collectContextIds2(flow) {
|
|
|
64176
65285
|
ids.add(entry.contextId);
|
|
64177
65286
|
for (const branch of moment.branches ?? []) {
|
|
64178
65287
|
for (const entry of branch.entries) {
|
|
64179
|
-
|
|
64180
|
-
ids.add(entry.contextId);
|
|
65288
|
+
ids.add(entry.contextId);
|
|
64181
65289
|
}
|
|
64182
65290
|
}
|
|
64183
65291
|
}
|
|
@@ -64213,6 +65321,7 @@ function renderFeatureHeader(lines, flow, ir) {
|
|
|
64213
65321
|
}
|
|
64214
65322
|
function renderMomentsByContext(lines, flow, ir, ctxMap) {
|
|
64215
65323
|
const contextGroups = groupMomentsByContext(flow);
|
|
65324
|
+
const ownedSagaIds = collectOwnedSagaIds(flow, ir);
|
|
64216
65325
|
for (const [ctxId, moments] of contextGroups) {
|
|
64217
65326
|
const ctx = ctxMap.get(ctxId);
|
|
64218
65327
|
const ctxName = ctx?.name ?? ctxId.replace(/^ctx-/, "");
|
|
@@ -64230,51 +65339,83 @@ function renderMomentsByContext(lines, flow, ir, ctxMap) {
|
|
|
64230
65339
|
renderScenario(lines, moment, moment.contextEntries, flow, ctxMap, ir, void 0, sharedPreconditions);
|
|
64231
65340
|
}
|
|
64232
65341
|
}
|
|
64233
|
-
renderSagaScenarios(lines, ctxId, ir);
|
|
65342
|
+
renderSagaScenarios(lines, ctxId, ir, ownedSagaIds);
|
|
64234
65343
|
}
|
|
65344
|
+
renderOrphanOwnedSagas(lines, ir, contextGroups, ownedSagaIds);
|
|
64235
65345
|
}
|
|
64236
65346
|
function renderScenario(lines, moment, entries, flow, ctxMap, ir, variant, sharedPreconditions = /* @__PURE__ */ new Set()) {
|
|
64237
65347
|
const label = variant ? `${moment.name} [${variant}]` : moment.name;
|
|
64238
|
-
const tags = buildScenarioTags(entries, flow, ctxMap, ir
|
|
65348
|
+
const tags = buildScenarioTags(entries, moment, void 0, flow, ctxMap, ir);
|
|
64239
65349
|
if (tags.length > 0)
|
|
64240
65350
|
lines.push(` ${tags.join(" ")}`);
|
|
64241
65351
|
lines.push(` Scenario: ${label}`);
|
|
64242
|
-
|
|
64243
|
-
|
|
65352
|
+
const steps = [];
|
|
65353
|
+
const usedConnections = /* @__PURE__ */ new Set();
|
|
65354
|
+
for (const entry of orderedMainEntries(moment)) {
|
|
65355
|
+
renderEntrySteps(steps, entry, moment, void 0, flow, ctxMap, sharedPreconditions, usedConnections);
|
|
64244
65356
|
}
|
|
65357
|
+
promoteLeadingAnd(steps);
|
|
65358
|
+
lines.push(...steps);
|
|
64245
65359
|
lines.push("");
|
|
64246
65360
|
}
|
|
64247
65361
|
function renderBranchScenario(lines, moment, condition, branchEntries, flow, ctxMap, ir, sharedPreconditions = /* @__PURE__ */ new Set()) {
|
|
64248
65362
|
const isTerminal = branchEntries.some((e) => e.terminal);
|
|
64249
65363
|
if (isTerminal) {
|
|
64250
|
-
renderTerminalBranchScenario(lines, moment, condition, flow, ctxMap, ir);
|
|
65364
|
+
renderTerminalBranchScenario(lines, moment, condition, branchEntries, flow, ctxMap, ir);
|
|
64251
65365
|
return;
|
|
64252
65366
|
}
|
|
64253
65367
|
const allEntries = [...moment.contextEntries, ...branchEntries];
|
|
64254
|
-
const tags = buildScenarioTags(allEntries, flow, ctxMap, ir
|
|
65368
|
+
const tags = buildScenarioTags(allEntries, moment, condition, flow, ctxMap, ir);
|
|
65369
|
+
const returnsTo = findReturnsTo(moment, condition, flow);
|
|
64255
65370
|
if (!tags.includes("@failure-path"))
|
|
64256
|
-
tags.push("@
|
|
65371
|
+
tags.push(returnsTo ? "@retry-path" : "@alt-path");
|
|
64257
65372
|
if (tags.length > 0)
|
|
64258
65373
|
lines.push(` ${tags.join(" ")}`);
|
|
64259
65374
|
lines.push(` Scenario: ${moment.name} [${condition}]`);
|
|
64260
|
-
|
|
64261
|
-
|
|
64262
|
-
|
|
65375
|
+
const steps = buildBranchScenarioSteps(moment, condition, branchEntries, flow, ctxMap, sharedPreconditions);
|
|
65376
|
+
if (returnsTo) {
|
|
65377
|
+
const targetLabel = resolveReturnsToLabel(returnsTo, flow);
|
|
65378
|
+
if (targetLabel)
|
|
65379
|
+
steps.push(` Then the flow returns to "${targetLabel}"`);
|
|
65380
|
+
}
|
|
65381
|
+
promoteLeadingAnd(steps);
|
|
65382
|
+
lines.push(...steps);
|
|
64263
65383
|
lines.push("");
|
|
64264
65384
|
}
|
|
64265
|
-
function
|
|
65385
|
+
function buildBranchScenarioSteps(moment, condition, branchEntries, flow, ctxMap, sharedPreconditions) {
|
|
65386
|
+
const steps = [];
|
|
65387
|
+
const usedConnections = /* @__PURE__ */ new Set();
|
|
65388
|
+
for (const child of orderedMomentChildren2(moment)) {
|
|
65389
|
+
if (child.kind === "entry") {
|
|
65390
|
+
renderEntrySteps(steps, child.entry, moment, void 0, flow, ctxMap, sharedPreconditions, usedConnections);
|
|
65391
|
+
} else if (child.branch.condition === condition && child.branch.entries === branchEntries) {
|
|
65392
|
+
for (const entry of child.branch.entries) {
|
|
65393
|
+
renderEntrySteps(steps, entry, moment, condition, flow, ctxMap, sharedPreconditions, usedConnections);
|
|
65394
|
+
}
|
|
65395
|
+
}
|
|
65396
|
+
}
|
|
65397
|
+
return steps;
|
|
65398
|
+
}
|
|
65399
|
+
function renderTerminalBranchScenario(lines, moment, condition, branchEntries, flow, ctxMap, ir) {
|
|
64266
65400
|
const tags = ["@terminal", "@failure-path"];
|
|
64267
65401
|
lines.push(` ${tags.join(" ")}`);
|
|
64268
65402
|
lines.push(` Scenario: ${moment.name} [${condition}]`);
|
|
64269
|
-
const failedPrecondition = findFailedPrecondition(moment,
|
|
65403
|
+
const failedPrecondition = findFailedPrecondition(moment, ctxMap);
|
|
65404
|
+
lines.push(` Given the ${moment.name.toLowerCase()} is evaluated`);
|
|
64270
65405
|
if (failedPrecondition) {
|
|
64271
|
-
lines.push(` Given the ${moment.name.toLowerCase()} is evaluated`);
|
|
64272
65406
|
lines.push(` When ${failedPrecondition.name} is not satisfied`);
|
|
64273
|
-
lines.push(` Then the flow terminates because ${failedPrecondition.description}`);
|
|
64274
65407
|
} else {
|
|
64275
|
-
lines.push(` Given the ${moment.name.toLowerCase()} is evaluated`);
|
|
64276
65408
|
lines.push(` When the outcome is ${condition}`);
|
|
64277
|
-
|
|
65409
|
+
}
|
|
65410
|
+
const usedConnections = /* @__PURE__ */ new Set();
|
|
65411
|
+
for (const entry of branchEntries) {
|
|
65412
|
+
renderEntrySteps(lines, entry, moment, condition, flow, ctxMap, /* @__PURE__ */ new Set(), usedConnections);
|
|
65413
|
+
}
|
|
65414
|
+
if (failedPrecondition) {
|
|
65415
|
+
lines.push(` Then the flow terminates because ${failedPrecondition.description}`);
|
|
65416
|
+
} else {
|
|
65417
|
+
const terminalNode = branchEntries.find((e) => e.terminal)?.nodeName;
|
|
65418
|
+
lines.push(` Then the flow terminates${terminalNode ? ` at ${terminalNode}` : ""}`);
|
|
64278
65419
|
}
|
|
64279
65420
|
const compensation = findCompensationForMoment(moment, ir);
|
|
64280
65421
|
if (compensation) {
|
|
@@ -64282,10 +65423,10 @@ function renderTerminalBranchScenario(lines, moment, condition, flow, ctxMap, ir
|
|
|
64282
65423
|
}
|
|
64283
65424
|
lines.push("");
|
|
64284
65425
|
}
|
|
64285
|
-
function buildScenarioTags(entries, flow, ctxMap, ir
|
|
65426
|
+
function buildScenarioTags(entries, moment, branchCondition, flow, ctxMap, ir) {
|
|
64286
65427
|
const tags = [];
|
|
64287
65428
|
collectAggregateTags(entries, ctxMap, tags);
|
|
64288
|
-
if (entries.some((e) => findCrossing(e, flow)))
|
|
65429
|
+
if (entries.some((e) => findCrossing(e, moment, branchCondition, flow)))
|
|
64289
65430
|
tags.push("@crossing");
|
|
64290
65431
|
collectPolicyTags(entries, ctxMap, tags);
|
|
64291
65432
|
collectSagaTags(entries, ir, tags);
|
|
@@ -64334,16 +65475,16 @@ function collectInvariantTags(entries, ctxMap, tags) {
|
|
|
64334
65475
|
}
|
|
64335
65476
|
}
|
|
64336
65477
|
}
|
|
64337
|
-
function renderEntrySteps(lines, entry, flow, ctxMap, sharedPreconditions = /* @__PURE__ */ new Set()) {
|
|
65478
|
+
function renderEntrySteps(lines, entry, moment, branchCondition, flow, ctxMap, sharedPreconditions = /* @__PURE__ */ new Set(), usedConnections = /* @__PURE__ */ new Set()) {
|
|
64338
65479
|
const ctx = ctxMap.get(entry.contextId);
|
|
64339
65480
|
const ctxName = entry.contextId.replace(/^ctx-/, "");
|
|
64340
|
-
if (
|
|
64341
|
-
renderCommandStep(lines, entry, ctx, ctxName, flow, sharedPreconditions);
|
|
65481
|
+
if (entry.nodeKind === "command") {
|
|
65482
|
+
renderCommandStep(lines, entry, ctx, ctxName, moment, flow, sharedPreconditions);
|
|
64342
65483
|
} else {
|
|
64343
|
-
renderEventStep(lines, entry, ctx, ctxName, flow);
|
|
65484
|
+
renderEventStep(lines, entry, ctx, ctxName, moment, branchCondition, flow, usedConnections);
|
|
64344
65485
|
}
|
|
64345
65486
|
}
|
|
64346
|
-
function renderCommandStep(lines, entry, ctx, ctxName, flow, sharedPreconditions = /* @__PURE__ */ new Set()) {
|
|
65487
|
+
function renderCommandStep(lines, entry, ctx, ctxName, moment, flow, sharedPreconditions = /* @__PURE__ */ new Set()) {
|
|
64347
65488
|
const cmd = findCommand2(ctx, entry.nodeName);
|
|
64348
65489
|
if (cmd) {
|
|
64349
65490
|
for (const pre of cmd.preconditions) {
|
|
@@ -64352,7 +65493,7 @@ function renderCommandStep(lines, entry, ctx, ctxName, flow, sharedPreconditions
|
|
|
64352
65493
|
}
|
|
64353
65494
|
}
|
|
64354
65495
|
}
|
|
64355
|
-
const trigger = findTriggeredBy(entry, flow);
|
|
65496
|
+
const trigger = findTriggeredBy(entry, moment, flow);
|
|
64356
65497
|
if (trigger) {
|
|
64357
65498
|
lines.push(` And ${trigger} has occurred`);
|
|
64358
65499
|
}
|
|
@@ -64380,9 +65521,10 @@ function renderInternalEventStep(lines, entry, evt, ctxName) {
|
|
|
64380
65521
|
lines.push(` carrying ${evt.fields.map((f) => f.name).join(", ")}`);
|
|
64381
65522
|
}
|
|
64382
65523
|
}
|
|
64383
|
-
function renderEventStep(lines, entry, ctx, ctxName, flow) {
|
|
64384
|
-
const crossing = findCrossing(entry, flow);
|
|
65524
|
+
function renderEventStep(lines, entry, ctx, ctxName, moment, branchCondition, flow, usedConnections = /* @__PURE__ */ new Set()) {
|
|
65525
|
+
const crossing = findCrossing(entry, moment, branchCondition, flow, usedConnections);
|
|
64385
65526
|
if (crossing) {
|
|
65527
|
+
usedConnections.add(crossing.id);
|
|
64386
65528
|
renderCrossingStep(lines, entry, crossing);
|
|
64387
65529
|
} else {
|
|
64388
65530
|
renderInternalEventStep(lines, entry, findEvent2(ctx, entry.nodeName), ctxName);
|
|
@@ -64435,15 +65577,51 @@ function renderBackgroundBlock(lines, sharedPreconditions) {
|
|
|
64435
65577
|
}
|
|
64436
65578
|
lines.push("");
|
|
64437
65579
|
}
|
|
64438
|
-
function
|
|
65580
|
+
function collectOwnedSagaIds(flow, ir) {
|
|
65581
|
+
const owned = /* @__PURE__ */ new Set();
|
|
65582
|
+
for (const ctx of ir.contexts) {
|
|
65583
|
+
for (const saga of ctx.sagas) {
|
|
65584
|
+
const owner = ir.flows.find((f) => flowContainsNode2(f, saga.trigger)) ?? ir.flows[0];
|
|
65585
|
+
if (owner && owner.id === flow.id)
|
|
65586
|
+
owned.add(saga.id);
|
|
65587
|
+
}
|
|
65588
|
+
}
|
|
65589
|
+
return owned;
|
|
65590
|
+
}
|
|
65591
|
+
function flowContainsNode2(flow, nodeName) {
|
|
65592
|
+
for (const moment of flow.moments) {
|
|
65593
|
+
if (momentContainsNode(moment, nodeName))
|
|
65594
|
+
return true;
|
|
65595
|
+
}
|
|
65596
|
+
return false;
|
|
65597
|
+
}
|
|
65598
|
+
function renderSagaScenarios(lines, ctxId, ir, ownedSagaIds) {
|
|
64439
65599
|
const ctx = ir.contexts.find((c) => c.id === ctxId);
|
|
64440
65600
|
if (!ctx)
|
|
64441
65601
|
return;
|
|
64442
65602
|
for (const saga of ctx.sagas) {
|
|
65603
|
+
if (!ownedSagaIds.has(saga.id))
|
|
65604
|
+
continue;
|
|
64443
65605
|
renderSagaTransitionScenario(lines, saga);
|
|
64444
65606
|
renderSagaCompensationScenario(lines, saga);
|
|
64445
65607
|
}
|
|
64446
65608
|
}
|
|
65609
|
+
function renderOrphanOwnedSagas(lines, ir, contextGroups, ownedSagaIds) {
|
|
65610
|
+
for (const ctx of ir.contexts) {
|
|
65611
|
+
if (contextGroups.has(ctx.id))
|
|
65612
|
+
continue;
|
|
65613
|
+
const owned = ctx.sagas.filter((s) => ownedSagaIds.has(s.id));
|
|
65614
|
+
if (owned.length === 0)
|
|
65615
|
+
continue;
|
|
65616
|
+
const classification = ctx.classification ? ` [${ctx.classification}]` : "";
|
|
65617
|
+
lines.push(` Rule: ${ctx.name}${classification}`);
|
|
65618
|
+
lines.push("");
|
|
65619
|
+
for (const saga of owned) {
|
|
65620
|
+
renderSagaTransitionScenario(lines, saga);
|
|
65621
|
+
renderSagaCompensationScenario(lines, saga);
|
|
65622
|
+
}
|
|
65623
|
+
}
|
|
65624
|
+
}
|
|
64447
65625
|
function renderSagaTransitionScenario(lines, saga) {
|
|
64448
65626
|
lines.push(` @saga:${saga.name}`);
|
|
64449
65627
|
lines.push(` Scenario: ${saga.name} state transitions`);
|
|
@@ -64459,17 +65637,14 @@ function renderSagaCompensationScenario(lines, saga) {
|
|
|
64459
65637
|
lines.push(` Then ${saga.compensation} is executed`);
|
|
64460
65638
|
lines.push("");
|
|
64461
65639
|
}
|
|
64462
|
-
function findFailedPrecondition(moment,
|
|
64463
|
-
|
|
64464
|
-
|
|
64465
|
-
|
|
64466
|
-
|
|
64467
|
-
|
|
64468
|
-
|
|
64469
|
-
|
|
64470
|
-
if (cmd && cmd.preconditions.length > 0) {
|
|
64471
|
-
return cmd.preconditions[0];
|
|
64472
|
-
}
|
|
65640
|
+
function findFailedPrecondition(moment, ctxMap) {
|
|
65641
|
+
for (const entry of moment.contextEntries) {
|
|
65642
|
+
if (entry.nodeKind !== "command")
|
|
65643
|
+
continue;
|
|
65644
|
+
const ctx = ctxMap.get(entry.contextId);
|
|
65645
|
+
const cmd = findCommand2(ctx, entry.nodeName);
|
|
65646
|
+
if (cmd && cmd.preconditions.length > 0) {
|
|
65647
|
+
return cmd.preconditions[0];
|
|
64473
65648
|
}
|
|
64474
65649
|
}
|
|
64475
65650
|
return void 0;
|
|
@@ -64489,10 +65664,47 @@ function findCompensationForMoment(moment, ir) {
|
|
|
64489
65664
|
}
|
|
64490
65665
|
return void 0;
|
|
64491
65666
|
}
|
|
64492
|
-
function
|
|
64493
|
-
|
|
65667
|
+
function orderedMomentChildren2(moment) {
|
|
65668
|
+
const entries = moment.contextEntries;
|
|
65669
|
+
const branches = moment.branches ?? [];
|
|
65670
|
+
const seq = moment.sequence;
|
|
65671
|
+
if (seq && isUsableSequence2(seq, entries.length, branches.length)) {
|
|
65672
|
+
return seq.map((item) => item.kind === "entry" ? { kind: "entry", entry: entries[item.index] } : { kind: "branch", branch: branches[item.index] });
|
|
65673
|
+
}
|
|
65674
|
+
return [
|
|
65675
|
+
...entries.map((entry) => ({ kind: "entry", entry })),
|
|
65676
|
+
...branches.map((branch) => ({ kind: "branch", branch }))
|
|
65677
|
+
];
|
|
65678
|
+
}
|
|
65679
|
+
function isUsableSequence2(seq, entryCount, branchCount) {
|
|
65680
|
+
if (seq.length !== entryCount + branchCount)
|
|
64494
65681
|
return false;
|
|
64495
|
-
|
|
65682
|
+
const seenEntries = /* @__PURE__ */ new Set();
|
|
65683
|
+
const seenBranches = /* @__PURE__ */ new Set();
|
|
65684
|
+
for (const item of seq) {
|
|
65685
|
+
const max = item.kind === "entry" ? entryCount : branchCount;
|
|
65686
|
+
const seen = item.kind === "entry" ? seenEntries : seenBranches;
|
|
65687
|
+
if (item.index < 0 || item.index >= max || seen.has(item.index))
|
|
65688
|
+
return false;
|
|
65689
|
+
seen.add(item.index);
|
|
65690
|
+
}
|
|
65691
|
+
return true;
|
|
65692
|
+
}
|
|
65693
|
+
function orderedMainEntries(moment) {
|
|
65694
|
+
const out = [];
|
|
65695
|
+
for (const child of orderedMomentChildren2(moment)) {
|
|
65696
|
+
if (child.kind === "entry")
|
|
65697
|
+
out.push(child.entry);
|
|
65698
|
+
}
|
|
65699
|
+
return out;
|
|
65700
|
+
}
|
|
65701
|
+
function promoteLeadingAnd(steps) {
|
|
65702
|
+
if (steps.length === 0)
|
|
65703
|
+
return;
|
|
65704
|
+
const first2 = steps[0];
|
|
65705
|
+
if (first2.trimStart().startsWith("And ")) {
|
|
65706
|
+
steps[0] = first2.replace("And ", "Given ");
|
|
65707
|
+
}
|
|
64496
65708
|
}
|
|
64497
65709
|
function findCommand2(ctx, name) {
|
|
64498
65710
|
if (!ctx)
|
|
@@ -64532,19 +65744,36 @@ function momentContainsNode(moment, nodeName) {
|
|
|
64532
65744
|
}
|
|
64533
65745
|
return false;
|
|
64534
65746
|
}
|
|
64535
|
-
function findTriggeredBy(entry, flow) {
|
|
65747
|
+
function findTriggeredBy(entry, moment, flow) {
|
|
64536
65748
|
for (const conn of flow.connections) {
|
|
64537
65749
|
if (conn.connectionType !== "triggered-by")
|
|
64538
65750
|
continue;
|
|
64539
65751
|
const triggerEventName = conn.eventId.replace(/^evt-/, "");
|
|
64540
|
-
|
|
64541
|
-
|
|
64542
|
-
|
|
65752
|
+
if (conn.targetNodeName) {
|
|
65753
|
+
if (conn.sourceMomentId === moment.id && conn.targetNodeName === entry.nodeName) {
|
|
65754
|
+
return triggerEventName;
|
|
65755
|
+
}
|
|
65756
|
+
} else {
|
|
65757
|
+
const owner = flow.moments.find((m) => m.id === conn.sourceMomentId);
|
|
65758
|
+
if (owner && momentContainsNode(owner, entry.nodeName))
|
|
65759
|
+
return triggerEventName;
|
|
65760
|
+
}
|
|
64543
65761
|
}
|
|
64544
65762
|
return void 0;
|
|
64545
65763
|
}
|
|
64546
|
-
function findCrossing(entry, flow) {
|
|
64547
|
-
return flow.connections.find((c) => c.connectionType === "crosses-to" && c.eventId === `evt-${entry.nodeName}`);
|
|
65764
|
+
function findCrossing(entry, moment, branchCondition, flow, usedConnections = /* @__PURE__ */ new Set()) {
|
|
65765
|
+
return flow.connections.find((c) => c.connectionType === "crosses-to" && c.sourceMomentId === moment.id && (c.sourceNodeName ? c.sourceNodeName === entry.nodeName : c.eventId === `evt-${entry.nodeName}`) && (c.branchCondition === void 0 || c.branchCondition === branchCondition) && !usedConnections.has(c.id));
|
|
65766
|
+
}
|
|
65767
|
+
function findReturnsTo(moment, branchCondition, flow) {
|
|
65768
|
+
return flow.connections.find((c) => c.connectionType === "returns-to" && c.sourceMomentId === moment.id && (c.branchCondition === void 0 || c.branchCondition === branchCondition));
|
|
65769
|
+
}
|
|
65770
|
+
function resolveReturnsToLabel(conn, flow) {
|
|
65771
|
+
if (conn.targetMomentId) {
|
|
65772
|
+
const target = flow.moments.find((m) => m.id === conn.targetMomentId);
|
|
65773
|
+
if (target)
|
|
65774
|
+
return target.name;
|
|
65775
|
+
}
|
|
65776
|
+
return "targetMomentLabel" in conn ? conn.targetMomentLabel : void 0;
|
|
64548
65777
|
}
|
|
64549
65778
|
function collectFlowContextIds(flow) {
|
|
64550
65779
|
const ids = /* @__PURE__ */ new Set();
|
|
@@ -64713,8 +65942,9 @@ var SpecificationDocumentGenerator = class {
|
|
|
64713
65942
|
}
|
|
64714
65943
|
renderMomentNarrative(lines, moment, step, flow, ir) {
|
|
64715
65944
|
this.renderMomentHeader(lines, moment, step, flow, ir);
|
|
65945
|
+
const usedConnections = /* @__PURE__ */ new Set();
|
|
64716
65946
|
for (const entry of moment.contextEntries) {
|
|
64717
|
-
this.renderEntryNarrative(lines, entry, flow, ir);
|
|
65947
|
+
this.renderEntryNarrative(lines, entry, moment, void 0, flow, ir, " ", usedConnections);
|
|
64718
65948
|
}
|
|
64719
65949
|
this.renderMomentBranches(lines, moment, flow, ir);
|
|
64720
65950
|
this.renderMomentPoliciesAndRules(lines, moment, ir);
|
|
@@ -64738,15 +65968,35 @@ var SpecificationDocumentGenerator = class {
|
|
|
64738
65968
|
for (const branch of moment.branches) {
|
|
64739
65969
|
const isTerminal = branch.entries.some((e) => e.terminal);
|
|
64740
65970
|
if (isTerminal) {
|
|
64741
|
-
|
|
65971
|
+
this.renderTerminalBranch(lines, moment, branch, flow, ir);
|
|
64742
65972
|
} else {
|
|
64743
|
-
|
|
64744
|
-
for (const entry of branch.entries) {
|
|
64745
|
-
this.renderEntryNarrative(lines, entry, flow, ir, " ");
|
|
64746
|
-
}
|
|
65973
|
+
this.renderNonTerminalBranch(lines, moment, branch, flow, ir);
|
|
64747
65974
|
}
|
|
64748
65975
|
}
|
|
64749
65976
|
}
|
|
65977
|
+
renderTerminalBranch(lines, moment, branch, flow, ir) {
|
|
65978
|
+
const usedConnections = /* @__PURE__ */ new Set();
|
|
65979
|
+
const terminalNode = branch.entries.find((e) => e.terminal)?.nodeName;
|
|
65980
|
+
lines.push(` - \u274C **If ${branch.condition}:** flow terminates${terminalNode ? ` at **${terminalNode}**` : ""}`);
|
|
65981
|
+
for (const entry of branch.entries) {
|
|
65982
|
+
if (entry.terminal)
|
|
65983
|
+
continue;
|
|
65984
|
+
this.renderEntryNarrative(lines, entry, moment, branch.condition, flow, ir, " ", usedConnections);
|
|
65985
|
+
}
|
|
65986
|
+
}
|
|
65987
|
+
renderNonTerminalBranch(lines, moment, branch, flow, ir) {
|
|
65988
|
+
const usedConnections = /* @__PURE__ */ new Set();
|
|
65989
|
+
lines.push(` - \u2705 **If ${branch.condition}:**`);
|
|
65990
|
+
for (const entry of branch.entries) {
|
|
65991
|
+
this.renderEntryNarrative(lines, entry, moment, branch.condition, flow, ir, " ", usedConnections);
|
|
65992
|
+
}
|
|
65993
|
+
const returnsTo = this.findReturnsTo(moment, branch.condition, flow);
|
|
65994
|
+
if (returnsTo) {
|
|
65995
|
+
const label = this.resolveReturnsToLabel(returnsTo, flow);
|
|
65996
|
+
if (label)
|
|
65997
|
+
lines.push(` - \u21A9 *returns to "${label}"*`);
|
|
65998
|
+
}
|
|
65999
|
+
}
|
|
64750
66000
|
renderMomentPoliciesAndRules(lines, moment, ir) {
|
|
64751
66001
|
for (const pol of this.findPoliciesTriggeredBy(moment, ir)) {
|
|
64752
66002
|
lines.push(` - \u{1F517} *Policy: ${pol.name}* \u2014 ${pol.action}`);
|
|
@@ -64755,13 +66005,16 @@ var SpecificationDocumentGenerator = class {
|
|
|
64755
66005
|
lines.push(` - \u{1F4CB} *Rule ${rule.id}:* ${rule.description}`);
|
|
64756
66006
|
}
|
|
64757
66007
|
}
|
|
64758
|
-
renderEntryNarrative(lines, entry, flow, ir, indent = " ") {
|
|
66008
|
+
renderEntryNarrative(lines, entry, moment, branchCondition, flow, ir, indent = " ", usedConnections = /* @__PURE__ */ new Set()) {
|
|
64759
66009
|
const ctx = ir.contexts.find((c) => c.id === entry.contextId);
|
|
64760
66010
|
const ctxName = entry.contextId.replace(/^ctx-/, "");
|
|
64761
|
-
|
|
64762
|
-
if (this.isCommand(entry.nodeName, ctx)) {
|
|
66011
|
+
if (entry.nodeKind === "command") {
|
|
64763
66012
|
this.renderCommandNarrative(lines, entry, ctx, ctxName, indent);
|
|
64764
|
-
|
|
66013
|
+
return;
|
|
66014
|
+
}
|
|
66015
|
+
const crossing = this.findCrossing(entry, moment, branchCondition, flow, usedConnections);
|
|
66016
|
+
if (crossing) {
|
|
66017
|
+
usedConnections.add(crossing.id);
|
|
64765
66018
|
const target = this.resolveCtxName(crossing.targetContextId, ir);
|
|
64766
66019
|
lines.push(`${indent}- **${entry.nodeName}** \u2192 crosses to **${target}**`);
|
|
64767
66020
|
} else {
|
|
@@ -64954,7 +66207,7 @@ var SpecificationDocumentGenerator = class {
|
|
|
64954
66207
|
if (conn.connectionType !== "crosses-to")
|
|
64955
66208
|
continue;
|
|
64956
66209
|
const moment = flow.moments.find((m) => m.id === conn.sourceMomentId);
|
|
64957
|
-
const sourceCtxId = this.
|
|
66210
|
+
const sourceCtxId = moment ? this.findEntryForConnection(conn, moment)?.contextId : void 0;
|
|
64958
66211
|
if (!sourceCtxId)
|
|
64959
66212
|
continue;
|
|
64960
66213
|
const sourceNode = this.mermaidNodeId(this.resolveCtxName(sourceCtxId, ir));
|
|
@@ -65019,7 +66272,7 @@ var SpecificationDocumentGenerator = class {
|
|
|
65019
66272
|
}
|
|
65020
66273
|
renderMomentSequenceMessages(lines, moment, flow, ir) {
|
|
65021
66274
|
const ctxName = this.resolveMomentCtxName(moment, ir);
|
|
65022
|
-
this.renderSequenceEntries(lines, moment.contextEntries,
|
|
66275
|
+
this.renderSequenceEntries(lines, moment.contextEntries, moment, void 0, flow, ir);
|
|
65023
66276
|
if (moment.branches && moment.branches.length > 0) {
|
|
65024
66277
|
this.renderBranchAltBlock(lines, moment, ctxName, flow, ir);
|
|
65025
66278
|
}
|
|
@@ -65033,8 +66286,7 @@ var SpecificationDocumentGenerator = class {
|
|
|
65033
66286
|
const branch = nonTerminal[i];
|
|
65034
66287
|
const keyword = i === 0 ? "alt" : "else";
|
|
65035
66288
|
lines.push(` ${keyword} ${branch.condition}`);
|
|
65036
|
-
|
|
65037
|
-
this.renderSequenceEntries(lines, branch.entries, branchCtx, flow, ir);
|
|
66289
|
+
this.renderSequenceEntries(lines, branch.entries, moment, branch.condition, flow, ir);
|
|
65038
66290
|
}
|
|
65039
66291
|
if (terminal.length > 0) {
|
|
65040
66292
|
const keyword = nonTerminal.length === 0 ? "alt" : "else";
|
|
@@ -65044,24 +66296,22 @@ var SpecificationDocumentGenerator = class {
|
|
|
65044
66296
|
}
|
|
65045
66297
|
lines.push(" end");
|
|
65046
66298
|
}
|
|
65047
|
-
|
|
65048
|
-
const
|
|
65049
|
-
return entry ? this.resolveCtxName(entry.contextId, ir) : fallback;
|
|
65050
|
-
}
|
|
65051
|
-
renderSequenceEntries(lines, entries, ctxName, flow, ir) {
|
|
66299
|
+
renderSequenceEntries(lines, entries, moment, branchCondition, flow, ir) {
|
|
66300
|
+
const usedConnections = /* @__PURE__ */ new Set();
|
|
65052
66301
|
for (const entry of entries) {
|
|
65053
66302
|
if (entry.terminal)
|
|
65054
66303
|
continue;
|
|
65055
|
-
this.renderSingleSequenceEntry(lines, entry,
|
|
66304
|
+
this.renderSingleSequenceEntry(lines, entry, moment, branchCondition, flow, ir, usedConnections);
|
|
65056
66305
|
}
|
|
65057
66306
|
}
|
|
65058
|
-
renderSingleSequenceEntry(lines, entry,
|
|
66307
|
+
renderSingleSequenceEntry(lines, entry, moment, branchCondition, flow, ir, usedConnections) {
|
|
65059
66308
|
const entryCtx = this.resolveCtxName(entry.contextId, ir);
|
|
65060
|
-
const crossing = this.findCrossing(entry
|
|
66309
|
+
const crossing = this.findCrossing(entry, moment, branchCondition, flow, usedConnections);
|
|
65061
66310
|
if (crossing) {
|
|
66311
|
+
usedConnections.add(crossing.id);
|
|
65062
66312
|
const target = this.resolveCtxName(crossing.targetContextId, ir);
|
|
65063
66313
|
lines.push(` ${entryCtx}->>${target}: ${entry.nodeName} (crosses)`);
|
|
65064
|
-
} else if (
|
|
66314
|
+
} else if (entry.nodeKind === "command") {
|
|
65065
66315
|
const cmd = this.findCommand(ir.contexts.find((c) => c.id === entry.contextId), entry.nodeName);
|
|
65066
66316
|
const emits = cmd?.emitsEvent ? ` \u2192 ${cmd.emitsEvent}` : "";
|
|
65067
66317
|
lines.push(` ${entryCtx}->>${entryCtx}: ${entry.nodeName}${emits}`);
|
|
@@ -65076,12 +66326,6 @@ var SpecificationDocumentGenerator = class {
|
|
|
65076
66326
|
mermaidNodeId(name) {
|
|
65077
66327
|
return name.replace(/[^a-zA-Z0-9]/g, "");
|
|
65078
66328
|
}
|
|
65079
|
-
resolveSourceContextId(moment) {
|
|
65080
|
-
if (!moment)
|
|
65081
|
-
return void 0;
|
|
65082
|
-
const entry = moment.contextEntries[0] ?? moment.branches?.[0]?.entries?.[0];
|
|
65083
|
-
return entry?.contextId;
|
|
65084
|
-
}
|
|
65085
66329
|
// ===========================================================================
|
|
65086
66330
|
// Saga Helpers
|
|
65087
66331
|
// ===========================================================================
|
|
@@ -65137,11 +66381,6 @@ var SpecificationDocumentGenerator = class {
|
|
|
65137
66381
|
resolveCtxName(id, ir) {
|
|
65138
66382
|
return ir.contexts.find((c) => c.id === id)?.name ?? id.replace(/^ctx-/, "");
|
|
65139
66383
|
}
|
|
65140
|
-
isCommand(name, ctx) {
|
|
65141
|
-
if (!ctx)
|
|
65142
|
-
return false;
|
|
65143
|
-
return ctx.commands.some((c) => c.name === name);
|
|
65144
|
-
}
|
|
65145
66384
|
findCommand(ctx, name) {
|
|
65146
66385
|
if (!ctx)
|
|
65147
66386
|
return void 0;
|
|
@@ -65152,17 +66391,49 @@ var SpecificationDocumentGenerator = class {
|
|
|
65152
66391
|
}
|
|
65153
66392
|
return void 0;
|
|
65154
66393
|
}
|
|
65155
|
-
|
|
65156
|
-
|
|
66394
|
+
/**
|
|
66395
|
+
* Finds the crossing declared by this entry in this moment (and branch).
|
|
66396
|
+
* Scoped to (sourceMomentId, node) so an event crossing to several targets
|
|
66397
|
+
* from different moments resolves to the right connection and contract.
|
|
66398
|
+
*/
|
|
66399
|
+
findCrossing(entry, moment, branchCondition, flow, usedConnections = /* @__PURE__ */ new Set()) {
|
|
66400
|
+
return flow.connections.find((c) => c.connectionType === "crosses-to" && c.sourceMomentId === moment.id && (c.sourceNodeName ? c.sourceNodeName === entry.nodeName : c.eventId === `evt-${entry.nodeName}`) && (c.branchCondition === void 0 || c.branchCondition === branchCondition) && !usedConnections.has(c.id));
|
|
66401
|
+
}
|
|
66402
|
+
findReturnsTo(moment, branchCondition, flow) {
|
|
66403
|
+
return flow.connections.find((c) => c.connectionType === "returns-to" && c.sourceMomentId === moment.id && (c.branchCondition === void 0 || c.branchCondition === branchCondition));
|
|
66404
|
+
}
|
|
66405
|
+
resolveReturnsToLabel(conn, flow) {
|
|
66406
|
+
if (conn.targetMomentId) {
|
|
66407
|
+
const target = flow.moments.find((m) => m.id === conn.targetMomentId);
|
|
66408
|
+
if (target)
|
|
66409
|
+
return target.name;
|
|
66410
|
+
}
|
|
66411
|
+
return "targetMomentLabel" in conn ? conn.targetMomentLabel : void 0;
|
|
65157
66412
|
}
|
|
65158
66413
|
findSourceCtx(conn, moment, ir) {
|
|
65159
66414
|
if (!moment)
|
|
65160
66415
|
return "\u2014";
|
|
65161
|
-
const entry =
|
|
66416
|
+
const entry = this.findEntryForConnection(conn, moment);
|
|
65162
66417
|
return entry ? this.resolveCtxName(entry.contextId, ir) : "\u2014";
|
|
65163
66418
|
}
|
|
66419
|
+
/**
|
|
66420
|
+
* Resolves the entry that declared a connection, preferring the connection's
|
|
66421
|
+
* own sourceNodeName over positional guessing.
|
|
66422
|
+
*/
|
|
66423
|
+
findEntryForConnection(conn, moment) {
|
|
66424
|
+
const allEntries = [
|
|
66425
|
+
...moment.contextEntries,
|
|
66426
|
+
...(moment.branches ?? []).flatMap((b) => b.entries)
|
|
66427
|
+
];
|
|
66428
|
+
if (conn.sourceNodeName) {
|
|
66429
|
+
const declared = allEntries.find((e) => e.nodeName === conn.sourceNodeName);
|
|
66430
|
+
if (declared)
|
|
66431
|
+
return declared;
|
|
66432
|
+
}
|
|
66433
|
+
return allEntries[0];
|
|
66434
|
+
}
|
|
65164
66435
|
findPoliciesTriggeredBy(moment, ir) {
|
|
65165
|
-
const eventNames = moment.contextEntries.filter((e) =>
|
|
66436
|
+
const eventNames = moment.contextEntries.filter((e) => e.nodeKind !== "command").map((e) => e.nodeName);
|
|
65166
66437
|
const policies = [];
|
|
65167
66438
|
for (const ctx of ir.contexts) {
|
|
65168
66439
|
for (const pol of ctx.policies) {
|
|
@@ -65200,8 +66471,9 @@ function generateAsyncApiSpec(ir) {
|
|
|
65200
66471
|
const crossings = collectCrossings(ir);
|
|
65201
66472
|
const channels = buildChannelYaml(crossings);
|
|
65202
66473
|
const messages = buildMessageYaml(crossings);
|
|
65203
|
-
const title = escapeYaml(ir.metadata.name || "
|
|
65204
|
-
const
|
|
66474
|
+
const title = escapeYaml(ir.metadata.name || "Moment Specification");
|
|
66475
|
+
const rawVersion = ir.metadata.version;
|
|
66476
|
+
const version = escapeYaml(!rawVersion || rawVersion === "0.0.0" ? "1.0.0" : rawVersion);
|
|
65205
66477
|
const description = escapeYaml(ir.metadata.description || "");
|
|
65206
66478
|
const parts = [];
|
|
65207
66479
|
parts.push(`asyncapi: '3.0.0'`);
|
|
@@ -65229,27 +66501,58 @@ function collectCrossings(ir) {
|
|
|
65229
66501
|
for (const conn of flow.connections) {
|
|
65230
66502
|
if (conn.connectionType !== "crosses-to")
|
|
65231
66503
|
continue;
|
|
65232
|
-
const
|
|
65233
|
-
if (!
|
|
66504
|
+
const info = crossingFromConnection(conn, flow, ir);
|
|
66505
|
+
if (!info)
|
|
65234
66506
|
continue;
|
|
65235
|
-
const
|
|
65236
|
-
const consumerCtx = ir.contexts.find((c) => c.id === conn.targetContextId);
|
|
65237
|
-
if (!producerCtx || !consumerCtx)
|
|
65238
|
-
continue;
|
|
65239
|
-
const key = `${event.name}|${producerCtx.name}|${consumerCtx.name}`;
|
|
66507
|
+
const key = `${info.eventName}|${info.producerContext}|${info.consumerContext}`;
|
|
65240
66508
|
if (seen.has(key))
|
|
65241
66509
|
continue;
|
|
65242
66510
|
seen.add(key);
|
|
65243
|
-
crossings.push(
|
|
65244
|
-
eventName: event.name,
|
|
65245
|
-
eventFields: event.fields.map((f) => ({ name: f.name, type: f.type, deprecated: f.deprecated ? true : void 0 })),
|
|
65246
|
-
producerContext: producerCtx.name,
|
|
65247
|
-
consumerContext: consumerCtx.name
|
|
65248
|
-
});
|
|
66511
|
+
crossings.push(info);
|
|
65249
66512
|
}
|
|
65250
66513
|
}
|
|
65251
66514
|
return crossings;
|
|
65252
66515
|
}
|
|
66516
|
+
function crossingFromConnection(conn, flow, ir) {
|
|
66517
|
+
const event = findEventById(conn.eventId, ir);
|
|
66518
|
+
const eventName = event?.name ?? conn.schemaContract.eventType;
|
|
66519
|
+
if (!eventName)
|
|
66520
|
+
return void 0;
|
|
66521
|
+
const producerCtx = findProducerContext(conn.eventId, ir);
|
|
66522
|
+
const producerName = producerCtx?.name ?? findProducingEntryContext2(eventName, conn.sourceMomentId, flow, ir);
|
|
66523
|
+
if (!producerName)
|
|
66524
|
+
return void 0;
|
|
66525
|
+
const consumerCtx = ir.contexts.find((c) => c.id === conn.targetContextId);
|
|
66526
|
+
const consumerName = consumerCtx?.name ?? conn.targetContextId.replace(/^ctx-/, "");
|
|
66527
|
+
const { eventFields, requiredFields } = crossingSchema(event, conn);
|
|
66528
|
+
return {
|
|
66529
|
+
eventName,
|
|
66530
|
+
eventFields,
|
|
66531
|
+
requiredFields,
|
|
66532
|
+
producerContext: producerName,
|
|
66533
|
+
consumerContext: consumerName
|
|
66534
|
+
};
|
|
66535
|
+
}
|
|
66536
|
+
function crossingSchema(event, conn) {
|
|
66537
|
+
const eventFields = event ? event.fields.map((f) => ({ name: f.name, type: f.type, deprecated: f.deprecated ? true : void 0 })) : conn.schemaContract.fields.map((f) => ({ name: f.name, type: f.type, deprecated: void 0 }));
|
|
66538
|
+
const contractRequired = conn.schemaContract.fields.filter((f) => f.required).map((f) => f.name);
|
|
66539
|
+
const requiredFields = contractRequired.length > 0 ? contractRequired : event?.fields.filter((f) => f.required).map((f) => f.name) ?? [];
|
|
66540
|
+
return { eventFields, requiredFields };
|
|
66541
|
+
}
|
|
66542
|
+
function findProducingEntryContext2(eventName, sourceMomentId, flow, ir) {
|
|
66543
|
+
const moment = flow.moments.find((m) => m.id === sourceMomentId);
|
|
66544
|
+
if (!moment)
|
|
66545
|
+
return void 0;
|
|
66546
|
+
const entries = [
|
|
66547
|
+
...moment.contextEntries,
|
|
66548
|
+
...(moment.branches ?? []).flatMap((b) => b.entries)
|
|
66549
|
+
];
|
|
66550
|
+
const producing = entries.find((e) => e.nodeName === eventName);
|
|
66551
|
+
if (!producing)
|
|
66552
|
+
return void 0;
|
|
66553
|
+
const ctx = ir.contexts.find((c) => c.id === producing.contextId);
|
|
66554
|
+
return ctx?.name ?? producing.contextId.replace(/^ctx-/, "");
|
|
66555
|
+
}
|
|
65253
66556
|
function findEventById(eventId, ir) {
|
|
65254
66557
|
for (const ctx of ir.contexts) {
|
|
65255
66558
|
for (const evt of ctx.events) {
|
|
@@ -65277,15 +66580,31 @@ function findProducerContext(eventId, ir) {
|
|
|
65277
66580
|
return void 0;
|
|
65278
66581
|
}
|
|
65279
66582
|
function buildChannelYaml(crossings) {
|
|
65280
|
-
const
|
|
66583
|
+
const byEvent = /* @__PURE__ */ new Map();
|
|
65281
66584
|
for (const crossing of crossings) {
|
|
65282
|
-
|
|
66585
|
+
let group = byEvent.get(crossing.eventName);
|
|
66586
|
+
if (!group) {
|
|
66587
|
+
group = { producers: [], consumers: [] };
|
|
66588
|
+
byEvent.set(crossing.eventName, group);
|
|
66589
|
+
}
|
|
66590
|
+
if (!group.producers.includes(crossing.producerContext)) {
|
|
66591
|
+
group.producers.push(crossing.producerContext);
|
|
66592
|
+
}
|
|
66593
|
+
if (!group.consumers.includes(crossing.consumerContext)) {
|
|
66594
|
+
group.consumers.push(crossing.consumerContext);
|
|
66595
|
+
}
|
|
66596
|
+
}
|
|
66597
|
+
const lines = [];
|
|
66598
|
+
for (const [eventName, group] of byEvent) {
|
|
66599
|
+
const channelName = toKebabCase(eventName);
|
|
66600
|
+
const producers = group.producers.map(escapeYaml).join(", ");
|
|
66601
|
+
const consumers = group.consumers.map(escapeYaml).join(", ");
|
|
65283
66602
|
lines.push(` ${channelName}:`);
|
|
65284
66603
|
lines.push(` address: '${channelName}'`);
|
|
65285
66604
|
lines.push(` messages:`);
|
|
65286
|
-
lines.push(` ${
|
|
65287
|
-
lines.push(` $ref: '#/components/messages/${
|
|
65288
|
-
lines.push(` description: 'Published by ${
|
|
66605
|
+
lines.push(` ${eventName}:`);
|
|
66606
|
+
lines.push(` $ref: '#/components/messages/${eventName}'`);
|
|
66607
|
+
lines.push(` description: 'Published by ${producers}, consumed by ${consumers}'`);
|
|
65289
66608
|
}
|
|
65290
66609
|
return lines.join("\n");
|
|
65291
66610
|
}
|
|
@@ -65308,6 +66627,12 @@ function buildMessageYaml(crossings) {
|
|
|
65308
66627
|
lines.push(` deprecated: true`);
|
|
65309
66628
|
}
|
|
65310
66629
|
}
|
|
66630
|
+
if (crossing.requiredFields.length > 0) {
|
|
66631
|
+
lines.push(` required:`);
|
|
66632
|
+
for (const name of crossing.requiredFields) {
|
|
66633
|
+
lines.push(` - ${name}`);
|
|
66634
|
+
}
|
|
66635
|
+
}
|
|
65311
66636
|
}
|
|
65312
66637
|
return lines.join("\n");
|
|
65313
66638
|
}
|
|
@@ -65399,7 +66724,7 @@ function isStepLine(line) {
|
|
|
65399
66724
|
function parseStepLine(line, lineNumber) {
|
|
65400
66725
|
const keyword = line.split(" ")[0] + " ";
|
|
65401
66726
|
const name = line.slice(keyword.length);
|
|
65402
|
-
return { keyword, name, line: lineNumber, result: { status: "
|
|
66727
|
+
return { keyword, name, line: lineNumber, result: { status: "pending", duration: 0 } };
|
|
65403
66728
|
}
|
|
65404
66729
|
function buildScenario(parsed, flow, suite) {
|
|
65405
66730
|
const status = resolveScenarioStatus(parsed.name, parsed.tags, flow, suite);
|
|
@@ -65420,23 +66745,22 @@ function buildScenario(parsed, flow, suite) {
|
|
|
65420
66745
|
function resolveScenarioStatus(scenarioName, tags, flow, suite) {
|
|
65421
66746
|
if (!suite)
|
|
65422
66747
|
return "skipped";
|
|
66748
|
+
const bracketIdx = scenarioName.indexOf(" [");
|
|
66749
|
+
const momentName = bracketIdx !== -1 ? scenarioName.slice(0, bracketIdx) : scenarioName;
|
|
66750
|
+
const variant = bracketIdx !== -1 ? scenarioName.slice(bracketIdx + 2, scenarioName.length - 1) : void 0;
|
|
66751
|
+
const moment = flow.moments.find((m) => m.name === momentName);
|
|
66752
|
+
if (moment) {
|
|
66753
|
+
const matchingCase = suite.testCases.find((tc) => tc.momentId === moment.id && (variant === void 0 || tc.variant === variant));
|
|
66754
|
+
return matchingCase ? "pending" : "skipped";
|
|
66755
|
+
}
|
|
65423
66756
|
const isSaga = tags.some((t) => t.name.startsWith("@saga:"));
|
|
65424
|
-
const isCompensation = tags.some((t) => t.name === "@compensation");
|
|
65425
66757
|
if (isSaga) {
|
|
65426
|
-
const
|
|
65427
|
-
const matchingCases = suite.testCases.filter((tc) => tc.momentId.startsWith(sagaPrefix));
|
|
66758
|
+
const matchingCases = suite.testCases.filter((tc) => tc.momentId.startsWith("saga-"));
|
|
65428
66759
|
if (matchingCases.length === 0)
|
|
65429
66760
|
return "skipped";
|
|
65430
|
-
return "
|
|
66761
|
+
return "pending";
|
|
65431
66762
|
}
|
|
65432
|
-
|
|
65433
|
-
const momentName = bracketIdx !== -1 ? scenarioName.slice(0, bracketIdx) : scenarioName;
|
|
65434
|
-
const variant = bracketIdx !== -1 ? scenarioName.slice(bracketIdx + 2, scenarioName.length - 1) : void 0;
|
|
65435
|
-
const moment = flow.moments.find((m) => m.name === momentName);
|
|
65436
|
-
if (!moment)
|
|
65437
|
-
return "skipped";
|
|
65438
|
-
const matchingCase = suite.testCases.find((tc) => tc.momentId === moment.id && (variant === void 0 || tc.variant === variant));
|
|
65439
|
-
return matchingCase ? "passed" : "skipped";
|
|
66763
|
+
return "skipped";
|
|
65440
66764
|
}
|
|
65441
66765
|
function extractFeatureTags(content) {
|
|
65442
66766
|
const firstLine = content.split("\n")[0]?.trim() ?? "";
|
|
@@ -65748,27 +67072,35 @@ function sanitizeComment(s) {
|
|
|
65748
67072
|
function generateSetupComment(step) {
|
|
65749
67073
|
return ` // Setup: ${sanitizeComment(step.contextName)}.${sanitizeComment(step.aggregateName)} \u2014 ${sanitizeComment(step.precondition)}`;
|
|
65750
67074
|
}
|
|
65751
|
-
function
|
|
67075
|
+
function assertionTestName(assertion, testCase) {
|
|
67076
|
+
if (assertion.assertionType === "saga" || assertion.assertionType === "policy-chain") {
|
|
67077
|
+
return `should verify ${escapeStringLiteral(testCase.momentName)}`;
|
|
67078
|
+
}
|
|
65752
67079
|
const eventType = assertion.schemaContract.eventType;
|
|
65753
67080
|
const source = assertion.sourceContext;
|
|
65754
67081
|
const target = assertion.targetContext;
|
|
67082
|
+
return `should verify ${escapeStringLiteral(eventType)} crosses from ${escapeStringLiteral(source)} to ${escapeStringLiteral(target)}`;
|
|
67083
|
+
}
|
|
67084
|
+
function generateAssertionIt(assertion, testCase) {
|
|
65755
67085
|
const lines = [];
|
|
65756
|
-
lines.push(`
|
|
65757
|
-
lines.push(`
|
|
65758
|
-
lines.push(` // Assertion type: ${assertion.assertionType}`);
|
|
67086
|
+
lines.push(` // Crossing: ${assertion.crossingId}`);
|
|
67087
|
+
lines.push(` // Assertion type: ${assertion.assertionType}`);
|
|
65759
67088
|
if (assertion.schemaContract.expectedFields.length > 0) {
|
|
65760
|
-
lines.push(`
|
|
67089
|
+
lines.push(` // Expected fields:`);
|
|
65761
67090
|
for (const field of assertion.schemaContract.expectedFields) {
|
|
65762
|
-
lines.push(`
|
|
67091
|
+
lines.push(` // ${field.fieldName}: ${field.expectedType} (${field.required ? "required" : "optional"})`);
|
|
65763
67092
|
}
|
|
65764
67093
|
}
|
|
65765
|
-
lines.push(`
|
|
65766
|
-
lines.push(` });`);
|
|
67094
|
+
lines.push(` it.todo('${assertionTestName(assertion, testCase)}');`);
|
|
65767
67095
|
return lines.join("\n");
|
|
65768
67096
|
}
|
|
67097
|
+
function describeName(testCase) {
|
|
67098
|
+
const base = escapeStringLiteral(testCase.momentName);
|
|
67099
|
+
return testCase.variant ? `${base} [${escapeStringLiteral(testCase.variant)}]` : base;
|
|
67100
|
+
}
|
|
65769
67101
|
function generateTestCase(testCase) {
|
|
65770
67102
|
const lines = [];
|
|
65771
|
-
lines.push(` describe('${
|
|
67103
|
+
lines.push(` describe('${describeName(testCase)}', () => {`);
|
|
65772
67104
|
if (testCase.setupSteps.length > 0) {
|
|
65773
67105
|
lines.push(` beforeEach(() => {`);
|
|
65774
67106
|
for (const step of testCase.setupSteps) {
|
|
@@ -65778,7 +67110,7 @@ function generateTestCase(testCase) {
|
|
|
65778
67110
|
lines.push("");
|
|
65779
67111
|
}
|
|
65780
67112
|
for (const assertion of testCase.assertions) {
|
|
65781
|
-
lines.push(generateAssertionIt(assertion));
|
|
67113
|
+
lines.push(generateAssertionIt(assertion, testCase));
|
|
65782
67114
|
lines.push("");
|
|
65783
67115
|
}
|
|
65784
67116
|
if (lines[lines.length - 1] === "") {
|
|
@@ -65787,12 +67119,12 @@ function generateTestCase(testCase) {
|
|
|
65787
67119
|
lines.push(` });`);
|
|
65788
67120
|
return lines.join("\n");
|
|
65789
67121
|
}
|
|
65790
|
-
function
|
|
65791
|
-
return suite.testCases.
|
|
67122
|
+
function renderableTestCases(suite) {
|
|
67123
|
+
return suite.testCases.filter((tc) => tc.assertions.length > 0);
|
|
65792
67124
|
}
|
|
65793
|
-
function generateFlowSpecFile(suite) {
|
|
67125
|
+
function generateFlowSpecFile(suite, testCases) {
|
|
65794
67126
|
const lines = [];
|
|
65795
|
-
const needsBeforeEach =
|
|
67127
|
+
const needsBeforeEach = testCases.some((tc) => tc.setupSteps.length > 0);
|
|
65796
67128
|
if (needsBeforeEach) {
|
|
65797
67129
|
lines.push("import { describe, it, beforeEach, expect } from 'vitest';");
|
|
65798
67130
|
} else {
|
|
@@ -65800,9 +67132,9 @@ function generateFlowSpecFile(suite) {
|
|
|
65800
67132
|
}
|
|
65801
67133
|
lines.push("");
|
|
65802
67134
|
lines.push(`describe('${escapeStringLiteral(suite.flowName)}', () => {`);
|
|
65803
|
-
for (let i = 0; i <
|
|
65804
|
-
lines.push(generateTestCase(
|
|
65805
|
-
if (i <
|
|
67135
|
+
for (let i = 0; i < testCases.length; i++) {
|
|
67136
|
+
lines.push(generateTestCase(testCases[i]));
|
|
67137
|
+
if (i < testCases.length - 1) {
|
|
65806
67138
|
lines.push("");
|
|
65807
67139
|
}
|
|
65808
67140
|
}
|
|
@@ -65816,15 +67148,12 @@ function generateAggregateSpecFile(aggregate) {
|
|
|
65816
67148
|
lines.push("");
|
|
65817
67149
|
lines.push(`describe('${escapeStringLiteral(aggregate.name)}', () => {`);
|
|
65818
67150
|
for (const command2 of aggregate.commands) {
|
|
65819
|
-
lines.push(` it('should handle ${escapeStringLiteral(command2.name)}'
|
|
65820
|
-
lines.push(` // TODO: implement`);
|
|
65821
|
-
lines.push(` });`);
|
|
67151
|
+
lines.push(` it.todo('should handle ${escapeStringLiteral(command2.name)}');`);
|
|
65822
67152
|
lines.push("");
|
|
65823
67153
|
}
|
|
65824
67154
|
for (const invariant of aggregate.invariants) {
|
|
65825
|
-
lines.push(`
|
|
65826
|
-
lines.push(`
|
|
65827
|
-
lines.push(` });`);
|
|
67155
|
+
lines.push(` // TODO: implement invariant violation test`);
|
|
67156
|
+
lines.push(` it.todo('should enforce invariant: ${escapeStringLiteral(invariant.description)}');`);
|
|
65828
67157
|
lines.push("");
|
|
65829
67158
|
}
|
|
65830
67159
|
if (lines[lines.length - 1] === "") {
|
|
@@ -65852,8 +67181,11 @@ var TestScaffoldEmitter = class {
|
|
|
65852
67181
|
const files = /* @__PURE__ */ new Map();
|
|
65853
67182
|
const specFilesWritten = [];
|
|
65854
67183
|
for (const suite of topology.suites) {
|
|
67184
|
+
const testCases = renderableTestCases(suite);
|
|
67185
|
+
if (testCases.length === 0)
|
|
67186
|
+
continue;
|
|
65855
67187
|
const fileName = `__tests__/flows/${safePathSegment2(suite.flowName)}.spec.ts`;
|
|
65856
|
-
const content = generateFlowSpecFile(suite);
|
|
67188
|
+
const content = generateFlowSpecFile(suite, testCases);
|
|
65857
67189
|
files.set(fileName, content);
|
|
65858
67190
|
specFilesWritten.push(fileName);
|
|
65859
67191
|
}
|
|
@@ -65861,6 +67193,8 @@ var TestScaffoldEmitter = class {
|
|
|
65861
67193
|
for (const context of ir.contexts) {
|
|
65862
67194
|
for (const aggregate of context.aggregates) {
|
|
65863
67195
|
allAggregates.push(aggregate);
|
|
67196
|
+
if (aggregate.commands.length === 0 && aggregate.invariants.length === 0)
|
|
67197
|
+
continue;
|
|
65864
67198
|
const contextDir = safePathSegment2(context.name);
|
|
65865
67199
|
const fileName = `__tests__/${contextDir}/${safePathSegment2(aggregate.name)}.spec.ts`;
|
|
65866
67200
|
const content = generateAggregateSpecFile(aggregate);
|
|
@@ -65877,6 +67211,31 @@ var TestScaffoldEmitter = class {
|
|
|
65877
67211
|
}
|
|
65878
67212
|
};
|
|
65879
67213
|
|
|
67214
|
+
// src/lib/flags.ts
|
|
67215
|
+
function collectUnknownFlags(tokens, knownOptions) {
|
|
67216
|
+
const known = new Set(knownOptions);
|
|
67217
|
+
const unknown = [];
|
|
67218
|
+
for (const token of tokens) {
|
|
67219
|
+
if (token.kind !== "option" || !token.name) continue;
|
|
67220
|
+
if (known.has(token.name)) continue;
|
|
67221
|
+
const raw = token.rawName ?? `--${token.name}`;
|
|
67222
|
+
if (!unknown.includes(raw)) unknown.push(raw);
|
|
67223
|
+
}
|
|
67224
|
+
return unknown;
|
|
67225
|
+
}
|
|
67226
|
+
function resolveStringFlag(values2, ...names) {
|
|
67227
|
+
for (const name of names) {
|
|
67228
|
+
const value = values2[name];
|
|
67229
|
+
if (typeof value === "string") return value;
|
|
67230
|
+
}
|
|
67231
|
+
return void 0;
|
|
67232
|
+
}
|
|
67233
|
+
function warnUnknownFlags(tokens, knownOptions, warn = (m) => console.warn(m)) {
|
|
67234
|
+
for (const flag of collectUnknownFlags(tokens, knownOptions)) {
|
|
67235
|
+
warn(`Warning: unrecognized flag ${flag} (ignored)`);
|
|
67236
|
+
}
|
|
67237
|
+
}
|
|
67238
|
+
|
|
65880
67239
|
// src/commands/generate.ts
|
|
65881
67240
|
var EMPTY2 = [];
|
|
65882
67241
|
function fail2(message) {
|
|
@@ -65891,16 +67250,21 @@ function readFile2(path) {
|
|
|
65891
67250
|
}
|
|
65892
67251
|
}
|
|
65893
67252
|
async function runGenerate(argv) {
|
|
65894
|
-
const
|
|
67253
|
+
const options = {
|
|
67254
|
+
out: { type: "string", short: "o" },
|
|
67255
|
+
// Alias for --out, symmetric with `moment simulate --out-dir`.
|
|
67256
|
+
"out-dir": { type: "string" }
|
|
67257
|
+
};
|
|
67258
|
+
const { values: values2, positionals, tokens } = parseArgs2({
|
|
65895
67259
|
args: argv,
|
|
65896
|
-
options
|
|
65897
|
-
out: { type: "string", short: "o" }
|
|
65898
|
-
},
|
|
67260
|
+
options,
|
|
65899
67261
|
allowPositionals: true,
|
|
65900
|
-
strict: false
|
|
67262
|
+
strict: false,
|
|
67263
|
+
tokens: true
|
|
65901
67264
|
});
|
|
67265
|
+
warnUnknownFlags(tokens, Object.keys(options));
|
|
65902
67266
|
const filePath = positionals[0];
|
|
65903
|
-
if (!filePath) return fail2("Usage: moment generate <file.moment> [--out <dir>]");
|
|
67267
|
+
if (!filePath) return fail2("Usage: moment generate <file.moment> [--out <dir> | --out-dir <dir>]");
|
|
65904
67268
|
const resolvedPath = resolve8(filePath);
|
|
65905
67269
|
if (!existsSync5(resolvedPath)) return fail2(`Error: File not found: ${resolvedPath}`);
|
|
65906
67270
|
const content = readFile2(resolvedPath);
|
|
@@ -65926,10 +67290,7 @@ async function runGenerate(argv) {
|
|
|
65926
67290
|
const docs = docGen.generate(ir);
|
|
65927
67291
|
const tsOutput = tsEmitter.emit(ir, { scope: { level: "system" } });
|
|
65928
67292
|
const scaffoldOutput = scaffoldEmitter.emit(ir, topology);
|
|
65929
|
-
const outDir = resolveOutputBaseDir(
|
|
65930
|
-
resolvedPath,
|
|
65931
|
-
typeof values2.out === "string" ? values2.out : void 0
|
|
65932
|
-
);
|
|
67293
|
+
const outDir = resolveOutputBaseDir(resolvedPath, resolveStringFlag(values2, "out-dir", "out"));
|
|
65933
67294
|
const allFiles = /* @__PURE__ */ new Map();
|
|
65934
67295
|
for (const [path, content2] of tsOutput.files) allFiles.set(path, content2);
|
|
65935
67296
|
for (const [path, content2] of scaffoldOutput.files) allFiles.set(path, content2);
|
|
@@ -69890,13 +71251,14 @@ function writeOutputFiles3(groups, ir, outDir) {
|
|
|
69890
71251
|
manifestScenarios.push({
|
|
69891
71252
|
scenarioId: scenario.scenarioId,
|
|
69892
71253
|
scenarioLabel: scenario.scenarioLabel,
|
|
71254
|
+
kind: scenario.kind,
|
|
69893
71255
|
description: scenario.description,
|
|
69894
71256
|
file: fileName,
|
|
69895
71257
|
eventCount: scenario.events.length,
|
|
69896
71258
|
pathLength: scenario.expectedPath.length,
|
|
69897
71259
|
branchCount: scenario.activeBranches.length,
|
|
69898
|
-
isHappyPath: scenario.
|
|
69899
|
-
isNegative: scenario.
|
|
71260
|
+
isHappyPath: scenario.kind === "happy",
|
|
71261
|
+
isNegative: scenario.kind === "negative"
|
|
69900
71262
|
});
|
|
69901
71263
|
}
|
|
69902
71264
|
manifestFlows.push({
|
|
@@ -69926,6 +71288,9 @@ function writeArtifacts(ir, outDir) {
|
|
|
69926
71288
|
const sagas = generateSagaStateMachines(ir);
|
|
69927
71289
|
files.sagaStateMachines = "saga-state-machines.json";
|
|
69928
71290
|
writeSafe(outDir, files.sagaStateMachines, JSON.stringify(sagas, null, 2) + "\n");
|
|
71291
|
+
const policies = generatePolicyDefinitions(ir);
|
|
71292
|
+
files.policyDefinitions = "policy-definitions.json";
|
|
71293
|
+
writeSafe(outDir, files.policyDefinitions, JSON.stringify(policies, null, 2) + "\n");
|
|
69929
71294
|
const asyncapi = generateAsyncApiSpec(ir);
|
|
69930
71295
|
files.asyncApi = "asyncapi.yaml";
|
|
69931
71296
|
writeSafe(outDir, files.asyncApi, asyncapi);
|
|
@@ -69937,7 +71302,13 @@ function kebab3(s) {
|
|
|
69937
71302
|
function runOutDirWrite(flows, ir, outDir, includeAll) {
|
|
69938
71303
|
const groups = flows.map((flow) => ({
|
|
69939
71304
|
flow,
|
|
69940
|
-
scenarios: includeAll ? [
|
|
71305
|
+
scenarios: includeAll ? [
|
|
71306
|
+
...generateAllScenarios(ir, flow),
|
|
71307
|
+
...deriveNegativeScenarios(ir, flow),
|
|
71308
|
+
// Saga-timeout scenarios: neither happy nor negative — the manifest
|
|
71309
|
+
// carries kind:'timeout' with both flags false.
|
|
71310
|
+
...deriveTimeoutScenarios(ir, flow)
|
|
71311
|
+
] : [generateSimulationScenario(ir, flow)]
|
|
69941
71312
|
}));
|
|
69942
71313
|
try {
|
|
69943
71314
|
return writeOutputFiles3(groups, ir, outDir);
|
|
@@ -69947,17 +71318,22 @@ function runOutDirWrite(flows, ir, outDir, includeAll) {
|
|
|
69947
71318
|
}
|
|
69948
71319
|
}
|
|
69949
71320
|
async function runSimulate(argv) {
|
|
69950
|
-
const
|
|
71321
|
+
const options = {
|
|
71322
|
+
json: { type: "boolean" },
|
|
71323
|
+
flow: { type: "string" },
|
|
71324
|
+
all: { type: "boolean" },
|
|
71325
|
+
"out-dir": { type: "string" },
|
|
71326
|
+
// Alias for --out-dir, symmetric with `moment generate --out`.
|
|
71327
|
+
out: { type: "string" }
|
|
71328
|
+
};
|
|
71329
|
+
const { values: values2, positionals, tokens } = parseArgs18({
|
|
69951
71330
|
args: argv,
|
|
69952
|
-
options
|
|
69953
|
-
json: { type: "boolean" },
|
|
69954
|
-
flow: { type: "string" },
|
|
69955
|
-
all: { type: "boolean" },
|
|
69956
|
-
"out-dir": { type: "string" }
|
|
69957
|
-
},
|
|
71331
|
+
options,
|
|
69958
71332
|
allowPositionals: true,
|
|
69959
|
-
strict: false
|
|
71333
|
+
strict: false,
|
|
71334
|
+
tokens: true
|
|
69960
71335
|
});
|
|
71336
|
+
warnUnknownFlags(tokens, Object.keys(options));
|
|
69961
71337
|
const filePath = positionals[0];
|
|
69962
71338
|
if (!filePath)
|
|
69963
71339
|
return fail16(
|
|
@@ -69984,13 +71360,14 @@ async function runSimulate(argv) {
|
|
|
69984
71360
|
if (targetFlows.length === 0) {
|
|
69985
71361
|
return fail16(`Flow '${values2.flow}' not found.`);
|
|
69986
71362
|
}
|
|
69987
|
-
const outDir = values2
|
|
71363
|
+
const outDir = resolveStringFlag(values2, "out-dir", "out");
|
|
69988
71364
|
if (outDir) {
|
|
69989
71365
|
return runOutDirWrite(targetFlows, ir, outDir, values2.all === true);
|
|
69990
71366
|
}
|
|
69991
71367
|
const scenarios = values2.all ? targetFlows.flatMap((flow) => [
|
|
69992
71368
|
...generateAllScenarios(ir, flow),
|
|
69993
|
-
...deriveNegativeScenarios(ir, flow)
|
|
71369
|
+
...deriveNegativeScenarios(ir, flow),
|
|
71370
|
+
...deriveTimeoutScenarios(ir, flow)
|
|
69994
71371
|
]) : targetFlows.map((flow) => generateSimulationScenario(ir, flow));
|
|
69995
71372
|
return formatScenarios(scenarios, values2.json === true);
|
|
69996
71373
|
}
|
|
@@ -70000,8 +71377,8 @@ function getClientId() {
|
|
|
70000
71377
|
if (process.env.MOMENT_GITHUB_CLIENT_ID) {
|
|
70001
71378
|
return process.env.MOMENT_GITHUB_CLIENT_ID;
|
|
70002
71379
|
}
|
|
70003
|
-
if ("
|
|
70004
|
-
return "
|
|
71380
|
+
if ("") {
|
|
71381
|
+
return "";
|
|
70005
71382
|
}
|
|
70006
71383
|
throw new Error(
|
|
70007
71384
|
"GitHub App client ID not configured. Set MOMENT_GITHUB_CLIENT_ID or build with GH_APP_CLIENT_ID."
|