fix(es/parser): Parse types in CallExpression inside templates (#6611)

**Related issue:**

 - Closes https://github.com/swc-project/swc/issues/6601.
This commit is contained in:
Alexander Akait 2022-12-10 03:05:25 +03:00 committed by GitHub
parent 66b52824e5
commit c44f1d0a7f
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
6 changed files with 4308 additions and 17 deletions

View File

@ -369,9 +369,6 @@ pub struct Context {
in_forced_jsx_context: bool, in_forced_jsx_context: bool,
/// If true, `:` should not be treated as a type annotation.
dont_parse_colon_as_type_ann: bool,
// If true, allow super.x and super[x] // If true, allow super.x and super[x]
allow_direct_super: bool, allow_direct_super: bool,

View File

@ -218,7 +218,6 @@ impl<I: Tokens> Parser<I> {
let ctx = Context { let ctx = Context {
in_cond_expr: true, in_cond_expr: true,
will_expect_colon_for_cond: false, will_expect_colon_for_cond: false,
dont_parse_colon_as_type_ann: false,
..self.ctx() ..self.ctx()
}; };
let alt = self.with_ctx(ctx).parse_assignment_expr()?; let alt = self.with_ctx(ctx).parse_assignment_expr()?;
@ -306,7 +305,6 @@ impl<I: Tokens> Parser<I> {
tok!('[') => { tok!('[') => {
let ctx = Context { let ctx = Context {
will_expect_colon_for_cond: false, will_expect_colon_for_cond: false,
dont_parse_colon_as_type_ann: false,
..self.ctx() ..self.ctx()
}; };
return self.with_ctx(ctx).parse_array_lit(); return self.with_ctx(ctx).parse_array_lit();
@ -378,8 +376,13 @@ impl<I: Tokens> Parser<I> {
} }
tok!('`') => { tok!('`') => {
let ctx = Context {
will_expect_colon_for_cond: false,
..self.ctx()
};
// parse template literal // parse template literal
return Ok(Box::new(Expr::Tpl(self.parse_tpl(false)?))); return Ok(Box::new(Expr::Tpl(self.with_ctx(ctx).parse_tpl(false)?)));
} }
tok!('(') => { tok!('(') => {
@ -841,7 +844,6 @@ impl<I: Tokens> Parser<I> {
let return_type = if !self.ctx().will_expect_colon_for_cond let return_type = if !self.ctx().will_expect_colon_for_cond
&& self.input.syntax().typescript() && self.input.syntax().typescript()
&& is!(self, ':') && is!(self, ':')
&& !self.ctx().dont_parse_colon_as_type_ann
{ {
self.try_parse_ts(|p| { self.try_parse_ts(|p| {
let return_type = p.parse_ts_type_or_type_predicate_ann(&tok!(':'))?; let return_type = p.parse_ts_type_or_type_predicate_ann(&tok!(':'))?;
@ -1470,7 +1472,12 @@ impl<I: Tokens> Parser<I> {
// MemberExpression[?Yield, ?Await] TemplateLiteral[?Yield, ?Await, +Tagged] // MemberExpression[?Yield, ?Await] TemplateLiteral[?Yield, ?Await, +Tagged]
if is!(self, '`') { if is!(self, '`') {
let tpl = self.parse_tagged_tpl(expr, None)?; let ctx = Context {
will_expect_colon_for_cond: false,
..self.ctx()
};
let tpl = self.with_ctx(ctx).parse_tagged_tpl(expr, None)?;
return Ok((Box::new(Expr::TaggedTpl(tpl)), true)); return Ok((Box::new(Expr::TaggedTpl(tpl)), true));
} }

View File

@ -14,7 +14,6 @@ impl<I: Tokens> Parser<I> {
{ {
let ctx = Context { let ctx = Context {
will_expect_colon_for_cond: false, will_expect_colon_for_cond: false,
dont_parse_colon_as_type_ann: false,
..self.ctx() ..self.ctx()
}; };
self.with_ctx(ctx).parse_with(|p| { self.with_ctx(ctx).parse_with(|p| {

View File

@ -610,15 +610,8 @@ impl<'a, I: Tokens> Parser<I> {
let is_case = is!(p, "case"); let is_case = is!(p, "case");
let case_start = cur_pos!(p); let case_start = cur_pos!(p);
bump!(p); bump!(p);
let ctx = Context {
dont_parse_colon_as_type_ann: true,
..p.ctx()
};
let test = if is_case { let test = if is_case {
p.with_ctx(ctx) p.include_in_expr(true).parse_expr().map(Some)?
.include_in_expr(true)
.parse_expr()
.map(Some)?
} else { } else {
if let Some(previous) = span_of_previous_default { if let Some(previous) = span_of_previous_default {
syntax_error!(p, SyntaxError::MultipleDefault { previous }); syntax_error!(p, SyntaxError::MultipleDefault { previous });

View File

@ -0,0 +1,104 @@
function exampleFunction1() {
return Math.random() > 0.5
? `<button
@click="${(): void => console.log('this line causes a syntax error')}"
></button>`
: `<button
@click="${(): void => console.log('this line does NOT causes a syntax error')}"
></button>`;
}
function exampleFunction2() {
return Math.random() > 0.5
? `<bar></bar>` + `<button
@click="${(): void => console.log('this line causes a syntax error')}"
></button>`
: `<bar></bar>` + `<button
@click="${(): void => console.log('this line does NOT causes a syntax error')}"
></button>`;
}
function exampleFunction3() {
return Math.random() > 0.5
? (): void => console.log('this line causes a syntax error')
: (): void => console.log('this line does NOT causes a syntax error');
}
function exampleFunction4() {
return Math.random() > 0.5
? function (): void { console.log('this line causes a syntax error') }
: function (): void { console.log('this line does NOT causes a syntax error') };
}
function exampleFunction5() {
return Math.random() > 0.5
? (function (): void { console.log('this line causes a syntax error') })
: (function (): void { console.log('this line does NOT causes a syntax error') });
}
function exampleFunction6() {
return Math.random() > 0.5
? "test" == "test"
? `<button @click="${(): void => console.log('this line causes a syntax error')}"></button>`
: "bar"
: `<button
@click="${(): void => console.log('this line does NOT causes a syntax error')}"
></button>`;
}
function exampleFunction6() {
return Math.random() > 0.5
? `<button @click="${(): void => console.log('this line causes a syntax error')}"></button>`
: "test" == "test"
? `<button @click="${(): void => console.log('this line causes a syntax error')}"></button>`
: "bar";
}
function exampleFunction7() {
return Math.random() > 0.5
? foo`<button @click="${(): void => console.log('this line causes a syntax error')}"></button>`
: bar`<button @click="${(): void => console.log('this line does NOT causes a syntax error')}"></button>`;
}
function exampleFunction8() {
return Math.random() > 0.5
? ((): void => console.log('this line causes a syntax error'))
: ((): void => console.log('this line does NOT causes a syntax error'));
}
function exampleFunction9() {
return Math.random() > 0.5
? async (): Promise<void> => console.log('this line causes a syntax error')
: async (): Promise<void> => console.log('this line causes a syntax error');
}
function exampleFunction10() {
const foo = "Oranges";
switch (foo) {
case 'Oranges': {
return `<button @click="${(): void => console.log('this line causes a syntax error')}" ></button>`;
}
default:
console.log(`Sorry, we are out of test.`);
}
}
function exampleFunction11() {
switch (true) {
case ((): boolean => true)(): {
console.log('This shape is a square.');
break;
}
}
}
function exampleFunction12() {
switch (((): boolean => true)()) {
case ((): boolean => true)(): {
console.log('This shape is a square.');
break;
}
}
}

File diff suppressed because it is too large Load Diff