eventmodeler 0.4.3 → 0.4.5
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/api/index.d.ts +282 -0
- package/dist/api/index.js +320 -0
- package/dist/cloud/slices/index.d.ts +7 -0
- package/dist/index.js +256 -798
- package/dist/lib/config.d.ts +2 -1
- package/dist/lib/project-config.d.ts +0 -3
- package/dist/lib/project-config.js +1 -8
- package/dist/lib/slice-utils.d.ts +0 -79
- package/dist/lib/slice-utils.js +87 -237
- package/dist/projection.js +0 -146
- package/dist/slices/add-scenario/index.d.ts +0 -2
- package/dist/slices/add-scenario/index.js +120 -318
- package/dist/slices/init/index.d.ts +1 -0
- package/dist/slices/init/index.js +40 -93
- package/dist/slices/whoami/index.d.ts +1 -1
- package/dist/slices/whoami/index.js +19 -10
- package/package.json +5 -2
package/dist/index.js
CHANGED
|
@@ -2,61 +2,20 @@
|
|
|
2
2
|
import * as fs from 'node:fs';
|
|
3
3
|
import * as path from 'node:path';
|
|
4
4
|
import { fileURLToPath } from 'node:url';
|
|
5
|
-
import { findEventModelFile, loadModel } from './lib/file-loader.js';
|
|
6
5
|
import { getDefaultFormat } from './lib/config.js';
|
|
7
6
|
const __filename = fileURLToPath(import.meta.url);
|
|
8
7
|
const __dirname = path.dirname(__filename);
|
|
9
8
|
const packageJson = JSON.parse(fs.readFileSync(path.join(__dirname, '..', 'package.json'), 'utf-8'));
|
|
10
9
|
const VERSION = packageJson.version;
|
|
11
|
-
//
|
|
12
|
-
import { listSlices } from './slices/list-slices/index.js';
|
|
13
|
-
import { listEvents } from './slices/list-events/index.js';
|
|
14
|
-
import { listCommands } from './slices/list-commands/index.js';
|
|
15
|
-
import { showSlice } from './slices/show-slice/index.js';
|
|
16
|
-
import { showEvent } from './slices/show-event/index.js';
|
|
17
|
-
import { showCommand } from './slices/show-command/index.js';
|
|
18
|
-
import { markSliceStatus } from './slices/mark-slice-status/index.js';
|
|
19
|
-
import { showModelSummary } from './slices/show-model-summary/index.js';
|
|
20
|
-
import { exportEventmodelToJson } from './slices/export-eventmodel-to-json/index.js';
|
|
10
|
+
// Utilities
|
|
21
11
|
import { openApp } from './slices/open-app/index.js';
|
|
22
|
-
import {
|
|
23
|
-
import { listChapters } from './slices/list-chapters/index.js';
|
|
24
|
-
import { showChapter } from './slices/show-chapter/index.js';
|
|
25
|
-
import { addScenario, parseScenarioInput } from './slices/add-scenario/index.js';
|
|
26
|
-
import { addField } from './slices/add-field/index.js';
|
|
27
|
-
import { removeScenario } from './slices/remove-scenario/index.js';
|
|
28
|
-
import { removeField } from './slices/remove-field/index.js';
|
|
29
|
-
import { showCompleteness, showModelCompleteness } from './slices/show-completeness/index.js';
|
|
30
|
-
import { mapFields } from './slices/map-fields/index.js';
|
|
31
|
-
import { updateField } from './slices/update-field/index.js';
|
|
32
|
-
import { showAggregateCompleteness, listAggregates } from './slices/show-aggregate-completeness/index.js';
|
|
33
|
-
import { showActor, listActors } from './slices/show-actor/index.js';
|
|
34
|
-
import { listReadModels } from './slices/list-readmodels/index.js';
|
|
35
|
-
import { listScreens } from './slices/list-screens/index.js';
|
|
36
|
-
import { listProcessors } from './slices/list-processors/index.js';
|
|
37
|
-
import { listScenarios } from './slices/list-scenarios/index.js';
|
|
38
|
-
import { showReadModel } from './slices/show-readmodel/index.js';
|
|
39
|
-
import { showScreen } from './slices/show-screen/index.js';
|
|
40
|
-
import { showProcessor } from './slices/show-processor/index.js';
|
|
41
|
-
import { showAggregate } from './slices/show-aggregate/index.js';
|
|
42
|
-
import { showScenario } from './slices/show-scenario/index.js';
|
|
43
|
-
import { createStateChangeSlice } from './slices/create-state-change-slice/index.js';
|
|
44
|
-
import { createAutomationSlice } from './slices/create-automation-slice/index.js';
|
|
45
|
-
import { createStateViewSlice } from './slices/create-state-view-slice/index.js';
|
|
46
|
-
import { createFlow } from './slices/create-flow/index.js';
|
|
47
|
-
import { codegenSlice } from './slices/codegen-slice/index.js';
|
|
48
|
-
import { codegenEvents } from './slices/codegen-chapter-events/index.js';
|
|
49
|
-
import { diff } from './slices/diff/index.js';
|
|
50
|
-
import { merge } from './slices/merge/index.js';
|
|
51
|
-
import { gitSetup, gitStatus } from './slices/git/index.js';
|
|
52
|
-
import { importModel } from './slices/import/index.js';
|
|
53
|
-
// Auth and cloud commands
|
|
12
|
+
import { parseScenarioInput } from './slices/add-scenario/index.js';
|
|
54
13
|
import { login } from './slices/login/index.js';
|
|
55
14
|
import { logout } from './slices/logout/index.js';
|
|
56
15
|
import { whoami } from './slices/whoami/index.js';
|
|
57
16
|
import { init } from './slices/init/index.js';
|
|
58
|
-
|
|
59
|
-
import
|
|
17
|
+
import * as api from './api/index.js';
|
|
18
|
+
import { XMLBuilder, XMLParser } from 'fast-xml-parser';
|
|
60
19
|
import { loadProjectConfig } from './lib/project-config.js';
|
|
61
20
|
const args = process.argv.slice(2);
|
|
62
21
|
function getNamedArg(argList, ...names) {
|
|
@@ -95,7 +54,7 @@ AUTHENTICATION:
|
|
|
95
54
|
whoami Show authentication status
|
|
96
55
|
|
|
97
56
|
PROJECT SETUP:
|
|
98
|
-
init Initialize project (link to
|
|
57
|
+
init Initialize project (link to a model)
|
|
99
58
|
|
|
100
59
|
COMMANDS:
|
|
101
60
|
list slices [--chapter <name>] List all slices (optionally filtered by chapter)
|
|
@@ -115,8 +74,9 @@ COMMANDS:
|
|
|
115
74
|
show command <name> Show detailed XML view of a command
|
|
116
75
|
show chapter <name> Show chapter with slices, flow graph, and
|
|
117
76
|
external dependencies
|
|
118
|
-
show completeness
|
|
119
|
-
show
|
|
77
|
+
show information-completeness Show information completeness of all flows
|
|
78
|
+
show information-completeness <name>
|
|
79
|
+
Show field mapping completeness for an element
|
|
120
80
|
show aggregate-completeness <name>
|
|
121
81
|
Show if events in aggregate have the ID field
|
|
122
82
|
show actor <name> Show actor with its screens
|
|
@@ -133,18 +93,18 @@ COMMANDS:
|
|
|
133
93
|
|
|
134
94
|
add scenario --slice <name> --json|--xml <data>
|
|
135
95
|
Add a scenario to a slice
|
|
136
|
-
add field
|
|
96
|
+
add field <element-name> --json|--xml <data>
|
|
137
97
|
Add a field to an entity
|
|
138
98
|
|
|
139
99
|
remove scenario <name> [--slice <name>]
|
|
140
100
|
Remove a scenario by name
|
|
141
|
-
remove field
|
|
101
|
+
remove field <element-name> --field <name>
|
|
142
102
|
Remove a field from an entity
|
|
143
103
|
|
|
144
104
|
map fields --flow <source→target> --json|--xml <mappings>
|
|
145
105
|
Set field mappings on a flow
|
|
146
106
|
|
|
147
|
-
update field
|
|
107
|
+
update field <element-name> --field <name> [--optional true|false] [--generated true|false] [--user-input true|false]
|
|
148
108
|
Update field properties
|
|
149
109
|
|
|
150
110
|
create state-change-slice --xml <data>
|
|
@@ -164,27 +124,7 @@ COMMANDS:
|
|
|
164
124
|
|
|
165
125
|
export json Export entire model as JSON
|
|
166
126
|
|
|
167
|
-
IMPORT/EXPORT:
|
|
168
|
-
import <file> [--name <name>] Import .eventmodel file to cloud (creates new model)
|
|
169
|
-
|
|
170
|
-
GIT INTEGRATION:
|
|
171
|
-
git setup Configure git to use semantic diff/merge for .eventmodel files
|
|
172
|
-
git setup --global Configure globally (for all repos)
|
|
173
|
-
git status Show git integration status
|
|
174
|
-
|
|
175
|
-
diff <file1> <file2> Compare two event model files semantically
|
|
176
|
-
diff <file> [--ref <gitref>] Compare working copy against git ref (default: HEAD)
|
|
177
|
-
diff ... --format text Human-readable output (default for git)
|
|
178
|
-
diff ... --format xml|json Structured output
|
|
179
|
-
|
|
180
|
-
merge --base <file> --ours <file> --theirs <file> --output <file>
|
|
181
|
-
Three-way merge of event model files
|
|
182
|
-
merge ... --strategy ours|theirs
|
|
183
|
-
Auto-resolve conflicts with given strategy
|
|
184
|
-
merge ... --dry-run Show conflicts without writing output
|
|
185
|
-
|
|
186
127
|
OPTIONS:
|
|
187
|
-
-f, --file <path> Path to .eventmodel file (default: auto-detect)
|
|
188
128
|
--format <xml|json> Output format (default: xml, or from config)
|
|
189
129
|
-h, --help Show this help message
|
|
190
130
|
-v, --version Show version number
|
|
@@ -199,25 +139,21 @@ EXAMPLES:
|
|
|
199
139
|
eventmodeler show slice "Place Order"
|
|
200
140
|
eventmodeler mark "Place Order" done
|
|
201
141
|
eventmodeler add scenario --slice "Place Order" --json '{"name": "Happy path", "then": {"type": "events", "events": []}}'
|
|
202
|
-
eventmodeler add field
|
|
203
|
-
eventmodeler remove field
|
|
204
|
-
eventmodeler show completeness
|
|
205
|
-
eventmodeler show
|
|
142
|
+
eventmodeler add field "OrderPlaced" --json '{"name": "orderId", "type": "UUID"}'
|
|
143
|
+
eventmodeler remove field "OrderPlaced" --field "orderId"
|
|
144
|
+
eventmodeler show information-completeness
|
|
145
|
+
eventmodeler show information-completeness "OrderSummary"
|
|
206
146
|
eventmodeler map fields --flow "OrderPlaced→OrderSummary" --json '[{"from": "total", "to": "totalAmount"}]'
|
|
207
|
-
eventmodeler update field
|
|
147
|
+
eventmodeler update field "OrderSummary" --field "notes" --optional true
|
|
208
148
|
`);
|
|
209
149
|
}
|
|
210
150
|
async function main() {
|
|
211
|
-
let fileArg = null;
|
|
212
151
|
let formatArg = null;
|
|
213
152
|
let chapterArg = null;
|
|
214
153
|
const filteredArgs = [];
|
|
215
154
|
let helpRequested = false;
|
|
216
155
|
for (let i = 0; i < args.length; i++) {
|
|
217
|
-
if (args[i] === '
|
|
218
|
-
fileArg = args[++i];
|
|
219
|
-
}
|
|
220
|
-
else if (args[i] === '--format') {
|
|
156
|
+
if (args[i] === '--format') {
|
|
221
157
|
formatArg = args[++i];
|
|
222
158
|
}
|
|
223
159
|
else if (args[i] === '--chapter') {
|
|
@@ -254,144 +190,6 @@ async function main() {
|
|
|
254
190
|
openApp();
|
|
255
191
|
return;
|
|
256
192
|
}
|
|
257
|
-
// Handle diff and merge commands separately (they manage their own file loading)
|
|
258
|
-
if (command === 'diff') {
|
|
259
|
-
if (helpRequested) {
|
|
260
|
-
console.log(`
|
|
261
|
-
eventmodeler diff - Compare event model files semantically
|
|
262
|
-
|
|
263
|
-
USAGE:
|
|
264
|
-
eventmodeler diff <file1> <file2> [--format text|xml|json]
|
|
265
|
-
eventmodeler diff <file> [--ref <gitref>] [--format text|xml|json]
|
|
266
|
-
eventmodeler diff --base <file> --compare <file> [--format text|xml|json]
|
|
267
|
-
|
|
268
|
-
ARGUMENTS:
|
|
269
|
-
<file1> <file2> Two files to compare
|
|
270
|
-
<file> Single file to compare against git ref
|
|
271
|
-
|
|
272
|
-
OPTIONS:
|
|
273
|
-
--ref <gitref> Git reference to compare against (default: HEAD)
|
|
274
|
-
--base <file> Base file (alternative syntax)
|
|
275
|
-
--compare <file> Compare file (alternative syntax)
|
|
276
|
-
--format <format> Output format: text (default), xml, or json
|
|
277
|
-
|
|
278
|
-
OUTPUT:
|
|
279
|
-
Semantic differences between models:
|
|
280
|
-
- Added/removed/modified entities
|
|
281
|
-
- Field changes (with flag changes like isGenerated)
|
|
282
|
-
- Flow changes
|
|
283
|
-
- Scenario changes
|
|
284
|
-
|
|
285
|
-
Unlike line-based diff, this understands event model structure.
|
|
286
|
-
|
|
287
|
-
EXAMPLES:
|
|
288
|
-
eventmodeler diff model-v1.eventmodel model-v2.eventmodel
|
|
289
|
-
eventmodeler diff mymodel.eventmodel --ref HEAD~1
|
|
290
|
-
eventmodeler diff mymodel.eventmodel --ref main
|
|
291
|
-
eventmodeler diff model.eventmodel --format json
|
|
292
|
-
`);
|
|
293
|
-
process.exit(0);
|
|
294
|
-
}
|
|
295
|
-
const baseArg = getNamedArg(filteredArgs, '--base');
|
|
296
|
-
const compareArg = getNamedArg(filteredArgs, '--compare');
|
|
297
|
-
const refArg = getNamedArg(filteredArgs, '--ref');
|
|
298
|
-
// Diff supports 'text' format in addition to xml/json
|
|
299
|
-
const diffFormat = formatArg === 'json' ? 'json'
|
|
300
|
-
: formatArg === 'xml' ? 'xml'
|
|
301
|
-
: formatArg === 'text' ? 'text'
|
|
302
|
-
: 'text'; // Default to text for human-readable output
|
|
303
|
-
// Two-file mode: diff file1 file2 OR diff --base file1 --compare file2
|
|
304
|
-
if (baseArg && compareArg) {
|
|
305
|
-
diff(baseArg, compareArg, diffFormat);
|
|
306
|
-
return;
|
|
307
|
-
}
|
|
308
|
-
// Positional args: diff file1 file2
|
|
309
|
-
const file1 = filteredArgs[1];
|
|
310
|
-
const file2 = filteredArgs[2];
|
|
311
|
-
if (file1 && file2 && !file1.startsWith('--') && !file2.startsWith('--')) {
|
|
312
|
-
diff(file1, file2, diffFormat);
|
|
313
|
-
return;
|
|
314
|
-
}
|
|
315
|
-
// Single file mode: diff file [--ref HEAD]
|
|
316
|
-
if (file1 && !file1.startsWith('--')) {
|
|
317
|
-
diff(file1, undefined, diffFormat, refArg);
|
|
318
|
-
return;
|
|
319
|
-
}
|
|
320
|
-
console.error('Usage: eventmodeler diff <file1> <file2>');
|
|
321
|
-
console.error(' eventmodeler diff <file> [--ref <gitref>]');
|
|
322
|
-
console.error(' eventmodeler diff --base <file> --compare <file>');
|
|
323
|
-
console.error('Run "eventmodeler diff --help" for more information.');
|
|
324
|
-
process.exit(1);
|
|
325
|
-
}
|
|
326
|
-
if (command === 'merge') {
|
|
327
|
-
if (helpRequested) {
|
|
328
|
-
console.log(`
|
|
329
|
-
eventmodeler merge - Three-way merge of event model files
|
|
330
|
-
|
|
331
|
-
USAGE:
|
|
332
|
-
eventmodeler merge --base <file> --ours <file> --theirs <file> --output <file>
|
|
333
|
-
|
|
334
|
-
OPTIONS:
|
|
335
|
-
--base <file> Common ancestor file (required)
|
|
336
|
-
--ours <file> Our version file (required)
|
|
337
|
-
--theirs <file> Their version file (required)
|
|
338
|
-
--output <file> Output file path (required unless --dry-run)
|
|
339
|
-
--strategy <s> Auto-resolve conflicts: ours or theirs
|
|
340
|
-
--dry-run Show result without writing file
|
|
341
|
-
--format xml|json Output format for conflict reporting
|
|
342
|
-
|
|
343
|
-
HOW IT WORKS:
|
|
344
|
-
Performs semantic three-way merge:
|
|
345
|
-
1. Identifies changes in "ours" vs base
|
|
346
|
-
2. Identifies changes in "theirs" vs base
|
|
347
|
-
3. Auto-merges non-conflicting changes
|
|
348
|
-
4. Reports conflicts for manual resolution
|
|
349
|
-
|
|
350
|
-
CONFLICT RESOLUTION:
|
|
351
|
-
--strategy ours Keep our changes when conflicts occur
|
|
352
|
-
--strategy theirs Keep their changes when conflicts occur
|
|
353
|
-
|
|
354
|
-
EXAMPLES:
|
|
355
|
-
# Standard merge
|
|
356
|
-
eventmodeler merge --base base.eventmodel --ours mine.eventmodel --theirs theirs.eventmodel --output merged.eventmodel
|
|
357
|
-
|
|
358
|
-
# Auto-resolve with our changes taking precedence
|
|
359
|
-
eventmodeler merge --base base.eventmodel --ours mine.eventmodel --theirs theirs.eventmodel --output merged.eventmodel --strategy ours
|
|
360
|
-
|
|
361
|
-
# Preview merge without writing
|
|
362
|
-
eventmodeler merge --base base.eventmodel --ours mine.eventmodel --theirs theirs.eventmodel --dry-run
|
|
363
|
-
`);
|
|
364
|
-
process.exit(0);
|
|
365
|
-
}
|
|
366
|
-
const baseArg = getNamedArg(filteredArgs, '--base');
|
|
367
|
-
const oursArg = getNamedArg(filteredArgs, '--ours');
|
|
368
|
-
const theirsArg = getNamedArg(filteredArgs, '--theirs');
|
|
369
|
-
const outputArg = getNamedArg(filteredArgs, '--output');
|
|
370
|
-
const strategyArg = getNamedArg(filteredArgs, '--strategy');
|
|
371
|
-
const dryRun = filteredArgs.includes('--dry-run');
|
|
372
|
-
if (!baseArg || !oursArg || !theirsArg) {
|
|
373
|
-
console.error('Usage: eventmodeler merge --base <file> --ours <file> --theirs <file> --output <file>');
|
|
374
|
-
console.error('Options:');
|
|
375
|
-
console.error(' --strategy ours|theirs Auto-resolve conflicts');
|
|
376
|
-
console.error(' --dry-run Show result without writing');
|
|
377
|
-
console.error('Run "eventmodeler merge --help" for more information.');
|
|
378
|
-
process.exit(1);
|
|
379
|
-
}
|
|
380
|
-
if (!outputArg && !dryRun) {
|
|
381
|
-
console.error('Error: --output is required (or use --dry-run)');
|
|
382
|
-
process.exit(1);
|
|
383
|
-
}
|
|
384
|
-
merge({
|
|
385
|
-
basePath: baseArg,
|
|
386
|
-
oursPath: oursArg,
|
|
387
|
-
theirsPath: theirsArg,
|
|
388
|
-
outputPath: outputArg ?? '',
|
|
389
|
-
strategy: strategyArg === 'ours' || strategyArg === 'theirs' ? strategyArg : undefined,
|
|
390
|
-
dryRun,
|
|
391
|
-
format,
|
|
392
|
-
});
|
|
393
|
-
return;
|
|
394
|
-
}
|
|
395
193
|
// Auth commands (no file needed)
|
|
396
194
|
if (command === 'login') {
|
|
397
195
|
if (helpRequested) {
|
|
@@ -405,8 +203,7 @@ Opens your browser for authentication via Keycloak.
|
|
|
405
203
|
Credentials are stored securely in ~/.eventmodeler/config.json
|
|
406
204
|
|
|
407
205
|
After login, you can:
|
|
408
|
-
- Use "eventmodeler init" to connect a project to a
|
|
409
|
-
- Access cloud-hosted event models
|
|
206
|
+
- Use "eventmodeler init" to connect a project to a model
|
|
410
207
|
|
|
411
208
|
EXAMPLES:
|
|
412
209
|
eventmodeler login
|
|
@@ -468,12 +265,8 @@ USAGE:
|
|
|
468
265
|
Interactive setup to connect this directory to an event model.
|
|
469
266
|
Creates a .eventmodeler.json config file in your project root.
|
|
470
267
|
|
|
471
|
-
OPTIONS:
|
|
472
|
-
1. Cloud - Link to an event model on eventmodeler.app
|
|
473
|
-
2. Local - Use a local .eventmodel file
|
|
474
|
-
|
|
475
268
|
PREREQUISITES:
|
|
476
|
-
-
|
|
269
|
+
- You must be logged in (run "eventmodeler login" first)
|
|
477
270
|
|
|
478
271
|
EXAMPLES:
|
|
479
272
|
cd my-project
|
|
@@ -484,151 +277,13 @@ EXAMPLES:
|
|
|
484
277
|
await init();
|
|
485
278
|
return;
|
|
486
279
|
}
|
|
487
|
-
if (command === 'import') {
|
|
488
|
-
if (helpRequested) {
|
|
489
|
-
console.log(`
|
|
490
|
-
eventmodeler import - Import .eventmodel file to cloud
|
|
491
|
-
|
|
492
|
-
USAGE:
|
|
493
|
-
eventmodeler import <file> [--name <name>]
|
|
494
|
-
|
|
495
|
-
ARGUMENTS:
|
|
496
|
-
<file> Path to .eventmodel file to import
|
|
497
|
-
|
|
498
|
-
OPTIONS:
|
|
499
|
-
--name <name> Override model name (default: derived from file or EventModelCreated event)
|
|
500
|
-
|
|
501
|
-
DESCRIPTION:
|
|
502
|
-
Imports a local .eventmodel file to the cloud backend, creating a new
|
|
503
|
-
cloud-hosted model. All events are preserved except EventModelCreated,
|
|
504
|
-
which is regenerated with a new modelId.
|
|
505
|
-
|
|
506
|
-
PREREQUISITES:
|
|
507
|
-
- Must be logged in (run "eventmodeler login" first)
|
|
508
|
-
|
|
509
|
-
EXAMPLES:
|
|
510
|
-
eventmodeler import mymodel.eventmodel
|
|
511
|
-
eventmodeler import ./models/order-system.eventmodel --name "Order System"
|
|
512
|
-
`);
|
|
513
|
-
process.exit(0);
|
|
514
|
-
}
|
|
515
|
-
const importFilePath = subcommand;
|
|
516
|
-
if (!importFilePath) {
|
|
517
|
-
console.error('Usage: eventmodeler import <file> [--name <name>]');
|
|
518
|
-
console.error('Run "eventmodeler import --help" for more information.');
|
|
519
|
-
process.exit(1);
|
|
520
|
-
}
|
|
521
|
-
const importName = getNamedArg(filteredArgs, '--name', '-n');
|
|
522
|
-
await importModel(importFilePath, { name: importName });
|
|
523
|
-
return;
|
|
524
|
-
}
|
|
525
|
-
if (command === 'git') {
|
|
526
|
-
const gitCommand = filteredArgs[1];
|
|
527
|
-
const globalFlag = filteredArgs.includes('--global');
|
|
528
|
-
if (helpRequested && !gitCommand) {
|
|
529
|
-
console.log(`
|
|
530
|
-
eventmodeler git - Git integration commands
|
|
531
|
-
|
|
532
|
-
USAGE:
|
|
533
|
-
eventmodeler git <command> [options]
|
|
534
|
-
|
|
535
|
-
COMMANDS:
|
|
536
|
-
setup Configure git for semantic diff/merge of .eventmodel files
|
|
537
|
-
status Show current git integration status
|
|
538
|
-
|
|
539
|
-
Run "eventmodeler git <command> --help" for command-specific help.
|
|
540
|
-
`);
|
|
541
|
-
process.exit(0);
|
|
542
|
-
}
|
|
543
|
-
switch (gitCommand) {
|
|
544
|
-
case 'setup':
|
|
545
|
-
if (helpRequested) {
|
|
546
|
-
console.log(`
|
|
547
|
-
eventmodeler git setup - Configure git for semantic diff/merge
|
|
548
|
-
|
|
549
|
-
USAGE:
|
|
550
|
-
eventmodeler git setup [--global]
|
|
551
|
-
|
|
552
|
-
OPTIONS:
|
|
553
|
-
--global Configure globally (for all repositories)
|
|
554
|
-
|
|
555
|
-
WHAT IT DOES:
|
|
556
|
-
1. Adds .gitattributes entry: *.eventmodel diff=eventmodel merge=eventmodel
|
|
557
|
-
2. Configures git diff driver for semantic comparison
|
|
558
|
-
3. Configures git merge driver for semantic merging
|
|
559
|
-
|
|
560
|
-
After setup:
|
|
561
|
-
- "git diff" shows semantic differences for .eventmodel files
|
|
562
|
-
- "git merge" performs semantic merging
|
|
563
|
-
- Conflicts are reported at entity level, not line level
|
|
564
|
-
|
|
565
|
-
LOCAL VS GLOBAL:
|
|
566
|
-
Without --global: Configures current repository only
|
|
567
|
-
With --global: Configures for all repositories (user-level)
|
|
568
|
-
|
|
569
|
-
EXAMPLES:
|
|
570
|
-
eventmodeler git setup # Configure current repo
|
|
571
|
-
eventmodeler git setup --global # Configure globally
|
|
572
|
-
`);
|
|
573
|
-
process.exit(0);
|
|
574
|
-
}
|
|
575
|
-
gitSetup(globalFlag);
|
|
576
|
-
return;
|
|
577
|
-
case 'status':
|
|
578
|
-
if (helpRequested) {
|
|
579
|
-
console.log(`
|
|
580
|
-
eventmodeler git status - Show git integration status
|
|
581
|
-
|
|
582
|
-
USAGE:
|
|
583
|
-
eventmodeler git status
|
|
584
|
-
|
|
585
|
-
OUTPUT:
|
|
586
|
-
Shows current configuration:
|
|
587
|
-
- Whether git drivers are configured
|
|
588
|
-
- Local vs global configuration status
|
|
589
|
-
- .gitattributes configuration status
|
|
590
|
-
|
|
591
|
-
EXAMPLES:
|
|
592
|
-
eventmodeler git status
|
|
593
|
-
`);
|
|
594
|
-
process.exit(0);
|
|
595
|
-
}
|
|
596
|
-
gitStatus();
|
|
597
|
-
return;
|
|
598
|
-
default:
|
|
599
|
-
console.error('Usage: eventmodeler git setup [--global]');
|
|
600
|
-
console.error(' eventmodeler git status');
|
|
601
|
-
console.error('Run "eventmodeler git --help" for more information.');
|
|
602
|
-
process.exit(1);
|
|
603
|
-
}
|
|
604
|
-
}
|
|
605
|
-
// Determine backend mode: cloud or local
|
|
606
280
|
const projectConfig = loadProjectConfig();
|
|
607
|
-
|
|
608
|
-
|
|
609
|
-
|
|
610
|
-
|
|
611
|
-
let model = null;
|
|
612
|
-
let filePath = null;
|
|
613
|
-
if (!isCloudMode) {
|
|
614
|
-
// Local mode - load model from file
|
|
615
|
-
if (projectConfig?.type === 'local') {
|
|
616
|
-
filePath = fileArg ?? projectConfig.file;
|
|
617
|
-
}
|
|
618
|
-
else {
|
|
619
|
-
filePath = fileArg ?? await findEventModelFile();
|
|
620
|
-
}
|
|
621
|
-
if (!filePath) {
|
|
622
|
-
console.error('Error: No .eventmodel file found in current directory.');
|
|
623
|
-
console.error('Use -f <path> to specify a file or run "eventmodeler init" to set up a project.');
|
|
624
|
-
process.exit(1);
|
|
625
|
-
}
|
|
626
|
-
if (!fs.existsSync(filePath)) {
|
|
627
|
-
console.error(`Error: File not found: ${filePath}`);
|
|
628
|
-
process.exit(1);
|
|
629
|
-
}
|
|
630
|
-
model = loadModel(filePath);
|
|
281
|
+
if (!projectConfig || projectConfig.type !== 'cloud') {
|
|
282
|
+
console.error('Error: No project configured.');
|
|
283
|
+
console.error('Run "eventmodeler init" to connect this directory to a model.');
|
|
284
|
+
process.exit(1);
|
|
631
285
|
}
|
|
286
|
+
const modelId = projectConfig.modelId;
|
|
632
287
|
switch (command) {
|
|
633
288
|
case 'list':
|
|
634
289
|
if (helpRequested && !subcommand) {
|
|
@@ -688,13 +343,10 @@ EXAMPLES:
|
|
|
688
343
|
`);
|
|
689
344
|
process.exit(0);
|
|
690
345
|
}
|
|
691
|
-
|
|
692
|
-
const output = await
|
|
346
|
+
{
|
|
347
|
+
const output = await api.listSlices(modelId, format, chapterArg ?? undefined);
|
|
693
348
|
console.log(output);
|
|
694
349
|
}
|
|
695
|
-
else {
|
|
696
|
-
listSlices(model, format, chapterArg ?? undefined);
|
|
697
|
-
}
|
|
698
350
|
break;
|
|
699
351
|
case 'events':
|
|
700
352
|
if (helpRequested) {
|
|
@@ -719,13 +371,10 @@ EXAMPLES:
|
|
|
719
371
|
`);
|
|
720
372
|
process.exit(0);
|
|
721
373
|
}
|
|
722
|
-
|
|
723
|
-
const output = await
|
|
374
|
+
{
|
|
375
|
+
const output = await api.listEvents(modelId, format);
|
|
724
376
|
console.log(output);
|
|
725
377
|
}
|
|
726
|
-
else {
|
|
727
|
-
listEvents(model, format);
|
|
728
|
-
}
|
|
729
378
|
break;
|
|
730
379
|
case 'commands':
|
|
731
380
|
if (helpRequested) {
|
|
@@ -748,13 +397,10 @@ EXAMPLES:
|
|
|
748
397
|
`);
|
|
749
398
|
process.exit(0);
|
|
750
399
|
}
|
|
751
|
-
|
|
752
|
-
const output = await
|
|
400
|
+
{
|
|
401
|
+
const output = await api.listCommands(modelId, format);
|
|
753
402
|
console.log(output);
|
|
754
403
|
}
|
|
755
|
-
else {
|
|
756
|
-
listCommands(model, format);
|
|
757
|
-
}
|
|
758
404
|
break;
|
|
759
405
|
case 'chapters':
|
|
760
406
|
if (helpRequested) {
|
|
@@ -777,13 +423,10 @@ EXAMPLES:
|
|
|
777
423
|
`);
|
|
778
424
|
process.exit(0);
|
|
779
425
|
}
|
|
780
|
-
|
|
781
|
-
const output = await
|
|
426
|
+
{
|
|
427
|
+
const output = await api.listChapters(modelId, format);
|
|
782
428
|
console.log(output);
|
|
783
429
|
}
|
|
784
|
-
else {
|
|
785
|
-
listChapters(model, format);
|
|
786
|
-
}
|
|
787
430
|
break;
|
|
788
431
|
case 'aggregates':
|
|
789
432
|
if (helpRequested) {
|
|
@@ -807,13 +450,10 @@ EXAMPLES:
|
|
|
807
450
|
`);
|
|
808
451
|
process.exit(0);
|
|
809
452
|
}
|
|
810
|
-
|
|
811
|
-
const result = await
|
|
453
|
+
{
|
|
454
|
+
const result = await api.listAggregates(modelId, format);
|
|
812
455
|
console.log(result);
|
|
813
456
|
}
|
|
814
|
-
else {
|
|
815
|
-
listAggregates(model, format);
|
|
816
|
-
}
|
|
817
457
|
break;
|
|
818
458
|
case 'actors':
|
|
819
459
|
if (helpRequested) {
|
|
@@ -836,12 +476,10 @@ EXAMPLES:
|
|
|
836
476
|
`);
|
|
837
477
|
process.exit(0);
|
|
838
478
|
}
|
|
839
|
-
|
|
840
|
-
const output = await
|
|
479
|
+
{
|
|
480
|
+
const output = await api.listActors(modelId, format);
|
|
841
481
|
console.log(output);
|
|
842
|
-
break;
|
|
843
482
|
}
|
|
844
|
-
listActors(model, format);
|
|
845
483
|
break;
|
|
846
484
|
case 'readmodels':
|
|
847
485
|
if (helpRequested) {
|
|
@@ -861,12 +499,10 @@ EXAMPLES:
|
|
|
861
499
|
`);
|
|
862
500
|
process.exit(0);
|
|
863
501
|
}
|
|
864
|
-
|
|
865
|
-
const output = await
|
|
502
|
+
{
|
|
503
|
+
const output = await api.listReadModels(modelId, format);
|
|
866
504
|
console.log(output);
|
|
867
|
-
break;
|
|
868
505
|
}
|
|
869
|
-
listReadModels(model, format);
|
|
870
506
|
break;
|
|
871
507
|
case 'screens':
|
|
872
508
|
if (helpRequested) {
|
|
@@ -886,12 +522,10 @@ EXAMPLES:
|
|
|
886
522
|
`);
|
|
887
523
|
process.exit(0);
|
|
888
524
|
}
|
|
889
|
-
|
|
890
|
-
const output = await
|
|
525
|
+
{
|
|
526
|
+
const output = await api.listScreens(modelId, format);
|
|
891
527
|
console.log(output);
|
|
892
|
-
break;
|
|
893
528
|
}
|
|
894
|
-
listScreens(model, format);
|
|
895
529
|
break;
|
|
896
530
|
case 'processors':
|
|
897
531
|
if (helpRequested) {
|
|
@@ -910,12 +544,10 @@ EXAMPLES:
|
|
|
910
544
|
`);
|
|
911
545
|
process.exit(0);
|
|
912
546
|
}
|
|
913
|
-
|
|
914
|
-
const output = await
|
|
547
|
+
{
|
|
548
|
+
const output = await api.listProcessors(modelId, format);
|
|
915
549
|
console.log(output);
|
|
916
|
-
break;
|
|
917
550
|
}
|
|
918
|
-
listProcessors(model, format);
|
|
919
551
|
break;
|
|
920
552
|
case 'scenarios':
|
|
921
553
|
if (helpRequested) {
|
|
@@ -936,12 +568,10 @@ EXAMPLES:
|
|
|
936
568
|
`);
|
|
937
569
|
process.exit(0);
|
|
938
570
|
}
|
|
939
|
-
|
|
940
|
-
const output = await
|
|
571
|
+
{
|
|
572
|
+
const output = await api.listScenarios(modelId, format);
|
|
941
573
|
console.log(output);
|
|
942
|
-
break;
|
|
943
574
|
}
|
|
944
|
-
listScenarios(model, format);
|
|
945
575
|
break;
|
|
946
576
|
default:
|
|
947
577
|
console.error(`Unknown list target: ${subcommand}`);
|
|
@@ -963,8 +593,8 @@ TYPES:
|
|
|
963
593
|
event Show event with all fields
|
|
964
594
|
command Show command with all fields
|
|
965
595
|
chapter Show chapter with slices and dependencies
|
|
966
|
-
completeness
|
|
967
|
-
|
|
596
|
+
information-completeness Show information completeness of all flows
|
|
597
|
+
(with element name: show per-element completeness)
|
|
968
598
|
aggregate-completeness Show if events have aggregate ID field
|
|
969
599
|
actor Show actor with screens
|
|
970
600
|
readmodel Show read model with fields and flows
|
|
@@ -979,7 +609,7 @@ OPTIONS:
|
|
|
979
609
|
EXAMPLES:
|
|
980
610
|
eventmodeler show slice "Place Order"
|
|
981
611
|
eventmodeler show event OrderPlaced
|
|
982
|
-
eventmodeler show completeness OrderSummary
|
|
612
|
+
eventmodeler show information-completeness OrderSummary
|
|
983
613
|
|
|
984
614
|
Run "eventmodeler show <type> --help" for type-specific help.
|
|
985
615
|
`);
|
|
@@ -1018,13 +648,10 @@ EXAMPLES:
|
|
|
1018
648
|
console.error('Run "eventmodeler show slice --help" for more information.');
|
|
1019
649
|
process.exit(1);
|
|
1020
650
|
}
|
|
1021
|
-
|
|
1022
|
-
const result = await
|
|
651
|
+
{
|
|
652
|
+
const result = await api.showSlice(modelId, target, format);
|
|
1023
653
|
console.log(result);
|
|
1024
654
|
}
|
|
1025
|
-
else {
|
|
1026
|
-
showSlice(model, target, format);
|
|
1027
|
-
}
|
|
1028
655
|
break;
|
|
1029
656
|
case 'event':
|
|
1030
657
|
if (helpRequested) {
|
|
@@ -1066,13 +693,10 @@ EXAMPLES:
|
|
|
1066
693
|
console.error('Run "eventmodeler show event --help" for more information.');
|
|
1067
694
|
process.exit(1);
|
|
1068
695
|
}
|
|
1069
|
-
|
|
1070
|
-
const result = await
|
|
696
|
+
{
|
|
697
|
+
const result = await api.showEvent(modelId, target, format);
|
|
1071
698
|
console.log(result);
|
|
1072
699
|
}
|
|
1073
|
-
else {
|
|
1074
|
-
showEvent(model, target, format);
|
|
1075
|
-
}
|
|
1076
700
|
break;
|
|
1077
701
|
case 'command':
|
|
1078
702
|
if (helpRequested) {
|
|
@@ -1100,13 +724,10 @@ EXAMPLES:
|
|
|
1100
724
|
console.error('Run "eventmodeler show command --help" for more information.');
|
|
1101
725
|
process.exit(1);
|
|
1102
726
|
}
|
|
1103
|
-
|
|
1104
|
-
const result = await
|
|
727
|
+
{
|
|
728
|
+
const result = await api.showCommand(modelId, target, format);
|
|
1105
729
|
console.log(result);
|
|
1106
730
|
}
|
|
1107
|
-
else {
|
|
1108
|
-
showCommand(model, target, format);
|
|
1109
|
-
}
|
|
1110
731
|
break;
|
|
1111
732
|
case 'chapter':
|
|
1112
733
|
if (helpRequested) {
|
|
@@ -1135,26 +756,28 @@ EXAMPLES:
|
|
|
1135
756
|
console.error('Run "eventmodeler show chapter --help" for more information.');
|
|
1136
757
|
process.exit(1);
|
|
1137
758
|
}
|
|
1138
|
-
|
|
1139
|
-
const result = await
|
|
759
|
+
{
|
|
760
|
+
const result = await api.showChapter(modelId, target, format);
|
|
1140
761
|
console.log(result);
|
|
1141
762
|
}
|
|
1142
|
-
else {
|
|
1143
|
-
showChapter(model, target, format);
|
|
1144
|
-
}
|
|
1145
763
|
break;
|
|
1146
|
-
case 'completeness':
|
|
764
|
+
case 'information-completeness':
|
|
1147
765
|
if (helpRequested) {
|
|
1148
766
|
console.log(`
|
|
1149
|
-
eventmodeler show completeness - Show
|
|
767
|
+
eventmodeler show information-completeness - Show information completeness
|
|
1150
768
|
|
|
1151
769
|
USAGE:
|
|
1152
|
-
eventmodeler show completeness
|
|
770
|
+
eventmodeler show information-completeness [--format xml|json]
|
|
771
|
+
eventmodeler show information-completeness --slice "Place Order"
|
|
772
|
+
eventmodeler show information-completeness --chapter "Ordering"
|
|
773
|
+
eventmodeler show information-completeness <element-name> [--format xml|json]
|
|
1153
774
|
|
|
1154
|
-
|
|
1155
|
-
|
|
775
|
+
OUTPUT INCLUDES (model-wide):
|
|
776
|
+
- Summary of complete/incomplete flows across the whole model
|
|
777
|
+
- Incomplete flows grouped by slice, with untraceable fields
|
|
778
|
+
- Incomplete read models with untraceable fields and source events
|
|
1156
779
|
|
|
1157
|
-
OUTPUT INCLUDES:
|
|
780
|
+
OUTPUT INCLUDES (per-element):
|
|
1158
781
|
- Total fields vs mapped fields
|
|
1159
782
|
- List of unmapped fields needing attention
|
|
1160
783
|
- Mapping sources for mapped fields
|
|
@@ -1164,53 +787,31 @@ IMPORTANT - GENERATED FIELDS:
|
|
|
1164
787
|
Generated fields are computed/synthesized values that don't need
|
|
1165
788
|
source mappings (e.g., calculated totals, timestamps, derived data).
|
|
1166
789
|
|
|
1167
|
-
|
|
1168
|
-
|
|
1169
|
-
eventmodeler show completeness "Order Summary" --format json
|
|
1170
|
-
`);
|
|
1171
|
-
process.exit(0);
|
|
1172
|
-
}
|
|
1173
|
-
if (!target) {
|
|
1174
|
-
console.error('Usage: eventmodeler show completeness <element-name>');
|
|
1175
|
-
console.error('Searches: commands, events, read models, screens, processors');
|
|
1176
|
-
console.error('Run "eventmodeler show completeness --help" for more information.');
|
|
1177
|
-
process.exit(1);
|
|
1178
|
-
}
|
|
1179
|
-
if (isCloudMode) {
|
|
1180
|
-
const result = await cloudSlices.showCompleteness(modelId, target, format);
|
|
1181
|
-
console.log(result);
|
|
1182
|
-
}
|
|
1183
|
-
else {
|
|
1184
|
-
showCompleteness(model, target, format);
|
|
1185
|
-
}
|
|
1186
|
-
break;
|
|
1187
|
-
case 'model-completeness':
|
|
1188
|
-
if (helpRequested) {
|
|
1189
|
-
console.log(`
|
|
1190
|
-
eventmodeler show model-completeness - Show completeness of all flows
|
|
1191
|
-
|
|
1192
|
-
USAGE:
|
|
1193
|
-
eventmodeler show model-completeness [--format xml|json]
|
|
1194
|
-
|
|
1195
|
-
OUTPUT INCLUDES:
|
|
1196
|
-
- Complete flows (all required fields mapped)
|
|
1197
|
-
- Incomplete flows with missing mappings
|
|
1198
|
-
- Overall completeness percentage
|
|
1199
|
-
|
|
1200
|
-
NOTE: Generated fields (isGenerated=true) are excluded from checks.
|
|
790
|
+
NOTE: Generated and user-input fields are excluded from checks.
|
|
791
|
+
Auto-matching uses field name AND type.
|
|
1201
792
|
|
|
1202
793
|
EXAMPLES:
|
|
1203
|
-
eventmodeler show
|
|
1204
|
-
eventmodeler show
|
|
794
|
+
eventmodeler show information-completeness
|
|
795
|
+
eventmodeler show information-completeness --slice "Place Order"
|
|
796
|
+
eventmodeler show information-completeness --chapter "Ordering"
|
|
797
|
+
eventmodeler show information-completeness --format json
|
|
798
|
+
eventmodeler show information-completeness CreateOrder
|
|
799
|
+
eventmodeler show information-completeness "Order Summary" --format json
|
|
1205
800
|
`);
|
|
1206
801
|
process.exit(0);
|
|
1207
802
|
}
|
|
1208
|
-
|
|
1209
|
-
|
|
1210
|
-
|
|
1211
|
-
|
|
1212
|
-
|
|
1213
|
-
|
|
803
|
+
{
|
|
804
|
+
if (target) {
|
|
805
|
+
// Per-element completeness
|
|
806
|
+
const result = await api.showElementCompleteness(modelId, target, format);
|
|
807
|
+
console.log(result);
|
|
808
|
+
}
|
|
809
|
+
else {
|
|
810
|
+
// Model-wide information completeness
|
|
811
|
+
const sliceFilter = getNamedArg(filteredArgs, '--slice');
|
|
812
|
+
const result = await api.showInformationCompleteness(modelId, format, sliceFilter, chapterArg ?? undefined);
|
|
813
|
+
console.log(result);
|
|
814
|
+
}
|
|
1214
815
|
}
|
|
1215
816
|
break;
|
|
1216
817
|
case 'aggregate-completeness':
|
|
@@ -1239,13 +840,10 @@ EXAMPLES:
|
|
|
1239
840
|
console.error('Run "eventmodeler show aggregate-completeness --help" for more information.');
|
|
1240
841
|
process.exit(1);
|
|
1241
842
|
}
|
|
1242
|
-
|
|
1243
|
-
const result = await
|
|
843
|
+
{
|
|
844
|
+
const result = await api.showAggregateCompleteness(modelId, target, format);
|
|
1244
845
|
console.log(result);
|
|
1245
846
|
}
|
|
1246
|
-
else {
|
|
1247
|
-
showAggregateCompleteness(model, target, format);
|
|
1248
|
-
}
|
|
1249
847
|
break;
|
|
1250
848
|
case 'actor':
|
|
1251
849
|
if (helpRequested) {
|
|
@@ -1273,13 +871,10 @@ EXAMPLES:
|
|
|
1273
871
|
console.error('Run "eventmodeler show actor --help" for more information.');
|
|
1274
872
|
process.exit(1);
|
|
1275
873
|
}
|
|
1276
|
-
|
|
1277
|
-
const result = await
|
|
874
|
+
{
|
|
875
|
+
const result = await api.showActor(modelId, target, format);
|
|
1278
876
|
console.log(result);
|
|
1279
877
|
}
|
|
1280
|
-
else {
|
|
1281
|
-
showActor(model, target, format);
|
|
1282
|
-
}
|
|
1283
878
|
break;
|
|
1284
879
|
case 'readmodel':
|
|
1285
880
|
if (helpRequested) {
|
|
@@ -1308,13 +903,10 @@ EXAMPLES:
|
|
|
1308
903
|
console.error('Run "eventmodeler show readmodel --help" for more information.');
|
|
1309
904
|
process.exit(1);
|
|
1310
905
|
}
|
|
1311
|
-
|
|
1312
|
-
const result = await
|
|
906
|
+
{
|
|
907
|
+
const result = await api.showReadModel(modelId, target, format);
|
|
1313
908
|
console.log(result);
|
|
1314
909
|
}
|
|
1315
|
-
else {
|
|
1316
|
-
showReadModel(model, target, format);
|
|
1317
|
-
}
|
|
1318
910
|
break;
|
|
1319
911
|
case 'screen':
|
|
1320
912
|
if (helpRequested) {
|
|
@@ -1344,13 +936,10 @@ EXAMPLES:
|
|
|
1344
936
|
console.error('Run "eventmodeler show screen --help" for more information.');
|
|
1345
937
|
process.exit(1);
|
|
1346
938
|
}
|
|
1347
|
-
|
|
1348
|
-
const result = await
|
|
939
|
+
{
|
|
940
|
+
const result = await api.showScreen(modelId, target, format);
|
|
1349
941
|
console.log(result);
|
|
1350
942
|
}
|
|
1351
|
-
else {
|
|
1352
|
-
showScreen(model, target, format);
|
|
1353
|
-
}
|
|
1354
943
|
break;
|
|
1355
944
|
case 'processor':
|
|
1356
945
|
if (helpRequested) {
|
|
@@ -1379,13 +968,10 @@ EXAMPLES:
|
|
|
1379
968
|
console.error('Run "eventmodeler show processor --help" for more information.');
|
|
1380
969
|
process.exit(1);
|
|
1381
970
|
}
|
|
1382
|
-
|
|
1383
|
-
const result = await
|
|
971
|
+
{
|
|
972
|
+
const result = await api.showProcessor(modelId, target, format);
|
|
1384
973
|
console.log(result);
|
|
1385
974
|
}
|
|
1386
|
-
else {
|
|
1387
|
-
showProcessor(model, target, format);
|
|
1388
|
-
}
|
|
1389
975
|
break;
|
|
1390
976
|
case 'aggregate':
|
|
1391
977
|
if (helpRequested) {
|
|
@@ -1415,13 +1001,10 @@ EXAMPLES:
|
|
|
1415
1001
|
console.error('Run "eventmodeler show aggregate --help" for more information.');
|
|
1416
1002
|
process.exit(1);
|
|
1417
1003
|
}
|
|
1418
|
-
|
|
1419
|
-
const result = await
|
|
1004
|
+
{
|
|
1005
|
+
const result = await api.showAggregate(modelId, target, format);
|
|
1420
1006
|
console.log(result);
|
|
1421
1007
|
}
|
|
1422
|
-
else {
|
|
1423
|
-
showAggregate(model, target, format);
|
|
1424
|
-
}
|
|
1425
1008
|
break;
|
|
1426
1009
|
case 'scenario':
|
|
1427
1010
|
if (helpRequested) {
|
|
@@ -1452,17 +1035,14 @@ EXAMPLES:
|
|
|
1452
1035
|
console.error('Run "eventmodeler show scenario --help" for more information.');
|
|
1453
1036
|
process.exit(1);
|
|
1454
1037
|
}
|
|
1455
|
-
|
|
1456
|
-
const result = await
|
|
1038
|
+
{
|
|
1039
|
+
const result = await api.showScenario(modelId, target, format);
|
|
1457
1040
|
console.log(result);
|
|
1458
1041
|
}
|
|
1459
|
-
else {
|
|
1460
|
-
showScenario(model, target, format);
|
|
1461
|
-
}
|
|
1462
1042
|
break;
|
|
1463
1043
|
default:
|
|
1464
1044
|
console.error(`Unknown show target: ${subcommand}`);
|
|
1465
|
-
console.error('Valid targets: slice, event, command, chapter,
|
|
1045
|
+
console.error('Valid targets: slice, event, command, chapter, information-completeness, aggregate-completeness, actor, readmodel, screen, processor, aggregate, scenario');
|
|
1466
1046
|
console.error('Run "eventmodeler show --help" for more information.');
|
|
1467
1047
|
process.exit(1);
|
|
1468
1048
|
}
|
|
@@ -1503,24 +1083,42 @@ EXAMPLES:
|
|
|
1503
1083
|
console.error('Run "eventmodeler search --help" for more information.');
|
|
1504
1084
|
process.exit(1);
|
|
1505
1085
|
}
|
|
1506
|
-
|
|
1507
|
-
const response = await
|
|
1086
|
+
{
|
|
1087
|
+
const response = await api.search(modelId, subcommand);
|
|
1508
1088
|
if (format === 'json') {
|
|
1509
1089
|
console.log(JSON.stringify(response, null, 2));
|
|
1510
1090
|
}
|
|
1511
1091
|
else {
|
|
1512
|
-
const
|
|
1513
|
-
|
|
1514
|
-
for (const r of response.results) {
|
|
1092
|
+
const xb = new XMLBuilder({ ignoreAttributes: false, attributeNamePrefix: '@_', suppressEmptyNode: true });
|
|
1093
|
+
const results = response.results.map(r => {
|
|
1515
1094
|
const tag = r.type === 'readmodel' ? 'read-model' : r.type;
|
|
1516
|
-
|
|
1517
|
-
|
|
1518
|
-
|
|
1095
|
+
const attrs = {};
|
|
1096
|
+
if (r.id)
|
|
1097
|
+
attrs['@_id'] = r.id;
|
|
1098
|
+
if (r.name)
|
|
1099
|
+
attrs['@_name'] = r.name;
|
|
1100
|
+
if (r.chapterId)
|
|
1101
|
+
attrs['@_chapter-id'] = r.chapterId;
|
|
1102
|
+
if (r.chapterName)
|
|
1103
|
+
attrs['@_chapter-name'] = r.chapterName;
|
|
1104
|
+
if (r.sliceId)
|
|
1105
|
+
attrs['@_slice-id'] = r.sliceId;
|
|
1106
|
+
if (r.sliceName)
|
|
1107
|
+
attrs['@_slice-name'] = r.sliceName;
|
|
1108
|
+
if (r.sliceStatus)
|
|
1109
|
+
attrs['@_slice-status'] = r.sliceStatus;
|
|
1110
|
+
if (r.parentChapterId)
|
|
1111
|
+
attrs['@_parent-chapter-id'] = r.parentChapterId;
|
|
1112
|
+
if (r.parentChapterName)
|
|
1113
|
+
attrs['@_parent-chapter-name'] = r.parentChapterName;
|
|
1114
|
+
return ` ${xb.build({ [tag]: attrs }).trim()}`;
|
|
1115
|
+
});
|
|
1116
|
+
const wrapper = xb.build({ 'search-results': { '@_query': subcommand, '@_count': String(response.results.length) } });
|
|
1117
|
+
// Replace self-closing tag with children
|
|
1118
|
+
const open = wrapper.replace(/\/>$/, '>').trim();
|
|
1119
|
+
console.log([open, ...results, '</search-results>'].join('\n'));
|
|
1519
1120
|
}
|
|
1520
1121
|
}
|
|
1521
|
-
else {
|
|
1522
|
-
search(model, subcommand, format);
|
|
1523
|
-
}
|
|
1524
1122
|
break;
|
|
1525
1123
|
case 'mark': {
|
|
1526
1124
|
if (helpRequested) {
|
|
@@ -1560,15 +1158,8 @@ EXAMPLES:
|
|
|
1560
1158
|
}
|
|
1561
1159
|
const sliceName = allArgs.slice(0, -1).join(' ');
|
|
1562
1160
|
const status = lastArg;
|
|
1563
|
-
|
|
1564
|
-
|
|
1565
|
-
await cloudSlices.markSliceStatus(modelId, sliceName, status);
|
|
1566
|
-
console.log(`Marked slice "${sliceName}" as ${status}`);
|
|
1567
|
-
}
|
|
1568
|
-
else {
|
|
1569
|
-
// Local mode
|
|
1570
|
-
markSliceStatus(model, filePath, sliceName, status);
|
|
1571
|
-
}
|
|
1161
|
+
await api.markSliceStatus(modelId, sliceName, status);
|
|
1162
|
+
console.log(`Marked slice "${sliceName}" as ${status}`);
|
|
1572
1163
|
break;
|
|
1573
1164
|
}
|
|
1574
1165
|
case 'summary':
|
|
@@ -1595,30 +1186,30 @@ EXAMPLES:
|
|
|
1595
1186
|
`);
|
|
1596
1187
|
process.exit(0);
|
|
1597
1188
|
}
|
|
1598
|
-
|
|
1599
|
-
const summary = await
|
|
1189
|
+
{
|
|
1190
|
+
const summary = await api.getSummary(modelId);
|
|
1600
1191
|
if (format === 'json') {
|
|
1601
1192
|
console.log(JSON.stringify(summary, null, 2));
|
|
1602
1193
|
}
|
|
1603
1194
|
else {
|
|
1604
|
-
const
|
|
1605
|
-
console.log(
|
|
1606
|
-
|
|
1607
|
-
|
|
1608
|
-
|
|
1609
|
-
|
|
1610
|
-
|
|
1611
|
-
|
|
1612
|
-
|
|
1613
|
-
|
|
1614
|
-
|
|
1615
|
-
|
|
1616
|
-
|
|
1195
|
+
const xb = new XMLBuilder({ ignoreAttributes: false, attributeNamePrefix: '@_', format: true, indentBy: ' ', suppressEmptyNode: true });
|
|
1196
|
+
console.log(xb.build({
|
|
1197
|
+
model: {
|
|
1198
|
+
'@_name': summary.modelName || '',
|
|
1199
|
+
slices: { '@_count': String(summary.slices.total) },
|
|
1200
|
+
commands: { '@_count': String(summary.commands) },
|
|
1201
|
+
events: { '@_count': String(summary.events) },
|
|
1202
|
+
'read-models': { '@_count': String(summary.readModels) },
|
|
1203
|
+
screens: { '@_count': String(summary.screens) },
|
|
1204
|
+
processors: { '@_count': String(summary.processors) },
|
|
1205
|
+
aggregates: { '@_count': String(summary.aggregates) },
|
|
1206
|
+
actors: { '@_count': String(summary.actors) },
|
|
1207
|
+
scenarios: { '@_count': String(summary.scenarios) },
|
|
1208
|
+
flows: { '@_count': String(summary.flows) },
|
|
1209
|
+
},
|
|
1210
|
+
}).trim());
|
|
1617
1211
|
}
|
|
1618
1212
|
}
|
|
1619
|
-
else {
|
|
1620
|
-
showModelSummary(model, format);
|
|
1621
|
-
}
|
|
1622
1213
|
break;
|
|
1623
1214
|
case 'export':
|
|
1624
1215
|
if (helpRequested && !subcommand) {
|
|
@@ -1658,13 +1249,10 @@ EXAMPLES:
|
|
|
1658
1249
|
`);
|
|
1659
1250
|
process.exit(0);
|
|
1660
1251
|
}
|
|
1661
|
-
|
|
1662
|
-
const result = await
|
|
1252
|
+
{
|
|
1253
|
+
const result = await api.exportJson(modelId);
|
|
1663
1254
|
console.log(JSON.stringify(JSON.parse(result), null, 2));
|
|
1664
1255
|
}
|
|
1665
|
-
else {
|
|
1666
|
-
exportEventmodelToJson(model);
|
|
1667
|
-
}
|
|
1668
1256
|
break;
|
|
1669
1257
|
default:
|
|
1670
1258
|
console.error(`Unknown export format: ${subcommand}`);
|
|
@@ -1756,7 +1344,7 @@ EXAMPLES:
|
|
|
1756
1344
|
console.error('Run "eventmodeler add scenario --help" for detailed format.');
|
|
1757
1345
|
process.exit(1);
|
|
1758
1346
|
}
|
|
1759
|
-
|
|
1347
|
+
{
|
|
1760
1348
|
let parsedScenario;
|
|
1761
1349
|
try {
|
|
1762
1350
|
parsedScenario = parseScenarioInput(inputData);
|
|
@@ -1800,12 +1388,9 @@ EXAMPLES:
|
|
|
1800
1388
|
: undefined,
|
|
1801
1389
|
},
|
|
1802
1390
|
};
|
|
1803
|
-
await
|
|
1391
|
+
await api.createScenario(modelId, sliceArg, scenario);
|
|
1804
1392
|
console.log(`Created scenario "${scenario.name}" in slice "${sliceArg}"`);
|
|
1805
1393
|
}
|
|
1806
|
-
else {
|
|
1807
|
-
addScenario(model, filePath, sliceArg, inputData);
|
|
1808
|
-
}
|
|
1809
1394
|
break;
|
|
1810
1395
|
}
|
|
1811
1396
|
case 'field': {
|
|
@@ -1814,14 +1399,10 @@ EXAMPLES:
|
|
|
1814
1399
|
eventmodeler add field - Add a field to an entity
|
|
1815
1400
|
|
|
1816
1401
|
USAGE:
|
|
1817
|
-
eventmodeler add field
|
|
1402
|
+
eventmodeler add field <element-name> --json|--xml <data>
|
|
1818
1403
|
|
|
1819
1404
|
OPTIONS:
|
|
1820
|
-
|
|
1821
|
-
--event <name> Target event name
|
|
1822
|
-
--read-model <name> Target read model name
|
|
1823
|
-
--screen <name> Target screen name
|
|
1824
|
-
--processor <name> Target processor name
|
|
1405
|
+
<element-name> Name of the command, event, read model, screen, or processor
|
|
1825
1406
|
--json <data> Field definition in JSON format
|
|
1826
1407
|
--xml <data> Field definition in XML format
|
|
1827
1408
|
|
|
@@ -1898,28 +1479,31 @@ NOTES:
|
|
|
1898
1479
|
- Subfields support arbitrary nesting depth
|
|
1899
1480
|
|
|
1900
1481
|
EXAMPLES:
|
|
1901
|
-
eventmodeler add field
|
|
1902
|
-
eventmodeler add field
|
|
1903
|
-
eventmodeler add field
|
|
1482
|
+
eventmodeler add field OrderPlaced --json '{"name": "orderId", "type": "UUID"}'
|
|
1483
|
+
eventmodeler add field OrderSummary --json '{"name": "totalWithTax", "type": "Decimal", "isGenerated": true}'
|
|
1484
|
+
eventmodeler add field OrderPlaced --xml '<field name="item" type="Custom"><field name="price" type="Decimal"/><field name="tax" type="Decimal" isGenerated="true"/></field>'
|
|
1904
1485
|
`);
|
|
1905
1486
|
process.exit(0);
|
|
1906
1487
|
}
|
|
1907
|
-
const commandArg = getNamedArg(filteredArgs, '--command');
|
|
1908
|
-
const eventArg = getNamedArg(filteredArgs, '--event');
|
|
1909
|
-
const readModelArg = getNamedArg(filteredArgs, '--read-model');
|
|
1910
|
-
const screenArg = getNamedArg(filteredArgs, '--screen');
|
|
1911
|
-
const processorArg = getNamedArg(filteredArgs, '--processor');
|
|
1912
1488
|
const jsonArg = getNamedArg(filteredArgs, '--json');
|
|
1913
1489
|
const xmlArg = getNamedArg(filteredArgs, '--xml');
|
|
1914
1490
|
const inputData = jsonArg ?? xmlArg;
|
|
1491
|
+
// Element name is the first positional arg (not a flag or flag value)
|
|
1492
|
+
const elementName = filteredArgs.find((a, i) => !a.startsWith('-') && (i === 0 || !['--json', '--xml'].includes(filteredArgs[i - 1])));
|
|
1493
|
+
if (!elementName) {
|
|
1494
|
+
console.error('Error: Element name is required');
|
|
1495
|
+
console.error('Usage: eventmodeler add field <element-name> --json|--xml <data>');
|
|
1496
|
+
console.error('Run "eventmodeler add field --help" for detailed format documentation.');
|
|
1497
|
+
process.exit(1);
|
|
1498
|
+
}
|
|
1915
1499
|
if (!inputData) {
|
|
1916
1500
|
console.error('Error: --json or --xml is required');
|
|
1917
|
-
console.error('Usage: eventmodeler add field
|
|
1501
|
+
console.error('Usage: eventmodeler add field <element-name> --json|--xml <data>');
|
|
1918
1502
|
console.error('Run "eventmodeler add field --help" for detailed format documentation.');
|
|
1919
1503
|
process.exit(1);
|
|
1920
1504
|
}
|
|
1921
|
-
|
|
1922
|
-
// Parse field data
|
|
1505
|
+
{
|
|
1506
|
+
// Parse field data
|
|
1923
1507
|
let field;
|
|
1924
1508
|
try {
|
|
1925
1509
|
if (jsonArg) {
|
|
@@ -1935,59 +1519,29 @@ EXAMPLES:
|
|
|
1935
1519
|
};
|
|
1936
1520
|
}
|
|
1937
1521
|
else {
|
|
1938
|
-
|
|
1939
|
-
const
|
|
1940
|
-
|
|
1941
|
-
|
|
1942
|
-
|
|
1943
|
-
const
|
|
1944
|
-
|
|
1945
|
-
|
|
1946
|
-
|
|
1947
|
-
|
|
1948
|
-
|
|
1949
|
-
|
|
1950
|
-
|
|
1951
|
-
|
|
1952
|
-
|
|
1522
|
+
const parser = await import('./lib/slice-utils.js');
|
|
1523
|
+
const parsed = parser.parseFieldsFromXml(inputData);
|
|
1524
|
+
if (parsed.length === 0) {
|
|
1525
|
+
throw new Error('No <field> element found in XML');
|
|
1526
|
+
}
|
|
1527
|
+
const toApiField = (f) => ({
|
|
1528
|
+
name: f.name,
|
|
1529
|
+
fieldType: f.type,
|
|
1530
|
+
isList: f.isList,
|
|
1531
|
+
isOptional: f.isOptional,
|
|
1532
|
+
isGenerated: f.isGenerated,
|
|
1533
|
+
isUserInput: f.isUserInput,
|
|
1534
|
+
subfields: f.subfields?.map(toApiField),
|
|
1535
|
+
});
|
|
1536
|
+
field = toApiField(parsed[0]);
|
|
1953
1537
|
}
|
|
1954
1538
|
}
|
|
1955
1539
|
catch (err) {
|
|
1956
1540
|
console.error(`Error parsing field data: ${err.message}`);
|
|
1957
1541
|
process.exit(1);
|
|
1958
1542
|
}
|
|
1959
|
-
|
|
1960
|
-
|
|
1961
|
-
let elementName;
|
|
1962
|
-
if (commandArg) {
|
|
1963
|
-
elementType = 'command';
|
|
1964
|
-
elementName = commandArg;
|
|
1965
|
-
}
|
|
1966
|
-
else if (eventArg) {
|
|
1967
|
-
elementType = 'event';
|
|
1968
|
-
elementName = eventArg;
|
|
1969
|
-
}
|
|
1970
|
-
else if (readModelArg) {
|
|
1971
|
-
elementType = 'readModel';
|
|
1972
|
-
elementName = readModelArg;
|
|
1973
|
-
}
|
|
1974
|
-
else if (screenArg) {
|
|
1975
|
-
elementType = 'screen';
|
|
1976
|
-
elementName = screenArg;
|
|
1977
|
-
}
|
|
1978
|
-
else if (processorArg) {
|
|
1979
|
-
elementType = 'processor';
|
|
1980
|
-
elementName = processorArg;
|
|
1981
|
-
}
|
|
1982
|
-
else {
|
|
1983
|
-
console.error('Error: Must specify one of --command, --event, --read-model, --screen, or --processor');
|
|
1984
|
-
process.exit(1);
|
|
1985
|
-
}
|
|
1986
|
-
await cloudSlices.addField(modelId, elementType, elementName, field);
|
|
1987
|
-
console.log(`Added field "${field.name}" to ${elementType} "${elementName}"`);
|
|
1988
|
-
}
|
|
1989
|
-
else {
|
|
1990
|
-
addField(model, filePath, { command: commandArg, event: eventArg, readModel: readModelArg, screen: screenArg, processor: processorArg }, inputData);
|
|
1543
|
+
await api.addField(modelId, elementName, field);
|
|
1544
|
+
console.log(`Added field "${field.name}" to "${elementName}"`);
|
|
1991
1545
|
}
|
|
1992
1546
|
break;
|
|
1993
1547
|
}
|
|
@@ -2049,13 +1603,8 @@ EXAMPLES:
|
|
|
2049
1603
|
console.error('Run "eventmodeler remove scenario --help" for more information.');
|
|
2050
1604
|
process.exit(1);
|
|
2051
1605
|
}
|
|
2052
|
-
|
|
2053
|
-
|
|
2054
|
-
console.log(`Removed scenario "${scenarioName}"${sliceArg ? ` from slice "${sliceArg}"` : ''}`);
|
|
2055
|
-
}
|
|
2056
|
-
else {
|
|
2057
|
-
removeScenario(model, filePath, scenarioName, sliceArg);
|
|
2058
|
-
}
|
|
1606
|
+
await api.removeScenario(modelId, scenarioName, sliceArg);
|
|
1607
|
+
console.log(`Removed scenario "${scenarioName}"${sliceArg ? ` from slice "${sliceArg}"` : ''}`);
|
|
2059
1608
|
break;
|
|
2060
1609
|
}
|
|
2061
1610
|
case 'field': {
|
|
@@ -2064,67 +1613,36 @@ EXAMPLES:
|
|
|
2064
1613
|
eventmodeler remove field - Remove a field from an entity
|
|
2065
1614
|
|
|
2066
1615
|
USAGE:
|
|
2067
|
-
eventmodeler remove field
|
|
1616
|
+
eventmodeler remove field <element-name> --field <field-name>
|
|
2068
1617
|
|
|
2069
1618
|
OPTIONS:
|
|
2070
|
-
|
|
2071
|
-
--event <name> Target event name
|
|
2072
|
-
--read-model <name> Target read model name
|
|
2073
|
-
--screen <name> Target screen name
|
|
2074
|
-
--processor <name> Target processor name
|
|
1619
|
+
<element-name> Name of the command, event, read model, screen, or processor
|
|
2075
1620
|
--field <name> Field name to remove (required)
|
|
2076
1621
|
|
|
2077
1622
|
EXAMPLES:
|
|
2078
|
-
eventmodeler remove field
|
|
2079
|
-
eventmodeler remove field
|
|
1623
|
+
eventmodeler remove field OrderPlaced --field orderId
|
|
1624
|
+
eventmodeler remove field "Order Summary" --field notes
|
|
2080
1625
|
`);
|
|
2081
1626
|
process.exit(0);
|
|
2082
1627
|
}
|
|
2083
|
-
const commandArg = getNamedArg(filteredArgs, '--command');
|
|
2084
|
-
const eventArg = getNamedArg(filteredArgs, '--event');
|
|
2085
|
-
const readModelArg = getNamedArg(filteredArgs, '--read-model');
|
|
2086
|
-
const screenArg = getNamedArg(filteredArgs, '--screen');
|
|
2087
|
-
const processorArg = getNamedArg(filteredArgs, '--processor');
|
|
2088
1628
|
const fieldArg = getNamedArg(filteredArgs, '--field');
|
|
1629
|
+
// Element name is the first positional arg (not a flag or flag value)
|
|
1630
|
+
const elementName = filteredArgs.find((a, i) => !a.startsWith('-') && (i === 0 || !['--field'].includes(filteredArgs[i - 1])));
|
|
2089
1631
|
if (!fieldArg) {
|
|
2090
1632
|
console.error('Error: --field is required');
|
|
2091
|
-
console.error('Usage: eventmodeler remove field
|
|
1633
|
+
console.error('Usage: eventmodeler remove field <element-name> --field <field-name>');
|
|
2092
1634
|
console.error('Run "eventmodeler remove field --help" for more information.');
|
|
2093
1635
|
process.exit(1);
|
|
2094
1636
|
}
|
|
2095
|
-
if (
|
|
2096
|
-
|
|
2097
|
-
|
|
2098
|
-
|
|
2099
|
-
|
|
2100
|
-
elementType = 'command';
|
|
2101
|
-
elementName = commandArg;
|
|
2102
|
-
}
|
|
2103
|
-
else if (eventArg) {
|
|
2104
|
-
elementType = 'event';
|
|
2105
|
-
elementName = eventArg;
|
|
2106
|
-
}
|
|
2107
|
-
else if (readModelArg) {
|
|
2108
|
-
elementType = 'readModel';
|
|
2109
|
-
elementName = readModelArg;
|
|
2110
|
-
}
|
|
2111
|
-
else if (screenArg) {
|
|
2112
|
-
elementType = 'screen';
|
|
2113
|
-
elementName = screenArg;
|
|
2114
|
-
}
|
|
2115
|
-
else if (processorArg) {
|
|
2116
|
-
elementType = 'processor';
|
|
2117
|
-
elementName = processorArg;
|
|
2118
|
-
}
|
|
2119
|
-
else {
|
|
2120
|
-
console.error('Error: Must specify one of --command, --event, --read-model, --screen, or --processor');
|
|
2121
|
-
process.exit(1);
|
|
2122
|
-
}
|
|
2123
|
-
await cloudSlices.removeField(modelId, elementType, elementName, fieldArg);
|
|
2124
|
-
console.log(`Removed field "${fieldArg}" from ${elementType} "${elementName}"`);
|
|
1637
|
+
if (!elementName) {
|
|
1638
|
+
console.error('Error: Element name is required');
|
|
1639
|
+
console.error('Usage: eventmodeler remove field <element-name> --field <field-name>');
|
|
1640
|
+
console.error('Run "eventmodeler remove field --help" for more information.');
|
|
1641
|
+
process.exit(1);
|
|
2125
1642
|
}
|
|
2126
|
-
|
|
2127
|
-
removeField(
|
|
1643
|
+
{
|
|
1644
|
+
await api.removeField(modelId, elementName, fieldArg);
|
|
1645
|
+
console.log(`Removed field "${fieldArg}" from "${elementName}"`);
|
|
2128
1646
|
}
|
|
2129
1647
|
break;
|
|
2130
1648
|
}
|
|
@@ -2179,7 +1697,7 @@ XML FORMAT:
|
|
|
2179
1697
|
NOTES:
|
|
2180
1698
|
- Mappings define how fields flow from source to target
|
|
2181
1699
|
- Fields marked as isGenerated=true don't need mappings
|
|
2182
|
-
- Use "show completeness" to check mapping status
|
|
1700
|
+
- Use "show information-completeness <name>" to check mapping status
|
|
2183
1701
|
|
|
2184
1702
|
EXAMPLES:
|
|
2185
1703
|
eventmodeler map fields --flow "OrderPlaced→OrderSummary" --json '[{"from": "total", "to": "totalAmount"}]'
|
|
@@ -2204,7 +1722,7 @@ EXAMPLES:
|
|
|
2204
1722
|
console.error('Run "eventmodeler map fields --help" for detailed format.');
|
|
2205
1723
|
process.exit(1);
|
|
2206
1724
|
}
|
|
2207
|
-
|
|
1725
|
+
{
|
|
2208
1726
|
// Parse flow argument to extract source and target names
|
|
2209
1727
|
const flowParts = flowArg.split(/→|->/).map(s => s.trim());
|
|
2210
1728
|
if (flowParts.length !== 2) {
|
|
@@ -2219,28 +1737,23 @@ EXAMPLES:
|
|
|
2219
1737
|
mappings = JSON.parse(inputData);
|
|
2220
1738
|
}
|
|
2221
1739
|
else {
|
|
2222
|
-
|
|
2223
|
-
const
|
|
2224
|
-
|
|
2225
|
-
|
|
2226
|
-
|
|
2227
|
-
|
|
2228
|
-
|
|
2229
|
-
|
|
2230
|
-
};
|
|
2231
|
-
});
|
|
1740
|
+
const xp = new XMLParser({ ignoreAttributes: false, attributeNamePrefix: '@_', isArray: (name) => name === 'mapping' });
|
|
1741
|
+
const parsed = xp.parse(inputData);
|
|
1742
|
+
const root = parsed['mappings'];
|
|
1743
|
+
const nodes = root ? (Array.isArray(root['mapping']) ? root['mapping'] : root['mapping'] ? [root['mapping']] : []) : [];
|
|
1744
|
+
mappings = nodes.map(m => ({
|
|
1745
|
+
from: m['@_from'] ?? '',
|
|
1746
|
+
to: m['@_to'] ?? '',
|
|
1747
|
+
}));
|
|
2232
1748
|
}
|
|
2233
1749
|
}
|
|
2234
1750
|
catch (err) {
|
|
2235
1751
|
console.error(`Error parsing mappings: ${err.message}`);
|
|
2236
1752
|
process.exit(1);
|
|
2237
1753
|
}
|
|
2238
|
-
await
|
|
1754
|
+
await api.mapFields(modelId, sourceName, targetName, mappings);
|
|
2239
1755
|
console.log(`Mapped ${mappings.length} field(s) from "${sourceName}" to "${targetName}"`);
|
|
2240
1756
|
}
|
|
2241
|
-
else {
|
|
2242
|
-
mapFields(model, filePath, flowArg, inputData);
|
|
2243
|
-
}
|
|
2244
1757
|
break;
|
|
2245
1758
|
}
|
|
2246
1759
|
default:
|
|
@@ -2272,22 +1785,18 @@ Run "eventmodeler update field --help" for detailed help.
|
|
|
2272
1785
|
eventmodeler update field - Update field properties
|
|
2273
1786
|
|
|
2274
1787
|
USAGE:
|
|
2275
|
-
eventmodeler update field
|
|
1788
|
+
eventmodeler update field <element-name> --field <field-name> [updates]
|
|
2276
1789
|
|
|
2277
|
-
|
|
2278
|
-
|
|
2279
|
-
--event <name> Target event
|
|
2280
|
-
--read-model <name> Target read model
|
|
2281
|
-
--screen <name> Target screen
|
|
2282
|
-
--processor <name> Target processor
|
|
1790
|
+
OPTIONS:
|
|
1791
|
+
<element-name> Name of the command, event, read model, screen, or processor
|
|
2283
1792
|
|
|
2284
1793
|
REQUIRED:
|
|
2285
|
-
--field <name>
|
|
1794
|
+
--field <name> Field to update
|
|
2286
1795
|
|
|
2287
1796
|
UPDATE OPTIONS (at least one required):
|
|
2288
1797
|
--optional true|false Set isOptional flag
|
|
2289
1798
|
--generated true|false Set isGenerated flag
|
|
2290
|
-
--user-input true|false Set isUserInput flag
|
|
1799
|
+
--user-input true|false Set isUserInput flag
|
|
2291
1800
|
--type <type> Change field type
|
|
2292
1801
|
|
|
2293
1802
|
FIELD FLAGS EXPLAINED:
|
|
@@ -2297,38 +1806,37 @@ FIELD FLAGS EXPLAINED:
|
|
|
2297
1806
|
|
|
2298
1807
|
EXAMPLES:
|
|
2299
1808
|
# Mark field as optional
|
|
2300
|
-
eventmodeler update field
|
|
1809
|
+
eventmodeler update field OrderSummary --field notes --optional true
|
|
2301
1810
|
|
|
2302
1811
|
# Mark field as generated (computed value, no mapping needed)
|
|
2303
|
-
eventmodeler update field
|
|
1812
|
+
eventmodeler update field OrderSummary --field totalWithTax --generated true
|
|
2304
1813
|
|
|
2305
1814
|
# Mark screen field as user input
|
|
2306
|
-
eventmodeler update field
|
|
1815
|
+
eventmodeler update field "Order Form" --field quantity --user-input true
|
|
2307
1816
|
|
|
2308
1817
|
# Change field type
|
|
2309
|
-
eventmodeler update field
|
|
1818
|
+
eventmodeler update field OrderPlaced --field amount --type Decimal
|
|
2310
1819
|
`);
|
|
2311
1820
|
process.exit(0);
|
|
2312
1821
|
}
|
|
2313
|
-
const commandArg = getNamedArg(filteredArgs, '--command');
|
|
2314
|
-
const eventArg = getNamedArg(filteredArgs, '--event');
|
|
2315
|
-
const readModelArg = getNamedArg(filteredArgs, '--read-model');
|
|
2316
|
-
const screenArg = getNamedArg(filteredArgs, '--screen');
|
|
2317
|
-
const processorArg = getNamedArg(filteredArgs, '--processor');
|
|
2318
1822
|
const fieldArg = getNamedArg(filteredArgs, '--field');
|
|
2319
1823
|
const optionalArg = getNamedArg(filteredArgs, '--optional');
|
|
2320
1824
|
const generatedArg = getNamedArg(filteredArgs, '--generated');
|
|
2321
1825
|
const userInputArg = getNamedArg(filteredArgs, '--user-input');
|
|
2322
1826
|
const typeArg = getNamedArg(filteredArgs, '--type');
|
|
1827
|
+
// Element name is the first positional arg (not a flag or flag value)
|
|
1828
|
+
const flagsWithValues = ['--field', '--optional', '--generated', '--user-input', '--type'];
|
|
1829
|
+
const elementName = filteredArgs.find((a, i) => !a.startsWith('-') && (i === 0 || !flagsWithValues.includes(filteredArgs[i - 1])));
|
|
2323
1830
|
if (!fieldArg) {
|
|
2324
1831
|
console.error('Error: --field is required');
|
|
2325
|
-
console.error('Usage: eventmodeler update field
|
|
1832
|
+
console.error('Usage: eventmodeler update field <element-name> --field <field-name> [--optional true|false] [--generated true|false] [--user-input true|false]');
|
|
2326
1833
|
console.error('Run "eventmodeler update field --help" for detailed options.');
|
|
2327
1834
|
process.exit(1);
|
|
2328
1835
|
}
|
|
2329
|
-
|
|
2330
|
-
|
|
2331
|
-
console.error('
|
|
1836
|
+
if (!elementName) {
|
|
1837
|
+
console.error('Error: Element name is required');
|
|
1838
|
+
console.error('Usage: eventmodeler update field <element-name> --field <field-name> [--optional true|false] [--generated true|false] [--user-input true|false]');
|
|
1839
|
+
console.error('Run "eventmodeler update field --help" for detailed options.');
|
|
2332
1840
|
process.exit(1);
|
|
2333
1841
|
}
|
|
2334
1842
|
const updates = {};
|
|
@@ -2349,49 +1857,19 @@ EXAMPLES:
|
|
|
2349
1857
|
console.error('Run "eventmodeler update field --help" for available options.');
|
|
2350
1858
|
process.exit(1);
|
|
2351
1859
|
}
|
|
2352
|
-
|
|
2353
|
-
//
|
|
2354
|
-
|
|
2355
|
-
let elementName;
|
|
2356
|
-
if (commandArg) {
|
|
2357
|
-
elementType = 'command';
|
|
2358
|
-
elementName = commandArg;
|
|
2359
|
-
}
|
|
2360
|
-
else if (eventArg) {
|
|
2361
|
-
elementType = 'event';
|
|
2362
|
-
elementName = eventArg;
|
|
2363
|
-
}
|
|
2364
|
-
else if (readModelArg) {
|
|
2365
|
-
elementType = 'readModel';
|
|
2366
|
-
elementName = readModelArg;
|
|
2367
|
-
}
|
|
2368
|
-
else if (screenArg) {
|
|
2369
|
-
elementType = 'screen';
|
|
2370
|
-
elementName = screenArg;
|
|
2371
|
-
}
|
|
2372
|
-
else if (processorArg) {
|
|
2373
|
-
elementType = 'processor';
|
|
2374
|
-
elementName = processorArg;
|
|
2375
|
-
}
|
|
2376
|
-
else {
|
|
2377
|
-
console.error('Error: Must specify one of --command, --event, --read-model, --screen, or --processor');
|
|
2378
|
-
process.exit(1);
|
|
2379
|
-
}
|
|
2380
|
-
// Convert local updates format to cloud format
|
|
2381
|
-
const cloudUpdates = {};
|
|
1860
|
+
{
|
|
1861
|
+
// Convert updates to API format
|
|
1862
|
+
const fieldUpdates = {};
|
|
2382
1863
|
if (updates.optional !== undefined)
|
|
2383
|
-
|
|
1864
|
+
fieldUpdates.isOptional = updates.optional;
|
|
2384
1865
|
if (updates.generated !== undefined)
|
|
2385
|
-
|
|
1866
|
+
fieldUpdates.isGenerated = updates.generated;
|
|
2386
1867
|
if (updates.userInput !== undefined)
|
|
2387
|
-
|
|
1868
|
+
fieldUpdates.isUserInput = updates.userInput;
|
|
2388
1869
|
if (updates.type !== undefined)
|
|
2389
|
-
|
|
2390
|
-
await
|
|
2391
|
-
console.log(`Updated field "${fieldArg}" on
|
|
2392
|
-
}
|
|
2393
|
-
else {
|
|
2394
|
-
updateField(model, filePath, { command: commandArg, event: eventArg, readModel: readModelArg, screen: screenArg, processor: processorArg }, fieldArg, updates);
|
|
1870
|
+
fieldUpdates.fieldType = updates.type;
|
|
1871
|
+
await api.updateField(modelId, elementName, fieldArg, fieldUpdates);
|
|
1872
|
+
console.log(`Updated field "${fieldArg}" on "${elementName}"`);
|
|
2395
1873
|
}
|
|
2396
1874
|
break;
|
|
2397
1875
|
}
|
|
@@ -2505,11 +1983,11 @@ EXAMPLES:
|
|
|
2505
1983
|
console.error('Run "eventmodeler create state-change-slice --help" for detailed format.');
|
|
2506
1984
|
process.exit(1);
|
|
2507
1985
|
}
|
|
2508
|
-
|
|
1986
|
+
{
|
|
2509
1987
|
// Parse XML input to extract structured data
|
|
2510
1988
|
const parser = await import('./lib/slice-utils.js');
|
|
2511
1989
|
const parsed = parser.parseStateChangeSliceXml(xmlArg);
|
|
2512
|
-
const
|
|
1990
|
+
const sliceInput = {
|
|
2513
1991
|
sliceName: parsed.sliceName,
|
|
2514
1992
|
after: parsed.after,
|
|
2515
1993
|
before: parsed.before,
|
|
@@ -2517,7 +1995,7 @@ EXAMPLES:
|
|
|
2517
1995
|
command: { name: parsed.command.name, fields: toCompoundFields(parsed.command.fields) },
|
|
2518
1996
|
event: { name: parsed.event.name, fields: toCompoundFields(parsed.event.fields) },
|
|
2519
1997
|
};
|
|
2520
|
-
const result = await
|
|
1998
|
+
const result = await api.createStateChangeSlice(modelId, sliceInput);
|
|
2521
1999
|
console.log(`Created state-change slice "${parsed.sliceName}"`);
|
|
2522
2000
|
console.log(` Screen: ${parsed.screen.name} (${parsed.screen.fields.length} fields)`);
|
|
2523
2001
|
console.log(` Command: ${parsed.command.name} (${parsed.command.fields.length} fields)`);
|
|
@@ -2525,9 +2003,6 @@ EXAMPLES:
|
|
|
2525
2003
|
console.log(` Screen -> Command mappings: ${result.screenToCommandMappings}`);
|
|
2526
2004
|
console.log(` Command -> Event mappings: ${result.commandToEventMappings}`);
|
|
2527
2005
|
}
|
|
2528
|
-
else {
|
|
2529
|
-
createStateChangeSlice(model, filePath, xmlArg);
|
|
2530
|
-
}
|
|
2531
2006
|
break;
|
|
2532
2007
|
}
|
|
2533
2008
|
case 'automation-slice': {
|
|
@@ -2608,11 +2083,11 @@ EXAMPLES:
|
|
|
2608
2083
|
console.error('Run "eventmodeler create automation-slice --help" for detailed format.');
|
|
2609
2084
|
process.exit(1);
|
|
2610
2085
|
}
|
|
2611
|
-
|
|
2086
|
+
{
|
|
2612
2087
|
// Parse XML input to extract structured data
|
|
2613
2088
|
const parser = await import('./lib/slice-utils.js');
|
|
2614
2089
|
const parsed = parser.parseAutomationSliceXml(xmlArg);
|
|
2615
|
-
const
|
|
2090
|
+
const sliceInput = {
|
|
2616
2091
|
sliceName: parsed.sliceName,
|
|
2617
2092
|
after: parsed.after,
|
|
2618
2093
|
before: parsed.before,
|
|
@@ -2621,7 +2096,7 @@ EXAMPLES:
|
|
|
2621
2096
|
command: { name: parsed.command.name, fields: toCompoundFields(parsed.command.fields) },
|
|
2622
2097
|
event: { name: parsed.event.name, fields: toCompoundFields(parsed.event.fields) },
|
|
2623
2098
|
};
|
|
2624
|
-
const result = await
|
|
2099
|
+
const result = await api.createAutomationSlice(modelId, sliceInput);
|
|
2625
2100
|
console.log(`Created automation slice "${parsed.sliceName}"`);
|
|
2626
2101
|
console.log(` ReadModel: ${parsed.readModel.name} (${parsed.readModel.fields.length} fields)`);
|
|
2627
2102
|
console.log(` Processor: ${parsed.processor.name}`);
|
|
@@ -2630,9 +2105,6 @@ EXAMPLES:
|
|
|
2630
2105
|
console.log(` ReadModel -> Command mappings: ${result.readModelToCommandMappings}`);
|
|
2631
2106
|
console.log(` Command -> Event mappings: ${result.commandToEventMappings}`);
|
|
2632
2107
|
}
|
|
2633
|
-
else {
|
|
2634
|
-
createAutomationSlice(model, filePath, xmlArg);
|
|
2635
|
-
}
|
|
2636
2108
|
break;
|
|
2637
2109
|
}
|
|
2638
2110
|
case 'state-view-slice': {
|
|
@@ -2699,23 +2171,20 @@ EXAMPLES:
|
|
|
2699
2171
|
console.error('Run "eventmodeler create state-view-slice --help" for detailed format.');
|
|
2700
2172
|
process.exit(1);
|
|
2701
2173
|
}
|
|
2702
|
-
|
|
2174
|
+
{
|
|
2703
2175
|
// Parse XML input to extract structured data
|
|
2704
2176
|
const parser = await import('./lib/slice-utils.js');
|
|
2705
2177
|
const parsed = parser.parseStateViewSliceXml(xmlArg);
|
|
2706
|
-
const
|
|
2178
|
+
const sliceInput = {
|
|
2707
2179
|
sliceName: parsed.sliceName,
|
|
2708
2180
|
after: parsed.after,
|
|
2709
2181
|
before: parsed.before,
|
|
2710
2182
|
readModel: { name: parsed.readModel.name, fields: toCompoundFields(parsed.readModel.fields) },
|
|
2711
2183
|
};
|
|
2712
|
-
const result = await
|
|
2184
|
+
const result = await api.createStateViewSlice(modelId, sliceInput);
|
|
2713
2185
|
console.log(`Created state-view slice "${parsed.sliceName}"`);
|
|
2714
2186
|
console.log(` ReadModel: ${parsed.readModel.name} (${parsed.readModel.fields.length} fields)`);
|
|
2715
2187
|
}
|
|
2716
|
-
else {
|
|
2717
|
-
createStateViewSlice(model, filePath, xmlArg);
|
|
2718
|
-
}
|
|
2719
2188
|
break;
|
|
2720
2189
|
}
|
|
2721
2190
|
case 'flow': {
|
|
@@ -2750,13 +2219,8 @@ EXAMPLES:
|
|
|
2750
2219
|
console.error('Run "eventmodeler create flow --help" for more information.');
|
|
2751
2220
|
process.exit(1);
|
|
2752
2221
|
}
|
|
2753
|
-
|
|
2754
|
-
|
|
2755
|
-
console.log(`Created flow from "${fromArg}" to "${toArg}"`);
|
|
2756
|
-
}
|
|
2757
|
-
else {
|
|
2758
|
-
createFlow(model, filePath, fromArg, toArg);
|
|
2759
|
-
}
|
|
2222
|
+
await api.createFlow(modelId, fromArg, toArg);
|
|
2223
|
+
console.log(`Created flow from "${fromArg}" to "${toArg}"`);
|
|
2760
2224
|
break;
|
|
2761
2225
|
}
|
|
2762
2226
|
default:
|
|
@@ -2820,13 +2284,10 @@ EXAMPLES:
|
|
|
2820
2284
|
console.error('Run "eventmodeler codegen slice --help" for more information.');
|
|
2821
2285
|
process.exit(1);
|
|
2822
2286
|
}
|
|
2823
|
-
|
|
2824
|
-
const result = await
|
|
2287
|
+
{
|
|
2288
|
+
const result = await api.codegenSlice(modelId, sliceName);
|
|
2825
2289
|
console.log(JSON.stringify(JSON.parse(result), null, 2));
|
|
2826
2290
|
}
|
|
2827
|
-
else {
|
|
2828
|
-
codegenSlice(model, sliceName);
|
|
2829
|
-
}
|
|
2830
2291
|
break;
|
|
2831
2292
|
}
|
|
2832
2293
|
case 'events': {
|
|
@@ -2858,13 +2319,10 @@ EXAMPLES:
|
|
|
2858
2319
|
process.exit(0);
|
|
2859
2320
|
}
|
|
2860
2321
|
const chapterName = chapterArg ?? target;
|
|
2861
|
-
|
|
2862
|
-
const output = await
|
|
2322
|
+
{
|
|
2323
|
+
const output = await api.codegenEvents(modelId, chapterName);
|
|
2863
2324
|
console.log(JSON.stringify(output, null, 2));
|
|
2864
2325
|
}
|
|
2865
|
-
else {
|
|
2866
|
-
codegenEvents(model, chapterName);
|
|
2867
|
-
}
|
|
2868
2326
|
break;
|
|
2869
2327
|
}
|
|
2870
2328
|
default:
|