eventmodeler 0.5.0 → 0.6.1

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.
Files changed (150) hide show
  1. package/dist/index.js +6776 -2132
  2. package/package.json +11 -5
  3. package/dist/api/index.d.ts +0 -285
  4. package/dist/api/index.js +0 -323
  5. package/dist/cloud/slices/index.d.ts +0 -276
  6. package/dist/cloud/slices/index.js +0 -406
  7. package/dist/eventmodeler.js +0 -5646
  8. package/dist/formatters.d.ts +0 -17
  9. package/dist/formatters.js +0 -482
  10. package/dist/index.d.ts +0 -2
  11. package/dist/lib/auth.d.ts +0 -24
  12. package/dist/lib/auth.js +0 -331
  13. package/dist/lib/backend.d.ts +0 -43
  14. package/dist/lib/backend.js +0 -73
  15. package/dist/lib/chapter-utils.d.ts +0 -13
  16. package/dist/lib/chapter-utils.js +0 -71
  17. package/dist/lib/cloud-client.d.ts +0 -69
  18. package/dist/lib/cloud-client.js +0 -364
  19. package/dist/lib/config.d.ts +0 -30
  20. package/dist/lib/config.js +0 -95
  21. package/dist/lib/diff/merge-rules.d.ts +0 -45
  22. package/dist/lib/diff/merge-rules.js +0 -210
  23. package/dist/lib/diff/model-differ.d.ts +0 -8
  24. package/dist/lib/diff/model-differ.js +0 -568
  25. package/dist/lib/diff/three-way-merge.d.ts +0 -7
  26. package/dist/lib/diff/three-way-merge.js +0 -390
  27. package/dist/lib/diff/types.d.ts +0 -75
  28. package/dist/lib/diff/types.js +0 -1
  29. package/dist/lib/element-lookup.d.ts +0 -58
  30. package/dist/lib/element-lookup.js +0 -126
  31. package/dist/lib/file-loader.d.ts +0 -8
  32. package/dist/lib/file-loader.js +0 -108
  33. package/dist/lib/flow-utils.d.ts +0 -53
  34. package/dist/lib/flow-utils.js +0 -348
  35. package/dist/lib/format.d.ts +0 -10
  36. package/dist/lib/format.js +0 -23
  37. package/dist/lib/project-config.d.ts +0 -27
  38. package/dist/lib/project-config.js +0 -83
  39. package/dist/lib/slice-utils.d.ts +0 -59
  40. package/dist/lib/slice-utils.js +0 -140
  41. package/dist/local/slices/index.d.ts +0 -11
  42. package/dist/local/slices/index.js +0 -13
  43. package/dist/projection.d.ts +0 -3
  44. package/dist/projection.js +0 -828
  45. package/dist/slices/add-field/index.d.ts +0 -8
  46. package/dist/slices/add-field/index.js +0 -211
  47. package/dist/slices/add-scenario/index.d.ts +0 -27
  48. package/dist/slices/add-scenario/index.js +0 -307
  49. package/dist/slices/codegen-chapter-events/index.d.ts +0 -2
  50. package/dist/slices/codegen-chapter-events/index.js +0 -145
  51. package/dist/slices/codegen-slice/index.d.ts +0 -2
  52. package/dist/slices/codegen-slice/index.js +0 -448
  53. package/dist/slices/create-automation-slice/index.d.ts +0 -2
  54. package/dist/slices/create-automation-slice/index.js +0 -304
  55. package/dist/slices/create-flow/index.d.ts +0 -2
  56. package/dist/slices/create-flow/index.js +0 -183
  57. package/dist/slices/create-state-change-slice/index.d.ts +0 -2
  58. package/dist/slices/create-state-change-slice/index.js +0 -263
  59. package/dist/slices/create-state-view-slice/index.d.ts +0 -2
  60. package/dist/slices/create-state-view-slice/index.js +0 -128
  61. package/dist/slices/diff/index.d.ts +0 -11
  62. package/dist/slices/diff/index.js +0 -293
  63. package/dist/slices/export-eventmodel-to-json/index.d.ts +0 -2
  64. package/dist/slices/export-eventmodel-to-json/index.js +0 -355
  65. package/dist/slices/git/index.d.ts +0 -2
  66. package/dist/slices/git/index.js +0 -125
  67. package/dist/slices/guide/guides/codegen.d.ts +0 -5
  68. package/dist/slices/guide/guides/codegen.js +0 -339
  69. package/dist/slices/guide/guides/connect-slices.d.ts +0 -5
  70. package/dist/slices/guide/guides/connect-slices.js +0 -202
  71. package/dist/slices/guide/guides/create-slices.d.ts +0 -5
  72. package/dist/slices/guide/guides/create-slices.js +0 -303
  73. package/dist/slices/guide/guides/explore.d.ts +0 -5
  74. package/dist/slices/guide/guides/explore.js +0 -251
  75. package/dist/slices/guide/guides/information-flow.d.ts +0 -5
  76. package/dist/slices/guide/guides/information-flow.js +0 -318
  77. package/dist/slices/guide/guides/scenarios.d.ts +0 -5
  78. package/dist/slices/guide/guides/scenarios.js +0 -269
  79. package/dist/slices/guide/index.d.ts +0 -1
  80. package/dist/slices/guide/index.js +0 -40
  81. package/dist/slices/import/index.d.ts +0 -8
  82. package/dist/slices/import/index.js +0 -63
  83. package/dist/slices/init/index.d.ts +0 -5
  84. package/dist/slices/init/index.js +0 -80
  85. package/dist/slices/list-chapters/index.d.ts +0 -3
  86. package/dist/slices/list-chapters/index.js +0 -21
  87. package/dist/slices/list-commands/index.d.ts +0 -3
  88. package/dist/slices/list-commands/index.js +0 -20
  89. package/dist/slices/list-events/index.d.ts +0 -3
  90. package/dist/slices/list-events/index.js +0 -98
  91. package/dist/slices/list-processors/index.d.ts +0 -3
  92. package/dist/slices/list-processors/index.js +0 -20
  93. package/dist/slices/list-readmodels/index.d.ts +0 -3
  94. package/dist/slices/list-readmodels/index.js +0 -21
  95. package/dist/slices/list-scenarios/index.d.ts +0 -3
  96. package/dist/slices/list-scenarios/index.js +0 -35
  97. package/dist/slices/list-screens/index.d.ts +0 -3
  98. package/dist/slices/list-screens/index.js +0 -47
  99. package/dist/slices/list-slices/index.d.ts +0 -3
  100. package/dist/slices/list-slices/index.js +0 -35
  101. package/dist/slices/login/index.d.ts +0 -1
  102. package/dist/slices/login/index.js +0 -20
  103. package/dist/slices/logout/index.d.ts +0 -1
  104. package/dist/slices/logout/index.js +0 -14
  105. package/dist/slices/map-fields/index.d.ts +0 -2
  106. package/dist/slices/map-fields/index.js +0 -269
  107. package/dist/slices/mark-slice-status/index.d.ts +0 -2
  108. package/dist/slices/mark-slice-status/index.js +0 -31
  109. package/dist/slices/merge/index.d.ts +0 -19
  110. package/dist/slices/merge/index.js +0 -147
  111. package/dist/slices/open-app/index.d.ts +0 -1
  112. package/dist/slices/open-app/index.js +0 -36
  113. package/dist/slices/remove-field/index.d.ts +0 -8
  114. package/dist/slices/remove-field/index.js +0 -167
  115. package/dist/slices/remove-scenario/index.d.ts +0 -2
  116. package/dist/slices/remove-scenario/index.js +0 -77
  117. package/dist/slices/search/index.d.ts +0 -3
  118. package/dist/slices/search/index.js +0 -302
  119. package/dist/slices/show-actor/index.d.ts +0 -4
  120. package/dist/slices/show-actor/index.js +0 -115
  121. package/dist/slices/show-aggregate/index.d.ts +0 -3
  122. package/dist/slices/show-aggregate/index.js +0 -108
  123. package/dist/slices/show-aggregate-completeness/index.d.ts +0 -4
  124. package/dist/slices/show-aggregate-completeness/index.js +0 -181
  125. package/dist/slices/show-chapter/index.d.ts +0 -3
  126. package/dist/slices/show-chapter/index.js +0 -195
  127. package/dist/slices/show-command/index.d.ts +0 -3
  128. package/dist/slices/show-command/index.js +0 -133
  129. package/dist/slices/show-completeness/index.d.ts +0 -4
  130. package/dist/slices/show-completeness/index.js +0 -731
  131. package/dist/slices/show-event/index.d.ts +0 -3
  132. package/dist/slices/show-event/index.js +0 -118
  133. package/dist/slices/show-model-summary/index.d.ts +0 -3
  134. package/dist/slices/show-model-summary/index.js +0 -31
  135. package/dist/slices/show-processor/index.d.ts +0 -3
  136. package/dist/slices/show-processor/index.js +0 -111
  137. package/dist/slices/show-readmodel/index.d.ts +0 -3
  138. package/dist/slices/show-readmodel/index.js +0 -158
  139. package/dist/slices/show-scenario/index.d.ts +0 -3
  140. package/dist/slices/show-scenario/index.js +0 -196
  141. package/dist/slices/show-screen/index.d.ts +0 -3
  142. package/dist/slices/show-screen/index.js +0 -139
  143. package/dist/slices/show-slice/index.d.ts +0 -3
  144. package/dist/slices/show-slice/index.js +0 -696
  145. package/dist/slices/update-field/index.d.ts +0 -15
  146. package/dist/slices/update-field/index.js +0 -208
  147. package/dist/slices/whoami/index.d.ts +0 -2
  148. package/dist/slices/whoami/index.js +0 -44
  149. package/dist/types.d.ts +0 -195
  150. package/dist/types.js +0 -1
