use crate::cfg::Cfg;
use crate::err::ProcessingResult;
use crate::proc::MatchAction::*;
use crate::proc::MatchMode::*;
use crate::proc::Processor;
use aho_corasick::AhoCorasick;
use aho_corasick::AhoCorasickBuilder;
use once_cell::sync::Lazy;
use oxc_allocator::Allocator;
use oxc_codegen::Codegen;
use oxc_codegen::CodegenOptions;
use oxc_minifier::CompressOptions;
use oxc_minifier::MangleOptions;
use oxc_minifier::Minifier;
use oxc_minifier::MinifierOptions;
use oxc_parser::Parser;
use oxc_span::SourceType;
static SCRIPT_END: Lazy<AhoCorasick> = Lazy::new(|| {
AhoCorasickBuilder::new()
.ascii_case_insensitive(true)
.build(["</script"])
.unwrap()
});
#[derive(Debug, Clone, Copy)]
pub enum TopLevelMode {
Global,
Module,
}
#[inline(always)]
pub fn process_script(
proc: &mut Processor,
cfg: &Cfg,
mode: Option<TopLevelMode>,
) -> ProcessingResult<()> {
proc.require_not_at_end()?;
let src = proc.m(WhileNotSeq(&SCRIPT_END), Discard);
if cfg.minify_js && mode.is_some() {
let code = &proc[src];
if let Ok(source_text) = std::str::from_utf8(code) {
let allocator = Allocator::default();
let source_type = match mode.unwrap() {
TopLevelMode::Module => SourceType::mjs(),
TopLevelMode::Global => SourceType::default(),
};
let parser_ret = Parser::new(&allocator, source_text, source_type).parse();
if parser_ret.errors.is_empty() {
let mut program = parser_ret.program;
let minifier_options = MinifierOptions {
mangle: Some(MangleOptions::default()),
compress: Some(CompressOptions::safest()),
};
let _minifier_ret = Minifier::new(minifier_options).minify(&allocator, &mut program);
let codegen_options = CodegenOptions {
minify: true,
..CodegenOptions::default()
};
let minified = Codegen::new()
.with_options(codegen_options)
.build(&program)
.code;
if minified.len() < src.len() {
proc.write_slice(minified.as_bytes());
return Ok(());
}
}
}
proc.write_range(src);
} else {
proc.write_range(src);
};
Ok(())
}