mirror of
https://github.com/MercuryWorkshop/scramjet.git
synced 2025-05-14 06:50:01 -04:00
benches and generic infection
This commit is contained in:
parent
2f7d2fa043
commit
633d0f17fc
11 changed files with 1113 additions and 204 deletions
320
rewriter/Cargo.lock
generated
320
rewriter/Cargo.lock
generated
|
@ -1,6 +1,6 @@
|
|||
# This file is automatically @generated by Cargo.
|
||||
# It is not intended for manual editing.
|
||||
version = 3
|
||||
version = 4
|
||||
|
||||
[[package]]
|
||||
name = "ahash"
|
||||
|
@ -14,12 +14,33 @@ dependencies = [
|
|||
"zerocopy",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "aho-corasick"
|
||||
version = "1.1.3"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "8e60d3430d3a69478ad0993f19238d2df97c507009a52b3c10addcd7f6bcb916"
|
||||
dependencies = [
|
||||
"memchr",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "allocator-api2"
|
||||
version = "0.2.21"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "683d7910e743518b0e34f1186f92494becacb047c7b6bf616c96772180fef923"
|
||||
|
||||
[[package]]
|
||||
name = "anes"
|
||||
version = "0.1.6"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "4b46cbb362ab8752921c97e041f5e366ee6297bd428a31275b9fcf1e380f7299"
|
||||
|
||||
[[package]]
|
||||
name = "anstyle"
|
||||
version = "1.0.10"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "55cc3b69f167a1ef2e161439aa98aed94e6028e5f9a59be9a6ffb47aef1651f9"
|
||||
|
||||
[[package]]
|
||||
name = "anyhow"
|
||||
version = "1.0.94"
|
||||
|
@ -88,7 +109,7 @@ dependencies = [
|
|||
"icu_normalizer",
|
||||
"indexmap",
|
||||
"intrusive-collections",
|
||||
"itertools",
|
||||
"itertools 0.13.0",
|
||||
"num-bigint",
|
||||
"num-integer",
|
||||
"num-traits",
|
||||
|
@ -224,6 +245,12 @@ version = "1.5.0"
|
|||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "1fd0f2584146f6f2ef48085050886acf353beff7305ebd1ae69500e27c67f64b"
|
||||
|
||||
[[package]]
|
||||
name = "cast"
|
||||
version = "0.3.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "37b2a672a2cb129a2e41c10b1224bb368f9f37a2b16b612598138befd7b37eb5"
|
||||
|
||||
[[package]]
|
||||
name = "castaway"
|
||||
version = "0.2.3"
|
||||
|
@ -239,6 +266,58 @@ version = "1.0.0"
|
|||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd"
|
||||
|
||||
[[package]]
|
||||
name = "ciborium"
|
||||
version = "0.2.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "42e69ffd6f0917f5c029256a24d0161db17cea3997d185db0d35926308770f0e"
|
||||
dependencies = [
|
||||
"ciborium-io",
|
||||
"ciborium-ll",
|
||||
"serde",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "ciborium-io"
|
||||
version = "0.2.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "05afea1e0a06c9be33d539b876f1ce3692f4afea2cb41f740e7743225ed1c757"
|
||||
|
||||
[[package]]
|
||||
name = "ciborium-ll"
|
||||
version = "0.2.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "57663b653d948a338bfb3eeba9bb2fd5fcfaecb9e199e87e1eda4d9e8b240fd9"
|
||||
dependencies = [
|
||||
"ciborium-io",
|
||||
"half",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "clap"
|
||||
version = "4.5.23"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "3135e7ec2ef7b10c6ed8950f0f792ed96ee093fa088608f1c76e569722700c84"
|
||||
dependencies = [
|
||||
"clap_builder",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "clap_builder"
|
||||
version = "4.5.23"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "30582fc632330df2bd26877bde0c1f4470d57c582bbc070376afcd04d8cb4838"
|
||||
dependencies = [
|
||||
"anstyle",
|
||||
"clap_lex",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "clap_lex"
|
||||
version = "0.7.4"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "f46ad14479a25103f283c0f10005961cf086d8dc42205bb44c46ac563475dca6"
|
||||
|
||||
[[package]]
|
||||
name = "compact_str"
|
||||
version = "0.8.0"
|
||||
|
@ -259,12 +338,73 @@ version = "0.1.3"
|
|||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "417bef24afe1460300965a25ff4a24b8b45ad011948302ec221e8a0a81eb2c79"
|
||||
|
||||
[[package]]
|
||||
name = "criterion"
|
||||
version = "0.5.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "f2b12d017a929603d80db1831cd3a24082f8137ce19c69e6447f54f5fc8d692f"
|
||||
dependencies = [
|
||||
"anes",
|
||||
"cast",
|
||||
"ciborium",
|
||||
"clap",
|
||||
"criterion-plot",
|
||||
"is-terminal",
|
||||
"itertools 0.10.5",
|
||||
"num-traits",
|
||||
"once_cell",
|
||||
"oorandom",
|
||||
"plotters",
|
||||
"rayon",
|
||||
"regex",
|
||||
"serde",
|
||||
"serde_derive",
|
||||
"serde_json",
|
||||
"tinytemplate",
|
||||
"walkdir",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "criterion-plot"
|
||||
version = "0.5.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "6b50826342786a51a89e2da3a28f1c32b06e387201bc2d19791f622c673706b1"
|
||||
dependencies = [
|
||||
"cast",
|
||||
"itertools 0.10.5",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "crossbeam-deque"
|
||||
version = "0.8.5"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "613f8cc01fe9cf1a3eb3d7f488fd2fa8388403e97039e2f73692932e291a770d"
|
||||
dependencies = [
|
||||
"crossbeam-epoch",
|
||||
"crossbeam-utils",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "crossbeam-epoch"
|
||||
version = "0.9.18"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "5b82ac4a3c2ca9c3460964f020e1402edd5753411d7737aa39c3714ad1b5420e"
|
||||
dependencies = [
|
||||
"crossbeam-utils",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "crossbeam-utils"
|
||||
version = "0.8.20"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "22ec99545bb0ed0ea7bb9b8e1e9122ea386ff8a48c0922e43f36d45ab09e0e80"
|
||||
|
||||
[[package]]
|
||||
name = "crunchy"
|
||||
version = "0.2.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "7a81dae078cea95a014a339291cec439d2f232ebe854a9d672b796c6afafa9b7"
|
||||
|
||||
[[package]]
|
||||
name = "dashmap"
|
||||
version = "6.1.0"
|
||||
|
@ -343,6 +483,16 @@ dependencies = [
|
|||
"wasi",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "half"
|
||||
version = "2.4.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "6dd08c532ae367adf81c312a4580bc67f1d0fe8bc9c460520283f4c0ff277888"
|
||||
dependencies = [
|
||||
"cfg-if",
|
||||
"crunchy",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "hashbrown"
|
||||
version = "0.14.5"
|
||||
|
@ -364,6 +514,12 @@ dependencies = [
|
|||
"foldhash",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "hermit-abi"
|
||||
version = "0.4.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "fbf6a919d6cf397374f7dfeeea91d974c7c0a7221d0d0f4f20d859d329e53fcc"
|
||||
|
||||
[[package]]
|
||||
name = "icu_collections"
|
||||
version = "1.5.0"
|
||||
|
@ -534,6 +690,26 @@ dependencies = [
|
|||
"memoffset",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "is-terminal"
|
||||
version = "0.4.13"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "261f68e344040fbd0edea105bef17c66edf46f984ddb1115b775ce31be948f4b"
|
||||
dependencies = [
|
||||
"hermit-abi",
|
||||
"libc",
|
||||
"windows-sys 0.52.0",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "itertools"
|
||||
version = "0.10.5"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "b0fd2260e829bddf4cb6ea802289de2f86d6a7a690192fbe91b3f46e0f2c8473"
|
||||
dependencies = [
|
||||
"either",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "itertools"
|
||||
version = "0.13.0"
|
||||
|
@ -608,6 +784,7 @@ version = "0.1.0"
|
|||
dependencies = [
|
||||
"anyhow",
|
||||
"boa_engine",
|
||||
"criterion",
|
||||
"oxc",
|
||||
"rewriter",
|
||||
"url",
|
||||
|
@ -691,6 +868,12 @@ version = "1.20.2"
|
|||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "1261fe7e33c73b354eab43b1273a57c8f967d0391e80353e51f764ac02cf6775"
|
||||
|
||||
[[package]]
|
||||
name = "oorandom"
|
||||
version = "11.1.4"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "b410bbe7e14ab526a0e86877eb47c6996a2bd7746f027ba551028c925390e4e9"
|
||||
|
||||
[[package]]
|
||||
name = "owo-colors"
|
||||
version = "4.1.0"
|
||||
|
@ -950,6 +1133,34 @@ dependencies = [
|
|||
"siphasher",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "plotters"
|
||||
version = "0.3.7"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "5aeb6f403d7a4911efb1e33402027fc44f29b5bf6def3effcc22d7bb75f2b747"
|
||||
dependencies = [
|
||||
"num-traits",
|
||||
"plotters-backend",
|
||||
"plotters-svg",
|
||||
"wasm-bindgen",
|
||||
"web-sys",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "plotters-backend"
|
||||
version = "0.3.7"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "df42e13c12958a16b3f7f4386b9ab1f3e7933914ecea48da7139435263a4172a"
|
||||
|
||||
[[package]]
|
||||
name = "plotters-svg"
|
||||
version = "0.3.7"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "51bae2ac328883f7acdfea3d66a7c35751187f870bc81f94563733a154d7a670"
|
||||
dependencies = [
|
||||
"plotters-backend",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "pollster"
|
||||
version = "0.4.0"
|
||||
|
@ -1034,6 +1245,26 @@ dependencies = [
|
|||
"getrandom",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "rayon"
|
||||
version = "1.10.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "b418a60154510ca1a002a752ca9714984e21e4241e804d32555251faf8b78ffa"
|
||||
dependencies = [
|
||||
"either",
|
||||
"rayon-core",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "rayon-core"
|
||||
version = "1.12.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "1465873a3dfdaa8ae7cb14b4383657caab0b3e8a0aa9ae8e04b044854c8dfce2"
|
||||
dependencies = [
|
||||
"crossbeam-deque",
|
||||
"crossbeam-utils",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "redox_syscall"
|
||||
version = "0.5.8"
|
||||
|
@ -1043,6 +1274,35 @@ dependencies = [
|
|||
"bitflags",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "regex"
|
||||
version = "1.11.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "b544ef1b4eac5dc2db33ea63606ae9ffcfac26c1416a2806ae0bf5f56b201191"
|
||||
dependencies = [
|
||||
"aho-corasick",
|
||||
"memchr",
|
||||
"regex-automata",
|
||||
"regex-syntax",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "regex-automata"
|
||||
version = "0.4.9"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "809e8dc61f6de73b46c85f4c96486310fe304c434cfa43669d7b40f711150908"
|
||||
dependencies = [
|
||||
"aho-corasick",
|
||||
"memchr",
|
||||
"regex-syntax",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "regex-syntax"
|
||||
version = "0.8.5"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "2b15c43186be67a4fd63bee50d0303afffcef381492ebe2c5d87f324e1b8815c"
|
||||
|
||||
[[package]]
|
||||
name = "regress"
|
||||
version = "0.10.1"
|
||||
|
@ -1087,6 +1347,15 @@ version = "1.0.1"
|
|||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "ad97d4ce1560a5e27cec89519dc8300d1aa6035b099821261c651486a19e44d5"
|
||||
|
||||
[[package]]
|
||||
name = "same-file"
|
||||
version = "1.0.6"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "93fc1dc3aaa9bfed95e02e6eadabb4baf7e3078b0bd1b4d7b6b0b68378900502"
|
||||
dependencies = [
|
||||
"winapi-util",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "scopeguard"
|
||||
version = "1.2.0"
|
||||
|
@ -1296,6 +1565,16 @@ dependencies = [
|
|||
"zerovec",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "tinytemplate"
|
||||
version = "1.2.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "be4d6b5f19ff7664e8c98d03e2139cb510db9b0a60b55f8e8709b689d939b6bc"
|
||||
dependencies = [
|
||||
"serde",
|
||||
"serde_json",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "toml_datetime"
|
||||
version = "0.6.8"
|
||||
|
@ -1378,6 +1657,16 @@ version = "0.9.5"
|
|||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "0b928f33d975fc6ad9f86c8f283853ad26bdd5b10b7f1542aa2fa15e2289105a"
|
||||
|
||||
[[package]]
|
||||
name = "walkdir"
|
||||
version = "2.5.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "29790946404f91d9c5d06f9874efddea1dc06c5efe94541a7d6863108e3a5e4b"
|
||||
dependencies = [
|
||||
"same-file",
|
||||
"winapi-util",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "wasi"
|
||||
version = "0.11.0+wasi-snapshot-preview1"
|
||||
|
@ -1462,6 +1751,33 @@ dependencies = [
|
|||
"wasm-bindgen",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "winapi-util"
|
||||
version = "0.1.9"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "cf221c93e13a30d793f7645a0e7762c55d169dbb0a49671918a2319d289b10bb"
|
||||
dependencies = [
|
||||
"windows-sys 0.59.0",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "windows-sys"
|
||||
version = "0.52.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "282be5f36a8ce781fad8c8ae18fa3f9beff57ec1b52cb3de0789201425d9a33d"
|
||||
dependencies = [
|
||||
"windows-targets",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "windows-sys"
|
||||
version = "0.59.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "1e38bc4d79ed67fd075bcc251a1c39b32a1776bbe92e5bef1f0bf1f8c531853b"
|
||||
dependencies = [
|
||||
"windows-targets",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "windows-targets"
|
||||
version = "0.52.6"
|
||||
|
|
|
@ -12,3 +12,8 @@ urlencoding = "2.1.3"
|
|||
|
||||
[dev-dependencies]
|
||||
boa_engine = "0.20.0"
|
||||
criterion = "0.5.1"
|
||||
|
||||
[[bench]]
|
||||
name = "samples"
|
||||
harness = false
|
||||
|
|
62
rewriter/native/benches/samples.rs
Normal file
62
rewriter/native/benches/samples.rs
Normal file
|
@ -0,0 +1,62 @@
|
|||
use criterion::{criterion_group, criterion_main, BatchSize, BenchmarkId, Criterion};
|
||||
use rewriter::{cfg::Config, rewrite};
|
||||
use std::str::FromStr;
|
||||
use url::Url;
|
||||
use urlencoding::encode;
|
||||
|
||||
fn encode_string(str: String) -> String {
|
||||
encode(&str).to_string()
|
||||
}
|
||||
|
||||
pub fn bench(c: &mut Criterion) {
|
||||
let discord = include_str!("../sample/discord.js");
|
||||
let google = include_str!("../sample/google.js");
|
||||
|
||||
let cfg = Config {
|
||||
prefix: "/scrammedjet/".to_string(),
|
||||
encoder: Box::new(encode_string),
|
||||
|
||||
base: Url::from_str("https://google.com/glorngle/si.js").expect("invalid base"),
|
||||
sourcetag: "glongle1".to_string(),
|
||||
|
||||
wrapfn: "$wrap".to_string(),
|
||||
wrapthisfn: "$gwrap".to_string(),
|
||||
importfn: "$import".to_string(),
|
||||
rewritefn: "$rewrite".to_string(),
|
||||
metafn: "$meta".to_string(),
|
||||
setrealmfn: "$setrealm".to_string(),
|
||||
pushsourcemapfn: "$pushsourcemap".to_string(),
|
||||
|
||||
capture_errors: true,
|
||||
do_sourcemaps: true,
|
||||
scramitize: false,
|
||||
strict_rewrites: true,
|
||||
};
|
||||
|
||||
c.bench_with_input(
|
||||
BenchmarkId::new("rewrite/samples", "discord"),
|
||||
&(discord, cfg.clone()),
|
||||
|b, input| {
|
||||
b.iter_batched(
|
||||
|| input.clone(),
|
||||
|x| rewrite(x.0, x.1),
|
||||
BatchSize::SmallInput,
|
||||
)
|
||||
},
|
||||
);
|
||||
|
||||
c.bench_with_input(
|
||||
BenchmarkId::new("rewrite/samples", "google"),
|
||||
&(google, cfg.clone()),
|
||||
|b, input| {
|
||||
b.iter_batched(
|
||||
|| input.clone(),
|
||||
|x| rewrite(x.0, x.1),
|
||||
BatchSize::SmallInput,
|
||||
)
|
||||
},
|
||||
);
|
||||
}
|
||||
|
||||
criterion_group!(samples, bench);
|
||||
criterion_main!(samples);
|
491
rewriter/native/flamegraph.svg
Normal file
491
rewriter/native/flamegraph.svg
Normal file
File diff suppressed because one or more lines are too long
After Width: | Height: | Size: 8.6 MiB |
|
@ -37,34 +37,42 @@ fn dorewrite(data: &str) -> Result<RewriteResult> {
|
|||
.context("failed to rewrite file")
|
||||
}
|
||||
|
||||
fn dobench(data: String) {
|
||||
loop {
|
||||
let _ = dorewrite(&data);
|
||||
}
|
||||
}
|
||||
|
||||
fn main() -> Result<()> {
|
||||
let file = env::args().nth(1).unwrap_or_else(|| "test.js".to_string());
|
||||
let data = fs::read_to_string(file).context("failed to read file")?;
|
||||
let bench = env::args().nth(2).is_some();
|
||||
|
||||
if bench {
|
||||
loop {
|
||||
dorewrite(&data)?;
|
||||
for _ in 0..15 {
|
||||
let data = data.clone();
|
||||
std::thread::spawn(move || dobench(data));
|
||||
}
|
||||
dobench(data);
|
||||
} else {
|
||||
let res = dorewrite(&data)?;
|
||||
|
||||
let source = Arc::new(
|
||||
NamedSource::new(data, "https://google.com/glorngle/si.js").with_language("javascript"),
|
||||
);
|
||||
eprintln!("errors:");
|
||||
for err in res.errors {
|
||||
eprintln!("{}", err.with_source_code(source.clone()));
|
||||
}
|
||||
|
||||
println!("changes: {:#?}", res.changes);
|
||||
|
||||
println!(
|
||||
"rewritten:\n{}",
|
||||
String::from_utf8(res.js).context("failed to parse rewritten js")?
|
||||
);
|
||||
}
|
||||
|
||||
let res = dorewrite(&data)?;
|
||||
|
||||
let source = Arc::new(
|
||||
NamedSource::new(data, "https://google.com/glorngle/si.js").with_language("javascript"),
|
||||
);
|
||||
eprintln!("errors:");
|
||||
for err in res.errors {
|
||||
eprintln!("{}", err.with_source_code(source.clone()));
|
||||
}
|
||||
|
||||
println!("changes: {:#?}", res.changes);
|
||||
|
||||
println!(
|
||||
"rewritten:\n{}",
|
||||
String::from_utf8(res.js).context("failed to parse rewritten js")?
|
||||
);
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
|
|
|
@ -1,24 +1,27 @@
|
|||
use url::Url;
|
||||
|
||||
pub struct Config {
|
||||
pub prefix: String,
|
||||
#[derive(Clone)]
|
||||
pub struct Config<E>
|
||||
where
|
||||
E: Fn(String) -> String,
|
||||
E: Clone,
|
||||
{
|
||||
pub prefix: String,
|
||||
pub sourcetag: String,
|
||||
pub base: Url,
|
||||
|
||||
pub wrapfn: String,
|
||||
pub wrapthisfn: String,
|
||||
pub importfn: String,
|
||||
pub rewritefn: String,
|
||||
pub setrealmfn: String,
|
||||
pub metafn: String,
|
||||
pub pushsourcemapfn: String,
|
||||
pub wrapfn: String,
|
||||
pub wrapthisfn: String,
|
||||
pub importfn: String,
|
||||
pub rewritefn: String,
|
||||
pub setrealmfn: String,
|
||||
pub metafn: String,
|
||||
pub pushsourcemapfn: String,
|
||||
|
||||
pub encoder: EncodeFn,
|
||||
pub encoder: E,
|
||||
|
||||
pub capture_errors: bool,
|
||||
pub scramitize: bool,
|
||||
pub do_sourcemaps: bool,
|
||||
pub strict_rewrites: bool,
|
||||
pub capture_errors: bool,
|
||||
pub scramitize: bool,
|
||||
pub do_sourcemaps: bool,
|
||||
pub strict_rewrites: bool,
|
||||
}
|
||||
|
||||
pub type EncodeFn = Box<dyn Fn(String) -> String>;
|
||||
|
|
|
@ -112,7 +112,11 @@ impl JsChange {
|
|||
|
||||
// returns (bunch of stuff to add before, option<bunch of stuff to add after>)
|
||||
// bunch of stuff to add after should only be some if it's not a replace op
|
||||
fn to_inner<'a>(&'a self, cfg: &'a Config) -> JsChangeInner<'a> {
|
||||
fn to_inner<'a, E>(&'a self, cfg: &'a Config<E>) -> JsChangeInner<'a>
|
||||
where
|
||||
E: Fn(String) -> String,
|
||||
E: Clone,
|
||||
{
|
||||
match self {
|
||||
Self::WrapFn { ident, wrapped, .. } => JsChangeInner::Replace(if *wrapped {
|
||||
smallvec!["(", cfg.wrapfn.as_str(), "(", ident.as_str(), ")", ")"]
|
||||
|
@ -220,7 +224,11 @@ impl JsChanges {
|
|||
self.inner.push(change);
|
||||
}
|
||||
|
||||
pub fn perform(&mut self, js: &str, cfg: &Config) -> JsChangeResult {
|
||||
pub fn perform<E>(&mut self, js: &str, cfg: &Config<E>) -> JsChangeResult
|
||||
where
|
||||
E: Fn(String) -> String,
|
||||
E: Clone,
|
||||
{
|
||||
let mut offset = 0;
|
||||
let mut buffer = Vec::with_capacity(((js.len() as u64 * 120) / 100) as usize);
|
||||
|
||||
|
|
|
@ -1,11 +1,11 @@
|
|||
use cfg::Config;
|
||||
use changes::{JsChange, JsChangeResult, JsChanges};
|
||||
use oxc::{
|
||||
allocator::Allocator,
|
||||
ast::Visit,
|
||||
diagnostics::OxcDiagnostic,
|
||||
parser::{ParseOptions, Parser},
|
||||
span::SourceType,
|
||||
allocator::Allocator,
|
||||
ast::Visit,
|
||||
diagnostics::OxcDiagnostic,
|
||||
parser::{ParseOptions, Parser},
|
||||
span::SourceType,
|
||||
};
|
||||
use thiserror::Error;
|
||||
use visitor::Visitor;
|
||||
|
@ -16,50 +16,54 @@ mod visitor;
|
|||
|
||||
#[derive(Error, Debug)]
|
||||
pub enum RewriterError {
|
||||
#[error("oxc panicked in parser")]
|
||||
OxcPanicked,
|
||||
#[error("oxc panicked in parser")]
|
||||
OxcPanicked,
|
||||
}
|
||||
|
||||
#[derive(Debug)]
|
||||
pub struct RewriteResult {
|
||||
pub js: Vec<u8>,
|
||||
pub sourcemap: Vec<u8>,
|
||||
pub errors: Vec<OxcDiagnostic>,
|
||||
pub changes: Vec<JsChange>,
|
||||
pub js: Vec<u8>,
|
||||
pub sourcemap: Vec<u8>,
|
||||
pub errors: Vec<OxcDiagnostic>,
|
||||
pub changes: Vec<JsChange>,
|
||||
}
|
||||
|
||||
pub fn rewrite(js: &str, config: Config) -> Result<RewriteResult, RewriterError> {
|
||||
let allocator = Allocator::default();
|
||||
let source_type = SourceType::default();
|
||||
let ret = Parser::new(&allocator, js, source_type)
|
||||
.with_options(ParseOptions {
|
||||
parse_regular_expression: false, // default
|
||||
allow_return_outside_function: true,
|
||||
preserve_parens: true, // default
|
||||
})
|
||||
.parse();
|
||||
pub fn rewrite<E>(js: &str, config: Config<E>) -> Result<RewriteResult, RewriterError>
|
||||
where
|
||||
E: Fn(String) -> String,
|
||||
E: Clone,
|
||||
{
|
||||
let allocator = Allocator::default();
|
||||
let source_type = SourceType::default();
|
||||
let ret = Parser::new(&allocator, js, source_type)
|
||||
.with_options(ParseOptions {
|
||||
parse_regular_expression: false, // default
|
||||
allow_return_outside_function: true,
|
||||
preserve_parens: true, // default
|
||||
})
|
||||
.parse();
|
||||
|
||||
if ret.panicked {
|
||||
return Err(RewriterError::OxcPanicked);
|
||||
}
|
||||
if ret.panicked {
|
||||
return Err(RewriterError::OxcPanicked);
|
||||
}
|
||||
|
||||
let mut visitor = Visitor {
|
||||
jschanges: JsChanges::new(),
|
||||
config,
|
||||
};
|
||||
visitor.visit_program(&ret.program);
|
||||
let Visitor {
|
||||
mut jschanges,
|
||||
config,
|
||||
} = visitor;
|
||||
let mut visitor = Visitor {
|
||||
jschanges: JsChanges::new(),
|
||||
config,
|
||||
};
|
||||
visitor.visit_program(&ret.program);
|
||||
let Visitor {
|
||||
mut jschanges,
|
||||
config,
|
||||
} = visitor;
|
||||
|
||||
let JsChangeResult { js, sourcemap } = jschanges.perform(js, &config);
|
||||
let JsChanges { inner: changes } = jschanges;
|
||||
let JsChangeResult { js, sourcemap } = jschanges.perform(js, &config);
|
||||
let JsChanges { inner: changes } = jschanges;
|
||||
|
||||
Ok(RewriteResult {
|
||||
js,
|
||||
sourcemap,
|
||||
errors: ret.errors,
|
||||
changes,
|
||||
})
|
||||
Ok(RewriteResult {
|
||||
js,
|
||||
sourcemap,
|
||||
errors: ret.errors,
|
||||
changes,
|
||||
})
|
||||
}
|
||||
|
|
|
@ -34,12 +34,20 @@ const UNSAFE_GLOBALS: &[&str] = &[
|
|||
"frames",
|
||||
];
|
||||
|
||||
pub struct Visitor {
|
||||
pub struct Visitor<E>
|
||||
where
|
||||
E: Fn(String) -> String,
|
||||
E: Clone,
|
||||
{
|
||||
pub jschanges: JsChanges,
|
||||
pub config: Config,
|
||||
pub config: Config<E>,
|
||||
}
|
||||
|
||||
impl Visitor {
|
||||
impl<E> Visitor<E>
|
||||
where
|
||||
E: Fn(String) -> String,
|
||||
E: Clone,
|
||||
{
|
||||
fn rewrite_url(&mut self, url: String) -> String {
|
||||
let url = self.config.base.join(&url).unwrap();
|
||||
|
||||
|
@ -80,7 +88,11 @@ impl Visitor {
|
|||
}
|
||||
}
|
||||
|
||||
impl<'a> Visit<'a> for Visitor {
|
||||
impl<'a, E> Visit<'a> for Visitor<E>
|
||||
where
|
||||
E: Fn(String) -> String,
|
||||
E: Clone,
|
||||
{
|
||||
fn visit_identifier_reference(&mut self, it: &IdentifierReference) {
|
||||
// if self.config.capture_errors {
|
||||
// self.jschanges.insert(JsChange::GenericChange {
|
||||
|
|
|
@ -5,45 +5,45 @@ use wasm_bindgen::{JsError, JsValue};
|
|||
|
||||
#[derive(Debug, Error)]
|
||||
pub enum RewriterError {
|
||||
#[error("JS: {0}")]
|
||||
Js(String),
|
||||
#[error("URL parse error: {0}")]
|
||||
Url(#[from] url::ParseError),
|
||||
#[error("str fromutf8 error: {0}")]
|
||||
Str(#[from] std::str::Utf8Error),
|
||||
#[error("Rewriter: {0}")]
|
||||
Rewriter(#[from] InnerRewriterError),
|
||||
#[error("reflect set failed: {0}")]
|
||||
ReflectSetFail(String),
|
||||
#[error("JS: {0}")]
|
||||
Js(String),
|
||||
#[error("URL parse error: {0}")]
|
||||
Url(#[from] url::ParseError),
|
||||
#[error("str fromutf8 error: {0}")]
|
||||
Str(#[from] std::str::Utf8Error),
|
||||
#[error("Rewriter: {0}")]
|
||||
Rewriter(#[from] InnerRewriterError),
|
||||
#[error("reflect set failed: {0}")]
|
||||
ReflectSetFail(String),
|
||||
|
||||
#[error("{0} was not {1}")]
|
||||
Not(String, &'static str),
|
||||
#[error("{0} was not {1}")]
|
||||
Not(String, &'static str),
|
||||
}
|
||||
|
||||
impl From<JsValue> for RewriterError {
|
||||
fn from(value: JsValue) -> Self {
|
||||
Self::Js(Error::from(value).to_string().into())
|
||||
}
|
||||
fn from(value: JsValue) -> Self {
|
||||
Self::Js(Error::from(value).to_string().into())
|
||||
}
|
||||
}
|
||||
|
||||
impl From<RewriterError> for JsValue {
|
||||
fn from(value: RewriterError) -> Self {
|
||||
JsError::from(value).into()
|
||||
}
|
||||
fn from(value: RewriterError) -> Self {
|
||||
JsError::from(value).into()
|
||||
}
|
||||
}
|
||||
|
||||
impl RewriterError {
|
||||
pub fn not_str(x: &str) -> Self {
|
||||
Self::Not(x.to_string(), "string")
|
||||
}
|
||||
pub fn not_str(x: &str) -> Self {
|
||||
Self::Not(x.to_string(), "string")
|
||||
}
|
||||
|
||||
pub fn not_fn(x: &str) -> Self {
|
||||
Self::Not(x.to_string(), "function")
|
||||
}
|
||||
pub fn not_fn(x: &str) -> Self {
|
||||
Self::Not(x.to_string(), "function")
|
||||
}
|
||||
|
||||
pub fn not_bool(x: &str) -> Self {
|
||||
Self::Not(x.to_string(), "bool")
|
||||
}
|
||||
pub fn not_bool(x: &str) -> Self {
|
||||
Self::Not(x.to_string(), "bool")
|
||||
}
|
||||
}
|
||||
|
||||
pub type Result<T> = std::result::Result<T, RewriterError>;
|
||||
|
|
|
@ -7,8 +7,8 @@ use instant::Instant;
|
|||
use js_sys::{Function, Object, Reflect};
|
||||
use oxc::diagnostics::NamedSource;
|
||||
use rewriter::{
|
||||
cfg::{Config, EncodeFn},
|
||||
rewrite, RewriteResult,
|
||||
cfg::{Config, EncodeFn},
|
||||
rewrite, RewriteResult,
|
||||
};
|
||||
use url::Url;
|
||||
use wasm_bindgen::prelude::*;
|
||||
|
@ -27,148 +27,148 @@ export function scramtag() {
|
|||
}
|
||||
"#)]
|
||||
extern "C" {
|
||||
pub fn scramtag() -> String;
|
||||
pub fn scramtag() -> String;
|
||||
}
|
||||
|
||||
#[wasm_bindgen]
|
||||
extern "C" {
|
||||
#[wasm_bindgen(typescript_type = "RewriterOutput")]
|
||||
pub type JsRewriterOutput;
|
||||
#[wasm_bindgen(typescript_type = "RewriterOutput")]
|
||||
pub type JsRewriterOutput;
|
||||
}
|
||||
|
||||
#[wasm_bindgen]
|
||||
extern "C" {
|
||||
#[wasm_bindgen(js_namespace = console)]
|
||||
fn error(s: &str);
|
||||
#[wasm_bindgen(js_namespace = console)]
|
||||
fn error(s: &str);
|
||||
}
|
||||
|
||||
fn create_encode_function(encode: JsValue) -> Result<EncodeFn> {
|
||||
let encode = encode.dyn_into::<Function>()?;
|
||||
let encode = encode.dyn_into::<Function>()?;
|
||||
|
||||
Ok(Box::new(move |str| {
|
||||
encode
|
||||
.call1(&JsValue::NULL, &str.into())
|
||||
.unwrap()
|
||||
.as_string()
|
||||
.unwrap()
|
||||
.to_string()
|
||||
}))
|
||||
Ok(Box::new(move |str| {
|
||||
encode
|
||||
.call1(&JsValue::NULL, &str.into())
|
||||
.unwrap()
|
||||
.as_string()
|
||||
.unwrap()
|
||||
.to_string()
|
||||
}))
|
||||
}
|
||||
|
||||
fn get_obj(obj: &JsValue, k: &str) -> Result<JsValue> {
|
||||
Ok(Reflect::get(obj, &k.into())?)
|
||||
Ok(Reflect::get(obj, &k.into())?)
|
||||
}
|
||||
|
||||
fn get_str(obj: &JsValue, k: &str) -> Result<String> {
|
||||
Reflect::get(obj, &k.into())?
|
||||
.as_string()
|
||||
.ok_or_else(|| RewriterError::not_str(k))
|
||||
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)? {
|
||||
Err(RewriterError::ReflectSetFail(k.to_string()))
|
||||
} else {
|
||||
Ok(())
|
||||
}
|
||||
if !Reflect::set(&obj.into(), &k.into(), v)? {
|
||||
Err(RewriterError::ReflectSetFail(k.to_string()))
|
||||
} else {
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
||||
fn get_flag(scramjet: &Object, url: &str, flag: &str) -> Result<bool> {
|
||||
let fenabled = get_obj(scramjet, "flagEnabled")?
|
||||
.dyn_into::<Function>()
|
||||
.map_err(|_| RewriterError::not_fn("scramjet.flagEnabled"))?;
|
||||
let ret = fenabled.call2(
|
||||
&JsValue::NULL,
|
||||
&flag.into(),
|
||||
&web_sys::Url::new(url)?.into(),
|
||||
)?;
|
||||
let fenabled = get_obj(scramjet, "flagEnabled")?
|
||||
.dyn_into::<Function>()
|
||||
.map_err(|_| RewriterError::not_fn("scramjet.flagEnabled"))?;
|
||||
let ret = fenabled.call2(
|
||||
&JsValue::NULL,
|
||||
&flag.into(),
|
||||
&web_sys::Url::new(url)?.into(),
|
||||
)?;
|
||||
|
||||
ret.as_bool()
|
||||
.ok_or_else(|| RewriterError::not_bool("scramjet.flagEnabled return value"))
|
||||
ret.as_bool()
|
||||
.ok_or_else(|| RewriterError::not_bool("scramjet.flagEnabled return value"))
|
||||
}
|
||||
|
||||
fn get_config(scramjet: &Object, url: &str) -> Result<Config> {
|
||||
let codec = &get_obj(scramjet, "codec")?;
|
||||
let config = &get_obj(scramjet, "config")?;
|
||||
let globals = &get_obj(config, "globals")?;
|
||||
let codec = &get_obj(scramjet, "codec")?;
|
||||
let config = &get_obj(scramjet, "config")?;
|
||||
let globals = &get_obj(config, "globals")?;
|
||||
|
||||
Ok(Config {
|
||||
prefix: get_str(config, "prefix")?,
|
||||
encoder: create_encode_function(get_obj(codec, "encode")?)?,
|
||||
base: Url::from_str(url)?,
|
||||
sourcetag: scramtag(),
|
||||
Ok(Config {
|
||||
prefix: get_str(config, "prefix")?,
|
||||
encoder: create_encode_function(get_obj(codec, "encode")?)?,
|
||||
base: Url::from_str(url)?,
|
||||
sourcetag: scramtag(),
|
||||
|
||||
wrapfn: get_str(globals, "wrapfn")?,
|
||||
wrapthisfn: get_str(globals, "wrapthisfn")?,
|
||||
importfn: get_str(globals, "importfn")?,
|
||||
rewritefn: get_str(globals, "rewritefn")?,
|
||||
metafn: get_str(globals, "metafn")?,
|
||||
setrealmfn: get_str(globals, "setrealmfn")?,
|
||||
pushsourcemapfn: get_str(globals, "pushsourcemapfn")?,
|
||||
wrapfn: get_str(globals, "wrapfn")?,
|
||||
wrapthisfn: get_str(globals, "wrapthisfn")?,
|
||||
importfn: get_str(globals, "importfn")?,
|
||||
rewritefn: get_str(globals, "rewritefn")?,
|
||||
metafn: get_str(globals, "metafn")?,
|
||||
setrealmfn: get_str(globals, "setrealmfn")?,
|
||||
pushsourcemapfn: get_str(globals, "pushsourcemapfn")?,
|
||||
|
||||
do_sourcemaps: get_flag(scramjet, url, "sourcemaps")?,
|
||||
capture_errors: get_flag(scramjet, url, "captureErrors")?,
|
||||
scramitize: get_flag(scramjet, url, "scramitize")?,
|
||||
strict_rewrites: get_flag(scramjet, url, "strictRewrites")?,
|
||||
})
|
||||
do_sourcemaps: get_flag(scramjet, url, "sourcemaps")?,
|
||||
capture_errors: get_flag(scramjet, url, "captureErrors")?,
|
||||
scramitize: get_flag(scramjet, url, "scramitize")?,
|
||||
strict_rewrites: get_flag(scramjet, url, "strictRewrites")?,
|
||||
})
|
||||
}
|
||||
|
||||
fn duration_to_millis_f64(duration: Duration) -> f64 {
|
||||
(duration.as_secs() as f64) * 1_000f64 + (duration.subsec_nanos() as f64) / 1_000_000f64
|
||||
(duration.as_secs() as f64) * 1_000f64 + (duration.subsec_nanos() as f64) / 1_000_000f64
|
||||
}
|
||||
|
||||
fn create_rewriter_output(
|
||||
out: RewriteResult,
|
||||
url: String,
|
||||
src: String,
|
||||
duration: Duration,
|
||||
out: RewriteResult,
|
||||
url: String,
|
||||
src: String,
|
||||
duration: Duration,
|
||||
) -> Result<JsRewriterOutput> {
|
||||
let src = Arc::new(NamedSource::new(url, src).with_language("javascript"));
|
||||
#[cfg(feature = "debug")]
|
||||
let errs: Vec<_> = out
|
||||
.errors
|
||||
.into_iter()
|
||||
.map(|x| format!("{}", x.with_source_code(src.clone())))
|
||||
.collect();
|
||||
let src = Arc::new(NamedSource::new(url, src).with_language("javascript"));
|
||||
#[cfg(feature = "debug")]
|
||||
let errs: Vec<_> = out
|
||||
.errors
|
||||
.into_iter()
|
||||
.map(|x| format!("{}", x.with_source_code(src.clone())))
|
||||
.collect();
|
||||
|
||||
let obj = Object::new();
|
||||
set_obj(&obj, "js", &out.js.into())?;
|
||||
#[cfg(feature = "debug")]
|
||||
set_obj(&obj, "errors", &errs.into())?;
|
||||
#[cfg(not(feature = "debug"))]
|
||||
set_obj(&obj, "errors", &js_sys::Array::new())?;
|
||||
set_obj(&obj, "duration", &duration_to_millis_f64(duration).into())?;
|
||||
let obj = Object::new();
|
||||
set_obj(&obj, "js", &out.js.into())?;
|
||||
#[cfg(feature = "debug")]
|
||||
set_obj(&obj, "errors", &errs.into())?;
|
||||
#[cfg(not(feature = "debug"))]
|
||||
set_obj(&obj, "errors", &js_sys::Array::new())?;
|
||||
set_obj(&obj, "duration", &duration_to_millis_f64(duration).into())?;
|
||||
|
||||
Ok(JsRewriterOutput::from(JsValue::from(obj)))
|
||||
Ok(JsRewriterOutput::from(JsValue::from(obj)))
|
||||
}
|
||||
|
||||
#[wasm_bindgen]
|
||||
pub fn rewrite_js(
|
||||
js: String,
|
||||
url: &str,
|
||||
script_url: String,
|
||||
scramjet: &Object,
|
||||
js: String,
|
||||
url: &str,
|
||||
script_url: String,
|
||||
scramjet: &Object,
|
||||
) -> Result<JsRewriterOutput> {
|
||||
let before = Instant::now();
|
||||
let out = rewrite(&js, get_config(scramjet, url)?)?;
|
||||
let after = Instant::now();
|
||||
let before = Instant::now();
|
||||
let out = rewrite(&js, get_config(scramjet, url)?)?;
|
||||
let after = Instant::now();
|
||||
|
||||
create_rewriter_output(out, script_url, js, after - before)
|
||||
create_rewriter_output(out, script_url, js, after - before)
|
||||
}
|
||||
|
||||
#[wasm_bindgen]
|
||||
pub fn rewrite_js_from_arraybuffer(
|
||||
js: Vec<u8>,
|
||||
url: &str,
|
||||
script_url: String,
|
||||
scramjet: &Object,
|
||||
js: Vec<u8>,
|
||||
url: &str,
|
||||
script_url: String,
|
||||
scramjet: &Object,
|
||||
) -> Result<JsRewriterOutput> {
|
||||
// we know that this is a valid utf-8 string
|
||||
let js = unsafe { String::from_utf8_unchecked(js) };
|
||||
// we know that this is a valid utf-8 string
|
||||
let js = unsafe { String::from_utf8_unchecked(js) };
|
||||
|
||||
let before = Instant::now();
|
||||
let out = rewrite(&js, get_config(scramjet, url)?)?;
|
||||
let after = Instant::now();
|
||||
let before = Instant::now();
|
||||
let out = rewrite(&js, get_config(scramjet, url)?)?;
|
||||
let after = Instant::now();
|
||||
|
||||
create_rewriter_output(out, script_url, js, after - before)
|
||||
create_rewriter_output(out, script_url, js, after - before)
|
||||
}
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue