eventmodeler 0.1.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.
Files changed (37) hide show
  1. package/dist/formatters.d.ts +17 -0
  2. package/dist/formatters.js +482 -0
  3. package/dist/index.d.ts +2 -0
  4. package/dist/index.js +186 -0
  5. package/dist/lib/file-loader.d.ts +5 -0
  6. package/dist/lib/file-loader.js +53 -0
  7. package/dist/projection.d.ts +3 -0
  8. package/dist/projection.js +781 -0
  9. package/dist/slices/export-eventmodel-to-json/index.d.ts +2 -0
  10. package/dist/slices/export-eventmodel-to-json/index.js +296 -0
  11. package/dist/slices/list-chapters/index.d.ts +2 -0
  12. package/dist/slices/list-chapters/index.js +22 -0
  13. package/dist/slices/list-commands/index.d.ts +2 -0
  14. package/dist/slices/list-commands/index.js +21 -0
  15. package/dist/slices/list-events/index.d.ts +2 -0
  16. package/dist/slices/list-events/index.js +21 -0
  17. package/dist/slices/list-slices/index.d.ts +2 -0
  18. package/dist/slices/list-slices/index.js +21 -0
  19. package/dist/slices/mark-slice-status/index.d.ts +2 -0
  20. package/dist/slices/mark-slice-status/index.js +38 -0
  21. package/dist/slices/open-app/index.d.ts +1 -0
  22. package/dist/slices/open-app/index.js +36 -0
  23. package/dist/slices/search/index.d.ts +2 -0
  24. package/dist/slices/search/index.js +175 -0
  25. package/dist/slices/show-chapter/index.d.ts +2 -0
  26. package/dist/slices/show-chapter/index.js +43 -0
  27. package/dist/slices/show-command/index.d.ts +2 -0
  28. package/dist/slices/show-command/index.js +78 -0
  29. package/dist/slices/show-event/index.d.ts +2 -0
  30. package/dist/slices/show-event/index.js +75 -0
  31. package/dist/slices/show-model-summary/index.d.ts +2 -0
  32. package/dist/slices/show-model-summary/index.js +20 -0
  33. package/dist/slices/show-slice/index.d.ts +2 -0
  34. package/dist/slices/show-slice/index.js +239 -0
  35. package/dist/types.d.ts +161 -0
  36. package/dist/types.js +1 -0
  37. package/package.json +40 -0
