eventmodeler 0.6.14 → 0.6.15

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.
Files changed (2) hide show
  1. package/dist/index.js +266 -45
  2. package/package.json +1 -1
package/dist/index.js CHANGED
@@ -2573,6 +2573,15 @@ function registerStatusCommands(program, conn) {
2573
2573
  }
2574
2574
  // ../packages/canvas-model/src/build.ts
2575
2575
  import * as Y2 from "yjs";
2576
+ function buildYMap(props) {
2577
+ const m = new Y2.Map;
2578
+ for (const [k, v] of Object.entries(props)) {
2579
+ if (v === undefined)
2580
+ continue;
2581
+ m.set(k, v);
2582
+ }
2583
+ return m;
2584
+ }
2576
2585
  function buildYArray(items) {
2577
2586
  const arr = new Y2.Array;
2578
2587
  if (items.length > 0)
@@ -3036,6 +3045,9 @@ function resolveSheet(doc, sheetId) {
3036
3045
  columnSlices
3037
3046
  };
3038
3047
  }
3048
+ function sliceOf(columnSlices, columnId) {
3049
+ return columnSlices[columnId] ?? columnId;
3050
+ }
3039
3051
  function ensureSheet(doc, sheetId) {
3040
3052
  doc.transact(() => {
3041
3053
  resolveSheet(doc, sheetId);
@@ -3053,6 +3065,23 @@ function readSheet(doc, sheetId) {
3053
3065
  columnSlices[c] = c;
3054
3066
  return { ...json, columns, columnSlices };
3055
3067
  }
3068
+ function sliceOrder(structure) {
3069
+ const cs = structure.columnSlices ?? {};
3070
+ const seen = new Set;
3071
+ const out = [];
3072
+ for (const colId of structure.columns) {
3073
+ const sid = sliceOf(cs, colId);
3074
+ if (!seen.has(sid)) {
3075
+ seen.add(sid);
3076
+ out.push(sid);
3077
+ }
3078
+ }
3079
+ return out;
3080
+ }
3081
+ function sliceColumns(structure, sliceId) {
3082
+ const cs = structure.columnSlices ?? {};
3083
+ return structure.columns.filter((c) => sliceOf(cs, c) === sliceId);
3084
+ }
3056
3085
  function clampIndex(at, length) {
3057
3086
  if (at === undefined || at > length)
3058
3087
  return length;
@@ -3072,6 +3101,25 @@ function addColumn(doc, sheetId, sliceId, at) {
3072
3101
  columnSlices.set(sliceId, sliceId);
3073
3102
  });
3074
3103
  }
3104
+ function addColumnToSlice(doc, sheetId, sliceId, columnId, atWithin) {
3105
+ doc.transact(() => {
3106
+ const { columns, columnSlices } = resolveSheet(doc, sheetId);
3107
+ const arr = columns.toArray();
3108
+ if (arr.includes(columnId))
3109
+ return;
3110
+ const slices = columnSlices.toJSON();
3111
+ const flatIdxs = arr.map((c, i) => [c, i]).filter(([c]) => sliceOf(slices, c) === sliceId).map(([, i]) => i);
3112
+ let flat;
3113
+ if (flatIdxs.length === 0) {
3114
+ flat = columns.length;
3115
+ } else {
3116
+ const within = atWithin === undefined ? flatIdxs.length : Math.max(0, Math.min(flatIdxs.length, atWithin));
3117
+ flat = within < flatIdxs.length ? flatIdxs[within] : flatIdxs[flatIdxs.length - 1] + 1;
3118
+ }
3119
+ columns.insert(flat, [columnId]);
3120
+ columnSlices.set(columnId, sliceId);
3121
+ });
3122
+ }
3075
3123
  function moveColumn(doc, sheetId, columnId, toIndex) {
3076
3124
  doc.transact(() => {
3077
3125
  const { columns } = resolveSheet(doc, sheetId);
@@ -3105,6 +3153,12 @@ function removeColumn(doc, sheetId, columnId) {
3105
3153
  }
3106
3154
  });
3107
3155
  }
3156
+ function setColumnSlice(doc, sheetId, columnId, sliceId) {
3157
+ doc.transact(() => {
3158
+ const { columnSlices } = resolveSheet(doc, sheetId);
3159
+ columnSlices.set(columnId, sliceId);
3160
+ });
3161
+ }
3108
3162
  function ensureColumnSlices(doc, sheetId) {
3109
3163
  doc.transact(() => {
3110
3164
  const { columns, columnSlices } = resolveSheet(doc, sheetId);
@@ -3228,6 +3282,62 @@ function setCellNote(doc, sheetId, sliceId, swimLaneId, text) {
3228
3282
  getCellNotesMap(doc, sheetId, true).set(key, trimmed);
3229
3283
  });
3230
3284
  }
3285
+ // ../packages/canvas-model/src/slice-span.ts
3286
+ var SLICES_SCOPE2 = "slices";
3287
+ var SHEET_FLOWS_SCOPE = "sheetFlows";
3288
+ function sliceIdFromHandle(handleId) {
3289
+ if (typeof handleId !== "string")
3290
+ return;
3291
+ const parts = handleId.split(":");
3292
+ if (parts[0] === "sf" && parts[1] === "slice" && parts.length >= 5)
3293
+ return parts.slice(4).join(":");
3294
+ return;
3295
+ }
3296
+ function pruneSheetFlowsForSlice(doc, sliceId) {
3297
+ const map = getScopeMap(doc, SHEET_FLOWS_SCOPE);
3298
+ for (const [id, f] of [...map.entries()]) {
3299
+ if (sliceIdFromHandle(f.get("sourceHandle")) === sliceId || sliceIdFromHandle(f.get("targetHandle")) === sliceId) {
3300
+ map.delete(id);
3301
+ }
3302
+ }
3303
+ }
3304
+ function resizeSliceSpan(doc, sheetId, sliceId, targetLast) {
3305
+ doc.transact(() => {
3306
+ const structure = readSheet(doc, sheetId);
3307
+ if (!structure)
3308
+ return;
3309
+ const cols = structure.columns;
3310
+ const owned = sliceColumns(structure, sliceId);
3311
+ if (owned.length === 0)
3312
+ return;
3313
+ const firstFlat = cols.indexOf(owned[0]);
3314
+ const currentLast = cols.indexOf(owned[owned.length - 1]);
3315
+ const target = Math.max(firstFlat, Math.min(targetLast, cols.length - 1));
3316
+ if (target === currentLast)
3317
+ return;
3318
+ const owner = (c) => structure.columnSlices?.[c] ?? c;
3319
+ const slices = getScopeMap(doc, SLICES_SCOPE2);
3320
+ const modelId = getEntry(doc, SLICES_SCOPE2, sliceId)?.modelId;
3321
+ const d = ELEMENT_DIMENSIONS.slice;
3322
+ const claimed = cols.slice(firstFlat, target + 1);
3323
+ const prevOwners = new Set(claimed.map(owner).filter((s) => s !== sliceId));
3324
+ for (const colId of claimed)
3325
+ setColumnSlice(doc, sheetId, colId, sliceId);
3326
+ for (const colId of cols.slice(target + 1, currentLast + 1)) {
3327
+ const newSliceId = crypto.randomUUID();
3328
+ const base = { sliceId: newSliceId, name: "Slice", x: 0, y: 0, width: d.width, height: d.height };
3329
+ slices.set(newSliceId, buildYMap(modelId ? { ...base, modelId } : base));
3330
+ setColumnSlice(doc, sheetId, colId, newSliceId);
3331
+ }
3332
+ const after = readSheet(doc, sheetId);
3333
+ for (const sid of prevOwners) {
3334
+ if (sliceColumns(after, sid).length === 0) {
3335
+ slices.delete(sid);
3336
+ pruneSheetFlowsForSlice(doc, sid);
3337
+ }
3338
+ }
3339
+ });
3340
+ }
3231
3341
  // ../packages/canvas-model/src/migrate.ts
3232
3342
  function migrateChaptersToSheets(doc) {
3233
3343
  const chapters = getScopeMap(doc, "chapters");
@@ -3261,10 +3371,10 @@ function migrateChaptersToSheets(doc) {
3261
3371
  }
3262
3372
  // ../packages/canvas-model/src/sheet-delete.ts
3263
3373
  var SHEETS_SCOPE = "sheets";
3264
- var SLICES_SCOPE2 = "slices";
3374
+ var SLICES_SCOPE3 = "slices";
3265
3375
  var SWIM_LANES_SCOPE = "swimLanes";
3266
3376
  var SCENARIOS_SCOPE2 = "scenarios";
3267
- var SHEET_FLOWS_SCOPE = "sheetFlows";
3377
+ var SHEET_FLOWS_SCOPE2 = "sheetFlows";
3268
3378
  function deleteSheet(doc, sheetId) {
3269
3379
  doc.transact(() => {
3270
3380
  const sheet = getGridMap(doc).get(sheetId);
@@ -3286,7 +3396,7 @@ function deleteSheet(doc, sheetId) {
3286
3396
  }
3287
3397
  }
3288
3398
  for (const id of sliceIds)
3289
- getScopeMap(doc, SLICES_SCOPE2).delete(id);
3399
+ getScopeMap(doc, SLICES_SCOPE3).delete(id);
3290
3400
  for (const id of laneIds)
3291
3401
  getScopeMap(doc, SWIM_LANES_SCOPE).delete(id);
3292
3402
  const scenarios = getScopeMap(doc, SCENARIOS_SCOPE2);
@@ -3297,7 +3407,7 @@ function deleteSheet(doc, sheetId) {
3297
3407
  }
3298
3408
  }
3299
3409
  cascadeStickyRemoval(doc, removedStickies);
3300
- const sheetFlows = getScopeMap(doc, SHEET_FLOWS_SCOPE);
3410
+ const sheetFlows = getScopeMap(doc, SHEET_FLOWS_SCOPE2);
3301
3411
  for (const [id, f] of sheetFlows.entries()) {
3302
3412
  if (f.get("sourceSheetId") === sheetId || f.get("targetSheetId") === sheetId) {
3303
3413
  sheetFlows.delete(id);
@@ -3518,7 +3628,7 @@ function computeSheetLayout(doc, sheetId, override) {
3518
3628
  // ../packages/canvas-model/src/reflow.ts
3519
3629
  var REFLOW_ORIGIN = Symbol("sheet-reflow");
3520
3630
  var SHEETS_SCOPE2 = "sheets";
3521
- var SLICES_SCOPE3 = "slices";
3631
+ var SLICES_SCOPE4 = "slices";
3522
3632
  var SWIM_LANES_SCOPE2 = "swimLanes";
3523
3633
  var STICKY_SCOPES = [
3524
3634
  "commands",
@@ -3553,7 +3663,7 @@ function reflowAllSheets(doc, origin = REFLOW_ORIGIN) {
3553
3663
  ensureSheet(doc, sheetId);
3554
3664
  ensureColumnSlices(doc, sheetId);
3555
3665
  }
3556
- const slices = getScopeMap(doc, SLICES_SCOPE3);
3666
+ const slices = getScopeMap(doc, SLICES_SCOPE4);
3557
3667
  const lanes = getScopeMap(doc, SWIM_LANES_SCOPE2);
3558
3668
  const stickyMaps = STICKY_SCOPES.map((s) => getScopeMap(doc, s));
3559
3669
  for (const sheetId of getGridMap(doc).keys()) {
@@ -5033,19 +5143,30 @@ function resolve4(doc, sheetId) {
5033
5143
  return;
5034
5144
  const { columns, rows, cells } = structure;
5035
5145
  const notes = readCellNotes(doc, sheetId);
5036
- const cols = columns.map((sliceId, i) => ({
5037
- label: colLabel(i),
5038
- name: entityName(doc, "slices", sliceId),
5039
- note: Boolean(getEntry(doc, "slices", sliceId)?.note)
5040
- }));
5146
+ const cols = columns.map((_, i) => ({ label: colLabel(i) }));
5147
+ const slices = sliceOrder(structure).map((sliceId) => {
5148
+ const cids = sliceColumns(structure, sliceId);
5149
+ const firstCol = columns.indexOf(cids[0]);
5150
+ const lastCol = columns.indexOf(cids[cids.length - 1]);
5151
+ const e = getEntry(doc, "slices", sliceId);
5152
+ return {
5153
+ label: firstCol === lastCol ? colLabel(firstCol) : `${colLabel(firstCol)}–${colLabel(lastCol)}`,
5154
+ name: e?.name?.trim() || "(unnamed)",
5155
+ status: e?.status ?? "",
5156
+ note: Boolean(e?.note),
5157
+ firstCol,
5158
+ lastCol
5159
+ };
5160
+ });
5041
5161
  const lanes2 = rows.map((swimLaneId, i) => {
5042
5162
  const e = getEntry(doc, "swimLanes", swimLaneId);
5043
5163
  return { label: String(i + 1), name: e?.name?.trim() || "(unnamed)", kind: e?.laneKind ?? "?", note: Boolean(e?.note) };
5044
5164
  });
5045
- const elems = columns.map((sliceId) => rows.map((swimLaneId) => (cells[cellKey(sliceId, swimLaneId)] ?? []).map((r) => elementText(doc, r))));
5046
- const cellNote = columns.map((sliceId) => rows.map((swimLaneId) => Boolean(notes[cellKey(sliceId, swimLaneId)])));
5165
+ const elems = columns.map((columnId) => rows.map((swimLaneId) => (cells[cellKey(columnId, swimLaneId)] ?? []).map((r) => elementText(doc, r))));
5166
+ const cellNote = columns.map((columnId) => rows.map((swimLaneId) => Boolean(notes[cellKey(columnId, swimLaneId)])));
5047
5167
  return {
5048
5168
  title: entityName(doc, "sheets", sheetId),
5169
+ slices,
5049
5170
  columns: cols,
5050
5171
  rows: lanes2,
5051
5172
  elems,
@@ -5058,7 +5179,12 @@ function rowLabel(r) {
5058
5179
  return r.note ? `${base} ${NOTE}` : base;
5059
5180
  }
5060
5181
  function header(r) {
5061
- return `Sheet "${r.title}" (${r.columns.length} slices × ${r.rows.length} lanes)`;
5182
+ return `Sheet "${r.title}" (${r.slices.length} slices · ${r.columns.length} columns × ${r.rows.length} lanes)`;
5183
+ }
5184
+ function bandLabel(s) {
5185
+ const status = s.status && s.status !== "draft" ? ` · ${s.status}` : "";
5186
+ const note = s.note ? ` ${NOTE}` : "";
5187
+ return `⟦ ${s.label} ${s.name}${status}${note} ⟧`;
5062
5188
  }
5063
5189
  function cellLines(elems, width, hasNote) {
5064
5190
  const lines = elems.length === 0 ? [EMPTY] : (() => {
@@ -5069,22 +5195,27 @@ function cellLines(elems, width, hasNote) {
5069
5195
  lines[lines.length - 1] = `${lines[lines.length - 1]} ${NOTE}`;
5070
5196
  return lines;
5071
5197
  }
5072
- function colHead(c) {
5073
- return c.note ? `${c.label} ${c.name} ${NOTE}` : `${c.label} ${c.name}`;
5198
+ function spanWidth(s, colWidths) {
5199
+ let w = 2 * (s.lastCol - s.firstCol);
5200
+ for (let i = s.firstCol;i <= s.lastCol; i += 1)
5201
+ w += colWidths[i];
5202
+ return w;
5074
5203
  }
5075
5204
  function renderTable(r, opts) {
5076
5205
  const gutter = Math.max(...r.rows.map(rowLabel).map((s) => s.length), 0);
5077
5206
  const colWidths = r.columns.map((c, ci) => {
5078
- const widest = Math.max(colHead(c).length, ...r.elems[ci].map((cell, ri) => Math.max(0, ...cell.map((e) => e.length)) + (r.cellNote[ci][ri] ? 2 : 0)), EMPTY.length);
5207
+ const widest = Math.max(c.label.length, ...r.elems[ci].map((cell, ri) => Math.max(0, ...cell.map((e) => e.length)) + (r.cellNote[ci][ri] ? 2 : 0)), EMPTY.length);
5079
5208
  return Math.min(widest, opts.maxColWidth + 2);
5080
5209
  });
5210
+ for (const s of r.slices) {
5211
+ const deficit = bandLabel(s).length - spanWidth(s, colWidths);
5212
+ if (deficit > 0)
5213
+ colWidths[s.lastCol] += deficit;
5214
+ }
5081
5215
  const totalWidth = gutter + colWidths.reduce((a, w) => a + w + 2, 0);
5082
5216
  const lines = [header(r), LEGEND, ""];
5083
- const headCells = r.columns.map((c, ci) => wrap(colHead(c), colWidths[ci]));
5084
- const headHeight = Math.max(...headCells.map((h) => h.length));
5085
- for (let i = 0;i < headHeight; i += 1) {
5086
- lines.push(pad("", gutter) + " " + r.columns.map((_, ci) => pad(headCells[ci][i] ?? "", colWidths[ci])).join(" "));
5087
- }
5217
+ lines.push(pad("", gutter) + " " + r.slices.map((s) => pad(bandLabel(s), spanWidth(s, colWidths))).join(" "));
5218
+ lines.push(pad("", gutter) + " " + r.columns.map((c, ci) => pad(c.label, colWidths[ci])).join(" "));
5088
5219
  lines.push("─".repeat(totalWidth));
5089
5220
  r.rows.forEach((row, ri) => {
5090
5221
  const cellsLines = r.columns.map((_, ci) => cellLines(r.elems[ci][ri], colWidths[ci], r.cellNote[ci][ri]));
@@ -5102,24 +5233,28 @@ function renderTable(r, opts) {
5102
5233
  }
5103
5234
  function renderListing(r) {
5104
5235
  const lines = [header(r), LEGEND, ""];
5105
- r.columns.forEach((c, ci) => {
5106
- lines.push(`${c.label} "${c.name}"${c.note ? ` ${NOTE}` : ""}`);
5236
+ r.slices.forEach((s) => {
5237
+ const status = s.status && s.status !== "draft" ? ` · ${s.status}` : "";
5238
+ lines.push(`⟦ ${s.label} ⟧ "${s.name}"${status}${s.note ? ` ${NOTE}` : ""}`);
5107
5239
  let any = false;
5108
- r.rows.forEach((row, ri) => {
5109
- const elems = r.elems[ci][ri];
5110
- const noted = r.cellNote[ci][ri];
5111
- if (elems.length === 0 && !noted)
5112
- return;
5113
- any = true;
5114
- const addr = `${c.label}${row.label}`;
5115
- const mark = noted ? ` ${NOTE}` : "";
5116
- if (elems.length <= 1) {
5117
- lines.push(` ${addr} ${elems[0] ?? EMPTY} [${row.kind}]${mark}`);
5118
- } else {
5119
- lines.push(` ${addr} [${row.kind}]${mark}`);
5120
- elems.forEach((e, i) => lines.push(` ${addr}.${i + 1} ${e}`));
5121
- }
5122
- });
5240
+ for (let ci = s.firstCol;ci <= s.lastCol; ci += 1) {
5241
+ const col = r.columns[ci];
5242
+ r.rows.forEach((row, ri) => {
5243
+ const elems = r.elems[ci][ri];
5244
+ const noted = r.cellNote[ci][ri];
5245
+ if (elems.length === 0 && !noted)
5246
+ return;
5247
+ any = true;
5248
+ const addr = `${col.label}${row.label}`;
5249
+ const mark = noted ? ` ${NOTE}` : "";
5250
+ if (elems.length <= 1) {
5251
+ lines.push(` ${addr} ${elems[0] ?? EMPTY} [${row.kind}]${mark}`);
5252
+ } else {
5253
+ lines.push(` ${addr} [${row.kind}]${mark}`);
5254
+ elems.forEach((e, i) => lines.push(` ${addr}.${i + 1} ${e}`));
5255
+ }
5256
+ });
5257
+ }
5123
5258
  if (!any)
5124
5259
  lines.push(" (empty)");
5125
5260
  lines.push("");
@@ -5217,6 +5352,36 @@ function resolveRow(doc, s, ref) {
5217
5352
  throw new SheetAddressError(`Ambiguous row name "${ref}" — use its number instead.`);
5218
5353
  throw new SheetAddressError(numeric ? `No row "${ref}" — not a lane name, and row ${ref} is out of range (sheet has ${rows.length} rows).` : `No row named "${ref}".`);
5219
5354
  }
5355
+ function resolveSlice(doc, s, ref) {
5356
+ const { columns, columnSlices } = s.structure;
5357
+ const order = sliceOrder(s.structure);
5358
+ const make = (sliceId) => {
5359
+ const columnIds = sliceColumns(s.structure, sliceId);
5360
+ const firstIndex = columns.indexOf(columnIds[0]);
5361
+ const lastIndex = columns.indexOf(columnIds[columnIds.length - 1]);
5362
+ return {
5363
+ sliceId,
5364
+ columnIds,
5365
+ firstIndex,
5366
+ lastIndex,
5367
+ label: firstIndex === lastIndex ? labelOf(firstIndex) : `${labelOf(firstIndex)}–${labelOf(lastIndex)}`
5368
+ };
5369
+ };
5370
+ const lower = ref.toLowerCase();
5371
+ const byName = order.filter((sid) => name(doc, "slices", sid).toLowerCase() === lower);
5372
+ if (byName.length === 1)
5373
+ return make(byName[0]);
5374
+ if (byName.length > 1)
5375
+ throw new SheetAddressError(`Ambiguous slice name "${ref}" — use its leading column letter instead.`);
5376
+ const byLabel = colIndexFromLabel(ref);
5377
+ if (byLabel >= 0 && byLabel < columns.length) {
5378
+ const columnId = columns[byLabel];
5379
+ return make((columnSlices ?? {})[columnId] ?? columnId);
5380
+ }
5381
+ if (order.includes(ref))
5382
+ return make(ref);
5383
+ throw new SheetAddressError(`No slice "${ref}" — not a slice name, a leading column letter, or a sliceId.`);
5384
+ }
5220
5385
  function labelOf(index) {
5221
5386
  let n = index;
5222
5387
  let str = "";
@@ -5375,18 +5540,58 @@ function rejectLane(doc, swimLaneId, rowIndex, kind, type) {
5375
5540
  const allowed = (LANE_ELEMENT_SCOPES[kind] ?? []).map((sc) => TYPE_LABEL[sc] ?? sc).join(", ");
5376
5541
  throw new SheetAddressError(`Lane "${nameOf(doc, "swimLanes", swimLaneId)}" (row ${rowIndex + 1}, kind=${kind}) accepts ${allowed || "(nothing)"}, not ${type}.`);
5377
5542
  }
5378
- function insertColumn(doc, s, modelId, name2, at) {
5543
+ function insertColumn(doc, s, modelId, name2, at, cols = 1) {
5379
5544
  const id = crypto.randomUUID();
5380
5545
  const d = ELEMENT_DIMENSIONS.slice;
5381
5546
  const v = validateEntry("slices", { name: name2, x: 0, y: 0, width: d.width, height: d.height });
5382
5547
  if (!v.ok)
5383
5548
  throw new SheetAddressError(`Invalid slice: ${v.issues.join("; ")}`);
5549
+ const span = Math.max(1, cols);
5384
5550
  doc.transact(() => {
5385
5551
  getScopeMap(doc, "slices").set(id, deepToY({ ...v.data, sliceId: id, modelId }));
5386
5552
  addColumn(doc, s.sheetId, id, at);
5553
+ for (let i = 1;i < span; i += 1)
5554
+ addColumnToSlice(doc, s.sheetId, id, crypto.randomUUID());
5387
5555
  });
5388
5556
  const idx = readSheet(doc, s.sheetId).columns.indexOf(id);
5389
- return `${colLabel2(idx)} "${name2}" ${id}`;
5557
+ const note = span > 1 ? ` (${span} cols)` : "";
5558
+ return `${colLabel2(idx)} "${name2}"${note} ${id}`;
5559
+ }
5560
+ function spanSlice(doc, s, ref, toCol) {
5561
+ const slice = resolveSlice(doc, s, ref);
5562
+ const col = resolveColumn(doc, s, toCol);
5563
+ const sliceName = getEntry(doc, "slices", slice.sliceId)?.name ?? "(unnamed)";
5564
+ doc.transact(() => resizeSliceSpan(doc, s.sheetId, slice.sliceId, col.index));
5565
+ const after = resolveSlice(doc, { sheetId: s.sheetId, structure: readSheet(doc, s.sheetId) }, slice.sliceId);
5566
+ return `slice "${sliceName}" now spans ${after.label}`;
5567
+ }
5568
+ function splitSlice(doc, s, modelId, colRef) {
5569
+ const col = resolveColumn(doc, s, colRef);
5570
+ const columnId = col.sliceId;
5571
+ const owningSlice = (s.structure.columnSlices ?? {})[columnId] ?? columnId;
5572
+ const cols = sliceColumns(s.structure, owningSlice);
5573
+ const pos = cols.indexOf(columnId);
5574
+ if (pos <= 0)
5575
+ throw new SheetAddressError(`Column ${col.label} already begins its slice — nothing to split.`);
5576
+ const newId = crypto.randomUUID();
5577
+ const d = ELEMENT_DIMENSIONS.slice;
5578
+ doc.transact(() => {
5579
+ getScopeMap(doc, "slices").set(newId, deepToY({ sliceId: newId, modelId, name: "Slice", x: 0, y: 0, width: d.width, height: d.height }));
5580
+ for (const c of cols.slice(pos))
5581
+ setColumnSlice(doc, s.sheetId, c, newId);
5582
+ });
5583
+ return `split at ${col.label} — a new slice now covers ${col.label} onward ${newId}`;
5584
+ }
5585
+ function renameSlice(doc, s, ref, newName) {
5586
+ const slice = resolveSlice(doc, s, ref);
5587
+ if (!newName.trim())
5588
+ throw new SheetAddressError("A slice name cannot be empty.");
5589
+ doc.transact(() => {
5590
+ const e = getScopeMap(doc, "slices").get(slice.sliceId);
5591
+ if (e)
5592
+ e.set("name", newName.trim());
5593
+ });
5594
+ return `renamed slice ${slice.label} → "${newName.trim()}"`;
5390
5595
  }
5391
5596
  function insertLane(doc, s, modelId, kind, name2, at) {
5392
5597
  const id = crypto.randomUUID();
@@ -5860,9 +6065,21 @@ function buildFromSpec(doc, modelId, nameArg, spec) {
5860
6065
  }
5861
6066
  function buildSheetJson(doc, s) {
5862
6067
  const { columns, rows, cells } = s.structure;
5863
- const columnViews = columns.map((sliceId, i) => {
6068
+ const ownerOf = (columnId) => (s.structure.columnSlices ?? {})[columnId] ?? columnId;
6069
+ const columnViews = columns.map((columnId, i) => {
6070
+ const e = getEntry(doc, "slices", ownerOf(columnId));
6071
+ return { label: colLabel2(i), columnId, name: e?.name ?? "(unnamed)", status: e?.status ?? null, note: e?.note ?? null };
6072
+ });
6073
+ const slices = sliceOrder(s.structure).map((sliceId) => {
6074
+ const cids = sliceColumns(s.structure, sliceId);
5864
6075
  const e = getEntry(doc, "slices", sliceId);
5865
- return { label: colLabel2(i), name: e?.name ?? "(unnamed)", sliceId, status: e?.status ?? null, note: e?.note ?? null };
6076
+ return {
6077
+ sliceId,
6078
+ name: e?.name ?? "(unnamed)",
6079
+ status: e?.status ?? null,
6080
+ note: e?.note ?? null,
6081
+ cols: cids.map((c) => colLabel2(columns.indexOf(c)))
6082
+ };
5866
6083
  });
5867
6084
  const rowViews = rows.map((swimLaneId, i) => {
5868
6085
  const e = getEntry(doc, "swimLanes", swimLaneId);
@@ -5891,7 +6108,7 @@ function buildSheetJson(doc, s) {
5891
6108
  }));
5892
6109
  });
5893
6110
  });
5894
- return { sheet: nameOf(doc, "sheets", s.sheetId), sheetId: s.sheetId, columns: columnViews, rows: rowViews, cells: cellViews, cellNotes: cellNotesByAddr };
6111
+ return { sheet: nameOf(doc, "sheets", s.sheetId), sheetId: s.sheetId, slices, columns: columnViews, rows: rowViews, cells: cellViews, cellNotes: cellNotesByAddr };
5895
6112
  }
5896
6113
  function buildCellView(doc, s, cellArg) {
5897
6114
  const { ordinal } = parseCellAddress(cellArg);
@@ -6032,7 +6249,7 @@ This cannot be undone. Re-run with --yes to confirm.`;
6032
6249
  }
6033
6250
  });
6034
6251
  const insert = sheet.command("insert").description("Insert a slice (column), a lane (row), or an element into a cell");
6035
- insert.command("slice <name>").description("Insert a new slice (column)").option("--at <n>", "Position (1-based); appends if omitted").option("--sheet <ref>", "Which sheet (name or sheetId) when the model has several").option("--model <id>", "Target model id").action((name2, opts) => runWrite(opts, (doc, s, modelId) => insertColumn(doc, s, modelId, name2, atIndex(opts.at))));
6252
+ insert.command("slice <name>").description("Insert a new slice; --cols N makes it span N contiguous columns").option("--at <n>", "Position (1-based); appends if omitted").option("--cols <n>", "How many columns the slice spans (default 1)").option("--sheet <ref>", "Which sheet (name or sheetId) when the model has several").option("--model <id>", "Target model id").action((name2, opts) => runWrite(opts, (doc, s, modelId) => insertColumn(doc, s, modelId, name2, atIndex(opts.at), opts.cols ? Math.max(1, parseInt(opts.cols, 10) || 1) : 1)));
6036
6253
  for (const kind of LANE_KINDS) {
6037
6254
  insert.command(`${kind} <name>`).description(`Insert a ${kind} lane (row)`).option("--at <n>", "Position (1-based); appends if omitted").option("--sheet <ref>", "Which sheet (name or sheetId) when the model has several").option("--model <id>", "Target model id").action((name2, opts) => runWrite(opts, (doc, s, modelId) => insertLane(doc, s, modelId, kind, name2, atIndex(opts.at))));
6038
6255
  }
@@ -6041,6 +6258,10 @@ This cannot be undone. Re-run with --yes to confirm.`;
6041
6258
  }
6042
6259
  sheet.command("move <element>").description("Move an element to another cell, e.g. `move B2.1 --to C2` (keeps its id + flows)").requiredOption("--to <cell>", "Destination cell (e.g. C2)").option("--sheet <ref>", "Which sheet when the model has several").option("--model <id>", "Target model id").action((element, opts) => runWrite(opts, (doc, s) => moveElement(doc, s, element, opts.to)));
6043
6260
  sheet.command("reorder <ref>").description("Reorder a slice (column letter) or lane (row number), e.g. `reorder A --to 3`").requiredOption("--to <n>", "New 1-based position").option("--sheet <ref>", "Which sheet when the model has several").option("--model <id>", "Target model id").action((ref, opts) => runWrite(opts, (doc, s) => reorderAxis(doc, s, ref, parseInt(opts.to, 10))));
6261
+ const slice = sheet.command("slice").description("Slice (work-ticket) ops: span across columns, split, rename");
6262
+ slice.command("span <slice>").description("Set a slice to span up to a column, e.g. `slice span A --to C` (grows or shrinks)").requiredOption("--to <col>", "The column the slice should end at (letter or name)").option("--sheet <ref>", "Which sheet when the model has several").option("--model <id>", "Target model id").action((sliceRef, opts) => runWrite(opts, (doc, s) => spanSlice(doc, s, sliceRef, opts.to)));
6263
+ slice.command("split <col>").description("Split a slice so <col> begins a new slice (the columns from <col> onward break off)").option("--sheet <ref>", "Which sheet when the model has several").option("--model <id>", "Target model id").action((col, opts) => runWrite(opts, (doc, s, modelId) => splitSlice(doc, s, modelId, col)));
6264
+ slice.command("rename <slice> <name>").description("Rename a slice (by name, leading column letter, or id)").option("--sheet <ref>", "Which sheet when the model has several").option("--model <id>", "Target model id").action((sliceRef, name2, opts) => runWrite(opts, (doc, s) => renameSlice(doc, s, sliceRef, name2)));
6044
6265
  sheet.command("rm <target>").description("Remove an element (B2.1), a column (A), or a lane (2) — cascades to flows/scenarios").option("--sheet <ref>", "Which sheet when the model has several").option("--model <id>", "Target model id").action((target, opts) => runWrite(opts, (doc, s) => removeTarget(doc, s, target)));
6045
6266
  sheet.command("update <address> <json>").description(`Replace an element's shape in place (e.g. \`update A2.1 '{"name":"PlaceOrderV2","fields":[…]}'\`)`).option("--sheet <ref>", "Which sheet when the model has several").option("--model <id>", "Target model id").action((address, json, opts) => runWrite(opts, (doc, s, modelId) => updateElement(doc, s, modelId, address, json)));
6046
6267
  sheet.command("flow <from> <to>").description("Connect two elements, e.g. `flow A2.1 A3.1` (flow type inferred from the element kinds)").option("--type <flowType>", "Force a flow type (otherwise inferred)").option("--sheet <ref>", "Which sheet when the model has several").option("--model <id>", "Target model id").action((from, to, opts) => runWrite(opts, (doc, s, modelId) => flowBetween(doc, s, modelId, from, to, opts.type)));
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "eventmodeler",
3
- "version": "0.6.14",
3
+ "version": "0.6.15",
4
4
  "description": "CLI tool for event modeling - explore, design, and generate code from your event models",
5
5
  "type": "module",
6
6
  "repository": {