swc_ecma_transforms:
 - report error if jsx namespace is used (#301)
This commit is contained in:
강동윤 2019-03-01 18:18:57 +09:00 committed by GitHub
parent a2144bbbf5
commit 1a0f1108a1
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
9 changed files with 125 additions and 67 deletions

View File

@ -205,7 +205,15 @@ impl<'a, I: Input> Lexer<'a, I> {
assert!(self.input.cur().unwrap().is_ident_start());
let cur_pos = self.input.cur_pos();
let slice = self.input.uncons_while(|c| c.is_ident_part() || c == '-');
let mut first = true;
let slice = self.input.uncons_while(|c| {
if first {
first = false;
c.is_ident_start()
} else {
c.is_ident_part() || c == '-'
}
});
Ok(Token::JSXName { name: slice.into() })
}

View File

@ -1,6 +1,9 @@
use crate::{
pass::Pass,
util::{drop_span, CM, SESSION},
util::{
drop_span,
options::{CM, SESSION},
},
};
use ast::*;
use chashmap::CHashMap;

View File

@ -1,4 +1,7 @@
use crate::util::{prepend_stmts, DropSpan, CM, SESSION};
use crate::util::{
options::{CM, SESSION},
prepend_stmts, DropSpan,
};
use ast::*;
use scoped_tls::scoped_thread_local;
use std::sync::atomic::{AtomicBool, Ordering};

View File

@ -1,6 +1,10 @@
use crate::{
pass::Pass,
util::{drop_span, ExprFactory, CM, SESSION},
util::{
drop_span,
options::{CM, SESSION},
ExprFactory, HANDLER,
},
};
use ast::*;
use chashmap::CHashMap;
@ -100,6 +104,7 @@ pub fn jsx(options: Options) -> impl Pass {
expr: parse_option("pragmaFrag", options.pragma_frag),
},
use_builtins: options.use_builtins,
throw_if_namespace: options.throw_if_namespace,
}
}
@ -107,6 +112,7 @@ struct Jsx {
pragma: ExprOrSuper,
pragma_frag: ExprOrSpread,
use_builtins: bool,
throw_if_namespace: bool,
}
impl Jsx {
@ -133,7 +139,7 @@ impl Jsx {
fn jsx_elem_to_expr(&mut self, el: JSXElement) -> Expr {
let span = el.span();
let name = jsx_name(el.opening.name);
let name = self.jsx_name(el.opening.name);
Expr::Call(CallExpr {
span,
@ -278,60 +284,75 @@ impl Fold<Expr> for Jsx {
}
}
fn jsx_name(name: JSXElementName) -> Box<Expr> {
let span = name.span();
match name {
JSXElementName::Ident(i) => {
// If it starts with lowercase digit
let c = i.sym.chars().next().unwrap();
impl Jsx {
fn jsx_name(&self, name: JSXElementName) -> Box<Expr> {
let span = name.span();
match name {
JSXElementName::Ident(i) => {
// If it starts with lowercase digit
let c = i.sym.chars().next().unwrap();
if i.sym == js_word!("this") {
return box Expr::This(ThisExpr { span });
}
if i.sym == js_word!("this") {
return box Expr::This(ThisExpr { span });
}
if c.is_ascii_lowercase() {
box Expr::Lit(Lit::Str(Str {
span,
value: i.sym,
has_escape: false,
}))
} else {
box Expr::Ident(i)
}
}
JSXElementName::JSXNamespacedName(JSXNamespacedName { ref ns, ref name }) => {
box Expr::Lit(Lit::Str(Str {
span,
value: format!("{}:{}", ns.sym, name.sym).into(),
has_escape: false,
}))
}
JSXElementName::JSXMemberExpr(JSXMemberExpr { obj, prop }) => {
fn convert_obj(obj: JSXObject) -> ExprOrSuper {
let span = obj.span();
match obj {
JSXObject::Ident(i) => {
if i.sym == js_word!("this") {
return ExprOrSuper::Expr(box Expr::This(ThisExpr { span }));
}
i.as_obj()
}
JSXObject::JSXMemberExpr(box JSXMemberExpr { obj, prop }) => MemberExpr {
if c.is_ascii_lowercase() {
box Expr::Lit(Lit::Str(Str {
span,
obj: convert_obj(obj),
prop: box Expr::Ident(prop),
computed: false,
}
.as_obj(),
value: i.sym,
has_escape: false,
}))
} else {
box Expr::Ident(i)
}
}
box Expr::Member(MemberExpr {
span,
obj: convert_obj(obj),
prop: box Expr::Ident(prop),
computed: false,
})
JSXElementName::JSXNamespacedName(JSXNamespacedName { ref ns, ref name }) => {
if self.throw_if_namespace {
HANDLER.with(|handler| {
handler
.struct_span_err(
span,
"JSX Namespace is disabled by default because react does not \
support it yet. You can specify \
jsc.transform.react.throwIfNamespace to false to override \
default behavior",
)
.emit()
});
}
box Expr::Lit(Lit::Str(Str {
span,
value: format!("{}:{}", ns.sym, name.sym).into(),
has_escape: false,
}))
}
JSXElementName::JSXMemberExpr(JSXMemberExpr { obj, prop }) => {
fn convert_obj(obj: JSXObject) -> ExprOrSuper {
let span = obj.span();
match obj {
JSXObject::Ident(i) => {
if i.sym == js_word!("this") {
return ExprOrSuper::Expr(box Expr::This(ThisExpr { span }));
}
i.as_obj()
}
JSXObject::JSXMemberExpr(box JSXMemberExpr { obj, prop }) => MemberExpr {
span,
obj: convert_obj(obj),
prop: box Expr::Ident(prop),
computed: false,
}
.as_obj(),
}
}
box Expr::Member(MemberExpr {
span,
obj: convert_obj(obj),
prop: box Expr::Ident(prop),
computed: false,
})
}
}
}
}

View File

@ -645,7 +645,7 @@ React.createElement("div", {
id: "w\xF4w"
});
React.createElement("div", {
id: "\\w"
id: "w"
});
React.createElement("div", {
id: "w < w"

View File

@ -29,7 +29,9 @@ impl<'a> Tester<'a> {
F: FnOnce(&mut Tester) -> Result<(), ()>,
{
let out = ::testing::run_test(false, |cm, handler| {
HELPERS.set(&Default::default(), || op(&mut Tester { cm, handler }))
crate::util::HANDLER.set(handler, || {
HELPERS.set(&Default::default(), || op(&mut Tester { cm, handler }))
})
});
match out {

View File

@ -10,23 +10,22 @@ pub use self::{
Purity::{MayBeImpure, Pure},
};
use ast::*;
use scoped_tls::scoped_thread_local;
use std::{
borrow::Cow,
f64::{INFINITY, NAN},
num::FpCategory,
ops::Add,
sync::Arc,
};
use swc_atoms::JsWord;
use swc_common::{
errors::{ColorConfig, Handler},
FilePathMapping, Fold, FoldWith, Mark, SourceMap, Span, Spanned, Visit, VisitWith, DUMMY_SP,
errors::Handler, Fold, FoldWith, Mark, Span, Spanned, Visit, VisitWith, DUMMY_SP,
};
use swc_ecma_parser::Session;
use unicode_xid::UnicodeXID;
pub(crate) mod constructor;
mod factory;
pub(crate) mod options;
mod value;
pub(crate) mod var;
@ -1015,10 +1014,4 @@ impl<'a> UsageFinder<'a> {
}
}
lazy_static! {
pub(crate) static ref CM: Arc<SourceMap> =
{ Arc::new(SourceMap::new(FilePathMapping::empty())) };
pub(crate) static ref HANDLER: Handler =
{ Handler::with_tty_emitter(ColorConfig::Always, false, true, Some(CM.clone())) };
pub(crate) static ref SESSION: Session<'static> = { Session { handler: &*HANDLER } };
}
scoped_thread_local!(pub static HANDLER: Handler);

View File

@ -0,0 +1,14 @@
use std::sync::Arc;
use swc_common::{
errors::{ColorConfig, Handler},
FilePathMapping, SourceMap,
};
use swc_ecma_parser::Session;
lazy_static! {
pub(crate) static ref CM: Arc<SourceMap> =
{ Arc::new(SourceMap::new(FilePathMapping::empty())) };
pub(crate) static ref HANDLER: Handler =
{ Handler::with_tty_emitter(ColorConfig::Always, false, true, Some(CM.clone())) };
pub(crate) static ref SESSION: Session<'static> = { Session { handler: &*HANDLER } };
}

View File

@ -42,6 +42,20 @@ where
}
}
pub fn run_test2<F, Ret>(treat_err_as_bug: bool, op: F) -> Result<Ret, StdErr>
where
F: FnOnce(Arc<SourceMap>, Handler) -> Result<Ret, ()>,
{
let cm = Arc::new(SourceMap::new(FilePathMapping::empty()));
let (handler, errors) = self::errors::new_handler(cm.clone(), treat_err_as_bug);
let result = swc_common::GLOBALS.set(&swc_common::Globals::new(), || op(cm, handler));
match result {
Ok(res) => Ok(res),
Err(()) => Err(errors.into()),
}
}
/// Remove all span from `t`.
pub fn drop_span<T>(t: T) -> T
where