swc_ecma_transforms_react/jsx_src/
mod.rs

1use 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
10/// `@babel/plugin-transform-react-jsx-source`
11pub 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}