From 8aa7810dfc44152fdeb5599c0087eb0abd9c1463 Mon Sep 17 00:00:00 2001 From: Tom Pridham <pridham.tom@gmail.com> Date: Sun, 29 Jul 2018 03:21:57 -0600 Subject: [PATCH] Disallow dupe attrs (#138) --- .editorconfig | 12 ++++++++++++ maud_macros/src/parse.rs | 34 ++++++++++++++++++++++++++++++++++ 2 files changed, 46 insertions(+) create mode 100644 .editorconfig diff --git a/.editorconfig b/.editorconfig new file mode 100644 index 0000000..c5a9bb9 --- /dev/null +++ b/.editorconfig @@ -0,0 +1,12 @@ +# EditorConfig helps developers define and maintain consistent +# coding styles between different editors and IDEs +# editorconfig.org + +root = true + +[*.rs] +end_of_line = lf +charset = utf-8 +trim_trailing_whitespace = true +indent_style = space +indent_size = 4 diff --git a/maud_macros/src/parse.rs b/maud_macros/src/parse.rs index 8eb37fa..a9c4bd8 100644 --- a/maud_macros/src/parse.rs +++ b/maud_macros/src/parse.rs @@ -6,6 +6,7 @@ use proc_macro::{ TokenStream, TokenTree, }; +use std::collections::HashMap; use std::mem; use literalext::LiteralExt; @@ -558,6 +559,39 @@ impl Parser { _ => break, } } + + let mut attr_map: HashMap<String, Vec<Span>> = HashMap::new(); + if let Some(class) = classes_static.first() { + attr_map.insert("class".to_owned(), vec![ast::span_tokens(class.clone())]); + } + if let Some((tokens, _)) = classes_toggled.first() { + attr_map.insert("class".to_owned(), vec![ast::span_tokens(tokens.clone())]); + } + if let Some(id) = ids.first() { + attr_map.insert("id".to_owned(), vec![ast::span_tokens(id.clone())]); + }; + + for attr in &attrs { + let span = ast::span_tokens(attr.name.clone()); + let name = attr.name.clone().into_iter().map(|token| token.to_string()).collect(); + let entry = attr_map.entry(name).or_default(); + entry.push(span); + } + + for (name, spans) in attr_map { + if spans.len() > 1 { + let mut spans = spans.into_iter(); + if let Some(first_span) = spans.next() { + spans + .fold( + first_span.error(format!("duplicate attribute `{}` used here", name)), + |acc, span| acc.span_error(span, format!("duplicate attribute `{}` used here", name)) + ) + .emit(); + } + } + } + Ok(ast::Attrs { classes_static, classes_toggled, ids, attrs }) }