File size: 3,543 Bytes
bee6636
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
use std::{error::Error, str::FromStr};

use anyhow::{Context, Result};
use bytes::Buf;
use js::{
	RewriteResult, Rewriter,
	cfg::{Config, Flags, UrlRewriter},
};
use oxc::allocator::{Allocator, StringBuilder};
use url::Url;
use urlencoding::encode;

use crate::RewriterOptions;

struct NativeUrlRewriter;

impl UrlRewriter for NativeUrlRewriter {
	fn rewrite(
		&self,
		_cfg: &Config,
		flags: &Flags,
		url: &str,
		builder: &mut StringBuilder,
		_module: bool,
	) -> Result<(), Box<dyn Error + Sync + Send>> {
		let base = Url::from_str(&flags.base)?;
		builder.push_str(encode(base.join(url)?.as_str()).as_ref());

		Ok(())
	}
}

#[derive(Debug)]
enum RewriteType<'a> {
	Insert { pos: u32, size: u32 },
	Replace { start: u32, end: u32, str: &'a [u8] },
}

pub struct NativeRewriter {
	alloc: Allocator,
	rewriter: Rewriter<NativeUrlRewriter>,
}

impl NativeRewriter {
	#[allow(dead_code)]
	pub fn default() -> Self {
		Self::new(&RewriterOptions::default())
	}

	pub fn new(cfg: &RewriterOptions) -> Self {
		let rewriter = Rewriter::new(
			Config {
				prefix: cfg.prefix.clone(),
				wrapfn: cfg.wrapfn.clone(),
				wrapthisfn: cfg.wrapthisfn.clone(),
				importfn: cfg.importfn.clone(),
				rewritefn: cfg.rewritefn.clone(),
				metafn: cfg.metafn.clone(),
				setrealmfn: cfg.setrealmfn.clone(),
				pushsourcemapfn: cfg.pushsourcemapfn.clone(),
			},
			NativeUrlRewriter,
		);

		Self {
			alloc: Allocator::new(),
			rewriter,
		}
	}

	#[allow(dead_code)]
	pub fn rewrite_default(&self, data: &str) -> Result<RewriteResult<'_>> {
		self.rewrite(data, &RewriterOptions::default())
	}

	pub fn rewrite(&self, data: &str, cfg: &RewriterOptions) -> Result<RewriteResult<'_>> {
		self.rewriter
			.rewrite(
				&self.alloc,
				data,
				Flags {
					base: cfg.base.clone(),
					sourcetag: cfg.sourcetag.clone(),

					is_module: cfg.is_module,

					capture_errors: cfg.capture_errors,
					do_sourcemaps: cfg.do_sourcemaps,
					scramitize: cfg.scramitize,
					strict_rewrites: cfg.strict_rewrites,
				},
			)
			.context("failed to rewrite file")
	}
	pub fn reset(&mut self) {
		self.alloc.reset();
	}

	pub fn unrewrite(res: &RewriteResult) -> Vec<u8> {
		let js = res.js.as_slice();
		let mut map = res.sourcemap.as_slice();
		let rewrite_cnt = map.get_u32_le();
		let mut rewrites = Vec::with_capacity(rewrite_cnt as usize);

		for x in 0..rewrite_cnt {
			let pos = map.get_u32_le();
			let size = map.get_u32_le();

			let ty = map.get_u8();
			if ty == 0 {
				rewrites.push(RewriteType::Insert { pos, size });
			} else if ty == 1 {
				let len = map.get_u32_le();

				let (str, new) = map.split_at(len as usize);
				map = new;

				rewrites.push(RewriteType::Replace {
					start: pos,
					end: pos + size,
					str,
				});
			} else {
				panic!(
					"{x} {ty} {:X?} {:#?}",
					&map[0..10],
					&rewrites.last_chunk::<3>()
				)
			}
		}

		let mut out = Vec::with_capacity(res.js.len());

		let mut cursor: u32 = 0;

		for rewrite in rewrites {
			match rewrite {
				RewriteType::Insert { pos, size } => {
					out.extend_from_slice(&js[cursor as usize..pos as usize]);
					cursor = pos + size;
				}
				RewriteType::Replace { start, end, str } => {
					out.extend_from_slice(&js[cursor as usize..start as usize]);
					out.extend_from_slice(&str);
					cursor = end;
				}
			}
		}

		out.extend_from_slice(&js[cursor as usize..]);

		out.to_vec()
	}
}