pub mod error; use error::{Result, RewriterError}; use htmlr::{HtmlRewriter, HtmlRewriterOutput, create_html, create_html_output, get_html_params}; use js_sys::{Function, Object, Reflect}; use jsr::{JsRewriter, JsRewriterOutput, create_js, create_js_output, get_js_flags}; use oxc::allocator::Allocator; use wasm_bindgen::prelude::*; use web_sys::Url; mod htmlr; mod jsr; #[wasm_bindgen] extern "C" { #[wasm_bindgen(js_namespace = console, js_name = error)] fn console_error(s: &str); #[wasm_bindgen(js_namespace = console, js_name = error)] fn console_error2(s: &JsValue); } fn get_obj(obj: &JsValue, k: &'static str) -> Result { Ok(Reflect::get(obj, &k.into())?) } fn get_str(obj: &JsValue, k: &'static str) -> Result { Reflect::get(obj, &k.into())? .as_string() .ok_or_else(|| RewriterError::not_str(k)) } fn set_obj(obj: &Object, k: &str, v: &JsValue) -> Result<()> { if Reflect::set(&obj.into(), &k.into(), v)? { Ok(()) } else { Err(RewriterError::ReflectSetFail(k.to_string())) } } fn get_flag(scramjet: &Object, url: &str, flag: &str) -> Result { let fenabled = get_obj(scramjet, "flagEnabled")? .dyn_into::() .map_err(|_| RewriterError::not_fn("scramjet.flagEnabled"))?; let ret = fenabled.call2(&JsValue::NULL, &flag.into(), &Url::new(url)?.into())?; ret.as_bool() .ok_or_else(|| RewriterError::not_bool("scramjet.flagEnabled return value")) } #[wasm_bindgen] pub struct Rewriter { alloc: Allocator, scramjet: Object, js: JsRewriter, html: HtmlRewriter, html_funcs: (Function, Function, Function, Function), } #[wasm_bindgen] impl Rewriter { #[wasm_bindgen(constructor)] pub fn new(scramjet: Object) -> Result { Ok(Self { alloc: Allocator::default(), js: create_js(&scramjet)?, html: create_html(&scramjet)?, html_funcs: get_html_params(&scramjet)?, scramjet, }) } #[wasm_bindgen] pub fn rewrite_js( &mut self, js: String, base: String, url: String, module: bool, ) -> Result { let flags = get_js_flags(&self.scramjet, base, module)?; let out = match self.js.rewrite(&self.alloc, &js, flags) { Ok(x) => x, Err(x) => { self.alloc.reset(); Err(x)? } }; let ret = create_js_output(out, url, js); self.alloc.reset(); ret } #[wasm_bindgen] pub fn rewrite_js_bytes( &mut self, js: Vec, base: String, url: String, module: bool, ) -> Result { // SAFETY: we know the js is a valid utf-8 string let js = unsafe { std::string::String::from_utf8_unchecked(js) }; self.rewrite_js(js, base, url, module) } #[allow(clippy::needless_pass_by_value)] #[wasm_bindgen] pub fn rewrite_html( &mut self, html: String, meta: Object, cookie: Object, from_top: bool, ) -> Result { let out = match self.html.rewrite( &self.alloc, &html, &( meta, cookie, self.html_funcs.0.clone(), self.html_funcs.1.clone(), self.html_funcs.2.clone(), self.html_funcs.3.clone(), ), from_top, ) { Ok(x) => x, Err(x) => { self.alloc.reset(); Err(x)? } }; let ret = create_html_output(&out); self.alloc.reset(); ret } }