Spaces:
Running
Running
Update class_diagram_generator.py
Browse files- class_diagram_generator.py +8 -32
class_diagram_generator.py
CHANGED
@@ -486,20 +486,17 @@ def generate_class_diagram(json_input: str, output_format: str) -> str:
|
|
486 |
{
|
487 |
"from": "Car",
|
488 |
"to": "Vehicle",
|
489 |
-
"type": "inheritance"
|
490 |
-
"label": "extends"
|
491 |
},
|
492 |
{
|
493 |
"from": "Motorcycle",
|
494 |
"to": "Vehicle",
|
495 |
-
"type": "inheritance"
|
496 |
-
"label": "extends"
|
497 |
},
|
498 |
{
|
499 |
"from": "Car",
|
500 |
"to": "Engine",
|
501 |
"type": "composition",
|
502 |
-
"label": "has",
|
503 |
"multiplicity_from": "1",
|
504 |
"multiplicity_to": "1"
|
505 |
},
|
@@ -507,7 +504,6 @@ def generate_class_diagram(json_input: str, output_format: str) -> str:
|
|
507 |
"from": "Motorcycle",
|
508 |
"to": "Engine",
|
509 |
"type": "composition",
|
510 |
-
"label": "has",
|
511 |
"multiplicity_from": "1",
|
512 |
"multiplicity_to": "1"
|
513 |
},
|
@@ -515,7 +511,6 @@ def generate_class_diagram(json_input: str, output_format: str) -> str:
|
|
515 |
"from": "Car",
|
516 |
"to": "TransmissionType",
|
517 |
"type": "association",
|
518 |
-
"label": "uses",
|
519 |
"multiplicity_from": "1",
|
520 |
"multiplicity_to": "1"
|
521 |
},
|
@@ -523,21 +518,18 @@ def generate_class_diagram(json_input: str, output_format: str) -> str:
|
|
523 |
"from": "Vehicle",
|
524 |
"to": "FuelType",
|
525 |
"type": "association",
|
526 |
-
"label": "uses",
|
527 |
"multiplicity_from": "1",
|
528 |
"multiplicity_to": "1"
|
529 |
},
|
530 |
{
|
531 |
"from": "GarageService",
|
532 |
"to": "VehicleService",
|
533 |
-
"type": "realization"
|
534 |
-
"label": "implements"
|
535 |
},
|
536 |
{
|
537 |
"from": "GarageService",
|
538 |
"to": "Vehicle",
|
539 |
"type": "dependency",
|
540 |
-
"label": "services",
|
541 |
"multiplicity_from": "1",
|
542 |
"multiplicity_to": "*"
|
543 |
}
|
@@ -556,7 +548,6 @@ def generate_class_diagram(json_input: str, output_format: str) -> str:
|
|
556 |
if 'classes' not in data:
|
557 |
raise ValueError("Missing required field: classes")
|
558 |
|
559 |
-
# Configuración del diagrama usando la misma estrategia exitosa del mapa conceptual
|
560 |
dot = graphviz.Digraph(comment='Class Diagram')
|
561 |
dot.attr(rankdir='TB', bgcolor='white', pad='0.5', nodesep='0.8', ranksep='1.2', splines='ortho')
|
562 |
dot.attr('node', shape='plaintext', fontname='Arial', fontsize='11')
|
@@ -574,10 +565,8 @@ def generate_class_diagram(json_input: str, output_format: str) -> str:
|
|
574 |
if not class_name:
|
575 |
continue
|
576 |
|
577 |
-
# Crear tabla HTML para estructura de clase
|
578 |
html_label = '<TABLE BORDER="1" CELLBORDER="0" CELLSPACING="0" CELLPADDING="5" BGCOLOR="white">'
|
579 |
|
580 |
-
# Header con nombre de clase y estereotipo
|
581 |
if class_type == 'abstract':
|
582 |
html_label += f'<TR><TD ALIGN="CENTER"><B><<abstract>><BR/>{class_name}</B></TD></TR>'
|
583 |
elif class_type == 'interface':
|
@@ -587,10 +576,8 @@ def generate_class_diagram(json_input: str, output_format: str) -> str:
|
|
587 |
else:
|
588 |
html_label += f'<TR><TD ALIGN="CENTER"><B>{class_name}</B></TD></TR>'
|
589 |
|
590 |
-
# Línea separadora después del nombre
|
591 |
html_label += '<HR/>'
|
592 |
|
593 |
-
# Sección de atributos
|
594 |
if attributes:
|
595 |
for attr in attributes:
|
596 |
visibility = attr.get('visibility', '+')
|
@@ -602,17 +589,14 @@ def generate_class_diagram(json_input: str, output_format: str) -> str:
|
|
602 |
if attr_type:
|
603 |
line += f" : {attr_type}"
|
604 |
if is_static:
|
605 |
-
line = f"<U>{line}</U>"
|
606 |
|
607 |
html_label += f'<TR><TD ALIGN="LEFT">{line}</TD></TR>'
|
608 |
else:
|
609 |
-
# Espacio vacío si no hay atributos
|
610 |
html_label += '<TR><TD ALIGN="LEFT"> </TD></TR>'
|
611 |
|
612 |
-
# Línea separadora entre atributos y métodos
|
613 |
html_label += '<HR/>'
|
614 |
|
615 |
-
# Sección de métodos
|
616 |
if methods:
|
617 |
for method in methods:
|
618 |
visibility = method.get('visibility', '+')
|
@@ -633,21 +617,18 @@ def generate_class_diagram(json_input: str, output_format: str) -> str:
|
|
633 |
line += f") : {return_type}"
|
634 |
|
635 |
if is_static:
|
636 |
-
line = f"<U>{line}</U>"
|
637 |
if is_abstract:
|
638 |
-
line = f"<I>{line}</I>"
|
639 |
|
640 |
html_label += f'<TR><TD ALIGN="LEFT">{line}</TD></TR>'
|
641 |
else:
|
642 |
-
# Espacio vacío si no hay métodos
|
643 |
html_label += '<TR><TD ALIGN="LEFT"> </TD></TR>'
|
644 |
|
645 |
html_label += '</TABLE>'
|
646 |
|
647 |
-
# Agregar nodo con la tabla HTML
|
648 |
dot.node(class_name, f'<{html_label}>')
|
649 |
|
650 |
-
# Procesar relaciones con líneas rectas
|
651 |
for relationship in relationships:
|
652 |
from_class = relationship.get('from')
|
653 |
to_class = relationship.get('to')
|
@@ -660,19 +641,15 @@ def generate_class_diagram(json_input: str, output_format: str) -> str:
|
|
660 |
continue
|
661 |
|
662 |
edge_attrs = {
|
663 |
-
'color': 'black'
|
664 |
}
|
665 |
|
666 |
-
if label:
|
667 |
-
edge_attrs['label'] = label
|
668 |
-
|
669 |
if multiplicity_from:
|
670 |
edge_attrs['taillabel'] = multiplicity_from
|
671 |
|
672 |
if multiplicity_to:
|
673 |
edge_attrs['headlabel'] = multiplicity_to
|
674 |
|
675 |
-
# Configurar estilos de flecha según el tipo de relación
|
676 |
if rel_type == 'inheritance':
|
677 |
edge_attrs['arrowhead'] = 'empty'
|
678 |
edge_attrs['color'] = 'black'
|
@@ -694,13 +671,12 @@ def generate_class_diagram(json_input: str, output_format: str) -> str:
|
|
694 |
edge_attrs['arrowhead'] = 'normal'
|
695 |
edge_attrs['style'] = 'dashed'
|
696 |
edge_attrs['color'] = 'black'
|
697 |
-
else:
|
698 |
edge_attrs['arrowhead'] = 'normal'
|
699 |
edge_attrs['color'] = 'black'
|
700 |
|
701 |
dot.edge(from_class, to_class, **edge_attrs)
|
702 |
|
703 |
-
# Renderizar el diagrama
|
704 |
with NamedTemporaryFile(delete=False, suffix=f'.{output_format}') as tmp:
|
705 |
dot.render(tmp.name, format=output_format, cleanup=True)
|
706 |
return f"{tmp.name}.{output_format}"
|
|
|
486 |
{
|
487 |
"from": "Car",
|
488 |
"to": "Vehicle",
|
489 |
+
"type": "inheritance"
|
|
|
490 |
},
|
491 |
{
|
492 |
"from": "Motorcycle",
|
493 |
"to": "Vehicle",
|
494 |
+
"type": "inheritance"
|
|
|
495 |
},
|
496 |
{
|
497 |
"from": "Car",
|
498 |
"to": "Engine",
|
499 |
"type": "composition",
|
|
|
500 |
"multiplicity_from": "1",
|
501 |
"multiplicity_to": "1"
|
502 |
},
|
|
|
504 |
"from": "Motorcycle",
|
505 |
"to": "Engine",
|
506 |
"type": "composition",
|
|
|
507 |
"multiplicity_from": "1",
|
508 |
"multiplicity_to": "1"
|
509 |
},
|
|
|
511 |
"from": "Car",
|
512 |
"to": "TransmissionType",
|
513 |
"type": "association",
|
|
|
514 |
"multiplicity_from": "1",
|
515 |
"multiplicity_to": "1"
|
516 |
},
|
|
|
518 |
"from": "Vehicle",
|
519 |
"to": "FuelType",
|
520 |
"type": "association",
|
|
|
521 |
"multiplicity_from": "1",
|
522 |
"multiplicity_to": "1"
|
523 |
},
|
524 |
{
|
525 |
"from": "GarageService",
|
526 |
"to": "VehicleService",
|
527 |
+
"type": "realization"
|
|
|
528 |
},
|
529 |
{
|
530 |
"from": "GarageService",
|
531 |
"to": "Vehicle",
|
532 |
"type": "dependency",
|
|
|
533 |
"multiplicity_from": "1",
|
534 |
"multiplicity_to": "*"
|
535 |
}
|
|
|
548 |
if 'classes' not in data:
|
549 |
raise ValueError("Missing required field: classes")
|
550 |
|
|
|
551 |
dot = graphviz.Digraph(comment='Class Diagram')
|
552 |
dot.attr(rankdir='TB', bgcolor='white', pad='0.5', nodesep='0.8', ranksep='1.2', splines='ortho')
|
553 |
dot.attr('node', shape='plaintext', fontname='Arial', fontsize='11')
|
|
|
565 |
if not class_name:
|
566 |
continue
|
567 |
|
|
|
568 |
html_label = '<TABLE BORDER="1" CELLBORDER="0" CELLSPACING="0" CELLPADDING="5" BGCOLOR="white">'
|
569 |
|
|
|
570 |
if class_type == 'abstract':
|
571 |
html_label += f'<TR><TD ALIGN="CENTER"><B><<abstract>><BR/>{class_name}</B></TD></TR>'
|
572 |
elif class_type == 'interface':
|
|
|
576 |
else:
|
577 |
html_label += f'<TR><TD ALIGN="CENTER"><B>{class_name}</B></TD></TR>'
|
578 |
|
|
|
579 |
html_label += '<HR/>'
|
580 |
|
|
|
581 |
if attributes:
|
582 |
for attr in attributes:
|
583 |
visibility = attr.get('visibility', '+')
|
|
|
589 |
if attr_type:
|
590 |
line += f" : {attr_type}"
|
591 |
if is_static:
|
592 |
+
line = f"<U>{line}</U>"
|
593 |
|
594 |
html_label += f'<TR><TD ALIGN="LEFT">{line}</TD></TR>'
|
595 |
else:
|
|
|
596 |
html_label += '<TR><TD ALIGN="LEFT"> </TD></TR>'
|
597 |
|
|
|
598 |
html_label += '<HR/>'
|
599 |
|
|
|
600 |
if methods:
|
601 |
for method in methods:
|
602 |
visibility = method.get('visibility', '+')
|
|
|
617 |
line += f") : {return_type}"
|
618 |
|
619 |
if is_static:
|
620 |
+
line = f"<U>{line}</U>"
|
621 |
if is_abstract:
|
622 |
+
line = f"<I>{line}</I>"
|
623 |
|
624 |
html_label += f'<TR><TD ALIGN="LEFT">{line}</TD></TR>'
|
625 |
else:
|
|
|
626 |
html_label += '<TR><TD ALIGN="LEFT"> </TD></TR>'
|
627 |
|
628 |
html_label += '</TABLE>'
|
629 |
|
|
|
630 |
dot.node(class_name, f'<{html_label}>')
|
631 |
|
|
|
632 |
for relationship in relationships:
|
633 |
from_class = relationship.get('from')
|
634 |
to_class = relationship.get('to')
|
|
|
641 |
continue
|
642 |
|
643 |
edge_attrs = {
|
644 |
+
'color': 'black'
|
645 |
}
|
646 |
|
|
|
|
|
|
|
647 |
if multiplicity_from:
|
648 |
edge_attrs['taillabel'] = multiplicity_from
|
649 |
|
650 |
if multiplicity_to:
|
651 |
edge_attrs['headlabel'] = multiplicity_to
|
652 |
|
|
|
653 |
if rel_type == 'inheritance':
|
654 |
edge_attrs['arrowhead'] = 'empty'
|
655 |
edge_attrs['color'] = 'black'
|
|
|
671 |
edge_attrs['arrowhead'] = 'normal'
|
672 |
edge_attrs['style'] = 'dashed'
|
673 |
edge_attrs['color'] = 'black'
|
674 |
+
else:
|
675 |
edge_attrs['arrowhead'] = 'normal'
|
676 |
edge_attrs['color'] = 'black'
|
677 |
|
678 |
dot.edge(from_class, to_class, **edge_attrs)
|
679 |
|
|
|
680 |
with NamedTemporaryFile(delete=False, suffix=f'.{output_format}') as tmp:
|
681 |
dot.render(tmp.name, format=output_format, cleanup=True)
|
682 |
return f"{tmp.name}.{output_format}"
|