eventmodeler 0.2.1 → 0.2.4

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 (52) hide show
  1. package/README.md +175 -0
  2. package/dist/index.js +114 -19
  3. package/dist/lib/config.d.ts +2 -0
  4. package/dist/lib/config.js +26 -0
  5. package/dist/lib/element-lookup.d.ts +47 -0
  6. package/dist/lib/element-lookup.js +86 -0
  7. package/dist/lib/format.d.ts +3 -0
  8. package/dist/lib/format.js +11 -0
  9. package/dist/lib/slice-utils.d.ts +83 -0
  10. package/dist/lib/slice-utils.js +135 -0
  11. package/dist/projection.js +161 -35
  12. package/dist/slices/add-field/index.js +4 -33
  13. package/dist/slices/add-scenario/index.js +7 -74
  14. package/dist/slices/create-automation-slice/index.d.ts +2 -0
  15. package/dist/slices/create-automation-slice/index.js +217 -0
  16. package/dist/slices/create-flow/index.d.ts +2 -0
  17. package/dist/slices/create-flow/index.js +177 -0
  18. package/dist/slices/create-state-change-slice/index.d.ts +2 -0
  19. package/dist/slices/create-state-change-slice/index.js +239 -0
  20. package/dist/slices/create-state-view-slice/index.d.ts +2 -0
  21. package/dist/slices/create-state-view-slice/index.js +120 -0
  22. package/dist/slices/list-chapters/index.d.ts +2 -1
  23. package/dist/slices/list-chapters/index.js +11 -12
  24. package/dist/slices/list-commands/index.d.ts +2 -1
  25. package/dist/slices/list-commands/index.js +10 -11
  26. package/dist/slices/list-events/index.d.ts +2 -1
  27. package/dist/slices/list-events/index.js +36 -15
  28. package/dist/slices/list-slices/index.d.ts +2 -1
  29. package/dist/slices/list-slices/index.js +10 -11
  30. package/dist/slices/mark-slice-status/index.js +2 -11
  31. package/dist/slices/remove-field/index.js +4 -33
  32. package/dist/slices/remove-scenario/index.js +45 -11
  33. package/dist/slices/search/index.d.ts +2 -1
  34. package/dist/slices/search/index.js +148 -21
  35. package/dist/slices/show-actor/index.d.ts +3 -2
  36. package/dist/slices/show-actor/index.js +46 -20
  37. package/dist/slices/show-aggregate-completeness/index.d.ts +3 -2
  38. package/dist/slices/show-aggregate-completeness/index.js +62 -20
  39. package/dist/slices/show-chapter/index.d.ts +2 -1
  40. package/dist/slices/show-chapter/index.js +14 -22
  41. package/dist/slices/show-command/index.d.ts +2 -1
  42. package/dist/slices/show-command/index.js +54 -19
  43. package/dist/slices/show-completeness/index.d.ts +3 -1
  44. package/dist/slices/show-completeness/index.js +313 -31
  45. package/dist/slices/show-event/index.d.ts +2 -1
  46. package/dist/slices/show-event/index.js +44 -20
  47. package/dist/slices/show-model-summary/index.d.ts +2 -1
  48. package/dist/slices/show-model-summary/index.js +18 -9
  49. package/dist/slices/show-slice/index.d.ts +2 -1
  50. package/dist/slices/show-slice/index.js +174 -24
  51. package/dist/slices/update-field/index.js +4 -33
  52. package/package.json +5 -3
