mirror of
https://github.com/swc-project/swc.git
synced 2024-11-27 13:38:33 +03:00
Support jsx pragma (#1015)
swc_ecma_transforms - Support jsx pragma (#107, #838)
This commit is contained in:
parent
a60b0a9cd4
commit
578d64a398
@ -32,14 +32,14 @@ install:
|
||||
- rm -rf ~/.nvm
|
||||
- git clone https://github.com/creationix/nvm.git ~/.nvm
|
||||
- source ~/.nvm/nvm.sh
|
||||
- nvm install 8.15.0
|
||||
- nvm use 8.15.0
|
||||
- nvm install 12.18.3
|
||||
- nvm use 12.18.3
|
||||
- npm install
|
||||
- npm install browserslist regenerator
|
||||
- npm install -g jest
|
||||
|
||||
script:
|
||||
# - RUST_BACKTRACE=0 cargo check --color always --all --all-targets
|
||||
# - RUST_BACKTRACE=0 cargo check --color always --all --all-targets
|
||||
- true
|
||||
|
||||
before_deploy:
|
||||
|
@ -1,6 +1,6 @@
|
||||
[package]
|
||||
name = "swc_bundler"
|
||||
version = "0.5.0"
|
||||
version = "0.6.0"
|
||||
authors = ["강동윤 <kdy1997.dev@gmail.com>"]
|
||||
license = "Apache-2.0/MIT"
|
||||
repository = "https://github.com/swc-project/swc.git"
|
||||
@ -20,7 +20,7 @@ swc_common = { version = "0.10.0", path = "../common" }
|
||||
swc_ecma_ast = { version = "0.30.0", path = "../ecmascript/ast" }
|
||||
swc_ecma_codegen = { version = "0.34.0", path = "../ecmascript/codegen" }
|
||||
swc_ecma_parser = { version = "0.36.0", path = "../ecmascript/parser" }
|
||||
swc_ecma_transforms = { version = "0.22.0", path = "../ecmascript/transforms" }
|
||||
swc_ecma_transforms = { version = "0.23.0", path = "../ecmascript/transforms" }
|
||||
swc_ecma_utils = { version = "0.20.0", path = "../ecmascript/utils" }
|
||||
swc_ecma_visit = { version = "0.16.0", path = "../ecmascript/visit" }
|
||||
anyhow = "1"
|
||||
|
@ -1,6 +1,6 @@
|
||||
[package]
|
||||
name = "swc_ecmascript"
|
||||
version = "0.6.3"
|
||||
version = "0.7.0"
|
||||
authors = ["강동윤 <kdy1997.dev@gmail.com>"]
|
||||
license = "Apache-2.0/MIT"
|
||||
repository = "https://github.com/swc-project/swc.git"
|
||||
@ -25,7 +25,7 @@ swc_ecma_codegen = { version = "0.34.0", path ="./codegen", optional = true }
|
||||
swc_ecma_dep_graph = { version = "0.1.0", path = "./dep-graph", optional = true }
|
||||
swc_ecma_parser = { version = "0.36.0", path ="./parser", optional = true }
|
||||
swc_ecma_utils = { version = "0.20.0", path ="./utils", optional = true }
|
||||
swc_ecma_transforms = { version = "0.22.0", path ="./transforms", optional = true }
|
||||
swc_ecma_transforms = { version = "0.23.0", path ="./transforms", optional = true }
|
||||
swc_ecma_visit = { version = "0.16.0", path ="./visit", optional = true }
|
||||
|
||||
[dev-dependencies]
|
||||
|
@ -6,7 +6,7 @@ edition = "2018"
|
||||
license = "Apache-2.0/MIT"
|
||||
name = "swc_ecma_transforms"
|
||||
repository = "https://github.com/swc-project/swc.git"
|
||||
version = "0.22.2"
|
||||
version = "0.23.0"
|
||||
|
||||
[features]
|
||||
const-modules = ["dashmap"]
|
||||
|
@ -6,7 +6,7 @@ pub use self::{
|
||||
jsx_self::jsx_self,
|
||||
jsx_src::jsx_src,
|
||||
};
|
||||
use swc_common::{chain, sync::Lrc, SourceMap};
|
||||
use swc_common::{chain, comments::Comments, sync::Lrc, SourceMap};
|
||||
use swc_ecma_visit::Fold;
|
||||
|
||||
mod display_name;
|
||||
@ -17,11 +17,14 @@ mod jsx_src;
|
||||
/// `@babel/preset-react`
|
||||
///
|
||||
/// Preset for all React plugins.
|
||||
pub fn react(cm: Lrc<SourceMap>, options: Options) -> impl Fold {
|
||||
pub fn react<C>(cm: Lrc<SourceMap>, comments: Option<C>, options: Options) -> impl Fold
|
||||
where
|
||||
C: Comments,
|
||||
{
|
||||
let Options { development, .. } = options;
|
||||
|
||||
chain!(
|
||||
jsx(cm.clone(), options),
|
||||
jsx(cm.clone(), comments, options),
|
||||
display_name(),
|
||||
jsx_src(development, cm),
|
||||
jsx_self(development)
|
||||
|
@ -5,7 +5,12 @@ use regex::Regex;
|
||||
use serde::{Deserialize, Serialize};
|
||||
use std::{iter, mem};
|
||||
use swc_atoms::{js_word, JsWord};
|
||||
use swc_common::{iter::IdentifyLast, sync::Lrc, FileName, SourceMap, Spanned, DUMMY_SP};
|
||||
use swc_common::{
|
||||
comments::{CommentKind, Comments},
|
||||
iter::IdentifyLast,
|
||||
sync::Lrc,
|
||||
FileName, SourceMap, Spanned, DUMMY_SP,
|
||||
};
|
||||
use swc_ecma_ast::*;
|
||||
use swc_ecma_parser::{Parser, StringInput, Syntax};
|
||||
use swc_ecma_visit::{noop_fold_type, Fold, FoldWith};
|
||||
@ -86,9 +91,14 @@ fn parse_option(cm: &SourceMap, name: &str, src: String) -> Box<Expr> {
|
||||
/// `@babel/plugin-transform-react-jsx`
|
||||
///
|
||||
/// Turn JSX into React function calls
|
||||
pub fn jsx(cm: Lrc<SourceMap>, options: Options) -> impl Fold {
|
||||
pub fn jsx<C>(cm: Lrc<SourceMap>, comments: Option<C>, options: Options) -> impl Fold
|
||||
where
|
||||
C: Comments,
|
||||
{
|
||||
Jsx {
|
||||
cm: cm.clone(),
|
||||
pragma: ExprOrSuper::Expr(parse_option(&cm, "pragma", options.pragma)),
|
||||
comments,
|
||||
pragma_frag: ExprOrSpread {
|
||||
spread: None,
|
||||
expr: parse_option(&cm, "pragmaFrag", options.pragma_frag),
|
||||
@ -98,14 +108,22 @@ pub fn jsx(cm: Lrc<SourceMap>, options: Options) -> impl Fold {
|
||||
}
|
||||
}
|
||||
|
||||
struct Jsx {
|
||||
struct Jsx<C>
|
||||
where
|
||||
C: Comments,
|
||||
{
|
||||
cm: Lrc<SourceMap>,
|
||||
pragma: ExprOrSuper,
|
||||
comments: Option<C>,
|
||||
pragma_frag: ExprOrSpread,
|
||||
use_builtins: bool,
|
||||
throw_if_namespace: bool,
|
||||
}
|
||||
|
||||
impl Jsx {
|
||||
impl<C> Jsx<C>
|
||||
where
|
||||
C: Comments,
|
||||
{
|
||||
fn jsx_frag_to_expr(&mut self, el: JSXFragment) -> Expr {
|
||||
let span = el.span();
|
||||
|
||||
@ -252,9 +270,59 @@ impl Jsx {
|
||||
}
|
||||
}
|
||||
|
||||
impl Fold for Jsx {
|
||||
impl<C> Fold for Jsx<C>
|
||||
where
|
||||
C: Comments,
|
||||
{
|
||||
noop_fold_type!();
|
||||
|
||||
fn fold_module(&mut self, module: Module) -> Module {
|
||||
let leading = if let Some(comments) = &self.comments {
|
||||
let leading = comments.take_leading(module.span.lo);
|
||||
|
||||
if let Some(leading) = &leading {
|
||||
for leading in &**leading {
|
||||
if leading.kind != CommentKind::Block {
|
||||
continue;
|
||||
}
|
||||
|
||||
for line in leading.text.lines() {
|
||||
if !line.trim().starts_with("* @jsx") {
|
||||
continue;
|
||||
}
|
||||
|
||||
if line.trim().starts_with("* @jsxFrag") {
|
||||
let src = line.replace("* @jsxFrag", "").trim().to_string();
|
||||
self.pragma_frag = ExprOrSpread {
|
||||
expr: parse_option(&self.cm, "module-jsx-pragma-frag", src),
|
||||
spread: None,
|
||||
};
|
||||
} else {
|
||||
let src = line.replace("* @jsx", "").trim().to_string();
|
||||
|
||||
self.pragma =
|
||||
ExprOrSuper::Expr(parse_option(&self.cm, "module-jsx-pragma", src));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
leading
|
||||
} else {
|
||||
None
|
||||
};
|
||||
|
||||
let module = module.fold_children_with(self);
|
||||
|
||||
if let Some(leading) = leading {
|
||||
if let Some(comments) = &self.comments {
|
||||
comments.add_leading_comments(module.span.lo, leading);
|
||||
}
|
||||
}
|
||||
|
||||
module
|
||||
}
|
||||
|
||||
fn fold_expr(&mut self, expr: Expr) -> Expr {
|
||||
let mut expr = expr.fold_children_with(self);
|
||||
|
||||
@ -290,7 +358,10 @@ impl Fold for Jsx {
|
||||
}
|
||||
}
|
||||
|
||||
impl Jsx {
|
||||
impl<C> Jsx<C>
|
||||
where
|
||||
C: Comments,
|
||||
{
|
||||
fn jsx_name(&self, name: JSXElementName) -> Box<Expr> {
|
||||
let span = name.span();
|
||||
match name {
|
||||
|
@ -12,7 +12,7 @@ use swc_common::{chain, Mark};
|
||||
|
||||
fn tr(t: &mut Tester, options: Options) -> impl Fold {
|
||||
chain!(
|
||||
jsx(t.cm.clone(), options),
|
||||
jsx(t.cm.clone(), Some(t.comments.clone()), options),
|
||||
display_name(),
|
||||
classes(),
|
||||
arrow(),
|
||||
@ -288,7 +288,6 @@ test!(
|
||||
);
|
||||
|
||||
test!(
|
||||
ignore,
|
||||
::swc_ecma_parser::Syntax::Es(::swc_ecma_parser::EsConfig {
|
||||
jsx: true,
|
||||
..Default::default()
|
||||
@ -313,7 +312,6 @@ var profile = dom("div", null, dom("img", {
|
||||
);
|
||||
|
||||
test!(
|
||||
ignore,
|
||||
::swc_ecma_parser::Syntax::Es(::swc_ecma_parser::EsConfig {
|
||||
jsx: true,
|
||||
..Default::default()
|
||||
@ -564,7 +562,6 @@ React.createElement("div", null, React.createElement(
|
||||
);
|
||||
|
||||
test!(
|
||||
ignore,
|
||||
::swc_ecma_parser::Syntax::Es(::swc_ecma_parser::EsConfig {
|
||||
jsx: true,
|
||||
..Default::default()
|
||||
@ -583,7 +580,6 @@ dom("div", null, "no fragment is used");
|
||||
);
|
||||
|
||||
test!(
|
||||
ignore,
|
||||
::swc_ecma_parser::Syntax::Es(::swc_ecma_parser::EsConfig {
|
||||
jsx: true,
|
||||
..Default::default()
|
||||
@ -915,7 +911,6 @@ test!(
|
||||
|
||||
test!(
|
||||
// Comments are currently stripped out
|
||||
ignore,
|
||||
::swc_ecma_parser::Syntax::Es(::swc_ecma_parser::EsConfig {
|
||||
jsx: true,
|
||||
..Default::default()
|
||||
|
@ -20,7 +20,7 @@ use tempfile::tempdir_in;
|
||||
pub(crate) struct Tester<'a> {
|
||||
pub cm: Lrc<SourceMap>,
|
||||
pub handler: &'a Handler,
|
||||
pub comments: SingleThreadedComments,
|
||||
pub comments: Lrc<SingleThreadedComments>,
|
||||
}
|
||||
|
||||
impl<'a> Tester<'a> {
|
||||
@ -101,7 +101,7 @@ impl<'a> Tester<'a> {
|
||||
.new_source_file(FileName::Real(name.into()), src.into());
|
||||
|
||||
let module = {
|
||||
let mut p = Parser::new(syntax, StringInput::from(&*fm), None);
|
||||
let mut p = Parser::new(syntax, StringInput::from(&*fm), Some(&self.comments));
|
||||
let res = p
|
||||
.parse_module()
|
||||
.map_err(|e| e.into_diagnostic(&self.handler).emit());
|
||||
@ -174,7 +174,7 @@ pub(crate) fn test_transform<F, P>(
|
||||
expected: &str,
|
||||
ok_if_code_eq: bool,
|
||||
) where
|
||||
F: FnOnce(&mut Tester<'_>) -> P,
|
||||
F: FnOnce(&mut Tester) -> P,
|
||||
P: Fold,
|
||||
{
|
||||
crate::tests::Tester::run(|tester| {
|
||||
|
@ -49,7 +49,7 @@ macro_rules! validate {
|
||||
pub struct Tester<'a> {
|
||||
pub cm: Lrc<SourceMap>,
|
||||
pub handler: &'a Handler,
|
||||
pub comments: SingleThreadedComments,
|
||||
pub comments: Lrc<SingleThreadedComments>,
|
||||
}
|
||||
|
||||
impl<'a> Tester<'a> {
|
||||
|
@ -2195,7 +2195,10 @@ test!(
|
||||
jsx: true,
|
||||
..Default::default()
|
||||
}),
|
||||
|t| chain!(tr(), jsx(t.cm.clone(), Default::default())),
|
||||
|t| chain!(
|
||||
tr(),
|
||||
jsx(t.cm.clone(), Some(t.comments.clone()), Default::default())
|
||||
),
|
||||
regression_2775,
|
||||
r#"
|
||||
import React, {Component} from 'react';
|
||||
|
@ -223,7 +223,10 @@ impl Options {
|
||||
|
||||
let pass = chain!(
|
||||
// handle jsx
|
||||
Optional::new(react::react(cm.clone(), transform.react), syntax.jsx()),
|
||||
Optional::new(
|
||||
react::react(cm.clone(), comments, transform.react),
|
||||
syntax.jsx()
|
||||
),
|
||||
// Decorators may use type information
|
||||
Optional::new(
|
||||
decorators(decorators::Config {
|
||||
|
Loading…
Reference in New Issue
Block a user