cod8a 0.1.0__tar.gz → 0.2.1__tar.gz

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (31) hide show
  1. {cod8a-0.1.0 → cod8a-0.2.1}/PKG-INFO +68 -52
  2. {cod8a-0.1.0 → cod8a-0.2.1}/README.md +65 -50
  3. {cod8a-0.1.0 → cod8a-0.2.1}/pyproject.toml +8 -5
  4. {cod8a-0.1.0 → cod8a-0.2.1}/src/cod8a/cli.py +32 -15
  5. {cod8a-0.1.0/src/cod8a/dotnet/CodeAnalysis → cod8a-0.2.1/src/cod8a/dotnet/CodeAnalyzer}/Parsers/FileParser.cs +38 -15
  6. {cod8a-0.1.0/src/cod8a/dotnet/CodeAnalysis → cod8a-0.2.1/src/cod8a/dotnet/CodeAnalyzer}/Parsers/ProjectParser.cs +10 -4
  7. {cod8a-0.1.0/src/cod8a/dotnet/CodeAnalysis → cod8a-0.2.1/src/cod8a/dotnet/CodeAnalyzer}/Parsers/SolutionParser.cs +1 -1
  8. {cod8a-0.1.0/src/cod8a/dotnet/CodeAnalysis → cod8a-0.2.1/src/cod8a/dotnet/CodeAnalyzer}/Program.cs +18 -15
  9. {cod8a-0.1.0/src/cod8a/dotnet/CodeAnalysis → cod8a-0.2.1/src/cod8a/dotnet/CodeAnalyzer}/models/FileStructure.cs +3 -3
  10. {cod8a-0.1.0/src/cod8a/dotnet/CodeAnalysis → cod8a-0.2.1/src/cod8a/dotnet/CodeAnalyzer}/models/ProjectStructure.cs +3 -3
  11. {cod8a-0.1.0/src/cod8a/dotnet/CodeAnalysis → cod8a-0.2.1/src/cod8a/dotnet/CodeAnalyzer}/models/SolutionStructure.cs +3 -3
  12. {cod8a-0.1.0 → cod8a-0.2.1}/src/cod8a/dotnet/Test/CodeAnalyzerTest.csproj +1 -1
  13. cod8a-0.2.1/src/cod8a/dotnet/Test/ExtensionTypeTest.cs +64 -0
  14. {cod8a-0.1.0 → cod8a-0.2.1}/src/cod8a/generators/mermaid/class_diagram.py +11 -5
  15. {cod8a-0.1.0 → cod8a-0.2.1}/src/cod8a/generators/mermaid/flowchart_diagram.py +18 -11
  16. {cod8a-0.1.0 → cod8a-0.2.1}/src/cod8a/generators/mermaid/sequence_diagram.py +10 -8
  17. {cod8a-0.1.0 → cod8a-0.2.1}/src/cod8a/helpers/cli_helper.py +3 -3
  18. {cod8a-0.1.0 → cod8a-0.2.1}/src/cod8a/parsers/dotnet_parser.py +10 -2
  19. {cod8a-0.1.0 → cod8a-0.2.1}/LICENSE +0 -0
  20. {cod8a-0.1.0 → cod8a-0.2.1}/src/cod8a/__init__.py +0 -0
  21. {cod8a-0.1.0 → cod8a-0.2.1}/src/cod8a/cod8a.py +0 -0
  22. {cod8a-0.1.0/src/cod8a/dotnet/CodeAnalysis → cod8a-0.2.1/src/cod8a/dotnet/CodeAnalyzer}/CodeAnalyzer.csproj +0 -0
  23. {cod8a-0.1.0/src/cod8a/dotnet/CodeAnalysis → cod8a-0.2.1/src/cod8a/dotnet/CodeAnalyzer}/CodeAnalyzer.csproj.lscache +0 -0
  24. {cod8a-0.1.0/src/cod8a/dotnet/CodeAnalysis → cod8a-0.2.1/src/cod8a/dotnet/CodeAnalyzer}/Parsers/BaseParser.cs +0 -0
  25. {cod8a-0.1.0 → cod8a-0.2.1}/src/cod8a/dotnet/Test/Mermaid/ClassDiagramTest.cs +0 -0
  26. {cod8a-0.1.0 → cod8a-0.2.1}/src/cod8a/enums/__init__.py +0 -0
  27. {cod8a-0.1.0 → cod8a-0.2.1}/src/cod8a/enums/diagram_type.py +0 -0
  28. {cod8a-0.1.0 → cod8a-0.2.1}/src/cod8a/helpers/__init__.py +0 -0
  29. {cod8a-0.1.0 → cod8a-0.2.1}/src/cod8a/models/__init__.py +0 -0
  30. {cod8a-0.1.0 → cod8a-0.2.1}/src/cod8a/models/models.py +0 -0
  31. {cod8a-0.1.0 → cod8a-0.2.1}/src/cod8a/parsers/python_parser.py +0 -0
@@ -1,11 +1,11 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: cod8a
3
- Version: 0.1.0
3
+ Version: 0.2.1
4
4
  Summary: cod8a is a code documentation and visualization tool for Python and .NET projects
5
5
  License-Expression: MIT
6
6
  License-File: LICENSE
7
7
  Keywords: visualization,uml,docs,flowchart,class,sequence,diagram
8
- Author: Akumbom
8
+ Author: Marietta Akumbom
9
9
  Author-email: akumbom5ma@gmail.com
10
10
  Maintainer: Marietta Akumbom
11
11
  Requires-Python: >=3.13
@@ -14,6 +14,7 @@ Classifier: Programming Language :: Python :: 3.13
14
14
  Classifier: Programming Language :: Python :: 3.14
15
15
  Requires-Dist: click (>=8.3.3,<9.0.0)
16
16
  Requires-Dist: pydantic (>=2.13.3,<3.0.0)
17
+ Project-URL: Repository, https://github.com/marietta-a/cod8a
17
18
  Description-Content-Type: text/markdown
18
19
 
19
20
  # cod8a