@@ -1,9 +1,116 @@
1
- function escapeXml(str) {
2
- return str
3
- .replace(/&/g, '&')
4
- .replace(/</g, '&lt;')
5
- .replace(/>/g, '&gt;')
6
- .replace(/"/g, '&quot;');
1
+ import { escapeXml, outputJson } from '../../lib/format.js';
2
+ const INCOMING_FLOW_TYPES = {
3
+ command: ['ScreenToCommand', 'ProcessorToCommand'],
4
+ event: ['CommandToEvent'],
5
+ readModel: ['EventToReadModel'],
6
+ screen: ['ReadModelToScreen'],
7
+ processor: ['ReadModelToProcessor'],
8
+ };
9
+ function findElementByName(model, name) {
10
+ // Check for UUID lookup (id:prefix or full UUID format)
11
+ if (name.startsWith('id:')) {
12
+ const idSearch = name.slice(3).toLowerCase();
13
+ // Search all element types by ID
14
+ for (const cmd of model.commands.values()) {
15
+ if (cmd.id.toLowerCase().startsWith(idSearch)) {
16
+ return { element: { id: cmd.id, name: cmd.name, fields: cmd.fields, type: 'command' }, ambiguous: [] };
17
+ }
18
+ }
19
+ for (const evt of model.events.values()) {
20
+ if (evt.id.toLowerCase().startsWith(idSearch)) {
21
+ return { element: { id: evt.id, name: evt.name, fields: evt.fields, type: 'event' }, ambiguous: [] };
22
+ }
23
+ }
24
+ for (const rm of model.readModels.values()) {
25
+ if (rm.id.toLowerCase().startsWith(idSearch)) {
26
+ return { element: { id: rm.id, name: rm.name, fields: rm.fields, type: 'readModel' }, ambiguous: [] };
27
+ }
28
+ }
29
+ for (const scr of model.screens.values()) {
30
+ if (scr.id.toLowerCase().startsWith(idSearch)) {
31
+ return { element: { id: scr.id, name: scr.name, fields: scr.fields, type: 'screen' }, ambiguous: [] };
32
+ }
33
+ }
34
+ for (const proc of model.processors.values()) {
35
+ if (proc.id.toLowerCase().startsWith(idSearch)) {
36
+ return { element: { id: proc.id, name: proc.name, fields: proc.fields, type: 'processor' }, ambiguous: [] };
37
+ }
38
+ }
39
+ return { element: null, ambiguous: [] };
40
+ }
41
+ // Check if it's a full UUID
42
+ const uuidPattern = /^[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$/i;
43
+ if (uuidPattern.test(name)) {
44
+ const cmd = model.commands.get(name);
45
+ if (cmd)
46
+ return { element: { id: cmd.id, name: cmd.name, fields: cmd.fields, type: 'command' }, ambiguous: [] };
47
+ const evt = model.events.get(name);
48
+ if (evt)
49
+ return { element: { id: evt.id, name: evt.name, fields: evt.fields, type: 'event' }, ambiguous: [] };
50
+ const rm = model.readModels.get(name);
51
+ if (rm)
52
+ return { element: { id: rm.id, name: rm.name, fields: rm.fields, type: 'readModel' }, ambiguous: [] };
53
+ const scr = model.screens.get(name);
54
+ if (scr)
55
+ return { element: { id: scr.id, name: scr.name, fields: scr.fields, type: 'screen' }, ambiguous: [] };
56
+ const proc = model.processors.get(name);
57
+ if (proc)
58
+ return { element: { id: proc.id, name: proc.name, fields: proc.fields, type: 'processor' }, ambiguous: [] };
59
+ return { element: null, ambiguous: [] };
60
+ }
61
+ // Case-insensitive exact name match across all types
62
+ const nameLower = name.toLowerCase();
63
+ const matches = [];
64
+ for (const cmd of model.commands.values()) {
65
+ if (cmd.name.toLowerCase() === nameLower) {
66
+ matches.push({ element: { id: cmd.id, name: cmd.name, fields: cmd.fields, type: 'command' }, type: 'command' });
67
+ }
68
+ }
69
+ for (const evt of model.events.values()) {
70
+ if (evt.name.toLowerCase() === nameLower) {
71
+ matches.push({ element: { id: evt.id, name: evt.name, fields: evt.fields, type: 'event' }, type: 'event' });
72
+ }
73
+ }
74
+ for (const rm of model.readModels.values()) {
75
+ if (rm.name.toLowerCase() === nameLower) {
76
+ matches.push({ element: { id: rm.id, name: rm.name, fields: rm.fields, type: 'readModel' }, type: 'readModel' });
77
+ }
78
+ }
79
+ for (const scr of model.screens.values()) {
80
+ if (scr.name.toLowerCase() === nameLower) {
81
+ matches.push({ element: { id: scr.id, name: scr.name, fields: scr.fields, type: 'screen' }, type: 'screen' });
82
+ }
83
+ }
84
+ for (const proc of model.processors.values()) {
85
+ if (proc.name.toLowerCase() === nameLower) {
86
+ matches.push({ element: { id: proc.id, name: proc.name, fields: proc.fields, type: 'processor' }, type: 'processor' });
87
+ }
88
+ }
89
+ if (matches.length === 1) {
90
+ return { element: matches[0].element, ambiguous: [] };
91
+ }
92
+ if (matches.length > 1) {
93
+ return { element: null, ambiguous: matches };
94
+ }
95
+ return { element: null, ambiguous: [] };
96
+ }
97
+ function getSourceFields(model, sourceId) {
98
+ const cmd = model.commands.get(sourceId);
99
+ if (cmd)
100
+ return cmd.fields;
101
+ const evt = model.events.get(sourceId);
102
+ if (evt)
103
+ return evt.fields;
104
+ const rm = model.readModels.get(sourceId);
105
+ if (rm)
106
+ return rm.fields;
107
+ const scr = model.screens.get(sourceId);
108
+ if (scr)
109
+ return scr.fields;
110
+ const proc = model.processors.get(sourceId);
111
+ if (proc)
112
+ return proc.fields;
113
+ return [];
7
114
  }
8
115
  function flattenFields(fields, prefix = '') {
9
116
  const result = [];
@@ -104,40 +211,117 @@ function calculateFlowCompleteness(model, flow, targetFields, sourceFields) {
104
211
  })),
105
212
  };
106
213
  }
