use serde::{Deserialize, Serialize};
use crate::unit::Unit;
#[derive(Clone, Debug, PartialEq, Serialize, Deserialize)]
#[serde(rename_all = "camelCase")]
pub struct CodebaseIndex {
pub schema_version: String,
pub build: IndexBuild,
pub packages: Vec<PackageRecord>,
pub traceability: Traceability,
pub diagnostics: Diagnostics,
}
#[derive(Clone, Debug, PartialEq, Eq, Serialize, Deserialize)]
#[serde(rename_all = "camelCase")]
pub struct IndexBuild {
pub indexer_id: String,
pub indexer_version: String,
pub repo_root: String,
pub content_hash: String,
}
#[derive(Clone, Copy, Debug, PartialEq, Eq, Serialize, Deserialize)]
#[serde(rename_all = "kebab-case")]
pub enum PackageKind {
RustLib,
RustBin,
RustLibBin,
NpmPackage,
NpmWorkspace,
}
#[derive(Clone, Debug, PartialEq, Eq, Serialize, Deserialize)]
#[serde(rename_all = "camelCase")]
pub struct PackageRecord {
pub name: String,
pub path: String,
pub kind: PackageKind,
#[serde(default, skip_serializing_if = "Option::is_none")]
pub version: Option<String>,
#[serde(default, skip_serializing_if = "Option::is_none")]
pub edition: Option<String>,
#[serde(default, skip_serializing_if = "Option::is_none")]
pub spec_ref: Option<String>,
}
#[derive(Clone, Debug, PartialEq, Serialize, Deserialize)]
#[serde(rename_all = "camelCase")]
pub struct Traceability {
pub mappings: Vec<TraceMapping>,
pub orphaned_specs: Vec<String>,
pub untraced_code: Vec<String>,
}
#[derive(Clone, Debug, PartialEq, Serialize, Deserialize)]
#[serde(rename_all = "camelCase")]
pub struct TraceMapping {
pub spec_id: String,
#[serde(default, skip_serializing_if = "Option::is_none")]
pub spec_status: Option<String>,
#[serde(default, skip_serializing_if = "Vec::is_empty")]
pub depends_on: Vec<String>,
#[serde(default, skip_serializing_if = "Vec::is_empty")]
pub amends: Vec<String>,
#[serde(default, skip_serializing_if = "Option::is_none")]
pub amendment_record: Option<String>,
pub implementing_paths: Vec<ImplementingPath>,
#[serde(default, skip_serializing_if = "Vec::is_empty")]
pub resolved_units: Vec<ResolvedUnit>,
}
#[derive(Clone, Copy, Debug, PartialEq, Eq, PartialOrd, Ord, Serialize, Deserialize)]
#[serde(rename_all = "kebab-case")]
pub enum TraceSource {
SpecEdge,
ManifestMetadata,
CommentHeader,
Multiple,
}
#[derive(Clone, Debug, PartialEq, Eq, Serialize, Deserialize)]
#[serde(rename_all = "camelCase")]
pub struct ImplementingPath {
pub path: String,
pub source: TraceSource,
}
#[derive(Clone, Copy, Debug, PartialEq, Eq, Serialize, Deserialize)]
#[serde(rename_all = "snake_case")]
pub enum SourceField {
Establishes,
Extends,
Refines,
Supersedes,
Amends,
CoAuthority,
Constrains,
References,
}
impl SourceField {
pub fn is_ownership(self) -> bool {
!matches!(self, SourceField::References)
}
}
#[derive(Clone, Debug, PartialEq, Eq, Serialize, Deserialize)]
#[serde(rename_all = "camelCase")]
pub struct ResolvedUnit {
pub unit: Unit,
pub source_field: SourceField,
pub ownership: bool,
pub locations: Vec<ResolvedLocation>,
}
#[derive(Clone, Debug, PartialEq, Eq, Serialize, Deserialize)]
#[serde(rename_all = "camelCase")]
pub struct ResolvedLocation {
pub file: String,
#[serde(default, skip_serializing_if = "Option::is_none")]
pub span: Option<LineSpan>,
}
#[derive(Clone, Copy, Debug, PartialEq, Eq, Serialize, Deserialize)]
#[serde(rename_all = "camelCase")]
pub struct LineSpan {
pub start_line: usize,
pub end_line: usize,
}
impl LineSpan {
pub fn new(start_line: usize, end_line: usize) -> Self {
LineSpan {
start_line,
end_line,
}
}
}
#[derive(Clone, Debug, PartialEq, Eq, Default, Serialize, Deserialize)]
#[serde(rename_all = "camelCase")]
pub struct Diagnostics {
pub warnings: Vec<Diagnostic>,
pub errors: Vec<Diagnostic>,
}
#[derive(Clone, Debug, PartialEq, Eq, Serialize, Deserialize)]
#[serde(rename_all = "camelCase")]
pub struct Diagnostic {
pub code: String,
pub message: String,
#[serde(default, skip_serializing_if = "Option::is_none")]
pub path: Option<String>,
}