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}"
|