Skip to content

Commit 041386b

Browse files
authored
Merge pull request #2548 from haxtibal/tdmg/source_node_section_only_where_needed
fix(backend/sdoc_source_code): Don't auto-generate sections for merged source nodes
2 parents bac6c3d + 1f3f972 commit 041386b

File tree

6 files changed

+159
-47
lines changed

6 files changed

+159
-47
lines changed

strictdoc/core/file_traceability_index.py

Lines changed: 56 additions & 47 deletions
Original file line numberDiff line numberDiff line change
@@ -16,11 +16,10 @@
1616

1717
from strictdoc.backend.sdoc.document_reference import DocumentReference
1818
from strictdoc.backend.sdoc.error_handling import StrictDocSemanticError
19-
from strictdoc.backend.sdoc.models.document import SDocDocument
2019
from strictdoc.backend.sdoc.models.document_grammar import (
2120
DocumentGrammar,
2221
)
23-
from strictdoc.backend.sdoc.models.model import SDocDocumentIF, SDocNodeIF
22+
from strictdoc.backend.sdoc.models.model import SDocDocumentIF
2423
from strictdoc.backend.sdoc.models.node import SDocNode
2524
from strictdoc.backend.sdoc.models.reference import FileEntry, FileReference
2625
from strictdoc.backend.sdoc_source_code.models.function import Function
@@ -568,34 +567,9 @@ def validate_and_resolve(
568567
# STEP: Create auto-generated documents created from source file comments.
569568
# Register these documents with the main traceability index.
570569
#
571-
def create_folder_section(
572-
parent__: Union[SDocDocumentIF, SDocNodeIF],
573-
document__: SDocDocument,
574-
path__: str,
575-
) -> SDocNode:
576-
section_node = SDocNode(
577-
parent=parent__,
578-
node_type="SECTION",
579-
fields=[],
580-
relations=[],
581-
is_composite=True,
582-
node_type_close="SECTION",
583-
# It is important that this autogenerated node is marked as such.
584-
autogen=True,
585-
)
586-
section_node.ng_document_reference = DocumentReference()
587-
section_node.ng_document_reference.set_document(document__)
588-
section_node.ng_including_document_reference = DocumentReference()
589-
section_node.set_field_value(
590-
field_name="TITLE",
591-
form_field_index=0,
592-
value=path__,
593-
)
594-
return section_node
595-
596570
documents_with_generated_content = set()
597571

598-
section_cache = {}
572+
section_cache: Dict[str, Union[SDocDocumentIF, SDocNode]] = {}
599573
source_nodes_config: List[SourceNodesEntry] = (
600574
project_config.source_nodes
601575
)
@@ -627,24 +601,7 @@ def create_folder_section(
627601
document_uid = relevant_source_node_entry.uid
628602
document = traceability_index.get_node_by_uid(document_uid)
629603
documents_with_generated_content.add(document)
630-
631-
current_top_node = document
632-
path_components = path_to_source_file_.split("/")
633-
for path_component_idx_, path_component_ in enumerate(
634-
path_components
635-
):
636-
if path_component_ not in section_cache:
637-
path_component_title = (
638-
path_component_ + "/"
639-
if path_component_idx_ < (len(path_components) - 1)
640-
else path_component_
641-
)
642-
current_section = create_folder_section(
643-
current_top_node, document, path_component_title
644-
)
645-
current_top_node.section_contents.append(current_section)
646-
section_cache[path_component_] = current_section
647-
current_top_node = section_cache[path_component_]
604+
current_top_node = None
648605

649606
for source_node_ in traceability_info_.source_nodes:
650607
if len(source_node_.fields) == 0:
@@ -676,12 +633,20 @@ def create_folder_section(
676633
document,
677634
)
678635
sdoc_node_uid = assert_cast(sdoc_node.reserved_uid, str)
679-
current_top_node.section_contents.append(sdoc_node)
680636
traceability_index.graph_database.create_link(
681637
link_type=GraphLinkType.UID_TO_NODE,
682638
lhs_node=sdoc_node_uid,
683639
rhs_node=sdoc_node,
684640
)
641+
if current_top_node is None:
642+
current_top_node = (
643+
FileTraceabilityIndex.create_source_node_section(
644+
document,
645+
path_to_source_file_,
646+
section_cache,
647+
)
648+
)
649+
current_top_node.section_contents.append(sdoc_node)
685650

686651
self.connect_source_node_function(
687652
source_node_, sdoc_node_uid, traceability_info_
@@ -1053,6 +1018,50 @@ def set_sdoc_node_fields(
10531018
value=field_value,
10541019
)
10551020

1021+
@staticmethod
1022+
def create_source_node_section(
1023+
document: SDocDocumentIF,
1024+
path_to_source_file: str,
1025+
section_cache: Dict[str, Union[SDocDocumentIF, SDocNode]],
1026+
) -> Union[SDocDocumentIF, SDocNode]:
1027+
"""
1028+
Add a subsection for each path components in a given file path.
1029+
"""
1030+
current_top_node: Union[SDocDocumentIF, SDocNode] = document
1031+
path_components = path_to_source_file.split("/")
1032+
for path_component_idx_, path_component_ in enumerate(path_components):
1033+
if path_component_ not in section_cache:
1034+
path_component_title = (
1035+
path_component_ + "/"
1036+
if path_component_idx_ < (len(path_components) - 1)
1037+
else path_component_
1038+
)
1039+
current_section = SDocNode(
1040+
parent=current_top_node,
1041+
node_type="SECTION",
1042+
fields=[],
1043+
relations=[],
1044+
is_composite=True,
1045+
node_type_close="SECTION",
1046+
# It is important that this autogenerated node is marked as such.
1047+
autogen=True,
1048+
)
1049+
current_section.ng_document_reference = DocumentReference()
1050+
current_section.ng_document_reference.set_document(document)
1051+
current_section.ng_including_document_reference = (
1052+
DocumentReference()
1053+
)
1054+
current_section.set_field_value(
1055+
field_name="TITLE",
1056+
form_field_index=0,
1057+
value=path_component_title,
1058+
)
1059+
1060+
current_top_node.section_contents.append(current_section)
1061+
section_cache[path_component_] = current_section
1062+
current_top_node = section_cache[path_component_]
1063+
return current_top_node
1064+
10561065
def connect_sdoc_node_with_file_path(
10571066
self, sdoc_node: SDocNode, path_to_source_file_: str
10581067
) -> None:
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,12 @@
1+
[DOCUMENT]
2+
TITLE: Hello world doc
3+
4+
[REQUIREMENT]
5+
UID: REQ-1
6+
TITLE: Requirement Title
7+
STATEMENT: Requirement Statement
8+
9+
[REQUIREMENT]
10+
UID: REQ-2
11+
TITLE: Requirement Title #2
12+
STATEMENT: Requirement Statement #2
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,41 @@
1+
[DOCUMENT]
2+
MID: c2d4542d5f1741c88dfcb4f68ad7dcbd
3+
TITLE: Requirements from Source Nodes
4+
UID: SRC-NODES-BASE
5+
6+
[GRAMMAR]
7+
ELEMENTS:
8+
- TAG: SECTION
9+
PROPERTIES:
10+
IS_COMPOSITE: True
11+
FIELDS:
12+
- TITLE: UID
13+
TYPE: String
14+
REQUIRED: False
15+
- TITLE: TITLE
16+
TYPE: String
17+
REQUIRED: True
18+
- TAG: REQUIREMENT
19+
PROPERTIES:
20+
VIEW_STYLE: Narrative
21+
FIELDS:
22+
- TITLE: UID
23+
TYPE: String
24+
REQUIRED: False
25+
- TITLE: TITLE
26+
TYPE: String
27+
REQUIRED: False
28+
- TITLE: STATEMENT
29+
TYPE: String
30+
REQUIRED: False
31+
RELATIONS:
32+
- TYPE: Parent
33+
- TYPE: File
34+
35+
[[SECTION]]
36+
TITLE: No need to generate a section if node is located in static section
37+
38+
[REQUIREMENT]
39+
UID: REQ-EXAMPLE-1
40+
41+
[[/SECTION]]
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,14 @@
1+
#include <stdio.h>
2+
3+
/**
4+
* Some text.
5+
*
6+
* UID: REQ-EXAMPLE-1
7+
*
8+
* TITLE: Title from example.c
9+
*
10+
* STATEMENT: Statement from example.c
11+
*/
12+
void example_1(void) {
13+
print("hello world\n");
14+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,14 @@
1+
[project]
2+
3+
features = [
4+
"REQUIREMENT_TO_SOURCE_TRACEABILITY",
5+
"SOURCE_FILE_LANGUAGE_PARSERS",
6+
]
7+
8+
source_nodes = [
9+
{ "src/" = { uid = "SRC-NODES-BASE", node_type = "REQUIREMENT" } }
10+
]
11+
12+
exclude_source_paths = [
13+
"test.itest"
14+
]
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,22 @@
1+
#
2+
# This test verifies that source nodes that are merged with a static SDoc node
3+
# do not cause auto-generation of one or more parent sections. The static node
4+
# is already in a static parent section. Auto-generated section with conventional
5+
# name would stay empty and are thus unexpected.
6+
#
7+
# @relation(SDOC-SRS-141, scope=file)
8+
#
9+
10+
RUN: %strictdoc --debug export %S --output-dir %T | filecheck %s
11+
12+
CHECK: Published: Hello world doc
13+
14+
RUN: %check_exists --file "%T/html/_source_files/src/example/example.c.html"
15+
16+
RUN: %cat %T/html/%THIS_TEST_FOLDER/source_node_base.html | filecheck %s --check-prefix CHECK-HTML
17+
CHECK-HTML: Requirements from Source Nodes
18+
CHECK-HTML: REQ-EXAMPLE-1
19+
CHECK-HTML: Title from example.c
20+
CHECK-HTML: src/example/example.c, <i>lines: 3-14</i>, function example_1()
21+
CHECK-HTML: Statement from example.c
22+
CHECK-HTML-NOT: <sdoc-autogen>{{.*}}example.c</sdoc-autogen>

0 commit comments

Comments
 (0)