@@ -27,61 +28,17 @@ cod8a pronounced codetta, is a code documentation and visualization tool for **P
27
28
  - **[Python 3.9+](https://www.python.org/downloads/)**
28
29
  - **[.NET 10.0 Runtime or SDK](https://dotnet.microsoft.com/download/dotnet/10.0)** (Required **only** for C#/.NET analysis)
29
30
 
30
- ### From PyPI (Recommended for Users)
31
+ ### From PyPI
31
32
 
32
- Once published, you can install `cod8a` directly using pip:
33
+ Install `cod8a` directly using pip:
33
34
 
34
35
  ```bash
35
36
  pip install cod8a
36
37
  ```
37
38
 
38
- ## Development & Contribution
39
-
40
- If you want to contribute to the project or run it from source:
41
-
42
- ### Setup
43
-
44
- 1. **Fork** the repository on GitHub.
45
- 2. **Clone** your fork:
46
-
47
- ```bash
48
- git clone https://github.com/yourusername/cod8a.git
49
- cd cod8a
50
- ```
51
-
52
- ### Development Options
53
-
54
- #### 1. Local Setup
55
- 3. **Install** Python dependencies using **[Poetry](https://python-poetry.org/docs/#installation)**:
56
-
57
- ```bash
58
- poetry install
59
- ```
60
-
61
- 4. **Optional**: Ensure .NET 10.0 is installed (if documenting C#)
62
-
63
- ```bash
64
- dotnet --version
65
- ```
66
-
67
- #### 2. VS Code Dev Container (Recommended)
68
- If you use VS Code, you can skip the local setup by using the provided **Dev Container**. It comes pre-configured with Python 3.13, .NET 10.0, and Poetry.
69
- - Simply open the project in VS Code and click **"Reopen in Container"** when prompted.
70
-
71
- #### 3. Docker
72
- You can also run `cod8a` as a standalone container without installing any dependencies locally:
73
-
74
- ```bash
75
- # Build the image
76
- docker build -t cod8a .
77
-
78
- # Run the tool
79
- docker run -v $(pwd):/app/data cod8a uml -p /app/data/src
80
- ```
81
-
82
39
  ## Usage
83
40
 
84
- The tool uses a CLI interface to analyze code and generate visualizations.
41
+ The tool uses a CLI interface to analyze code and generate mermaid diagrams.
85
42
 
86
43
  ### UML Diagrams
87
44
 
@@ -92,13 +49,19 @@ Generate Mermaid-compatible diagrams (Class, Sequence, Flowchart):
92
49
  cod8a uml -p <path_to_source> -d <diagram_type>
93
50
 
94
51
  # Generate a class diagram (default)
95
- cod8a uml -p src/my_project
52
+ cod8a uml -p <path_to_source>
96
53
 
97
54
  # Generate a sequence diagram
98
- cod8a uml -p src/my_file.py -d sequence
55
+ cod8a uml -p <path_to_source> -d sequence
99
56
 
100
57
  # Generate a flowchart
101
- cod8a uml -p src/my_logic -d flow
58
+ cod8a uml -p <path_to_source> -d flow
59
+
60
+ # Summarize a large project (omit fields/methods)
61
+ cod8a uml -p <path_to_source> --summarize
62
+
63
+ # Force full diagram details for a large file
64
+ cod8a uml -p <path_to_source> --no-summarize
102
65
  ```
103
66
 
104
67
  #### Diagram Type Options:
@@ -106,11 +69,19 @@ cod8a uml -p src/my_logic -d flow
106
69
  - **Sequence:** `sequence`, `seq`, `s`
107
70
  - **Flowchart:** `flowchart`, `flow`, `f`
108
71
 
72
+ ### Samples
73
+ Below are detailed example Mermaid diagrams generated by `cod8a` based on its own `src/cod8a/models/models.py` file:
74
+
75
+ - [Class Diagram Example](examples/class_diagram.mmd)
76
+ - [Flowchart Example](examples/flowchart.mmd)
77
+ - [Sequence Diagram Example](examples/sequence_diagram.mmd)
78
+
109
79
  ### CLI Options
110
80
 
111
81
  - `-p, --path`: Path to the file or directory to analyze.
112
82
  - `-d, --diagram`: Type of diagram to generate (default: `class`).
113
83
  - `-o, --output`: Output file path (saves as `.mmd`).
84
+ - `-s, --summarize / --no-summarize`: Enable or disable diagram summarization. When enabled, details like fields and methods are omitted (useful for large files). Defaults to auto-summarize for large files.
114
85
 
115
86
  ### Documentation (In development)
116
87
 
@@ -132,3 +103,48 @@ cod8a doc -p path/to/source
132
103
  - **Markdown Documentation (TODO):** Detailed markdown generation for code documentation is currently in development.
133
104
 
134
105
 
106
+ <!-- ## Development & Contribution -->
107
+ <!-- If you want to contribute to the project or run it from source: -->
108
+ ## Development
109
+
110
+ ### Setup
111
+
112
+ 1. **Fork** the repository on GitHub.
113
+ 2. **Clone** your fork:
114
+
115
+ ```bash
116
+ git clone https://github.com/yourusername/cod8a.git
117
+ cd cod8a
118
+ ```
119
+
120
+ ### Development Options
121
+
122
+ #### 1. Local Setup
123
+ 3. **Install** Python dependencies:
124
+
125
+ Using **[Poetry](https://python-poetry.org/docs/#installation)** (recommended):
126
+ ```bash
127
+ poetry install
128
+ ```
129
+
130
+ 4. **Optional**: Ensure .NET 10.0 is installed (if documenting C#)
131
+
132
+ ```bash
133
+ dotnet --version
134
+ ```
135
+
136
+ #### 2. VS Code Dev Container (Recommended)
137
+ If you use VS Code, you can skip the local setup by using the provided **Dev Container**. It comes pre-configured with Python 3.13, .NET 10.0, and Poetry.
138
+ - Simply open the project in VS Code and click **"Reopen in Container"** when prompted.
139
+
140
+ #### 3. Docker
141
+ You can also run `cod8a` as a standalone container without installing any dependencies locally:
142
+
143
+ ```bash
144
+ # Build the image
145
+ docker build -t cod8a .
146
+
147
+ # Run the tool
148
+ docker run -v $(pwd):/app/data cod8a uml -p /app/data/src
149
+ ```
150
+
@@ -9,61 +9,17 @@ cod8a pronounced codetta, is a code documentation and visualization tool for **P
9
9
  - **[Python 3.9+](https://www.python.org/downloads/)**
10
10
  - **[.NET 10.0 Runtime or SDK](https://dotnet.microsoft.com/download/dotnet/10.0)** (Required **only** for C#/.NET analysis)
11
11
 
12
- ### From PyPI (Recommended for Users)
12
+ ### From PyPI
13
13
 
14
- Once published, you can install `cod8a` directly using pip:
14
+ Install `cod8a` directly using pip:
15
15
 
16
16
  ```bash
17
17
  pip install cod8a
18
18
  ```
19
19
 
20
- ## Development & Contribution
21
-
22
- If you want to contribute to the project or run it from source:
23
-
24
- ### Setup
25
-
26
- 1. **Fork** the repository on GitHub.
27
- 2. **Clone** your fork:
28
-
29
- ```bash
30
- git clone https://github.com/yourusername/cod8a.git
31
- cd cod8a
32
- ```
33
-
34
- ### Development Options
35
-
36
- #### 1. Local Setup
37
- 3. **Install** Python dependencies using **[Poetry](https://python-poetry.org/docs/#installation)**:
38
-
39
- ```bash
40
- poetry install
41
- ```
42
-
43
- 4. **Optional**: Ensure .NET 10.0 is installed (if documenting C#)
44
-
45
- ```bash
46
- dotnet --version
47
- ```
48
-
49
- #### 2. VS Code Dev Container (Recommended)
50
- If you use VS Code, you can skip the local setup by using the provided **Dev Container**. It comes pre-configured with Python 3.13, .NET 10.0, and Poetry.
51
- - Simply open the project in VS Code and click **"Reopen in Container"** when prompted.
52
-
53
- #### 3. Docker
54
- You can also run `cod8a` as a standalone container without installing any dependencies locally:
55
-
56
- ```bash
57
- # Build the image
58
- docker build -t cod8a .
59
-
60
- # Run the tool
61
- docker run -v $(pwd):/app/data cod8a uml -p /app/data/src
62
- ```
63
-
64
20
  ## Usage
65
21
 
66
- The tool uses a CLI interface to analyze code and generate visualizations.
22
+ The tool uses a CLI interface to analyze code and generate mermaid diagrams.
67
23
 
68
24
  ### UML Diagrams
69
25
 
@@ -74,13 +30,19 @@ Generate Mermaid-compatible diagrams (Class, Sequence, Flowchart):
74
30
  cod8a uml -p <path_to_source> -d <diagram_type>
75
31
 
76
32
  # Generate a class diagram (default)
77
- cod8a uml -p src/my_project
33
+ cod8a uml -p <path_to_source>
78
34
 
79
35
  # Generate a sequence diagram
80
- cod8a uml -p src/my_file.py -d sequence
36
+ cod8a uml -p <path_to_source> -d sequence
81
37
 
82
38
  # Generate a flowchart
83
- cod8a uml -p src/my_logic -d flow
39
+ cod8a uml -p <path_to_source> -d flow
40
+
41
+ # Summarize a large project (omit fields/methods)
42
+ cod8a uml -p <path_to_source> --summarize
43
+
44
+ # Force full diagram details for a large file
45
+ cod8a uml -p <path_to_source> --no-summarize
84
46
  ```
85
47
 
86
48
  #### Diagram Type Options:
@@ -88,11 +50,19 @@ cod8a uml -p src/my_logic -d flow
88
50
  - **Sequence:** `sequence`, `seq`, `s`
89
51
  - **Flowchart:** `flowchart`, `flow`, `f`
90
52
 
53
+ ### Samples
54
+ Below are detailed example Mermaid diagrams generated by `cod8a` based on its own `src/cod8a/models/models.py` file:
55
+
56
+ - [Class Diagram Example](examples/class_diagram.mmd)
57
+ - [Flowchart Example](examples/flowchart.mmd)
58
+ - [Sequence Diagram Example](examples/sequence_diagram.mmd)
59
+
91
60
  ### CLI Options
92
61
 
93
62
  - `-p, --path`: Path to the file or directory to analyze.
94
63
  - `-d, --diagram`: Type of diagram to generate (default: `class`).
95
64
  - `-o, --output`: Output file path (saves as `.mmd`).
65
+ - `-s, --summarize / --no-summarize`: Enable or disable diagram summarization. When enabled, details like fields and methods are omitted (useful for large files). Defaults to auto-summarize for large files.
96
66
 
97
67
  ### Documentation (In development)
98
68
 
@@ -113,3 +83,48 @@ cod8a doc -p path/to/source
113
83
  - **Python Support:** Uses AST-based parsing for Python files.
114
84
  - **Markdown Documentation (TODO):** Detailed markdown generation for code documentation is currently in development.
115
85
 
86
+
87
+ <!-- ## Development & Contribution -->
88
+ <!-- If you want to contribute to the project or run it from source: -->
89
+ ## Development
90
+
91
+ ### Setup
92
+
93
+ 1. **Fork** the repository on GitHub.
94
+ 2. **Clone** your fork:
95
+
96
+ ```bash
97
+ git clone https://github.com/yourusername/cod8a.git
98
+ cd cod8a
99
+ ```
100
+
101
+ ### Development Options
102
+
103
+ #### 1. Local Setup
104
+ 3. **Install** Python dependencies:
105
+
106
+ Using **[Poetry](https://python-poetry.org/docs/#installation)** (recommended):
107
+ ```bash
108
+ poetry install
109
+ ```
110
+
111
+ 4. **Optional**: Ensure .NET 10.0 is installed (if documenting C#)
112
+
113
+ ```bash
114
+ dotnet --version
115
+ ```
116
+
117
+ #### 2. VS Code Dev Container (Recommended)
118
+ If you use VS Code, you can skip the local setup by using the provided **Dev Container**. It comes pre-configured with Python 3.13, .NET 10.0, and Poetry.
119
+ - Simply open the project in VS Code and click **"Reopen in Container"** when prompted.
120
+
121
+ #### 3. Docker
122
+ You can also run `cod8a` as a standalone container without installing any dependencies locally:
123
+
124
+ ```bash
125
+ # Build the image
126
+ docker build -t cod8a .
127
+
128
+ # Run the tool
129
+ docker run -v $(pwd):/app/data cod8a uml -p /app/data/src
130
+ ```
@@ -1,9 +1,9 @@
1
1
  [project]
2
2
  name = "cod8a"
3
- version = "0.1.0"
3
+ version = "0.2.1"
4
4
  description = "cod8a is a code documentation and visualization tool for Python and .NET projects"
5
5
  authors = [
6
- { name = "Akumbom",email = "akumbom5ma@gmail.com"}
6
+ { name = "Marietta Akumbom",email = "akumbom5ma@gmail.com"}
7
7
  ]
8
8
  maintainers = [
9
9
  { name = "Marietta Akumbom" }
@@ -17,14 +17,17 @@ dependencies = [
17
17
  "pydantic (>=2.13.3,<3.0.0)"
18
18
  ]
19
19
 
20
+ [project.urls]
21
+ Repository = "https://github.com/marietta-a/cod8a"
22
+
20
23
  [tool.poetry]
21
24
  packages = [{include = "cod8a", from = "src"}]
22
25
  include = [
23
- { path = "src/cod8a/dotnet/CodeAnalysis/bin/Release/net10.0/*.dll", format = ["wheel"] },
24
- { path = "src/cod8a/dotnet/CodeAnalysis/bin/Release/net10.0/*.json", format = ["wheel"] }
26
+ { path = "src/cod8a/dotnet/CodeAnalyzer/bin/Release/net10.0/*.dll", format = ["wheel"] },
27
+ { path = "src/cod8a/dotnet/CodeAnalyzer/bin/Release/net10.0/*.json", format = ["wheel"] }
25
28
  ]
26
29
 
27
- [tool.poetry.scripts]
30
+ [project.scripts]
28
31
  cod8a = "cod8a.cli:main"
29
32
  cde8a = "cod8a.cli:doc_main"
30
33
 
@@ -43,7 +43,9 @@ def cli():
43
43
  help='The type of diagram to generate (default: class).')
44
44
  @click.option('-o', '--output',
45
45
  help='Optional output file path. If not provided, you will be prompted to save to the Downloads folder.')
46
- def uml(path, diagram_type, output):
46
+ @click.option('-s', '--summarize', is_flag=True,
47
+ help='Summarize the diagram by omitting details like fields and methods (recommended for large files).')
48
+ def uml(path, diagram_type, output, summarize):
47
49
  """Generate UML diagram (Mermaid format)."""
48
50
  struct = extract_structure(path)
49
51
  base_name = os.path.basename(path or os.getcwd())
@@ -53,15 +55,30 @@ def uml(path, diagram_type, output):
53
55
  click.echo("Error: Could not extract structure.")
54
56
  return
55
57
 
58
+ # Auto-summarize if not explicitly requested
59
+ if not summarize:
60
+ classes = []
61
+ if hasattr(struct, 'files'):
62
+ classes = [c for f in struct.files for c in f.classes]
63
+ elif hasattr(struct, 'classes'):
64
+ classes = struct.classes
65
+ elif isinstance(struct, list):
66
+ classes = [c for f in struct for c in f.classes]
67
+
68
+ total_members = sum(len(c.fields) + len(c.methods) for c in classes)
69
+ if len(classes) > 50 or total_members > 250:
70
+ click.echo("Note: Large file/project detected. Auto-summarizing diagram for better visualization.")
71
+ summarize = True
72
+
56
73
  canon_type = "class"
57
74
  if DiagramType.FLOWCHART.value.startswith(diagram_type):
58
- diagram = generate_flowchart_diagram(struct, base_name)
75
+ diagram = generate_flowchart_diagram(struct, base_name, summarize)
59
76
  canon_type = "flowchart"
60
77
  elif DiagramType.SEQUENCE.value.startswith(diagram_type):
61
- diagram = generate_sequence_diagram(struct)
78
+ diagram = generate_sequence_diagram(struct, summarize)
62
79
  canon_type = "sequence"
63
80
  else:
64
- diagram = generate_class_diagram(struct)
81
+ diagram = generate_class_diagram(struct, summarize)
65
82
  canon_type = "class"
66
83
 
67
84
  print(diagram)
@@ -70,24 +87,24 @@ def uml(path, diagram_type, output):
70
87
  save_diagram(struct, canon_type, diagram, output, path)
71
88
 
72
89
 
73
- # TODO Generating code documentation
74
- @click.command(help="[TODO] Generate documentation (Markdown format) from code structure.")
75
- @click.option('-p', '--path', help='Specific path of file(s) to analyze')
76
- @click.option('--json', 'output_json', is_flag=True, help='Output in JSON format')
77
- def doc_cli(path, output_json):
78
- """Generate documentation (Markdown format)."""
79
- target = path or os.getcwd()
80
- struct = extract_structure(target)
90
+ # # TODO Generating code documentation
91
+ # @click.command(help="[TODO] Generate documentation (Markdown format) from code structure.")
92
+ # @click.option('-p', '--path', help='Specific path of file(s) to analyze')
93
+ # @click.option('--json', 'output_json', is_flag=True, help='Output in JSON format')
94
+ # def doc_cli(path, output_json):
95
+ # """Generate documentation (Markdown format)."""
96
+ # target = path or os.getcwd()
97
+ # struct = extract_structure(target)
81
98
 
82
99
 
83
100
  # Main entry point for cod8a
84
101
  def main():
85
- cli.add_command(doc_cli, name="doc")
102
+ # cli.add_command(doc_cli, name="doc")
86
103
  cli()
87
104
 
88
105
  # Separate entry point for code8a
89
- def doc_main():
90
- doc_cli()
106
+ # def doc_main():
107
+ # doc_cli()
91
108
 
92
109
  if __name__ == "__main__":
93
110
  main()
@@ -19,12 +19,13 @@ namespace CodeAnalyzer.Parsers
19
19
  public sealed partial class FileParser<T> : BaseParser<T> where T : FileStructure
20
20
  {
21
21
 
22
- public override string Name { get; init; }
22
+ public override required string Name { get; init; }
23
23
 
24
24
  /// <summary>
25
25
  /// Gets the code associated with this instance.
26
26
  /// </summary>
27
- public string FilePath { get; init; }
27
+ public required string FilePath { get; init; }
28
+ public int Id { get; init; } = 1;
28
29
  public override T Parse()
29
30
  {
30
31
  try
@@ -37,8 +38,7 @@ namespace CodeAnalyzer.Parsers
37
38
  CompilationUnitSyntax root = tree.GetCompilationUnitRoot();
38
39
 
39
40
 
40
- var directory = Directory.GetCurrentDirectory();
41
- var fileName = Path.GetFileName(directory);
41
+ var fileName = Name ?? Path.GetFileName(FilePath);
42
42
  var id = 0;
43
43
  var usings = root.Usings.Select(b =>
44
44
  {
@@ -47,7 +47,7 @@ namespace CodeAnalyzer.Parsers
47
47
  });
48
48
  var fileStructure = new FileStructure
49
49
  {
50
- Id = 1,
50
+ Id = Id,
51
51
  Name = fileName,
52
52
  UsingDirectives = usings.ToList(),
53
53
  };
@@ -57,7 +57,7 @@ namespace CodeAnalyzer.Parsers
57
57
 
58
58
  return (T)fileStructure;
59
59
  }
60
- catch (Exception ex)
60
+ catch
61
61
  {
62
62
  throw;
63
63
  }
@@ -76,7 +76,7 @@ namespace CodeAnalyzer.Parsers
76
76
  _ => string.Empty
77
77
  };
78
78
  }
79
- catch( Exception ex )
79
+ catch
80
80
  {
81
81
  throw;
82
82
  }
@@ -98,7 +98,10 @@ namespace CodeAnalyzer.Parsers
98
98
  var relationships = new List<RelationShip>();
99
99
 
100
100
  var baseTypes = classDeclaration.BaseList?.Types;
101
- int id = 0;
101
+ int relId = 0;
102
+ int fieldId = 0;
103
+ int methodId = 0;
104
+ int classId = 0;
102
105
 
103
106
  if(baseTypes is not null)
104
107
  {
@@ -112,19 +115,19 @@ namespace CodeAnalyzer.Parsers
112
115
  _ => b.Type.ToString().Split('<')[0]
113
116
  };
114
117
  var type = parent.StartsWith("I") && parent.Length > 1 && char.IsUpper(parent[1]) ? "Interface" : "Class";
115
- return new RelationShip (++id, type, parent);
118
+ return new RelationShip (++relId, type, parent);
116
119
  })
117
120
  );
118
121
  }
119
122
 
120
123
  // Extract standard fields and properties
121
- fieldStructures.AddRange(classDeclaration.DescendantNodes().OfType<FieldDeclarationSyntax>().Select(f => new FieldStructure(default, f.Declaration.Variables.First().Identifier.Text, f.Modifiers.ToFullString().Trim(), f.Declaration.Type.ToString(), f.GetLeadingTrivia().ToString().Trim())));
122
- fieldStructures.AddRange(classDeclaration.DescendantNodes().OfType<PropertyDeclarationSyntax>().Select(f => new FieldStructure(default, f.Identifier.Text, f.Modifiers.ToFullString().Trim(), f.Type.ToString(), f.GetLeadingTrivia().ToString().Trim())));
124
+ fieldStructures.AddRange(classDeclaration.DescendantNodes().OfType<FieldDeclarationSyntax>().Select(f => new FieldStructure(++fieldId, f.Declaration.Variables.First().Identifier.Text, f.Modifiers.ToFullString().Trim(), f.Declaration.Type.ToString(), f.GetLeadingTrivia().ToString().Trim())));
125
+ fieldStructures.AddRange(classDeclaration.DescendantNodes().OfType<PropertyDeclarationSyntax>().Select(f => new FieldStructure(++fieldId, f.Identifier.Text, f.Modifiers.ToFullString().Trim(), f.Type.ToString(), f.GetLeadingTrivia().ToString().Trim())));
123
126
 
124
127
  // Extract record positional parameters as properties
125
128
  if (classDeclaration is RecordDeclarationSyntax recordDecl && recordDecl.ParameterList != null)
126
129
  {
127
- fieldStructures.AddRange(recordDecl.ParameterList.Parameters.Select(p => new FieldStructure(default, p.Identifier.Text, "public", p.Type?.ToString() ?? "", p.GetLeadingTrivia().ToString().Trim())));
130
+ fieldStructures.AddRange(recordDecl.ParameterList.Parameters.Select(p => new FieldStructure(++fieldId, p.Identifier.Text, "public", p.Type?.ToString() ?? "", p.GetLeadingTrivia().ToString().Trim())));
128
131
  }
129
132
 
130
133
  foreach (var method in classDeclaration.Members.OfType<MethodDeclarationSyntax>())
@@ -132,14 +135,34 @@ namespace CodeAnalyzer.Parsers
132
135
  var parameters = method.ParameterList.Parameters.Select(p => new ParameterStructure(p.Identifier.Text, p.Modifiers.ToFullString().Trim(), p.Type?.ToString() ?? "", p.GetLeadingTrivia().ToString().Trim())).ToList();
133
136
  parameterStructures.AddRange(parameters);
134
137
 
135
- methodStructures.Add(new MethodStructure(default, method.Identifier.Text, method.Modifiers.ToFullString().Trim(), method.ReturnType.ToString(), parameters, method.GetLeadingTrivia().ToString().Trim()));
138
+ methodStructures.Add(new MethodStructure(++methodId, method.Identifier.Text, method.Modifiers.ToFullString().Trim(), method.ReturnType.ToString(), parameters, method.GetLeadingTrivia().ToString().Trim()));
136
139
  }
