eventmodeler 0.3.4 → 0.3.6

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -115,14 +115,32 @@ function applyEvent(model, event) {
115
115
  }
116
116
  case 'EventFieldAdded': {
117
117
  const evt = model.events.get(event.eventStickyId);
118
- if (evt)
118
+ if (evt) {
119
119
  evt.fields.push(event.field);
120
+ // Sync field to all linked copies with the same canonicalId
121
+ if (evt.canonicalId) {
122
+ for (const otherEvt of model.events.values()) {
123
+ if (otherEvt.id !== evt.id && otherEvt.canonicalId === evt.canonicalId) {
124
+ otherEvt.fields.push(event.field);
125
+ }
126
+ }
127
+ }
128
+ }
120
129
  break;
121
130
  }
122
131
  case 'EventFieldRemoved': {
123
132
  const evt = model.events.get(event.eventStickyId);
124
- if (evt)
133
+ if (evt) {
125
134
  evt.fields = evt.fields.filter(f => f.id !== event.fieldId);
135
+ // Sync removal to all linked copies with the same canonicalId
136
+ if (evt.canonicalId) {
137
+ for (const otherEvt of model.events.values()) {
138
+ if (otherEvt.id !== evt.id && otherEvt.canonicalId === evt.canonicalId) {
139
+ otherEvt.fields = otherEvt.fields.filter(f => f.id !== event.fieldId);
140
+ }
141
+ }
142
+ }
143
+ }
126
144
  break;
127
145
  }
