eventmodeler 0.5.0 → 0.6.0

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 (204) hide show
  1. package/dist/api/client-config.js +10 -0
  2. package/dist/api/generated/client/client.gen.js +235 -0
  3. package/dist/api/generated/client/index.js +6 -0
  4. package/dist/api/generated/client/types.gen.js +2 -0
  5. package/dist/api/generated/client/utils.gen.js +228 -0
  6. package/dist/api/generated/client.gen.js +4 -0
  7. package/dist/api/generated/core/auth.gen.js +14 -0
  8. package/dist/api/generated/core/bodySerializer.gen.js +57 -0
  9. package/dist/api/generated/core/params.gen.js +100 -0
  10. package/dist/api/generated/core/pathSerializer.gen.js +106 -0
  11. package/dist/api/generated/core/queryKeySerializer.gen.js +92 -0
  12. package/dist/api/generated/core/serverSentEvents.gen.js +133 -0
  13. package/dist/api/generated/core/types.gen.js +2 -0
  14. package/dist/api/generated/core/utils.gen.js +87 -0
  15. package/dist/api/generated/index.js +2 -0
  16. package/dist/api/generated/sdk.gen.js +4222 -0
  17. package/dist/api/generated/types.gen.js +2 -0
  18. package/dist/api/generated/zod.gen.js +7217 -0
  19. package/dist/commands/add.js +315 -0
  20. package/dist/commands/auth.js +14 -0
  21. package/dist/commands/create.js +192 -0
  22. package/dist/commands/design.js +108 -0
  23. package/dist/commands/guide.js +15 -0
  24. package/dist/commands/init.js +21 -0
  25. package/dist/commands/list-schemas.js +177 -0
  26. package/dist/commands/list.js +39 -0
  27. package/dist/commands/loop.js +101 -0
  28. package/dist/commands/map.js +40 -0
  29. package/dist/commands/mark.js +27 -0
  30. package/dist/commands/move.js +35 -0
  31. package/dist/commands/remove.js +170 -0
  32. package/dist/commands/rename.js +53 -0
  33. package/dist/commands/resize.js +30 -0
  34. package/dist/commands/search.js +14 -0
  35. package/dist/commands/set.js +199 -0
  36. package/dist/commands/show-schemas.js +259 -0
  37. package/dist/commands/show.js +56 -0
  38. package/dist/commands/summary.js +13 -0
  39. package/dist/commands/update.js +240 -0
  40. package/dist/index.js +46 -2379
  41. package/dist/lib/auth.js +1 -1
  42. package/dist/lib/config.js +0 -15
  43. package/dist/lib/excalidraw-schema.js +66 -0
  44. package/dist/lib/globals.js +8 -0
  45. package/dist/lib/model.js +11 -0
  46. package/dist/lib/project-config.js +20 -0
  47. package/dist/lib/resolve.js +59 -0
  48. package/dist/lib/scenario.js +15 -0
  49. package/dist/slices/add-scenario/index.js +2 -206
  50. package/dist/slices/guide/guides/codegen.js +1 -1
  51. package/dist/slices/guide/guides/connect-slices.js +38 -38
  52. package/dist/slices/guide/guides/create-slices.js +110 -140
  53. package/dist/slices/guide/guides/explore.js +37 -50
  54. package/dist/slices/guide/guides/information-flow.js +70 -84
  55. package/dist/slices/guide/guides/scenarios.js +82 -137
  56. package/dist/slices/guide/index.js +6 -6
  57. package/dist/slices/help/index.js +96 -0
  58. package/dist/slices/help/topics/build-codegen.js +109 -0
  59. package/dist/slices/help/topics/build-slice.js +147 -0
  60. package/dist/slices/help/topics/check-completeness.js +57 -0
  61. package/dist/slices/help/topics/connect-slices.js +99 -0
  62. package/dist/slices/help/topics/explore-model.js +112 -0
  63. package/dist/slices/help/topics/json-reference.js +188 -0
  64. package/dist/slices/help/topics/linked-copies.js +89 -0
  65. package/dist/slices/help/topics/manipulate-canvas.js +150 -0
  66. package/dist/slices/help/topics/write-scenarios.js +162 -0
  67. package/dist/slices/init/index.js +10 -4
  68. package/dist/slices/init/loop.js +60 -0
  69. package/dist/slices/login/index.js +2 -2
  70. package/dist/slices/logout/index.js +2 -2
  71. package/dist/slices/whoami/index.js +11 -36
  72. package/package.json +8 -3
  73. package/dist/api/index.d.ts +0 -285
  74. package/dist/api/index.js +0 -323
  75. package/dist/cloud/slices/index.d.ts +0 -276
  76. package/dist/cloud/slices/index.js +0 -406
  77. package/dist/eventmodeler.js +0 -5646
  78. package/dist/formatters.d.ts +0 -17
  79. package/dist/formatters.js +0 -482
  80. package/dist/index.d.ts +0 -2
  81. package/dist/lib/auth.d.ts +0 -24
  82. package/dist/lib/backend.d.ts +0 -43
  83. package/dist/lib/backend.js +0 -73
  84. package/dist/lib/chapter-utils.d.ts +0 -13
  85. package/dist/lib/chapter-utils.js +0 -71
  86. package/dist/lib/cloud-client.d.ts +0 -69
  87. package/dist/lib/cloud-client.js +0 -364
  88. package/dist/lib/config.d.ts +0 -30
  89. package/dist/lib/diff/merge-rules.d.ts +0 -45
  90. package/dist/lib/diff/merge-rules.js +0 -210
  91. package/dist/lib/diff/model-differ.d.ts +0 -8
  92. package/dist/lib/diff/model-differ.js +0 -568
  93. package/dist/lib/diff/three-way-merge.d.ts +0 -7
  94. package/dist/lib/diff/three-way-merge.js +0 -390
  95. package/dist/lib/diff/types.d.ts +0 -75
  96. package/dist/lib/diff/types.js +0 -1
  97. package/dist/lib/element-lookup.d.ts +0 -58
  98. package/dist/lib/element-lookup.js +0 -126
  99. package/dist/lib/file-loader.d.ts +0 -8
  100. package/dist/lib/file-loader.js +0 -108
  101. package/dist/lib/flow-utils.d.ts +0 -53
  102. package/dist/lib/flow-utils.js +0 -348
  103. package/dist/lib/format.d.ts +0 -10
  104. package/dist/lib/format.js +0 -23
  105. package/dist/lib/project-config.d.ts +0 -27
  106. package/dist/lib/slice-utils.d.ts +0 -59
  107. package/dist/lib/slice-utils.js +0 -140
  108. package/dist/local/slices/index.d.ts +0 -11
  109. package/dist/local/slices/index.js +0 -13
  110. package/dist/projection.d.ts +0 -3
  111. package/dist/projection.js +0 -828
  112. package/dist/slices/add-field/index.d.ts +0 -8
  113. package/dist/slices/add-field/index.js +0 -211
  114. package/dist/slices/add-scenario/index.d.ts +0 -27
  115. package/dist/slices/codegen-chapter-events/index.d.ts +0 -2
  116. package/dist/slices/codegen-chapter-events/index.js +0 -145
  117. package/dist/slices/codegen-slice/index.d.ts +0 -2
  118. package/dist/slices/codegen-slice/index.js +0 -448
  119. package/dist/slices/create-automation-slice/index.d.ts +0 -2
  120. package/dist/slices/create-automation-slice/index.js +0 -304
  121. package/dist/slices/create-flow/index.d.ts +0 -2
  122. package/dist/slices/create-flow/index.js +0 -183
  123. package/dist/slices/create-state-change-slice/index.d.ts +0 -2
  124. package/dist/slices/create-state-change-slice/index.js +0 -263
  125. package/dist/slices/create-state-view-slice/index.d.ts +0 -2
  126. package/dist/slices/create-state-view-slice/index.js +0 -128
  127. package/dist/slices/diff/index.d.ts +0 -11
  128. package/dist/slices/diff/index.js +0 -293
  129. package/dist/slices/export-eventmodel-to-json/index.d.ts +0 -2
  130. package/dist/slices/export-eventmodel-to-json/index.js +0 -355
  131. package/dist/slices/git/index.d.ts +0 -2
  132. package/dist/slices/git/index.js +0 -125
  133. package/dist/slices/guide/guides/codegen.d.ts +0 -5
  134. package/dist/slices/guide/guides/connect-slices.d.ts +0 -5
  135. package/dist/slices/guide/guides/create-slices.d.ts +0 -5
  136. package/dist/slices/guide/guides/explore.d.ts +0 -5
  137. package/dist/slices/guide/guides/information-flow.d.ts +0 -5
  138. package/dist/slices/guide/guides/scenarios.d.ts +0 -5
  139. package/dist/slices/guide/index.d.ts +0 -1
  140. package/dist/slices/import/index.d.ts +0 -8
  141. package/dist/slices/import/index.js +0 -63
  142. package/dist/slices/init/index.d.ts +0 -5
  143. package/dist/slices/list-chapters/index.d.ts +0 -3
  144. package/dist/slices/list-chapters/index.js +0 -21
  145. package/dist/slices/list-commands/index.d.ts +0 -3
  146. package/dist/slices/list-commands/index.js +0 -20
  147. package/dist/slices/list-events/index.d.ts +0 -3
  148. package/dist/slices/list-events/index.js +0 -98
  149. package/dist/slices/list-processors/index.d.ts +0 -3
  150. package/dist/slices/list-processors/index.js +0 -20
  151. package/dist/slices/list-readmodels/index.d.ts +0 -3
  152. package/dist/slices/list-readmodels/index.js +0 -21
  153. package/dist/slices/list-scenarios/index.d.ts +0 -3
  154. package/dist/slices/list-scenarios/index.js +0 -35
  155. package/dist/slices/list-screens/index.d.ts +0 -3
  156. package/dist/slices/list-screens/index.js +0 -47
  157. package/dist/slices/list-slices/index.d.ts +0 -3
  158. package/dist/slices/list-slices/index.js +0 -35
  159. package/dist/slices/login/index.d.ts +0 -1
  160. package/dist/slices/logout/index.d.ts +0 -1
  161. package/dist/slices/map-fields/index.d.ts +0 -2
  162. package/dist/slices/map-fields/index.js +0 -269
  163. package/dist/slices/mark-slice-status/index.d.ts +0 -2
  164. package/dist/slices/mark-slice-status/index.js +0 -31
  165. package/dist/slices/merge/index.d.ts +0 -19
  166. package/dist/slices/merge/index.js +0 -147
  167. package/dist/slices/open-app/index.d.ts +0 -1
  168. package/dist/slices/remove-field/index.d.ts +0 -8
  169. package/dist/slices/remove-field/index.js +0 -167
  170. package/dist/slices/remove-scenario/index.d.ts +0 -2
  171. package/dist/slices/remove-scenario/index.js +0 -77
  172. package/dist/slices/search/index.d.ts +0 -3
  173. package/dist/slices/search/index.js +0 -302
  174. package/dist/slices/show-actor/index.d.ts +0 -4
  175. package/dist/slices/show-actor/index.js +0 -115
  176. package/dist/slices/show-aggregate/index.d.ts +0 -3
  177. package/dist/slices/show-aggregate/index.js +0 -108
  178. package/dist/slices/show-aggregate-completeness/index.d.ts +0 -4
  179. package/dist/slices/show-aggregate-completeness/index.js +0 -181
  180. package/dist/slices/show-chapter/index.d.ts +0 -3
  181. package/dist/slices/show-chapter/index.js +0 -195
  182. package/dist/slices/show-command/index.d.ts +0 -3
  183. package/dist/slices/show-command/index.js +0 -133
  184. package/dist/slices/show-completeness/index.d.ts +0 -4
  185. package/dist/slices/show-completeness/index.js +0 -731
  186. package/dist/slices/show-event/index.d.ts +0 -3
  187. package/dist/slices/show-event/index.js +0 -118
  188. package/dist/slices/show-model-summary/index.d.ts +0 -3
  189. package/dist/slices/show-model-summary/index.js +0 -31
  190. package/dist/slices/show-processor/index.d.ts +0 -3
  191. package/dist/slices/show-processor/index.js +0 -111
  192. package/dist/slices/show-readmodel/index.d.ts +0 -3
  193. package/dist/slices/show-readmodel/index.js +0 -158
  194. package/dist/slices/show-scenario/index.d.ts +0 -3
  195. package/dist/slices/show-scenario/index.js +0 -196
  196. package/dist/slices/show-screen/index.d.ts +0 -3
  197. package/dist/slices/show-screen/index.js +0 -139
  198. package/dist/slices/show-slice/index.d.ts +0 -3
  199. package/dist/slices/show-slice/index.js +0 -696
  200. package/dist/slices/update-field/index.d.ts +0 -15
  201. package/dist/slices/update-field/index.js +0 -208
  202. package/dist/slices/whoami/index.d.ts +0 -2
  203. package/dist/types.d.ts +0 -195
  204. package/dist/types.js +0 -1
