csskit_derives 0.0.27

Derive macros for CSS parsing, visiting, and AST operations.
Documentation
use crate::visitor;
use insta::assert_snapshot;
use quote::quote;

fn expand(tokens: proc_macro2::TokenStream) -> String {
	let item = syn::parse2::<syn::ItemImpl>(tokens).unwrap();
	let out = visitor::expand(item).expect("visitor expansion failed");
	let file = syn::parse2::<syn::File>(out).unwrap();
	prettyplease::unparse(&file)
}

#[test]
fn observer_method_gets_return_type_and_descend_tail() {
	let out = expand(quote! {
		impl Visit for V {
			fn visit_color(&mut self, c: &Color) {
				self.seen.push(c);
			}
		}
	});
	assert_snapshot!("visitor_observer", out);
}

#[test]
fn explicit_return_type_is_untouched() {
	let out = expand(quote! {
		impl Visit for V {
			fn consider_node(&self, q: VisitNode) -> VisitFlow {
				VisitFlow::SKIP_CHILDREN
			}
		}
	});
	assert_snapshot!("visitor_explicit_return", out);
}

#[test]
fn bare_return_in_observer_is_rewritten() {
	let out = expand(quote! {
		impl Visit for V {
			fn visit_color(&mut self, c: &Color) {
				if c.is_empty() {
					return;
				}
				self.seen.push(c);
			}
		}
	});
	assert_snapshot!("visitor_bare_return", out);
}

#[test]
fn return_in_nested_closure_is_not_rewritten() {
	let out = expand(quote! {
		impl Visit for V {
			fn visit_color(&mut self, c: &Color) {
				let f = || {
					return;
				};
				f();
			}
		}
	});
	assert_snapshot!("visitor_nested_closure", out);
}

#[test]
fn explicit_unit_return_opts_out() {
	let out = expand(quote! {
		impl VisitMut for V {
			fn visit_color(&mut self, c: &Color) -> () {
				self.seen.push(c);
			}
		}
	});
	assert_snapshot!("visitor_unit_optout", out);
}

#[test]
fn rejects_inherent_impl() {
	let item = syn::parse2::<syn::ItemImpl>(quote! {
		impl V {
			fn visit_color(&mut self, c: &Color) {
				self.seen.push(c);
			}
		}
	})
	.unwrap();

	assert!(visitor::expand(item).is_err());
}