eventmodeler 0.2.9 → 0.3.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/index.js +25 -13
- package/dist/lib/chapter-utils.d.ts +13 -0
- package/dist/lib/chapter-utils.js +71 -0
- package/dist/lib/flow-utils.d.ts +52 -0
- package/dist/lib/flow-utils.js +305 -0
- package/dist/lib/slice-utils.js +17 -4
- package/dist/slices/add-field/index.d.ts +2 -0
- package/dist/slices/add-field/index.js +46 -3
- package/dist/slices/codegen-slice/index.js +2 -13
- package/dist/slices/list-slices/index.d.ts +1 -1
- package/dist/slices/list-slices/index.js +17 -2
- package/dist/slices/remove-field/index.d.ts +2 -0
- package/dist/slices/remove-field/index.js +59 -3
- package/dist/slices/show-chapter/index.js +162 -2
- package/dist/slices/show-slice/index.js +242 -10
- package/dist/slices/update-field/index.d.ts +2 -0
- package/dist/slices/update-field/index.js +57 -3
- package/package.json +1 -1
|
@@ -68,13 +68,13 @@ function createFieldFromInput(input) {
|
|
|
68
68
|
}
|
|
69
69
|
export function addField(model, filePath, options, input) {
|
|
70
70
|
// Determine which entity type
|
|
71
|
-
const entityCount = [options.command, options.event, options.readModel].filter(Boolean).length;
|
|
71
|
+
const entityCount = [options.command, options.event, options.readModel, options.screen, options.processor].filter(Boolean).length;
|
|
72
72
|
if (entityCount === 0) {
|
|
73
|
-
console.error('Error: Must specify one of --command, --event,
|
|
73
|
+
console.error('Error: Must specify one of --command, --event, --read-model, --screen, or --processor');
|
|
74
74
|
process.exit(1);
|
|
75
75
|
}
|
|
76
76
|
if (entityCount > 1) {
|
|
77
|
-
console.error('Error: Can only specify one of --command, --event,
|
|
77
|
+
console.error('Error: Can only specify one of --command, --event, --read-model, --screen, or --processor');
|
|
78
78
|
process.exit(1);
|
|
79
79
|
}
|
|
80
80
|
// Parse input
|
|
@@ -90,6 +90,11 @@ export function addField(model, filePath, options, input) {
|
|
|
90
90
|
if (!validFieldTypes.includes(fieldInput.type)) {
|
|
91
91
|
console.error(`Error: Invalid field type: ${fieldInput.type}`);
|
|
92
92
|
console.error(`Valid types: ${validFieldTypes.join(', ')}`);
|
|
93
|
+
const typeLower = fieldInput.type.toLowerCase();
|
|
94
|
+
if (typeLower === 'list' || typeLower === 'array') {
|
|
95
|
+
console.error(`\nHint: To make a field a list/array, use isList="true" with a valid type:`);
|
|
96
|
+
console.error(` <field name="items" type="String" isList="true"/>`);
|
|
97
|
+
}
|
|
93
98
|
process.exit(1);
|
|
94
99
|
}
|
|
95
100
|
// Find entity and add field
|
|
@@ -102,6 +107,12 @@ export function addField(model, filePath, options, input) {
|
|
|
102
107
|
else if (options.readModel) {
|
|
103
108
|
addFieldToReadModel(model, filePath, options.readModel, fieldInput);
|
|
104
109
|
}
|
|
110
|
+
else if (options.screen) {
|
|
111
|
+
addFieldToScreen(model, filePath, options.screen, fieldInput);
|
|
112
|
+
}
|
|
113
|
+
else if (options.processor) {
|
|
114
|
+
addFieldToProcessor(model, filePath, options.processor, fieldInput);
|
|
115
|
+
}
|
|
105
116
|
}
|
|
106
117
|
function addFieldToCommand(model, filePath, commandName, fieldInput) {
|
|
107
118
|
const command = findElementOrExit(model.commands, commandName, 'command');
|
|
@@ -151,3 +162,35 @@ function addFieldToReadModel(model, filePath, readModelName, fieldInput) {
|
|
|
151
162
|
});
|
|
152
163
|
console.log(`Added field "${field.name}" to read model "${readModel.name}"`);
|
|
153
164
|
}
|
|
165
|
+
function addFieldToScreen(model, filePath, screenName, fieldInput) {
|
|
166
|
+
const screen = findElementOrExit(model.screens, screenName, 'screen');
|
|
167
|
+
// Check for duplicate field name
|
|
168
|
+
if (screen.fields.some(f => f.name.toLowerCase() === fieldInput.name.toLowerCase())) {
|
|
169
|
+
console.error(`Error: Field "${fieldInput.name}" already exists on screen "${screen.name}"`);
|
|
170
|
+
process.exit(1);
|
|
171
|
+
}
|
|
172
|
+
const field = createFieldFromInput(fieldInput);
|
|
173
|
+
appendEvent(filePath, {
|
|
174
|
+
type: 'ScreenFieldAdded',
|
|
175
|
+
screenId: screen.id,
|
|
176
|
+
field,
|
|
177
|
+
timestamp: Date.now(),
|
|
178
|
+
});
|
|
179
|
+
console.log(`Added field "${field.name}" to screen "${screen.name}"`);
|
|
180
|
+
}
|
|
181
|
+
function addFieldToProcessor(model, filePath, processorName, fieldInput) {
|
|
182
|
+
const processor = findElementOrExit(model.processors, processorName, 'processor');
|
|
183
|
+
// Check for duplicate field name
|
|
184
|
+
if (processor.fields.some(f => f.name.toLowerCase() === fieldInput.name.toLowerCase())) {
|
|
185
|
+
console.error(`Error: Field "${fieldInput.name}" already exists on processor "${processor.name}"`);
|
|
186
|
+
process.exit(1);
|
|
187
|
+
}
|
|
188
|
+
const field = createFieldFromInput(fieldInput);
|
|
189
|
+
appendEvent(filePath, {
|
|
190
|
+
type: 'ProcessorFieldAdded',
|
|
191
|
+
processorId: processor.id,
|
|
192
|
+
field,
|
|
193
|
+
timestamp: Date.now(),
|
|
194
|
+
});
|
|
195
|
+
console.log(`Added field "${field.name}" to processor "${processor.name}"`);
|
|
196
|
+
}
|
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import { outputJson } from '../../lib/format.js';
|
|
2
2
|
import { findElementOrExit } from '../../lib/element-lookup.js';
|
|
3
|
+
import { findChapterForSlice, getChapterHierarchy } from '../../lib/chapter-utils.js';
|
|
3
4
|
// Get components inside a slice by checking if center point is within bounds
|
|
4
5
|
function getSliceComponents(model, slice) {
|
|
5
6
|
const bounds = {
|
|
@@ -71,18 +72,6 @@ function findActorForScreen(model, screen) {
|
|
|
71
72
|
}
|
|
72
73
|
return undefined;
|
|
73
74
|
}
|
|
74
|
-
// Find which chapter contains a slice (based on horizontal center)
|
|
75
|
-
function findChapterForSlice(model, slice) {
|
|
76
|
-
const sliceCenterX = slice.position.x + slice.size.width / 2;
|
|
77
|
-
for (const chapter of model.chapters.values()) {
|
|
78
|
-
const chapterLeft = chapter.position.x;
|
|
79
|
-
const chapterRight = chapter.position.x + chapter.size.width;
|
|
80
|
-
if (sliceCenterX >= chapterLeft && sliceCenterX <= chapterRight) {
|
|
81
|
-
return chapter;
|
|
82
|
-
}
|
|
83
|
-
}
|
|
84
|
-
return null;
|
|
85
|
-
}
|
|
86
75
|
// Convert Field to JSON-friendly format
|
|
87
76
|
function fieldToJson(field) {
|
|
88
77
|
const result = {
|
|
@@ -351,7 +340,7 @@ export function codegenSlice(model, sliceName) {
|
|
|
351
340
|
id: slice.id,
|
|
352
341
|
name: slice.name,
|
|
353
342
|
},
|
|
354
|
-
...(chapter && { chapter:
|
|
343
|
+
...(chapter && { chapter: getChapterHierarchy(model, chapter) }),
|
|
355
344
|
elements: {
|
|
356
345
|
readModels: components.readModels.map(rm => ({
|
|
357
346
|
id: rm.id,
|
|
@@ -1,3 +1,3 @@
|
|
|
1
1
|
import type { EventModel } from '../../types.js';
|
|
2
2
|
import { type OutputFormat } from '../../lib/format.js';
|
|
3
|
-
export declare function listSlices(model: EventModel, format: OutputFormat): void;
|
|
3
|
+
export declare function listSlices(model: EventModel, format: OutputFormat, chapterName?: string): void;
|
|
@@ -1,9 +1,24 @@
|
|
|
1
1
|
import { escapeXml, outputJson } from '../../lib/format.js';
|
|
2
|
-
|
|
3
|
-
|
|
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
|
+
}
|
|
4
18
|
const sorted = [...slices].sort((a, b) => a.position.x - b.position.x);
|
|
5
19
|
if (format === 'json') {
|
|
6
20
|
outputJson({
|
|
21
|
+
...(chapterName && { chapter: chapterName }),
|
|
7
22
|
slices: sorted.map(s => ({ id: s.id, name: s.name, status: s.status }))
|
|
8
23
|
});
|
|
9
24
|
return;
|
|
@@ -2,13 +2,13 @@ import { appendEvent } from '../../lib/file-loader.js';
|
|
|
2
2
|
import { findElementOrExit } from '../../lib/element-lookup.js';
|
|
3
3
|
export function removeField(model, filePath, options, fieldName) {
|
|
4
4
|
// Determine which entity type
|
|
5
|
-
const entityCount = [options.command, options.event, options.readModel].filter(Boolean).length;
|
|
5
|
+
const entityCount = [options.command, options.event, options.readModel, options.screen, options.processor].filter(Boolean).length;
|
|
6
6
|
if (entityCount === 0) {
|
|
7
|
-
console.error('Error: Must specify one of --command, --event,
|
|
7
|
+
console.error('Error: Must specify one of --command, --event, --read-model, --screen, or --processor');
|
|
8
8
|
process.exit(1);
|
|
9
9
|
}
|
|
10
10
|
if (entityCount > 1) {
|
|
11
|
-
console.error('Error: Can only specify one of --command, --event,
|
|
11
|
+
console.error('Error: Can only specify one of --command, --event, --read-model, --screen, or --processor');
|
|
12
12
|
process.exit(1);
|
|
13
13
|
}
|
|
14
14
|
if (options.command) {
|
|
@@ -20,6 +20,12 @@ export function removeField(model, filePath, options, fieldName) {
|
|
|
20
20
|
else if (options.readModel) {
|
|
21
21
|
removeFieldFromReadModel(model, filePath, options.readModel, fieldName);
|
|
22
22
|
}
|
|
23
|
+
else if (options.screen) {
|
|
24
|
+
removeFieldFromScreen(model, filePath, options.screen, fieldName);
|
|
25
|
+
}
|
|
26
|
+
else if (options.processor) {
|
|
27
|
+
removeFieldFromProcessor(model, filePath, options.processor, fieldName);
|
|
28
|
+
}
|
|
23
29
|
}
|
|
24
30
|
function removeFieldFromCommand(model, filePath, commandName, fieldName) {
|
|
25
31
|
const command = findElementOrExit(model.commands, commandName, 'command');
|
|
@@ -96,3 +102,53 @@ function removeFieldFromReadModel(model, filePath, readModelName, fieldName) {
|
|
|
96
102
|
});
|
|
97
103
|
console.log(`Removed field "${field.name}" from read model "${readModel.name}"`);
|
|
98
104
|
}
|
|
105
|
+
function removeFieldFromScreen(model, filePath, screenName, fieldName) {
|
|
106
|
+
const screen = findElementOrExit(model.screens, screenName, 'screen');
|
|
107
|
+
const fieldNameLower = fieldName.toLowerCase();
|
|
108
|
+
const field = screen.fields.find(f => f.name.toLowerCase() === fieldNameLower);
|
|
109
|
+
if (!field) {
|
|
110
|
+
console.error(`Error: Field "${fieldName}" not found on screen "${screen.name}"`);
|
|
111
|
+
if (screen.fields.length > 0) {
|
|
112
|
+
console.error('Available fields:');
|
|
113
|
+
for (const f of screen.fields) {
|
|
114
|
+
console.error(` - ${f.name} (${f.fieldType})`);
|
|
115
|
+
}
|
|
116
|
+
}
|
|
117
|
+
else {
|
|
118
|
+
console.error('This screen has no fields.');
|
|
119
|
+
}
|
|
120
|
+
process.exit(1);
|
|
121
|
+
}
|
|
122
|
+
appendEvent(filePath, {
|
|
123
|
+
type: 'ScreenFieldRemoved',
|
|
124
|
+
screenId: screen.id,
|
|
125
|
+
fieldId: field.id,
|
|
126
|
+
timestamp: Date.now(),
|
|
127
|
+
});
|
|
128
|
+
console.log(`Removed field "${field.name}" from screen "${screen.name}"`);
|
|
129
|
+
}
|
|
130
|
+
function removeFieldFromProcessor(model, filePath, processorName, fieldName) {
|
|
131
|
+
const processor = findElementOrExit(model.processors, processorName, 'processor');
|
|
132
|
+
const fieldNameLower = fieldName.toLowerCase();
|
|
133
|
+
const field = processor.fields.find(f => f.name.toLowerCase() === fieldNameLower);
|
|
134
|
+
if (!field) {
|
|
135
|
+
console.error(`Error: Field "${fieldName}" not found on processor "${processor.name}"`);
|
|
136
|
+
if (processor.fields.length > 0) {
|
|
137
|
+
console.error('Available fields:');
|
|
138
|
+
for (const f of processor.fields) {
|
|
139
|
+
console.error(` - ${f.name} (${f.fieldType})`);
|
|
140
|
+
}
|
|
141
|
+
}
|
|
142
|
+
else {
|
|
143
|
+
console.error('This processor has no fields.');
|
|
144
|
+
}
|
|
145
|
+
process.exit(1);
|
|
146
|
+
}
|
|
147
|
+
appendEvent(filePath, {
|
|
148
|
+
type: 'ProcessorFieldRemoved',
|
|
149
|
+
processorId: processor.id,
|
|
150
|
+
fieldId: field.id,
|
|
151
|
+
timestamp: Date.now(),
|
|
152
|
+
});
|
|
153
|
+
console.log(`Removed field "${field.name}" from processor "${processor.name}"`);
|
|
154
|
+
}
|
|
@@ -1,5 +1,7 @@
|
|
|
1
1
|
import { escapeXml, outputJson } from '../../lib/format.js';
|
|
2
2
|
import { findElementOrExit } from '../../lib/element-lookup.js';
|
|
3
|
+
import { getChapterHierarchy, findChapterForSlice } from '../../lib/chapter-utils.js';
|
|
4
|
+
import { findSliceToSliceFlows, findChapterInboundFlows, findChapterOutboundFlows, } from '../../lib/flow-utils.js';
|
|
3
5
|
function getSlicesUnderChapter(model, chapter) {
|
|
4
6
|
// A slice is "under" a chapter if its horizontal center falls within the chapter's x range
|
|
5
7
|
const chapterLeft = chapter.position.x;
|
|
@@ -9,18 +11,149 @@ function getSlicesUnderChapter(model, chapter) {
|
|
|
9
11
|
return sliceCenterX >= chapterLeft && sliceCenterX <= chapterRight;
|
|
10
12
|
}).sort((a, b) => a.position.x - b.position.x);
|
|
11
13
|
}
|
|
14
|
+
function formatSliceFlowXml(sliceFlow) {
|
|
15
|
+
let xml = ` <slice-flow from="${escapeXml(sliceFlow.fromSlice.name)}" to="${escapeXml(sliceFlow.toSlice.name)}">\n`;
|
|
16
|
+
for (const flow of sliceFlow.flows) {
|
|
17
|
+
xml += ` <via type="${flow.flowType}">\n`;
|
|
18
|
+
xml += ` <source element="${escapeXml(flow.source.name)}" type="${flow.source.type}"/>\n`;
|
|
19
|
+
xml += ` <target element="${escapeXml(flow.target.name)}" type="${flow.target.type}"/>\n`;
|
|
20
|
+
if (flow.fieldMappings.length > 0) {
|
|
21
|
+
xml += ' <mappings>\n';
|
|
22
|
+
for (const mapping of flow.fieldMappings) {
|
|
23
|
+
xml += ` <map from="${escapeXml(mapping.from)}" to="${escapeXml(mapping.to)}"/>\n`;
|
|
24
|
+
}
|
|
25
|
+
xml += ' </mappings>\n';
|
|
26
|
+
}
|
|
27
|
+
xml += ' </via>\n';
|
|
28
|
+
}
|
|
29
|
+
xml += ' </slice-flow>\n';
|
|
30
|
+
return xml;
|
|
31
|
+
}
|
|
32
|
+
function formatExternalFlowXml(flow, direction, model) {
|
|
33
|
+
let xml = ` <flow ${direction === 'inbound' ? `to-slice="${escapeXml(flow.targetSlice?.name ?? 'unknown')}"` : `from-slice="${escapeXml(flow.sourceSlice?.name ?? 'unknown')}"`} type="${flow.flowType}">\n`;
|
|
34
|
+
// For inbound: source is external, for outbound: target is external
|
|
35
|
+
if (direction === 'inbound') {
|
|
36
|
+
// Find the chapter of the external source
|
|
37
|
+
const sourceSlice = flow.sourceSlice;
|
|
38
|
+
let chapterInfo = '';
|
|
39
|
+
if (sourceSlice) {
|
|
40
|
+
const sourceSliceObj = model.slices.get(sourceSlice.id);
|
|
41
|
+
if (sourceSliceObj) {
|
|
42
|
+
const sourceChapter = findChapterForSlice(model, sourceSliceObj);
|
|
43
|
+
if (sourceChapter) {
|
|
44
|
+
chapterInfo = ` chapter="${escapeXml(sourceChapter.name)}"`;
|
|
45
|
+
}
|
|
46
|
+
}
|
|
47
|
+
}
|
|
48
|
+
xml += ` <from external="true"${chapterInfo}>${escapeXml(flow.source.name)} (${flow.source.type})</from>\n`;
|
|
49
|
+
xml += ` <to>${escapeXml(flow.target.name)} (${flow.target.type})</to>\n`;
|
|
50
|
+
}
|
|
51
|
+
else {
|
|
52
|
+
xml += ` <from>${escapeXml(flow.source.name)} (${flow.source.type})</from>\n`;
|
|
53
|
+
// Find the chapter of the external target
|
|
54
|
+
const targetSlice = flow.targetSlice;
|
|
55
|
+
let chapterInfo = '';
|
|
56
|
+
if (targetSlice) {
|
|
57
|
+
const targetSliceObj = model.slices.get(targetSlice.id);
|
|
58
|
+
if (targetSliceObj) {
|
|
59
|
+
const targetChapter = findChapterForSlice(model, targetSliceObj);
|
|
60
|
+
if (targetChapter) {
|
|
61
|
+
chapterInfo = ` chapter="${escapeXml(targetChapter.name)}"`;
|
|
62
|
+
}
|
|
63
|
+
}
|
|
64
|
+
}
|
|
65
|
+
xml += ` <to external="true"${chapterInfo}>${escapeXml(flow.target.name)} (${flow.target.type})</to>\n`;
|
|
66
|
+
}
|
|
67
|
+
if (flow.fieldMappings.length > 0) {
|
|
68
|
+
xml += ' <mappings>\n';
|
|
69
|
+
for (const mapping of flow.fieldMappings) {
|
|
70
|
+
xml += ` <map from="${escapeXml(mapping.from)}" to="${escapeXml(mapping.to)}"/>\n`;
|
|
71
|
+
}
|
|
72
|
+
xml += ' </mappings>\n';
|
|
73
|
+
}
|
|
74
|
+
xml += ' </flow>\n';
|
|
75
|
+
return xml;
|
|
76
|
+
}
|
|
12
77
|
export function showChapter(model, name, format) {
|
|
13
78
|
const chapter = findElementOrExit(model.chapters, name, 'chapter');
|
|
14
79
|
const slices = getSlicesUnderChapter(model, chapter);
|
|
80
|
+
// Get flow information
|
|
81
|
+
const sliceToSliceFlows = findSliceToSliceFlows(model, slices);
|
|
82
|
+
const chapterInboundFlows = findChapterInboundFlows(model, slices);
|
|
83
|
+
const chapterOutboundFlows = findChapterOutboundFlows(model, slices);
|
|
15
84
|
if (format === 'json') {
|
|
16
|
-
|
|
85
|
+
const result = {
|
|
17
86
|
id: chapter.id,
|
|
18
87
|
name: chapter.name,
|
|
88
|
+
parent: chapter ? getChapterHierarchy(model, chapter).parent : undefined,
|
|
19
89
|
slices: slices.map(s => ({ id: s.id, name: s.name, status: s.status }))
|
|
20
|
-
}
|
|
90
|
+
};
|
|
91
|
+
// Add flow graph if there are slice-to-slice flows
|
|
92
|
+
if (sliceToSliceFlows.length > 0) {
|
|
93
|
+
result.flowGraph = sliceToSliceFlows.map(sf => ({
|
|
94
|
+
from: sf.fromSlice.name,
|
|
95
|
+
to: sf.toSlice.name,
|
|
96
|
+
flows: sf.flows.map(f => ({
|
|
97
|
+
type: f.flowType,
|
|
98
|
+
source: { element: f.source.name, type: f.source.type },
|
|
99
|
+
target: { element: f.target.name, type: f.target.type },
|
|
100
|
+
...(f.fieldMappings.length > 0 && {
|
|
101
|
+
mappings: f.fieldMappings.map(m => ({ from: m.from, to: m.to }))
|
|
102
|
+
})
|
|
103
|
+
}))
|
|
104
|
+
}));
|
|
105
|
+
}
|
|
106
|
+
// Add external dependencies
|
|
107
|
+
if (chapterInboundFlows.length > 0 || chapterOutboundFlows.length > 0) {
|
|
108
|
+
result.externalDependencies = {
|
|
109
|
+
...(chapterInboundFlows.length > 0 && {
|
|
110
|
+
inbound: chapterInboundFlows.map(f => {
|
|
111
|
+
const sourceSliceObj = f.sourceSlice ? model.slices.get(f.sourceSlice.id) : null;
|
|
112
|
+
const sourceChapter = sourceSliceObj ? findChapterForSlice(model, sourceSliceObj) : null;
|
|
113
|
+
return {
|
|
114
|
+
toSlice: f.targetSlice?.name,
|
|
115
|
+
type: f.flowType,
|
|
116
|
+
from: {
|
|
117
|
+
element: f.source.name,
|
|
118
|
+
type: f.source.type,
|
|
119
|
+
slice: f.sourceSlice?.name,
|
|
120
|
+
chapter: sourceChapter?.name
|
|
121
|
+
},
|
|
122
|
+
to: { element: f.target.name, type: f.target.type },
|
|
123
|
+
...(f.fieldMappings.length > 0 && {
|
|
124
|
+
mappings: f.fieldMappings.map(m => ({ from: m.from, to: m.to }))
|
|
125
|
+
})
|
|
126
|
+
};
|
|
127
|
+
})
|
|
128
|
+
}),
|
|
129
|
+
...(chapterOutboundFlows.length > 0 && {
|
|
130
|
+
outbound: chapterOutboundFlows.map(f => {
|
|
131
|
+
const targetSliceObj = f.targetSlice ? model.slices.get(f.targetSlice.id) : null;
|
|
132
|
+
const targetChapter = targetSliceObj ? findChapterForSlice(model, targetSliceObj) : null;
|
|
133
|
+
return {
|
|
134
|
+
fromSlice: f.sourceSlice?.name,
|
|
135
|
+
type: f.flowType,
|
|
136
|
+
from: { element: f.source.name, type: f.source.type },
|
|
137
|
+
to: {
|
|
138
|
+
element: f.target.name,
|
|
139
|
+
type: f.target.type,
|
|
140
|
+
slice: f.targetSlice?.name,
|
|
141
|
+
chapter: targetChapter?.name
|
|
142
|
+
},
|
|
143
|
+
...(f.fieldMappings.length > 0 && {
|
|
144
|
+
mappings: f.fieldMappings.map(m => ({ from: m.from, to: m.to }))
|
|
145
|
+
})
|
|
146
|
+
};
|
|
147
|
+
})
|
|
148
|
+
})
|
|
149
|
+
};
|
|
150
|
+
}
|
|
151
|
+
outputJson(result);
|
|
21
152
|
return;
|
|
22
153
|
}
|
|
154
|
+
// XML format
|
|
23
155
|
console.log(`<chapter id="${chapter.id}" name="${escapeXml(chapter.name)}">`);
|
|
156
|
+
// Slices section
|
|
24
157
|
if (slices.length === 0) {
|
|
25
158
|
console.log(' <slices/>');
|
|
26
159
|
}
|
|
@@ -31,5 +164,32 @@ export function showChapter(model, name, format) {
|
|
|
31
164
|
}
|
|
32
165
|
console.log(' </slices>');
|
|
33
166
|
}
|
|
167
|
+
// Flow graph section
|
|
168
|
+
if (sliceToSliceFlows.length > 0) {
|
|
169
|
+
console.log(' <flow-graph>');
|
|
170
|
+
for (const sliceFlow of sliceToSliceFlows) {
|
|
171
|
+
process.stdout.write(formatSliceFlowXml(sliceFlow));
|
|
172
|
+
}
|
|
173
|
+
console.log(' </flow-graph>');
|
|
174
|
+
}
|
|
175
|
+
// External dependencies section
|
|
176
|
+
if (chapterInboundFlows.length > 0 || chapterOutboundFlows.length > 0) {
|
|
177
|
+
console.log(' <external-dependencies>');
|
|
178
|
+
if (chapterInboundFlows.length > 0) {
|
|
179
|
+
console.log(' <inbound>');
|
|
180
|
+
for (const flow of chapterInboundFlows) {
|
|
181
|
+
process.stdout.write(formatExternalFlowXml(flow, 'inbound', model));
|
|
182
|
+
}
|
|
183
|
+
console.log(' </inbound>');
|
|
184
|
+
}
|
|
185
|
+
if (chapterOutboundFlows.length > 0) {
|
|
186
|
+
console.log(' <outbound>');
|
|
187
|
+
for (const flow of chapterOutboundFlows) {
|
|
188
|
+
process.stdout.write(formatExternalFlowXml(flow, 'outbound', model));
|
|
189
|
+
}
|
|
190
|
+
console.log(' </outbound>');
|
|
191
|
+
}
|
|
192
|
+
console.log(' </external-dependencies>');
|
|
193
|
+
}
|
|
34
194
|
console.log('</chapter>');
|
|
35
195
|
}
|