swc_ecma_transforms_react/jsx_src/
mod.rs1use swc_common::{sync::Lrc, SourceMap, DUMMY_SP};
2use swc_ecma_ast::*;
3use swc_ecma_transforms_base::perf::Parallel;
4use swc_ecma_utils::quote_ident;
5use swc_ecma_visit::{noop_visit_mut_type, visit_mut_pass, VisitMut, VisitMutWith};
6
7#[cfg(test)]
8mod tests;
9
10pub fn jsx_src(dev: bool, cm: Lrc<SourceMap>) -> impl Pass {
12 visit_mut_pass(JsxSrc { cm, dev })
13}
14
15#[derive(Clone)]
16struct JsxSrc {
17 cm: Lrc<SourceMap>,
18 dev: bool,
19}
20
21impl Parallel for JsxSrc {
22 fn create(&self) -> Self {
23 self.clone()
24 }
25
26 fn merge(&mut self, _: Self) {}
27}
28
29impl VisitMut for JsxSrc {
30 noop_visit_mut_type!();
31
32 fn visit_mut_jsx_opening_element(&mut self, e: &mut JSXOpeningElement) {
33 if !self.dev || e.span == DUMMY_SP {
34 return;
35 }
36
37 e.visit_mut_children_with(self);
38
39 let loc = self.cm.lookup_char_pos(e.span.lo);
40 let file_name = loc.file.name.to_string();
41
42 e.attrs.push(JSXAttrOrSpread::JSXAttr(JSXAttr {
43 span: DUMMY_SP,
44 name: JSXAttrName::Ident(quote_ident!("__source")),
45 value: Some(JSXAttrValue::JSXExprContainer(JSXExprContainer {
46 span: DUMMY_SP,
47 expr: JSXExpr::Expr(Box::new(
48 ObjectLit {
49 span: DUMMY_SP,
50 props: vec![
51 PropOrSpread::Prop(Box::new(Prop::KeyValue(KeyValueProp {
52 key: PropName::Ident(quote_ident!("fileName")),
53 value: Box::new(Expr::Lit(Lit::Str(Str {
54 span: DUMMY_SP,
55 raw: None,
56 value: file_name.into(),
57 }))),
58 }))),
59 PropOrSpread::Prop(Box::new(Prop::KeyValue(KeyValueProp {
60 key: PropName::Ident(quote_ident!("lineNumber")),
61 value: loc.line.into(),
62 }))),
63 PropOrSpread::Prop(Box::new(Prop::KeyValue(KeyValueProp {
64 key: PropName::Ident(quote_ident!("columnNumber")),
65 value: (loc.col.0 + 1).into(),
66 }))),
67 ],
68 }
69 .into(),
70 )),
71 })),
72 }));
73 }
74}