Skip to content

Commit 2381d02

Browse files
magic-akarikdy1
authored andcommitted
refactor(es/react): Merge jsx-dev pass into jsx pass (#10639)
1 parent 6e6dc44 commit 2381d02

File tree

10 files changed

+272
-419
lines changed

10 files changed

+272
-419
lines changed

crates/swc/tests/fixture/issues-8xxx/8210/output/1.js

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,7 @@ const Component = ()=>{
55
fileName: "$DIR/tests/fixture/issues-8xxx/8210/input/1.js",
66
lineNumber: 2,
77
columnNumber: 23
8-
}, void 0),
8+
}, this),
99
children: "Hello"
1010
}, void 0, false, {
1111
fileName: "$DIR/tests/fixture/issues-8xxx/8210/input/1.js",

crates/swc_ecma_transforms_react/src/jsx/automatic.rs

Lines changed: 71 additions & 51 deletions
Original file line numberDiff line numberDiff line change
@@ -4,16 +4,19 @@ use std::iter::once;
44

55
use swc_atoms::{atom, Atom};
66
use swc_common::{
7-
comments::Comments, errors::HANDLER, sync::Lrc, util::take::Take, BytePos, Mark, Spanned,
8-
SyntaxContext, DUMMY_SP,
7+
comments::Comments, errors::HANDLER, sync::Lrc, util::take::Take, BytePos, Mark, SourceMap,
8+
Spanned, SyntaxContext, DUMMY_SP,
99
};
1010
use swc_ecma_ast::*;
1111
use swc_ecma_utils::{prepend_stmt, private_ident, quote_ident, ExprFactory, StmtLike};
1212
use swc_ecma_visit::{noop_visit_mut_type, visit_mut_pass, VisitMut, VisitMutWith};
1313

1414
use crate::{
15-
jsx::should_use_create_element, jsx_name, jsx_text_to_str, transform_jsx_attr_str,
16-
AutomaticConfig, CommonConfig,
15+
jsx::{
16+
development::{visit_mut_development, DevelopmentContext, JsxDev},
17+
should_use_create_element,
18+
},
19+
jsx_name, jsx_text_to_str, transform_jsx_attr_str, AutomaticConfig, CommonConfig,
1720
};
1821

1922
/// Automatic runtime JSX transformer
@@ -27,6 +30,7 @@ pub fn automatic<C>(
2730
common: CommonConfig,
2831
unresolved_mark: Mark,
2932
comments: Option<C>,
33+
cm: Lrc<SourceMap>,
3034
) -> impl Pass + VisitMut
3135
where
3236
C: Comments + 'static,
@@ -46,9 +50,13 @@ where
4650
import_fragment: None,
4751
import_create_element: None,
4852

49-
development: common.development.into_bool(),
5053
throw_if_namespace: common.throw_if_namespace.into_bool(),
54+
55+
development: common.development.into_bool(),
56+
development_ctx: DevelopmentContext::default(),
57+
5158
add_pure_comment,
59+
cm,
5260
})
5361
}
5462

@@ -61,10 +69,13 @@ struct Automatic {
6169
import_create_element: Option<Ident>,
6270
import_fragment: Option<Ident>,
6371

64-
development: bool,
6572
throw_if_namespace: bool,
6673

74+
development: bool,
75+
development_ctx: DevelopmentContext,
76+
6777
add_pure_comment: Lrc<dyn Fn(BytePos)>,
78+
cm: Lrc<SourceMap>,
6879
}
6980