137
- classes.Add(new ClassStructure(default, classDeclaration.Identifier.Text, methodStructures, fieldStructures, classDeclaration.Keyword.ToFullString().Trim(), relationships, classDeclaration.GetLeadingTrivia().ToString().Trim()));
140
+
141
+ var className = classDeclaration.Identifier.Text;
142
+ if (string.IsNullOrEmpty(className) && classDeclaration.Keyword.Text == "extension")
143
+ {
144
+ var parameterList = classDeclaration.ChildNodes().OfType<ParameterListSyntax>().FirstOrDefault();
145
+ if (parameterList != null && parameterList.Parameters.Any())
146
+ {
147
+ var extendedType = parameterList.Parameters[0].Type;
148
+ if (extendedType != null)
149
+ {
150
+ className = $"{extendedType}ExtensionBlock";
151
+ relationships.Add(new RelationShip(++relId, "Extension", extendedType.ToString()));
152
+ }
153
+ }
154
+ else
155
+ {
156
+ className = "extension";
157
+ }
158
+ }
159
+
160
+ classes.Add(new ClassStructure(++classId, className, methodStructures, fieldStructures, classDeclaration.Keyword.ToFullString().Trim(), relationships, classDeclaration.GetLeadingTrivia().ToString().Trim()));
138
161
  }
