1#![allow(dead_code)]
2
3use std::hash::Hash;
4
5use rustc_hash::FxBuildHasher;
6#[cfg(not(feature = "concurrent"))]
7use rustc_hash::FxHashMap;
8use swc_atoms::atom;
9use swc_common::{SyntaxContext, DUMMY_SP};
10use swc_ecma_ast::*;
11use swc_ecma_utils::ident::IdentLike;
12use swc_ecma_visit::{noop_visit_mut_type, VisitMut};
13
14#[cfg(feature = "concurrent")]
15pub(crate) type Readonly<T> = std::sync::Arc<T>;
16
17#[cfg(not(feature = "concurrent"))]
18pub(crate) type Readonly<T> = T;
19
20const TRACK: bool = false;
21
22pub(crate) trait VarDeclaratorExt: Into<VarDeclarator> {
23 fn into_module_item(self, injected_ctxt: SyntaxContext, name: &str) -> ModuleItem {
24 VarDecl {
25 span: DUMMY_SP,
26 ctxt: injected_ctxt,
27 kind: VarDeclKind::Const,
28 declare: false,
29 decls: if TRACK {
30 vec![
31 self.into(),
32 Str {
33 span: DUMMY_SP,
34 raw: None,
35 value: name.into(),
36 }
37 .assign_to(Ident::new_no_ctxt(atom!("INJECTED_FROM"), DUMMY_SP)),
38 ]
39 } else {
40 vec![self.into()]
41 },
42 }
43 .into()
44 }
45}
46
47impl<T> VarDeclaratorExt for T where T: Into<VarDeclarator> {}
48
49pub(crate) trait ExprExt: Into<Expr> {
50 #[track_caller]
51 fn assign_to<T>(self, lhs: T) -> VarDeclarator
52 where
53 T: IdentLike,
54 {
55 let init = self.into();
56 let lhs = lhs.into_id();
57
58 if cfg!(debug_assertions) {
59 if let Expr::Ident(rhs) = &init {
60 debug_assert_ne!(lhs, rhs.to_id());
61 }
62 }
63
64 VarDeclarator {
65 span: DUMMY_SP,
66 name: Ident::new(lhs.0, DUMMY_SP, lhs.1).into(),
67 init: Some(Box::new(init)),
68 definite: false,
69 }
70 }
71}
72
73impl<T> ExprExt for T where T: Into<Expr> {}
74
75#[derive(Debug)]
76pub(crate) struct CHashSet<V>
77where
78 V: Eq + Hash,
79{
80 inner: CloneMap<V, ()>,
81}
82
83impl<V> CHashSet<V>
84where
85 V: Eq + Hash,
86{
87 }
91
92impl<V> Default for CHashSet<V>
93where
94 V: Eq + Hash,
95{
96 fn default() -> Self {
97 Self {
98 inner: Default::default(),
99 }
100 }
101}
102
103#[derive(Debug)]
104pub(crate) struct CloneMap<K, V>
105where
106 K: Eq + Hash,
107 V: Clone,
108{
109 #[cfg(feature = "concurrent")]
110 inner: dashmap::DashMap<K, V, FxBuildHasher>,
111 #[cfg(not(feature = "concurrent"))]
112 inner: std::cell::RefCell<FxHashMap<K, V>>,
113}
114
115impl<K, V> Default for CloneMap<K, V>
116where
117 K: Eq + Hash,
118 V: Clone,
119{
120 fn default() -> Self {
121 Self {
122 inner: Default::default(),
123 }
124 }
125}
126
127impl<K, V> CloneMap<K, V>
128where
129 K: Eq + Hash,
130 V: Clone,
131{
132 #[cfg(feature = "concurrent")]
133 pub fn get(&self, k: &K) -> Option<V> {
134 self.inner.get(k).map(|v| v.value().clone())
135 }
136
137 #[cfg(not(feature = "concurrent"))]
138 pub fn get(&self, k: &K) -> Option<V> {
139 self.inner.borrow().get(k).map(|v| v.clone())
140 }
141
142 #[cfg(feature = "concurrent")]
143 pub fn insert(&self, k: K, v: V) -> Option<V> {
144 self.inner.insert(k, v)
145 }
146
147 #[cfg(not(feature = "concurrent"))]
148 pub fn insert(&self, k: K, v: V) -> Option<V> {
149 self.inner.borrow_mut().insert(k, v)
150 }
151}
152
153pub(crate) struct HygieneRemover;
154
155impl VisitMut for HygieneRemover {
156 noop_visit_mut_type!(fail);
157
158 fn visit_mut_syntax_context(&mut self, n: &mut SyntaxContext) {
159 *n = SyntaxContext::empty();
160 }
161}
162
163#[cfg(feature = "rayon")]
164pub(crate) use rayon::join;
165
166#[cfg(not(feature = "rayon"))]
167pub(crate) fn join<A, B, RA, RB>(op_a: A, op_b: B) -> (RA, RB)
168where
169 A: FnOnce() -> RA,
170 B: FnOnce() -> RB,
171{
172 (op_a(), op_b())
173}
174
175#[cfg(feature = "rayon")]
176pub(crate) use rayon::iter::IntoParallelIterator;
177
178#[cfg(not(feature = "rayon"))]
180pub(crate) trait IntoParallelIterator: Sized + IntoIterator {
181 fn into_par_iter(self) -> <Self as IntoIterator>::IntoIter {
182 self.into_iter()
183 }
184}
185
186#[cfg(not(feature = "rayon"))]
187impl<T> IntoParallelIterator for T where T: IntoIterator {}
188
189fn metadata(key: &str, value: &str) -> PropOrSpread {
190 PropOrSpread::Prop(Box::new(Prop::KeyValue(KeyValueProp {
191 key: PropName::Ident(IdentName::new(key.into(), DUMMY_SP)),
192 value: Lit::Str(Str {
193 span: DUMMY_SP,
194 value: value.into(),
195 raw: None,
196 })
197 .into(),
198 })))
199}
200
201#[derive(Debug, Default)]
202pub(crate) struct ExportMetadata {
203 pub injected: bool,
204 pub export_ctxt: Option<SyntaxContext>,
205}
206
207impl ExportMetadata {
208 pub fn into_with(self) -> Box<ObjectLit> {
209 let mut obj = Some(Box::new(ObjectLit {
210 span: DUMMY_SP,
211 props: Vec::new(),
212 }));
213
214 self.encode(&mut obj);
215
216 obj.unwrap()
217 }
218
219 pub fn encode(&self, to: &mut Option<Box<ObjectLit>>) {
220 let mut props = Vec::new();
221
222 if self.injected {
223 props.push(metadata("__swc_bundler__injected__", "1"));
224 }
225
226 if let Some(export_ctxt) = self.export_ctxt {
227 props.push(metadata(
228 "__swc_bundler__export_ctxt__",
229 &export_ctxt.as_u32().to_string(),
230 ));
231 }
232
233 if to.is_none() {
234 *to = Some(Box::new(ObjectLit {
235 span: DUMMY_SP,
236 props,
237 }));
238 } else {
239 let obj = to.as_mut().unwrap();
240 obj.props.extend(props);
241 }
242 }
243
244 pub fn decode(with: Option<&ObjectLit>) -> Self {
245 let mut data = ExportMetadata::default();
246
247 if let Some(with) = with {
248 for prop in &with.props {
249 if let PropOrSpread::Prop(p) = prop {
250 if let Prop::KeyValue(KeyValueProp {
251 key: PropName::Ident(IdentName { sym, .. }),
252 value,
253 ..
254 }) = &**p
255 {
256 if *sym == "__swc_bundler__injected__" {
257 if let Expr::Lit(Lit::Str(Str { value, .. })) = &**value {
258 if value == "1" {
259 data.injected = true;
260 }
261 }
262 } else if *sym == "__swc_bundler__export_ctxt__" {
263 if let Expr::Lit(Lit::Str(Str { value, .. })) = &**value {
264 if let Some(value) = value.as_str() {
265 if let Ok(v) = value.parse() {
266 data.export_ctxt = Some(SyntaxContext::from_u32(v));
267 }
268 }
269 }
270 }
271 }
272 }
273 }
274 }
275
276 data
277 }
278}
279
280pub(crate) fn is_injected(with: &ObjectLit) -> bool {
281 ExportMetadata::decode(Some(with)).injected
282}