use indexmap::{IndexMap, IndexSet};
use std::sync::Arc;
use query_flow::{Db, QueryError, QueryResultExt, query};
use crate::report::{ErrorReport, Severity};
use super::assets::{OpenDocuments, OpenDocumentsList, TextFile};
use super::report::GetFileErrorReports;
use super::schema::ResolveSchema;
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub enum DiagnosticSeverity {
Error,
Warning,
Info,
Hint,
}
#[derive(Debug, Clone, PartialEq)]
pub struct DiagnosticMessage {
pub file: TextFile,
pub start: usize,
pub end: usize,
pub message: String,
pub severity: DiagnosticSeverity,
}
#[query(debug = "{Self}({file})")]
pub fn get_file_diagnostics(
db: &impl Db,
file: TextFile,
) -> Result<Vec<DiagnosticMessage>, QueryError> {
let reports = db.query(GetFileErrorReports::new(file))?;
Ok(reports.iter().map(error_report_to_diagnostic).collect())
}
#[query]
pub fn collect_diagnostic_targets(db: &impl Db) -> Result<IndexSet<TextFile>, QueryError> {
let mut targets = IndexSet::new();
let open_docs: Arc<OpenDocumentsList> = db.asset(OpenDocuments)?;
targets.extend(open_docs.0.iter().cloned());
let schema_files = db.query(CollectSchemaFiles::new())?;
targets.extend(schema_files.iter().cloned());
Ok(targets)
}
#[query]
pub fn collect_schema_files(db: &impl Db) -> Result<IndexSet<TextFile>, QueryError> {
use crate::query::error::EureQueryError;
let open_docs: Arc<OpenDocumentsList> = db.asset(OpenDocuments)?;
let mut schemas = IndexSet::new();
for file in open_docs.0.iter() {
let resolved = match db.query(ResolveSchema::new(file.clone())) {
Ok(r) => r,
Err(QueryError::UserError(_)) => continue, Err(e) => return Err(e), };
let Some(resolved) = resolved.as_ref().as_ref() else {
continue; };
if !resolved.file.is_local() {
continue;
}
if db
.asset(resolved.file.clone())
.downcast_err::<EureQueryError>()?
.is_err()
{
continue;
}
schemas.insert(resolved.file.clone());
}
Ok(schemas)
}
#[query]
pub fn get_all_diagnostics(
db: &impl Db,
) -> Result<IndexMap<TextFile, Vec<DiagnosticMessage>>, QueryError> {
let all_files = db.query(CollectDiagnosticTargets::new())?;
let mut result = IndexMap::new();
for file in all_files.iter() {
let diags = db.query(GetFileDiagnostics::new(file.clone()))?;
result.insert(file.clone(), diags.as_ref().clone());
}
Ok(result)
}
fn error_report_to_diagnostic(report: &ErrorReport) -> DiagnosticMessage {
DiagnosticMessage {
file: report.primary_origin.file.clone(),
start: report.primary_origin.span.start as usize,
end: report.primary_origin.span.end as usize,
message: report.title.to_string(),
severity: match report.severity {
Severity::Error => DiagnosticSeverity::Error,
Severity::Warning => DiagnosticSeverity::Warning,
Severity::Note => DiagnosticSeverity::Info,
Severity::Hint => DiagnosticSeverity::Hint,
},
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn test_diagnostic_severity_eq() {
assert_eq!(DiagnosticSeverity::Error, DiagnosticSeverity::Error);
assert_ne!(DiagnosticSeverity::Error, DiagnosticSeverity::Warning);
}
}