use std::{ mem::take, path::{Path, PathBuf}, }; use swc_common::{FileName, Span}; use swc_css_ast::Stylesheet; use swc_css_codegen::{ writer::basic::{BasicCssWriter, BasicCssWriterConfig}, CodeGenerator, CodegenConfig, Emit, }; use swc_css_parser::{parse_file, parser::ParserConfig}; use swc_css_visit::{VisitMut, VisitMutWith}; use testing::{assert_eq, run_test2, NormalizedOutput}; fn run(input: &Path, minify: bool) { let dir = input.parent().unwrap(); let output = if minify { dir.join(format!( "output.min.{}", input.extension().unwrap().to_string_lossy() )) } else { dir.join(format!( "output.{}", input.extension().unwrap().to_string_lossy() )) }; run_test2(false, |cm, handler| { let fm = cm.load_file(input).unwrap(); eprintln!("==== ==== Input ==== ====\n{}\n", fm.src); let mut errors = vec![]; let stylesheet: Stylesheet = parse_file( &fm, ParserConfig { parse_values: true, ..Default::default() }, &mut errors, ) .unwrap(); for err in take(&mut errors) { err.to_diagnostics(&handler).emit(); } let mut css_str = String::new(); { let wr = BasicCssWriter::new( &mut css_str, BasicCssWriterConfig { indent: if minify { "" } else { "\t" }, }, ); let mut gen = CodeGenerator::new(wr, CodegenConfig { minify }); gen.emit(&stylesheet).unwrap(); } NormalizedOutput::from(css_str) .compare_to_file(output) .unwrap(); Ok(()) }) .unwrap(); } #[testing::fixture("tests/fixture/**/input.css")] fn css(input: PathBuf) { run(&input, false); run(&input, true); } #[testing::fixture("../swc_css_parser/tests/fixture/**/input.css")] fn parse_again(input: PathBuf) { eprintln!("{}", input.display()); testing::run_test2(false, |cm, handler| { let fm = cm.load_file(&input).unwrap(); eprintln!("==== ==== Input ==== ====\n{}\n", fm.src); let mut errors = vec![]; let mut stylesheet: Stylesheet = parse_file( &fm, ParserConfig { parse_values: true, ..Default::default() }, &mut errors, ) .unwrap(); for err in take(&mut errors) { err.to_diagnostics(&handler).emit(); } let mut css_str = String::new(); { let wr = BasicCssWriter::new(&mut css_str, BasicCssWriterConfig { indent: "\t" }); let mut gen = CodeGenerator::new(wr, CodegenConfig { minify: false }); gen.emit(&stylesheet).unwrap(); } eprintln!("==== ==== Codegen ==== ====\n{}\n", css_str); let new_fm = cm.new_source_file(FileName::Anon, css_str); let mut parsed: Stylesheet = parse_file( &new_fm, ParserConfig { parse_values: true, ..Default::default() }, &mut errors, ) .map_err(|err| { err.to_diagnostics(&handler).emit(); })?; for err in errors { err.to_diagnostics(&handler).emit(); } stylesheet.visit_mut_with(&mut DropSpan); parsed.visit_mut_with(&mut DropSpan); assert_eq!(stylesheet, parsed); Ok(()) }) .unwrap(); } struct DropSpan; impl VisitMut for DropSpan { fn visit_mut_span(&mut self, n: &mut Span) { *n = Default::default() } }