StrictDoc Documentation
strictdoc/core/file_system/source_tree.py
Source file coverage
Path:
strictdoc/core/file_system/source_tree.py
Lines:
142
Non-empty lines:
116
Non-empty lines covered with requirements:
116 / 116 (100.0%)
Functions:
17
Functions covered by requirements:
17 / 17 (100.0%)
1
"""
2
@relation(SDOC-SRS-33, scope=file)
3
"""
4
 
5
import os
6
from enum import Enum
7
from typing import Dict, List, Sequence
8
 
9
from strictdoc.core.file_system.file_tree import File, FileTree
10
from strictdoc.helpers.auto_described import auto_described
11
 
12
 
13
class SourceFileType(Enum):
14
    PYTHON = [".py"]
15
    C = [".h", ".c"]
16
    CPP = [".cpp", ".cc"]
17
    TEX = [".tex"]
18
    # Is there an idiomatic file extension for Jinja templates?
19
    # https://stackoverflow.com/questions/29590931/is-there-an-idiomatic-file-extension-for-jinja-templates
20
    TOML = [".toml"]
21
    JINJA = [".jinja", ".jinja2", ".j2", ".html.jinja"]
22
    JAVASCRIPT = [".js"]
23
    YAML = [".yaml", ".yml"]
24
    RST = [".rst"]
25
    SDOC = [".sdoc"]
26
 
27
    # Structured Text (PLC)
28
    STRUCTURED_TEXT = [".st"]
29
 
30
    UNKNOWN: List[str] = []  # type: ignore[misc]
31
 
32
    @classmethod
33
    def create_from_path(cls, path_to_file: str) -> "SourceFileType":
34
        if path_to_file.endswith(".py"):
35
            return cls.PYTHON
36
        if path_to_file.endswith(".h") or path_to_file.endswith(".c"):
37
            return cls.C
38
        for enum_value in SourceFileType.CPP.value:
39
            if path_to_file.endswith(enum_value):
40
                return cls.CPP
41
        if path_to_file.endswith(".tex"):
42
            return cls.TEX
43
        if path_to_file.endswith(".toml"):
44
            return cls.TOML
45
        for enum_value in SourceFileType.JINJA.value:
46
            if path_to_file.endswith(enum_value):
47
                return cls.JINJA
48
        if path_to_file.endswith(".js"):
49
            return cls.JAVASCRIPT
50
        for enum_value in SourceFileType.YAML.value:
51
            if path_to_file.endswith(enum_value):
52
                return cls.YAML
53
        for enum_value in SourceFileType.RST.value:
54
            if path_to_file.endswith(enum_value):
55
                return cls.RST
56
        if path_to_file.endswith(".sdoc"):
57
            return cls.SDOC
58
        # FIXME: .st file could conflict between Structured Text (PLC) and Smalltalk.
59
        #        No Smalltalk has been requested by users until now but we may
60
        #        want to set up a general disambiguation procedure for cases like this.
61
        #        https://github.com/strictdoc-project/strictdoc/issues/2569
62
        if path_to_file.endswith(".st"):
63
            return cls.STRUCTURED_TEXT
64
 
65
        return cls.UNKNOWN
66
 
67
 
68
@auto_described
69
class SourceFile:
70
    def __init__(
71
        self,
72
        level: int,
73
        full_path: str,
74
        in_doctree_source_file_rel_path: str,
75
        output_dir_full_path: str,
76
        output_file_full_path: str,
77
    ) -> None:
78
        assert isinstance(level, int)
79
        assert os.path.exists(full_path)
80
 
81
        self.level = level
82
        self.full_path = full_path
83
        self.file_name = os.path.basename(full_path)
84
        self.in_doctree_source_file_rel_path = in_doctree_source_file_rel_path
85
        self.in_doctree_source_file_rel_path_posix: str = (
86
            in_doctree_source_file_rel_path.replace("\\", "/")
87
        )
88
        self.output_dir_full_path = output_dir_full_path
89
        self.output_file_full_path = output_file_full_path
90
        self.path_depth_prefix = ("../" * (level + 1))[:-1]
91
 
92
        self.file_type: SourceFileType = SourceFileType.create_from_path(
93
            in_doctree_source_file_rel_path
94
        )
95
 
96
        self.is_referenced = False
97
 
98
    def is_python_file(self) -> bool:
99
        return self.file_type == SourceFileType.PYTHON
100
 
101
    def is_c_file(self) -> bool:
102
        return self.file_type == SourceFileType.C
103
 
104
    def is_cpp_file(self) -> bool:
105
        return self.file_type == SourceFileType.CPP
106
 
107
    def is_tex_file(self) -> bool:
108
        return self.file_type == SourceFileType.TEX
109
 
110
    def is_toml_file(self) -> bool:
111
        return self.file_type == SourceFileType.TOML
112
 
113
    def is_jinja_file(self) -> bool:
114
        return self.file_type == SourceFileType.JINJA
115
 
116
    def is_javascript_file(self) -> bool:
117
        return self.file_type == SourceFileType.JAVASCRIPT
118
 
119
    def is_yaml_file(self) -> bool:
120
        return self.file_type == SourceFileType.YAML
121
 
122
    def is_rst_file(self) -> bool:
123
        return self.file_type == SourceFileType.RST
124
 
125
    def is_st_file(self) -> bool:
126
        return self.file_type == SourceFileType.STRUCTURED_TEXT
127
 
128
 
129
class SourceTree:
130
    def __init__(
131
        self,
132
        file_tree: FileTree,
133
        source_files: Sequence[SourceFile],
134
        map_file_to_source: Dict[File, SourceFile],
135
    ):
136
        self.file_tree: FileTree = file_tree
137
        self.source_files: Sequence[SourceFile] = source_files
138
        self.map_file_to_source: Dict[File, SourceFile] = map_file_to_source
139
 
140
    def get_source_for_file(self, file: File) -> SourceFile:
141
        assert isinstance(file, File)
142
        return self.map_file_to_source[file]