1use std::path::Path;
4
5use fluent_syntax::ast::{Entry, PatternElement};
6
7use crate::diagnostics::{CheckId, DiagCtx, RunningCheck};
8use crate::walk::{filter_dirs, walk};
9
10fn filter_fluent(path: &Path) -> bool {
11 if let Some(ext) = path.extension() { ext.to_str() != Some("ftl") } else { true }
12}
13
14const ALLOWLIST: &[&str] = &[
18 "const_eval_long_running",
19 "const_eval_validation_failure_note",
20 "driver_impl_ice",
21 "incremental_corrupt_file",
22];
23
24fn check_period(filename: &str, contents: &str, check: &mut RunningCheck) {
25 if filename.contains("codegen") {
26 return;
28 }
29
30 let (Ok(parse) | Err((parse, _))) = fluent_syntax::parser::parse(contents);
31 for entry in &parse.body {
32 if let Entry::Message(m) = entry {
33 if ALLOWLIST.contains(&m.id.name) {
34 continue;
35 }
36
37 if let Some(pat) = &m.value
38 && let Some(PatternElement::TextElement { value }) = pat.elements.last()
39 {
40 if value.ends_with(".") && !value.ends_with("...") {
42 let ll = find_line(contents, value);
43 let name = m.id.name;
44 check.error(format!("{filename}:{ll}: message `{name}` ends in a period"));
45 }
46 }
47
48 for attr in &m.attributes {
49 if attr.id.name == "teach_note" {
51 continue;
52 }
53
54 if let Some(PatternElement::TextElement { value }) = attr.value.elements.last()
55 && value.ends_with(".")
56 && !value.ends_with("...")
57 {
58 let ll = find_line(contents, value);
59 let name = attr.id.name;
60 check.error(format!("{filename}:{ll}: attr `{name}` ends in a period"));
61 }
62 }
63 }
64 }
65}
66
67fn find_line(haystack: &str, needle: &str) -> usize {
69 for (ll, line) in haystack.lines().enumerate() {
70 if line.as_ptr() > needle.as_ptr() {
71 return ll;
72 }
73 }
74
75 1
76}
77
78pub fn check(path: &Path, diag_ctx: DiagCtx) {
79 let mut check = diag_ctx.start_check(CheckId::new("fluent_period").path(path));
80
81 walk(
82 path,
83 |path, is_dir| filter_dirs(path) || (!is_dir && filter_fluent(path)),
84 &mut |ent, contents| {
85 check_period(ent.path().to_str().unwrap(), contents, &mut check);
86 },
87 );
88}