107
- export function showCompleteness(model, readModelName) {
108
- // Find the read model
109
- const nameLower = readModelName.toLowerCase();
110
- const readModels = [...model.readModels.values()];
111
- const readModel = readModels.find(rm => rm.name.toLowerCase() === nameLower || rm.name.toLowerCase().includes(nameLower));
112
- if (!readModel) {
113
- console.error(`Error: Read model not found: ${readModelName}`);
114
- console.error('Available read models:');
115
- for (const rm of readModels) {
116
- console.error(` - ${rm.name}`);
214
+ export function showCompleteness(model, elementName, format) {
215
+ // Find the element by name (searches all element types)
216
+ const { element, ambiguous } = findElementByName(model, elementName);
217
+ if (ambiguous.length > 0) {
218
+ console.error(`Error: Multiple elements found with name "${elementName}"`);
219
+ console.error('Please specify using the element ID:');
220
+ for (const match of ambiguous) {
221
+ console.error(` - "${match.element.name}" (${match.type}) (id: ${match.element.id})`);
222
+ }
223
+ console.error('');
224
+ console.error(`Usage: eventmodeler show completeness "id:${ambiguous[0].element.id.slice(0, 8)}"`);
225
+ process.exit(1);
226
+ }
227
+ if (!element) {
228
+ console.error(`Error: Element not found: "${elementName}"`);
229
+ // List all available elements with their IDs
230
+ const allElements = [];
231
+ for (const cmd of model.commands.values()) {
232
+ allElements.push({ name: cmd.name, type: 'command', id: cmd.id });
233
+ }
234
+ for (const evt of model.events.values()) {
235
+ allElements.push({ name: evt.name, type: 'event', id: evt.id });
236
+ }
237
+ for (const rm of model.readModels.values()) {
238
+ allElements.push({ name: rm.name, type: 'read model', id: rm.id });
239
+ }
240
+ for (const scr of model.screens.values()) {
241
+ allElements.push({ name: scr.name, type: 'screen', id: scr.id });
242
+ }
243
+ for (const proc of model.processors.values()) {
244
+ allElements.push({ name: proc.name, type: 'processor', id: proc.id });
245
+ }
246
+ if (allElements.length > 0) {
247
+ console.error('Available elements:');
248
+ for (const el of allElements) {
249
+ console.error(` - "${el.name}" (${el.type}) (id: ${el.id.slice(0, 8)})`);
250
+ }
251
+ }
252
+ else {
253
+ console.error('No elements exist in the model.');
117
254
  }
118
255
  process.exit(1);
119
256
  }
120
- // Find all flows into this read model (EventToReadModel flows)
121
- const incomingFlows = [...model.flows.values()].filter(f => f.targetId === readModel.id && f.flowType === 'EventToReadModel');
257
+ // Find all incoming flows for this element type
258
+ const validFlowTypes = INCOMING_FLOW_TYPES[element.type];
259
+ const incomingFlows = [...model.flows.values()].filter(f => f.targetId === element.id && validFlowTypes.includes(f.flowType));
260
+ const elementTypeLabel = element.type === 'readModel' ? 'read-model' : element.type;
122
261
  if (incomingFlows.length === 0) {
123
- console.log(`<completeness readModel="${escapeXml(readModel.name)}">`);
124
- console.log(' <no-flows>No events flow into this read model</no-flows>');
125
- console.log('</completeness>');
262
+ if (format === 'json') {
263
+ outputJson({
264
+ elementType: elementTypeLabel,
265
+ name: element.name,
266
+ message: `No flows into this ${elementTypeLabel}`
267
+ });
268
+ }
269
+ else {
270
+ console.log(`<completeness ${elementTypeLabel}="${escapeXml(element.name)}">`);
271
+ console.log(` <no-flows>No flows into this ${elementTypeLabel}</no-flows>`);
272
+ console.log('</completeness>');
273
+ }
126
274
  return;
127
275
  }
128
276
  // Calculate completeness for each flow
129
277
  const completenessResults = [];
130
278
  for (const flow of incomingFlows) {
131
- const sourceEvent = model.events.get(flow.sourceId);
132
- if (!sourceEvent)
133
- continue;
134
- const result = calculateFlowCompleteness(model, flow, readModel.fields, sourceEvent.fields);
279
+ const sourceFields = getSourceFields(model, flow.sourceId);
280
+ if (sourceFields.length === 0 && element.fields.length > 0) {
281
+ // Source has no fields but target expects some - still calculate
282
+ }
283
+ const result = calculateFlowCompleteness(model, flow, element.fields, sourceFields);
135
284
  completenessResults.push(result);
136
285
  }
137
- // Output XML
138
286
  const overallComplete = completenessResults.every(r => r.isComplete);
139
287
  const overallStatus = overallComplete ? 'complete' : 'incomplete';
140
- console.log(`<completeness readModel="${escapeXml(readModel.name)}" status="${overallStatus}">`);
288
+ if (format === 'json') {
289
+ const flatTargetFields = flattenFields(element.fields);
290
+ outputJson({
291
+ elementType: elementTypeLabel,
292
+ name: element.name,
293
+ status: overallStatus,
294
+ flows: completenessResults.map(result => ({
295
+ flowId: result.flowId,
296
+ from: result.sourceName,
297
+ sourceType: result.sourceType,
298
+ status: result.isComplete ? 'complete' : 'incomplete',
299
+ ...(result.hasWarnings ? { hasWarnings: true } : {}),
300
+ targetFields: result.targetFields.map(f => ({
301
+ name: f.fieldName,
302
+ status: f.status,
303
+ ...(f.sourceFieldName ? { source: f.sourceFieldName } : {})
304
+ })),
305
+ availableSourceFields: result.sourceFields.map(sf => ({
306
+ id: sf.id,
307
+ name: sf.name,
308
+ type: sf.type,
309
+ ...(sf.isList ? { isList: true } : {})
310
+ }))
311
+ })),
312
+ elementFields: flatTargetFields.map(({ id, path, field }) => ({
313
+ id,
314
+ name: path,
315
+ type: field.fieldType,
316
+ ...(field.isList ? { isList: true } : {}),
317
+ ...(field.isOptional ? { isOptional: true } : {}),
318
+ ...(field.isGenerated ? { isGenerated: true } : {})
319
+ }))
320
+ });
321
+ return;
322
+ }
323
+ // Output XML
324
+ console.log(`<completeness ${elementTypeLabel}="${escapeXml(element.name)}" status="${overallStatus}">`);
141
325
  for (const result of completenessResults) {
142
326
  const flowStatus = result.isComplete ? 'complete' : 'incomplete';
143
327
  const warningAttr = result.hasWarnings ? ' hasWarnings="true"' : '';
@@ -162,9 +346,9 @@ export function showCompleteness(model, readModelName) {
162
346
  console.log(' </available-source-fields>');
163
347
  console.log(' </flow>');
164
348
  }
165
- // Also show the read model's fields with their IDs (needed for mapping)
166
- console.log(' <read-model-fields>');
167
- const flatTargetFields = flattenFields(readModel.fields);
349
+ // Also show the element's fields with their IDs (needed for mapping)
350
+ console.log(` <${elementTypeLabel}-fields>`);
351
+ const flatTargetFields = flattenFields(element.fields);
168
352
  for (const { id, path, field } of flatTargetFields) {
169
353
  const attrs = [`id="${id}"`, `name="${escapeXml(path)}"`, `type="${field.fieldType}"`];
170
354
  if (field.isList)
@@ -175,6 +359,104 @@ export function showCompleteness(model, readModelName) {
175
359
  attrs.push('isGenerated="true"');
176
360
  console.log(` <field ${attrs.join(' ')}/>`);
177
361
  }
178
- console.log(' </read-model-fields>');
362
+ console.log(` </${elementTypeLabel}-fields>`);
179
363
  console.log('</completeness>');
180
364
  }
365
+ export function showModelCompleteness(model, format) {
366
+ const allFlows = [...model.flows.values()];
367
+ const incompleteFlows = [];
368
+ let completeCount = 0;
369
+ let totalCount = 0;
370
+ for (const flow of allFlows) {
371
+ // Get target element info
372
+ let targetName = 'Unknown';
373
+ let targetType = 'unknown';
374
+ let targetFields = [];
375
+ const targetCmd = model.commands.get(flow.targetId);
376
+ const targetEvt = model.events.get(flow.targetId);
377
+ const targetRm = model.readModels.get(flow.targetId);
378
+ const targetScr = model.screens.get(flow.targetId);
379
+ const targetProc = model.processors.get(flow.targetId);
380
+ if (targetCmd) {
381
+ targetName = targetCmd.name;
382
+ targetType = 'command';
383
+ targetFields = targetCmd.fields;
384
+ }
385
+ else if (targetEvt) {
386
+ targetName = targetEvt.name;
387
+ targetType = 'event';
388
+ targetFields = targetEvt.fields;
389
+ }
390
+ else if (targetRm) {
391
+ targetName = targetRm.name;
392
+ targetType = 'read-model';
393
+ targetFields = targetRm.fields;
394
+ }
395
+ else if (targetScr) {
396
+ targetName = targetScr.name;
397
+ targetType = 'screen';
398
+ targetFields = targetScr.fields;
399
+ }
400
+ else if (targetProc) {
401
+ targetName = targetProc.name;
402
+ targetType = 'processor';
403
+ targetFields = targetProc.fields;
404
+ }
405
+ // Get source fields
406
+ const sourceFields = getSourceFields(model, flow.sourceId);
407
+ // Calculate completeness
408
+ const result = calculateFlowCompleteness(model, flow, targetFields, sourceFields);
409
+ totalCount++;
410
+ if (result.isComplete) {
411
+ completeCount++;
412
+ }
413
+ else {
414
+ const unsatisfiedFields = result.targetFields
415
+ .filter(f => f.status === 'unsatisfied')
416
+ .map(f => f.fieldName);
417
+ incompleteFlows.push({
418
+ flow,
419
+ sourceName: result.sourceName,
420
+ targetName,
421
+ targetType,
422
+ unsatisfiedFields,
423
+ });
424
+ }
425
+ }
426
+ const incompleteCount = totalCount - completeCount;
427
+ if (format === 'json') {
428
+ outputJson({
429
+ summary: {
430
+ complete: completeCount,
431
+ incomplete: incompleteCount,
432
+ total: totalCount
433
+ },
434
+ incompleteFlows: incompleteFlows.map(item => ({
435
+ from: item.sourceName,
436
+ to: item.targetName,
437
+ targetType: item.targetType,
438
+ flowType: item.flow.flowType,
439
+ unsatisfiedFields: item.unsatisfiedFields
440
+ }))
441
+ });
442
+ return;
443
+ }
444
+ console.log('<model-completeness>');
445
+ console.log(` <summary complete="${completeCount}" incomplete="${incompleteCount}" total="${totalCount}"/>`);
446
+ if (incompleteFlows.length > 0) {
447
+ console.log(' <incomplete-flows>');
448
+ for (const item of incompleteFlows) {
449
+ console.log(` <flow from="${escapeXml(item.sourceName)}" to="${escapeXml(item.targetName)}" target-type="${item.targetType}" flow-type="${item.flow.flowType}">`);
450
+ if (item.unsatisfiedFields.length > 0) {
451
+ console.log(' <unsatisfied-fields>');
452
+ for (const fieldName of item.unsatisfiedFields) {
453
+ console.log(` <field name="${escapeXml(fieldName)}"/>`);
454
+ }
455
+ console.log(' </unsatisfied-fields>');
456
+ }
457
+ console.log(' </flow>');
458
+ }
459
+ console.log(' </incomplete-flows>');
460
+ }
461
+ console.log('</model-completeness>');
462
+ }
@@ -1,2 +1,3 @@
1
1
  import type { EventModel } from '../../types.js';
2
- export declare function showEvent(model: EventModel, name: string): void;
2
+ import { type OutputFormat } from '../../lib/format.js';
3
+ export declare function showEvent(model: EventModel, name: string, format: OutputFormat): void;
@@ -1,11 +1,5 @@
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
- }
1
+ import { escapeXml, outputJson } from '../../lib/format.js';
2
+ import { findElementOrExit } from '../../lib/element-lookup.js';
9
3
  function formatFieldXml(field, indent) {
10
4
  const attrs = [
11
5
  `name="${escapeXml(field.name)}"`,
@@ -27,6 +21,22 @@ function formatFieldXml(field, indent) {
27
21
  }
28
22
  return `${indent}<field ${attrs.join(' ')}/>\n`;
29
23
  }
24
+ function fieldToJson(field) {
25
+ const result = {
26
+ name: field.name,
27
+ type: field.fieldType
28
+ };
29
+ if (field.isList)
30
+ result.list = true;
31
+ if (field.isGenerated)
32
+ result.generated = true;
33
+ if (field.isOptional)
34
+ result.optional = true;
35
+ if (field.subfields && field.subfields.length > 0) {
36
+ result.subfields = field.subfields.map(fieldToJson);
37
+ }
38
+ return result;
39
+ }
30
40
  // Find which aggregate an event belongs to (center point inside aggregate bounds)
31
41
  function findAggregateForEvent(model, event) {
32
42
  const centerX = event.position.x + event.width / 2;
@@ -47,7 +57,7 @@ function findAggregateForEvent(model, event) {
47
57
  function formatEventXml(model, event) {
48
58
  const aggregate = findAggregateForEvent(model, event);
49
59
  const aggregateAttr = aggregate ? ` aggregate="${escapeXml(aggregate.name)}"` : '';
50
- let xml = `<event name="${escapeXml(event.name)}"${aggregateAttr}>\n`;
60
+ let xml = `<event id="${event.id}" name="${escapeXml(event.name)}"${aggregateAttr}>\n`;
51
61
  if (event.fields.length > 0) {
52
62
  xml += ' <fields>\n';
53
63
  for (const field of event.fields) {
@@ -78,17 +88,31 @@ function formatEventXml(model, event) {
78
88
  xml += '</event>';
79
89
  return xml;
80
90
  }
81
- export function showEvent(model, name) {
82
- const events = [...model.events.values()];
83
- const nameLower = name.toLowerCase();
84
- const event = events.find(e => e.name.toLowerCase() === nameLower || e.name.toLowerCase().includes(nameLower));
85
- if (!event) {
86
- console.error(`Error: Event not found: ${name}`);
87
- console.error('Available events:');
88
- for (const e of events) {
89
- console.error(` - ${e.name}`);
90
- }
91
- process.exit(1);
91
+ export function showEvent(model, name, format) {
92
+ const event = findElementOrExit(model.events, name, 'event');
93
+ if (format === 'json') {
94
+ const aggregate = findAggregateForEvent(model, event);
95
+ const incomingFlows = [...model.flows.values()].filter(f => f.targetId === event.id);
96
+ const outgoingFlows = [...model.flows.values()].filter(f => f.sourceId === event.id);
97
+ const result = {
98
+ id: event.id,
99
+ name: event.name,
100
+ fields: event.fields.map(fieldToJson)
101
+ };
102
+ if (aggregate)
103
+ result.aggregate = aggregate.name;
104
+ const producedBy = incomingFlows
105
+ .map(f => model.commands.get(f.sourceId)?.name)
106
+ .filter(Boolean);
107
+ if (producedBy.length > 0)
108
+ result.producedBy = producedBy;
109
+ const consumedBy = outgoingFlows
110
+ .map(f => model.readModels.get(f.targetId)?.name)
111
+ .filter(Boolean);
112
+ if (consumedBy.length > 0)
113
+ result.consumedBy = consumedBy;
114
+ outputJson(result);
115
+ return;
92
116
  }
93
117
  console.log(formatEventXml(model, event));
94
118
  }
@@ -1,2 +1,3 @@
1
1
  import type { EventModel } from '../../types.js';
2
- export declare function showModelSummary(model: EventModel): void;
2
+ import { type OutputFormat } from '../../lib/format.js';
3
+ export declare function showModelSummary(model: EventModel, format: OutputFormat): void;
@@ -1,12 +1,21 @@
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) {
1
+ import { escapeXml, outputJson } from '../../lib/format.js';
2
+ export function showModelSummary(model, format) {
3
+ if (format === 'json') {
4
+ outputJson({
5
+ name: model.name,
6
+ slices: model.slices.size,
7
+ commands: model.commands.size,
8
+ events: model.events.size,
9
+ readModels: model.readModels.size,
10
+ screens: model.screens.size,
11
+ processors: model.processors.size,
12
+ aggregates: model.aggregates.size,
13
+ actors: model.actors.size,
14
+ scenarios: model.scenarios.size,
15
+ flows: model.flows.size
16
+ });
17
+ return;
18
+ }
10
19
  console.log(`<model name="${escapeXml(model.name)}">`);
11
20
  console.log(` <slices count="${model.slices.size}"/>`);
12
21
  console.log(` <commands count="${model.commands.size}"/>`);
@@ -1,2 +1,3 @@
1
1
  import type { EventModel } from '../../types.js';
2
- export declare function showSlice(model: EventModel, name: string): void;
2
+ import { type OutputFormat } from '../../lib/format.js';
3
+ export declare function showSlice(model: EventModel, name: string, format: OutputFormat): void;