Skip to content

Commit 7b45145

Browse files
committed
feat(backend/sdoc_source_code): Support merge by MID
Until now, finding a static merge candidate for source nodes relied on having a UID field set at source code side. Now we can also use MIDs for this purpose.
1 parent 041386b commit 7b45145

File tree

1 file changed

+74
-9
lines changed

1 file changed

+74
-9
lines changed

strictdoc/core/file_traceability_index.py

Lines changed: 74 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -47,6 +47,7 @@
4747
from strictdoc.helpers.cast import assert_cast
4848
from strictdoc.helpers.exception import StrictDocException
4949
from strictdoc.helpers.google_test import convert_function_name_to_gtest_macro
50+
from strictdoc.helpers.mid import MID
5051
from strictdoc.helpers.ordered_set import OrderedSet
5152

5253
if TYPE_CHECKING:
@@ -608,15 +609,50 @@ def validate_and_resolve(
608609
continue
609610

610611
assert source_node_.entity_name is not None
612+
sdoc_node = None
611613
sdoc_node_uid = source_node_.get_sdoc_field(
612614
"UID", relevant_source_node_entry
613615
)
614-
if sdoc_node_uid is None:
615-
sdoc_node_uid = f"{document_uid}/{path_to_source_file_}/{source_node_.entity_name}"
616-
sdoc_node = traceability_index.get_node_by_uid_weak(
617-
sdoc_node_uid
616+
mid = source_node_.get_sdoc_field(
617+
"MID", relevant_source_node_entry
618618
)
619619

620+
# First merge criterion: Merge if SDoc node with same MID exists.
621+
if mid is not None:
622+
sdoc_node_mid = MID(mid)
623+
merge_candidate_sdoc_node = (
624+
traceability_index.get_node_by_mid_weak(sdoc_node_mid)
625+
)
626+
if merge_candidate_sdoc_node is not None:
627+
merge_candidate_sdoc_node = assert_cast(
628+
merge_candidate_sdoc_node, SDocNode
629+
)
630+
# Simplification: Either SDoc must have a static UID that is not overwritten by source node.
631+
if (
632+
merge_candidate_sdoc_node.reserved_uid is not None
633+
and (
634+
merge_candidate_sdoc_node.reserved_uid
635+
== sdoc_node_uid
636+
or sdoc_node_uid is None
637+
)
638+
):
639+
sdoc_node_uid = (
640+
merge_candidate_sdoc_node.reserved_uid
641+
)
642+
sdoc_node = merge_candidate_sdoc_node
643+
644+
if sdoc_node is None:
645+
# If no UID from source code field or merge-by-MID, create UID by conventional scheme.
646+
if sdoc_node_uid is None:
647+
sdoc_node_uid = f"{document_uid}/{path_to_source_file_}/{source_node_.entity_name}"
648+
# Second merge criterion: Merge if SDoc node with same UID exists.
649+
tmp_sdoc_node = traceability_index.get_node_by_uid_weak(
650+
sdoc_node_uid
651+
)
652+
if isinstance(tmp_sdoc_node, SDocNode):
653+
sdoc_node = tmp_sdoc_node
654+
655+
assert sdoc_node_uid is not None
620656
if sdoc_node is not None:
621657
sdoc_node = assert_cast(sdoc_node, SDocNode)
622658
self.merge_sdoc_node_with_source_node(
@@ -633,11 +669,6 @@ def validate_and_resolve(
633669
document,
634670
)
635671
sdoc_node_uid = assert_cast(sdoc_node.reserved_uid, str)
636-
traceability_index.graph_database.create_link(
637-
link_type=GraphLinkType.UID_TO_NODE,
638-
lhs_node=sdoc_node_uid,
639-
rhs_node=sdoc_node,
640-
)
641672
if current_top_node is None:
642673
current_top_node = (
643674
FileTraceabilityIndex.create_source_node_section(
@@ -971,6 +1002,11 @@ def create_sdoc_node_from_source_node(
9711002
):
9721003
sdoc_node_fields["TITLE"] = source_node.entity_name
9731004
FileTraceabilityIndex.set_sdoc_node_fields(sdoc_node, sdoc_node_fields)
1005+
if "MID" in sdoc_node_fields:
1006+
mid = sdoc_node_fields["MID"]
1007+
sdoc_node.reserved_mid = MID(mid)
1008+
if parent_document.config.enable_mid:
1009+
sdoc_node.mid_permanent = True
9741010
return sdoc_node
9751011

9761012
@staticmethod
@@ -1007,6 +1043,10 @@ def merge_sdoc_node_with_source_node(
10071043
sdoc_node_fields = source_node.get_sdoc_fields(source_node_config_entry)
10081044
FileTraceabilityIndex.set_sdoc_node_fields(sdoc_node, sdoc_node_fields)
10091045

1046+
if "MID" in sdoc_node_fields:
1047+
mid = sdoc_node_fields["MID"]
1048+
sdoc_node.reserved_mid = MID(mid)
1049+
10101050
@staticmethod
10111051
def set_sdoc_node_fields(
10121052
sdoc_node: SDocNode, sdoc_node_fields: dict[str, str]
@@ -1088,6 +1128,31 @@ def connect_source_node_requirements(
10881128
10891129
Here we link REQ and sdoc_node bidirectional.
10901130
"""
1131+
if (
1132+
sdoc_node.reserved_uid is not None
1133+
and not traceability_index.graph_database.has_link(
1134+
link_type=GraphLinkType.UID_TO_NODE,
1135+
lhs_node=sdoc_node.reserved_uid,
1136+
rhs_node=sdoc_node,
1137+
)
1138+
):
1139+
traceability_index.graph_database.create_link(
1140+
link_type=GraphLinkType.UID_TO_NODE,
1141+
lhs_node=sdoc_node.reserved_uid,
1142+
rhs_node=sdoc_node,
1143+
)
1144+
1145+
if not traceability_index.graph_database.has_link(
1146+
link_type=GraphLinkType.MID_TO_NODE,
1147+
lhs_node=sdoc_node.reserved_mid,
1148+
rhs_node=sdoc_node,
1149+
):
1150+
traceability_index.graph_database.create_link(
1151+
link_type=GraphLinkType.MID_TO_NODE,
1152+
lhs_node=sdoc_node.reserved_mid,
1153+
rhs_node=sdoc_node,
1154+
)
1155+
10911156
for marker_ in source_node.markers:
10921157
if not isinstance(marker_, FunctionRangeMarker):
10931158
continue

0 commit comments

Comments
 (0)