7081
impl Automatic {
@@ -241,8 +252,6 @@ impl Automatic {
241252
};
242253

243254
let mut key = None;
244-
let mut source_props = None;
245-
let mut self_props = None;
246255

247256
for attr in el.opening.attrs {
248257
match attr {
@@ -270,36 +279,6 @@ impl Automatic {
270279
continue;
271280
}
272281

273-
if !use_create_element && *i.sym == *"__source" && self.development {
274-
if source_props.is_some() {
275-
panic!("Duplicate __source is found");
276-
}
277-
source_props = attr
278-
.value
279-
.and_then(jsx_attr_value_to_expr)
280-
.map(|expr| expr.as_arg());
281-
assert_ne!(
282-
source_props, None,
283-
"value of property '__source' should not be empty"
284-
);
285-
continue;
286-
}
287-
288-
if !use_create_element && *i.sym == *"__self" && self.development {
289-
if self_props.is_some() {
290-
panic!("Duplicate __self is found");
291-
}
292-
self_props = attr
293-
.value
294-
.and_then(jsx_attr_value_to_expr)
295-
.map(|expr| expr.as_arg());
296-
assert_ne!(
297-
self_props, None,
298-
"value of property '__self' should not be empty"
299-
);
300-
continue;
301-
}
302-
303282
let value = match attr.value {
304283
Some(v) => {
305284
jsx_attr_value_to_expr(v).expect("empty expression container?")
@@ -407,6 +386,23 @@ impl Automatic {
407386
}
408387
}
409388

389+
if use_create_element && self.development {
390+
props_obj.props.push(
391+
Prop::KeyValue(KeyValueProp {
392+
key: quote_ident!("__source").into(),
393+
value: self.source_props(el.span.lo).into(),
394+
})
395+
.into(),
396+
);
397+
props_obj.props.push(
398+
Prop::KeyValue(KeyValueProp {
399+
key: quote_ident!("__self").into(),
400+
value: self.self_props().into(),
401+
})
402+
.into(),
403+
);
404+
}
405+
410406
let args = once(name.as_arg()).chain(once(props_obj.as_arg()));
411407
let args = if use_create_element {
412408
args.chain(children.into_iter().flatten()).collect()
@@ -417,21 +413,10 @@ impl Automatic {
417413
None => Expr::undefined(DUMMY_SP).as_arg(),
418414
};
419415

420-
// set undefined literal to __source if __source is None
421-
let source_props = match source_props {
422-
Some(source_props) => source_props,
423-
None => Expr::undefined(DUMMY_SP).as_arg(),
424-
};
425-
426-
// set undefined literal to __self if __self is None
427-
let self_props = match self_props {
428-
Some(self_props) => self_props,
429-
None => Expr::undefined(DUMMY_SP).as_arg(),
430-
};
431416
args.chain(once(key))
432417
.chain(once(use_jsxs.as_arg()))
433-
.chain(once(source_props))
434-
.chain(once(self_props))
418+
.chain(once(self.source_props(el.span.lo).as_arg()))
419+
.chain(once(self.self_props().as_arg()))
435420
.collect()
436421
} else {
437422
args.chain(key).collect()
@@ -488,9 +473,44 @@ impl Automatic {
488473
}
489474
}
490475

476+
impl Automatic {
477+
fn source_props(&self, pos: BytePos) -> ObjectLit {
478+
let loc = self.cm.lookup_char_pos(pos);
479+
480+
ObjectLit {
481+
props: vec![
482+
Prop::KeyValue(KeyValueProp {
483+
key: quote_ident!("fileName").into(),
484+
value: loc.file.name.to_string().into(),
485+
})
486+
.into(),
487+
Prop::KeyValue(KeyValueProp {
488+
key: quote_ident!("lineNumber").into(),
489+
value: loc.line.into(),
490+
})
491+
.into(),
492+
Prop::KeyValue(KeyValueProp {
493+
key: quote_ident!("columnNumber").into(),
494+
value: (loc.col.0 + 1).into(),
495+
})
496+
.into(),
497+
],
498+
..Default::default()
499+
}
500+
}
501+
}
502+
503+
impl JsxDev for Automatic {
504+
fn development_ctxt(&mut self) -> &mut DevelopmentContext {
505+
&mut self.development_ctx
506+
}
507+
}
508+
491509
impl VisitMut for Automatic {
492510
noop_visit_mut_type!();
493511

512+
visit_mut_development!();
513+
494514
fn visit_mut_expr(&mut self, expr: &mut Expr) {
495515
if let Expr::JSXElement(el) = expr {
496516
// <div></div> => React.createElement('div', null);

crates/swc_ecma_transforms_react/src/jsx/classic.rs

Lines changed: 88 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -14,10 +14,13 @@ use swc_common::{
1414
};
1515
use swc_ecma_ast::*;
1616
use swc_ecma_parser::{parse_file_as_expr, Syntax};
17-
use swc_ecma_utils::{drop_span, ExprFactory};
17+
use swc_ecma_utils::{drop_span, quote_ident, ExprFactory};
1818
use swc_ecma_visit::{noop_visit_mut_type, visit_mut_pass, VisitMut, VisitMutWith};
1919

20-
use crate::{jsx_name, jsx_text_to_str, transform_jsx_attr_str, ClassicConfig, CommonConfig};
20+
use crate::{
21+
jsx::development::{visit_mut_development, DevelopmentContext, JsxDev},
22+
jsx_name, jsx_text_to_str, transform_jsx_attr_str, ClassicConfig, CommonConfig,
23+
};
2124

2225
/// Parse `src` to use as a `pragma` or `pragmaFrag` in jsx.
2326
pub fn parse_expr_for_jsx(
@@ -107,20 +110,29 @@ where
107110

108111
visit_mut_pass(Classic {
109112
pragma,
110-
111113
pragma_frag,
114+
112115
throw_if_namespace: common.throw_if_namespace.into_bool(),
116+
117+
development: common.development.into_bool(),
118+
development_ctx: DevelopmentContext::default(),
119+
113120
add_pure_comment,
121+
cm,
114122
})
115123
}
116124

117125
struct Classic {
118126
pragma: Lrc<Box<Expr>>,
119-
120127
pragma_frag: Lrc<Box<Expr>>,
128+
121129
throw_if_namespace: bool,
122130

131+
development: bool,
132+
development_ctx: DevelopmentContext,
133+
123134
add_pure_comment: Lrc<dyn Fn(BytePos)>,
135+
cm: Lrc<SourceMap>,
124136
}
125137

126138
#[cfg(feature = "concurrent")]
@@ -317,10 +329,20 @@ impl Classic {
317329
}
318330
}
319331

332+
impl JsxDev for Classic {
333+
fn development_ctxt(&mut self) -> &mut DevelopmentContext {
334+
&mut self.development_ctx
335+
}
336+
}
337+
320338
impl VisitMut for Classic {
321339
noop_visit_mut_type!();
322340

341+
visit_mut_development!();
342+
323343
fn visit_mut_expr(&mut self, expr: &mut Expr) {
344+
expr.visit_mut_children_with(self);
345+
324346
if let Expr::JSXElement(el) = expr {
325347
// <div></div> => React.createElement('div', null);
326348
*expr = self.jsx_elem_to_expr(*el.take());
@@ -340,8 +362,69 @@ impl VisitMut for Classic {
340362
*expr = self.jsx_frag_to_expr(frag.take());
341363
}
342364
}
365+
}
343366

344-
expr.visit_mut_children_with(self);
367+
fn visit_mut_jsx_opening_element(&mut self, e: &mut JSXOpeningElement) {
368+
e.visit_mut_children_with(self);
369+
370+
if !self.development {
371+
return;
372+
}
373+
374+
let loc = self.cm.lookup_char_pos(e.span.lo);
375+
let file_name = loc.file.name.to_string();
376+
377+
e.attrs.push(
378+
JSXAttr {
379+
span: DUMMY_SP,
380+
name: quote_ident!("__source").into(),
381+
value: Some(
382+
JSXExprContainer {
383+
span: DUMMY_SP,
384+
expr: JSXExpr::Expr(
385+
ObjectLit {
386+
span: DUMMY_SP,
387+
props: vec![
388+
Prop::KeyValue(KeyValueProp {
389+
key: quote_ident!("fileName").into(),
390+
value: file_name.into(),
391+
})
392+
.into(),
393+
Prop::KeyValue(KeyValueProp {
394+
key: quote_ident!("lineNumber").into(),
395+
value: loc.line.into(),
396+
})
397+
.into(),
398+
Prop::KeyValue(KeyValueProp {
399+
key: quote_ident!("columnNumber").into(),
400+
value: (loc.col.0 + 1).into(),
401+
})
402+
.into(),
403+
],
404+
}
405+
.into(),
406+
),
407+
}
408+
.into(),
409+
),
410+
}
411+
.into(),
412+
);
413+
414+
e.attrs.push(
415+
JSXAttr {
416+
span: DUMMY_SP,
417+
name: quote_ident!("__self").into(),
418+
value: Some(
419+
JSXExprContainer {
420+
span: DUMMY_SP,
421+
expr: JSXExpr::Expr(self.self_props().into()),
422+
}
423+
.into(),
424+
),
425+
}
426+
.into(),
427+
);
345428
}
346429
}
347430

0 commit comments

Comments
 (0)