eventmodeler 0.3.1 → 0.3.2

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 CHANGED
@@ -282,14 +282,16 @@ async function main() {
282
282
  break;
283
283
  case 'mark': {
284
284
  // mark <slice-name> <status> - status is last arg, slice name is everything before
285
+ // Note: subcommand contains first part of slice name, remainingArgs has the rest
285
286
  const validStatuses = ['created', 'in-progress', 'blocked', 'done'];
286
- const lastArg = remainingArgs[remainingArgs.length - 1];
287
- if (remainingArgs.length < 2 || !validStatuses.includes(lastArg)) {
287
+ const allArgs = subcommand ? [subcommand, ...remainingArgs] : remainingArgs;
288
+ const lastArg = allArgs[allArgs.length - 1];
289
+ if (allArgs.length < 2 || !validStatuses.includes(lastArg)) {
288
290
  console.error('Usage: eventmodeler mark <slice-name> <status>');
289
291
  console.error('Valid statuses: created, in-progress, blocked, done');
290
292
  process.exit(1);
291
293
  }
292
- const sliceName = remainingArgs.slice(0, -1).join(' ');
294
+ const sliceName = allArgs.slice(0, -1).join(' ');
293
295
  const status = lastArg;
294
296
  markSliceStatus(model, filePath, sliceName, status);
295
297
  break;
@@ -61,12 +61,16 @@ function isElementInSlice(slice, position, width, height) {
61
61
  centerY >= slice.position.y &&
62
62
  centerY <= slice.position.y + slice.size.height);
63
63
  }
64
- // Get all component IDs in a slice
64
+ // Get all component IDs in a slice (including canonical group members for linked copies)
65
65
  export function getSliceComponentIds(model, slice) {
66
66
  const ids = new Set();
67
+ const canonicalIds = new Set();
68
+ // First pass: collect IDs and canonical IDs of elements in the slice
67
69
  for (const screen of model.screens.values()) {
68
70
  if (isElementInSlice(slice, screen.position, screen.width, screen.height)) {
69
71
  ids.add(screen.id);
72
+ if (screen.canonicalId)
73
+ canonicalIds.add(screen.canonicalId);
70
74
  }
71
75
  }
72
76
  for (const command of model.commands.values()) {
@@ -77,11 +81,15 @@ export function getSliceComponentIds(model, slice) {
77
81
  for (const event of model.events.values()) {
78
82
  if (isElementInSlice(slice, event.position, event.width, event.height)) {
79
83
  ids.add(event.id);
84
+ if (event.canonicalId)
85
+ canonicalIds.add(event.canonicalId);
80
86
  }
81
87
  }
82
88
  for (const readModel of model.readModels.values()) {
83
89
  if (isElementInSlice(slice, readModel.position, readModel.width, readModel.height)) {
84
90
  ids.add(readModel.id);
91
+ if (readModel.canonicalId)
92
+ canonicalIds.add(readModel.canonicalId);
85
93
  }
86
94
  }
87
95
  for (const processor of model.processors.values()) {
@@ -89,6 +97,25 @@ export function getSliceComponentIds(model, slice) {
89
97
  ids.add(processor.id);
90
98
  }
91
99
  }
100
+ // Second pass: add all elements that share a canonical ID with elements in the slice
101
+ // This ensures flows targeting any element in a canonical group are detected
102
+ if (canonicalIds.size > 0) {
103
+ for (const screen of model.screens.values()) {
104
+ if (screen.canonicalId && canonicalIds.has(screen.canonicalId)) {
105
+ ids.add(screen.id);
106
+ }
107
+ }
108
+ for (const event of model.events.values()) {
109
+ if (event.canonicalId && canonicalIds.has(event.canonicalId)) {
110
+ ids.add(event.id);
111
+ }
112
+ }
113
+ for (const readModel of model.readModels.values()) {
114
+ if (readModel.canonicalId && canonicalIds.has(readModel.canonicalId)) {
115
+ ids.add(readModel.id);
116
+ }
117
+ }
118
+ }
92
119
  return ids;
93
120
  }
94
121
  // Find which slice contains a component
@@ -292,12 +292,42 @@ export function codegenSlice(model, sliceName) {
292
292
  const slice = findElementOrExit(model.slices, sliceName, 'slice');
293
293
  // 2. Get components inside slice
294
294
  const components = getSliceComponents(model, slice);
295
- // 3. Build component ID set
295
+ // 3. Build component ID set (including canonical group members for linked copies)
296
296
  const componentIds = new Set();
297
297
  components.commands.forEach(c => componentIds.add(c.id));
298
- components.events.forEach(e => componentIds.add(e.id));
299
- components.readModels.forEach(rm => componentIds.add(rm.id));
300
- components.screens.forEach(s => componentIds.add(s.id));
298
+ components.events.forEach(e => {
299
+ componentIds.add(e.id);
300
+ // If this is a linked copy, also add all elements in the same canonical group
301
+ if (e.canonicalId) {
302
+ for (const evt of model.events.values()) {
303
+ if (evt.canonicalId === e.canonicalId) {
304
+ componentIds.add(evt.id);
305
+ }
306
+ }
307
+ }
308
+ });
309
+ components.readModels.forEach(rm => {
310
+ componentIds.add(rm.id);
311
+ // If this is a linked copy, also add all elements in the same canonical group
312
+ if (rm.canonicalId) {
313
+ for (const r of model.readModels.values()) {
314
+ if (r.canonicalId === rm.canonicalId) {
315
+ componentIds.add(r.id);
316
+ }
317
+ }
318
+ }
319
+ });
320
+ components.screens.forEach(s => {
321
+ componentIds.add(s.id);
322
+ // If this is a linked copy, also add all elements in the same canonical group
323
+ if (s.canonicalId) {
324
+ for (const scr of model.screens.values()) {
325
+ if (scr.canonicalId === s.canonicalId) {
326
+ componentIds.add(scr.id);
327
+ }
328
+ }
329
+ }
330
+ });
301
331
  components.processors.forEach(p => componentIds.add(p.id));
302
332
  // 4. Determine slice type
303
333
  const sliceType = determineSliceType(components.processors.length > 0, components.commands.length > 0, components.events.length > 0, components.readModels.length > 0, components.screens.length > 0);
@@ -1,7 +1,7 @@
1
1
  import { escapeXml, escapeXmlText, outputJson } from '../../lib/format.js';
2
2
  import { findElementOrExit } from '../../lib/element-lookup.js';
3
3
  import { findChapterForSlice, getChapterHierarchy } from '../../lib/chapter-utils.js';
4
- import { getInboundFlows, getOutboundFlows, getFlowsForElement, } from '../../lib/flow-utils.js';
4
+ import { getInboundFlows, getOutboundFlows, getFlowsForElement, getSliceComponentIds, } from '../../lib/flow-utils.js';
5
5
  function formatFieldValues(values) {
6
6
  if (!values || Object.keys(values).length === 0)
7
7
  return '';
@@ -189,12 +189,8 @@ function formatSliceXml(model, slice) {
189
189
  const components = getSliceComponents(model, slice);
190
190
  const scenarios = [...model.scenarios.values()].filter(s => s.sliceId === slice.id);
191
191
  const chapter = findChapterForSlice(model, slice);
192
- const componentIds = new Set();
193
- components.commands.forEach(c => componentIds.add(c.id));
194
- components.events.forEach(e => componentIds.add(e.id));
195
- components.readModels.forEach(rm => componentIds.add(rm.id));
196
- components.screens.forEach(s => componentIds.add(s.id));
197
- components.processors.forEach(p => componentIds.add(p.id));
192
+ // Use shared function that handles canonical groups for linked copies
193
+ const componentIds = getSliceComponentIds(model, slice);
198
194
  const flows = [...model.flows.values()].filter(f => componentIds.has(f.sourceId) || componentIds.has(f.targetId));
199
195
  const internalFlows = flows.filter(f => componentIds.has(f.sourceId) && componentIds.has(f.targetId));
200
196
  // Get inbound and outbound flows for the slice
@@ -430,12 +426,8 @@ function formatSliceJson(model, slice) {
430
426
  const components = getSliceComponents(model, slice);
431
427
  const scenarios = [...model.scenarios.values()].filter(s => s.sliceId === slice.id);
432
428
  const chapter = findChapterForSlice(model, slice);
433
- const componentIds = new Set();
434
- components.commands.forEach(c => componentIds.add(c.id));
435
- components.events.forEach(e => componentIds.add(e.id));
436
- components.readModels.forEach(rm => componentIds.add(rm.id));
437
- components.screens.forEach(s => componentIds.add(s.id));
438
- components.processors.forEach(p => componentIds.add(p.id));
429
+ // Use shared function that handles canonical groups for linked copies
430
+ const componentIds = getSliceComponentIds(model, slice);
439
431
  const flows = [...model.flows.values()].filter(f => componentIds.has(f.sourceId) || componentIds.has(f.targetId));
440
432
  const internalFlows = flows.filter(f => componentIds.has(f.sourceId) && componentIds.has(f.targetId));
441
433
  // Get inbound and outbound flows for the slice
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "eventmodeler",
3
- "version": "0.3.1",
3
+ "version": "0.3.2",
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": {