128
146
  case 'EventFieldAdjusted': {
@@ -130,7 +148,19 @@ function applyEvent(model, event) {
130
148
  if (evt) {
131
149
  const idx = evt.fields.findIndex(f => f.id === event.fieldId);
132
150
  if (idx !== -1) {
133
- evt.fields[idx] = { ...event.field, id: event.fieldId };
151
+ const adjustedField = { ...event.field, id: event.fieldId };
152
+ evt.fields[idx] = adjustedField;
153
+ // Sync adjustment to all linked copies with the same canonicalId
154
+ if (evt.canonicalId) {
155
+ for (const otherEvt of model.events.values()) {
156
+ if (otherEvt.id !== evt.id && otherEvt.canonicalId === evt.canonicalId) {
157
+ const otherIdx = otherEvt.fields.findIndex(f => f.id === event.fieldId);
158
+ if (otherIdx !== -1) {
159
+ otherEvt.fields[otherIdx] = adjustedField;
160
+ }
161
+ }
162
+ }
163
+ }
134
164
  }
135
165
  }
136
166
  break;
@@ -190,14 +220,32 @@ function applyEvent(model, event) {
190
220
  }
191
221
  case 'ReadModelFieldAdded': {
192
222
  const rm = model.readModels.get(event.readModelStickyId);
193
- if (rm)
223
+ if (rm) {
194
224
  rm.fields.push(event.field);
225
+ // Sync field to all linked copies with the same canonicalId
226
+ if (rm.canonicalId) {
227
+ for (const otherRm of model.readModels.values()) {
228
+ if (otherRm.id !== rm.id && otherRm.canonicalId === rm.canonicalId) {
229
+ otherRm.fields.push(event.field);
230
+ }
231
+ }
232
+ }
233
+ }
195
234
  break;
196
235
  }
197
236
  case 'ReadModelFieldRemoved': {
198
237
  const rm = model.readModels.get(event.readModelStickyId);
199
- if (rm)
238
+ if (rm) {
200
239
  rm.fields = rm.fields.filter(f => f.id !== event.fieldId);
240
+ // Sync removal to all linked copies with the same canonicalId
241
+ if (rm.canonicalId) {
242
+ for (const otherRm of model.readModels.values()) {
243
+ if (otherRm.id !== rm.id && otherRm.canonicalId === rm.canonicalId) {
244
+ otherRm.fields = otherRm.fields.filter(f => f.id !== event.fieldId);
245
+ }
246
+ }
247
+ }
248
+ }
201
249
  break;
202
250
  }
203
251
  case 'ReadModelFieldAdjusted': {
@@ -205,7 +253,19 @@ function applyEvent(model, event) {
205
253
  if (rm) {
206
254
  const idx = rm.fields.findIndex(f => f.id === event.fieldId);
207
255
  if (idx !== -1) {
208
- rm.fields[idx] = { ...event.field, id: event.fieldId };
256
+ const adjustedField = { ...event.field, id: event.fieldId };
257
+ rm.fields[idx] = adjustedField;
258
+ // Sync adjustment to all linked copies with the same canonicalId
259
+ if (rm.canonicalId) {
260
+ for (const otherRm of model.readModels.values()) {
261
+ if (otherRm.id !== rm.id && otherRm.canonicalId === rm.canonicalId) {
262
+ const otherIdx = otherRm.fields.findIndex(f => f.id === event.fieldId);
263
+ if (otherIdx !== -1) {
264
+ otherRm.fields[otherIdx] = adjustedField;
265
+ }
266
+ }
267
+ }
268
+ }
209
269
  }
210
270
  }
211
271
  break;
@@ -264,14 +324,32 @@ function applyEvent(model, event) {
264
324
  }
265
325
  case 'ScreenFieldAdded': {
266
326
  const scr = model.screens.get(event.screenId);
267
- if (scr)
327
+ if (scr) {
268
328
  scr.fields.push(event.field);
329
+ // Sync field to all linked copies with the same canonicalId
330
+ if (scr.canonicalId) {
331
+ for (const otherScr of model.screens.values()) {
332
+ if (otherScr.id !== scr.id && otherScr.canonicalId === scr.canonicalId) {
333
+ otherScr.fields.push(event.field);
334
+ }
335
+ }
336
+ }
337
+ }
269
338
  break;
270
339
  }
271
340
  case 'ScreenFieldRemoved': {
272
341
  const scr = model.screens.get(event.screenId);
273
- if (scr)
342
+ if (scr) {
274
343
  scr.fields = scr.fields.filter(f => f.id !== event.fieldId);
344
+ // Sync removal to all linked copies with the same canonicalId
345
+ if (scr.canonicalId) {
346
+ for (const otherScr of model.screens.values()) {
347
+ if (otherScr.id !== scr.id && otherScr.canonicalId === scr.canonicalId) {
348
+ otherScr.fields = otherScr.fields.filter(f => f.id !== event.fieldId);
349
+ }
350
+ }
351
+ }
352
+ }
275
353
  break;
276
354
  }
277
355
  case 'ScreenFieldAdjusted': {
@@ -279,7 +357,19 @@ function applyEvent(model, event) {
279
357
  if (scr) {
280
358
  const idx = scr.fields.findIndex(f => f.id === event.fieldId);
281
359
  if (idx !== -1) {
282
- scr.fields[idx] = { ...event.field, id: event.fieldId };
360
+ const adjustedField = { ...event.field, id: event.fieldId };
361
+ scr.fields[idx] = adjustedField;
362
+ // Sync adjustment to all linked copies with the same canonicalId
363
+ if (scr.canonicalId) {
364
+ for (const otherScr of model.screens.values()) {
365
+ if (otherScr.id !== scr.id && otherScr.canonicalId === scr.canonicalId) {
366
+ const otherIdx = otherScr.fields.findIndex(f => f.id === event.fieldId);
367
+ if (otherIdx !== -1) {
368
+ otherScr.fields[otherIdx] = adjustedField;
369
+ }
370
+ }
371
+ }
372
+ }
283
373
  }
284
374
  }
285
375
  break;
@@ -1,4 +1,36 @@
1
1
  import { appendEvent } from '../../lib/file-loader.js';
2
+ /**
3
+ * Resolves an entity ID to its canonical original.
4
+ * If the entity is a linked copy, returns the original's ID.
5
+ * Otherwise returns the entity ID unchanged.
6
+ */
7
+ function resolveToOriginal(model, entityId) {
8
+ const event = model.events.get(entityId);
9
+ if (event?.originalNodeId)
10
+ return event.originalNodeId;
11
+ const readModel = model.readModels.get(entityId);
12
+ if (readModel?.originalNodeId)
13
+ return readModel.originalNodeId;
14
+ const screen = model.screens.get(entityId);
15
+ if (screen?.originalNodeId)
16
+ return screen.originalNodeId;
17
+ return entityId;
18
+ }
19
+ /**
20
+ * Checks if an entity is a linked copy (has originalNodeId set).
21
+ */
22
+ function isLinkedCopy(model, entityId) {
23
+ const event = model.events.get(entityId);
24
+ if (event?.originalNodeId)
25
+ return true;
26
+ const readModel = model.readModels.get(entityId);
27
+ if (readModel?.originalNodeId)
28
+ return true;
29
+ const screen = model.screens.get(entityId);
30
+ if (screen?.originalNodeId)
31
+ return true;
32
+ return false;
33
+ }
2
34
  function flattenFields(fields, prefix = '') {
3
35
  const result = [];
4
36
  for (const field of fields) {
@@ -64,7 +96,8 @@ export function mapFields(model, filePath, flowIdentifier, input) {
64
96
  if (arrowMatch) {
65
97
  const sourceName = arrowMatch[1].trim().toLowerCase();
66
98
  const targetName = arrowMatch[2].trim().toLowerCase();
67
- // Find matching flow
99
+ // Find matching flow, preferring flows that don't involve linked copies
100
+ let fallbackFlow = undefined;
68
101
  for (const f of model.flows.values()) {
69
102
  let sourceEntityName = '';
70
103
  let targetEntityName = '';
@@ -104,16 +137,32 @@ export function mapFields(model, filePath, flowIdentifier, input) {
104
137
  const sourceMatches = sourceEntityName === sourceName || sourceEntityName.includes(sourceName);
105
138
  const targetMatches = targetEntityName === targetName || targetEntityName.includes(targetName);
106
139
  if (sourceMatches && targetMatches) {
107
- flow = f;
108
- break;
140
+ // Prefer flows that don't involve linked copies
141
+ const involvesLinkedCopy = isLinkedCopy(model, f.sourceId) || isLinkedCopy(model, f.targetId);
142
+ if (!involvesLinkedCopy) {
143
+ flow = f;
144
+ break;
145
+ }
146
+ else if (!fallbackFlow) {
147
+ // Keep as fallback in case no non-copy flow is found
148
+ fallbackFlow = f;
149
+ }
109
150
  }
110
151
  }
152
+ // Use fallback if no non-copy flow was found
153
+ if (!flow && fallbackFlow) {
154
+ flow = fallbackFlow;
155
+ }
111
156
  }
112
157
  }
113
158
  if (!flow) {
114
159
  console.error(`Error: Flow not found: ${flowIdentifier}`);
115
160
  console.error('Available flows:');
116
161
  for (const f of model.flows.values()) {
162
+ // Skip flows where source or target is a linked copy (UI-only elements)
163
+ if (isLinkedCopy(model, f.sourceId) || isLinkedCopy(model, f.targetId)) {
164
+ continue;
165
+ }
117
166
  const source = getEntityName(model, f.sourceId);
118
167
  const target = getEntityName(model, f.targetId);
119
168
  console.error(` - ${source}→${target} (${f.id})`);
@@ -197,19 +246,21 @@ function getEntityName(model, entityId) {
197
246
  return entityId;
198
247
  }
199
248
  function getEntityFields(model, entityId) {
200
- const event = model.events.get(entityId);
249
+ // Resolve linked copies to their originals to get canonical fields
250
+ const resolvedId = resolveToOriginal(model, entityId);
251
+ const event = model.events.get(resolvedId);
201
252
  if (event)
202
253
  return event.fields;
203
- const readModel = model.readModels.get(entityId);
254
+ const readModel = model.readModels.get(resolvedId);
204
255
  if (readModel)
205
256
  return readModel.fields;
206
- const command = model.commands.get(entityId);
257
+ const command = model.commands.get(resolvedId);
207
258
  if (command)
208
259
  return command.fields;
209
- const screen = model.screens.get(entityId);
260
+ const screen = model.screens.get(resolvedId);
210
261
  if (screen)
211
262
  return screen.fields;
212
- const processor = model.processors.get(entityId);
263
+ const processor = model.processors.get(resolvedId);
213
264
  if (processor)
214
265
  return processor.fields;
215
266
  return [];
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "eventmodeler",
3
- "version": "0.3.4",
3
+ "version": "0.3.6",
4
4
  "description": "CLI tool for interacting with Event Model files - query, update, and export event models from the terminal",
5
5
  "type": "module",
6
6
  "bin": {