jschange -> rewrite

This commit is contained in:
Toshit Chawda 2024-12-12 11:29:55 -08:00
parent 83ccb7602e
commit 6d03da6d85
No known key found for this signature in database
GPG key ID: 91480ED99E2B3D9D
4 changed files with 85 additions and 61 deletions

View file

@ -30,7 +30,7 @@ fn dorewrite(data: &str) -> Result<RewriteResult> {
capture_errors: true,
do_sourcemaps: true,
scramitize: false,
scramitize: true,
strict_rewrites: true,
},
)

View file

@ -4,10 +4,10 @@ use oxc::{
};
use smallvec::{smallvec, SmallVec};
use crate::cfg::Config;
use crate::{cfg::Config, RewriterError};
#[derive(Debug, PartialEq, Eq)]
pub enum JsChange {
#[derive(Debug, PartialEq, Eq, Clone)]
pub enum Rewrite {
/// `(cfg.wrapfn(ident))` | `cfg.wrapfn(ident)`
WrapFn {
span: Span,
@ -72,21 +72,7 @@ pub enum JsChange {
},
}
type Changes<'a> = SmallVec<[&'a str; 8]>;
enum JsChangeInner<'a> {
Wrap {
/// Changes to add before span
before: Changes<'a>,
/// Span to add in between
span: &'a Span,
/// Changes to add after span
after: Changes<'a>,
},
Replace(Changes<'a>),
}
impl JsChange {
impl Rewrite {
pub fn get_span(&self) -> &Span {
match self {
Self::WrapFn { span, .. } => span,
@ -120,25 +106,27 @@ impl JsChange {
if *wrapped {
JsChangeInner::Wrap {
before: smallvec!["(", cfg.wrapfn.as_str(), "("],
span,
inner: span,
after: smallvec!["))"],
}
} else {
JsChangeInner::Wrap {
before: smallvec![cfg.wrapfn.as_str(), "("],
span,
inner: span,
after: smallvec![")"],
}
}
}
Self::SetRealmFn { span } => JsChangeInner::Wrap {
before: smallvec![cfg.setrealmfn.as_str(), "({})."],
span,
inner: span,
after: smallvec![],
},
Self::WrapThisFn { .. } => {
JsChangeInner::Replace(smallvec![cfg.wrapthisfn.as_str(), "(this)"])
}
Self::WrapThisFn { span } => JsChangeInner::Wrap {
before: smallvec![cfg.wrapthisfn.as_str(), "("],
inner: span,
after: smallvec![")"],
},
Self::ImportFn { .. } => JsChangeInner::Replace(smallvec![
"(",
cfg.importfn.as_str(),
@ -153,18 +141,19 @@ impl JsChange {
"\")"
]),
// maps to insert
Self::ScramErr { name, .. } => {
JsChangeInner::Replace(smallvec!["$scramerr(", name.as_str(), ");"])
}
Self::Scramitize { span } => JsChangeInner::Wrap {
before: smallvec!["$scramitize("],
span,
inner: span,
after: smallvec![")"],
},
Self::Eval { inner, .. } => JsChangeInner::Wrap {
before: smallvec!["eval(", cfg.rewritefn.as_str(), "("],
span: inner,
inner,
after: smallvec![")"],
},
Self::Assignment {
@ -180,9 +169,10 @@ impl JsChange {
op.as_str(),
"t))("
],
span: rhsspan,
inner: rhsspan,
after: smallvec![")"],
},
// maps to insert
Self::ShorthandObj { name, .. } => JsChangeInner::Replace(smallvec![
name.as_str(),
":",
@ -191,6 +181,7 @@ impl JsChange {
name.as_str(),
")"
]),
// maps to insert
Self::SourceTag { tagname, .. } => JsChangeInner::Replace(smallvec![
"/*scramtag ",
tagname.as_str(),
@ -204,25 +195,41 @@ impl JsChange {
}
}
impl PartialOrd for JsChange {
impl PartialOrd for Rewrite {
fn partial_cmp(&self, other: &Self) -> Option<std::cmp::Ordering> {
Some(self.cmp(other))
}
}
impl Ord for JsChange {
impl Ord for Rewrite {
fn cmp(&self, other: &Self) -> std::cmp::Ordering {
self.get_span().start.cmp(&other.get_span().start)
}
}
type Changes<'a> = SmallVec<[&'a str; 8]>;
enum JsChangeInner<'a> {
Wrap {
/// Changes to add before span
before: Changes<'a>,
/// Span to add in between
inner: &'a Span,
/// Changes to add after span
after: Changes<'a>,
},
Replace {
str: Changes<'a>,
},
}
pub(crate) struct JsChangeResult {
pub js: Vec<u8>,
pub sourcemap: Vec<u8>,
}
pub(crate) struct JsChanges {
pub inner: Vec<JsChange>,
pub inner: Vec<Rewrite>,
}
impl JsChanges {
@ -230,11 +237,11 @@ impl JsChanges {
Self { inner: Vec::new() }
}
pub fn add(&mut self, change: JsChange) {
pub fn add(&mut self, change: Rewrite) {
self.inner.push(change);
}
pub fn perform<E>(&mut self, js: &str, cfg: &Config<E>) -> JsChangeResult
pub fn perform<E>(&mut self, js: &str, cfg: &Config<E>) -> Result<JsChangeResult, RewriterError>
where
E: Fn(String) -> String,
E: Clone,
@ -252,13 +259,17 @@ impl JsChanges {
let start = span.start as usize;
let end = span.end as usize;
buffer.extend_from_slice(js[offset..start].as_bytes());
buffer.extend_from_slice(
js.get(offset..start)
.ok_or_else(|| RewriterError::Oob(offset..start))?
.as_bytes(),
);
let change = change.to_inner(cfg);
match change {
let inner = change.to_inner(cfg);
match inner {
JsChangeInner::Wrap {
before,
span: wrapspan,
inner: wrapspan,
after,
} => {
// wrap op
@ -268,7 +279,11 @@ impl JsChanges {
let wrapstart = wrapspan.start as usize;
let wrapend = wrapspan.end as usize;
buffer.extend_from_slice(js[wrapstart..wrapend].as_bytes());
buffer.extend_from_slice(
js.get(wrapstart..wrapend)
.ok_or_else(|| RewriterError::Oob(wrapstart..wrapend))?
.as_bytes(),
);
for str in after {
buffer.extend_from_slice(str.as_bytes());
@ -284,11 +299,16 @@ impl JsChanges {
offset = end;
}
buffer.extend_from_slice(js[offset..].as_bytes());
let js_len = js.len();
buffer.extend_from_slice(
js.get(offset..js_len)
.ok_or_else(|| RewriterError::Oob(offset..js_len))?
.as_bytes(),
);
JsChangeResult {
Ok(JsChangeResult {
js: buffer,
sourcemap: map,
}
})
}
}

View file

@ -1,5 +1,7 @@
use std::ops::Range;
use cfg::Config;
use changes::{JsChange, JsChangeResult, JsChanges};
use changes::{Rewrite, JsChangeResult, JsChanges};
use oxc::{
allocator::Allocator,
ast::Visit,
@ -18,6 +20,8 @@ mod visitor;
pub enum RewriterError {
#[error("oxc panicked in parser")]
OxcPanicked,
#[error("out of bounds while applying range: {0:?})")]
Oob(Range<usize>),
}
#[derive(Debug)]
@ -25,7 +29,7 @@ pub struct RewriteResult {
pub js: Vec<u8>,
pub sourcemap: Vec<u8>,
pub errors: Vec<OxcDiagnostic>,
pub changes: Vec<JsChange>,
pub changes: Vec<Rewrite>,
}
pub fn rewrite<E>(js: &str, config: Config<E>) -> Result<RewriteResult, RewriterError>
@ -57,7 +61,7 @@ where
config,
} = visitor;
let JsChangeResult { js, sourcemap } = jschanges.perform(js, &config);
let JsChangeResult { js, sourcemap } = jschanges.perform(js, &config)?;
let JsChanges { inner: changes } = jschanges;
Ok(RewriteResult {

View file

@ -15,7 +15,7 @@ use oxc::{
use crate::{
cfg::Config,
changes::{JsChange, JsChanges},
changes::{Rewrite, JsChanges},
};
// js MUST not be able to get a reference to any of these because sbx
@ -58,7 +58,7 @@ where
fn rewrite_ident(&mut self, name: &Atom, span: Span) {
if UNSAFE_GLOBALS.contains(&name.as_str()) {
self.jschanges.add(JsChange::WrapFn {
self.jschanges.add(Rewrite::WrapFn {
span,
wrapped: true,
});
@ -83,7 +83,7 @@ where
}
fn scramitize(&mut self, span: Span) {
self.jschanges.add(JsChange::Scramitize { span });
self.jschanges.add(Rewrite::Scramitize { span });
}
}
@ -104,7 +104,7 @@ where
// } else {
//
if UNSAFE_GLOBALS.contains(&it.name.as_str()) {
self.jschanges.add(JsChange::WrapFn {
self.jschanges.add(Rewrite::WrapFn {
span: it.span,
wrapped: false,
});
@ -122,7 +122,7 @@ where
match it {
MemberExpression::StaticMemberExpression(s) => {
if s.property.name == "postMessage" {
self.jschanges.add(JsChange::SetRealmFn {
self.jschanges.add(Rewrite::SetRealmFn {
span: s.property.span,
});
@ -159,12 +159,12 @@ where
walk::walk_member_expression(self, it);
}
fn visit_this_expression(&mut self, it: &ThisExpression) {
self.jschanges.add(JsChange::WrapThisFn { span: it.span });
self.jschanges.add(Rewrite::WrapThisFn { span: it.span });
}
fn visit_debugger_statement(&mut self, it: &DebuggerStatement) {
// delete debugger statements entirely. some sites will spam debugger as an anti-debugging measure, and we don't want that!
self.jschanges.add(JsChange::Delete { span: it.span });
self.jschanges.add(Rewrite::Delete { span: it.span });
}
// we can't overwrite window.eval in the normal way because that would make everything an
@ -173,7 +173,7 @@ where
if let Expression::Identifier(s) = &it.callee {
// if it's optional that actually makes it an indirect eval which is handled separately
if s.name == "eval" && !it.optional {
self.jschanges.add(JsChange::Eval {
self.jschanges.add(Rewrite::Eval {
span: Span::new(it.span.start, it.span.end),
inner: Span::new(s.span.end + 1, it.span.end),
});
@ -193,14 +193,14 @@ where
fn visit_import_declaration(&mut self, it: &ImportDeclaration<'a>) {
let name = it.source.value.to_string();
let text = self.rewrite_url(name);
self.jschanges.add(JsChange::Replace {
self.jschanges.add(Rewrite::Replace {
span: it.source.span,
text,
});
walk::walk_import_declaration(self, it);
}
fn visit_import_expression(&mut self, it: &ImportExpression<'a>) {
self.jschanges.add(JsChange::ImportFn {
self.jschanges.add(Rewrite::ImportFn {
span: Span::new(it.span.start, it.span.start + 6),
});
walk::walk_import_expression(self, it);
@ -209,7 +209,7 @@ where
fn visit_export_all_declaration(&mut self, it: &ExportAllDeclaration<'a>) {
let name = it.source.value.to_string();
let text = self.rewrite_url(name);
self.jschanges.add(JsChange::Replace {
self.jschanges.add(Rewrite::Replace {
span: it.source.span,
text,
});
@ -218,7 +218,7 @@ where
if let Some(source) = &it.source {
let name = source.value.to_string();
let text = self.rewrite_url(name);
self.jschanges.add(JsChange::Replace {
self.jschanges.add(Rewrite::Replace {
span: source.span,
text,
});
@ -234,7 +234,7 @@ where
if let Some(h) = &it.handler {
if let Some(name) = &h.param {
if let Some(name) = name.pattern.get_identifier() {
self.jschanges.add(JsChange::ScramErr {
self.jschanges.add(Rewrite::ScramErr {
span: Span::new(h.body.span.start + 1, h.body.span.start + 1),
name: name.to_compact_str(),
});
@ -251,7 +251,7 @@ where
match &p.value {
Expression::Identifier(s) => {
if UNSAFE_GLOBALS.contains(&s.name.to_string().as_str()) && p.shorthand {
self.jschanges.add(JsChange::ShorthandObj {
self.jschanges.add(Rewrite::ShorthandObj {
span: s.span,
name: s.name.to_compact_str(),
});
@ -269,7 +269,7 @@ where
fn visit_function_body(&mut self, it: &FunctionBody<'a>) {
// tag function for use in sourcemaps
if self.config.do_sourcemaps {
self.jschanges.add(JsChange::SourceTag {
self.jschanges.add(Rewrite::SourceTag {
span: Span::new(it.span.start, it.span.start),
tagname: it.span.start.to_string(),
});
@ -313,7 +313,7 @@ where
fn visit_meta_property(&mut self, it: &MetaProperty<'a>) {
if it.meta.name == "import" {
self.jschanges.add(JsChange::MetaFn { span: it.span });
self.jschanges.add(Rewrite::MetaFn { span: it.span });
}
}
@ -321,7 +321,7 @@ where
match &it.left {
AssignmentTarget::AssignmentTargetIdentifier(s) => {
if ["location"].contains(&s.name.to_string().as_str()) {
self.jschanges.add(JsChange::Assignment {
self.jschanges.add(Rewrite::Assignment {
name: s.name.to_compact_str(),
entirespan: it.span,
rhsspan: it.right.span(),