eventmodeler 0.3.4 → 0.3.6
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/index.js +1274 -5
- package/dist/projection.js +99 -9
- package/dist/slices/map-fields/index.js +59 -8
- package/package.json +1 -1
package/dist/index.js
CHANGED
|
@@ -48,6 +48,9 @@ function getNamedArg(argList, ...names) {
|
|
|
48
48
|
}
|
|
49
49
|
return undefined;
|
|
50
50
|
}
|
|
51
|
+
function hasHelpFlag(argList) {
|
|
52
|
+
return argList.includes('-h') || argList.includes('--help');
|
|
53
|
+
}
|
|
51
54
|
function printHelp() {
|
|
52
55
|
console.log(`
|
|
53
56
|
eventmodeler - CLI tool for interacting with Event Model files
|
|
@@ -157,6 +160,7 @@ async function main() {
|
|
|
157
160
|
let formatArg = null;
|
|
158
161
|
let chapterArg = null;
|
|
159
162
|
const filteredArgs = [];
|
|
163
|
+
let helpRequested = false;
|
|
160
164
|
for (let i = 0; i < args.length; i++) {
|
|
161
165
|
if (args[i] === '-f' || args[i] === '--file') {
|
|
162
166
|
fileArg = args[++i];
|
|
@@ -167,18 +171,23 @@ async function main() {
|
|
|
167
171
|
else if (args[i] === '--chapter') {
|
|
168
172
|
chapterArg = args[++i];
|
|
169
173
|
}
|
|
170
|
-
else if (args[i] === '-h' || args[i] === '--help') {
|
|
171
|
-
printHelp();
|
|
172
|
-
process.exit(0);
|
|
173
|
-
}
|
|
174
174
|
else if (args[i] === '-v' || args[i] === '--version') {
|
|
175
175
|
console.log(`eventmodeler ${VERSION}`);
|
|
176
176
|
process.exit(0);
|
|
177
177
|
}
|
|
178
|
+
else if (args[i] === '-h' || args[i] === '--help') {
|
|
179
|
+
helpRequested = true;
|
|
180
|
+
}
|
|
178
181
|
else {
|
|
179
182
|
filteredArgs.push(args[i]);
|
|
180
183
|
}
|
|
181
184
|
}
|
|
185
|
+
// Handle --help: if no command specified, show general help
|
|
186
|
+
// Otherwise let command-specific help handle it
|
|
187
|
+
if (helpRequested && filteredArgs.length === 0) {
|
|
188
|
+
printHelp();
|
|
189
|
+
process.exit(0);
|
|
190
|
+
}
|
|
182
191
|
// Determine output format
|
|
183
192
|
const format = formatArg === 'json' ? 'json'
|
|
184
193
|
: formatArg === 'xml' ? 'xml'
|
|
@@ -195,6 +204,42 @@ async function main() {
|
|
|
195
204
|
}
|
|
196
205
|
// Handle diff and merge commands separately (they manage their own file loading)
|
|
197
206
|
if (command === 'diff') {
|
|
207
|
+
if (helpRequested) {
|
|
208
|
+
console.log(`
|
|
209
|
+
eventmodeler diff - Compare event model files semantically
|
|
210
|
+
|
|
211
|
+
USAGE:
|
|
212
|
+
eventmodeler diff <file1> <file2> [--format text|xml|json]
|
|
213
|
+
eventmodeler diff <file> [--ref <gitref>] [--format text|xml|json]
|
|
214
|
+
eventmodeler diff --base <file> --compare <file> [--format text|xml|json]
|
|
215
|
+
|
|
216
|
+
ARGUMENTS:
|
|
217
|
+
<file1> <file2> Two files to compare
|
|
218
|
+
<file> Single file to compare against git ref
|
|
219
|
+
|
|
220
|
+
OPTIONS:
|
|
221
|
+
--ref <gitref> Git reference to compare against (default: HEAD)
|
|
222
|
+
--base <file> Base file (alternative syntax)
|
|
223
|
+
--compare <file> Compare file (alternative syntax)
|
|
224
|
+
--format <format> Output format: text (default), xml, or json
|
|
225
|
+
|
|
226
|
+
OUTPUT:
|
|
227
|
+
Semantic differences between models:
|
|
228
|
+
- Added/removed/modified entities
|
|
229
|
+
- Field changes (with flag changes like isGenerated)
|
|
230
|
+
- Flow changes
|
|
231
|
+
- Scenario changes
|
|
232
|
+
|
|
233
|
+
Unlike line-based diff, this understands event model structure.
|
|
234
|
+
|
|
235
|
+
EXAMPLES:
|
|
236
|
+
eventmodeler diff model-v1.eventmodel model-v2.eventmodel
|
|
237
|
+
eventmodeler diff mymodel.eventmodel --ref HEAD~1
|
|
238
|
+
eventmodeler diff mymodel.eventmodel --ref main
|
|
239
|
+
eventmodeler diff model.eventmodel --format json
|
|
240
|
+
`);
|
|
241
|
+
process.exit(0);
|
|
242
|
+
}
|
|
198
243
|
const baseArg = getNamedArg(filteredArgs, '--base');
|
|
199
244
|
const compareArg = getNamedArg(filteredArgs, '--compare');
|
|
200
245
|
const refArg = getNamedArg(filteredArgs, '--ref');
|
|
@@ -223,9 +268,49 @@ async function main() {
|
|
|
223
268
|
console.error('Usage: eventmodeler diff <file1> <file2>');
|
|
224
269
|
console.error(' eventmodeler diff <file> [--ref <gitref>]');
|
|
225
270
|
console.error(' eventmodeler diff --base <file> --compare <file>');
|
|
271
|
+
console.error('Run "eventmodeler diff --help" for more information.');
|
|
226
272
|
process.exit(1);
|
|
227
273
|
}
|
|
228
274
|
if (command === 'merge') {
|
|
275
|
+
if (helpRequested) {
|
|
276
|
+
console.log(`
|
|
277
|
+
eventmodeler merge - Three-way merge of event model files
|
|
278
|
+
|
|
279
|
+
USAGE:
|
|
280
|
+
eventmodeler merge --base <file> --ours <file> --theirs <file> --output <file>
|
|
281
|
+
|
|
282
|
+
OPTIONS:
|
|
283
|
+
--base <file> Common ancestor file (required)
|
|
284
|
+
--ours <file> Our version file (required)
|
|
285
|
+
--theirs <file> Their version file (required)
|
|
286
|
+
--output <file> Output file path (required unless --dry-run)
|
|
287
|
+
--strategy <s> Auto-resolve conflicts: ours or theirs
|
|
288
|
+
--dry-run Show result without writing file
|
|
289
|
+
--format xml|json Output format for conflict reporting
|
|
290
|
+
|
|
291
|
+
HOW IT WORKS:
|
|
292
|
+
Performs semantic three-way merge:
|
|
293
|
+
1. Identifies changes in "ours" vs base
|
|
294
|
+
2. Identifies changes in "theirs" vs base
|
|
295
|
+
3. Auto-merges non-conflicting changes
|
|
296
|
+
4. Reports conflicts for manual resolution
|
|
297
|
+
|
|
298
|
+
CONFLICT RESOLUTION:
|
|
299
|
+
--strategy ours Keep our changes when conflicts occur
|
|
300
|
+
--strategy theirs Keep their changes when conflicts occur
|
|
301
|
+
|
|
302
|
+
EXAMPLES:
|
|
303
|
+
# Standard merge
|
|
304
|
+
eventmodeler merge --base base.eventmodel --ours mine.eventmodel --theirs theirs.eventmodel --output merged.eventmodel
|
|
305
|
+
|
|
306
|
+
# Auto-resolve with our changes taking precedence
|
|
307
|
+
eventmodeler merge --base base.eventmodel --ours mine.eventmodel --theirs theirs.eventmodel --output merged.eventmodel --strategy ours
|
|
308
|
+
|
|
309
|
+
# Preview merge without writing
|
|
310
|
+
eventmodeler merge --base base.eventmodel --ours mine.eventmodel --theirs theirs.eventmodel --dry-run
|
|
311
|
+
`);
|
|
312
|
+
process.exit(0);
|
|
313
|
+
}
|
|
229
314
|
const baseArg = getNamedArg(filteredArgs, '--base');
|
|
230
315
|
const oursArg = getNamedArg(filteredArgs, '--ours');
|
|
231
316
|
const theirsArg = getNamedArg(filteredArgs, '--theirs');
|
|
@@ -237,6 +322,7 @@ async function main() {
|
|
|
237
322
|
console.error('Options:');
|
|
238
323
|
console.error(' --strategy ours|theirs Auto-resolve conflicts');
|
|
239
324
|
console.error(' --dry-run Show result without writing');
|
|
325
|
+
console.error('Run "eventmodeler merge --help" for more information.');
|
|
240
326
|
process.exit(1);
|
|
241
327
|
}
|
|
242
328
|
if (!outputArg && !dryRun) {
|
|
@@ -257,16 +343,80 @@ async function main() {
|
|
|
257
343
|
if (command === 'git') {
|
|
258
344
|
const gitCommand = filteredArgs[1];
|
|
259
345
|
const globalFlag = filteredArgs.includes('--global');
|
|
346
|
+
if (helpRequested && !gitCommand) {
|
|
347
|
+
console.log(`
|
|
348
|
+
eventmodeler git - Git integration commands
|
|
349
|
+
|
|
350
|
+
USAGE:
|
|
351
|
+
eventmodeler git <command> [options]
|
|
352
|
+
|
|
353
|
+
COMMANDS:
|
|
354
|
+
setup Configure git for semantic diff/merge of .eventmodel files
|
|
355
|
+
status Show current git integration status
|
|
356
|
+
|
|
357
|
+
Run "eventmodeler git <command> --help" for command-specific help.
|
|
358
|
+
`);
|
|
359
|
+
process.exit(0);
|
|
360
|
+
}
|
|
260
361
|
switch (gitCommand) {
|
|
261
362
|
case 'setup':
|
|
363
|
+
if (helpRequested) {
|
|
364
|
+
console.log(`
|
|
365
|
+
eventmodeler git setup - Configure git for semantic diff/merge
|
|
366
|
+
|
|
367
|
+
USAGE:
|
|
368
|
+
eventmodeler git setup [--global]
|
|
369
|
+
|
|
370
|
+
OPTIONS:
|
|
371
|
+
--global Configure globally (for all repositories)
|
|
372
|
+
|
|
373
|
+
WHAT IT DOES:
|
|
374
|
+
1. Adds .gitattributes entry: *.eventmodel diff=eventmodel merge=eventmodel
|
|
375
|
+
2. Configures git diff driver for semantic comparison
|
|
376
|
+
3. Configures git merge driver for semantic merging
|
|
377
|
+
|
|
378
|
+
After setup:
|
|
379
|
+
- "git diff" shows semantic differences for .eventmodel files
|
|
380
|
+
- "git merge" performs semantic merging
|
|
381
|
+
- Conflicts are reported at entity level, not line level
|
|
382
|
+
|
|
383
|
+
LOCAL VS GLOBAL:
|
|
384
|
+
Without --global: Configures current repository only
|
|
385
|
+
With --global: Configures for all repositories (user-level)
|
|
386
|
+
|
|
387
|
+
EXAMPLES:
|
|
388
|
+
eventmodeler git setup # Configure current repo
|
|
389
|
+
eventmodeler git setup --global # Configure globally
|
|
390
|
+
`);
|
|
391
|
+
process.exit(0);
|
|
392
|
+
}
|
|
262
393
|
gitSetup(globalFlag);
|
|
263
394
|
return;
|
|
264
395
|
case 'status':
|
|
396
|
+
if (helpRequested) {
|
|
397
|
+
console.log(`
|
|
398
|
+
eventmodeler git status - Show git integration status
|
|
399
|
+
|
|
400
|
+
USAGE:
|
|
401
|
+
eventmodeler git status
|
|
402
|
+
|
|
403
|
+
OUTPUT:
|
|
404
|
+
Shows current configuration:
|
|
405
|
+
- Whether git drivers are configured
|
|
406
|
+
- Local vs global configuration status
|
|
407
|
+
- .gitattributes configuration status
|
|
408
|
+
|
|
409
|
+
EXAMPLES:
|
|
410
|
+
eventmodeler git status
|
|
411
|
+
`);
|
|
412
|
+
process.exit(0);
|
|
413
|
+
}
|
|
265
414
|
gitStatus();
|
|
266
415
|
return;
|
|
267
416
|
default:
|
|
268
417
|
console.error('Usage: eventmodeler git setup [--global]');
|
|
269
418
|
console.error(' eventmodeler git status');
|
|
419
|
+
console.error('Run "eventmodeler git --help" for more information.');
|
|
270
420
|
process.exit(1);
|
|
271
421
|
}
|
|
272
422
|
}
|
|
@@ -283,82 +433,461 @@ async function main() {
|
|
|
283
433
|
const model = loadModel(filePath);
|
|
284
434
|
switch (command) {
|
|
285
435
|
case 'list':
|
|
436
|
+
if (helpRequested && !subcommand) {
|
|
437
|
+
console.log(`
|
|
438
|
+
eventmodeler list - List entities in the event model
|
|
439
|
+
|
|
440
|
+
USAGE:
|
|
441
|
+
eventmodeler list <type> [options]
|
|
442
|
+
|
|
443
|
+
TYPES:
|
|
444
|
+
slices List all slices (with optional --chapter filter)
|
|
445
|
+
events List all events
|
|
446
|
+
commands List all commands
|
|
447
|
+
chapters List all chapters
|
|
448
|
+
aggregates List all aggregates
|
|
449
|
+
actors List all actors
|
|
450
|
+
|
|
451
|
+
OPTIONS:
|
|
452
|
+
--chapter <name> Filter slices by chapter (slices only)
|
|
453
|
+
--format xml|json Output format (default: xml)
|
|
454
|
+
|
|
455
|
+
EXAMPLES:
|
|
456
|
+
eventmodeler list slices
|
|
457
|
+
eventmodeler list slices --chapter "Order Management"
|
|
458
|
+
eventmodeler list events --format json
|
|
459
|
+
|
|
460
|
+
Run "eventmodeler list <type> --help" for type-specific help.
|
|
461
|
+
`);
|
|
462
|
+
process.exit(0);
|
|
463
|
+
}
|
|
286
464
|
switch (subcommand) {
|
|
287
465
|
case 'slices':
|
|
466
|
+
if (helpRequested) {
|
|
467
|
+
console.log(`
|
|
468
|
+
eventmodeler list slices - List all slices in the event model
|
|
469
|
+
|
|
470
|
+
USAGE:
|
|
471
|
+
eventmodeler list slices [--chapter <name>] [--format xml|json]
|
|
472
|
+
|
|
473
|
+
OPTIONS:
|
|
474
|
+
--chapter <name> Filter by chapter name
|
|
475
|
+
--format <format> Output format: xml (default) or json
|
|
476
|
+
|
|
477
|
+
OUTPUT FIELDS:
|
|
478
|
+
name Slice name
|
|
479
|
+
type state-change | automation | state-view
|
|
480
|
+
status created | in-progress | blocked | done
|
|
481
|
+
chapter Parent chapter name
|
|
482
|
+
|
|
483
|
+
EXAMPLES:
|
|
484
|
+
eventmodeler list slices
|
|
485
|
+
eventmodeler list slices --chapter "Order Management"
|
|
486
|
+
eventmodeler list slices --format json
|
|
487
|
+
`);
|
|
488
|
+
process.exit(0);
|
|
489
|
+
}
|
|
288
490
|
listSlices(model, format, chapterArg ?? undefined);
|
|
289
491
|
break;
|
|
290
492
|
case 'events':
|
|
493
|
+
if (helpRequested) {
|
|
494
|
+
console.log(`
|
|
495
|
+
eventmodeler list events - List all events in the event model
|
|
496
|
+
|
|
497
|
+
USAGE:
|
|
498
|
+
eventmodeler list events [--format xml|json]
|
|
499
|
+
|
|
500
|
+
OPTIONS:
|
|
501
|
+
--format <format> Output format: xml (default) or json
|
|
502
|
+
|
|
503
|
+
OUTPUT FIELDS:
|
|
504
|
+
name Event name
|
|
505
|
+
aggregate Parent aggregate name
|
|
506
|
+
|
|
507
|
+
NOTE: Linked copies (events referencing a canonical original) are excluded.
|
|
508
|
+
|
|
509
|
+
EXAMPLES:
|
|
510
|
+
eventmodeler list events
|
|
511
|
+
eventmodeler list events --format json
|
|
512
|
+
`);
|
|
513
|
+
process.exit(0);
|
|
514
|
+
}
|
|
291
515
|
listEvents(model, format);
|
|
292
516
|
break;
|
|
293
517
|
case 'commands':
|
|
518
|
+
if (helpRequested) {
|
|
519
|
+
console.log(`
|
|
520
|
+
eventmodeler list commands - List all commands in the event model
|
|
521
|
+
|
|
522
|
+
USAGE:
|
|
523
|
+
eventmodeler list commands [--format xml|json]
|
|
524
|
+
|
|
525
|
+
OPTIONS:
|
|
526
|
+
--format <format> Output format: xml (default) or json
|
|
527
|
+
|
|
528
|
+
OUTPUT FIELDS:
|
|
529
|
+
name Command name
|
|
530
|
+
aggregate Parent aggregate name
|
|
531
|
+
|
|
532
|
+
EXAMPLES:
|
|
533
|
+
eventmodeler list commands
|
|
534
|
+
eventmodeler list commands --format json
|
|
535
|
+
`);
|
|
536
|
+
process.exit(0);
|
|
537
|
+
}
|
|
294
538
|
listCommands(model, format);
|
|
295
539
|
break;
|
|
296
540
|
case 'chapters':
|
|
541
|
+
if (helpRequested) {
|
|
542
|
+
console.log(`
|
|
543
|
+
eventmodeler list chapters - List all chapters in the event model
|
|
544
|
+
|
|
545
|
+
USAGE:
|
|
546
|
+
eventmodeler list chapters [--format xml|json]
|
|
547
|
+
|
|
548
|
+
OPTIONS:
|
|
549
|
+
--format <format> Output format: xml (default) or json
|
|
550
|
+
|
|
551
|
+
OUTPUT FIELDS:
|
|
552
|
+
name Chapter name
|
|
553
|
+
sliceCount Number of slices in chapter
|
|
554
|
+
|
|
555
|
+
EXAMPLES:
|
|
556
|
+
eventmodeler list chapters
|
|
557
|
+
eventmodeler list chapters --format json
|
|
558
|
+
`);
|
|
559
|
+
process.exit(0);
|
|
560
|
+
}
|
|
297
561
|
listChapters(model, format);
|
|
298
562
|
break;
|
|
299
563
|
case 'aggregates':
|
|
564
|
+
if (helpRequested) {
|
|
565
|
+
console.log(`
|
|
566
|
+
eventmodeler list aggregates - List all aggregates in the event model
|
|
567
|
+
|
|
568
|
+
USAGE:
|
|
569
|
+
eventmodeler list aggregates [--format xml|json]
|
|
570
|
+
|
|
571
|
+
OPTIONS:
|
|
572
|
+
--format <format> Output format: xml (default) or json
|
|
573
|
+
|
|
574
|
+
OUTPUT FIELDS:
|
|
575
|
+
name Aggregate name
|
|
576
|
+
eventCount Number of events
|
|
577
|
+
commandCount Number of commands
|
|
578
|
+
|
|
579
|
+
EXAMPLES:
|
|
580
|
+
eventmodeler list aggregates
|
|
581
|
+
eventmodeler list aggregates --format json
|
|
582
|
+
`);
|
|
583
|
+
process.exit(0);
|
|
584
|
+
}
|
|
300
585
|
listAggregates(model, format);
|
|
301
586
|
break;
|
|
302
587
|
case 'actors':
|
|
588
|
+
if (helpRequested) {
|
|
589
|
+
console.log(`
|
|
590
|
+
eventmodeler list actors - List all actors in the event model
|
|
591
|
+
|
|
592
|
+
USAGE:
|
|
593
|
+
eventmodeler list actors [--format xml|json]
|
|
594
|
+
|
|
595
|
+
OPTIONS:
|
|
596
|
+
--format <format> Output format: xml (default) or json
|
|
597
|
+
|
|
598
|
+
OUTPUT FIELDS:
|
|
599
|
+
name Actor name
|
|
600
|
+
screenCount Number of screens
|
|
601
|
+
|
|
602
|
+
EXAMPLES:
|
|
603
|
+
eventmodeler list actors
|
|
604
|
+
eventmodeler list actors --format json
|
|
605
|
+
`);
|
|
606
|
+
process.exit(0);
|
|
607
|
+
}
|
|
303
608
|
listActors(model, format);
|
|
304
609
|
break;
|
|
305
610
|
default:
|
|
306
611
|
console.error(`Unknown list target: ${subcommand}`);
|
|
307
612
|
console.error('Valid targets: slices, events, commands, chapters, aggregates, actors');
|
|
613
|
+
console.error('Run "eventmodeler list --help" for more information.');
|
|
308
614
|
process.exit(1);
|
|
309
615
|
}
|
|
310
616
|
break;
|
|
311
617
|
case 'show':
|
|
618
|
+
if (helpRequested && !subcommand) {
|
|
619
|
+
console.log(`
|
|
620
|
+
eventmodeler show - Show detailed information about entities
|
|
621
|
+
|
|
622
|
+
USAGE:
|
|
623
|
+
eventmodeler show <type> <name> [options]
|
|
624
|
+
|
|
625
|
+
TYPES:
|
|
626
|
+
slice Show slice with components and flows
|
|
627
|
+
event Show event with all fields
|
|
628
|
+
command Show command with all fields
|
|
629
|
+
chapter Show chapter with slices and dependencies
|
|
630
|
+
completeness Show field mapping completeness for any element
|
|
631
|
+
model-completeness Show completeness of all flows
|
|
632
|
+
aggregate-completeness Show if events have aggregate ID field
|
|
633
|
+
actor Show actor with screens
|
|
634
|
+
|
|
635
|
+
OPTIONS:
|
|
636
|
+
--format xml|json Output format (default: xml)
|
|
637
|
+
|
|
638
|
+
EXAMPLES:
|
|
639
|
+
eventmodeler show slice "Place Order"
|
|
640
|
+
eventmodeler show event OrderPlaced
|
|
641
|
+
eventmodeler show completeness OrderSummary
|
|
642
|
+
|
|
643
|
+
Run "eventmodeler show <type> --help" for type-specific help.
|
|
644
|
+
`);
|
|
645
|
+
process.exit(0);
|
|
646
|
+
}
|
|
312
647
|
switch (subcommand) {
|
|
313
648
|
case 'slice':
|
|
649
|
+
if (helpRequested) {
|
|
650
|
+
console.log(`
|
|
651
|
+
eventmodeler show slice - Show detailed slice information
|
|
652
|
+
|
|
653
|
+
USAGE:
|
|
654
|
+
eventmodeler show slice <name> [--format xml|json]
|
|
655
|
+
|
|
656
|
+
ARGUMENTS:
|
|
657
|
+
<name> Slice name (spaces allowed without quotes)
|
|
658
|
+
|
|
659
|
+
OUTPUT INCLUDES:
|
|
660
|
+
- Slice type (state-change, automation, state-view)
|
|
661
|
+
- Status (created, in-progress, blocked, done)
|
|
662
|
+
- Components: screens, commands, events, read models, processors
|
|
663
|
+
- Each component's fields with types and flags
|
|
664
|
+
- Flow annotations and swimlane positions
|
|
665
|
+
- Inbound/outbound dependencies
|
|
666
|
+
- Scenarios (Given-When-Then specifications)
|
|
667
|
+
|
|
668
|
+
EXAMPLES:
|
|
669
|
+
eventmodeler show slice "Place Order"
|
|
670
|
+
eventmodeler show slice Place Order
|
|
671
|
+
eventmodeler show slice "Place Order" --format json
|
|
672
|
+
`);
|
|
673
|
+
process.exit(0);
|
|
674
|
+
}
|
|
314
675
|
if (!target) {
|
|
315
676
|
console.error('Usage: eventmodeler show slice <name>');
|
|
677
|
+
console.error('Run "eventmodeler show slice --help" for more information.');
|
|
316
678
|
process.exit(1);
|
|
317
679
|
}
|
|
318
680
|
showSlice(model, target, format);
|
|
319
681
|
break;
|
|
320
682
|
case 'event':
|
|
683
|
+
if (helpRequested) {
|
|
684
|
+
console.log(`
|
|
685
|
+
eventmodeler show event - Show detailed event information
|
|
686
|
+
|
|
687
|
+
USAGE:
|
|
688
|
+
eventmodeler show event <name> [--format xml|json]
|
|
689
|
+
|
|
690
|
+
ARGUMENTS:
|
|
691
|
+
<name> Event name (spaces allowed without quotes)
|
|
692
|
+
|
|
693
|
+
OUTPUT INCLUDES:
|
|
694
|
+
- Event name and aggregate
|
|
695
|
+
- All fields with:
|
|
696
|
+
- name: Field name
|
|
697
|
+
- type: UUID, String, Int, Long, Double, Decimal, Boolean, Date, DateTime, Custom
|
|
698
|
+
- isList: Whether field is an array
|
|
699
|
+
- isOptional: Whether field can be null
|
|
700
|
+
- isGenerated: Whether field is computed (not mapped from source)
|
|
701
|
+
- subfields: Nested fields for Custom types (recursive, with all flags)
|
|
702
|
+
|
|
703
|
+
FIELD OUTPUT FORMAT (XML):
|
|
704
|
+
<field name="orderId" type="UUID"/>
|
|
705
|
+
<field name="total" type="Decimal" isGenerated="true"/>
|
|
706
|
+
<field name="items" type="Custom" isList="true">
|
|
707
|
+
<field name="productId" type="UUID"/>
|
|
708
|
+
<field name="lineTotal" type="Decimal" isGenerated="true"/>
|
|
709
|
+
</field>
|
|
710
|
+
|
|
711
|
+
EXAMPLES:
|
|
712
|
+
eventmodeler show event OrderPlaced
|
|
713
|
+
eventmodeler show event "Order Placed" --format json
|
|
714
|
+
`);
|
|
715
|
+
process.exit(0);
|
|
716
|
+
}
|
|
321
717
|
if (!target) {
|
|
322
718
|
console.error('Usage: eventmodeler show event <name>');
|
|
719
|
+
console.error('Run "eventmodeler show event --help" for more information.');
|
|
323
720
|
process.exit(1);
|
|
324
721
|
}
|
|
325
722
|
showEvent(model, target, format);
|
|
326
723
|
break;
|
|
327
724
|
case 'command':
|
|
725
|
+
if (helpRequested) {
|
|
726
|
+
console.log(`
|
|
727
|
+
eventmodeler show command - Show detailed command information
|
|
728
|
+
|
|
729
|
+
USAGE:
|
|
730
|
+
eventmodeler show command <name> [--format xml|json]
|
|
731
|
+
|
|
732
|
+
ARGUMENTS:
|
|
733
|
+
<name> Command name (spaces allowed without quotes)
|
|
734
|
+
|
|
735
|
+
OUTPUT INCLUDES:
|
|
736
|
+
- Command name and aggregate
|
|
737
|
+
- All fields with types, flags, and nested subfields
|
|
738
|
+
|
|
739
|
+
EXAMPLES:
|
|
740
|
+
eventmodeler show command PlaceOrder
|
|
741
|
+
eventmodeler show command "Place Order" --format json
|
|
742
|
+
`);
|
|
743
|
+
process.exit(0);
|
|
744
|
+
}
|
|
328
745
|
if (!target) {
|
|
329
746
|
console.error('Usage: eventmodeler show command <name>');
|
|
747
|
+
console.error('Run "eventmodeler show command --help" for more information.');
|
|
330
748
|
process.exit(1);
|
|
331
749
|
}
|
|
332
750
|
showCommand(model, target, format);
|
|
333
751
|
break;
|
|
334
752
|
case 'chapter':
|
|
753
|
+
if (helpRequested) {
|
|
754
|
+
console.log(`
|
|
755
|
+
eventmodeler show chapter - Show detailed chapter information
|
|
756
|
+
|
|
757
|
+
USAGE:
|
|
758
|
+
eventmodeler show chapter <name> [--format xml|json]
|
|
759
|
+
|
|
760
|
+
ARGUMENTS:
|
|
761
|
+
<name> Chapter name
|
|
762
|
+
|
|
763
|
+
OUTPUT INCLUDES:
|
|
764
|
+
- All slices in the chapter
|
|
765
|
+
- Flow graph showing internal dependencies
|
|
766
|
+
- External dependencies (inbound/outbound)
|
|
767
|
+
|
|
768
|
+
EXAMPLES:
|
|
769
|
+
eventmodeler show chapter "Order Management"
|
|
770
|
+
eventmodeler show chapter "Order Management" --format json
|
|
771
|
+
`);
|
|
772
|
+
process.exit(0);
|
|
773
|
+
}
|
|
335
774
|
if (!target) {
|
|
336
775
|
console.error('Usage: eventmodeler show chapter <name>');
|
|
776
|
+
console.error('Run "eventmodeler show chapter --help" for more information.');
|
|
337
777
|
process.exit(1);
|
|
338
778
|
}
|
|
339
779
|
showChapter(model, target, format);
|
|
340
780
|
break;
|
|
341
781
|
case 'completeness':
|
|
782
|
+
if (helpRequested) {
|
|
783
|
+
console.log(`
|
|
784
|
+
eventmodeler show completeness - Show field mapping completeness
|
|
785
|
+
|
|
786
|
+
USAGE:
|
|
787
|
+
eventmodeler show completeness <name> [--format xml|json]
|
|
788
|
+
|
|
789
|
+
ARGUMENTS:
|
|
790
|
+
<name> Element name (command, event, read model, screen, or processor)
|
|
791
|
+
|
|
792
|
+
OUTPUT INCLUDES:
|
|
793
|
+
- Total fields vs mapped fields
|
|
794
|
+
- List of unmapped fields needing attention
|
|
795
|
+
- Mapping sources for mapped fields
|
|
796
|
+
|
|
797
|
+
IMPORTANT - GENERATED FIELDS:
|
|
798
|
+
Fields with isGenerated=true are EXCLUDED from completeness checks.
|
|
799
|
+
Generated fields are computed/synthesized values that don't need
|
|
800
|
+
source mappings (e.g., calculated totals, timestamps, derived data).
|
|
801
|
+
|
|
802
|
+
EXAMPLES:
|
|
803
|
+
eventmodeler show completeness OrderSummary
|
|
804
|
+
eventmodeler show completeness "Order Summary" --format json
|
|
805
|
+
`);
|
|
806
|
+
process.exit(0);
|
|
807
|
+
}
|
|
342
808
|
if (!target) {
|
|
343
809
|
console.error('Usage: eventmodeler show completeness <element-name>');
|
|
344
810
|
console.error('Searches: commands, events, read models, screens, processors');
|
|
811
|
+
console.error('Run "eventmodeler show completeness --help" for more information.');
|
|
345
812
|
process.exit(1);
|
|
346
813
|
}
|
|
347
814
|
showCompleteness(model, target, format);
|
|
348
815
|
break;
|
|
349
816
|
case 'model-completeness':
|
|
817
|
+
if (helpRequested) {
|
|
818
|
+
console.log(`
|
|
819
|
+
eventmodeler show model-completeness - Show completeness of all flows
|
|
820
|
+
|
|
821
|
+
USAGE:
|
|
822
|
+
eventmodeler show model-completeness [--format xml|json]
|
|
823
|
+
|
|
824
|
+
OUTPUT INCLUDES:
|
|
825
|
+
- Complete flows (all required fields mapped)
|
|
826
|
+
- Incomplete flows with missing mappings
|
|
827
|
+
- Overall completeness percentage
|
|
828
|
+
|
|
829
|
+
NOTE: Generated fields (isGenerated=true) are excluded from checks.
|
|
830
|
+
|
|
831
|
+
EXAMPLES:
|
|
832
|
+
eventmodeler show model-completeness
|
|
833
|
+
eventmodeler show model-completeness --format json
|
|
834
|
+
`);
|
|
835
|
+
process.exit(0);
|
|
836
|
+
}
|
|
350
837
|
showModelCompleteness(model, format);
|
|
351
838
|
break;
|
|
352
839
|
case 'aggregate-completeness':
|
|
840
|
+
if (helpRequested) {
|
|
841
|
+
console.log(`
|
|
842
|
+
eventmodeler show aggregate-completeness - Check aggregate ID field presence
|
|
843
|
+
|
|
844
|
+
USAGE:
|
|
845
|
+
eventmodeler show aggregate-completeness <name> [--format xml|json]
|
|
846
|
+
|
|
847
|
+
ARGUMENTS:
|
|
848
|
+
<name> Aggregate name
|
|
849
|
+
|
|
850
|
+
OUTPUT:
|
|
851
|
+
Lists all events in the aggregate and whether each has the
|
|
852
|
+
aggregate ID field (e.g., "orderId" for "Order" aggregate).
|
|
853
|
+
|
|
854
|
+
EXAMPLES:
|
|
855
|
+
eventmodeler show aggregate-completeness Order
|
|
856
|
+
eventmodeler show aggregate-completeness "Order" --format json
|
|
857
|
+
`);
|
|
858
|
+
process.exit(0);
|
|
859
|
+
}
|
|
353
860
|
if (!target) {
|
|
354
861
|
console.error('Usage: eventmodeler show aggregate-completeness <aggregate-name>');
|
|
862
|
+
console.error('Run "eventmodeler show aggregate-completeness --help" for more information.');
|
|
355
863
|
process.exit(1);
|
|
356
864
|
}
|
|
357
865
|
showAggregateCompleteness(model, target, format);
|
|
358
866
|
break;
|
|
359
867
|
case 'actor':
|
|
868
|
+
if (helpRequested) {
|
|
869
|
+
console.log(`
|
|
870
|
+
eventmodeler show actor - Show detailed actor information
|
|
871
|
+
|
|
872
|
+
USAGE:
|
|
873
|
+
eventmodeler show actor <name> [--format xml|json]
|
|
874
|
+
|
|
875
|
+
ARGUMENTS:
|
|
876
|
+
<name> Actor name
|
|
877
|
+
|
|
878
|
+
OUTPUT INCLUDES:
|
|
879
|
+
- Actor name
|
|
880
|
+
- All associated screens
|
|
881
|
+
|
|
882
|
+
EXAMPLES:
|
|
883
|
+
eventmodeler show actor Customer
|
|
884
|
+
eventmodeler show actor "Admin User" --format json
|
|
885
|
+
`);
|
|
886
|
+
process.exit(0);
|
|
887
|
+
}
|
|
360
888
|
if (!target) {
|
|
361
889
|
console.error('Usage: eventmodeler show actor <actor-name>');
|
|
890
|
+
console.error('Run "eventmodeler show actor --help" for more information.');
|
|
362
891
|
process.exit(1);
|
|
363
892
|
}
|
|
364
893
|
showActor(model, target, format);
|
|
@@ -366,17 +895,73 @@ async function main() {
|
|
|
366
895
|
default:
|
|
367
896
|
console.error(`Unknown show target: ${subcommand}`);
|
|
368
897
|
console.error('Valid targets: slice, event, command, chapter, completeness, model-completeness, aggregate-completeness, actor');
|
|
898
|
+
console.error('Run "eventmodeler show --help" for more information.');
|
|
369
899
|
process.exit(1);
|
|
370
900
|
}
|
|
371
901
|
break;
|
|
372
902
|
case 'search':
|
|
903
|
+
if (helpRequested) {
|
|
904
|
+
console.log(`
|
|
905
|
+
eventmodeler search - Search for entities by name
|
|
906
|
+
|
|
907
|
+
USAGE:
|
|
908
|
+
eventmodeler search <term> [--format xml|json]
|
|
909
|
+
|
|
910
|
+
ARGUMENTS:
|
|
911
|
+
<term> Search term (case-insensitive partial match)
|
|
912
|
+
|
|
913
|
+
OPTIONS:
|
|
914
|
+
--format <format> Output format: xml (default) or json
|
|
915
|
+
|
|
916
|
+
SEARCHES ACROSS:
|
|
917
|
+
- Slices
|
|
918
|
+
- Events
|
|
919
|
+
- Commands
|
|
920
|
+
- Read Models
|
|
921
|
+
- Screens
|
|
922
|
+
- Processors
|
|
923
|
+
- Chapters
|
|
924
|
+
- Aggregates
|
|
925
|
+
- Actors
|
|
926
|
+
|
|
927
|
+
EXAMPLES:
|
|
928
|
+
eventmodeler search order
|
|
929
|
+
eventmodeler search "payment" --format json
|
|
930
|
+
`);
|
|
931
|
+
process.exit(0);
|
|
932
|
+
}
|
|
373
933
|
if (!subcommand) {
|
|
374
934
|
console.error('Usage: eventmodeler search <term>');
|
|
935
|
+
console.error('Run "eventmodeler search --help" for more information.');
|
|
375
936
|
process.exit(1);
|
|
376
937
|
}
|
|
377
938
|
search(model, subcommand, format);
|
|
378
939
|
break;
|
|
379
940
|
case 'mark': {
|
|
941
|
+
if (helpRequested) {
|
|
942
|
+
console.log(`
|
|
943
|
+
eventmodeler mark - Mark a slice's status
|
|
944
|
+
|
|
945
|
+
USAGE:
|
|
946
|
+
eventmodeler mark <slice-name> <status>
|
|
947
|
+
|
|
948
|
+
ARGUMENTS:
|
|
949
|
+
<slice-name> Slice name (can include spaces)
|
|
950
|
+
<status> One of: created, in-progress, blocked, done
|
|
951
|
+
|
|
952
|
+
STATUSES:
|
|
953
|
+
created Initial state, not yet started
|
|
954
|
+
in-progress Currently being worked on
|
|
955
|
+
blocked Work paused due to dependency or issue
|
|
956
|
+
done Completed
|
|
957
|
+
|
|
958
|
+
EXAMPLES:
|
|
959
|
+
eventmodeler mark "Place Order" done
|
|
960
|
+
eventmodeler mark "Process Payment" in-progress
|
|
961
|
+
eventmodeler mark "Ship Order" blocked
|
|
962
|
+
`);
|
|
963
|
+
process.exit(0);
|
|
964
|
+
}
|
|
380
965
|
// mark <slice-name> <status> - status is last arg, slice name is everything before
|
|
381
966
|
// Note: subcommand contains first part of slice name, remainingArgs has the rest
|
|
382
967
|
const validStatuses = ['created', 'in-progress', 'blocked', 'done'];
|
|
@@ -385,6 +970,7 @@ async function main() {
|
|
|
385
970
|
if (allArgs.length < 2 || !validStatuses.includes(lastArg)) {
|
|
386
971
|
console.error('Usage: eventmodeler mark <slice-name> <status>');
|
|
387
972
|
console.error('Valid statuses: created, in-progress, blocked, done');
|
|
973
|
+
console.error('Run "eventmodeler mark --help" for more information.');
|
|
388
974
|
process.exit(1);
|
|
389
975
|
}
|
|
390
976
|
const sliceName = allArgs.slice(0, -1).join(' ');
|
|
@@ -393,22 +979,145 @@ async function main() {
|
|
|
393
979
|
break;
|
|
394
980
|
}
|
|
395
981
|
case 'summary':
|
|
982
|
+
if (helpRequested) {
|
|
983
|
+
console.log(`
|
|
984
|
+
eventmodeler summary - Show model summary statistics
|
|
985
|
+
|
|
986
|
+
USAGE:
|
|
987
|
+
eventmodeler summary [--format xml|json]
|
|
988
|
+
|
|
989
|
+
OPTIONS:
|
|
990
|
+
--format <format> Output format: xml (default) or json
|
|
991
|
+
|
|
992
|
+
OUTPUT:
|
|
993
|
+
Aggregate statistics including:
|
|
994
|
+
- Total counts (slices, events, commands, read models, screens, etc.)
|
|
995
|
+
- Slices by type (state-change, automation, state-view)
|
|
996
|
+
- Slices by status (created, in-progress, blocked, done)
|
|
997
|
+
- Chapter summary
|
|
998
|
+
|
|
999
|
+
EXAMPLES:
|
|
1000
|
+
eventmodeler summary
|
|
1001
|
+
eventmodeler summary --format json
|
|
1002
|
+
`);
|
|
1003
|
+
process.exit(0);
|
|
1004
|
+
}
|
|
396
1005
|
showModelSummary(model, format);
|
|
397
1006
|
break;
|
|
398
1007
|
case 'export':
|
|
1008
|
+
if (helpRequested && !subcommand) {
|
|
1009
|
+
console.log(`
|
|
1010
|
+
eventmodeler export - Export the model
|
|
1011
|
+
|
|
1012
|
+
USAGE:
|
|
1013
|
+
eventmodeler export <format>
|
|
1014
|
+
|
|
1015
|
+
FORMATS:
|
|
1016
|
+
json Export entire model as JSON
|
|
1017
|
+
|
|
1018
|
+
Run "eventmodeler export json --help" for detailed help.
|
|
1019
|
+
`);
|
|
1020
|
+
process.exit(0);
|
|
1021
|
+
}
|
|
399
1022
|
switch (subcommand) {
|
|
400
1023
|
case 'json':
|
|
1024
|
+
if (helpRequested) {
|
|
1025
|
+
console.log(`
|
|
1026
|
+
eventmodeler export json - Export entire model as JSON
|
|
1027
|
+
|
|
1028
|
+
USAGE:
|
|
1029
|
+
eventmodeler export json
|
|
1030
|
+
|
|
1031
|
+
OUTPUT:
|
|
1032
|
+
Complete event model as JSON to stdout, including:
|
|
1033
|
+
- All entities (slices, events, commands, read models, screens, etc.)
|
|
1034
|
+
- All flows and field mappings
|
|
1035
|
+
- All scenarios
|
|
1036
|
+
- Metadata (chapters, aggregates, actors)
|
|
1037
|
+
|
|
1038
|
+
EXAMPLES:
|
|
1039
|
+
eventmodeler export json
|
|
1040
|
+
eventmodeler export json > model.json
|
|
1041
|
+
eventmodeler export json | jq '.events'
|
|
1042
|
+
`);
|
|
1043
|
+
process.exit(0);
|
|
1044
|
+
}
|
|
401
1045
|
exportEventmodelToJson(model);
|
|
402
1046
|
break;
|
|
403
1047
|
default:
|
|
404
1048
|
console.error(`Unknown export format: ${subcommand}`);
|
|
405
1049
|
console.error('Valid formats: json');
|
|
1050
|
+
console.error('Run "eventmodeler export --help" for more information.');
|
|
406
1051
|
process.exit(1);
|
|
407
1052
|
}
|
|
408
1053
|
break;
|
|
409
1054
|
case 'add':
|
|
1055
|
+
if (helpRequested && !subcommand) {
|
|
1056
|
+
console.log(`
|
|
1057
|
+
eventmodeler add - Add entities to the model
|
|
1058
|
+
|
|
1059
|
+
USAGE:
|
|
1060
|
+
eventmodeler add <type> [options]
|
|
1061
|
+
|
|
1062
|
+
TYPES:
|
|
1063
|
+
scenario Add Given-When-Then scenario to a slice
|
|
1064
|
+
field Add field to command, event, read model, screen, or processor
|
|
1065
|
+
|
|
1066
|
+
Run "eventmodeler add <type> --help" for type-specific help.
|
|
1067
|
+
`);
|
|
1068
|
+
process.exit(0);
|
|
1069
|
+
}
|
|
410
1070
|
switch (subcommand) {
|
|
411
1071
|
case 'scenario': {
|
|
1072
|
+
if (helpRequested) {
|
|
1073
|
+
console.log(`
|
|
1074
|
+
eventmodeler add scenario - Add a scenario to a slice
|
|
1075
|
+
|
|
1076
|
+
USAGE:
|
|
1077
|
+
eventmodeler add scenario --slice <name> --json|--xml <data>
|
|
1078
|
+
|
|
1079
|
+
OPTIONS:
|
|
1080
|
+
--slice <name> Target slice name (required)
|
|
1081
|
+
--json <data> Scenario in JSON format
|
|
1082
|
+
--xml <data> Scenario in XML format
|
|
1083
|
+
|
|
1084
|
+
JSON FORMAT:
|
|
1085
|
+
{
|
|
1086
|
+
"name": "Scenario name",
|
|
1087
|
+
"given": { // Optional: preconditions
|
|
1088
|
+
"type": "events",
|
|
1089
|
+
"events": ["EventName1", "EventName2"]
|
|
1090
|
+
},
|
|
1091
|
+
"when": { // Optional: trigger
|
|
1092
|
+
"type": "command",
|
|
1093
|
+
"command": "CommandName"
|
|
1094
|
+
},
|
|
1095
|
+
"then": { // Required: expected outcome
|
|
1096
|
+
"type": "events",
|
|
1097
|
+
"events": ["ExpectedEvent"]
|
|
1098
|
+
}
|
|
1099
|
+
}
|
|
1100
|
+
|
|
1101
|
+
XML FORMAT:
|
|
1102
|
+
<scenario name="Scenario name">
|
|
1103
|
+
<given type="events">
|
|
1104
|
+
<event>EventName1</event>
|
|
1105
|
+
</given>
|
|
1106
|
+
<when type="command">
|
|
1107
|
+
<command>CommandName</command>
|
|
1108
|
+
</when>
|
|
1109
|
+
<then type="events">
|
|
1110
|
+
<event>ExpectedEvent</event>
|
|
1111
|
+
</then>
|
|
1112
|
+
</scenario>
|
|
1113
|
+
|
|
1114
|
+
EXAMPLES:
|
|
1115
|
+
eventmodeler add scenario --slice "Place Order" --json '{"name": "Happy path", "then": {"type": "events", "events": ["OrderPlaced"]}}'
|
|
1116
|
+
|
|
1117
|
+
eventmodeler add scenario --slice "Place Order" --xml '<scenario name="Out of stock"><given type="events"><event>ProductOutOfStock</event></given><then type="events"><event>OrderRejected</event></then></scenario>'
|
|
1118
|
+
`);
|
|
1119
|
+
process.exit(0);
|
|
1120
|
+
}
|
|
412
1121
|
const sliceArg = getNamedArg(filteredArgs, '--slice');
|
|
413
1122
|
const jsonArg = getNamedArg(filteredArgs, '--json');
|
|
414
1123
|
const xmlArg = getNamedArg(filteredArgs, '--xml');
|
|
@@ -416,17 +1125,114 @@ async function main() {
|
|
|
416
1125
|
if (!sliceArg) {
|
|
417
1126
|
console.error('Error: --slice is required');
|
|
418
1127
|
console.error('Usage: eventmodeler add scenario --slice <name> --json|--xml <data>');
|
|
1128
|
+
console.error('Run "eventmodeler add scenario --help" for detailed format.');
|
|
419
1129
|
process.exit(1);
|
|
420
1130
|
}
|
|
421
1131
|
if (!inputData) {
|
|
422
1132
|
console.error('Error: --json or --xml is required');
|
|
423
1133
|
console.error('Usage: eventmodeler add scenario --slice <name> --json|--xml <data>');
|
|
1134
|
+
console.error('Run "eventmodeler add scenario --help" for detailed format.');
|
|
424
1135
|
process.exit(1);
|
|
425
1136
|
}
|
|
426
1137
|
addScenario(model, filePath, sliceArg, inputData);
|
|
427
1138
|
break;
|
|
428
1139
|
}
|
|
429
1140
|
case 'field': {
|
|
1141
|
+
if (helpRequested) {
|
|
1142
|
+
console.log(`
|
|
1143
|
+
eventmodeler add field - Add a field to an entity
|
|
1144
|
+
|
|
1145
|
+
USAGE:
|
|
1146
|
+
eventmodeler add field --command|--event|--read-model|--screen|--processor <name> --json|--xml <data>
|
|
1147
|
+
|
|
1148
|
+
OPTIONS:
|
|
1149
|
+
--command <name> Target command name
|
|
1150
|
+
--event <name> Target event name
|
|
1151
|
+
--read-model <name> Target read model name
|
|
1152
|
+
--screen <name> Target screen name
|
|
1153
|
+
--processor <name> Target processor name
|
|
1154
|
+
--json <data> Field definition in JSON format
|
|
1155
|
+
--xml <data> Field definition in XML format
|
|
1156
|
+
|
|
1157
|
+
FIELD TYPES:
|
|
1158
|
+
UUID, String, Int, Long, Double, Decimal, Boolean, Date, DateTime, Custom
|
|
1159
|
+
|
|
1160
|
+
FIELD FLAGS (work on ALL fields including nested subfields):
|
|
1161
|
+
isList - Field contains multiple values (array)
|
|
1162
|
+
isOptional - Field may be null/missing
|
|
1163
|
+
isGenerated - Field is computed/synthesized, not mapped from source
|
|
1164
|
+
isUserInput - (Screen only) Field is entered by user
|
|
1165
|
+
|
|
1166
|
+
JSON FORMAT:
|
|
1167
|
+
Simple field:
|
|
1168
|
+
{"name": "orderId", "type": "UUID"}
|
|
1169
|
+
|
|
1170
|
+
Field with flags:
|
|
1171
|
+
{"name": "notes", "type": "String", "isOptional": true}
|
|
1172
|
+
{"name": "tags", "type": "String", "isList": true}
|
|
1173
|
+
{"name": "total", "type": "Decimal", "isGenerated": true}
|
|
1174
|
+
|
|
1175
|
+
Nested Custom field with subfields (ALL flags work on subfields):
|
|
1176
|
+
{
|
|
1177
|
+
"name": "lineItem",
|
|
1178
|
+
"type": "Custom",
|
|
1179
|
+
"subfields": [
|
|
1180
|
+
{"name": "productId", "type": "UUID"},
|
|
1181
|
+
{"name": "quantity", "type": "Int"},
|
|
1182
|
+
{"name": "unitPrice", "type": "Decimal"},
|
|
1183
|
+
{"name": "lineTotal", "type": "Decimal", "isGenerated": true}
|
|
1184
|
+
]
|
|
1185
|
+
}
|
|
1186
|
+
|
|
1187
|
+
List of Custom with generated subfields:
|
|
1188
|
+
{
|
|
1189
|
+
"name": "items",
|
|
1190
|
+
"type": "Custom",
|
|
1191
|
+
"isList": true,
|
|
1192
|
+
"subfields": [
|
|
1193
|
+
{"name": "sku", "type": "String"},
|
|
1194
|
+
{"name": "qty", "type": "Int"},
|
|
1195
|
+
{"name": "calculatedPrice", "type": "Decimal", "isGenerated": true}
|
|
1196
|
+
]
|
|
1197
|
+
}
|
|
1198
|
+
|
|
1199
|
+
XML FORMAT:
|
|
1200
|
+
Simple field:
|
|
1201
|
+
<field name="orderId" type="UUID"/>
|
|
1202
|
+
|
|
1203
|
+
Field with flags:
|
|
1204
|
+
<field name="notes" type="String" isOptional="true"/>
|
|
1205
|
+
<field name="tags" type="String" isList="true"/>
|
|
1206
|
+
<field name="total" type="Decimal" isGenerated="true"/>
|
|
1207
|
+
|
|
1208
|
+
Nested Custom field (ALL flags work on subfields):
|
|
1209
|
+
<field name="lineItem" type="Custom">
|
|
1210
|
+
<field name="productId" type="UUID"/>
|
|
1211
|
+
<field name="quantity" type="Int"/>
|
|
1212
|
+
<field name="unitPrice" type="Decimal"/>
|
|
1213
|
+
<field name="lineTotal" type="Decimal" isGenerated="true"/>
|
|
1214
|
+
</field>
|
|
1215
|
+
|
|
1216
|
+
List of Custom with flags on subfields:
|
|
1217
|
+
<field name="items" type="Custom" isList="true">
|
|
1218
|
+
<field name="sku" type="String"/>
|
|
1219
|
+
<field name="qty" type="Int"/>
|
|
1220
|
+
<field name="calculatedPrice" type="Decimal" isGenerated="true"/>
|
|
1221
|
+
<field name="notes" type="String" isOptional="true"/>
|
|
1222
|
+
</field>
|
|
1223
|
+
|
|
1224
|
+
NOTES:
|
|
1225
|
+
- Generated fields are excluded from completeness checks
|
|
1226
|
+
- Custom type fields must have subfields defined
|
|
1227
|
+
- Subfields support arbitrary nesting depth
|
|
1228
|
+
|
|
1229
|
+
EXAMPLES:
|
|
1230
|
+
eventmodeler add field --event OrderPlaced --json '{"name": "orderId", "type": "UUID"}'
|
|
1231
|
+
eventmodeler add field --read-model OrderSummary --json '{"name": "totalWithTax", "type": "Decimal", "isGenerated": true}'
|
|
1232
|
+
eventmodeler add field --event OrderPlaced --xml '<field name="item" type="Custom"><field name="price" type="Decimal"/><field name="tax" type="Decimal" isGenerated="true"/></field>'
|
|
1233
|
+
`);
|
|
1234
|
+
process.exit(0);
|
|
1235
|
+
}
|
|
430
1236
|
const commandArg = getNamedArg(filteredArgs, '--command');
|
|
431
1237
|
const eventArg = getNamedArg(filteredArgs, '--event');
|
|
432
1238
|
const readModelArg = getNamedArg(filteredArgs, '--read-model');
|
|
@@ -438,6 +1244,7 @@ async function main() {
|
|
|
438
1244
|
if (!inputData) {
|
|
439
1245
|
console.error('Error: --json or --xml is required');
|
|
440
1246
|
console.error('Usage: eventmodeler add field --command|--event|--read-model|--screen|--processor <name> --json|--xml <data>');
|
|
1247
|
+
console.error('Run "eventmodeler add field --help" for detailed format documentation.');
|
|
441
1248
|
process.exit(1);
|
|
442
1249
|
}
|
|
443
1250
|
addField(model, filePath, { command: commandArg, event: eventArg, readModel: readModelArg, screen: screenArg, processor: processorArg }, inputData);
|
|
@@ -450,18 +1257,74 @@ async function main() {
|
|
|
450
1257
|
}
|
|
451
1258
|
break;
|
|
452
1259
|
case 'remove':
|
|
1260
|
+
if (helpRequested && !subcommand) {
|
|
1261
|
+
console.log(`
|
|
1262
|
+
eventmodeler remove - Remove entities from the model
|
|
1263
|
+
|
|
1264
|
+
USAGE:
|
|
1265
|
+
eventmodeler remove <type> [options]
|
|
1266
|
+
|
|
1267
|
+
TYPES:
|
|
1268
|
+
scenario Remove a scenario from a slice
|
|
1269
|
+
field Remove a field from an entity
|
|
1270
|
+
|
|
1271
|
+
Run "eventmodeler remove <type> --help" for type-specific help.
|
|
1272
|
+
`);
|
|
1273
|
+
process.exit(0);
|
|
1274
|
+
}
|
|
453
1275
|
switch (subcommand) {
|
|
454
1276
|
case 'scenario': {
|
|
1277
|
+
if (helpRequested) {
|
|
1278
|
+
console.log(`
|
|
1279
|
+
eventmodeler remove scenario - Remove a scenario from a slice
|
|
1280
|
+
|
|
1281
|
+
USAGE:
|
|
1282
|
+
eventmodeler remove scenario <name> [--slice <slice-name>]
|
|
1283
|
+
|
|
1284
|
+
ARGUMENTS:
|
|
1285
|
+
<name> Scenario name to remove
|
|
1286
|
+
|
|
1287
|
+
OPTIONS:
|
|
1288
|
+
--slice <name> Limit search to specific slice (optional)
|
|
1289
|
+
|
|
1290
|
+
EXAMPLES:
|
|
1291
|
+
eventmodeler remove scenario "Happy path"
|
|
1292
|
+
eventmodeler remove scenario "Edge case" --slice "Place Order"
|
|
1293
|
+
`);
|
|
1294
|
+
process.exit(0);
|
|
1295
|
+
}
|
|
455
1296
|
const scenarioName = target;
|
|
456
1297
|
const sliceArg = getNamedArg(filteredArgs, '--slice');
|
|
457
1298
|
if (!scenarioName) {
|
|
458
1299
|
console.error('Usage: eventmodeler remove scenario <name> [--slice <slice-name>]');
|
|
1300
|
+
console.error('Run "eventmodeler remove scenario --help" for more information.');
|
|
459
1301
|
process.exit(1);
|
|
460
1302
|
}
|
|
461
1303
|
removeScenario(model, filePath, scenarioName, sliceArg);
|
|
462
1304
|
break;
|
|
463
1305
|
}
|
|
464
1306
|
case 'field': {
|
|
1307
|
+
if (helpRequested) {
|
|
1308
|
+
console.log(`
|
|
1309
|
+
eventmodeler remove field - Remove a field from an entity
|
|
1310
|
+
|
|
1311
|
+
USAGE:
|
|
1312
|
+
eventmodeler remove field --command|--event|--read-model|--screen|--processor <name> --field <field-name>
|
|
1313
|
+
|
|
1314
|
+
OPTIONS:
|
|
1315
|
+
--command <name> Target command name
|
|
1316
|
+
--event <name> Target event name
|
|
1317
|
+
--read-model <name> Target read model name
|
|
1318
|
+
--screen <name> Target screen name
|
|
1319
|
+
--processor <name> Target processor name
|
|
1320
|
+
--field <name> Field name to remove (required)
|
|
1321
|
+
|
|
1322
|
+
EXAMPLES:
|
|
1323
|
+
eventmodeler remove field --event OrderPlaced --field orderId
|
|
1324
|
+
eventmodeler remove field --read-model "Order Summary" --field notes
|
|
1325
|
+
`);
|
|
1326
|
+
process.exit(0);
|
|
1327
|
+
}
|
|
465
1328
|
const commandArg = getNamedArg(filteredArgs, '--command');
|
|
466
1329
|
const eventArg = getNamedArg(filteredArgs, '--event');
|
|
467
1330
|
const readModelArg = getNamedArg(filteredArgs, '--read-model');
|
|
@@ -471,6 +1334,7 @@ async function main() {
|
|
|
471
1334
|
if (!fieldArg) {
|
|
472
1335
|
console.error('Error: --field is required');
|
|
473
1336
|
console.error('Usage: eventmodeler remove field --command|--event|--read-model|--screen|--processor <name> --field <field-name>');
|
|
1337
|
+
console.error('Run "eventmodeler remove field --help" for more information.');
|
|
474
1338
|
process.exit(1);
|
|
475
1339
|
}
|
|
476
1340
|
removeField(model, filePath, { command: commandArg, event: eventArg, readModel: readModelArg, screen: screenArg, processor: processorArg }, fieldArg);
|
|
@@ -479,12 +1343,63 @@ async function main() {
|
|
|
479
1343
|
default:
|
|
480
1344
|
console.error(`Unknown remove target: ${subcommand}`);
|
|
481
1345
|
console.error('Valid targets: scenario, field');
|
|
1346
|
+
console.error('Run "eventmodeler remove --help" for more information.');
|
|
482
1347
|
process.exit(1);
|
|
483
1348
|
}
|
|
484
1349
|
break;
|
|
485
1350
|
case 'map':
|
|
1351
|
+
if (helpRequested && !subcommand) {
|
|
1352
|
+
console.log(`
|
|
1353
|
+
eventmodeler map - Set field mappings
|
|
1354
|
+
|
|
1355
|
+
USAGE:
|
|
1356
|
+
eventmodeler map <type> [options]
|
|
1357
|
+
|
|
1358
|
+
TYPES:
|
|
1359
|
+
fields Set field mappings on a flow
|
|
1360
|
+
|
|
1361
|
+
Run "eventmodeler map fields --help" for detailed help.
|
|
1362
|
+
`);
|
|
1363
|
+
process.exit(0);
|
|
1364
|
+
}
|
|
486
1365
|
switch (subcommand) {
|
|
487
1366
|
case 'fields': {
|
|
1367
|
+
if (helpRequested) {
|
|
1368
|
+
console.log(`
|
|
1369
|
+
eventmodeler map fields - Set field mappings on a flow
|
|
1370
|
+
|
|
1371
|
+
USAGE:
|
|
1372
|
+
eventmodeler map fields --flow <source→target> --json|--xml <mappings>
|
|
1373
|
+
|
|
1374
|
+
OPTIONS:
|
|
1375
|
+
--flow <spec> Flow as "SourceName→TargetName" (use → or ->)
|
|
1376
|
+
--json <data> Mappings in JSON format
|
|
1377
|
+
--xml <data> Mappings in XML format
|
|
1378
|
+
|
|
1379
|
+
JSON FORMAT:
|
|
1380
|
+
[
|
|
1381
|
+
{"from": "sourceField", "to": "targetField"},
|
|
1382
|
+
{"from": "amount", "to": "orderTotal"}
|
|
1383
|
+
]
|
|
1384
|
+
|
|
1385
|
+
XML FORMAT:
|
|
1386
|
+
<mappings>
|
|
1387
|
+
<mapping from="sourceField" to="targetField"/>
|
|
1388
|
+
<mapping from="amount" to="orderTotal"/>
|
|
1389
|
+
</mappings>
|
|
1390
|
+
|
|
1391
|
+
NOTES:
|
|
1392
|
+
- Mappings define how fields flow from source to target
|
|
1393
|
+
- Fields marked as isGenerated=true don't need mappings
|
|
1394
|
+
- Use "show completeness" to check mapping status
|
|
1395
|
+
|
|
1396
|
+
EXAMPLES:
|
|
1397
|
+
eventmodeler map fields --flow "OrderPlaced→OrderSummary" --json '[{"from": "total", "to": "totalAmount"}]'
|
|
1398
|
+
|
|
1399
|
+
eventmodeler map fields --flow "OrderPlaced->OrderSummary" --xml '<mappings><mapping from="total" to="totalAmount"/></mappings>'
|
|
1400
|
+
`);
|
|
1401
|
+
process.exit(0);
|
|
1402
|
+
}
|
|
488
1403
|
const flowArg = getNamedArg(filteredArgs, '--flow');
|
|
489
1404
|
const jsonArg = getNamedArg(filteredArgs, '--json');
|
|
490
1405
|
const xmlArg = getNamedArg(filteredArgs, '--xml');
|
|
@@ -492,11 +1407,13 @@ async function main() {
|
|
|
492
1407
|
if (!flowArg) {
|
|
493
1408
|
console.error('Error: --flow is required');
|
|
494
1409
|
console.error('Usage: eventmodeler map fields --flow <source→target> --json|--xml <mappings>');
|
|
1410
|
+
console.error('Run "eventmodeler map fields --help" for detailed format.');
|
|
495
1411
|
process.exit(1);
|
|
496
1412
|
}
|
|
497
1413
|
if (!inputData) {
|
|
498
1414
|
console.error('Error: --json or --xml is required');
|
|
499
1415
|
console.error('Usage: eventmodeler map fields --flow <source→target> --json|--xml <mappings>');
|
|
1416
|
+
console.error('Run "eventmodeler map fields --help" for detailed format.');
|
|
500
1417
|
process.exit(1);
|
|
501
1418
|
}
|
|
502
1419
|
mapFields(model, filePath, flowArg, inputData);
|
|
@@ -505,12 +1422,70 @@ async function main() {
|
|
|
505
1422
|
default:
|
|
506
1423
|
console.error(`Unknown map target: ${subcommand}`);
|
|
507
1424
|
console.error('Valid targets: fields');
|
|
1425
|
+
console.error('Run "eventmodeler map --help" for more information.');
|
|
508
1426
|
process.exit(1);
|
|
509
1427
|
}
|
|
510
1428
|
break;
|
|
511
1429
|
case 'update':
|
|
1430
|
+
if (helpRequested && !subcommand) {
|
|
1431
|
+
console.log(`
|
|
1432
|
+
eventmodeler update - Update entities in the model
|
|
1433
|
+
|
|
1434
|
+
USAGE:
|
|
1435
|
+
eventmodeler update <type> [options]
|
|
1436
|
+
|
|
1437
|
+
TYPES:
|
|
1438
|
+
field Update field properties
|
|
1439
|
+
|
|
1440
|
+
Run "eventmodeler update field --help" for detailed help.
|
|
1441
|
+
`);
|
|
1442
|
+
process.exit(0);
|
|
1443
|
+
}
|
|
512
1444
|
switch (subcommand) {
|
|
513
1445
|
case 'field': {
|
|
1446
|
+
if (helpRequested) {
|
|
1447
|
+
console.log(`
|
|
1448
|
+
eventmodeler update field - Update field properties
|
|
1449
|
+
|
|
1450
|
+
USAGE:
|
|
1451
|
+
eventmodeler update field --command|--event|--read-model|--screen|--processor <name> --field <field-name> [updates]
|
|
1452
|
+
|
|
1453
|
+
TARGET OPTIONS (one required):
|
|
1454
|
+
--command <name> Target command
|
|
1455
|
+
--event <name> Target event
|
|
1456
|
+
--read-model <name> Target read model
|
|
1457
|
+
--screen <name> Target screen
|
|
1458
|
+
--processor <name> Target processor
|
|
1459
|
+
|
|
1460
|
+
REQUIRED:
|
|
1461
|
+
--field <name> Field to update
|
|
1462
|
+
|
|
1463
|
+
UPDATE OPTIONS (at least one required):
|
|
1464
|
+
--optional true|false Set isOptional flag
|
|
1465
|
+
--generated true|false Set isGenerated flag
|
|
1466
|
+
--user-input true|false Set isUserInput flag (screen only)
|
|
1467
|
+
--type <type> Change field type
|
|
1468
|
+
|
|
1469
|
+
FIELD FLAGS EXPLAINED:
|
|
1470
|
+
isOptional Field may be null/missing
|
|
1471
|
+
isGenerated Field is computed, excluded from completeness checks
|
|
1472
|
+
isUserInput (Screen only) Field entered by user vs displayed
|
|
1473
|
+
|
|
1474
|
+
EXAMPLES:
|
|
1475
|
+
# Mark field as optional
|
|
1476
|
+
eventmodeler update field --read-model OrderSummary --field notes --optional true
|
|
1477
|
+
|
|
1478
|
+
# Mark field as generated (computed value, no mapping needed)
|
|
1479
|
+
eventmodeler update field --read-model OrderSummary --field totalWithTax --generated true
|
|
1480
|
+
|
|
1481
|
+
# Mark screen field as user input
|
|
1482
|
+
eventmodeler update field --screen "Order Form" --field quantity --user-input true
|
|
1483
|
+
|
|
1484
|
+
# Change field type
|
|
1485
|
+
eventmodeler update field --event OrderPlaced --field amount --type Decimal
|
|
1486
|
+
`);
|
|
1487
|
+
process.exit(0);
|
|
1488
|
+
}
|
|
514
1489
|
const commandArg = getNamedArg(filteredArgs, '--command');
|
|
515
1490
|
const eventArg = getNamedArg(filteredArgs, '--event');
|
|
516
1491
|
const readModelArg = getNamedArg(filteredArgs, '--read-model');
|
|
@@ -524,6 +1499,7 @@ async function main() {
|
|
|
524
1499
|
if (!fieldArg) {
|
|
525
1500
|
console.error('Error: --field is required');
|
|
526
1501
|
console.error('Usage: eventmodeler update field --command|--event|--read-model|--screen|--processor <name> --field <field-name> [--optional true|false] [--generated true|false] [--user-input true|false (screen only)]');
|
|
1502
|
+
console.error('Run "eventmodeler update field --help" for detailed options.');
|
|
527
1503
|
process.exit(1);
|
|
528
1504
|
}
|
|
529
1505
|
// --user-input is only valid for screens
|
|
@@ -546,6 +1522,7 @@ async function main() {
|
|
|
546
1522
|
}
|
|
547
1523
|
if (Object.keys(updates).length === 0) {
|
|
548
1524
|
console.error('Error: Must specify at least one update (--optional, --generated, --user-input, or --type)');
|
|
1525
|
+
console.error('Run "eventmodeler update field --help" for available options.');
|
|
549
1526
|
process.exit(1);
|
|
550
1527
|
}
|
|
551
1528
|
updateField(model, filePath, { command: commandArg, event: eventArg, readModel: readModelArg, screen: screenArg, processor: processorArg }, fieldArg, updates);
|
|
@@ -554,48 +1531,294 @@ async function main() {
|
|
|
554
1531
|
default:
|
|
555
1532
|
console.error(`Unknown update target: ${subcommand}`);
|
|
556
1533
|
console.error('Valid targets: field');
|
|
1534
|
+
console.error('Run "eventmodeler update --help" for more information.');
|
|
557
1535
|
process.exit(1);
|
|
558
1536
|
}
|
|
559
1537
|
break;
|
|
560
1538
|
case 'create':
|
|
1539
|
+
if (helpRequested && !subcommand) {
|
|
1540
|
+
console.log(`
|
|
1541
|
+
eventmodeler create - Create new slices and flows
|
|
1542
|
+
|
|
1543
|
+
USAGE:
|
|
1544
|
+
eventmodeler create <type> [options]
|
|
1545
|
+
|
|
1546
|
+
TYPES:
|
|
1547
|
+
state-change-slice Create Screen → Command → Event slice
|
|
1548
|
+
automation-slice Create ReadModel → Processor → Command → Event slice
|
|
1549
|
+
state-view-slice Create ReadModel-only slice
|
|
1550
|
+
flow Create flow between elements
|
|
1551
|
+
|
|
1552
|
+
Run "eventmodeler create <type> --help" for type-specific help.
|
|
1553
|
+
`);
|
|
1554
|
+
process.exit(0);
|
|
1555
|
+
}
|
|
561
1556
|
switch (subcommand) {
|
|
562
1557
|
case 'state-change-slice': {
|
|
1558
|
+
if (helpRequested) {
|
|
1559
|
+
console.log(`
|
|
1560
|
+
eventmodeler create state-change-slice - Create a state-change slice
|
|
1561
|
+
|
|
1562
|
+
A state-change slice represents user action: Screen → Command → Event
|
|
1563
|
+
|
|
1564
|
+
USAGE:
|
|
1565
|
+
eventmodeler create state-change-slice --xml <data>
|
|
1566
|
+
|
|
1567
|
+
XML FORMAT:
|
|
1568
|
+
<state-change-slice name="Slice Name" [after="Slice Name"] [before="Slice Name"]>
|
|
1569
|
+
<screen name="Screen Name" actor="Actor Name">
|
|
1570
|
+
<field name="fieldName" type="Type" [flags]/>
|
|
1571
|
+
</screen>
|
|
1572
|
+
<command name="CommandName">
|
|
1573
|
+
<field name="fieldName" type="Type" [flags]/>
|
|
1574
|
+
</command>
|
|
1575
|
+
<event name="EventName">
|
|
1576
|
+
<field name="fieldName" type="Type" [flags]/>
|
|
1577
|
+
</event>
|
|
1578
|
+
</state-change-slice>
|
|
1579
|
+
|
|
1580
|
+
POSITIONING (IMPORTANT):
|
|
1581
|
+
after="Slice Name" Place this slice immediately after the named slice
|
|
1582
|
+
before="Slice Name" Place this slice immediately before the named slice
|
|
1583
|
+
(shifts existing slices to the right)
|
|
1584
|
+
|
|
1585
|
+
If neither is specified, the slice is placed at the rightmost position.
|
|
1586
|
+
Use "eventmodeler list slices" to see existing slice names for positioning.
|
|
1587
|
+
|
|
1588
|
+
FIELD TYPES:
|
|
1589
|
+
UUID, String, Int, Long, Double, Decimal, Boolean, Date, DateTime, Custom
|
|
1590
|
+
|
|
1591
|
+
FIELD FLAGS (work on ALL fields and nested subfields):
|
|
1592
|
+
isList="true" Array/list of values
|
|
1593
|
+
isOptional="true" Nullable field
|
|
1594
|
+
isGenerated="true" Computed field (excluded from mapping completeness)
|
|
1595
|
+
isUserInput="true" User-entered field (screen fields only)
|
|
1596
|
+
|
|
1597
|
+
NESTED CUSTOM FIELDS:
|
|
1598
|
+
<field name="address" type="Custom">
|
|
1599
|
+
<field name="street" type="String"/>
|
|
1600
|
+
<field name="city" type="String"/>
|
|
1601
|
+
<field name="formattedFull" type="String" isGenerated="true"/>
|
|
1602
|
+
</field>
|
|
1603
|
+
|
|
1604
|
+
EXAMPLES:
|
|
1605
|
+
# Create slice at the end (default)
|
|
1606
|
+
eventmodeler create state-change-slice --xml '
|
|
1607
|
+
<state-change-slice name="Place Order">
|
|
1608
|
+
<screen name="Order Form" actor="Customer">
|
|
1609
|
+
<field name="productId" type="UUID" isUserInput="true"/>
|
|
1610
|
+
</screen>
|
|
1611
|
+
<command name="PlaceOrder">
|
|
1612
|
+
<field name="productId" type="UUID"/>
|
|
1613
|
+
</command>
|
|
1614
|
+
<event name="OrderPlaced">
|
|
1615
|
+
<field name="orderId" type="UUID"/>
|
|
1616
|
+
<field name="productId" type="UUID"/>
|
|
1617
|
+
</event>
|
|
1618
|
+
</state-change-slice>'
|
|
1619
|
+
|
|
1620
|
+
# Create slice after an existing slice
|
|
1621
|
+
eventmodeler create state-change-slice --xml '
|
|
1622
|
+
<state-change-slice name="Confirm Order" after="Place Order">
|
|
1623
|
+
...
|
|
1624
|
+
</state-change-slice>'
|
|
1625
|
+
|
|
1626
|
+
# Create slice before an existing slice (shifts others right)
|
|
1627
|
+
eventmodeler create state-change-slice --xml '
|
|
1628
|
+
<state-change-slice name="Review Cart" before="Place Order">
|
|
1629
|
+
...
|
|
1630
|
+
</state-change-slice>'
|
|
1631
|
+
`);
|
|
1632
|
+
process.exit(0);
|
|
1633
|
+
}
|
|
563
1634
|
const xmlArg = getNamedArg(filteredArgs, '--xml');
|
|
564
1635
|
if (!xmlArg) {
|
|
565
1636
|
console.error('Error: --xml is required');
|
|
566
1637
|
console.error('Usage: eventmodeler create state-change-slice --xml \'<state-change-slice>...</state-change-slice>\'');
|
|
1638
|
+
console.error('Run "eventmodeler create state-change-slice --help" for detailed format.');
|
|
567
1639
|
process.exit(1);
|
|
568
1640
|
}
|
|
569
1641
|
createStateChangeSlice(model, filePath, xmlArg);
|
|
570
1642
|
break;
|
|
571
1643
|
}
|
|
572
1644
|
case 'automation-slice': {
|
|
1645
|
+
if (helpRequested) {
|
|
1646
|
+
console.log(`
|
|
1647
|
+
eventmodeler create automation-slice - Create an automation slice
|
|
1648
|
+
|
|
1649
|
+
An automation slice represents system automation: ReadModel → Processor → Command → Event
|
|
1650
|
+
|
|
1651
|
+
USAGE:
|
|
1652
|
+
eventmodeler create automation-slice --xml <data>
|
|
1653
|
+
|
|
1654
|
+
XML FORMAT:
|
|
1655
|
+
<automation-slice name="Slice Name" [after="Slice Name"] [before="Slice Name"]>
|
|
1656
|
+
<read-model name="ReadModelName">
|
|
1657
|
+
<field name="fieldName" type="Type" [flags]/>
|
|
1658
|
+
</read-model>
|
|
1659
|
+
<processor name="ProcessorName">
|
|
1660
|
+
<field name="fieldName" type="Type" [flags]/>
|
|
1661
|
+
</processor>
|
|
1662
|
+
<command name="CommandName">
|
|
1663
|
+
<field name="fieldName" type="Type" [flags]/>
|
|
1664
|
+
</command>
|
|
1665
|
+
<event name="EventName">
|
|
1666
|
+
<field name="fieldName" type="Type" [flags]/>
|
|
1667
|
+
</event>
|
|
1668
|
+
</automation-slice>
|
|
1669
|
+
|
|
1670
|
+
POSITIONING (IMPORTANT):
|
|
1671
|
+
after="Slice Name" Place this slice immediately after the named slice
|
|
1672
|
+
before="Slice Name" Place this slice immediately before the named slice
|
|
1673
|
+
(shifts existing slices to the right)
|
|
1674
|
+
|
|
1675
|
+
If neither is specified, the slice is placed at the rightmost position.
|
|
1676
|
+
Use "eventmodeler list slices" to see existing slice names for positioning.
|
|
1677
|
+
|
|
1678
|
+
FIELD TYPES:
|
|
1679
|
+
UUID, String, Int, Long, Double, Decimal, Boolean, Date, DateTime, Custom
|
|
1680
|
+
|
|
1681
|
+
FIELD FLAGS (work on ALL fields and nested subfields):
|
|
1682
|
+
isList="true" Array/list of values
|
|
1683
|
+
isOptional="true" Nullable field
|
|
1684
|
+
isGenerated="true" Computed field (excluded from mapping completeness)
|
|
1685
|
+
|
|
1686
|
+
EXAMPLES:
|
|
1687
|
+
# Create automation slice after "Place Order" slice
|
|
1688
|
+
eventmodeler create automation-slice --xml '
|
|
1689
|
+
<automation-slice name="Auto-ship Order" after="Place Order">
|
|
1690
|
+
<read-model name="OrderReadyForShipment">
|
|
1691
|
+
<field name="orderId" type="UUID"/>
|
|
1692
|
+
<field name="shippingAddress" type="String"/>
|
|
1693
|
+
</read-model>
|
|
1694
|
+
<processor name="ShipmentScheduler">
|
|
1695
|
+
<field name="orderId" type="UUID"/>
|
|
1696
|
+
</processor>
|
|
1697
|
+
<command name="ScheduleShipment">
|
|
1698
|
+
<field name="orderId" type="UUID"/>
|
|
1699
|
+
</command>
|
|
1700
|
+
<event name="ShipmentScheduled">
|
|
1701
|
+
<field name="shipmentId" type="UUID" isGenerated="true"/>
|
|
1702
|
+
<field name="orderId" type="UUID"/>
|
|
1703
|
+
<field name="scheduledAt" type="DateTime" isGenerated="true"/>
|
|
1704
|
+
</event>
|
|
1705
|
+
</automation-slice>'
|
|
1706
|
+
|
|
1707
|
+
# Create automation slice before another slice
|
|
1708
|
+
eventmodeler create automation-slice --xml '
|
|
1709
|
+
<automation-slice name="Validate Inventory" before="Auto-ship Order">
|
|
1710
|
+
...
|
|
1711
|
+
</automation-slice>'
|
|
1712
|
+
`);
|
|
1713
|
+
process.exit(0);
|
|
1714
|
+
}
|
|
573
1715
|
const xmlArg = getNamedArg(filteredArgs, '--xml');
|
|
574
1716
|
if (!xmlArg) {
|
|
575
1717
|
console.error('Error: --xml is required');
|
|
576
1718
|
console.error('Usage: eventmodeler create automation-slice --xml \'<automation-slice>...</automation-slice>\'');
|
|
1719
|
+
console.error('Run "eventmodeler create automation-slice --help" for detailed format.');
|
|
577
1720
|
process.exit(1);
|
|
578
1721
|
}
|
|
579
1722
|
createAutomationSlice(model, filePath, xmlArg);
|
|
580
1723
|
break;
|
|
581
1724
|
}
|
|
582
1725
|
case 'state-view-slice': {
|
|
1726
|
+
if (helpRequested) {
|
|
1727
|
+
console.log(`
|
|
1728
|
+
eventmodeler create state-view-slice - Create a state-view slice
|
|
1729
|
+
|
|
1730
|
+
A state-view slice represents a read model for displaying data.
|
|
1731
|
+
|
|
1732
|
+
USAGE:
|
|
1733
|
+
eventmodeler create state-view-slice --xml <data>
|
|
1734
|
+
|
|
1735
|
+
XML FORMAT:
|
|
1736
|
+
<state-view-slice name="Slice Name" [after="Slice Name"] [before="Slice Name"]>
|
|
1737
|
+
<read-model name="ReadModelName">
|
|
1738
|
+
<field name="fieldName" type="Type" [flags]/>
|
|
1739
|
+
</read-model>
|
|
1740
|
+
</state-view-slice>
|
|
1741
|
+
|
|
1742
|
+
POSITIONING (IMPORTANT):
|
|
1743
|
+
after="Slice Name" Place this slice immediately after the named slice
|
|
1744
|
+
before="Slice Name" Place this slice immediately before the named slice
|
|
1745
|
+
(shifts existing slices to the right)
|
|
1746
|
+
|
|
1747
|
+
If neither is specified, the slice is placed at the rightmost position.
|
|
1748
|
+
Use "eventmodeler list slices" to see existing slice names for positioning.
|
|
1749
|
+
|
|
1750
|
+
FIELD TYPES:
|
|
1751
|
+
UUID, String, Int, Long, Double, Decimal, Boolean, Date, DateTime, Custom
|
|
1752
|
+
|
|
1753
|
+
FIELD FLAGS (work on ALL fields and nested subfields):
|
|
1754
|
+
isList="true" Array/list of values
|
|
1755
|
+
isOptional="true" Nullable field
|
|
1756
|
+
isGenerated="true" Computed/aggregated field (common for dashboards)
|
|
1757
|
+
|
|
1758
|
+
EXAMPLES:
|
|
1759
|
+
# Create state-view slice after "Place Order" slice
|
|
1760
|
+
eventmodeler create state-view-slice --xml '
|
|
1761
|
+
<state-view-slice name="Order Dashboard" after="Place Order">
|
|
1762
|
+
<read-model name="OrderDashboard">
|
|
1763
|
+
<field name="totalOrders" type="Int" isGenerated="true"/>
|
|
1764
|
+
<field name="totalRevenue" type="Decimal" isGenerated="true"/>
|
|
1765
|
+
<field name="averageOrderValue" type="Decimal" isGenerated="true"/>
|
|
1766
|
+
<field name="recentOrders" type="Custom" isList="true">
|
|
1767
|
+
<field name="orderId" type="UUID"/>
|
|
1768
|
+
<field name="total" type="Decimal"/>
|
|
1769
|
+
<field name="status" type="String"/>
|
|
1770
|
+
</field>
|
|
1771
|
+
</read-model>
|
|
1772
|
+
</state-view-slice>'
|
|
1773
|
+
|
|
1774
|
+
# Create state-view slice before another slice
|
|
1775
|
+
eventmodeler create state-view-slice --xml '
|
|
1776
|
+
<state-view-slice name="Customer Summary" before="Order Dashboard">
|
|
1777
|
+
...
|
|
1778
|
+
</state-view-slice>'
|
|
1779
|
+
`);
|
|
1780
|
+
process.exit(0);
|
|
1781
|
+
}
|
|
583
1782
|
const xmlArg = getNamedArg(filteredArgs, '--xml');
|
|
584
1783
|
if (!xmlArg) {
|
|
585
1784
|
console.error('Error: --xml is required');
|
|
586
1785
|
console.error('Usage: eventmodeler create state-view-slice --xml \'<state-view-slice>...</state-view-slice>\'');
|
|
1786
|
+
console.error('Run "eventmodeler create state-view-slice --help" for detailed format.');
|
|
587
1787
|
process.exit(1);
|
|
588
1788
|
}
|
|
589
1789
|
createStateViewSlice(model, filePath, xmlArg);
|
|
590
1790
|
break;
|
|
591
1791
|
}
|
|
592
1792
|
case 'flow': {
|
|
1793
|
+
if (helpRequested) {
|
|
1794
|
+
console.log(`
|
|
1795
|
+
eventmodeler create flow - Create a flow between elements
|
|
1796
|
+
|
|
1797
|
+
USAGE:
|
|
1798
|
+
eventmodeler create flow --from <source> --to <target>
|
|
1799
|
+
|
|
1800
|
+
OPTIONS:
|
|
1801
|
+
--from <name> Source element name (required)
|
|
1802
|
+
--to <name> Target element name (required)
|
|
1803
|
+
|
|
1804
|
+
VALID FLOW TYPES:
|
|
1805
|
+
Event → ReadModel Event data projects into read model
|
|
1806
|
+
ReadModel → Screen Read model provides data to UI
|
|
1807
|
+
ReadModel → Processor Read model triggers automation
|
|
1808
|
+
|
|
1809
|
+
EXAMPLES:
|
|
1810
|
+
eventmodeler create flow --from OrderPlaced --to OrderSummary
|
|
1811
|
+
eventmodeler create flow --from "Order Summary" --to "Order Dashboard Screen"
|
|
1812
|
+
eventmodeler create flow --from OrderReadyForShipment --to ShipmentProcessor
|
|
1813
|
+
`);
|
|
1814
|
+
process.exit(0);
|
|
1815
|
+
}
|
|
593
1816
|
const fromArg = getNamedArg(filteredArgs, '--from');
|
|
594
1817
|
const toArg = getNamedArg(filteredArgs, '--to');
|
|
595
1818
|
if (!fromArg || !toArg) {
|
|
596
1819
|
console.error('Error: --from and --to are required');
|
|
597
1820
|
console.error('Usage: eventmodeler create flow --from <source> --to <target>');
|
|
598
|
-
console.error('
|
|
1821
|
+
console.error('Run "eventmodeler create flow --help" for more information.');
|
|
599
1822
|
process.exit(1);
|
|
600
1823
|
}
|
|
601
1824
|
createFlow(model, filePath, fromArg, toArg);
|
|
@@ -604,16 +1827,61 @@ async function main() {
|
|
|
604
1827
|
default:
|
|
605
1828
|
console.error(`Unknown create target: ${subcommand}`);
|
|
606
1829
|
console.error('Valid targets: state-change-slice, automation-slice, state-view-slice, flow');
|
|
1830
|
+
console.error('Run "eventmodeler create --help" for more information.');
|
|
607
1831
|
process.exit(1);
|
|
608
1832
|
}
|
|
609
1833
|
break;
|
|
610
1834
|
case 'codegen':
|
|
1835
|
+
if (helpRequested && !subcommand) {
|
|
1836
|
+
console.log(`
|
|
1837
|
+
eventmodeler codegen - Generate code-ready output
|
|
1838
|
+
|
|
1839
|
+
USAGE:
|
|
1840
|
+
eventmodeler codegen <type> [options]
|
|
1841
|
+
|
|
1842
|
+
TYPES:
|
|
1843
|
+
slice Generate comprehensive JSON for a slice
|
|
1844
|
+
|
|
1845
|
+
Run "eventmodeler codegen slice --help" for detailed help.
|
|
1846
|
+
`);
|
|
1847
|
+
process.exit(0);
|
|
1848
|
+
}
|
|
611
1849
|
switch (subcommand) {
|
|
612
1850
|
case 'slice': {
|
|
1851
|
+
if (helpRequested) {
|
|
1852
|
+
console.log(`
|
|
1853
|
+
eventmodeler codegen slice - Generate code-ready JSON for a slice
|
|
1854
|
+
|
|
1855
|
+
USAGE:
|
|
1856
|
+
eventmodeler codegen slice <name>
|
|
1857
|
+
|
|
1858
|
+
ARGUMENTS:
|
|
1859
|
+
<name> Slice name
|
|
1860
|
+
|
|
1861
|
+
OUTPUT:
|
|
1862
|
+
Comprehensive JSON including:
|
|
1863
|
+
- Slice metadata (name, type, chapter, aggregate)
|
|
1864
|
+
- All components with full field definitions
|
|
1865
|
+
- Fields include: name, type, isList, isOptional, isGenerated
|
|
1866
|
+
- Nested subfields for Custom types (all flags preserved)
|
|
1867
|
+
- Field mappings between components
|
|
1868
|
+
- Scenarios (Given-When-Then specifications)
|
|
1869
|
+
- Dependencies (inbound/outbound flows)
|
|
1870
|
+
|
|
1871
|
+
This output is designed for code generation tools and includes
|
|
1872
|
+
all information needed to generate implementation code.
|
|
1873
|
+
|
|
1874
|
+
EXAMPLES:
|
|
1875
|
+
eventmodeler codegen slice "Place Order"
|
|
1876
|
+
eventmodeler codegen slice PlaceOrder > slice.json
|
|
1877
|
+
`);
|
|
1878
|
+
process.exit(0);
|
|
1879
|
+
}
|
|
613
1880
|
const sliceName = filteredArgs[2];
|
|
614
1881
|
if (!sliceName) {
|
|
615
1882
|
console.error('Error: slice name is required');
|
|
616
1883
|
console.error('Usage: eventmodeler codegen slice <name>');
|
|
1884
|
+
console.error('Run "eventmodeler codegen slice --help" for more information.');
|
|
617
1885
|
process.exit(1);
|
|
618
1886
|
}
|
|
619
1887
|
codegenSlice(model, sliceName);
|
|
@@ -622,6 +1890,7 @@ async function main() {
|
|
|
622
1890
|
default:
|
|
623
1891
|
console.error(`Unknown codegen target: ${subcommand}`);
|
|
624
1892
|
console.error('Valid targets: slice');
|
|
1893
|
+
console.error('Run "eventmodeler codegen --help" for more information.');
|
|
625
1894
|
process.exit(1);
|
|
626
1895
|
}
|
|
627
1896
|
break;
|