eventmodeler 0.4.7 → 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.
- package/dist/api/client-config.js +10 -0
- package/dist/api/generated/client/client.gen.js +235 -0
- package/dist/api/generated/client/index.js +6 -0
- package/dist/api/generated/client/types.gen.js +2 -0
- package/dist/api/generated/client/utils.gen.js +228 -0
- package/dist/api/generated/client.gen.js +4 -0
- package/dist/api/generated/core/auth.gen.js +14 -0
- package/dist/api/generated/core/bodySerializer.gen.js +57 -0
- package/dist/api/generated/core/params.gen.js +100 -0
- package/dist/api/generated/core/pathSerializer.gen.js +106 -0
- package/dist/api/generated/core/queryKeySerializer.gen.js +92 -0
- package/dist/api/generated/core/serverSentEvents.gen.js +133 -0
- package/dist/api/generated/core/types.gen.js +2 -0
- package/dist/api/generated/core/utils.gen.js +87 -0
- package/dist/api/generated/index.js +2 -0
- package/dist/api/generated/sdk.gen.js +4222 -0
- package/dist/api/generated/types.gen.js +2 -0
- package/dist/api/generated/zod.gen.js +7217 -0
- package/dist/commands/add.js +315 -0
- package/dist/commands/auth.js +14 -0
- package/dist/commands/create.js +192 -0
- package/dist/commands/design.js +108 -0
- package/dist/commands/guide.js +15 -0
- package/dist/commands/init.js +21 -0
- package/dist/commands/list-schemas.js +177 -0
- package/dist/commands/list.js +39 -0
- package/dist/commands/loop.js +101 -0
- package/dist/commands/map.js +40 -0
- package/dist/commands/mark.js +27 -0
- package/dist/commands/move.js +35 -0
- package/dist/commands/remove.js +170 -0
- package/dist/commands/rename.js +53 -0
- package/dist/commands/resize.js +30 -0
- package/dist/commands/search.js +14 -0
- package/dist/commands/set.js +199 -0
- package/dist/commands/show-schemas.js +259 -0
- package/dist/commands/show.js +56 -0
- package/dist/commands/summary.js +13 -0
- package/dist/commands/update.js +240 -0
- package/dist/index.js +46 -2379
- package/dist/lib/auth.js +1 -1
- package/dist/lib/config.js +0 -15
- package/dist/lib/excalidraw-schema.js +66 -0
- package/dist/lib/globals.js +8 -0
- package/dist/lib/model.js +11 -0
- package/dist/lib/project-config.js +20 -0
- package/dist/lib/resolve.js +59 -0
- package/dist/lib/scenario.js +15 -0
- package/dist/slices/add-scenario/index.js +2 -206
- package/dist/slices/guide/guides/codegen.js +1 -1
- package/dist/slices/guide/guides/connect-slices.js +12 -37
- package/dist/slices/guide/guides/create-slices.js +110 -140
- package/dist/slices/guide/guides/explore.js +37 -26
- package/dist/slices/guide/guides/information-flow.js +70 -82
- package/dist/slices/guide/guides/scenarios.js +82 -137
- package/dist/slices/guide/index.js +6 -6
- package/dist/slices/help/index.js +96 -0
- package/dist/slices/help/topics/build-codegen.js +109 -0
- package/dist/slices/help/topics/build-slice.js +147 -0
- package/dist/slices/help/topics/check-completeness.js +57 -0
- package/dist/slices/help/topics/connect-slices.js +99 -0
- package/dist/slices/help/topics/explore-model.js +112 -0
- package/dist/slices/help/topics/json-reference.js +188 -0
- package/dist/slices/help/topics/linked-copies.js +89 -0
- package/dist/slices/help/topics/manipulate-canvas.js +150 -0
- package/dist/slices/help/topics/write-scenarios.js +162 -0
- package/dist/slices/init/index.js +10 -4
- package/dist/slices/init/loop.js +60 -0
- package/dist/slices/login/index.js +2 -2
- package/dist/slices/logout/index.js +2 -2
- package/dist/slices/whoami/index.js +11 -36
- package/package.json +8 -3
- package/dist/api/index.d.ts +0 -285
- package/dist/api/index.js +0 -323
- package/dist/cloud/slices/index.d.ts +0 -276
- package/dist/cloud/slices/index.js +0 -406
- package/dist/eventmodeler.js +0 -5646
- package/dist/formatters.d.ts +0 -17
- package/dist/formatters.js +0 -482
- package/dist/index.d.ts +0 -2
- package/dist/lib/auth.d.ts +0 -24
- package/dist/lib/backend.d.ts +0 -43
- package/dist/lib/backend.js +0 -73
- package/dist/lib/chapter-utils.d.ts +0 -13
- package/dist/lib/chapter-utils.js +0 -71
- package/dist/lib/cloud-client.d.ts +0 -69
- package/dist/lib/cloud-client.js +0 -364
- package/dist/lib/config.d.ts +0 -30
- package/dist/lib/diff/merge-rules.d.ts +0 -45
- package/dist/lib/diff/merge-rules.js +0 -210
- package/dist/lib/diff/model-differ.d.ts +0 -8
- package/dist/lib/diff/model-differ.js +0 -568
- package/dist/lib/diff/three-way-merge.d.ts +0 -7
- package/dist/lib/diff/three-way-merge.js +0 -390
- package/dist/lib/diff/types.d.ts +0 -75
- package/dist/lib/diff/types.js +0 -1
- package/dist/lib/element-lookup.d.ts +0 -58
- package/dist/lib/element-lookup.js +0 -126
- package/dist/lib/file-loader.d.ts +0 -8
- package/dist/lib/file-loader.js +0 -108
- package/dist/lib/flow-utils.d.ts +0 -53
- package/dist/lib/flow-utils.js +0 -348
- package/dist/lib/format.d.ts +0 -10
- package/dist/lib/format.js +0 -23
- package/dist/lib/project-config.d.ts +0 -27
- package/dist/lib/slice-utils.d.ts +0 -59
- package/dist/lib/slice-utils.js +0 -140
- package/dist/local/slices/index.d.ts +0 -11
- package/dist/local/slices/index.js +0 -13
- package/dist/projection.d.ts +0 -3
- package/dist/projection.js +0 -828
- package/dist/slices/add-field/index.d.ts +0 -8
- package/dist/slices/add-field/index.js +0 -211
- package/dist/slices/add-scenario/index.d.ts +0 -27
- package/dist/slices/codegen-chapter-events/index.d.ts +0 -2
- package/dist/slices/codegen-chapter-events/index.js +0 -145
- package/dist/slices/codegen-slice/index.d.ts +0 -2
- package/dist/slices/codegen-slice/index.js +0 -448
- package/dist/slices/create-automation-slice/index.d.ts +0 -2
- package/dist/slices/create-automation-slice/index.js +0 -304
- package/dist/slices/create-flow/index.d.ts +0 -2
- package/dist/slices/create-flow/index.js +0 -183
- package/dist/slices/create-state-change-slice/index.d.ts +0 -2
- package/dist/slices/create-state-change-slice/index.js +0 -263
- package/dist/slices/create-state-view-slice/index.d.ts +0 -2
- package/dist/slices/create-state-view-slice/index.js +0 -128
- package/dist/slices/diff/index.d.ts +0 -11
- package/dist/slices/diff/index.js +0 -293
- package/dist/slices/export-eventmodel-to-json/index.d.ts +0 -2
- package/dist/slices/export-eventmodel-to-json/index.js +0 -355
- package/dist/slices/git/index.d.ts +0 -2
- package/dist/slices/git/index.js +0 -125
- package/dist/slices/guide/guides/codegen.d.ts +0 -5
- package/dist/slices/guide/guides/connect-slices.d.ts +0 -5
- package/dist/slices/guide/guides/create-slices.d.ts +0 -5
- package/dist/slices/guide/guides/explore.d.ts +0 -5
- package/dist/slices/guide/guides/information-flow.d.ts +0 -5
- package/dist/slices/guide/guides/scenarios.d.ts +0 -5
- package/dist/slices/guide/index.d.ts +0 -1
- package/dist/slices/import/index.d.ts +0 -8
- package/dist/slices/import/index.js +0 -63
- package/dist/slices/init/index.d.ts +0 -5
- package/dist/slices/list-chapters/index.d.ts +0 -3
- package/dist/slices/list-chapters/index.js +0 -21
- package/dist/slices/list-commands/index.d.ts +0 -3
- package/dist/slices/list-commands/index.js +0 -20
- package/dist/slices/list-events/index.d.ts +0 -3
- package/dist/slices/list-events/index.js +0 -98
- package/dist/slices/list-processors/index.d.ts +0 -3
- package/dist/slices/list-processors/index.js +0 -20
- package/dist/slices/list-readmodels/index.d.ts +0 -3
- package/dist/slices/list-readmodels/index.js +0 -21
- package/dist/slices/list-scenarios/index.d.ts +0 -3
- package/dist/slices/list-scenarios/index.js +0 -35
- package/dist/slices/list-screens/index.d.ts +0 -3
- package/dist/slices/list-screens/index.js +0 -47
- package/dist/slices/list-slices/index.d.ts +0 -3
- package/dist/slices/list-slices/index.js +0 -35
- package/dist/slices/login/index.d.ts +0 -1
- package/dist/slices/logout/index.d.ts +0 -1
- package/dist/slices/map-fields/index.d.ts +0 -2
- package/dist/slices/map-fields/index.js +0 -269
- package/dist/slices/mark-slice-status/index.d.ts +0 -2
- package/dist/slices/mark-slice-status/index.js +0 -31
- package/dist/slices/merge/index.d.ts +0 -19
- package/dist/slices/merge/index.js +0 -147
- package/dist/slices/open-app/index.d.ts +0 -1
- package/dist/slices/remove-field/index.d.ts +0 -8
- package/dist/slices/remove-field/index.js +0 -167
- package/dist/slices/remove-scenario/index.d.ts +0 -2
- package/dist/slices/remove-scenario/index.js +0 -77
- package/dist/slices/search/index.d.ts +0 -3
- package/dist/slices/search/index.js +0 -302
- package/dist/slices/show-actor/index.d.ts +0 -4
- package/dist/slices/show-actor/index.js +0 -115
- package/dist/slices/show-aggregate/index.d.ts +0 -3
- package/dist/slices/show-aggregate/index.js +0 -108
- package/dist/slices/show-aggregate-completeness/index.d.ts +0 -4
- package/dist/slices/show-aggregate-completeness/index.js +0 -181
- package/dist/slices/show-chapter/index.d.ts +0 -3
- package/dist/slices/show-chapter/index.js +0 -195
- package/dist/slices/show-command/index.d.ts +0 -3
- package/dist/slices/show-command/index.js +0 -133
- package/dist/slices/show-completeness/index.d.ts +0 -4
- package/dist/slices/show-completeness/index.js +0 -731
- package/dist/slices/show-event/index.d.ts +0 -3
- package/dist/slices/show-event/index.js +0 -118
- package/dist/slices/show-model-summary/index.d.ts +0 -3
- package/dist/slices/show-model-summary/index.js +0 -31
- package/dist/slices/show-processor/index.d.ts +0 -3
- package/dist/slices/show-processor/index.js +0 -111
- package/dist/slices/show-readmodel/index.d.ts +0 -3
- package/dist/slices/show-readmodel/index.js +0 -158
- package/dist/slices/show-scenario/index.d.ts +0 -3
- package/dist/slices/show-scenario/index.js +0 -196
- package/dist/slices/show-screen/index.d.ts +0 -3
- package/dist/slices/show-screen/index.js +0 -139
- package/dist/slices/show-slice/index.d.ts +0 -3
- package/dist/slices/show-slice/index.js +0 -696
- package/dist/slices/update-field/index.d.ts +0 -15
- package/dist/slices/update-field/index.js +0 -208
- package/dist/slices/whoami/index.d.ts +0 -2
- package/dist/types.d.ts +0 -195
- 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,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,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,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,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;
|