Creating first version of MCP server.
Some checks failed
CI Pipeline / Test and Build (20.x) (push) Failing after 3m22s
CI Pipeline / Code Quality Check (push) Failing after 11m52s
CI Pipeline / Security Audit (push) Failing after 11m53s
CI Pipeline / Test and Build (18.x) (push) Failing after 12m31s
CI Pipeline / Build Release Artifacts (push) Has been cancelled
CI Pipeline / Notification (push) Has been cancelled

This commit is contained in:
2025-07-22 07:11:59 +00:00
parent f10bf53522
commit bf088da9d5
38 changed files with 6398 additions and 9442 deletions

455
src/tools/create-diagram.ts Normal file
View File

@ -0,0 +1,455 @@
import { DiagramType, DiagramFormat, DiagramConfig } from '../types/diagram-types.js';
import { createFileConfig, createDiagramFile } from '../utils/file-manager.js';
import { generateDrawioXML } from '../utils/xml-parser.js';
import { generateLinearBPMNProcess, generateBPMNProcessWithGateway } from '../generators/bpmn-generator.js';
// Functional types
type CreateDiagramInput = Readonly<{
name: string;
type: DiagramType;
format?: DiagramFormat;
description?: string;
template?: string;
outputPath?: string;
workspaceRoot?: string;
// Specific parameters for different diagram types
tasks?: readonly string[];
entities?: readonly string[];
classes?: readonly string[];
components?: readonly string[];
processes?: readonly string[];
// BPMN specific
processName?: string;
gatewayType?: 'exclusive' | 'parallel';
branches?: readonly (readonly string[])[];
beforeGateway?: readonly string[];
afterGateway?: readonly string[];
}>;
type CreateDiagramResult = Readonly<{
success: boolean;
filePath?: string;
message: string;
diagramType: DiagramType;
format: DiagramFormat;
}>;
type DiagramGenerator = (input: CreateDiagramInput) => any;
type DiagramGeneratorMap = Readonly<Record<DiagramType, DiagramGenerator>>;
// Pure function to create successful result
const createSuccessResult = (
filePath: string,
diagramType: DiagramType,
format: DiagramFormat,
name: string
): CreateDiagramResult => ({
success: true,
filePath,
message: `Successfully created ${diagramType} diagram: ${name}`,
diagramType,
format
});
// Pure function to create error result
const createErrorResult = (
error: unknown,
diagramType: DiagramType,
format: DiagramFormat
): CreateDiagramResult => ({
success: false,
message: `Failed to create diagram: ${error}`,
diagramType,
format
});
// Higher-order function for diagram creation with error handling
const withDiagramErrorHandling = <T extends any[], R>(
operation: (...args: T) => Promise<R>
) => async (...args: T): Promise<R> => {
try {
return await operation(...args);
} catch (error) {
throw new Error(`Diagram creation failed: ${error}`);
}
};
// Pure function to generate BPMN diagram
const generateBPMNDiagram = (input: CreateDiagramInput) => {
const processName = input.processName || input.name;
const tasks = input.tasks || ['Task 1', 'Task 2', 'Task 3'];
if (input.branches && input.branches.length > 0) {
return generateBPMNProcessWithGateway(
processName,
Array.from(input.beforeGateway || []),
input.gatewayType || 'exclusive',
input.branches.map(branch => Array.from(branch)),
Array.from(input.afterGateway || [])
);
} else {
return generateLinearBPMNProcess(processName, Array.from(tasks));
}
};
// Pure function to generate UML Class diagram
const generateUMLClassDiagram = (input: CreateDiagramInput) => {
const classes = input.classes || ['Class1', 'Class2', 'Class3'];
return {
elements: classes.map((className, index) => ({
id: `class-${index}`,
type: 'uml-class',
label: className,
geometry: {
x: 100 + (index * 200),
y: 100,
width: 160,
height: 120
},
style: 'swimlane;fontStyle=1;align=center;verticalAlign=top;childLayout=stackLayout;horizontal=1;startSize=26;horizontalStack=0;resizeParent=1;resizeParentMax=0;resizeLast=0;collapsible=1;marginBottom=0;fillColor=#dae8fc;strokeColor=#6c8ebf;',
properties: { isClass: true }
})),
connections: [],
metadata: {
type: DiagramType.UML_CLASS,
format: DiagramFormat.DRAWIO,
created: new Date().toISOString(),
modified: new Date().toISOString(),
version: '1.0'
}
};
};
// Pure function to generate ER diagram
const generateERDiagram = (input: CreateDiagramInput) => {
const entities = input.entities || ['User', 'Order', 'Product'];
return {
elements: entities.map((entityName, index) => ({
id: `entity-${index}`,
type: 'er-entity',
label: entityName,
geometry: {
x: 100 + (index * 200),
y: 100,
width: 120,
height: 80
},
style: 'whiteSpace=wrap;html=1;align=center;treeFolding=1;treeMoving=1;newEdgeStyle={"edgeStyle":"entityRelationEdgeStyle","startArrow":"none","endArrow":"none","segment":10,"curved":1};fillColor=#e1d5e7;strokeColor=#9673a6;',
properties: { isEntity: true }
})),
connections: [],
metadata: {
type: DiagramType.ER_DIAGRAM,
format: DiagramFormat.DRAWIO,
created: new Date().toISOString(),
modified: new Date().toISOString(),
version: '1.0'
}
};
};
// Pure function to generate Network diagram
const generateNetworkDiagram = (input: CreateDiagramInput) => {
const components = input.components || ['Router', 'Switch', 'Server'];
return {
elements: components.map((componentName, index) => ({
id: `network-${index}`,
type: `network-${componentName.toLowerCase()}`,
label: componentName,
geometry: {
x: 100 + (index * 200),
y: 100,
width: 100,
height: 80
},
style: 'rounded=0;whiteSpace=wrap;html=1;fillColor=#f8cecc;strokeColor=#b85450;',
properties: { isNetworkComponent: true }
})),
connections: [],
metadata: {
type: DiagramType.NETWORK_TOPOLOGY,
format: DiagramFormat.DRAWIO,
created: new Date().toISOString(),
modified: new Date().toISOString(),
version: '1.0'
}
};
};
// Pure function to generate Architecture diagram
const generateArchitectureDiagram = (input: CreateDiagramInput) => {
const components = input.components || ['Frontend', 'API Gateway', 'Backend', 'Database'];
return {
elements: components.map((componentName, index) => ({
id: `arch-${index}`,
type: 'architecture-component',
label: componentName,
geometry: {
x: 100 + (index % 2) * 300,
y: 100 + Math.floor(index / 2) * 150,
width: 200,
height: 100
},
style: 'rounded=1;whiteSpace=wrap;html=1;fillColor=#dae8fc;strokeColor=#6c8ebf;',
properties: { isArchComponent: true }
})),
connections: [],
metadata: {
type: DiagramType.SYSTEM_ARCHITECTURE,
format: DiagramFormat.DRAWIO,
created: new Date().toISOString(),
modified: new Date().toISOString(),
version: '1.0'
}
};
};
// Pure function to generate Flowchart diagram
const generateFlowchartDiagram = (input: CreateDiagramInput) => {
const processes = input.processes || ['Start', 'Process 1', 'Decision', 'Process 2', 'End'];
return {
elements: processes.map((processName, index) => {
const isDecision = processName.toLowerCase().includes('decision');
const isStart = processName.toLowerCase().includes('start');
const isEnd = processName.toLowerCase().includes('end');
return {
id: `flow-${index}`,
type: isDecision ? 'diamond' : (isStart || isEnd ? 'ellipse' : 'rectangle'),
label: processName,
geometry: {
x: 100,
y: 100 + (index * 120),
width: isDecision ? 100 : 120,
height: isDecision ? 80 : 60
},
style: isDecision
? 'rhombus;whiteSpace=wrap;html=1;fillColor=#fff2cc;strokeColor=#d6b656;'
: isStart
? 'ellipse;whiteSpace=wrap;html=1;fillColor=#d5e8d4;strokeColor=#82b366;'
: isEnd
? 'ellipse;whiteSpace=wrap;html=1;fillColor=#f8cecc;strokeColor=#b85450;'
: 'rounded=0;whiteSpace=wrap;html=1;fillColor=#dae8fc;strokeColor=#6c8ebf;',
properties: { isFlowElement: true }
};
}),
connections: processes.slice(0, -1).map((_, index) => ({
id: `conn-${index}`,
source: `flow-${index}`,
target: `flow-${index + 1}`,
label: '',
style: 'edgeStyle=orthogonalEdgeStyle;rounded=0;orthogonalLoop=1;jettySize=auto;html=1;endArrow=classic;',
properties: {}
})),
metadata: {
type: DiagramType.FLOWCHART,
format: DiagramFormat.DRAWIO,
created: new Date().toISOString(),
modified: new Date().toISOString(),
version: '1.0'
}
};
};
// Pure function to generate basic diagram (fallback)
const generateBasicDiagram = (input: CreateDiagramInput) => {
return {
elements: [{
id: 'basic-1',
type: 'rectangle',
label: input.name,
geometry: {
x: 100,
y: 100,
width: 200,
height: 100
},
style: 'rounded=0;whiteSpace=wrap;html=1;fillColor=#dae8fc;strokeColor=#6c8ebf;',
properties: {}
}],
connections: [],
metadata: {
type: input.type,
format: DiagramFormat.DRAWIO,
created: new Date().toISOString(),
modified: new Date().toISOString(),
version: '1.0'
}
};
};
// Pure function to get diagram generator map
const getDiagramGeneratorMap = (): DiagramGeneratorMap => ({
[DiagramType.BPMN_PROCESS]: generateBPMNDiagram,
[DiagramType.BPMN_COLLABORATION]: generateBPMNDiagram,
[DiagramType.BPMN_CHOREOGRAPHY]: generateBPMNDiagram,
[DiagramType.UML_CLASS]: generateUMLClassDiagram,
[DiagramType.UML_SEQUENCE]: generateUMLClassDiagram,
[DiagramType.UML_USE_CASE]: generateUMLClassDiagram,
[DiagramType.UML_ACTIVITY]: generateUMLClassDiagram,
[DiagramType.UML_STATE]: generateUMLClassDiagram,
[DiagramType.UML_COMPONENT]: generateUMLClassDiagram,
[DiagramType.UML_DEPLOYMENT]: generateUMLClassDiagram,
[DiagramType.ER_DIAGRAM]: generateERDiagram,
[DiagramType.DATABASE_SCHEMA]: generateERDiagram,
[DiagramType.CONCEPTUAL_MODEL]: generateERDiagram,
[DiagramType.NETWORK_TOPOLOGY]: generateNetworkDiagram,
[DiagramType.INFRASTRUCTURE]: generateNetworkDiagram,
[DiagramType.CLOUD_ARCHITECTURE]: generateArchitectureDiagram,
[DiagramType.SYSTEM_ARCHITECTURE]: generateArchitectureDiagram,
[DiagramType.MICROSERVICES]: generateArchitectureDiagram,
[DiagramType.LAYERED_ARCHITECTURE]: generateArchitectureDiagram,
[DiagramType.C4_CONTEXT]: generateArchitectureDiagram,
[DiagramType.C4_CONTAINER]: generateArchitectureDiagram,
[DiagramType.C4_COMPONENT]: generateArchitectureDiagram,
[DiagramType.FLOWCHART]: generateFlowchartDiagram,
[DiagramType.ORGCHART]: generateBasicDiagram,
[DiagramType.MINDMAP]: generateBasicDiagram,
[DiagramType.WIREFRAME]: generateBasicDiagram,
[DiagramType.GANTT]: generateBasicDiagram
});
// Pure function to generate diagram data based on type and input
const generateDiagramData = (input: CreateDiagramInput) => {
const generatorMap = getDiagramGeneratorMap();
const generator = generatorMap[input.type] || generateBasicDiagram;
return generator(input);
};
// Main function to create a new diagram based on type and configuration
export const createDiagram = withDiagramErrorHandling(async (input: CreateDiagramInput): Promise<CreateDiagramResult> => {
try {
const config = createFileConfig(input.workspaceRoot);
const format = input.format || DiagramFormat.DRAWIO;
// Generate diagram data based on type
const diagramData = generateDiagramData(input);
// Convert to XML
const xmlContent = generateDrawioXML(diagramData);
// Create file
const createFile = createDiagramFile(config);
const filePath = await createFile(input.name)(xmlContent)(format)(input.outputPath);
return createSuccessResult(filePath, input.type, format, input.name);
} catch (error) {
return createErrorResult(error, input.type, input.format || DiagramFormat.DRAWIO);
}
});
// Pure function to validate create diagram input
export const validateCreateDiagramInput = (input: any): input is CreateDiagramInput => {
return (
typeof input === 'object' &&
input !== null &&
typeof input.name === 'string' &&
Object.values(DiagramType).includes(input.type)
);
};
// Pure function to get supported diagram types
export const getSupportedDiagramTypes = (): readonly DiagramType[] => {
return Object.values(DiagramType);
};
// Pure function to get diagram type descriptions
const getDiagramTypeDescriptions = (): Readonly<Record<DiagramType, string>> => ({
[DiagramType.BPMN_PROCESS]: 'Business Process Model and Notation diagram for modeling business processes',
[DiagramType.BPMN_COLLABORATION]: 'BPMN collaboration diagram showing interactions between participants',
[DiagramType.BPMN_CHOREOGRAPHY]: 'BPMN choreography diagram for modeling message exchanges',
[DiagramType.UML_CLASS]: 'UML Class diagram showing classes, attributes, methods, and relationships',
[DiagramType.UML_SEQUENCE]: 'UML Sequence diagram showing object interactions over time',
[DiagramType.UML_USE_CASE]: 'UML Use Case diagram showing system functionality and user interactions',
[DiagramType.UML_ACTIVITY]: 'UML Activity diagram showing workflow and business processes',
[DiagramType.UML_STATE]: 'UML State diagram showing object states and transitions',
[DiagramType.UML_COMPONENT]: 'UML Component diagram showing software components and dependencies',
[DiagramType.UML_DEPLOYMENT]: 'UML Deployment diagram showing hardware and software deployment',
[DiagramType.ER_DIAGRAM]: 'Entity-Relationship diagram for database design',
[DiagramType.DATABASE_SCHEMA]: 'Database schema diagram showing tables and relationships',
[DiagramType.CONCEPTUAL_MODEL]: 'Conceptual data model diagram',
[DiagramType.NETWORK_TOPOLOGY]: 'Network topology diagram showing network infrastructure',
[DiagramType.INFRASTRUCTURE]: 'Infrastructure diagram showing system components',
[DiagramType.CLOUD_ARCHITECTURE]: 'Cloud architecture diagram showing cloud services and components',
[DiagramType.SYSTEM_ARCHITECTURE]: 'System architecture diagram showing high-level system design',
[DiagramType.MICROSERVICES]: 'Microservices architecture diagram',
[DiagramType.LAYERED_ARCHITECTURE]: 'Layered architecture diagram showing application layers',
[DiagramType.C4_CONTEXT]: 'C4 Context diagram showing system context',
[DiagramType.C4_CONTAINER]: 'C4 Container diagram showing application containers',
[DiagramType.C4_COMPONENT]: 'C4 Component diagram showing component details',
[DiagramType.FLOWCHART]: 'Flowchart diagram showing process flow',
[DiagramType.ORGCHART]: 'Organizational chart showing hierarchy',
[DiagramType.MINDMAP]: 'Mind map diagram for brainstorming and organizing ideas',
[DiagramType.WIREFRAME]: 'Wireframe diagram for UI/UX design',
[DiagramType.GANTT]: 'Gantt chart for project management and scheduling'
});
// Pure function to get description for a specific diagram type
export const getDiagramTypeDescription = (diagramType: DiagramType): string => {
const descriptions = getDiagramTypeDescriptions();
return descriptions[diagramType] || 'Generic diagram type';
};
// Utility functions for functional composition
export const pipe = <T>(...fns: Array<(arg: T) => T>) => (value: T): T =>
fns.reduce((acc, fn) => fn(acc), value);
export const compose = <T>(...fns: Array<(arg: T) => T>) => (value: T): T =>
fns.reduceRight((acc, fn) => fn(acc), value);
// Higher-order function for operations with retry logic
export const withRetry = <T extends any[], R>(
operation: (...args: T) => Promise<R>,
maxRetries: number = 3,
delay: number = 1000
) => async (...args: T): Promise<R> => {
let lastError: Error;
for (let attempt = 1; attempt <= maxRetries; attempt++) {
try {
return await operation(...args);
} catch (error) {
lastError = error as Error;
if (attempt === maxRetries) break;
await new Promise(resolve => setTimeout(resolve, delay * attempt));
}
}
throw lastError!;
};
// Functional diagram creation with retry
export const createDiagramWithRetry = withRetry(createDiagram);
// Pure function to create diagram configuration
export const createDiagramConfig = (
name: string,
type: DiagramType,
options: Partial<CreateDiagramInput> = {}
): CreateDiagramInput => ({
name,
type,
format: DiagramFormat.DRAWIO,
...options
});
// Higher-order function to transform diagram input
export const transformDiagramInput = <T>(
transformer: (input: CreateDiagramInput) => T
) => (input: CreateDiagramInput): T => transformer(input);
// Pure function to merge diagram inputs
export const mergeDiagramInputs = (
base: CreateDiagramInput,
additional: Partial<CreateDiagramInput>
): CreateDiagramInput => ({
...base,
...additional
});