@@ -1,35 +0,0 @@
1
- import { escapeXml, outputJson } from '../../lib/format.js';
2
- export function listScenarios(model, format) {
3
- const scenarios = [...model.scenarios.values()];
4
- const sorted = [...scenarios].sort((a, b) => a.name.localeCompare(b.name));
5
- if (format === 'json') {
6
- outputJson({
7
- scenarios: sorted.map(scenario => {
8
- const slice = model.slices.get(scenario.sliceId);
9
- const result = {
10
- id: scenario.id,
11
- name: scenario.name,
12
- slice: slice?.name ?? scenario.sliceId,
13
- thenType: scenario.then.type
14
- };
15
- if (scenario.description) {
16
- result.description = scenario.description;
17
- }
18
- return result;
19
- })
20
- });
21
- return;
22
- }
23
- if (scenarios.length === 0) {
24
- console.log('<scenarios/>');
25
- return;
26
- }
27
- console.log('<scenarios>');
28
- for (const scenario of sorted) {
29
- const slice = model.slices.get(scenario.sliceId);
30
- const sliceName = slice?.name ?? scenario.sliceId;
31
- const descAttr = scenario.description ? ` description="${escapeXml(scenario.description)}"` : '';
32
- console.log(` <scenario id="${scenario.id}" name="${escapeXml(scenario.name)}" slice="${escapeXml(sliceName)}" then-type="${scenario.then.type}"${descAttr}/>`);
33
- }
34
- console.log('</scenarios>');
35
- }
@@ -1,3 +0,0 @@
1
- import type { EventModel } from '../../types.js';
2
- import { type OutputFormat } from '../../lib/format.js';
3
- export declare function listScreens(model: EventModel, format: OutputFormat): void;
@@ -1,47 +0,0 @@
1
- import { escapeXml, outputJson } from '../../lib/format.js';
2
- // Get the actor name for a screen based on spatial containment
3
- function getActorForScreen(model, screen) {
4
- const centerX = screen.position.x + screen.width / 2;
5
- const centerY = screen.position.y + screen.height / 2;
6
- for (const actor of model.actors.values()) {
7
- const bounds = {
8
- left: actor.position.x,
9
- right: actor.position.x + actor.size.width,
10
- top: actor.position.y,
11
- bottom: actor.position.y + actor.size.height,
12
- };
13
- if (centerX >= bounds.left && centerX <= bounds.right &&
14
- centerY >= bounds.top && centerY <= bounds.bottom) {
15
- return actor.name;
16
- }
17
- }
18
- return undefined;
19
- }
20
- export function listScreens(model, format) {
21
- // Filter out linked copies (they have originalNodeId set)
22
- const screens = [...model.screens.values()].filter(scr => !scr.originalNodeId);
23
- const sorted = [...screens].sort((a, b) => a.name.localeCompare(b.name));
24
- if (format === 'json') {
25
- outputJson({
26
- screens: sorted.map(scr => {
27
- const result = { id: scr.id, name: scr.name, fields: scr.fields.length };
28
- const actor = getActorForScreen(model, scr);
29
- if (actor)
30
- result.actor = actor;
31
- return result;
32
- })
33
- });
34
- return;
35
- }
36
- if (screens.length === 0) {
37
- console.log('<screens/>');
38
- return;
39
- }
40
- console.log('<screens>');
41
- for (const scr of sorted) {
42
- const actor = getActorForScreen(model, scr);
43
- const actorAttr = actor ? ` actor="${escapeXml(actor)}"` : '';
44
- console.log(` <screen id="${scr.id}" name="${escapeXml(scr.name)}" fields="${scr.fields.length}"${actorAttr}/>`);
45
- }
46
- console.log('</screens>');
47
- }
@@ -1,3 +0,0 @@
1
- import type { EventModel } from '../../types.js';
2
- import { type OutputFormat } from '../../lib/format.js';
3
- export declare function listSlices(model: EventModel, format: OutputFormat, chapterName?: string): void;
@@ -1,35 +0,0 @@
1
- import { escapeXml, outputJson } from '../../lib/format.js';
2
- import { findElementOrExit } from '../../lib/element-lookup.js';
3
- function getSlicesUnderChapter(model, chapter) {
4
- const chapterLeft = chapter.position.x;
5
- const chapterRight = chapter.position.x + chapter.size.width;
6
- return [...model.slices.values()].filter(slice => {
7
- const sliceCenterX = slice.position.x + slice.size.width / 2;
8
- return sliceCenterX >= chapterLeft && sliceCenterX <= chapterRight;
9
- });
10
- }
11
- export function listSlices(model, format, chapterName) {
12
- let slices = [...model.slices.values()];
13
- // Filter by chapter if specified
14
- if (chapterName) {
15
- const chapter = findElementOrExit(model.chapters, chapterName, 'chapter');
16
- slices = getSlicesUnderChapter(model, chapter);
17
- }
18
- const sorted = [...slices].sort((a, b) => a.position.x - b.position.x);
19
- if (format === 'json') {
20
- outputJson({
21
- ...(chapterName && { chapter: chapterName }),
22
- slices: sorted.map(s => ({ id: s.id, name: s.name, status: s.status }))
23
- });
24
- return;
25
- }
26
- if (slices.length === 0) {
27
- console.log('<slices/>');
28
- return;
29
- }
30
- console.log('<slices>');
31
- for (const slice of sorted) {
32
- console.log(` <slice id="${slice.id}" name="${escapeXml(slice.name)}" status="${slice.status}"/>`);
33
- }
34
- console.log('</slices>');
35
- }
@@ -1 +0,0 @@
1
- export declare function login(): Promise<void>;
@@ -1 +0,0 @@
1
- export declare function logout(): void;
@@ -1,2 +0,0 @@
1
- import type { EventModel } from '../../types.js';
2
- export declare function mapFields(model: EventModel, filePath: string, flowIdentifier: string, input: string): void;
@@ -1,269 +0,0 @@
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
- }
34
- function flattenFields(fields, prefix = '') {
35
- const result = [];
36
- for (const field of fields) {
37
- const path = prefix ? `${prefix}.${field.name}` : field.name;
38
- result.push({ id: field.id, path, field });
39
- if (field.fieldType === 'Custom' && field.subfields) {
40
- result.push(...flattenFields(field.subfields, path));
41
- }
42
- }
43
- return result;
44
- }
45
- function parseJsonInput(input) {
46
- const parsed = JSON.parse(input);
47
- if (!Array.isArray(parsed)) {
48
- return [parsed];
49
- }
50
- return parsed;
51
- }
52
- function parseXmlInput(input) {
53
- const mappings = [];
54
- const mappingMatches = input.matchAll(/<mapping[^>]*from="([^"]*)"[^>]*to="([^"]*)"[^>]*\/?>/g);
55
- for (const match of mappingMatches) {
56
- mappings.push({ from: match[1], to: match[2] });
57
- }
58
- // Also try alternate attribute order
59
- const altMatches = input.matchAll(/<mapping[^>]*to="([^"]*)"[^>]*from="([^"]*)"[^>]*\/?>/g);
60
- for (const match of altMatches) {
61
- // Check if this mapping was already added
62
- const exists = mappings.some(m => m.from === match[2] && m.to === match[1]);
63
- if (!exists) {
64
- mappings.push({ from: match[2], to: match[1] });
65
- }
66
- }
67
- if (mappings.length === 0) {
68
- throw new Error('No <mapping from="..." to="..."/> elements found in XML');
69
- }
70
- return mappings;
71
- }
72
- function parseInput(input) {
73
- const trimmed = input.trim();
74
- if (trimmed.startsWith('<')) {
75
- return parseXmlInput(trimmed);
76
- }
77
- return parseJsonInput(trimmed);
78
- }
79
- export function mapFields(model, filePath, flowIdentifier, input) {
80
- // Parse the mapping input
81
- let mappingInputs;
82
- try {
83
- mappingInputs = parseInput(input);
84
- }
85
- catch (err) {
86
- console.error(`Error: Invalid input format: ${err.message}`);
87
- process.exit(1);
88
- }
89
- // Find the flow - can be identified by:
90
- // 1. Flow ID directly
91
- // 2. "SourceName→TargetName" format (using → or ->)
92
- let flow = model.flows.get(flowIdentifier);
93
- if (!flow) {
94
- // Try to parse as "Source→Target" or "Source->Target"
95
- const arrowMatch = flowIdentifier.match(/^(.+?)(?:→|->)(.+)$/);
96
- if (arrowMatch) {
97
- const sourceName = arrowMatch[1].trim().toLowerCase();
98
- const targetName = arrowMatch[2].trim().toLowerCase();
99
- // Find matching flow, preferring flows that don't involve linked copies
100
- let fallbackFlow = undefined;
101
- for (const f of model.flows.values()) {
102
- let sourceEntityName = '';
103
- let targetEntityName = '';
104
- // Get source name
105
- const sourceEvent = model.events.get(f.sourceId);
106
- const sourceReadModel = model.readModels.get(f.sourceId);
107
- const sourceScreen = model.screens.get(f.sourceId);
108
- const sourceProcessor = model.processors.get(f.sourceId);
109
- const sourceCommand = model.commands.get(f.sourceId);
110
- if (sourceEvent)
111
- sourceEntityName = sourceEvent.name.toLowerCase();
112
- else if (sourceReadModel)
113
- sourceEntityName = sourceReadModel.name.toLowerCase();
114
- else if (sourceScreen)
115
- sourceEntityName = sourceScreen.name.toLowerCase();
116
- else if (sourceProcessor)
117
- sourceEntityName = sourceProcessor.name.toLowerCase();
118
- else if (sourceCommand)
119
- sourceEntityName = sourceCommand.name.toLowerCase();
120
- // Get target name
121
- const targetEvent = model.events.get(f.targetId);
122
- const targetReadModel = model.readModels.get(f.targetId);
123
- const targetScreen = model.screens.get(f.targetId);
124
- const targetProcessor = model.processors.get(f.targetId);
125
- const targetCommand = model.commands.get(f.targetId);
126
- if (targetEvent)
127
- targetEntityName = targetEvent.name.toLowerCase();
128
- else if (targetReadModel)
129
- targetEntityName = targetReadModel.name.toLowerCase();
130
- else if (targetScreen)
131
- targetEntityName = targetScreen.name.toLowerCase();
132
- else if (targetProcessor)
133
- targetEntityName = targetProcessor.name.toLowerCase();
134
- else if (targetCommand)
135
- targetEntityName = targetCommand.name.toLowerCase();
136
- // Check for match (exact or partial)
137
- const sourceMatches = sourceEntityName === sourceName || sourceEntityName.includes(sourceName);
138
- const targetMatches = targetEntityName === targetName || targetEntityName.includes(targetName);
139
- if (sourceMatches && targetMatches) {
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
- }
150
- }
151
- }
152
- // Use fallback if no non-copy flow was found
153
- if (!flow && fallbackFlow) {
154
- flow = fallbackFlow;
155
- }
156
- }
157
- }
158
- if (!flow) {
159
- console.error(`Error: Flow not found: ${flowIdentifier}`);
160
- console.error('Available flows:');
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
- }
166
- const source = getEntityName(model, f.sourceId);
167
- const target = getEntityName(model, f.targetId);
168
- console.error(` - ${source}→${target} (${f.id})`);
169
- }
170
- process.exit(1);
171
- }
172
- // Get source and target fields
173
- const sourceFields = getEntityFields(model, flow.sourceId);
174
- const targetFields = getEntityFields(model, flow.targetId);
175
- const flatSource = flattenFields(sourceFields);
176
- const flatTarget = flattenFields(targetFields);
177
- // Resolve mapping inputs to field IDs
178
- const mappings = [];
179
- for (const m of mappingInputs) {
180
- // Find source field (by name/path or ID)
181
- const sourceField = flatSource.find(sf => sf.id === m.from || sf.path.toLowerCase() === m.from.toLowerCase());
182
- if (!sourceField) {
183
- console.error(`Error: Source field not found: ${m.from}`);
184
- console.error('Available source fields:');
185
- for (const sf of flatSource) {
186
- console.error(` - ${sf.path} (${sf.id})`);
187
- }
188
- process.exit(1);
189
- }
190
- // Find target field (by name/path or ID)
191
- const targetField = flatTarget.find(tf => tf.id === m.to || tf.path.toLowerCase() === m.to.toLowerCase());
192
- if (!targetField) {
193
- console.error(`Error: Target field not found: ${m.to}`);
194
- console.error('Available target fields:');
195
- for (const tf of flatTarget) {
196
- console.error(` - ${tf.path} (${tf.id})`);
197
- }
198
- process.exit(1);
199
- }
200
- mappings.push({
201
- sourceFieldId: sourceField.id,
202
- targetFieldId: targetField.id,
203
- });
204
- }
205
- // Get existing mappings and merge
206
- const existingMappings = flow.fieldMappings ?? [];
207
- const mergedMappings = [...existingMappings];
208
- for (const newMapping of mappings) {
209
- // Remove any existing mapping for the same target field
210
- const existingIndex = mergedMappings.findIndex(m => m.targetFieldId === newMapping.targetFieldId);
211
- if (existingIndex >= 0) {
212
- mergedMappings.splice(existingIndex, 1);
213
- }
214
- mergedMappings.push(newMapping);
215
- }
216
- // Append the event
217
- appendEvent(filePath, {
218
- type: 'FieldMappingSpecified',
219
- data: {
220
- flowId: flow.id,
221
- mappings: mergedMappings,
222
- timestamp: Date.now(),
223
- },
224
- });
225
- const sourceName = getEntityName(model, flow.sourceId);
226
- const targetName = getEntityName(model, flow.targetId);
227
- console.log(`Mapped ${mappings.length} field(s) on flow ${sourceName}→${targetName}`);
228
- for (const m of mappingInputs) {
229
- console.log(` ${m.from} → ${m.to}`);
230
- }
231
- }
232
- function getEntityName(model, entityId) {
233
- const event = model.events.get(entityId);
234
- if (event)
235
- return event.name;
236
- const readModel = model.readModels.get(entityId);
237
- if (readModel)
238
- return readModel.name;
239
- const command = model.commands.get(entityId);
240
- if (command)
241
- return command.name;
242
- const screen = model.screens.get(entityId);
243
- if (screen)
244
- return screen.name;
245
- const processor = model.processors.get(entityId);
246
- if (processor)
247
- return processor.name;
248
- return entityId;
249
- }
250
- function getEntityFields(model, entityId) {
251
- // Resolve linked copies to their originals to get canonical fields
252
- const resolvedId = resolveToOriginal(model, entityId);
253
- const event = model.events.get(resolvedId);
254
- if (event)
255
- return event.fields;
256
- const readModel = model.readModels.get(resolvedId);
257
- if (readModel)
258
- return readModel.fields;
259
- const command = model.commands.get(resolvedId);
260
- if (command)
261
- return command.fields;
262
- const screen = model.screens.get(resolvedId);
263
- if (screen)
264
- return screen.fields;
265
- const processor = model.processors.get(resolvedId);
266
- if (processor)
267
- return processor.fields;
268
- return [];
269
- }
@@ -1,2 +0,0 @@
1
- import type { EventModel } from '../../types.js';
2
- export declare function markSliceStatus(model: EventModel, filePath: string, sliceName: string, status: string): void;
@@ -1,31 +0,0 @@
1
- import { appendEvent } from '../../lib/file-loader.js';
2
- import { findElementOrExit } from '../../lib/element-lookup.js';
3
- const validStatuses = ['created', 'in-progress', 'blocked', 'done'];
4
- const eventTypeMap = {
5
- 'created': 'SliceMarkedAsCreated',
6
- 'in-progress': 'SliceMarkedAsInProgress',
7
- 'blocked': 'SliceMarkedAsBlocked',
8
- 'done': 'SliceMarkedAsDone',
9
- };
10
- export function markSliceStatus(model, filePath, sliceName, status) {
11
- if (!validStatuses.includes(status)) {
12
- console.error(`Error: Invalid status: ${status}`);
13
- console.error('Valid statuses: created, in-progress, blocked, done');
14
- process.exit(1);
15
- }
16
- const newStatus = status;
17
- const slice = findElementOrExit(model.slices, sliceName, 'slice');
18
- if (slice.status === newStatus) {
19
- console.log(`Slice "${slice.name}" is already marked as ${newStatus}`);
20
- return;
21
- }
22
- const event = {
23
- type: eventTypeMap[newStatus],
24
- data: {
25
- sliceId: slice.id,
26
- timestamp: Date.now(),
27
- },
28
- };
29
- appendEvent(filePath, event);
30
- console.log(`Marked slice "${slice.name}" as ${newStatus}`);
31
- }
@@ -1,19 +0,0 @@
1
- import type { OutputFormat } from '../../lib/format.js';
2
- export interface MergeOptions {
3
- basePath: string;
4
- oursPath: string;
5
- theirsPath: string;
6
- outputPath: string;
7
- strategy?: 'ours' | 'theirs';
8
- dryRun: boolean;
9
- format: OutputFormat;
10
- }
11
- /**
12
- * Three-way merge of eventmodel files.
13
- *
14
- * Exit codes:
15
- * 0 - Clean merge (success)
16
- * 1 - Conflicts detected
17
- * 2 - Error (file not found, parse error)
18
- */
19
- export declare function merge(options: MergeOptions): void;
@@ -1,147 +0,0 @@
1
- import * as fs from 'node:fs';
2
- import { loadModel, loadRawEvents, writeEvents } from '../../lib/file-loader.js';
3
- import { threeWayMerge } from '../../lib/diff/three-way-merge.js';
4
- import { escapeXml, outputJson } from '../../lib/format.js';
5
- function formatConflictXml(conflict) {
6
- const lines = [];
7
- const entityAttr = escapeXml(conflict.entityType);
8
- const nameAttr = escapeXml(conflict.entityName);
9
- const idAttr = escapeXml(conflict.entityId);
10
- lines.push(` <conflict entity="${entityAttr}" name="${nameAttr}" id="${idAttr}">`);
11
- lines.push(` <reason>${escapeXml(conflict.reason)}</reason>`);
12
- if (conflict.baseValue !== undefined) {
13
- lines.push(` <base>${escapeXml(JSON.stringify(conflict.baseValue))}</base>`);
14
- }
15
- if (conflict.oursValue !== undefined) {
16
- lines.push(` <ours>${escapeXml(JSON.stringify(conflict.oursValue))}</ours>`);
17
- }
18
- if (conflict.theirsValue !== undefined) {
19
- lines.push(` <theirs>${escapeXml(JSON.stringify(conflict.theirsValue))}</theirs>`);
20
- }
21
- lines.push(' </conflict>');
22
- return lines.join('\n');
23
- }
24
- function formatAutoResolutionXml(resolution) {
25
- const entityAttr = escapeXml(resolution.entityType);
26
- const nameAttr = escapeXml(resolution.entityName);
27
- const actionAttr = escapeXml(resolution.action);
28
- return ` <resolution entity="${entityAttr}" name="${nameAttr}" action="${actionAttr}"/>`;
29
- }
30
- function formatMergeResultXml(result, dryRun) {
31
- const lines = [];
32
- const status = result.success ? 'success' : 'conflicts';
33
- lines.push(`<merge-result status="${status}">`);
34
- lines.push(` <summary merged-events="${result.mergedEvents.length}" conflicts="${result.conflicts.length}" auto-resolved="${result.autoResolved.length}"/>`);
35
- if (result.conflicts.length > 0) {
36
- lines.push(' <conflicts>');
37
- for (const conflict of result.conflicts) {
38
- lines.push(formatConflictXml(conflict));
39
- }
40
- lines.push(' </conflicts>');
41
- }
42
- if (result.autoResolved.length > 0) {
43
- lines.push(' <auto-resolved>');
44
- for (const resolution of result.autoResolved) {
45
- lines.push(formatAutoResolutionXml(resolution));
46
- }
47
- lines.push(' </auto-resolved>');
48
- }
49
- if (dryRun) {
50
- lines.push(' <note>Dry run - no files were modified</note>');
51
- }
52
- lines.push('</merge-result>');
53
- return lines.join('\n');
54
- }
55
- function formatMergeResultJson(result, dryRun) {
56
- return {
57
- success: result.success,
58
- summary: {
59
- mergedEvents: result.mergedEvents.length,
60
- conflicts: result.conflicts.length,
61
- autoResolved: result.autoResolved.length,
62
- },
63
- conflicts: result.conflicts.map((c) => ({
64
- entityType: c.entityType,
65
- entityId: c.entityId,
66
- entityName: c.entityName,
67
- reason: c.reason,
68
- property: c.property,
69
- base: c.baseValue,
70
- ours: c.oursValue,
71
- theirs: c.theirsValue,
72
- })),
73
- autoResolved: result.autoResolved.map((r) => ({
74
- entityType: r.entityType,
75
- entityId: r.entityId,
76
- entityName: r.entityName,
77
- action: r.action,
78
- })),
79
- dryRun,
80
- };
81
- }
82
- /**
83
- * Three-way merge of eventmodel files.
84
- *
85
- * Exit codes:
86
- * 0 - Clean merge (success)
87
- * 1 - Conflicts detected
88
- * 2 - Error (file not found, parse error)
89
- */
90
- export function merge(options) {
91
- const { basePath, oursPath, theirsPath, outputPath, strategy, dryRun, format } = options;
92
- // Validate files exist
93
- if (!fs.existsSync(basePath)) {
94
- console.error(`Error: Base file not found: ${basePath}`);
95
- process.exit(2);
96
- }
97
- if (!fs.existsSync(oursPath)) {
98
- console.error(`Error: Ours file not found: ${oursPath}`);
99
- process.exit(2);
100
- }
101
- if (!fs.existsSync(theirsPath)) {
102
- console.error(`Error: Theirs file not found: ${theirsPath}`);
103
- process.exit(2);
104
- }
105
- // Load models and raw events
106
- let baseModel, oursModel, theirsModel;
107
- let baseEvents, oursEvents, theirsEvents;
108
- try {
109
- baseModel = loadModel(basePath);
110
- oursModel = loadModel(oursPath);
111
- theirsModel = loadModel(theirsPath);
112
- baseEvents = loadRawEvents(basePath);
113
- oursEvents = loadRawEvents(oursPath);
114
- theirsEvents = loadRawEvents(theirsPath);
115
- }
116
- catch (err) {
117
- console.error(`Error parsing eventmodel files: ${err.message}`);
118
- process.exit(2);
119
- }
120
- // Perform merge
121
- const result = threeWayMerge(baseModel, oursModel, theirsModel, baseEvents, oursEvents, theirsEvents, strategy);
122
- // Output result
123
- if (format === 'json') {
124
- outputJson(formatMergeResultJson(result, dryRun));
125
- }
126
- else {
127
- console.log(formatMergeResultXml(result, dryRun));
128
- }
129
- // Write merged file if not dry run and successful (or strategy provided)
130
- if (!dryRun && (result.success || strategy)) {
131
- try {
132
- writeEvents(outputPath, result.mergedEvents);
133
- console.error(`Merged ${result.mergedEvents.length} events to ${outputPath}`);
134
- }
135
- catch (err) {
136
- console.error(`Error writing output file: ${err.message}`);
137
- process.exit(2);
138
- }
139
- }
140
- // Exit with appropriate code
141
- if (result.success) {
142
- process.exit(0);
143
- }
144
- else {
145
- process.exit(1);
146
- }
147
- }
@@ -1 +0,0 @@
1
- export declare function openApp(): void;
@@ -1,8 +0,0 @@
1
- import type { EventModel } from '../../types.js';
2
- export declare function removeField(model: EventModel, filePath: string, options: {
3
- command?: string;
4
- event?: string;
5
- readModel?: string;
6
- screen?: string;
7
- processor?: string;
8
- }, fieldName: string): void;