139
162
 
140
163
  return classes;
141
164
  }
142
- catch (Exception ex)
165
+ catch
143
166
  {
144
167
  throw;
145
168
  }
@@ -10,24 +10,30 @@ namespace CodeAnalyzer.Parsers
10
10
  {
11
11
  public sealed partial class ProjectParser<T> : BaseParser<T> where T : ProjectStructure
12
12
  {
13
- public override string Name { get; init; }
13
+ public override required string Name { get; init; }
14
14
 
15
- public string[] FilePaths { get; init; }
15
+ public required string[] FilePaths { get; init; }
16
16
 
17
17
  public override T Parse()
18
18
  {
19
19
  try
20
20
  {
21
+ var fileId = 1;
21
22
  var projectStructure = new ProjectStructure
22
23
  {
23
24
  Id = 1,
24
25
  Name = Name,
25
- Files = FilePaths.Select(b => new FileParser<FileStructure> { FilePath = b, Name = Path.GetFileName(b) }.Parse()).ToList(),
26
+ Files = FilePaths.Select(b => new FileParser<FileStructure>
27
+ {
28
+ FilePath = b,
29
+ Name = Path.GetFileName(b),
30
+ Id = fileId++
31
+ }.Parse()).ToList(),
26
32
  };
27
33
 
28
34
  return (T) projectStructure;
29
35
  }
30
- catch (Exception ex)
36
+ catch
31
37
  {
32
38
  throw;
33
39
  }
@@ -7,7 +7,7 @@ namespace CodeAnalyzer.Parsers
7
7
  {
8
8
  public sealed partial class SolutionParser<T> : BaseParser<T> where T : SolutionStructure
9
9
  {
10
- public override string Name { get; init; }
10
+ public override required string Name { get; init; }
11
11
 
12
12
  public override T Parse()
13
13
  {
@@ -9,35 +9,37 @@ class Program
9
9
  {
10
10
  static void Main(string[] args)
11
11
  {
12
- Console.WriteLine("Starting code analysis...");
13
- var fileName = args.Length > 0 ? args[0] : null;
14
- //Check if path is directory
15
- var fileAttr = File.GetAttributes(fileName!);
16
- var isDirectory = fileAttr.HasFlag(FileAttributes.Directory);
12
+ var path = args.Length > 0 ? args[0] : null;
17
13
 
18
-
19
- if(string.IsNullOrEmpty(fileName))
14
+ if(string.IsNullOrEmpty(path))
20
15
  {
21
16
  Console.Error.WriteLine(@"No file or project specified. Please provide a file/directory
22
17
  containing ...cs, .csproj, or .sln file.");
23
18
  return;
24
19
  }
25
20
 
26
- if (!File.Exists(fileName) && !isDirectory){
27
- Console.Error.WriteLine($"File not found: {fileName}");
21
+ //Check if path is directory
22
+ var fileAttr = File.GetAttributes(path!);
23
+ var isDirectory = fileAttr.HasFlag(FileAttributes.Directory);
24
+
25
+
26
+ if (!File.Exists(path) && !isDirectory){
27
+ Console.Error.WriteLine($"File not found: {path}");
28
28
  return;
29
29
  }
30
30
 
31
- string json = "";
31
+ var json = "";
32
+ var fileName = Path.GetFileName(path);
32
33
 
33
- if (isDirectory || fileName.EndsWith(".csproj") || fileName.EndsWith(".sln") || fileName.EndsWith(".slnx"))
34
+ if (isDirectory || path.EndsWith(".csproj") || path.EndsWith(".sln") || path.EndsWith(".slnx"))
34
35
  {
35
- var csFiles = Directory.GetFiles(Path.GetDirectoryName(fileName)!, "*.cs", SearchOption.AllDirectories).Where(f => !f.Contains("obj", StringComparison.CurrentCultureIgnoreCase)).ToArray();
36
+ var directoryPath = isDirectory ? path : Path.GetDirectoryName(path)!;
37
+ var csFiles = Directory.GetFiles(directoryPath, "*.cs", SearchOption.TopDirectoryOnly).Where(f => !f.Contains("obj", StringComparison.CurrentCultureIgnoreCase)).ToArray();
36
38
 
37
39
  BaseParser<ProjectStructure> projectStructure = new ProjectParser<ProjectStructure>()
38
40
  {
39
41
  FilePaths = csFiles,
40
- Name = Path.GetFileName(fileName),
42
+ Name = fileName,
41
43
  };
42
44
 
43
45
  json = JsonSerializer.Serialize(projectStructure.Parse(), new JsonSerializerOptions { WriteIndented = false });
@@ -46,13 +48,14 @@ class Program
46
48
  {
47
49
  BaseParser<FileStructure> fileStructure = new FileParser<FileStructure>()
48
50
  {
49
- FilePath = fileName,
50
- Name = Path.GetFileName(fileName),
51
+ FilePath = path,
52
+ Name = fileName,
51
53
  };
52
54
 
53
55
  json = JsonSerializer.Serialize(fileStructure.Parse(), new JsonSerializerOptions { WriteIndented = false });
54
56
  }
55
57
 
56
58
  Console.WriteLine(json);
59
+
57
60
  }
58
61
  }
@@ -14,17 +14,17 @@ namespace CodeAnalyzer.Models
14
14
  /// <summary>
15
15
  /// <see langword="nameof"/>of the namespace, e.g., <c>MyNamespace</c>.
16
16
  /// </summary>
17
- public string Name { get; set; }
17
+ public required string Name { get; set; }
18
18
 
19
19
  /// <summary>
20
20
  /// Gets or sets the collection of using directives associated with the current context.
21
21
  /// </summary>
22
- public List<UsingDirective> UsingDirectives { get; set; }
22
+ public List<UsingDirective>? UsingDirectives { get; set; }
23
23
 
24
24
  /// <summary>
25
25
  /// Gets or sets the collection of classes associated with the current instance.
26
26
  /// </summary>
27
- public List<ClassStructure> Classes { get; set; }
27
+ public List<ClassStructure>? Classes { get; set; }
28
28
 
29
29
  }
30
30
 
@@ -14,16 +14,16 @@ namespace CodeAnalyzer.Models
14
14
  /// <summary>
15
15
  /// Name of the Project
16
16
  /// </summary>
17
- public string Name { get; set; }
17
+ public required string Name { get; set; }
18
18
 
19
19
  /// <summary>
20
20
  /// Project Description
21
21
  /// </summary>
22
- public string Description { get; set; }
22
+ public string? Description { get; set; }
23
23
 
24
24
  /// <summary>
25
25
  /// Gets or sets the collection of files associated with the Project.
26
26
  /// </summary>
27
- public List<FileStructure> Files { get; set; }
27
+ public required List<FileStructure> Files { get; set; }
28
28
  }
29
29
  }
@@ -13,16 +13,16 @@ namespace CodeAnalyzer.Models
13
13
  /// <summary>
14
14
  /// Gets or sets the name of the Solution
15
15
  /// </summary>
16
- public string Name { get; set; }
16
+ public required string Name { get; set; }
17
17
 
18
18
  /// <summary>
19
19
  /// Gets or sets the description associated with the object.
20
20
  /// </summary>
21
- public string Description { get; set; }
21
+ public string? Description { get; set; }
22
22
 
23
23
  /// <summary>
24
24
  /// Gets or sets the collection of projects within this solution
25
25
  /// </summary>
26
- public List<ProjectStructure> Projects { get; set; }
26
+ public required List<ProjectStructure> Projects { get; set; }
27
27
  }
28
28
  }
@@ -19,7 +19,7 @@
19
19
  </ItemGroup>
20
20
 
21
21
  <ItemGroup>
22
- <ProjectReference Include="..\CodeAnalysis\CodeAnalyzer.csproj" />
22
+ <ProjectReference Include="..\CodeAnalyzer\CodeAnalyzer.csproj" />
23
23
  </ItemGroup>
24
24
 
25
25
  </Project>
@@ -0,0 +1,64 @@
1
+ using System;
2
+ using System.IO;
3
+ using System.Linq;
4
+ using Xunit;
5
+ using CodeAnalyzer.Parsers;
6
+ using CodeAnalyzer.Models;
7
+
8
+ namespace MermaidTests.Mermaid
9
+ {
10
+ public class ExtensionTypeTest
11
+ {
12
+ [Fact]
13
+ public void Parse_ExtensionType_HandlesEmptyIdentifier()
14
+ {
15
+ // Arrange
16
+ var testCode = @"
17
+ namespace TestNamespace
18
+ {
19
+ extension(Color)
20
+ {
21
+ public static Color GreenSmile()
22
+ {
23
+ return Color.FromArgb(83, 255, 26);
24
+ }
25
+ }
26
+ }";
27
+
28
+ var filePath = Path.GetTempFileName() + ".cs";
29
+ File.WriteAllText(filePath, testCode);
30
+
31
+ try
32
+ {
33
+ var parser = new FileParser<FileStructure>
34
+ {
35
+ FilePath = filePath,
36
+ Name = Path.GetFileName(filePath)
37
+ };
38
+
39
+ // Act
40
+ var result = parser.Parse();
41
+
42
+ // Assert
43
+ Assert.NotNull(result);
44
+ Assert.Single(result.Classes);
45
+ var extensionClass = result.Classes.First();
46
+
47
+ // This is what the user says is happening: it's empty.
48
+ // We want it to NOT be empty, or at least handle it gracefully.
49
+ Assert.Equal("extension(Color)", extensionClass.Name);
50
+
51
+ // Verify Relationship
52
+ Assert.NotNull(extensionClass.Relationships);
53
+ Assert.Single(extensionClass.Relationships);
54
+ var rel = extensionClass.Relationships.First();
55
+ Assert.Equal("Extension", rel.Type);
56
+ Assert.Equal("Color", rel.AssociatedItem);
57
+ }
58
+ finally
59
+ {
60
+ if (File.Exists(filePath)) File.Delete(filePath);
61
+ }
62
+ }
63
+ }
64
+ }
@@ -9,7 +9,7 @@ class ClassDiagramGenerator:
9
9
  Generates a Mermaid class diagram from a JSON representation of code structure.
10
10
  """
11
11
 
12
- def generate(self, data: Union[FileStructure, ProjectStructure, List[FileStructure]]) -> str:
12
+ def generate(self, data: Union[FileStructure, ProjectStructure, List[FileStructure]], summarize: bool = False) -> str:
13
13
  if not isinstance(data, FileStructure | ProjectStructure | list):
14
14
  return "Error: Invalid data structure"
15
15
 
@@ -19,7 +19,7 @@ class ClassDiagramGenerator:
19
19
  mermaid_lines = ["classDiagram"]
20
20
  # 1. Generate Class Definitions
21
21
  for cls in all_classes:
22
- mermaid_lines.extend(self._generate_class_block(cls))
22
+ mermaid_lines.extend(self._generate_class_block(cls, summarize))
23
23
 
24
24
  # 2. Generate Relationships
25
25
  mermaid_lines.extend(self._generate_relationships(all_classes))
@@ -58,7 +58,10 @@ class ClassDiagramGenerator:
58
58
 
59
59
  return classes
60
60
 
61
- def _generate_class_block(self, cls: ClassStructure) -> List[str]:
61
+ def _generate_class_block(self, cls: ClassStructure, summarize: bool = False) -> List[str]:
62
+ if summarize:
63
+ return [f" class {cls.name}", ""]
64
+
62
65
  lines = [f" class {cls.name} {{"]
63
66
 
64
67
  # Fields
@@ -129,6 +132,9 @@ class ClassDiagramGenerator:
129
132
  label = "inherits"
130
133
  if "interface" in relation.type.lower() or "implements" in relation.type.lower():
131
134
  label = "implements"
135
+ elif "extension" in relation.type.lower():
136
+ label = "extends"
137
+ connector = "<.."
132
138
 
133
139
  rel_lines.append(f" {relation.parent_name} {connector} {cls_name} : {label}")
134
140
 
@@ -153,10 +159,10 @@ class ClassDiagramGenerator:
153
159
 
154
160
  return sorted(list(set(rel_lines)))
155
161
 
156
- def generate_class_diagram(data: FileStructure | ProjectStructure) -> str:
162
+ def generate_class_diagram(data: FileStructure | ProjectStructure, summarize: bool = False) -> str:
157
163
  print("calling uml class generator ...")
158
164
  generator = ClassDiagramGenerator()
159
- return generator.generate(data)
165
+ return generator.generate(data, summarize)
160
166
 
161
167
  if __name__ == "__main__":
162
168
  import sys
@@ -8,9 +8,9 @@ class FlowchartDiagramGenerator:
8
8
  Generates a readable Mermaid flowchart from code structure.
9
9
  """
10
10
 
11
- def generate(self, data: Union['FileStructure', 'ProjectStructure', List['FileStructure']], file_name: str) -> str:
11
+ def generate(self, data: Union['FileStructure', 'ProjectStructure', List['FileStructure']], file_name: str, summarize: bool = False) -> str:
12
12
  mermaid_lines = ["graph TD"]
13
-
13
+
14
14
  # Track unique IDs to avoid conflicts in Mermaid
15
15
  self.counter = 0
16
16
 
@@ -21,31 +21,38 @@ class FlowchartDiagramGenerator:
21
21
  elif isinstance(data, list): files = data
22
22
 
23
23
  for file in files:
24
- file_id = f"file_{self._get_id()}"
24
+ # file_id = f"file_{self._get_id()}"
25
+ file_id = f"file_{file.id}" if file.id else f"file_{self._get_id()}"
25
26
  mermaid_lines.append(f' {file_id}["File: {file.name}"]')
26
-
27
+
27
28
  for cls in file.classes:
28
- cls_id = f"cls_{self._get_id()}"
29
+ # cls_id = f"cls_{self._get_id()}"
30
+ cls_id = f"cls_{cls.id}" if cls.id else f"cls_{self._get_id()}"
29
31
  mermaid_lines.append(f' {file_id} --> {cls_id}["Class: {cls.name}"]')
30
-
32
+
33
+ if summarize:
34
+ continue
35
+
31
36
  # Exclude private Properties
32
37
  fields = [f for f in cls.fields if f.modifier not in "private"]
33
38
  # If too many fields, don't overwhelm the diagram truncate
34
39
  fields = fields[:10] if len(fields) > 10 else fields
35
40
  for field in fields:
36
- f_id = f"f_{self._get_id()}"
41
+ # f_id = f"f_{self._get_id()}"
42
+ f_id = f"f_{field.id}" if field.id else f"f_{self._get_id()}"
37
43
  mermaid_lines.append(f' {cls_id} --> {f_id}["{field.name} ({field.type})"]')
38
44
 
39
45
  # Methods: Always helpful to see
40
46
  for method in cls.methods:
41
- m_id = f"m_{self._get_id()}"
47
+ # m_id = f"m_{self._get_id()}"
48
+ m_id = f"m_{method.id}" if method.id else f"m_{self._get_id()}"
42
49
  mermaid_lines.append(f' {cls_id} --> {m_id}{{"{method.name}()"}}')
43
-
50
+
44
51
  return "\n".join(mermaid_lines)
45
52
 
46
53
  def _get_id(self) -> int:
47
54
  self.counter += 1
48
55
  return self.counter
49
56
 
50
- def generate_flowchart_diagram(data, file_name) -> str:
51
- return FlowchartDiagramGenerator().generate(data, file_name)
57
+ def generate_flowchart_diagram(data, file_name, summarize: bool = False) -> str:
58
+ return FlowchartDiagramGenerator().generate(data, file_name, summarize)
@@ -9,7 +9,7 @@ class SequenceDiagramGenerator:
9
9
  def _sanitize(self, name: str) -> str:
10
10
  return re.sub(r'[^a-zA-Z0-9_ ]', '', name)
11
11
 
12
- def generate(self, data: Union['FileStructure', 'ProjectStructure', list['FileStructure']]) -> str:
12
+ def generate(self, data: Union['FileStructure', 'ProjectStructure', list['FileStructure']], summarize: bool = False) -> str:
13
13
  classes = self._extract_classes(data)
14
14
 
15
15
  mermaid_lines = ["sequenceDiagram", " autonumber"]
@@ -37,13 +37,15 @@ class SequenceDiagramGenerator:
37
37
  # Exclude private properties
38
38
  fields = [f for f in cls.fields if f.modifier != "private"]
39
39
  mermaid_lines.append(f" C->>{cls_alias}: Create {cls.name}")
40
- for field in fields[:5]: # Limit to 5 fields to avoid huge diagrams
41
- if not field.name.startswith('_'):
42
- mermaid_lines.append(f" {cls_alias}->>{cls_alias}: Set {self._sanitize(field.name)}")
40
+
41
+ if not summarize:
42
+ for field in cls.fields[:20]: # Limit to 20 fields to avoid huge diagrams
43
+ if not field.name.startswith('_'):
44
+ mermaid_lines.append(f" {cls_alias}->>{cls_alias}: Set {self._sanitize(field.name)}")
43
45
  else:
44
46
  # Exclude private methods
45
- methods = [m for m in cls.methods if m.modifier != "private"]
46
- for method in methods:
47
+ # methods = [m for m in cls.methods if m.modifier != "private"]
48
+ for method in cls.methods:
47
49
  if method.name.lower() in["dispose", "tostring", "equals", "gethashcode", "gettype"]:
48
50
  continue
49
51
 
@@ -70,8 +72,8 @@ class SequenceDiagramGenerator:
70
72
  if not type_str: return ""
71
73
  return re.split(r'[<\[]', type_str)[0].replace('?', '').split('.')[-1].strip()
72
74
 
73
- def generate_sequence_diagram(data) -> str:
74
- return SequenceDiagramGenerator().generate(data)
75
+ def generate_sequence_diagram(data, summarize: bool = False) -> str:
76
+ return SequenceDiagramGenerator().generate(data, summarize)
75
77
 
76
78
  if __name__ == "__main__":
77
79
  import sys
@@ -9,10 +9,10 @@ from cod8a.parsers.python_parser import PythonParser
9
9
  from cod8a.models.models import FileStructure, ProjectStructure
10
10
 
11
11
  # Path to the C# analyzer project
12
- DOTNET_ANALYZER_PATH = os.path.join(os.path.dirname(__file__), "..", "dotnet", "CodeAnalysis", "CodeAnalyzer.csproj")
12
+ DOTNET_ANALYZER_PATH = os.path.join(os.path.dirname(__file__), "..", "dotnet", "CodeAnalyzer", "CodeAnalyzer.csproj")
13
13
 
14
14
  def _get_parser(path: str):
15
- print(f"Checking analyzer ...")
15
+ print(f"Analyzing File ...")
16
16
  isDotnetParser = any(path.endswith(ext) for ext in [".cs", ".csproj", ".sln"]) or os.path.isdir(path) and any(f.endswith(".cs") for _, _, files in os.walk(path) for f in files)
17
17
  if isDotnetParser:
18
18
  return DotnetParser(DOTNET_ANALYZER_PATH)
@@ -25,7 +25,7 @@ def extract_structure(path) -> Union[FileStructure | ProjectStructure | list[Fil
25
25
 
26
26
  pathExists = os.path.exists(path)
27
27
  if not pathExists:
28
- print("Not found")
28
+ print("Not found: Ensure path doesn't end with a separator and points to a valid file or directory.")
29
29
  return
30
30
 
31
31
  struct = parser.parse(path or os.getcwd())
@@ -3,6 +3,7 @@ import json
3
3
  import os
4
4
  import shutil
5
5
  from typing import Union, List
6
+ from pathlib import Path
6
7
  from cod8a.models.models import (
7
8
  FileStructure, ProjectStructure, ClassStructure,
8
9
  MethodStructure, FieldStructure, ParameterStructure,
@@ -12,6 +13,7 @@ from cod8a.models.models import (
12
13
  class DotnetParser:
13
14
  def __init__(self, analyzer_path: str):
14
15
  self.analyzer_path = analyzer_path
16
+ self.file_name = ""
15
17
 
16
18
  def parse(self, path: str) -> Union[FileStructure, ProjectStructure]:
17
19
  if not shutil.which("dotnet"):
@@ -19,9 +21,14 @@ class DotnetParser:
19
21
 
20
22
  abs_path = os.path.abspath(path)
21
23
  cwd = os.path.dirname(self.analyzer_path)
24
+ self.file_name = Path(abs_path).stem
25
+
26
+ wdir = os.getcwd()
27
+ print(wdir)
28
+
22
29
 
23
30
  # Look for a compiled DLL first (production/distribution mode)
24
- # Expected path: src/cod8a/dotnet/CodeAnalysis/bin/Release/net10.0/CodeAnalyzer.dll
31
+ # Expected path: src/cod8a/dotnet/CodeAnalyzer/bin/Release/net10.0/CodeAnalyzer.dll
25
32
  dll_path = os.path.join(cwd, "bin", "Release", "net10.0", "CodeAnalyzer.dll")
26
33
 
27
34
  if os.path.exists(dll_path):
@@ -31,6 +38,7 @@ class DotnetParser:
31
38
  args = ["dotnet", "run", "--project", self.analyzer_path, "--", abs_path]
32
39
 
33
40
  result = subprocess.run(args, capture_output=True, text=True, cwd=cwd)
41
+
34
42
  if result.returncode != 0:
35
43
  raise Exception(f"Dotnet analyzer failed: {result.stderr}")
36
44
 
@@ -50,7 +58,7 @@ class DotnetParser:
50
58
 
51
59
  def _map_project(self, data: dict) -> ProjectStructure:
52
60
  return ProjectStructure(
53
- name=data.get("Name", ""),
61
+ name=self.file_name,
54
62
  files=[self._map_file(f) for f in data.get("Files", [])]
55
63
  )
56
64
 
File without changes
File without changes
File without changes
File without changes
File without changes