eventmodeler 0.2.3 → 0.2.4
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/index.js +63 -0
- package/dist/lib/element-lookup.d.ts +47 -0
- package/dist/lib/element-lookup.js +86 -0
- package/dist/lib/slice-utils.d.ts +83 -0
- package/dist/lib/slice-utils.js +135 -0
- package/dist/projection.js +132 -0
- package/dist/slices/add-field/index.js +4 -33
- package/dist/slices/add-scenario/index.js +7 -74
- package/dist/slices/create-automation-slice/index.d.ts +2 -0
- package/dist/slices/create-automation-slice/index.js +217 -0
- package/dist/slices/create-flow/index.d.ts +2 -0
- package/dist/slices/create-flow/index.js +177 -0
- package/dist/slices/create-state-change-slice/index.d.ts +2 -0
- package/dist/slices/create-state-change-slice/index.js +239 -0
- package/dist/slices/create-state-view-slice/index.d.ts +2 -0
- package/dist/slices/create-state-view-slice/index.js +120 -0
- package/dist/slices/list-chapters/index.js +2 -2
- package/dist/slices/list-commands/index.js +2 -2
- package/dist/slices/list-events/index.js +3 -2
- package/dist/slices/list-slices/index.js +2 -2
- package/dist/slices/mark-slice-status/index.js +2 -11
- package/dist/slices/remove-field/index.js +4 -33
- package/dist/slices/remove-scenario/index.js +45 -11
- package/dist/slices/show-actor/index.js +2 -11
- package/dist/slices/show-aggregate-completeness/index.js +2 -11
- package/dist/slices/show-chapter/index.js +6 -14
- package/dist/slices/show-command/index.js +4 -12
- package/dist/slices/show-completeness/index.js +108 -19
- package/dist/slices/show-event/index.js +4 -12
- package/dist/slices/show-slice/index.js +14 -17
- package/dist/slices/update-field/index.js +4 -33
- package/package.json +1 -1
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import { escapeXml, outputJson } from '../../lib/format.js';
|
|
2
|
+
import { findElementOrExit } from '../../lib/element-lookup.js';
|
|
2
3
|
function getSlicesUnderChapter(model, chapter) {
|
|
3
4
|
// A slice is "under" a chapter if its horizontal center falls within the chapter's x range
|
|
4
5
|
const chapterLeft = chapter.position.x;
|
|
@@ -9,33 +10,24 @@ function getSlicesUnderChapter(model, chapter) {
|
|
|
9
10
|
}).sort((a, b) => a.position.x - b.position.x);
|
|
10
11
|
}
|
|
11
12
|
export function showChapter(model, name, format) {
|
|
12
|
-
const
|
|
13
|
-
const nameLower = name.toLowerCase();
|
|
14
|
-
const chapter = chapters.find(c => c.name.toLowerCase() === nameLower || c.name.toLowerCase().includes(nameLower));
|
|
15
|
-
if (!chapter) {
|
|
16
|
-
console.error(`Error: Chapter not found: ${name}`);
|
|
17
|
-
console.error('Available chapters:');
|
|
18
|
-
for (const c of chapters) {
|
|
19
|
-
console.error(` - ${c.name}`);
|
|
20
|
-
}
|
|
21
|
-
process.exit(1);
|
|
22
|
-
}
|
|
13
|
+
const chapter = findElementOrExit(model.chapters, name, 'chapter');
|
|
23
14
|
const slices = getSlicesUnderChapter(model, chapter);
|
|
24
15
|
if (format === 'json') {
|
|
25
16
|
outputJson({
|
|
17
|
+
id: chapter.id,
|
|
26
18
|
name: chapter.name,
|
|
27
|
-
slices: slices.map(s => ({ name: s.name, status: s.status }))
|
|
19
|
+
slices: slices.map(s => ({ id: s.id, name: s.name, status: s.status }))
|
|
28
20
|
});
|
|
29
21
|
return;
|
|
30
22
|
}
|
|
31
|
-
console.log(`<chapter name="${escapeXml(chapter.name)}">`);
|
|
23
|
+
console.log(`<chapter id="${chapter.id}" name="${escapeXml(chapter.name)}">`);
|
|
32
24
|
if (slices.length === 0) {
|
|
33
25
|
console.log(' <slices/>');
|
|
34
26
|
}
|
|
35
27
|
else {
|
|
36
28
|
console.log(' <slices>');
|
|
37
29
|
for (const slice of slices) {
|
|
38
|
-
console.log(` <slice name="${escapeXml(slice.name)}" status="${slice.status}"/>`);
|
|
30
|
+
console.log(` <slice id="${slice.id}" name="${escapeXml(slice.name)}" status="${slice.status}"/>`);
|
|
39
31
|
}
|
|
40
32
|
console.log(' </slices>');
|
|
41
33
|
}
|
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import { escapeXml, outputJson } from '../../lib/format.js';
|
|
2
|
+
import { findElementOrExit } from '../../lib/element-lookup.js';
|
|
2
3
|
function formatFieldXml(field, indent) {
|
|
3
4
|
const attrs = [
|
|
4
5
|
`name="${escapeXml(field.name)}"`,
|
|
@@ -54,7 +55,7 @@ function findAggregateForEvent(model, event) {
|
|
|
54
55
|
return null;
|
|
55
56
|
}
|
|
56
57
|
function formatCommandXml(model, command) {
|
|
57
|
-
let xml = `<command name="${escapeXml(command.name)}">\n`;
|
|
58
|
+
let xml = `<command id="${command.id}" name="${escapeXml(command.name)}">\n`;
|
|
58
59
|
if (command.fields.length > 0) {
|
|
59
60
|
xml += ' <fields>\n';
|
|
60
61
|
for (const field of command.fields) {
|
|
@@ -92,21 +93,12 @@ function formatCommandXml(model, command) {
|
|
|
92
93
|
return xml;
|
|
93
94
|
}
|
|
94
95
|
export function showCommand(model, name, format) {
|
|
95
|
-
const
|
|
96
|
-
const nameLower = name.toLowerCase();
|
|
97
|
-
const command = commands.find(c => c.name.toLowerCase() === nameLower || c.name.toLowerCase().includes(nameLower));
|
|
98
|
-
if (!command) {
|
|
99
|
-
console.error(`Error: Command not found: ${name}`);
|
|
100
|
-
console.error('Available commands:');
|
|
101
|
-
for (const c of commands) {
|
|
102
|
-
console.error(` - ${c.name}`);
|
|
103
|
-
}
|
|
104
|
-
process.exit(1);
|
|
105
|
-
}
|
|
96
|
+
const command = findElementOrExit(model.commands, name, 'command');
|
|
106
97
|
if (format === 'json') {
|
|
107
98
|
const incomingFlows = [...model.flows.values()].filter(f => f.targetId === command.id);
|
|
108
99
|
const outgoingFlows = [...model.flows.values()].filter(f => f.sourceId === command.id);
|
|
109
100
|
const result = {
|
|
101
|
+
id: command.id,
|
|
110
102
|
name: command.name,
|
|
111
103
|
fields: command.fields.map(fieldToJson)
|
|
112
104
|
};
|
|
@@ -7,38 +7,92 @@ const INCOMING_FLOW_TYPES = {
|
|
|
7
7
|
processor: ['ReadModelToProcessor'],
|
|
8
8
|
};
|
|
9
9
|
function findElementByName(model, name) {
|
|
10
|
+
// Check for UUID lookup (id:prefix or full UUID format)
|
|
11
|
+
if (name.startsWith('id:')) {
|
|
12
|
+
const idSearch = name.slice(3).toLowerCase();
|
|
13
|
+
// Search all element types by ID
|
|
14
|
+
for (const cmd of model.commands.values()) {
|
|
15
|
+
if (cmd.id.toLowerCase().startsWith(idSearch)) {
|
|
16
|
+
return { element: { id: cmd.id, name: cmd.name, fields: cmd.fields, type: 'command' }, ambiguous: [] };
|
|
17
|
+
}
|
|
18
|
+
}
|
|
19
|
+
for (const evt of model.events.values()) {
|
|
20
|
+
if (evt.id.toLowerCase().startsWith(idSearch)) {
|
|
21
|
+
return { element: { id: evt.id, name: evt.name, fields: evt.fields, type: 'event' }, ambiguous: [] };
|
|
22
|
+
}
|
|
23
|
+
}
|
|
24
|
+
for (const rm of model.readModels.values()) {
|
|
25
|
+
if (rm.id.toLowerCase().startsWith(idSearch)) {
|
|
26
|
+
return { element: { id: rm.id, name: rm.name, fields: rm.fields, type: 'readModel' }, ambiguous: [] };
|
|
27
|
+
}
|
|
28
|
+
}
|
|
29
|
+
for (const scr of model.screens.values()) {
|
|
30
|
+
if (scr.id.toLowerCase().startsWith(idSearch)) {
|
|
31
|
+
return { element: { id: scr.id, name: scr.name, fields: scr.fields, type: 'screen' }, ambiguous: [] };
|
|
32
|
+
}
|
|
33
|
+
}
|
|
34
|
+
for (const proc of model.processors.values()) {
|
|
35
|
+
if (proc.id.toLowerCase().startsWith(idSearch)) {
|
|
36
|
+
return { element: { id: proc.id, name: proc.name, fields: proc.fields, type: 'processor' }, ambiguous: [] };
|
|
37
|
+
}
|
|
38
|
+
}
|
|
39
|
+
return { element: null, ambiguous: [] };
|
|
40
|
+
}
|
|
41
|
+
// Check if it's a full UUID
|
|
42
|
+
const uuidPattern = /^[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$/i;
|
|
43
|
+
if (uuidPattern.test(name)) {
|
|
44
|
+
const cmd = model.commands.get(name);
|
|
45
|
+
if (cmd)
|
|
46
|
+
return { element: { id: cmd.id, name: cmd.name, fields: cmd.fields, type: 'command' }, ambiguous: [] };
|
|
47
|
+
const evt = model.events.get(name);
|
|
48
|
+
if (evt)
|
|
49
|
+
return { element: { id: evt.id, name: evt.name, fields: evt.fields, type: 'event' }, ambiguous: [] };
|
|
50
|
+
const rm = model.readModels.get(name);
|
|
51
|
+
if (rm)
|
|
52
|
+
return { element: { id: rm.id, name: rm.name, fields: rm.fields, type: 'readModel' }, ambiguous: [] };
|
|
53
|
+
const scr = model.screens.get(name);
|
|
54
|
+
if (scr)
|
|
55
|
+
return { element: { id: scr.id, name: scr.name, fields: scr.fields, type: 'screen' }, ambiguous: [] };
|
|
56
|
+
const proc = model.processors.get(name);
|
|
57
|
+
if (proc)
|
|
58
|
+
return { element: { id: proc.id, name: proc.name, fields: proc.fields, type: 'processor' }, ambiguous: [] };
|
|
59
|
+
return { element: null, ambiguous: [] };
|
|
60
|
+
}
|
|
61
|
+
// Case-insensitive exact name match across all types
|
|
10
62
|
const nameLower = name.toLowerCase();
|
|
11
|
-
|
|
63
|
+
const matches = [];
|
|
12
64
|
for (const cmd of model.commands.values()) {
|
|
13
|
-
if (cmd.name.toLowerCase() === nameLower
|
|
14
|
-
|
|
65
|
+
if (cmd.name.toLowerCase() === nameLower) {
|
|
66
|
+
matches.push({ element: { id: cmd.id, name: cmd.name, fields: cmd.fields, type: 'command' }, type: 'command' });
|
|
15
67
|
}
|
|
16
68
|
}
|
|
17
|
-
// Search events
|
|
18
69
|
for (const evt of model.events.values()) {
|
|
19
|
-
if (evt.name.toLowerCase() === nameLower
|
|
20
|
-
|
|
70
|
+
if (evt.name.toLowerCase() === nameLower) {
|
|
71
|
+
matches.push({ element: { id: evt.id, name: evt.name, fields: evt.fields, type: 'event' }, type: 'event' });
|
|
21
72
|
}
|
|
22
73
|
}
|
|
23
|
-
// Search read models
|
|
24
74
|
for (const rm of model.readModels.values()) {
|
|
25
|
-
if (rm.name.toLowerCase() === nameLower
|
|
26
|
-
|
|
75
|
+
if (rm.name.toLowerCase() === nameLower) {
|
|
76
|
+
matches.push({ element: { id: rm.id, name: rm.name, fields: rm.fields, type: 'readModel' }, type: 'readModel' });
|
|
27
77
|
}
|
|
28
78
|
}
|
|
29
|
-
// Search screens
|
|
30
79
|
for (const scr of model.screens.values()) {
|
|
31
|
-
if (scr.name.toLowerCase() === nameLower
|
|
32
|
-
|
|
80
|
+
if (scr.name.toLowerCase() === nameLower) {
|
|
81
|
+
matches.push({ element: { id: scr.id, name: scr.name, fields: scr.fields, type: 'screen' }, type: 'screen' });
|
|
33
82
|
}
|
|
34
83
|
}
|
|
35
|
-
// Search processors
|
|
36
84
|
for (const proc of model.processors.values()) {
|
|
37
|
-
if (proc.name.toLowerCase() === nameLower
|
|
38
|
-
|
|
85
|
+
if (proc.name.toLowerCase() === nameLower) {
|
|
86
|
+
matches.push({ element: { id: proc.id, name: proc.name, fields: proc.fields, type: 'processor' }, type: 'processor' });
|
|
39
87
|
}
|
|
40
88
|
}
|
|
41
|
-
|
|
89
|
+
if (matches.length === 1) {
|
|
90
|
+
return { element: matches[0].element, ambiguous: [] };
|
|
91
|
+
}
|
|
92
|
+
if (matches.length > 1) {
|
|
93
|
+
return { element: null, ambiguous: matches };
|
|
94
|
+
}
|
|
95
|
+
return { element: null, ambiguous: [] };
|
|
42
96
|
}
|
|
43
97
|
function getSourceFields(model, sourceId) {
|
|
44
98
|
const cmd = model.commands.get(sourceId);
|
|
@@ -159,10 +213,45 @@ function calculateFlowCompleteness(model, flow, targetFields, sourceFields) {
|
|
|
159
213
|
}
|
|
160
214
|
export function showCompleteness(model, elementName, format) {
|
|
161
215
|
// Find the element by name (searches all element types)
|
|
162
|
-
const element = findElementByName(model, elementName);
|
|
216
|
+
const { element, ambiguous } = findElementByName(model, elementName);
|
|
217
|
+
if (ambiguous.length > 0) {
|
|
218
|
+
console.error(`Error: Multiple elements found with name "${elementName}"`);
|
|
219
|
+
console.error('Please specify using the element ID:');
|
|
220
|
+
for (const match of ambiguous) {
|
|
221
|
+
console.error(` - "${match.element.name}" (${match.type}) (id: ${match.element.id})`);
|
|
222
|
+
}
|
|
223
|
+
console.error('');
|
|
224
|
+
console.error(`Usage: eventmodeler show completeness "id:${ambiguous[0].element.id.slice(0, 8)}"`);
|
|
225
|
+
process.exit(1);
|
|
226
|
+
}
|
|
163
227
|
if (!element) {
|
|
164
|
-
console.error(`Error: Element not found: ${elementName}`);
|
|
165
|
-
|
|
228
|
+
console.error(`Error: Element not found: "${elementName}"`);
|
|
229
|
+
// List all available elements with their IDs
|
|
230
|
+
const allElements = [];
|
|
231
|
+
for (const cmd of model.commands.values()) {
|
|
232
|
+
allElements.push({ name: cmd.name, type: 'command', id: cmd.id });
|
|
233
|
+
}
|
|
234
|
+
for (const evt of model.events.values()) {
|
|
235
|
+
allElements.push({ name: evt.name, type: 'event', id: evt.id });
|
|
236
|
+
}
|
|
237
|
+
for (const rm of model.readModels.values()) {
|
|
238
|
+
allElements.push({ name: rm.name, type: 'read model', id: rm.id });
|
|
239
|
+
}
|
|
240
|
+
for (const scr of model.screens.values()) {
|
|
241
|
+
allElements.push({ name: scr.name, type: 'screen', id: scr.id });
|
|
242
|
+
}
|
|
243
|
+
for (const proc of model.processors.values()) {
|
|
244
|
+
allElements.push({ name: proc.name, type: 'processor', id: proc.id });
|
|
245
|
+
}
|
|
246
|
+
if (allElements.length > 0) {
|
|
247
|
+
console.error('Available elements:');
|
|
248
|
+
for (const el of allElements) {
|
|
249
|
+
console.error(` - "${el.name}" (${el.type}) (id: ${el.id.slice(0, 8)})`);
|
|
250
|
+
}
|
|
251
|
+
}
|
|
252
|
+
else {
|
|
253
|
+
console.error('No elements exist in the model.');
|
|
254
|
+
}
|
|
166
255
|
process.exit(1);
|
|
167
256
|
}
|
|
168
257
|
// Find all incoming flows for this element type
|
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import { escapeXml, outputJson } from '../../lib/format.js';
|
|
2
|
+
import { findElementOrExit } from '../../lib/element-lookup.js';
|
|
2
3
|
function formatFieldXml(field, indent) {
|
|
3
4
|
const attrs = [
|
|
4
5
|
`name="${escapeXml(field.name)}"`,
|
|
@@ -56,7 +57,7 @@ function findAggregateForEvent(model, event) {
|
|
|
56
57
|
function formatEventXml(model, event) {
|
|
57
58
|
const aggregate = findAggregateForEvent(model, event);
|
|
58
59
|
const aggregateAttr = aggregate ? ` aggregate="${escapeXml(aggregate.name)}"` : '';
|
|
59
|
-
let xml = `<event name="${escapeXml(event.name)}"${aggregateAttr}>\n`;
|
|
60
|
+
let xml = `<event id="${event.id}" name="${escapeXml(event.name)}"${aggregateAttr}>\n`;
|
|
60
61
|
if (event.fields.length > 0) {
|
|
61
62
|
xml += ' <fields>\n';
|
|
62
63
|
for (const field of event.fields) {
|
|
@@ -88,22 +89,13 @@ function formatEventXml(model, event) {
|
|
|
88
89
|
return xml;
|
|
89
90
|
}
|
|
90
91
|
export function showEvent(model, name, format) {
|
|
91
|
-
const
|
|
92
|
-
const nameLower = name.toLowerCase();
|
|
93
|
-
const event = events.find(e => e.name.toLowerCase() === nameLower || e.name.toLowerCase().includes(nameLower));
|
|
94
|
-
if (!event) {
|
|
95
|
-
console.error(`Error: Event not found: ${name}`);
|
|
96
|
-
console.error('Available events:');
|
|
97
|
-
for (const e of events) {
|
|
98
|
-
console.error(` - ${e.name}`);
|
|
99
|
-
}
|
|
100
|
-
process.exit(1);
|
|
101
|
-
}
|
|
92
|
+
const event = findElementOrExit(model.events, name, 'event');
|
|
102
93
|
if (format === 'json') {
|
|
103
94
|
const aggregate = findAggregateForEvent(model, event);
|
|
104
95
|
const incomingFlows = [...model.flows.values()].filter(f => f.targetId === event.id);
|
|
105
96
|
const outgoingFlows = [...model.flows.values()].filter(f => f.sourceId === event.id);
|
|
106
97
|
const result = {
|
|
98
|
+
id: event.id,
|
|
107
99
|
name: event.name,
|
|
108
100
|
fields: event.fields.map(fieldToJson)
|
|
109
101
|
};
|
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import { escapeXml, outputJson } from '../../lib/format.js';
|
|
2
|
+
import { findElementOrExit } from '../../lib/element-lookup.js';
|
|
2
3
|
function formatFieldValues(values) {
|
|
3
4
|
if (!values || Object.keys(values).length === 0)
|
|
4
5
|
return '';
|
|
@@ -120,7 +121,7 @@ function formatSliceXml(model, slice) {
|
|
|
120
121
|
model.processors.get(id)?.name ??
|
|
121
122
|
id);
|
|
122
123
|
}
|
|
123
|
-
let xml = `<slice name="${escapeXml(slice.name)}" status="${slice.status}">\n`;
|
|
124
|
+
let xml = `<slice id="${slice.id}" name="${escapeXml(slice.name)}" status="${slice.status}">\n`;
|
|
124
125
|
xml += ' <components>\n';
|
|
125
126
|
for (const screen of components.screens) {
|
|
126
127
|
// Check if this is a linked copy
|
|
@@ -135,7 +136,7 @@ function formatSliceXml(model, slice) {
|
|
|
135
136
|
// Check which actor this screen belongs to
|
|
136
137
|
const actor = findActorForScreen(model, screen);
|
|
137
138
|
const actorAttr = actor ? ` actor="${escapeXml(actor.name)}"` : '';
|
|
138
|
-
xml += ` <screen name="${escapeXml(screen.name)}"${copyAttr}${originAttr}${actorAttr}>\n`;
|
|
139
|
+
xml += ` <screen id="${screen.id}" name="${escapeXml(screen.name)}"${copyAttr}${originAttr}${actorAttr}>\n`;
|
|
139
140
|
if (screen.fields.length > 0) {
|
|
140
141
|
xml += ' <fields>\n';
|
|
141
142
|
for (const field of screen.fields) {
|
|
@@ -146,7 +147,7 @@ function formatSliceXml(model, slice) {
|
|
|
146
147
|
xml += ' </screen>\n';
|
|
147
148
|
}
|
|
148
149
|
for (const command of components.commands) {
|
|
149
|
-
xml += ` <command name="${escapeXml(command.name)}">\n`;
|
|
150
|
+
xml += ` <command id="${command.id}" name="${escapeXml(command.name)}">\n`;
|
|
150
151
|
if (command.fields.length > 0) {
|
|
151
152
|
xml += ' <fields>\n';
|
|
152
153
|
for (const field of command.fields) {
|
|
@@ -177,7 +178,7 @@ function formatSliceXml(model, slice) {
|
|
|
177
178
|
// Check which aggregate this event belongs to
|
|
178
179
|
const aggregate = findAggregateForEvent(model, event);
|
|
179
180
|
const aggregateAttr = aggregate ? ` aggregate="${escapeXml(aggregate.name)}"` : '';
|
|
180
|
-
xml += ` <event name="${escapeXml(event.name)}"${copyAttr}${originAttr}${aggregateAttr}>\n`;
|
|
181
|
+
xml += ` <event id="${event.id}" name="${escapeXml(event.name)}"${copyAttr}${originAttr}${aggregateAttr}>\n`;
|
|
181
182
|
if (event.fields.length > 0) {
|
|
182
183
|
xml += ' <fields>\n';
|
|
183
184
|
for (const field of event.fields) {
|
|
@@ -208,7 +209,7 @@ function formatSliceXml(model, slice) {
|
|
|
208
209
|
originAttr = ` origin-slice="${escapeXml(originSlice.name)}"`;
|
|
209
210
|
}
|
|
210
211
|
}
|
|
211
|
-
xml += ` <read-model name="${escapeXml(readModel.name)}"${copyAttr}${originAttr}>\n`;
|
|
212
|
+
xml += ` <read-model id="${readModel.id}" name="${escapeXml(readModel.name)}"${copyAttr}${originAttr}>\n`;
|
|
212
213
|
if (readModel.fields.length > 0) {
|
|
213
214
|
xml += ' <fields>\n';
|
|
214
215
|
for (const field of readModel.fields) {
|
|
@@ -219,7 +220,7 @@ function formatSliceXml(model, slice) {
|
|
|
219
220
|
xml += ' </read-model>\n';
|
|
220
221
|
}
|
|
221
222
|
for (const processor of components.processors) {
|
|
222
|
-
xml += ` <processor name="${escapeXml(processor.name)}">\n`;
|
|
223
|
+
xml += ` <processor id="${processor.id}" name="${escapeXml(processor.name)}">\n`;
|
|
223
224
|
if (processor.fields.length > 0) {
|
|
224
225
|
xml += ' <fields>\n';
|
|
225
226
|
for (const field of processor.fields) {
|
|
@@ -337,11 +338,13 @@ function formatSliceJson(model, slice) {
|
|
|
337
338
|
id);
|
|
338
339
|
}
|
|
339
340
|
const result = {
|
|
341
|
+
id: slice.id,
|
|
340
342
|
name: slice.name,
|
|
341
343
|
status: slice.status,
|
|
342
344
|
components: {
|
|
343
345
|
screens: components.screens.map(screen => {
|
|
344
346
|
const screenObj = {
|
|
347
|
+
id: screen.id,
|
|
345
348
|
name: screen.name,
|
|
346
349
|
fields: screen.fields.map(fieldToJson)
|
|
347
350
|
};
|
|
@@ -357,11 +360,13 @@ function formatSliceJson(model, slice) {
|
|
|
357
360
|
return screenObj;
|
|
358
361
|
}),
|
|
359
362
|
commands: components.commands.map(cmd => ({
|
|
363
|
+
id: cmd.id,
|
|
360
364
|
name: cmd.name,
|
|
361
365
|
fields: cmd.fields.map(fieldToJson)
|
|
362
366
|
})),
|
|
363
367
|
events: components.events.map(event => {
|
|
364
368
|
const eventObj = {
|
|
369
|
+
id: event.id,
|
|
365
370
|
name: event.name,
|
|
366
371
|
fields: event.fields.map(fieldToJson)
|
|
367
372
|
};
|
|
@@ -378,6 +383,7 @@ function formatSliceJson(model, slice) {
|
|
|
378
383
|
}),
|
|
379
384
|
readModels: components.readModels.map(rm => {
|
|
380
385
|
const rmObj = {
|
|
386
|
+
id: rm.id,
|
|
381
387
|
name: rm.name,
|
|
382
388
|
fields: rm.fields.map(fieldToJson)
|
|
383
389
|
};
|
|
@@ -390,6 +396,7 @@ function formatSliceJson(model, slice) {
|
|
|
390
396
|
return rmObj;
|
|
391
397
|
}),
|
|
392
398
|
processors: components.processors.map(proc => ({
|
|
399
|
+
id: proc.id,
|
|
393
400
|
name: proc.name,
|
|
394
401
|
fields: proc.fields.map(fieldToJson)
|
|
395
402
|
}))
|
|
@@ -456,17 +463,7 @@ function formatSliceJson(model, slice) {
|
|
|
456
463
|
return result;
|
|
457
464
|
}
|
|
458
465
|
export function showSlice(model, name, format) {
|
|
459
|
-
const
|
|
460
|
-
const nameLower = name.toLowerCase();
|
|
461
|
-
const slice = slices.find(s => s.name.toLowerCase() === nameLower || s.name.toLowerCase().includes(nameLower));
|
|
462
|
-
if (!slice) {
|
|
463
|
-
console.error(`Error: Slice not found: ${name}`);
|
|
464
|
-
console.error('Available slices:');
|
|
465
|
-
for (const s of slices) {
|
|
466
|
-
console.error(` - ${s.name}`);
|
|
467
|
-
}
|
|
468
|
-
process.exit(1);
|
|
469
|
-
}
|
|
466
|
+
const slice = findElementOrExit(model.slices, name, 'slice');
|
|
470
467
|
if (format === 'json') {
|
|
471
468
|
outputJson(formatSliceJson(model, slice));
|
|
472
469
|
return;
|
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import { appendEvent } from '../../lib/file-loader.js';
|
|
2
|
+
import { findElementOrExit } from '../../lib/element-lookup.js';
|
|
2
3
|
function findFieldByName(fields, fieldName) {
|
|
3
4
|
const nameLower = fieldName.toLowerCase();
|
|
4
5
|
for (const field of fields) {
|
|
@@ -52,17 +53,7 @@ export function updateField(model, filePath, options, fieldName, updates) {
|
|
|
52
53
|
}
|
|
53
54
|
}
|
|
54
55
|
function updateCommandField(model, filePath, commandName, fieldName, updates) {
|
|
55
|
-
const
|
|
56
|
-
const commands = [...model.commands.values()];
|
|
57
|
-
const command = commands.find(c => c.name.toLowerCase() === nameLower || c.name.toLowerCase().includes(nameLower));
|
|
58
|
-
if (!command) {
|
|
59
|
-
console.error(`Error: Command not found: ${commandName}`);
|
|
60
|
-
console.error('Available commands:');
|
|
61
|
-
for (const c of commands) {
|
|
62
|
-
console.error(` - ${c.name}`);
|
|
63
|
-
}
|
|
64
|
-
process.exit(1);
|
|
65
|
-
}
|
|
56
|
+
const command = findElementOrExit(model.commands, commandName, 'command');
|
|
66
57
|
const field = findFieldByName(command.fields, fieldName);
|
|
67
58
|
if (!field) {
|
|
68
59
|
console.error(`Error: Field "${fieldName}" not found on command "${command.name}"`);
|
|
@@ -86,17 +77,7 @@ function updateCommandField(model, filePath, commandName, fieldName, updates) {
|
|
|
86
77
|
logUpdates(updates);
|
|
87
78
|
}
|
|
88
79
|
function updateEventField(model, filePath, eventName, fieldName, updates) {
|
|
89
|
-
const
|
|
90
|
-
const events = [...model.events.values()];
|
|
91
|
-
const event = events.find(e => e.name.toLowerCase() === nameLower || e.name.toLowerCase().includes(nameLower));
|
|
92
|
-
if (!event) {
|
|
93
|
-
console.error(`Error: Event not found: ${eventName}`);
|
|
94
|
-
console.error('Available events:');
|
|
95
|
-
for (const e of events) {
|
|
96
|
-
console.error(` - ${e.name}`);
|
|
97
|
-
}
|
|
98
|
-
process.exit(1);
|
|
99
|
-
}
|
|
80
|
+
const event = findElementOrExit(model.events, eventName, 'event');
|
|
100
81
|
const field = findFieldByName(event.fields, fieldName);
|
|
101
82
|
if (!field) {
|
|
102
83
|
console.error(`Error: Field "${fieldName}" not found on event "${event.name}"`);
|
|
@@ -120,17 +101,7 @@ function updateEventField(model, filePath, eventName, fieldName, updates) {
|
|
|
120
101
|
logUpdates(updates);
|
|
121
102
|
}
|
|
122
103
|
function updateReadModelField(model, filePath, readModelName, fieldName, updates) {
|
|
123
|
-
const
|
|
124
|
-
const readModels = [...model.readModels.values()];
|
|
125
|
-
const readModel = readModels.find(rm => rm.name.toLowerCase() === nameLower || rm.name.toLowerCase().includes(nameLower));
|
|
126
|
-
if (!readModel) {
|
|
127
|
-
console.error(`Error: Read model not found: ${readModelName}`);
|
|
128
|
-
console.error('Available read models:');
|
|
129
|
-
for (const rm of readModels) {
|
|
130
|
-
console.error(` - ${rm.name}`);
|
|
131
|
-
}
|
|
132
|
-
process.exit(1);
|
|
133
|
-
}
|
|
104
|
+
const readModel = findElementOrExit(model.readModels, readModelName, 'read model');
|
|
134
105
|
const field = findFieldByName(readModel.fields, fieldName);
|
|
135
106
|
if (!field) {
|
|
136
107
|
console.error(`Error: Field "${fieldName}" not found on read model "${readModel.name}"`);
|