Skip to content

Commit 6839b7b

Browse files
Refactor SarifResults.Read to reduce cognitive complexity (#26)
* Initial plan * Refactor SarifResults.Read method to reduce cognitive complexity Co-authored-by: Malcolmnixon <1863707+Malcolmnixon@users.noreply.github.com> --------- Co-authored-by: copilot-swe-agent[bot] <198982749+Copilot@users.noreply.github.com> Co-authored-by: Malcolmnixon <1863707+Malcolmnixon@users.noreply.github.com>
1 parent eb4d0e3 commit 6839b7b

File tree

1 file changed

+172
-83
lines changed

1 file changed

+172
-83
lines changed

src/DemaConsulting.SarifMark/SarifResults.cs

Lines changed: 172 additions & 83 deletions
Original file line numberDiff line numberDiff line change
@@ -87,101 +87,190 @@ public static SarifResults Read(string filePath)
8787
using var document = JsonDocument.Parse(json);
8888
var root = document.RootElement;
8989

90-
// Validate SARIF version
91-
if (!root.TryGetProperty("version", out _))
92-
{
93-
throw new InvalidOperationException("Invalid SARIF file: missing 'version' property.");
94-
}
90+
var firstRun = ValidateSarifStructure(root);
91+
var (toolName, toolVersion) = ExtractToolInformation(firstRun);
92+
var results = ParseResults(firstRun);
9593

96-
// Get runs array
97-
if (!root.TryGetProperty("runs", out var runsElement) || runsElement.ValueKind != JsonValueKind.Array)
98-
{
99-
throw new InvalidOperationException("Invalid SARIF file: missing or invalid 'runs' array.");
100-
}
94+
return new SarifResults(toolName, toolVersion, results);
95+
}
96+
catch (JsonException ex)
97+
{
98+
throw new InvalidOperationException($"Invalid JSON in SARIF file: {ex.Message}", ex);
99+
}
100+
}
101101

102-
var runs = runsElement.EnumerateArray();
103-
if (!runs.Any())
104-
{
105-
throw new InvalidOperationException("Invalid SARIF file: 'runs' array is empty.");
106-
}
102+
/// <summary>
103+
/// Validates the SARIF file structure and returns the first run element.
104+
/// </summary>
105+
/// <param name="root">The root JSON element.</param>
106+
/// <returns>The first run element.</returns>
107+
/// <exception cref="InvalidOperationException">Thrown when the SARIF structure is invalid.</exception>
108+
private static JsonElement ValidateSarifStructure(JsonElement root)
109+
{
110+
if (!root.TryGetProperty("version", out _))
111+
{
112+
throw new InvalidOperationException("Invalid SARIF file: missing 'version' property.");
113+
}
107114

108-
// Get the first run
109-
var firstRun = runs.First();
115+
if (!root.TryGetProperty("runs", out var runsElement) || runsElement.ValueKind != JsonValueKind.Array)
116+
{
117+
throw new InvalidOperationException("Invalid SARIF file: missing or invalid 'runs' array.");
118+
}
110119

111-
// Get tool information
112-
if (!firstRun.TryGetProperty("tool", out var toolElement))
113-
{
114-
throw new InvalidOperationException("Invalid SARIF file: missing 'tool' property in run.");
115-
}
120+
var runs = runsElement.EnumerateArray();
121+
if (!runs.Any())
122+
{
123+
throw new InvalidOperationException("Invalid SARIF file: 'runs' array is empty.");
124+
}
116125

117-
if (!toolElement.TryGetProperty("driver", out var driverElement))
118-
{
119-
throw new InvalidOperationException("Invalid SARIF file: missing 'driver' property in tool.");
120-
}
126+
return runs.First();
127+
}
121128

