use super::GamePathBuf;
use serde::{Deserialize, Serialize};
#[derive(
Clone,
Copy,
Debug,
Eq,
PartialEq,
Serialize,
Deserialize,
rkyv::Archive,
rkyv::Serialize,
rkyv::Deserialize,
)]
#[serde(rename_all = "snake_case")]
pub enum DocumentFamily {
Clausewitz,
Localisation,
Csv,
Json,
}
#[derive(Clone, Debug, Serialize, Deserialize)]
pub struct DocumentRecord {
pub mod_id: String,
pub path: GamePathBuf,
pub family: DocumentFamily,
pub parse_ok: bool,
}
#[derive(Clone, Debug, Serialize, Deserialize)]
pub struct LocalisationDefinition {
pub key: String,
pub mod_id: String,
pub path: GamePathBuf,
pub line: usize,
pub column: usize,
}
#[derive(Clone, Debug, Serialize, Deserialize)]
pub struct LocalisationDuplicate {
pub key: String,
pub mod_id: String,
pub path: GamePathBuf,
pub first_line: usize,
pub duplicate_line: usize,
}
#[derive(Clone, Debug, Serialize, Deserialize)]
pub struct UiDefinition {
pub name: String,
pub mod_id: String,
pub path: GamePathBuf,
pub line: usize,
pub column: usize,
}
#[derive(Clone, Debug, Serialize, Deserialize)]
pub struct ResourceReference {
pub key: String,
pub value: String,
pub mod_id: String,
pub path: GamePathBuf,
pub line: usize,
pub column: usize,
}
#[derive(Clone, Debug, Serialize, Deserialize)]
pub struct CsvRow {
pub identity: String,
pub mod_id: String,
pub path: GamePathBuf,
pub line: usize,
pub column: usize,
}
#[derive(Clone, Debug, Serialize, Deserialize)]
pub struct JsonProperty {
pub key_path: String,
pub mod_id: String,
pub path: GamePathBuf,
pub line: usize,
pub column: usize,
}
#[derive(Clone, Debug, Serialize, Deserialize)]
pub struct ParseIssue {
pub mod_id: String,
pub path: GamePathBuf,
pub line: usize,
pub column: usize,
pub message: String,
#[serde(default, skip_serializing_if = "Option::is_none")]
pub repair: Option<SourceRepair>,
#[serde(default, skip_serializing_if = "Option::is_none")]
pub isolation: Option<Isolation>,
}
impl ParseIssue {
pub fn is_fatal(&self) -> bool {
self.repair.is_none() && self.isolation.is_none()
}
}
pub fn has_fatal_parse_issue(issues: &[ParseIssue]) -> bool {
issues.iter().any(ParseIssue::is_fatal)
}
pub fn reads_completely(issues: &[ParseIssue]) -> bool {
issues.iter().all(|issue| issue.repair.is_some())
}
pub fn isolated_definitions(issues: &[ParseIssue]) -> impl Iterator<Item = &Isolation> {
issues.iter().filter_map(|issue| issue.isolation.as_ref())
}
#[derive(
Clone,
Debug,
Eq,
PartialEq,
Serialize,
Deserialize,
rkyv::Archive,
rkyv::Serialize,
rkyv::Deserialize,
)]
pub struct Isolation {
pub definition: String,
pub end_line: usize,
pub proposals: Vec<RepairProposal>,
#[serde(default, skip_serializing_if = "Option::is_none")]
pub dropped: Option<LineRange>,
}
#[derive(
Clone,
Copy,
Debug,
Eq,
PartialEq,
Serialize,
Deserialize,
rkyv::Archive,
rkyv::Serialize,
rkyv::Deserialize,
)]
pub struct LineRange {
pub first: usize,
pub last: usize,
}
#[derive(
Clone,
Copy,
Debug,
Eq,
PartialEq,
Serialize,
Deserialize,
rkyv::Archive,
rkyv::Serialize,
rkyv::Deserialize,
)]
pub struct RepairProposal {
pub edit: SourceRepairEdit,
pub line: usize,
pub column: usize,
pub offset: usize,
}
impl RepairProposal {
pub fn description(self) -> String {
let edit = match self.edit {
SourceRepairEdit::RemovedClosingBrace => "leave out the `}`",
SourceRepairEdit::RemovedOpeningBrace => "leave out the `{`",
SourceRepairEdit::InsertedClosingBrace => "add a `}`",
SourceRepairEdit::InsertedOpeningBrace => "add a `{`",
SourceRepairEdit::ClosedStringAtLineEnd => "end the string",
SourceRepairEdit::RemovedEmptyAssignment => "leave out the empty assignment",
};
format!("{edit} at {}:{}", self.line, self.column)
}
}
#[derive(
Clone,
Copy,
Debug,
Eq,
Hash,
Ord,
PartialEq,
PartialOrd,
Serialize,
Deserialize,
rkyv::Archive,
rkyv::Serialize,
rkyv::Deserialize,
)]
pub struct SourceRepair {
pub edit: SourceRepairEdit,
pub evidence: SourceRepairEvidence,
}
#[derive(
Clone,
Copy,
Debug,
Eq,
Hash,
Ord,
PartialEq,
PartialOrd,
Serialize,
Deserialize,
rkyv::Archive,
rkyv::Serialize,
rkyv::Deserialize,
)]
#[serde(rename_all = "snake_case")]
pub enum SourceRepairEdit {
RemovedClosingBrace,
RemovedOpeningBrace,
InsertedClosingBrace,
InsertedOpeningBrace,
ClosedStringAtLineEnd,
RemovedEmptyAssignment,
}
#[derive(
Clone,
Copy,
Debug,
Eq,
Hash,
Ord,
PartialEq,
PartialOrd,
Serialize,
Deserialize,
rkyv::Archive,
rkyv::Serialize,
rkyv::Deserialize,
)]
#[serde(rename_all = "snake_case")]
pub enum SourceRepairEvidence {
OnlyReading,
NothingLost,
OnlySchemaValid,
SmallestChange,
}
impl SourceRepair {
pub fn description(self) -> String {
let edit = match self.edit {
SourceRepairEdit::RemovedClosingBrace => "left out an unmatched `}`",
SourceRepairEdit::RemovedOpeningBrace => "left out an unclosed `{`",
SourceRepairEdit::InsertedClosingBrace => "added a missing `}`",
SourceRepairEdit::InsertedOpeningBrace => "added a missing `{`",
SourceRepairEdit::ClosedStringAtLineEnd => {
"ended an unterminated string at the end of its line"
}
SourceRepairEdit::RemovedEmptyAssignment => "left out an assignment with no value",
};
let evidence = match self.evidence {
SourceRepairEvidence::OnlyReading => "every one-token repair reads the same",
SourceRepairEvidence::NothingLost => "it held nothing",
SourceRepairEvidence::OnlySchemaValid => "the only one-token repair the schema accepts",
SourceRepairEvidence::SmallestChange => {
"the one-token repair that moves the fewest statements"
}
};
format!("{edit} ({evidence})")
}
}