Skip to main content

linguini_analyzer/
message_coverage.rs

1use crate::Diagnostic;
2use linguini_syntax::Span;
3use std::collections::BTreeMap;
4
5#[derive(Debug, Clone, PartialEq, Eq)]
6pub struct PublicMessage {
7    pub name: String,
8    pub span: Span,
9}
10
11impl PublicMessage {
12    pub fn new(name: impl Into<String>, span: Span) -> Self {
13        Self {
14            name: name.into(),
15            span,
16        }
17    }
18}
19
20pub fn analyze_message_coverage(
21    schema_messages: &[PublicMessage],
22    locale_messages: &[PublicMessage],
23) -> Vec<Diagnostic> {
24    let schema = message_map(schema_messages);
25    let locale = message_map(locale_messages);
26    let mut diagnostics = Vec::new();
27
28    for schema_message in schema_messages {
29        if !locale.contains_key(schema_message.name.as_str()) {
30            diagnostics.push(
31                Diagnostic::error(
32                    format!(
33                        "missing locale implementation for public message `{}`",
34                        schema_message.name
35                    ),
36                    schema_message.span,
37                )
38                .with_note("add this message to the locale file"),
39            );
40        }
41    }
42
43    for locale_message in locale_messages {
44        if schema.contains_key(locale_message.name.as_str()) {
45            continue;
46        }
47
48        diagnostics.push(
49            Diagnostic::error(
50                format!(
51                    "unknown public message implementation `{}`",
52                    locale_message.name
53                ),
54                locale_message.span,
55            )
56            .with_note("remove this message or add it to the schema"),
57        );
58    }
59
60    diagnostics
61}
62
63fn message_map(messages: &[PublicMessage]) -> BTreeMap<&str, &PublicMessage> {
64    messages
65        .iter()
66        .map(|message| (message.name.as_str(), message))
67        .collect()
68}