@@ -0,0 +1,43 @@
1
+ function escapeXml(str) {
2
+ return str
3
+ .replace(/&/g, '&')
4
+ .replace(/</g, '&lt;')
5
+ .replace(/>/g, '&gt;')
6
+ .replace(/"/g, '&quot;')
7
+ .replace(/'/g, '&apos;');
8
+ }
9
+ function getSlicesUnderChapter(model, chapter) {
10
+ // A slice is "under" a chapter if its horizontal center falls within the chapter's x range
11
+ const chapterLeft = chapter.position.x;
12
+ const chapterRight = chapter.position.x + chapter.size.width;
13
+ return [...model.slices.values()].filter(slice => {
14
+ const sliceCenterX = slice.position.x + slice.size.width / 2;
15
+ return sliceCenterX >= chapterLeft && sliceCenterX <= chapterRight;
16
+ }).sort((a, b) => a.position.x - b.position.x);
17
+ }
18
+ export function showChapter(model, name) {
19
+ const chapters = [...model.chapters.values()];
20
+ const nameLower = name.toLowerCase();
21
+ const chapter = chapters.find(c => c.name.toLowerCase() === nameLower || c.name.toLowerCase().includes(nameLower));
22
+ if (!chapter) {
23
+ console.error(`Error: Chapter not found: ${name}`);
24
+ console.error('Available chapters:');
25
+ for (const c of chapters) {
26
+ console.error(` - ${c.name}`);
27
+ }
28
+ process.exit(1);
29
+ }
30
+ const slices = getSlicesUnderChapter(model, chapter);
31
+ console.log(`<chapter name="${escapeXml(chapter.name)}">`);
32
+ if (slices.length === 0) {
33
+ console.log(' <slices/>');
34
+ }
35
+ else {
36
+ console.log(' <slices>');
37
+ for (const slice of slices) {
38
+ console.log(` <slice name="${escapeXml(slice.name)}" status="${slice.status}"/>`);
39
+ }
40
+ console.log(' </slices>');
41
+ }
42
+ console.log('</chapter>');
43
+ }
@@ -0,0 +1,2 @@
1
+ import type { EventModel } from '../../types.js';
2
+ export declare function showCommand(model: EventModel, name: string): void;
@@ -0,0 +1,78 @@
1
+ function escapeXml(str) {
2
+ return str
3
+ .replace(/&/g, '&amp;')
4
+ .replace(/</g, '&lt;')
5
+ .replace(/>/g, '&gt;')
6
+ .replace(/"/g, '&quot;')
7
+ .replace(/'/g, '&apos;');
8
+ }
9
+ function formatFieldXml(field, indent) {
10
+ const attrs = [
11
+ `name="${escapeXml(field.name)}"`,
12
+ `type="${field.fieldType}"`,
13
+ ];
14
+ if (field.isList)
15
+ attrs.push('list="true"');
16
+ if (field.isGenerated)
17
+ attrs.push('generated="true"');
18
+ if (field.isOptional)
19
+ attrs.push('optional="true"');
20
+ if (field.subfields && field.subfields.length > 0) {
21
+ let xml = `${indent}<field ${attrs.join(' ')}>\n`;
22
+ for (const subfield of field.subfields) {
23
+ xml += formatFieldXml(subfield, indent + ' ');
24
+ }
25
+ xml += `${indent}</field>\n`;
26
+ return xml;
27
+ }
28
+ return `${indent}<field ${attrs.join(' ')}/>\n`;
29
+ }
30
+ function formatCommandXml(model, command) {
31
+ let xml = `<command name="${escapeXml(command.name)}">\n`;
32
+ if (command.fields.length > 0) {
33
+ xml += ' <fields>\n';
34
+ for (const field of command.fields) {
35
+ xml += formatFieldXml(field, ' ');
36
+ }
37
+ xml += ' </fields>\n';
38
+ }
39
+ const incomingFlows = [...model.flows.values()].filter(f => f.targetId === command.id);
40
+ const outgoingFlows = [...model.flows.values()].filter(f => f.sourceId === command.id);
41
+ if (incomingFlows.length > 0) {
42
+ xml += ' <triggered-by>\n';
43
+ for (const flow of incomingFlows) {
44
+ const screen = model.screens.get(flow.sourceId);
45
+ const processor = model.processors.get(flow.sourceId);
46
+ if (screen)
47
+ xml += ` <screen name="${escapeXml(screen.name)}"/>\n`;
48
+ if (processor)
49
+ xml += ` <processor name="${escapeXml(processor.name)}"/>\n`;
50
+ }
51
+ xml += ' </triggered-by>\n';
52
+ }
53
+ if (outgoingFlows.length > 0) {
54
+ xml += ' <produces>\n';
55
+ for (const flow of outgoingFlows) {
56
+ const target = model.events.get(flow.targetId);
57
+ if (target)
58
+ xml += ` <event name="${escapeXml(target.name)}"/>\n`;
59
+ }
60
+ xml += ' </produces>\n';
61
+ }
62
+ xml += '</command>';
63
+ return xml;
64
+ }
65
+ export function showCommand(model, name) {
66
+ const commands = [...model.commands.values()];
67
+ const nameLower = name.toLowerCase();
68
+ const command = commands.find(c => c.name.toLowerCase() === nameLower || c.name.toLowerCase().includes(nameLower));
69
+ if (!command) {
70
+ console.error(`Error: Command not found: ${name}`);
71
+ console.error('Available commands:');
72
+ for (const c of commands) {
73
+ console.error(` - ${c.name}`);
74
+ }
75
+ process.exit(1);
76
+ }
77
+ console.log(formatCommandXml(model, command));
78
+ }
@@ -0,0 +1,2 @@
1
+ import type { EventModel } from '../../types.js';
2
+ export declare function showEvent(model: EventModel, name: string): void;
@@ -0,0 +1,75 @@
1
+ function escapeXml(str) {
2
+ return str
3
+ .replace(/&/g, '&amp;')
4
+ .replace(/</g, '&lt;')
5
+ .replace(/>/g, '&gt;')
6
+ .replace(/"/g, '&quot;')
7
+ .replace(/'/g, '&apos;');
8
+ }
9
+ function formatFieldXml(field, indent) {
10
+ const attrs = [
11
+ `name="${escapeXml(field.name)}"`,
12
+ `type="${field.fieldType}"`,
13
+ ];
14
+ if (field.isList)
15
+ attrs.push('list="true"');
16
+ if (field.isGenerated)
17
+ attrs.push('generated="true"');
18
+ if (field.isOptional)
19
+ attrs.push('optional="true"');
20
+ if (field.subfields && field.subfields.length > 0) {
21
+ let xml = `${indent}<field ${attrs.join(' ')}>\n`;
22
+ for (const subfield of field.subfields) {
23
+ xml += formatFieldXml(subfield, indent + ' ');
24
+ }
25
+ xml += `${indent}</field>\n`;
26
+ return xml;
27
+ }
28
+ return `${indent}<field ${attrs.join(' ')}/>\n`;
29
+ }
30
+ function formatEventXml(model, event) {
31
+ let xml = `<event name="${escapeXml(event.name)}">\n`;
32
+ if (event.fields.length > 0) {
33
+ xml += ' <fields>\n';
34
+ for (const field of event.fields) {
35
+ xml += formatFieldXml(field, ' ');
36
+ }
37
+ xml += ' </fields>\n';
38
+ }
39
+ const incomingFlows = [...model.flows.values()].filter(f => f.targetId === event.id);
40
+ const outgoingFlows = [...model.flows.values()].filter(f => f.sourceId === event.id);
41
+ if (incomingFlows.length > 0) {
42
+ xml += ' <produced-by>\n';
43
+ for (const flow of incomingFlows) {
44
+ const source = model.commands.get(flow.sourceId);
45
+ if (source)
46
+ xml += ` <command name="${escapeXml(source.name)}"/>\n`;
47
+ }
48
+ xml += ' </produced-by>\n';
49
+ }
50
+ if (outgoingFlows.length > 0) {
51
+ xml += ' <consumed-by>\n';
52
+ for (const flow of outgoingFlows) {
53
+ const target = model.readModels.get(flow.targetId);
54
+ if (target)
55
+ xml += ` <read-model name="${escapeXml(target.name)}"/>\n`;
56
+ }
57
+ xml += ' </consumed-by>\n';
58
+ }
59
+ xml += '</event>';
60
+ return xml;
61
+ }
62
+ export function showEvent(model, name) {
63
+ const events = [...model.events.values()];
64
+ const nameLower = name.toLowerCase();
65
+ const event = events.find(e => e.name.toLowerCase() === nameLower || e.name.toLowerCase().includes(nameLower));
66
+ if (!event) {
67
+ console.error(`Error: Event not found: ${name}`);
68
+ console.error('Available events:');
69
+ for (const e of events) {
70
+ console.error(` - ${e.name}`);
71
+ }
72
+ process.exit(1);
73
+ }
74
+ console.log(formatEventXml(model, event));
75
+ }
@@ -0,0 +1,2 @@
1
+ import type { EventModel } from '../../types.js';
2
+ export declare function showModelSummary(model: EventModel): void;
@@ -0,0 +1,20 @@
1
+ function escapeXml(str) {
2
+ return str
3
+ .replace(/&/g, '&amp;')
4
+ .replace(/</g, '&lt;')
5
+ .replace(/>/g, '&gt;')
6
+ .replace(/"/g, '&quot;')
7
+ .replace(/'/g, '&apos;');
8
+ }
9
+ export function showModelSummary(model) {
10
+ console.log(`<model name="${escapeXml(model.name)}">`);
11
+ console.log(` <slices count="${model.slices.size}"/>`);
12
+ console.log(` <commands count="${model.commands.size}"/>`);
13
+ console.log(` <events count="${model.events.size}"/>`);
14
+ console.log(` <read-models count="${model.readModels.size}"/>`);
15
+ console.log(` <screens count="${model.screens.size}"/>`);
16
+ console.log(` <processors count="${model.processors.size}"/>`);
17
+ console.log(` <scenarios count="${model.scenarios.size}"/>`);
18
+ console.log(` <flows count="${model.flows.size}"/>`);
19
+ console.log('</model>');
20
+ }
@@ -0,0 +1,2 @@
1
+ import type { EventModel } from '../../types.js';
2
+ export declare function showSlice(model: EventModel, name: string): void;
@@ -0,0 +1,239 @@
1
+ function escapeXml(str) {
2
+ return str
3
+ .replace(/&/g, '&amp;')
4
+ .replace(/</g, '&lt;')
5
+ .replace(/>/g, '&gt;')
6
+ .replace(/"/g, '&quot;')
7
+ .replace(/'/g, '&apos;');
8
+ }
9
+ function formatFieldValues(values) {
10
+ if (!values || Object.keys(values).length === 0)
11
+ return '';
12
+ return Object.entries(values)
13
+ .map(([key, value]) => `${key}: ${JSON.stringify(value)}`)
14
+ .join(', ');
15
+ }
16
+ function formatFieldXml(field, indent, sourceInfo) {
17
+ const attrs = [
18
+ `name="${escapeXml(field.name)}"`,
19
+ `type="${field.fieldType}"`,
20
+ ];
21
+ if (field.isList)
22
+ attrs.push('list="true"');
23
+ if (field.isGenerated)
24
+ attrs.push('generated="true"');
25
+ if (field.isOptional)
26
+ attrs.push('optional="true"');
27
+ if (field.isUserInput)
28
+ attrs.push('user-input="true"');
29
+ if (sourceInfo)
30
+ attrs.push(`source="${escapeXml(sourceInfo)}"`);
31
+ if (field.subfields && field.subfields.length > 0) {
32
+ let xml = `${indent}<field ${attrs.join(' ')}>\n`;
33
+ for (const subfield of field.subfields) {
34
+ xml += formatFieldXml(subfield, indent + ' ');
35
+ }
36
+ xml += `${indent}</field>\n`;
37
+ return xml;
38
+ }
39
+ return `${indent}<field ${attrs.join(' ')}/>\n`;
40
+ }
41
+ function getSliceComponents(model, slice) {
42
+ const bounds = {
43
+ left: slice.position.x,
44
+ right: slice.position.x + slice.size.width,
45
+ top: slice.position.y,
46
+ bottom: slice.position.y + slice.size.height,
47
+ };
48
+ function isInSlice(pos, width, height) {
49
+ const centerX = pos.x + width / 2;
50
+ const centerY = pos.y + height / 2;
51
+ return centerX >= bounds.left && centerX <= bounds.right && centerY >= bounds.top && centerY <= bounds.bottom;
52
+ }
53
+ return {
54
+ commands: [...model.commands.values()].filter(c => isInSlice(c.position, c.width, c.height)),
55
+ events: [...model.events.values()].filter(e => isInSlice(e.position, e.width, e.height)),
56
+ readModels: [...model.readModels.values()].filter(rm => isInSlice(rm.position, rm.width, rm.height)),
57
+ screens: [...model.screens.values()].filter(s => isInSlice(s.position, s.width, s.height)),
58
+ processors: [...model.processors.values()].filter(p => isInSlice(p.position, p.width, p.height)),
59
+ };
60
+ }
61
+ function formatSliceXml(model, slice) {
62
+ const components = getSliceComponents(model, slice);
63
+ const scenarios = [...model.scenarios.values()].filter(s => s.sliceId === slice.id);
64
+ const componentIds = new Set();
65
+ components.commands.forEach(c => componentIds.add(c.id));
66
+ components.events.forEach(e => componentIds.add(e.id));
67
+ components.readModels.forEach(rm => componentIds.add(rm.id));
68
+ components.screens.forEach(s => componentIds.add(s.id));
69
+ components.processors.forEach(p => componentIds.add(p.id));
70
+ const flows = [...model.flows.values()].filter(f => componentIds.has(f.sourceId) || componentIds.has(f.targetId));
71
+ const internalFlows = flows.filter(f => componentIds.has(f.sourceId) && componentIds.has(f.targetId));
72
+ function getName(id) {
73
+ return (model.commands.get(id)?.name ??
74
+ model.events.get(id)?.name ??
75
+ model.readModels.get(id)?.name ??
76
+ model.screens.get(id)?.name ??
77
+ model.processors.get(id)?.name ??
78
+ id);
79
+ }
80
+ let xml = `<slice name="${escapeXml(slice.name)}" status="${slice.status}">\n`;
81
+ xml += ' <components>\n';
82
+ for (const screen of components.screens) {
83
+ xml += ` <screen name="${escapeXml(screen.name)}">\n`;
84
+ if (screen.fields.length > 0) {
85
+ xml += ' <fields>\n';
86
+ for (const field of screen.fields) {
87
+ xml += formatFieldXml(field, ' ', field.isUserInput ? 'user-input' : undefined);
88
+ }
89
+ xml += ' </fields>\n';
90
+ }
91
+ xml += ' </screen>\n';
92
+ }
93
+ for (const command of components.commands) {
94
+ xml += ` <command name="${escapeXml(command.name)}">\n`;
95
+ if (command.fields.length > 0) {
96
+ xml += ' <fields>\n';
97
+ for (const field of command.fields) {
98
+ const incomingFlow = flows.find(f => f.targetId === command.id);
99
+ let sourceInfo;
100
+ if (incomingFlow) {
101
+ const source = model.screens.get(incomingFlow.sourceId) ?? model.processors.get(incomingFlow.sourceId);
102
+ if (source?.fields.some(f => f.name === field.name)) {
103
+ sourceInfo = `${source.name}.${field.name}`;
104
+ }
105
+ }
106
+ xml += formatFieldXml(field, ' ', sourceInfo);
107
+ }
108
+ xml += ' </fields>\n';
109
+ }
110
+ xml += ' </command>\n';
111
+ }
112
+ for (const event of components.events) {
113
+ xml += ` <event name="${escapeXml(event.name)}">\n`;
114
+ if (event.fields.length > 0) {
115
+ xml += ' <fields>\n';
116
+ for (const field of event.fields) {
117
+ const incomingFlow = flows.find(f => f.targetId === event.id);
118
+ let sourceInfo;
119
+ if (field.isGenerated) {
120
+ sourceInfo = 'generated';
121
+ }
122
+ else if (incomingFlow) {
123
+ const source = model.commands.get(incomingFlow.sourceId);
124
+ if (source?.fields.some(f => f.name === field.name)) {
125
+ sourceInfo = `${source.name}.${field.name}`;
126
+ }
127
+ }
128
+ xml += formatFieldXml(field, ' ', sourceInfo);
129
+ }
130
+ xml += ' </fields>\n';
131
+ }
132
+ xml += ' </event>\n';
133
+ }
134
+ for (const readModel of components.readModels) {
135
+ xml += ` <read-model name="${escapeXml(readModel.name)}">\n`;
136
+ if (readModel.fields.length > 0) {
137
+ xml += ' <fields>\n';
138
+ for (const field of readModel.fields) {
139
+ xml += formatFieldXml(field, ' ');
140
+ }
141
+ xml += ' </fields>\n';
142
+ }
143
+ xml += ' </read-model>\n';
144
+ }
145
+ for (const processor of components.processors) {
146
+ xml += ` <processor name="${escapeXml(processor.name)}">\n`;
147
+ if (processor.fields.length > 0) {
148
+ xml += ' <fields>\n';
149
+ for (const field of processor.fields) {
150
+ xml += formatFieldXml(field, ' ');
151
+ }
152
+ xml += ' </fields>\n';
153
+ }
154
+ xml += ' </processor>\n';
155
+ }
156
+ xml += ' </components>\n';
157
+ if (internalFlows.length > 0) {
158
+ xml += ' <information-flow>\n';
159
+ for (const flow of internalFlows) {
160
+ xml += ` ${escapeXml(getName(flow.sourceId))} → ${escapeXml(getName(flow.targetId))}\n`;
161
+ }
162
+ xml += ' </information-flow>\n';
163
+ }
164
+ if (scenarios.length > 0) {
165
+ xml += ' <scenarios>\n';
166
+ for (const scenario of scenarios) {
167
+ xml += ` <scenario name="${escapeXml(scenario.name)}">\n`;
168
+ if (scenario.description) {
169
+ xml += ` <description>${escapeXml(scenario.description)}</description>\n`;
170
+ }
171
+ if (scenario.givenEvents.length > 0) {
172
+ xml += ' <given>\n';
173
+ for (const given of scenario.givenEvents) {
174
+ const evt = model.events.get(given.eventStickyId);
175
+ const name = evt?.name ?? 'UnknownEvent';
176
+ const values = formatFieldValues(given.fieldValues);
177
+ xml += values
178
+ ? ` <event type="${escapeXml(name)}">${escapeXml(values)}</event>\n`
179
+ : ` <event type="${escapeXml(name)}"/>\n`;
180
+ }
181
+ xml += ' </given>\n';
182
+ }
183
+ if (scenario.whenCommand) {
184
+ const cmd = model.commands.get(scenario.whenCommand.commandStickyId);
185
+ const name = cmd?.name ?? 'UnknownCommand';
186
+ const values = formatFieldValues(scenario.whenCommand.fieldValues);
187
+ xml += ' <when>\n';
188
+ xml += values
189
+ ? ` <command type="${escapeXml(name)}">${escapeXml(values)}</command>\n`
190
+ : ` <command type="${escapeXml(name)}"/>\n`;
191
+ xml += ' </when>\n';
192
+ }
193
+ xml += ' <then>\n';
194
+ if (scenario.then.type === 'error') {
195
+ xml += ` <error`;
196
+ if (scenario.then.errorType)
197
+ xml += ` type="${escapeXml(scenario.then.errorType)}"`;
198
+ xml += `>${escapeXml(scenario.then.errorMessage ?? '')}</error>\n`;
199
+ }
200
+ else if (scenario.then.type === 'events' && scenario.then.expectedEvents) {
201
+ for (const expected of scenario.then.expectedEvents) {
202
+ const evt = model.events.get(expected.eventStickyId);
203
+ const name = evt?.name ?? 'UnknownEvent';
204
+ const values = formatFieldValues(expected.fieldValues);
205
+ xml += values
206
+ ? ` <event type="${escapeXml(name)}">${escapeXml(values)}</event>\n`
207
+ : ` <event type="${escapeXml(name)}"/>\n`;
208
+ }
209
+ }
210
+ else if (scenario.then.type === 'readModelAssertion' && scenario.then.readModelAssertion) {
211
+ const assertion = scenario.then.readModelAssertion;
212
+ const rm = model.readModels.get(assertion.readModelStickyId);
213
+ const name = rm?.name ?? 'UnknownReadModel';
214
+ xml += ` <read-model-assertion type="${escapeXml(name)}">\n`;
215
+ xml += ` <expected>${escapeXml(formatFieldValues(assertion.expectedFieldValues))}</expected>\n`;
216
+ xml += ' </read-model-assertion>\n';
217
+ }
218
+ xml += ' </then>\n';
219
+ xml += ' </scenario>\n';
220
+ }
221
+ xml += ' </scenarios>\n';
222
+ }
223
+ xml += '</slice>';
224
+ return xml;
225
+ }
226
+ export function showSlice(model, name) {
227
+ const slices = [...model.slices.values()];
228
+ const nameLower = name.toLowerCase();
229
+ const slice = slices.find(s => s.name.toLowerCase() === nameLower || s.name.toLowerCase().includes(nameLower));
230
+ if (!slice) {
231
+ console.error(`Error: Slice not found: ${name}`);
232
+ console.error('Available slices:');
233
+ for (const s of slices) {
234
+ console.error(` - ${s.name}`);
235
+ }
236
+ process.exit(1);
237
+ }
238
+ console.log(formatSliceXml(model, slice));
239
+ }
@@ -0,0 +1,161 @@
1
+ export interface Field {
2
+ id: string;
3
+ name: string;
4
+ fieldType: 'UUID' | 'Boolean' | 'Double' | 'Decimal' | 'Date' | 'DateTime' | 'Long' | 'Int' | 'String' | 'Custom';
5
+ isList: boolean;
6
+ isGenerated: boolean;
7
+ isOptional?: boolean;
8
+ isUserInput?: boolean;
9
+ subfields?: Field[];
10
+ }
11
+ export type SliceStatus = 'created' | 'in-progress' | 'blocked' | 'done';
12
+ export interface EventReference {
13
+ eventStickyId: string;
14
+ fieldValues?: Record<string, unknown>;
15
+ }
16
+ export interface CommandReference {
17
+ commandStickyId: string;
18
+ fieldValues?: Record<string, unknown>;
19
+ }
20
+ export interface ReadModelAssertion {
21
+ readModelStickyId: string;
22
+ givenEvents: EventReference[];
23
+ expectedFieldValues: Record<string, unknown>;
24
+ }
25
+ export type ScenarioThenType = 'error' | 'events' | 'readModelAssertion';
26
+ export interface ScenarioThen {
27
+ type: ScenarioThenType;
28
+ errorMessage?: string;
29
+ errorType?: string;
30
+ expectedEvents?: EventReference[];
31
+ readModelAssertion?: ReadModelAssertion;
32
+ }
33
+ export interface FieldMapping {
34
+ sourceFieldId: string;
35
+ targetFieldId: string;
36
+ }
37
+ export interface CommandSticky {
38
+ id: string;
39
+ name: string;
40
+ fields: Field[];
41
+ position: {
42
+ x: number;
43
+ y: number;
44
+ };
45
+ width: number;
46
+ height: number;
47
+ }
48
+ export interface EventSticky {
49
+ id: string;
50
+ name: string;
51
+ fields: Field[];
52
+ position: {
53
+ x: number;
54
+ y: number;
55
+ };
56
+ width: number;
57
+ height: number;
58
+ canonicalId?: string;
59
+ }
60
+ export interface ReadModelSticky {
61
+ id: string;
62
+ name: string;
63
+ fields: Field[];
64
+ position: {
65
+ x: number;
66
+ y: number;
67
+ };
68
+ width: number;
69
+ height: number;
70
+ canonicalId?: string;
71
+ }
72
+ export interface Screen {
73
+ id: string;
74
+ name: string;
75
+ fields: Field[];
76
+ position: {
77
+ x: number;
78
+ y: number;
79
+ };
80
+ width: number;
81
+ height: number;
82
+ canonicalId?: string;
83
+ }
84
+ export interface Processor {
85
+ id: string;
86
+ name: string;
87
+ fields: Field[];
88
+ position: {
89
+ x: number;
90
+ y: number;
91
+ };
92
+ width: number;
93
+ height: number;
94
+ }
95
+ export interface Slice {
96
+ id: string;
97
+ name: string;
98
+ status: SliceStatus;
99
+ position: {
100
+ x: number;
101
+ y: number;
102
+ };
103
+ size: {
104
+ width: number;
105
+ height: number;
106
+ };
107
+ nodeIds: string[];
108
+ }
109
+ export interface Chapter {
110
+ id: string;
111
+ name: string;
112
+ position: {
113
+ x: number;
114
+ y: number;
115
+ };
116
+ size: {
117
+ width: number;
118
+ height: number;
119
+ };
120
+ }
121
+ export interface Scenario {
122
+ id: string;
123
+ sliceId: string;
124
+ name: string;
125
+ description: string;
126
+ position: {
127
+ x: number;
128
+ y: number;
129
+ };
130
+ width: number;
131
+ height: number;
132
+ givenEvents: EventReference[];
133
+ whenCommand: CommandReference | null;
134
+ then: ScenarioThen;
135
+ }
136
+ export type FlowType = 'CommandToEvent' | 'EventToReadModel' | 'ReadModelToScreen' | 'ReadModelToProcessor' | 'ScreenToCommand' | 'ProcessorToCommand';
137
+ export interface Flow {
138
+ id: string;
139
+ flowType: FlowType;
140
+ sourceId: string;
141
+ targetId: string;
142
+ fieldMappings: FieldMapping[];
143
+ }
144
+ export interface EventModel {
145
+ modelId: string;
146
+ name: string;
147
+ commands: Map<string, CommandSticky>;
148
+ events: Map<string, EventSticky>;
149
+ readModels: Map<string, ReadModelSticky>;
150
+ screens: Map<string, Screen>;
151
+ processors: Map<string, Processor>;
152
+ slices: Map<string, Slice>;
153
+ chapters: Map<string, Chapter>;
154
+ scenarios: Map<string, Scenario>;
155
+ flows: Map<string, Flow>;
156
+ }
157
+ export interface RawEvent {
158
+ type: string;
159
+ timestamp: number;
160
+ [key: string]: unknown;
161
+ }
package/dist/types.js ADDED
@@ -0,0 +1 @@
1
+ export {};
package/package.json ADDED
@@ -0,0 +1,40 @@
1
+ {
2
+ "name": "eventmodeler",
3
+ "version": "0.1.0",
4
+ "description": "CLI tool for interacting with Event Model files - query, update, and export event models from the terminal",
5
+ "type": "module",
6
+ "bin": {
7
+ "eventmodeler": "./dist/index.js"
8
+ },
9
+ "files": [
10
+ "dist"
11
+ ],
12
+ "scripts": {
13
+ "build": "tsc",
14
+ "dev": "tsc --watch",
15
+ "prepublishOnly": "npm run build"
16
+ },
17
+ "keywords": [
18
+ "event-modeling",
19
+ "event-sourcing",
20
+ "cqrs",
21
+ "ddd",
22
+ "domain-driven-design",
23
+ "cli",
24
+ "eventmodel"
25
+ ],
26
+ "author": "",
27
+ "license": "MIT",
28
+ "repository": {
29
+ "type": "git",
30
+ "url": "https://github.com/your-username/event-modeler"
31
+ },
32
+ "homepage": "https://www.eventmodeling.app",
33
+ "engines": {
34
+ "node": ">=18.0.0"
35
+ },
36
+ "devDependencies": {
37
+ "@types/node": "^22.0.0",
38
+ "typescript": "^5.9.3"
39
+ }
40
+ }