@@ -1,145 +0,0 @@
1
- import { outputJson } from '../../lib/format.js';
2
- import { findElementOrExit } from '../../lib/element-lookup.js';
3
- import { getChapterHierarchy } from '../../lib/chapter-utils.js';
4
- function countFieldsDeep(fields) {
5
- if (!fields || fields.length === 0) {
6
- return 0;
7
- }
8
- return fields.reduce((count, field) => count + 1 + countFieldsDeep(field.subfields), 0);
9
- }
10
- function normalizeName(name) {
11
- return name.trim().toLowerCase();
12
- }
13
- function fieldToJson(field) {
14
- const result = {
15
- name: field.name,
16
- type: field.fieldType,
17
- };
18
- if (field.isList)
19
- result.list = true;
20
- if (field.isGenerated)
21
- result.generated = true;
22
- if (field.isOptional)
23
- result.optional = true;
24
- if (field.isUserInput)
25
- result.userInput = true;
26
- if (field.subfields && field.subfields.length > 0) {
27
- result.subfields = field.subfields.map(fieldToJson);
28
- }
29
- return result;
30
- }
31
- function isCenterInSlice(slice, x, y, width, height) {
32
- const centerX = x + width / 2;
33
- const centerY = y + height / 2;
34
- return (centerX >= slice.position.x &&
35
- centerX <= slice.position.x + slice.size.width &&
36
- centerY >= slice.position.y &&
37
- centerY <= slice.position.y + slice.size.height);
38
- }
39
- function findAggregateForEvent(model, event) {
40
- const centerX = event.position.x + event.width / 2;
41
- const centerY = event.position.y + event.height / 2;
42
- for (const aggregate of model.aggregates.values()) {
43
- if (centerX >= aggregate.position.x &&
44
- centerX <= aggregate.position.x + aggregate.size.width &&
45
- centerY >= aggregate.position.y &&
46
- centerY <= aggregate.position.y + aggregate.size.height) {
47
- return aggregate.name;
48
- }
49
- }
50
- return undefined;
51
- }
52
- function determineSliceType(model, slice) {
53
- const hasProcessors = [...model.processors.values()].some(processor => isCenterInSlice(slice, processor.position.x, processor.position.y, processor.width, processor.height));
54
- if (hasProcessors) {
55
- return 'AUTOMATION';
56
- }
57
- const hasCommands = [...model.commands.values()].some(command => isCenterInSlice(slice, command.position.x, command.position.y, command.width, command.height));
58
- const hasEvents = [...model.events.values()].some(event => !event.originalNodeId && isCenterInSlice(slice, event.position.x, event.position.y, event.width, event.height));
59
- if (hasCommands && hasEvents) {
60
- return 'STATE_CHANGE';
61
- }
62
- return 'STATE_VIEW';
63
- }
64
- function getSlicesUnderChapter(model, chapter) {
65
- const chapterLeft = chapter.position.x;
66
- const chapterRight = chapter.position.x + chapter.size.width;
67
- return [...model.slices.values()].filter(slice => {
68
- const sliceCenterX = slice.position.x + slice.size.width / 2;
69
- return sliceCenterX >= chapterLeft && sliceCenterX <= chapterRight;
70
- });
71
- }
72
- function codegenChapterEvents(model, chapterName) {
73
- const chapter = findElementOrExit(model.chapters, chapterName, 'chapter');
74
- const chapterHierarchy = getChapterHierarchy(model, chapter);
75
- const slices = getSlicesUnderChapter(model, chapter).sort((a, b) => a.position.x - b.position.x);
76
- outputEventsFromSlices(model, slices, chapterHierarchy);
77
- }
78
- export function codegenEvents(model, chapterName) {
79
- if (chapterName) {
80
- codegenChapterEvents(model, chapterName);
81
- return;
82
- }
83
- const slices = [...model.slices.values()].sort((a, b) => {
84
- if (a.position.x === b.position.x) {
85
- return a.position.y - b.position.y;
86
- }
87
- return a.position.x - b.position.x;
88
- });
89
- outputEventsFromSlices(model, slices, null);
90
- }
91
- function outputEventsFromSlices(model, slices, chapterHierarchy) {
92
- const eventsByName = new Map();
93
- const sliceSummaries = [];
94
- for (const slice of slices) {
95
- sliceSummaries.push({
96
- id: slice.id,
97
- name: slice.name,
98
- sliceType: determineSliceType(model, slice),
99
- });
100
- const sliceEvents = [...model.events.values()].filter(event => !event.originalNodeId &&
101
- isCenterInSlice(slice, event.position.x, event.position.y, event.width, event.height));
102
- for (const event of sliceEvents) {
103
- const key = normalizeName(event.name);
104
- if (!key) {
105
- continue;
106
- }
107
- const eventFields = event.fields.map(fieldToJson);
108
- const existing = eventsByName.get(key);
109
- if (!existing) {
110
- eventsByName.set(key, {
111
- id: event.id,
112
- name: event.name,
113
- fields: eventFields,
114
- aggregate: findAggregateForEvent(model, event),
115
- sourceSlices: [slice.name],
116
- });
117
- continue;
118
- }
119
- if (!existing.sourceSlices.includes(slice.name)) {
120
- existing.sourceSlices.push(slice.name);
121
- }
122
- if (!existing.aggregate) {
123
- existing.aggregate = findAggregateForEvent(model, event);
124
- }
125
- if (countFieldsDeep(eventFields) > countFieldsDeep(existing.fields)) {
126
- existing.fields = eventFields;
127
- }
128
- if (!existing.id) {
129
- existing.id = event.id;
130
- }
131
- }
132
- }
133
- const events = [...eventsByName.values()]
134
- .map(event => ({ ...event, sourceSlices: [...event.sourceSlices].sort((a, b) => a.localeCompare(b)) }))
135
- .sort((a, b) => a.name.localeCompare(b.name));
136
- const sortedSlices = [...sliceSummaries].sort((a, b) => a.name.localeCompare(b.name));
137
- const output = {
138
- chapter: chapterHierarchy,
139
- sliceCount: sortedSlices.length,
140
- eventCount: events.length,
141
- slices: sortedSlices,
142
- events,
143
- };
144
- outputJson(output);
145
- }
@@ -1,2 +0,0 @@
1
- import type { EventModel } from '../../types.js';
2
- export declare function codegenSlice(model: EventModel, sliceName: string): void;
@@ -1,448 +0,0 @@
1
- import { outputJson } from '../../lib/format.js';
2
- import { findElementOrExit } from '../../lib/element-lookup.js';
3
- import { findChapterForSlice, getChapterHierarchy } from '../../lib/chapter-utils.js';
4
- // Get components inside a slice by checking if center point is within bounds
5
- function getSliceComponents(model, slice) {
6
- const bounds = {
7
- left: slice.position.x,
8
- right: slice.position.x + slice.size.width,
9
- top: slice.position.y,
10
- bottom: slice.position.y + slice.size.height,
11
- };
12
- function isInSlice(pos, width, height) {
13
- const centerX = pos.x + width / 2;
14
- const centerY = pos.y + height / 2;
15
- return centerX >= bounds.left && centerX <= bounds.right && centerY >= bounds.top && centerY <= bounds.bottom;
16
- }
17
- // Only include canonical elements - linked copies are UI-only conveniences
18
- // and should not appear as slice contents in codegen output
19
- return {
20
- commands: [...model.commands.values()].filter(c => isInSlice(c.position, c.width, c.height)),
21
- events: [...model.events.values()].filter(e => !e.originalNodeId && isInSlice(e.position, e.width, e.height)),
22
- readModels: [...model.readModels.values()].filter(rm => !rm.originalNodeId && isInSlice(rm.position, rm.width, rm.height)),
23
- screens: [...model.screens.values()].filter(s => !s.originalNodeId && isInSlice(s.position, s.width, s.height)),
24
- processors: [...model.processors.values()].filter(p => isInSlice(p.position, p.width, p.height)),
25
- };
26
- }
27
- // Find which slice contains a node
28
- function findSliceForNode(model, nodeId) {
29
- const event = model.events.get(nodeId);
30
- const readModel = model.readModels.get(nodeId);
31
- const screen = model.screens.get(nodeId);
32
- const command = model.commands.get(nodeId);
33
- const processor = model.processors.get(nodeId);
34
- const node = event ?? readModel ?? screen ?? command ?? processor;
35
- if (!node)
36
- return null;
37
- for (const slice of model.slices.values()) {
38
- const centerX = node.position.x + node.width / 2;
39
- const centerY = node.position.y + node.height / 2;
40
- if (centerX >= slice.position.x &&
41
- centerX <= slice.position.x + slice.size.width &&
42
- centerY >= slice.position.y &&
43
- centerY <= slice.position.y + slice.size.height) {
44
- return slice;
45
- }
46
- }
47
- return null;
48
- }
49
- // Find which aggregate an event belongs to
50
- function findAggregateForEvent(model, event) {
51
- const centerX = event.position.x + event.width / 2;
52
- const centerY = event.position.y + event.height / 2;
53
- for (const aggregate of model.aggregates.values()) {
54
- if (centerX >= aggregate.position.x &&
55
- centerX <= aggregate.position.x + aggregate.size.width &&
56
- centerY >= aggregate.position.y &&
57
- centerY <= aggregate.position.y + aggregate.size.height) {
58
- return aggregate.name;
59
- }
60
- }
61
- return undefined;
62
- }
63
- // Find which actor a screen belongs to
64
- function findActorForScreen(model, screen) {
65
- const centerX = screen.position.x + screen.width / 2;
66
- const centerY = screen.position.y + screen.height / 2;
67
- for (const actor of model.actors.values()) {
68
- if (centerX >= actor.position.x &&
69
- centerX <= actor.position.x + actor.size.width &&
70
- centerY >= actor.position.y &&
71
- centerY <= actor.position.y + actor.size.height) {
72
- return actor.name;
73
- }
74
- }
75
- return undefined;
76
- }
77
- // Convert Field to JSON-friendly format
78
- function fieldToJson(field) {
79
- const result = {
80
- name: field.name,
81
- type: field.fieldType,
82
- };
83
- if (field.isList)
84
- result.list = true;
85
- if (field.isGenerated)
86
- result.generated = true;
87
- if (field.isOptional)
88
- result.optional = true;
89
- if (field.isUserInput)
90
- result.userInput = true;
91
- if (field.subfields && field.subfields.length > 0) {
92
- result.subfields = field.subfields.map(fieldToJson);
93
- }
94
- return result;
95
- }
96
- // Determine slice type based on components, returns null for invalid configurations
97
- function determineSliceType(hasProcessors, hasCommands, hasEvents, hasReadModels, hasScreens) {
98
- // AUTOMATION: Must have a Processor (and typically ReadModel, Command, Event)
99
- if (hasProcessors)
100
- return 'AUTOMATION';
101
- // STATE_CHANGE: Must have both Command and Event (typically with Screen)
102
- if (hasCommands && hasEvents)
103
- return 'STATE_CHANGE';
104
- // STATE_VIEW: Must have at least one ReadModel
105
- if (hasReadModels && !hasCommands && !hasEvents)
106
- return 'STATE_VIEW';
107
- // Invalid configurations:
108
- // - Empty slice
109
- // - Only Command (no Event)
110
- // - Only Event (no Command)
111
- // - Only Screen (no Command)
112
- return null;
113
- }
114
- // Get element type for an ID
115
- function getElementType(model, id) {
116
- if (model.commands.has(id))
117
- return 'COMMAND';
118
- if (model.events.has(id))
119
- return 'EVENT';
120
- if (model.readModels.has(id))
121
- return 'READMODEL';
122
- if (model.screens.has(id))
123
- return 'SCREEN';
124
- if (model.processors.has(id))
125
- return 'PROCESSOR';
126
- return null;
127
- }
128
- // Get element name for an ID
129
- function getElementName(model, id) {
130
- return (model.commands.get(id)?.name ??
131
- model.events.get(id)?.name ??
132
- model.readModels.get(id)?.name ??
133
- model.screens.get(id)?.name ??
134
- model.processors.get(id)?.name ??
135
- 'Unknown');
136
- }
137
- // Get element fields for an ID
138
- function getElementFields(model, id) {
139
- return (model.commands.get(id)?.fields ??
140
- model.events.get(id)?.fields ??
141
- model.readModels.get(id)?.fields ??
142
- model.screens.get(id)?.fields ??
143
- model.processors.get(id)?.fields ??
144
- []);
145
- }
146
- // Find a field by ID within an element's fields
147
- function findFieldById(fields, fieldId) {
148
- for (const field of fields) {
149
- if (field.id === fieldId)
150
- return field;
151
- if (field.subfields) {
152
- const found = findFieldById(field.subfields, fieldId);
153
- if (found)
154
- return found;
155
- }
156
- }
157
- return undefined;
158
- }
159
- // Get element reference (type, id, name)
160
- function getElementRef(model, id) {
161
- return {
162
- type: getElementType(model, id) ?? 'EVENT',
163
- id,
164
- name: getElementName(model, id),
165
- };
166
- }
167
- // Get element with full schema
168
- function getElementWithSchema(model, id) {
169
- const type = getElementType(model, id) ?? 'EVENT';
170
- const name = getElementName(model, id);
171
- const fields = getElementFields(model, id).map(fieldToJson);
172
- const result = { type, id, name, fields };
173
- // Add aggregate info for events
174
- const event = model.events.get(id);
175
- if (event) {
176
- const aggregate = findAggregateForEvent(model, event);
177
- if (aggregate)
178
- result.aggregate = aggregate;
179
- const originSlice = findSliceForNode(model, id);
180
- if (originSlice)
181
- result.originSlice = originSlice.name;
182
- }
183
- // Add actor info for screens
184
- const screen = model.screens.get(id);
185
- if (screen) {
186
- const actor = findActorForScreen(model, screen);
187
- if (actor)
188
- result.actor = actor;
189
- }
190
- return result;
191
- }
192
- // Enrich field mappings with field names
193
- function enrichFieldMappings(model, flow) {
194
- const sourceFields = getElementFields(model, flow.sourceId);
195
- const targetFields = getElementFields(model, flow.targetId);
196
- return flow.fieldMappings.map(mapping => {
197
- const sourceField = findFieldById(sourceFields, mapping.sourceFieldId);
198
- const targetField = findFieldById(targetFields, mapping.targetFieldId);
199
- return {
200
- sourceFieldId: mapping.sourceFieldId,
201
- sourceFieldName: sourceField?.name ?? 'unknown',
202
- targetFieldId: mapping.targetFieldId,
203
- targetFieldName: targetField?.name ?? 'unknown',
204
- };
205
- });
206
- }
207
- // Get inbound dependencies (flows where target is in slice but source is not)
208
- function getInboundDependencies(model, componentIds) {
209
- return [...model.flows.values()]
210
- .filter(f => componentIds.has(f.targetId) && !componentIds.has(f.sourceId))
211
- .map(flow => ({
212
- flowId: flow.id,
213
- flowType: flow.flowType,
214
- source: getElementWithSchema(model, flow.sourceId),
215
- target: getElementRef(model, flow.targetId),
216
- fieldMappings: enrichFieldMappings(model, flow),
217
- }));
218
- }
219
- // Get internal flows (both source and target are in slice)
220
- function getInternalFlows(model, componentIds) {
221
- return [...model.flows.values()]
222
- .filter(f => componentIds.has(f.sourceId) && componentIds.has(f.targetId))
223
- .map(flow => ({
224
- flowId: flow.id,
225
- flowType: flow.flowType,
226
- source: getElementRef(model, flow.sourceId),
227
- target: getElementRef(model, flow.targetId),
228
- fieldMappings: enrichFieldMappings(model, flow),
229
- }));
230
- }
231
- // Format scenario then clause
232
- function formatScenarioThen(model, then) {
233
- if (then.type === 'error') {
234
- return {
235
- type: 'error',
236
- errorType: then.errorType,
237
- errorMessage: then.errorMessage,
238
- };
239
- }
240
- if (then.type === 'events' && then.expectedEvents) {
241
- return {
242
- type: 'events',
243
- expectedEvents: then.expectedEvents.map(expected => {
244
- const event = model.events.get(expected.eventStickyId);
245
- return {
246
- eventId: expected.eventStickyId,
247
- eventName: event?.name ?? 'UnknownEvent',
248
- eventSchema: { fields: event?.fields.map(fieldToJson) ?? [] },
249
- fieldValues: expected.fieldValues ?? {},
250
- };
251
- }),
252
- };
253
- }
254
- if (then.type === 'command' && then.expectedCommand) {
255
- const command = model.commands.get(then.expectedCommand.commandStickyId);
256
- return {
257
- type: 'command',
258
- expectedCommand: {
259
- commandId: then.expectedCommand.commandStickyId,
260
- commandName: command?.name ?? 'UnknownCommand',
261
- commandSchema: { fields: command?.fields.map(fieldToJson) ?? [] },
262
- fieldValues: then.expectedCommand.fieldValues ?? {},
263
- },
264
- };
265
- }
266
- if (then.type === 'noCommand') {
267
- return {
268
- type: 'noCommand',
269
- };
270
- }
271
- if (then.type === 'readModelAssertion' && then.readModelAssertion) {
272
- const rm = model.readModels.get(then.readModelAssertion.readModelStickyId);
273
- return {
274
- type: 'readModelAssertion',
275
- readModelName: rm?.name ?? 'UnknownReadModel',
276
- expectedFieldValues: then.readModelAssertion.expectedFieldValues,
277
- };
278
- }
279
- // Default fallback
280
- return { type: 'events', expectedEvents: [] };
281
- }
282
- // Format scenarios with resolved schemas
283
- function formatScenarios(model, scenarios) {
284
- return scenarios.map(scenario => ({
285
- id: scenario.id,
286
- name: scenario.name,
287
- description: scenario.description,
288
- given: scenario.givenEvents.map(ref => {
289
- const event = model.events.get(ref.eventStickyId);
290
- const originSlice = findSliceForNode(model, ref.eventStickyId);
291
- return {
292
- eventId: ref.eventStickyId,
293
- eventName: event?.name ?? 'UnknownEvent',
294
- originSlice: originSlice?.name ?? null,
295
- eventSchema: { fields: event?.fields.map(fieldToJson) ?? [] },
296
- fieldValues: ref.fieldValues ?? {},
297
- };
298
- }),
299
- whenCommand: scenario.whenCommand
300
- ? {
301
- commandId: scenario.whenCommand.commandStickyId,
302
- commandName: model.commands.get(scenario.whenCommand.commandStickyId)?.name ?? 'UnknownCommand',
303
- fieldValues: scenario.whenCommand.fieldValues ?? {},
304
- }
305
- : null,
306
- whenEvents: scenario.whenEvents.map(ref => {
307
- const event = model.events.get(ref.eventStickyId);
308
- const originSlice = findSliceForNode(model, ref.eventStickyId);
309
- return {
310
- eventId: ref.eventStickyId,
311
- eventName: event?.name ?? 'UnknownEvent',
312
- originSlice: originSlice?.name ?? null,
313
- eventSchema: { fields: event?.fields.map(fieldToJson) ?? [] },
314
- fieldValues: ref.fieldValues ?? {},
315
- };
316
- }),
317
- then: formatScenarioThen(model, scenario.then),
318
- }));
319
- }
320
- export function codegenSlice(model, sliceName) {
321
- // 1. Find the slice
322
- const slice = findElementOrExit(model.slices, sliceName, 'slice');
323
- // 2. Get components inside slice
324
- const components = getSliceComponents(model, slice);
325
- // 3. Build component ID set (including canonical group members for linked copies)
326
- const componentIds = new Set();
327
- components.commands.forEach(c => componentIds.add(c.id));
328
- components.events.forEach(e => {
329
- componentIds.add(e.id);
330
- // If this is a linked copy, also add all elements in the same canonical group
331
- if (e.canonicalId) {
332
- for (const evt of model.events.values()) {
333
- if (evt.canonicalId === e.canonicalId) {
334
- componentIds.add(evt.id);
335
- }
336
- }
337
- }
338
- });
339
- components.readModels.forEach(rm => {
340
- componentIds.add(rm.id);
341
- // If this is a linked copy, also add all elements in the same canonical group
342
- if (rm.canonicalId) {
343
- for (const r of model.readModels.values()) {
344
- if (r.canonicalId === rm.canonicalId) {
345
- componentIds.add(r.id);
346
- }
347
- }
348
- }
349
- });
350
- components.screens.forEach(s => {
351
- componentIds.add(s.id);
352
- // If this is a linked copy, also add all elements in the same canonical group
353
- if (s.canonicalId) {
354
- for (const scr of model.screens.values()) {
355
- if (scr.canonicalId === s.canonicalId) {
356
- componentIds.add(scr.id);
357
- }
358
- }
359
- }
360
- });
361
- components.processors.forEach(p => componentIds.add(p.id));
362
- // 4. Determine slice type
363
- const sliceType = determineSliceType(components.processors.length > 0, components.commands.length > 0, components.events.length > 0, components.readModels.length > 0, components.screens.length > 0);
364
- // Validate slice type - exit with error for invalid configurations
365
- if (sliceType === null) {
366
- const hasAny = componentIds.size > 0;
367
- if (!hasAny) {
368
- console.error(`Error: Slice "${slice.name}" is empty - no elements found inside slice bounds`);
369
- }
370
- else {
371
- const parts = [];
372
- if (components.commands.length > 0)
373
- parts.push(`${components.commands.length} command(s)`);
374
- if (components.events.length > 0)
375
- parts.push(`${components.events.length} event(s)`);
376
- if (components.screens.length > 0)
377
- parts.push(`${components.screens.length} screen(s)`);
378
- if (components.readModels.length > 0)
379
- parts.push(`${components.readModels.length} read model(s)`);
380
- console.error(`Error: Slice "${slice.name}" has invalid configuration for codegen: ${parts.join(', ')}`);
381
- console.error('Valid configurations:');
382
- console.error(' AUTOMATION: Processor + ReadModel + Command + Event');
383
- console.error(' STATE_CHANGE: Screen + Command + Event');
384
- console.error(' STATE_VIEW: ReadModel only');
385
- }
386
- process.exit(1);
387
- }
388
- // 5. Get inbound dependencies with full schemas
389
- const inboundDependencies = getInboundDependencies(model, componentIds);
390
- // 6. Get internal flows with field mappings
391
- const internalFlows = getInternalFlows(model, componentIds);
392
- // 7. Get scenarios for this slice
393
- const scenarios = [...model.scenarios.values()].filter(s => s.sliceId === slice.id);
394
- // 8. Find which chapter this slice belongs to
395
- const chapter = findChapterForSlice(model, slice);
396
- // 9. Build output
397
- const output = {
398
- sliceType,
399
- slice: {
400
- id: slice.id,
401
- name: slice.name,
402
- },
403
- ...(chapter && { chapter: getChapterHierarchy(model, chapter) }),
404
- elements: {
405
- readModels: components.readModels.map(rm => ({
406
- id: rm.id,
407
- name: rm.name,
408
- fields: rm.fields.map(fieldToJson),
409
- })),
410
- processors: components.processors.map(p => ({
411
- id: p.id,
412
- name: p.name,
413
- })),
414
- commands: components.commands.map(cmd => ({
415
- id: cmd.id,
416
- name: cmd.name,
417
- fields: cmd.fields.map(fieldToJson),
418
- })),
419
- events: components.events.map(evt => {
420
- const result = {
421
- id: evt.id,
422
- name: evt.name,
423
- fields: evt.fields.map(fieldToJson),
424
- };
425
- const aggregate = findAggregateForEvent(model, evt);
426
- if (aggregate)
427
- result.aggregate = aggregate;
428
- return result;
429
- }),
430
- screens: components.screens.map(scr => {
431
- const result = {
432
- id: scr.id,
433
- name: scr.name,
434
- fields: scr.fields.map(fieldToJson),
435
- };
436
- const actor = findActorForScreen(model, scr);
437
- if (actor)
438
- result.actor = actor;
439
- return result;
440
- }),
441
- },
442
- inboundDependencies,
443
- internalFlows,
444
- scenarios: formatScenarios(model, scenarios),
445
- };
446
- // 10. Output JSON
447
- outputJson(output);
448
- }
@@ -1,2 +0,0 @@
1
- import type { EventModel } from '../../types.js';
2
- export declare function createAutomationSlice(model: EventModel, filePath: string, xmlInput: string): void;