linguini_analyzer/
message_coverage.rs1use 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}