///|
/// Return the result message used by human-facing reports.
fn report_message(result : SarifResult) -> String {
match result.message.text {
Some(text) => text
None =>
match result.message.markdown {
Some(markdown) => markdown
None => ""
}
}
}
///|
fn report_level(result : SarifResult) -> String {
match result.level {
Some(level) => level
None => "none"
}
}
///|
fn report_baseline_state(result : SarifResult) -> String {
match result.baselineState {
Some(state) => state
None => "-"
}
}
///|
fn format_location(location : Location) -> String? {
match location.physicalLocation {
Some(physical) => {
let path = match physical.artifactLocation {
Some(artifact) =>
match artifact.uri {
Some(uri) => normalize_path(uri)
None => ""
}
None => ""
}
if path.is_empty() {
None
} else {
let line = match physical.region {
Some(region) =>
match region.startLine {
Some(value) => value.to_string()
None => ""
}
None => ""
}
let column = match physical.region {
Some(region) =>
match region.startColumn {
Some(value) => value.to_string()
None => ""
}
None => ""
}
let line_suffix = match line.is_empty() {
true => ""
false => ":" + line
}
let column_suffix = match column.is_empty() {
true => ""
false => ":" + column
}
Some(path + line_suffix + column_suffix)
}
}
None => None
}
}
///|
fn report_location(result : SarifResult) -> String {
match result.locations {
Some(locations) => {
for location in locations {
match format_location(location) {
Some(value) => return value
None => ()
}
}
"-"
}
None => "-"
}
}
///|
fn markdown_cell(value : String) -> String {
value.replace(old="|", new="\\|").replace(old="\n", new="
")
}
///|
fn html_escape(value : String) -> String {
value
.replace(old="&", new="&")
.replace(old="<", new="<")
.replace(old=">", new=">")
.replace(old="\"", new=""")
.replace(old="'", new="'")
.replace(old="\n", new="
")
}
///|
/// Render a compact Markdown report for a SARIF log.
pub fn render_markdown(log : SarifLog) -> String {
let summary = summarize(log)
let output = "# MoonSARIF Report\n\n" +
"## Summary\n\n" +
"| Metric | Value |\n| --- | ---: |\n" +
"| Runs | " +
summary.run_count.to_string() +
" |\n" +
"| Results | " +
summary.result_count.to_string() +
" |\n" +
"| Errors | " +
summary.error_count.to_string() +
" |\n" +
"| Warnings | " +
summary.warning_count.to_string() +
" |\n" +
"| Notes | " +
summary.note_count.to_string() +
" |\n" +
"| None | " +
summary.none_count.to_string() +
" |\n" +
"| Rules | " +
summary.unique_rule_count.to_string() +
" |\n\n" +
"## Findings\n\n" +
"| # | Level | Rule | Location | Message | Baseline |\n" +
"| ---: | --- | --- | --- | --- | --- |\n"
let mut body = ""
let mut index = 1
for run in log.runs {
match run.results {
Some(results) =>
for result in results {
let rule = match result.ruleId {
Some(value) => value
None => "-"
}
body += "| " +
index.to_string() +
" | " +
markdown_cell(report_level(result)) +
" | " +
markdown_cell(rule) +
" | " +
markdown_cell(report_location(result)) +
" | " +
markdown_cell(report_message(result)) +
" | " +
markdown_cell(report_baseline_state(result)) +
" |\n"
index += 1
}
None => ()
}
}
output + body
}
///|
/// Render a self-contained HTML report for a SARIF log.
pub fn render_html(log : SarifLog) -> String {
let summary = summarize(log)
let mut rows = ""
let mut index = 1
for run in log.runs {
match run.results {
Some(results) =>
for result in results {
let rule = match result.ruleId {
Some(value) => value
None => "-"
}
let level = report_level(result)
rows += "" +
index.to_string() +
" " +
html_escape(level) +
" " +
html_escape(rule) +
" " +
html_escape(report_location(result)) +
" " +
html_escape(report_message(result)) +
" " +
html_escape(report_baseline_state(result)) +
" \n"
index += 1
}
None => ()
}
}
"\n" +
"" +
"MoonSARIF Report MoonSARIF Report
" +
"" +
summary.run_count.to_string() +
"Runs" +
summary.result_count.to_string() +
"Results" +
summary.error_count.to_string() +
"Errors" +
summary.warning_count.to_string() +
"Warnings" +
summary.note_count.to_string() +
"Notes" +
summary.unique_rule_count.to_string() +
"RulesFindings
" +
"# Level Rule Location Message Baseline " +
rows +
"
"
}