122-
var toolName = driverElement.TryGetProperty("name", out var nameElement)
123-
? nameElement.GetString() ?? "Unknown"
124-
: "Unknown";
129+
/// <summary>
130+
/// Extracts tool information from a run element.
131+
/// </summary>
132+
/// <param name="runElement">The run JSON element.</param>
133+
/// <returns>A tuple containing the tool name and version.</returns>
134+
/// <exception cref="InvalidOperationException">Thrown when tool information is missing.</exception>
135+
private static (string ToolName, string ToolVersion) ExtractToolInformation(JsonElement runElement)
136+
{
137+
if (!runElement.TryGetProperty("tool", out var toolElement))
138+
{
139+
throw new InvalidOperationException("Invalid SARIF file: missing 'tool' property in run.");
140+
}
125141

126-
var toolVersion = driverElement.TryGetProperty("version", out var toolVersionElement)
127-
? toolVersionElement.GetString() ?? "Unknown"
128-
: "Unknown";
142+
if (!toolElement.TryGetProperty("driver", out var driverElement))
143+
{
144+
throw new InvalidOperationException("Invalid SARIF file: missing 'driver' property in tool.");
145+
}
129146

130-
// Parse results
131-
var results = new List<SarifResult>();
132-
if (firstRun.TryGetProperty("results", out var resultsElement) &&
133-
resultsElement.ValueKind == JsonValueKind.Array)
134-
{
135-
foreach (var resultElement in resultsElement.EnumerateArray())
136-
{
137-
var ruleId = resultElement.TryGetProperty("ruleId", out var ruleIdElement)
138-
? ruleIdElement.GetString() ?? string.Empty
139-
: string.Empty;
140-
141-
var level = resultElement.TryGetProperty("level", out var levelElement)
142-
? levelElement.GetString() ?? "warning"
143-
: "warning";
144-
145-
var message = string.Empty;
146-
if (resultElement.TryGetProperty("message", out var messageElement) &&
147-
messageElement.TryGetProperty("text", out var messageTextElement))
148-
{
149-
message = messageTextElement.GetString() ?? string.Empty;
150-
}
151-
152-
string? uri = null;
153-
int? startLine = null;
154-
if (resultElement.TryGetProperty("locations", out var locationsElement) &&
155-
locationsElement.ValueKind == JsonValueKind.Array)
156-
{
157-
var firstLocation = locationsElement.EnumerateArray().FirstOrDefault();
158-
if (firstLocation.ValueKind != JsonValueKind.Undefined &&
159-
firstLocation.TryGetProperty("physicalLocation", out var physicalLocationElement))
160-
{
161-
if (physicalLocationElement.TryGetProperty("artifactLocation", out var artifactLocationElement) &&
162-
artifactLocationElement.TryGetProperty("uri", out var uriElement))
163-
{
164-
uri = uriElement.GetString();
165-
}
166-
167-
if (physicalLocationElement.TryGetProperty("region", out var regionElement) &&
168-
regionElement.TryGetProperty("startLine", out var startLineElement))
169-
{
170-
startLine = startLineElement.GetInt32();
171-
}
172-
}
173-
}
174-
175-
results.Add(new SarifResult(ruleId, level, message, uri, startLine));
176-
}
177-
}
147+
var toolName = driverElement.TryGetProperty("name", out var nameElement)
148+
? nameElement.GetString() ?? "Unknown"
149+
: "Unknown";
178150

179-
return new SarifResults(toolName, toolVersion, results);
151+
var toolVersion = driverElement.TryGetProperty("version", out var toolVersionElement)
152+
? toolVersionElement.GetString() ?? "Unknown"
153+
: "Unknown";
154+
155+
return (toolName, toolVersion);
156+
}
157+
158+
/// <summary>
159+
/// Parses all results from a run element.
160+
/// </summary>
161+
/// <param name="runElement">The run JSON element.</param>
162+
/// <returns>A list of parsed SARIF results.</returns>
163+
private static List<SarifResult> ParseResults(JsonElement runElement)
164+
{
165+
var results = new List<SarifResult>();
166+
167+
if (!runElement.TryGetProperty("results", out var resultsElement) ||
168+
resultsElement.ValueKind != JsonValueKind.Array)
169+
{
170+
return results;
180171
}
181-
catch (JsonException ex)
172+
173+
foreach (var resultElement in resultsElement.EnumerateArray())
182174
{
183-
throw new InvalidOperationException($"Invalid JSON in SARIF file: {ex.Message}", ex);
175+
results.Add(ParseResult(resultElement));
176+
}
177+
178+
return results;
179+
}
180+
181+
/// <summary>
182+
/// Parses a single result element.
183+
/// </summary>
184+
/// <param name="resultElement">The result JSON element.</param>
185+
/// <returns>A parsed SARIF result.</returns>
186+
private static SarifResult ParseResult(JsonElement resultElement)
187+
{
188+
var ruleId = resultElement.TryGetProperty("ruleId", out var ruleIdElement)
189+
? ruleIdElement.GetString() ?? string.Empty
190+
: string.Empty;
191+
192+
var level = resultElement.TryGetProperty("level", out var levelElement)
193+
? levelElement.GetString() ?? "warning"
194+
: "warning";
195+
196+
var message = ParseMessage(resultElement);
197+
var (uri, startLine) = ParseLocation(resultElement);
198+
199+
return new SarifResult(ruleId, level, message, uri, startLine);
200+
}
201+
202+
/// <summary>
203+
/// Parses the message from a result element.
204+
/// </summary>
205+
/// <param name="resultElement">The result JSON element.</param>
206+
/// <returns>The message text.</returns>
207+
private static string ParseMessage(JsonElement resultElement)
208+
{
209+
if (resultElement.TryGetProperty("message", out var messageElement) &&
210+
messageElement.TryGetProperty("text", out var messageTextElement))
211+
{
212+
return messageTextElement.GetString() ?? string.Empty;
213+
}
214+
215+
return string.Empty;
216+
}
217+
218+
/// <summary>
219+
/// Parses location information from a result element.
220+
/// </summary>
221+
/// <param name="resultElement">The result JSON element.</param>
222+
/// <returns>A tuple containing the URI and start line.</returns>
223+
private static (string? Uri, int? StartLine) ParseLocation(JsonElement resultElement)
224+
{
225+
if (!resultElement.TryGetProperty("locations", out var locationsElement) ||
226+
locationsElement.ValueKind != JsonValueKind.Array)
227+
{
228+
return (null, null);
229+
}
230+
231+
var firstLocation = locationsElement.EnumerateArray().FirstOrDefault();
232+
if (firstLocation.ValueKind == JsonValueKind.Undefined ||
233+
!firstLocation.TryGetProperty("physicalLocation", out var physicalLocationElement))
234+
{
235+
return (null, null);
184236
}
237+
238+
var uri = ParseUri(physicalLocationElement);
239+
var startLine = ParseStartLine(physicalLocationElement);
240+
241+
return (uri, startLine);
242+
}
243+
244+
/// <summary>
245+
/// Parses the URI from a physical location element.
246+
/// </summary>
247+
/// <param name="physicalLocationElement">The physical location JSON element.</param>
248+
/// <returns>The URI string or null.</returns>
249+
private static string? ParseUri(JsonElement physicalLocationElement)
250+
{
251+
if (physicalLocationElement.TryGetProperty("artifactLocation", out var artifactLocationElement) &&
252+
artifactLocationElement.TryGetProperty("uri", out var uriElement))
253+
{
254+
return uriElement.GetString();
255+
}
256+
257+
return null;
258+
}
259+
260+
/// <summary>
261+
/// Parses the start line from a physical location element.
262+
/// </summary>
263+
/// <param name="physicalLocationElement">The physical location JSON element.</param>
264+
/// <returns>The start line number or null.</returns>
265+
private static int? ParseStartLine(JsonElement physicalLocationElement)
266+
{
267+
if (physicalLocationElement.TryGetProperty("region", out var regionElement) &&
268+
regionElement.TryGetProperty("startLine", out var startLineElement))
269+
{
270+
return startLineElement.GetInt32();
271+
}
272+
273+
return null;
185274
}
186275

187276
/// <summary>

0 commit comments

Comments
 (0)