45 lines
2.0 KiB
Rust
45 lines
2.0 KiB
Rust
#[cfg(feature = "js-esbuild")]
|
|
use {aho_corasick::AhoCorasick, crossbeam::sync::WaitGroup, esbuild_rs::TransformOptions};
|
|
|
|
#[cfg(feature = "js-esbuild")]
|
|
// TODO The use of WG is ugly and we don't want to be multi-threaded; wait for Rust port esbuild-transform-rs.
|
|
// `tag_to_escape` must be case insensitive if provided.
|
|
pub fn minify_using_esbuild(
|
|
out: &mut Vec<u8>,
|
|
code: &[u8],
|
|
transform_options: &TransformOptions,
|
|
tag_to_escape: Option<&'static AhoCorasick>,
|
|
) {
|
|
let wg = WaitGroup::new();
|
|
unsafe {
|
|
let wg = wg.clone();
|
|
esbuild_rs::transform_direct_unmanaged(code, transform_options, move |result| {
|
|
let min_code = result.code.as_str().trim().as_bytes();
|
|
match tag_to_escape {
|
|
None => out.extend_from_slice(min_code),
|
|
// TODO (JS) Handle other forms:
|
|
// 1 < /script/.exec(a).length
|
|
// ` ${` ${a</script/} `} `
|
|
// // </script>
|
|
// /* </script>
|
|
// Considerations:
|
|
// - Need to parse strings (e.g. "", '', ``) so syntax within strings aren't mistakenly interpreted as code.
|
|
// - Need to be able to parse regex literals to determine string delimiters aren't actually characters in the regex.
|
|
// - Determining whether a slash is division or regex requires a full-blown JS parser to handle all cases (this is a well-known JS parsing problem).
|
|
// - `/</script` or `/</ script` are not valid JS so don't need to be handled.
|
|
// TODO (CSS) Are there other places that can have unintentional closing tags?
|
|
Some(tag_to_escape) => {
|
|
tag_to_escape.replace_all_with_bytes(min_code, out, |_, orig, dst| {
|
|
dst.extend(b"<\\/");
|
|
// Keep original case.
|
|
dst.extend(&orig[2..]);
|
|
true
|
|
})
|
|
}
|
|
}
|
|
drop(wg);
|
|
});
|
|
};
|
|
wg.wait();
|
|
}
|