mirror of
https://github.com/MercuryWorkshop/scramjet.git
synced 2025-05-16 15:40:02 -04:00
jschange -> rewrite
This commit is contained in:
parent
83ccb7602e
commit
6d03da6d85
4 changed files with 85 additions and 61 deletions
|
@ -30,7 +30,7 @@ fn dorewrite(data: &str) -> Result<RewriteResult> {
|
|||
|
||||
capture_errors: true,
|
||||
do_sourcemaps: true,
|
||||
scramitize: false,
|
||||
scramitize: true,
|
||||
strict_rewrites: true,
|
||||
},
|
||||
)
|
||||
|
|
|
@ -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,
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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 {
|
||||
|
|
|
@ -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(),
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue