vize_bundler_before_observer/
vize_bundler_before_observer.rs1mod vize_bundler_before;
3
4use lightningcss::{
5 bundler::Bundler,
6 css_modules::{Config, Pattern},
7 error::Error,
8 printer::PrinterOptions,
9 stylesheet::{MinifyOptions, ParserOptions},
10};
11use parcel_sourcemap::SourceMap;
12use serde_json::{json, Value};
13use std::{fmt, fs, path::Path};
14use vize_bundler_before::Provider;
15
16fn error<T: fmt::Debug + fmt::Display>(stage: &str, value: Error<T>) -> Value {
17 json!({"stage": stage, "display": value.to_string(), "kind": format!("{:?}", value.kind), "loc": value.loc})
18}
19
20fn observe(case: &Value, provider: &Provider) -> Value {
21 let mut map = SourceMap::new("/");
22 let options = ParserOptions {
23 css_modules: case["cssModules"].as_bool().unwrap_or(false).then(|| Config {
24 dashed_idents: true,
25 pattern: Pattern::parse("[hash]_[local]").unwrap(),
26 ..Default::default()
27 }),
28 ..Default::default()
29 };
30 let mut bundler = Bundler::new(provider, Some(&mut map), options);
31 let result = match bundler.bundle(Path::new(case["entry"].as_str().unwrap())) {
32 Ok(mut stylesheet) => {
33 let bundle = json!({
35 "ast": stylesheet,
36 "sources": stylesheet.sources,
37 "sourceMapUrls": stylesheet.source_map_urls,
38 "licenseComments": stylesheet.license_comments,
39 "privateContentHashesObserved": false,
40 });
41 let minify_error = if case["minify"].as_bool().unwrap_or(false) {
42 stylesheet.minify(MinifyOptions::default()).err()
43 } else {
44 None
45 };
46 if let Some(value) = minify_error {
47 json!({"bundle": bundle, "error": error("minify", value)})
48 } else {
49 match stylesheet.to_css(PrinterOptions {
50 source_map: Some(&mut map),
51 ..Default::default()
52 }) {
53 Ok(result) => json!({
54 "bundle": bundle, "code": result.code, "exports": result.exports,
55 "references": result.references, "dependencies": result.dependencies,
56 }),
57 Err(value) => json!({"bundle": bundle, "error": error("print", value)}),
58 }
59 }
60 }
61 Err(value) => json!({"error": error("bundle", value)}),
62 };
63 let mappings: Vec<Value> = map
64 .get_mappings()
65 .iter()
66 .map(|mapping| {
67 json!({
68 "generatedLine": mapping.generated_line,
69 "generatedColumn": mapping.generated_column,
70 "original": mapping.original.map(|value| json!({
71 "line": value.original_line, "column": value.original_column,
72 "source": value.source, "name": value.name,
73 })),
74 })
75 })
76 .collect();
77 json!({
78 "result": result,
79 "map": {"json": map.to_json(None).unwrap(), "sources": map.get_sources(),
80 "sourcesContent": map.get_sources_content(), "names": map.get_names(), "mappings": mappings},
81 })
82}
83
84fn main() {
85 let args: Vec<String> = std::env::args().collect();
86 assert_eq!(args.len(), 5, "manifest case pool output-directory");
87 let manifest: Value = serde_json::from_slice(&fs::read(&args[1]).unwrap()).unwrap();
88 let case = manifest["cases"]
89 .as_array()
90 .unwrap()
91 .iter()
92 .find(|case| case["id"].as_str() == Some(args[2].as_str()))
93 .unwrap();
94 let threads: usize = args[3].parse().unwrap();
95 assert!([1, 8, 32].contains(&threads));
96 let directory = Path::new(&args[4]);
97 fs::create_dir_all(directory).unwrap();
98 fs::write(
99 directory.join("startup.json"),
100 serde_json::to_vec_pretty(&json!({
101 "case": case, "threads": threads, "pid": std::process::id(),
102 "sourceRevision": std::env::var("CSS_ENGINE_SOURCE_REVISION").unwrap(),
103 "expectationsRecaptured": false, "publicationQualification": false,
104 }))
105 .unwrap(),
106 )
107 .unwrap();
108 let provider = Provider::new(case, threads, directory.join("events.jsonl"));
109 let pool = rayon::ThreadPoolBuilder::new().num_threads(threads).build().unwrap();
110 let observed = pool.install(|| observe(case, &provider));
111 fs::write(
112 directory.join("observation.json"),
113 serde_json::to_vec_pretty(&observed).unwrap(),
114 )
115 .unwrap();
116 println!("{}", serde_json::to_string(&observed).unwrap());
117}