qlue-ls 3.0.1

A language server for SPARQL
Documentation
use crate::server::{
    Server,
    lsp::{
        base_types::LSPAny,
        diagnostic::{Diagnostic, DiagnosticCode, DiagnosticSeverity},
        textdocument::{Range, TextDocumentItem},
    },
};
use ll_sparql_parser::ast::{AstNode, PrefixedName, QueryUnit};
use std::{collections::HashSet, sync::LazyLock};

pub static CODE: LazyLock<DiagnosticCode> =
    LazyLock::new(|| DiagnosticCode::String("unused-prefix-declaration".to_string()));

pub(super) fn diagnostics(
    document: &TextDocumentItem,
    query_unit: &QueryUnit,
    _server: &Server,
) -> Option<Vec<Diagnostic>> {
    let prefix_declarations = query_unit.prologue()?.prefix_declarations();
    let used_prefixes: HashSet<String> =
        query_unit.strip_prologue().map_or(HashSet::new(), |query| {
            HashSet::from_iter(
                query
                    .descendants()
                    .flat_map(&PrefixedName::cast)
                    .map(|node| node.prefix()),
            )
        });
    Some(
        prefix_declarations
            .into_iter()
            .filter_map(|prefix_declaration| {
                (!used_prefixes.contains(&prefix_declaration.prefix().unwrap_or("".to_string())))
                    .then(|| Diagnostic {
                        range: Range::from_byte_offset_range(
                            prefix_declaration.syntax().text_range(),
                            &document.text,
                        )
                        .expect("prefix declaration text range should be in text"),
                        severity: DiagnosticSeverity::Warning,
                        source: Some("qlue-ls".to_string()),
                        code: Some((*CODE).clone()),
                        message: format!(
                            "'{}' is declared here, but was never used\n",
                            prefix_declaration.prefix().unwrap_or("prefix".to_string())
                        ),
                        data: prefix_declaration.prefix().map(LSPAny::String),
                    })
            })
            .collect(),
    )
}