1use serde::{Deserialize, Serialize};
2
3use super::super::{DomainError, GraphVersion, RepositoryCodeRange, error::required_text};
4use super::validation::{normalize_optional, stable_software_id, validate_confidence};
5
6#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
8pub struct SoftwareBuildTarget {
9 pub target_id: String,
10 pub repository_id: String,
11 pub source_scope: String,
12 pub ecosystem: String,
13 pub language_id: String,
14 pub name: String,
15 pub kind: String,
16 #[serde(skip_serializing_if = "Option::is_none")]
17 pub command: Option<String>,
18 #[serde(skip_serializing_if = "Option::is_none")]
19 pub output_hint: Option<String>,
20 pub source_kind: String,
21 pub evidence_path: String,
22 pub evidence_line_range: RepositoryCodeRange,
23 pub confidence_basis_points: u16,
24 pub created_graph_version: GraphVersion,
25}
26
27impl SoftwareBuildTarget {
28 pub fn new(input: SoftwareBuildTargetInput) -> Result<Self, DomainError> {
30 let source_scope = required_text("source_scope", input.source_scope)?;
31 let ecosystem = required_text("ecosystem", input.ecosystem)?;
32 let language_id = required_text("language_id", input.language_id)?;
33 let name = required_text("build_target_name", input.name)?;
34 let kind = required_text("build_target_kind", input.kind)?;
35 let command = normalize_optional("command", input.command)?;
36 let output_hint = normalize_optional("output_hint", input.output_hint)?;
37 let source_kind = required_text("source_kind", input.source_kind)?;
38 let evidence_path = required_text("evidence_path", input.evidence_path)?;
39 let line_start = input.evidence_line_range.start.to_string();
40
41 Ok(Self {
42 target_id: stable_software_id(
43 "build_target",
44 [
45 source_scope.as_str(),
46 ecosystem.as_str(),
47 language_id.as_str(),
48 name.as_str(),
49 kind.as_str(),
50 source_kind.as_str(),
51 evidence_path.as_str(),
52 line_start.as_str(),
53 ],
54 ),
55 repository_id: required_text("repository_id", input.repository_id)?,
56 source_scope,
57 ecosystem,
58 language_id,
59 name,
60 kind,
61 command,
62 output_hint,
63 source_kind,
64 evidence_path,
65 evidence_line_range: input.evidence_line_range,
66 confidence_basis_points: validate_confidence(input.confidence_basis_points)?,
67 created_graph_version: input.created_graph_version,
68 })
69 }
70}
71
72#[derive(Debug, Clone, PartialEq, Eq)]
74pub struct SoftwareBuildTargetInput {
75 pub repository_id: String,
76 pub source_scope: String,
77 pub ecosystem: String,
78 pub language_id: String,
79 pub name: String,
80 pub kind: String,
81 pub command: Option<String>,
82 pub output_hint: Option<String>,
83 pub source_kind: String,
84 pub evidence_path: String,
85 pub evidence_line_range: RepositoryCodeRange,
86 pub confidence_basis_points: u16,
87 pub created_graph_version: GraphVersion,
88}
89
90#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
92pub struct SoftwareIacResource {
93 pub resource_id: String,
94 pub repository_id: String,
95 pub source_scope: String,
96 pub language_id: String,
97 pub provider: String,
98 pub resource_kind: String,
99 pub name: String,
100 #[serde(skip_serializing_if = "Option::is_none")]
101 pub scope_hint: Option<String>,
102 #[serde(skip_serializing_if = "Option::is_none")]
103 pub target_hint: Option<String>,
104 pub resolution_state: String,
105 pub source_kind: String,
106 pub evidence_path: String,
107 pub evidence_line_range: RepositoryCodeRange,
108 pub confidence_basis_points: u16,
109 pub created_graph_version: GraphVersion,
110}
111
112impl SoftwareIacResource {
113 pub fn new(input: SoftwareIacResourceInput) -> Result<Self, DomainError> {
115 let source_scope = required_text("source_scope", input.source_scope)?;
116 let language_id = required_text("language_id", input.language_id)?;
117 let provider = required_text("iac_provider", input.provider)?;
118 let resource_kind = required_text("iac_resource_kind", input.resource_kind)?;
119 let name = required_text("iac_resource_name", input.name)?;
120 let scope_hint = normalize_optional("scope_hint", input.scope_hint)?;
121 let target_hint = normalize_optional("target_hint", input.target_hint)?;
122 let resolution_state = required_text("resolution_state", input.resolution_state)?;
123 let source_kind = required_text("source_kind", input.source_kind)?;
124 let evidence_path = required_text("evidence_path", input.evidence_path)?;
125 let line_start = input.evidence_line_range.start.to_string();
126
127 Ok(Self {
128 resource_id: stable_software_id(
129 "iac_resource",
130 [
131 source_scope.as_str(),
132 language_id.as_str(),
133 provider.as_str(),
134 resource_kind.as_str(),
135 name.as_str(),
136 source_kind.as_str(),
137 evidence_path.as_str(),
138 line_start.as_str(),
139 ],
140 ),
141 repository_id: required_text("repository_id", input.repository_id)?,
142 source_scope,
143 language_id,
144 provider,
145 resource_kind,
146 name,
147 scope_hint,
148 target_hint,
149 resolution_state,
150 source_kind,
151 evidence_path,
152 evidence_line_range: input.evidence_line_range,
153 confidence_basis_points: validate_confidence(input.confidence_basis_points)?,
154 created_graph_version: input.created_graph_version,
155 })
156 }
157}
158
159#[derive(Debug, Clone, PartialEq, Eq)]
161pub struct SoftwareIacResourceInput {
162 pub repository_id: String,
163 pub source_scope: String,
164 pub language_id: String,
165 pub provider: String,
166 pub resource_kind: String,
167 pub name: String,
168 pub scope_hint: Option<String>,
169 pub target_hint: Option<String>,
170 pub resolution_state: String,
171 pub source_kind: String,
172 pub evidence_path: String,
173 pub evidence_line_range: RepositoryCodeRange,
174 pub confidence_basis_points: u16,
175 pub created_graph_version: GraphVersion,
176}
177
178#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
180pub struct SoftwareDesignElement {
181 pub element_id: String,
182 pub repository_id: String,
183 pub source_scope: String,
184 pub language_id: String,
185 pub element_kind: String,
186 pub name: String,
187 #[serde(skip_serializing_if = "Option::is_none")]
188 pub parent: Option<String>,
189 #[serde(skip_serializing_if = "Option::is_none")]
190 pub summary: Option<String>,
191 pub source_kind: String,
192 pub evidence_path: String,
193 pub evidence_line_range: RepositoryCodeRange,
194 pub confidence_basis_points: u16,
195 pub created_graph_version: GraphVersion,
196}
197
198impl SoftwareDesignElement {
199 pub fn new(input: SoftwareDesignElementInput) -> Result<Self, DomainError> {
201 let source_scope = required_text("source_scope", input.source_scope)?;
202 let language_id = required_text("language_id", input.language_id)?;
203 let element_kind = required_text("design_element_kind", input.element_kind)?;
204 let name = required_text("design_element_name", input.name)?;
205 let parent = normalize_optional("parent", input.parent)?;
206 let summary = normalize_optional("summary", input.summary)?;
207 let source_kind = required_text("source_kind", input.source_kind)?;
208 let evidence_path = required_text("evidence_path", input.evidence_path)?;
209 let line_start = input.evidence_line_range.start.to_string();
210
211 Ok(Self {
212 element_id: stable_software_id(
213 "design_element",
214 [
215 source_scope.as_str(),
216 language_id.as_str(),
217 element_kind.as_str(),
218 name.as_str(),
219 source_kind.as_str(),
220 evidence_path.as_str(),
221 line_start.as_str(),
222 ],
223 ),
224 repository_id: required_text("repository_id", input.repository_id)?,
225 source_scope,
226 language_id,
227 element_kind,
228 name,
229 parent,
230 summary,
231 source_kind,
232 evidence_path,
233 evidence_line_range: input.evidence_line_range,
234 confidence_basis_points: validate_confidence(input.confidence_basis_points)?,
235 created_graph_version: input.created_graph_version,
236 })
237 }
238}
239
240#[derive(Debug, Clone, PartialEq, Eq)]
242pub struct SoftwareDesignElementInput {
243 pub repository_id: String,
244 pub source_scope: String,
245 pub language_id: String,
246 pub element_kind: String,
247 pub name: String,
248 pub parent: Option<String>,
249 pub summary: Option<String>,
250 pub source_kind: String,
251 pub evidence_path: String,
252 pub evidence_line_range: RepositoryCodeRange,
253 pub confidence_basis_points: u16,
254 pub created_graph_version: GraphVersion,
255}
256
257#[cfg(test)]
258#[path = "lifecycle_tests.rs"]
259mod tests;