provenant/output_schema/
license_match.rs1use serde::{Deserialize, Serialize};
5
6#[derive(Serialize, Deserialize, Debug, Clone, PartialEq)]
7pub struct OutputMatch {
8 pub license_expression: String,
9 pub license_expression_spdx: String,
10 pub from_file: Option<String>,
11 pub start_line: u64,
12 pub end_line: u64,
13 #[serde(skip_serializing_if = "Option::is_none")]
14 pub matcher: Option<String>,
15 pub score: f64,
16 #[serde(skip_serializing_if = "Option::is_none")]
17 pub matched_length: Option<usize>,
18 #[serde(skip_serializing_if = "Option::is_none")]
19 pub match_coverage: Option<f64>,
20 #[serde(skip_serializing_if = "Option::is_none")]
21 pub rule_relevance: Option<u8>,
22 #[serde(skip_serializing_if = "Option::is_none")]
23 pub rule_identifier: Option<String>,
24 pub rule_url: Option<String>,
25 #[serde(skip_serializing_if = "Option::is_none")]
26 pub matched_text: Option<String>,
27 #[serde(skip_serializing_if = "Option::is_none")]
28 pub matched_text_diagnostics: Option<String>,
29 #[serde(skip_serializing_if = "Option::is_none", default)]
30 pub referenced_filenames: Option<Vec<String>>,
31}
32
33impl From<&crate::models::Match> for OutputMatch {
34 fn from(value: &crate::models::Match) -> Self {
35 Self {
36 license_expression: value.license_expression.clone(),
37 license_expression_spdx: value.license_expression_spdx.clone(),
38 from_file: value.from_file.clone(),
39 start_line: value.start_line.get() as u64,
40 end_line: value.end_line.get() as u64,
41 matcher: Some(value.matcher.to_string()),
42 score: value.score.value(),
43 matched_length: value.matched_length,
44 match_coverage: value.match_coverage,
45 rule_relevance: value.rule_relevance,
46 rule_identifier: (!value.rule_identifier.is_empty())
47 .then(|| value.rule_identifier.clone()),
48 rule_url: value.rule_url.clone(),
49 matched_text: value.matched_text.clone(),
50 matched_text_diagnostics: value.matched_text_diagnostics.clone(),
51 referenced_filenames: value.referenced_filenames.clone(),
52 }
53 }
54}
55
56impl TryFrom<&OutputMatch> for crate::models::Match {
57 type Error = String;
58 fn try_from(value: &OutputMatch) -> Result<Self, Self::Error> {
59 use crate::models::LineNumber;
60 let start_line = LineNumber::new(value.start_line as usize)
61 .ok_or_else(|| format!("invalid start_line: {}", value.start_line))?;
62 let end_line = LineNumber::new(value.end_line as usize)
63 .ok_or_else(|| format!("invalid end_line: {}", value.end_line))?;
64 Ok(Self {
65 license_expression: value.license_expression.clone(),
66 license_expression_spdx: value.license_expression_spdx.clone(),
67 from_file: value.from_file.clone(),
68 start_line,
69 end_line,
70 matcher: value
71 .matcher
72 .as_deref()
73 .and_then(|s| s.parse().ok())
74 .unwrap_or(crate::license_detection::MatcherKind::Unknown),
75 score: crate::models::MatchScore::from_percentage(value.score),
76 matched_length: value.matched_length,
77 match_coverage: value.match_coverage,
78 rule_relevance: value.rule_relevance,
79 rule_identifier: value.rule_identifier.clone().unwrap_or_default(),
80 rule_url: value.rule_url.clone(),
81 matched_text: value.matched_text.clone(),
82 matched_text_diagnostics: value.matched_text_diagnostics.clone(),
83 referenced_filenames: value.referenced_filenames.clone(),
84 })
85 }
86}