diff --git a/capella_diff_tools/compare.py b/capella_diff_tools/compare.py
index 8824268..3df7c32 100644
--- a/capella_diff_tools/compare.py
+++ b/capella_diff_tools/compare.py
@@ -142,7 +142,6 @@ def compare_all_objects(
changes = _compare_object_type(old_layerobjs, new_layerobjs)
if changes:
result.setdefault(layer, {})[obj_type] = changes
-
return result
@@ -197,11 +196,27 @@ def _obj2dict(obj: c.GenericElement) -> types.FullObject:
attributes: dict[str, t.Any] = {}
for attr in dir(type(obj)):
acc = getattr(type(obj), attr, None)
- if isinstance(acc, c.AttributeProperty):
- val = getattr(obj, attr)
- if val is None:
- continue
- attributes[attr] = _serialize_obj(val)
+ if not isinstance(acc, c.AttributeProperty) and attr not in [
+ "parent",
+ "source",
+ "target",
+ "start",
+ "finish",
+ ]:
+ continue
+
+ val = getattr(obj, attr)
+ if val is None:
+ continue
+ attributes[attr] = _serialize_obj(val)
+
+ if hasattr(obj, "source") and hasattr(obj, "target"):
+ attributes["source"] = _serialize_obj(obj.source)
+ attributes["target"] = _serialize_obj(obj.target)
+ elif hasattr(obj, "start") and hasattr(obj, "finish"):
+ attributes["start"] = _serialize_obj(obj.start)
+ attributes["finish"] = _serialize_obj(obj.finish)
+
return {
"uuid": obj.uuid,
"display_name": _get_name(obj),
@@ -222,9 +237,12 @@ def _obj2diff(
"""
attributes: dict[str, types.ChangedAttribute] = {}
for attr in dir(type(old)):
- if not isinstance(
- getattr(type(old), attr, None),
- (c.AttributeProperty, c.AttrProxyAccessor, c.LinkAccessor),
+ if (
+ not isinstance(
+ getattr(type(old), attr, None),
+ (c.AttributeProperty, c.AttrProxyAccessor, c.LinkAccessor),
+ )
+ and attr != "parent"
):
continue
diff --git a/capella_diff_tools/report.html.jinja b/capella_diff_tools/report.html.jinja
index d033e67..ea96a54 100644
--- a/capella_diff_tools/report.html.jinja
+++ b/capella_diff_tools/report.html.jinja
@@ -34,6 +34,16 @@
.created, ins {
color: #00aa00;
}
+ .text-removed, del > p {
+ background: #ffe6e6;
+ text-decoration: none;
+ display: inline;
+ }
+ .text-added, ins > p {
+ background: #e6ffe6;
+ text-decoration: none;
+ display: inline;
+ }
/* nice table style with borders, bold th*/
table {
border-collapse: collapse;
@@ -109,11 +119,35 @@
{% if key in objects %}
{{key | upper}} ({{ objects[key] | length }})
-
- {% for obj in objects[key] %}
- - {{obj["display_name"] | e}}
+ {% set parent_dict = {} %}
+ {% for obj in objects[key] %}
+ {% if "parent" in obj["attributes"] %}
+ {% set parent_name = obj["attributes"]["parent"]["display_name"] %}
+ {% set display_name = obj["display_name"] %}
+ {% if parent_name in parent_dict %}
+ {% set _ = parent_dict[parent_name].append(obj) %}
+ {% else %}
+ {% set _ = parent_dict.update({parent_name: [obj]}) %}
+ {% endif %}
+ {% endif %}
+ {% endfor %}
+ {% if parent_dict %}
+ {% for parent, children in parent_dict.items() %}
+ {{ parent | e }}
+
+ {% for child in children %}
+ - {{ child.display_name | e }}
+
+ {% for key, value in child.attributes.items() %}
+ {% if key in ["start", "finish", "source", "target"] %}
+ - {{ key | e }}: {{ value.display_name | e }}
+ {% endif %}
+ {% endfor %}
+
+ {% endfor %}
+
{% endfor %}
-
+ {% endif %}
{% endif %}
{% endmacro %}
@@ -132,9 +166,14 @@
{% for change in obj["attributes"] %}
{{ change }}:
{% if "diff" in obj["attributes"][change] %}
- {{ obj["attributes"][change]["diff"] }}
- {% else %}
- {{ obj["attributes"][change]["previous"] | e }} -> {{ obj["attributes"][change]["current"] | e }}
+ {% if change == "description" %}
+
+ - Previous: {{ obj["attributes"][change]["previous"] | safe }}
+ - Current: {{ obj["attributes"][change]["current"] | safe }}
+
+ {% else %}
+ {{ obj["attributes"][change]["diff"] }}
+ {% endif %}
{% endif %}
{% endfor %}
diff --git a/capella_diff_tools/report.py b/capella_diff_tools/report.py
index e3af53a..71b9ff2 100644
--- a/capella_diff_tools/report.py
+++ b/capella_diff_tools/report.py
@@ -52,7 +52,7 @@ def _diff_lists(previous, current):
previous = {item["uuid"]: item for item in previous}
for item in current:
if item["uuid"] not in previous:
- out.append(f"{item}")
+ out.append(f"{item['display_name']}")
elif item["uuid"] in previous:
if item["display_name"] != previous[item["uuid"]]["display_name"]:
out.append(
@@ -96,7 +96,13 @@ def _traverse_and_diff(data):
elif prev_type == curr_type == list:
diff = _diff_lists(value["previous"], value["current"])
updates[key] = {"diff": diff}
-
+ elif key == "description":
+ prev, curr = _diff_description(
+ value["previous"].splitlines(),
+ value["current"].splitlines(),
+ )
+ updates[key] = {"diff": ""}
+ value.update({"previous": prev, "current": curr})
elif isinstance(value, list):
for item in value:
_traverse_and_diff(item)
@@ -107,6 +113,23 @@ def _traverse_and_diff(data):
return data
+def _diff_description(previous, current):
+ dmp = diff_match_patch.diff_match_patch()
+ diff = dmp.diff_main("\n".join(previous), "\n".join(current))
+ dmp.diff_cleanupSemantic(diff)
+ previous_result = ""
+ current_result = ""
+ for operation, text in diff:
+ if operation == 0:
+ previous_result += text
+ current_result += text
+ elif operation == -1:
+ previous_result += f"{text}"
+ elif operation == 1:
+ current_result += f"{text}"
+ return previous_result, current_result
+
+
def _compute_diff_stats(data):
"""Compute the diff stats for the data.
diff --git a/pyproject.toml b/pyproject.toml
index 83f7a21..2bdb478 100644
--- a/pyproject.toml
+++ b/pyproject.toml
@@ -27,7 +27,7 @@ classifiers = [
"Programming Language :: Python :: 3.12",
]
dependencies = [
- "capellambse>=0.5.39,<0.6",
+ "capellambse>=0.5.70,<0.6",
"click",
"diff-match-patch>=20230430",
"jinja2>=3.1.2",