Skip to content

Commit 98dd505

Browse files
committed
refactor(parser): improve parsing of TypeScript types
1 parent 2e026e1 commit 98dd505

File tree

23 files changed

+886
-568
lines changed

23 files changed

+886
-568
lines changed

Cargo.toml

+1-1
Original file line numberDiff line numberDiff line change
@@ -185,7 +185,7 @@ criterion2 = { version = "0.11.0", default-features = false }
185185
daachorse = { version = "1.0.0" }
186186

187187
[workspace.metadata.cargo-shear]
188-
ignored = ["napi", "oxc_traverse", "oxc_ast_codegen", "prettyplease"]
188+
ignored = ["napi", "oxc_ast_codegen", "oxc_traverse", "prettyplease"]
189189

190190
[profile.dev]
191191
# Disabling debug info speeds up local and CI builds,

crates/oxc_ast/src/ast/macros.rs

+4-1
Original file line numberDiff line numberDiff line change
@@ -621,7 +621,9 @@ macro_rules! inherit_variants {
621621
/// Inherited from [`TSType`]
622622
JSDocNullableType(Box<'a, JSDocNullableType<'a>>) = 34,
623623
/// Inherited from [`TSType`]
624-
JSDocUnknownType(Box<'a, JSDocUnknownType>) = 35,
624+
JSDocNonNullableType(Box<'a, JSDocNonNullableType<'a>>) = 35,
625+
/// Inherited from [`TSType`]
626+
JSDocUnknownType(Box<'a, JSDocUnknownType>) = 36,
625627

626628
$($rest)*
627629
}
@@ -671,6 +673,7 @@ macro_rules! inherit_variants {
671673
TSTypeReference,
672674
TSUnionType,
673675
JSDocNullableType,
676+
JSDocNonNullableType,
674677
JSDocUnknownType,
675678
]
676679
);

crates/oxc_ast/src/ast/ts.rs

+18-3
Original file line numberDiff line numberDiff line change
@@ -173,7 +173,8 @@ pub enum TSType<'a> {
173173
TSUnionType(Box<'a, TSUnionType<'a>>) = 33,
174174
// JSDoc
175175
JSDocNullableType(Box<'a, JSDocNullableType<'a>>) = 34,
176-
JSDocUnknownType(Box<'a, JSDocUnknownType>) = 35,
176+
JSDocNonNullableType(Box<'a, JSDocNonNullableType<'a>>) = 35,
177+
JSDocUnknownType(Box<'a, JSDocUnknownType>) = 36,
177178
}
178179

179180
/// Macro for matching `TSType`'s variants.
@@ -215,6 +216,7 @@ macro_rules! match_ts_type {
215216
| $ty::TSTypeReference(_)
216217
| $ty::TSUnionType(_)
217218
| $ty::JSDocNullableType(_)
219+
| $ty::JSDocNonNullableType(_)
218220
| $ty::JSDocUnknownType(_)
219221
};
220222
}
@@ -332,7 +334,7 @@ pub struct TSTupleType<'a> {
332334
pub struct TSNamedTupleMember<'a> {
333335
#[cfg_attr(feature = "serialize", serde(flatten))]
334336
pub span: Span,
335-
pub element_type: TSType<'a>,
337+
pub element_type: TSTupleElement<'a>,
336338
pub label: IdentifierName<'a>,
337339
pub optional: bool,
338340
}
@@ -906,7 +908,8 @@ pub enum TSTypeQueryExprName<'a> {
906908
pub struct TSImportType<'a> {
907909
#[cfg_attr(feature = "serialize", serde(flatten))]
908910
pub span: Span,
909-
pub argument: TSType<'a>,
911+
pub is_type_of: bool, // `typeof import("foo")`
912+
pub parameter: TSType<'a>,
910913
pub qualifier: Option<TSTypeName<'a>>,
911914
pub attributes: Option<TSImportAttributes<'a>>,
912915
pub type_parameters: Option<Box<'a, TSTypeParameterInstantiation<'a>>>,
@@ -1157,6 +1160,18 @@ pub struct JSDocNullableType<'a> {
11571160
pub postfix: bool,
11581161
}
11591162

1163+
/// `type foo = ty!` or `type foo = !ty`
1164+
#[visited_node]
1165+
#[derive(Debug, Hash)]
1166+
#[cfg_attr(feature = "serialize", derive(Serialize, Tsify))]
1167+
#[cfg_attr(feature = "serialize", serde(tag = "type", rename_all = "camelCase"))]
1168+
pub struct JSDocNonNullableType<'a> {
1169+
#[cfg_attr(feature = "serialize", serde(flatten))]
1170+
pub span: Span,
1171+
pub type_annotation: TSType<'a>,
1172+
pub postfix: bool,
1173+
}
1174+
11601175
#[visited_node]
11611176
#[derive(Debug, Hash)]
11621177
#[cfg_attr(feature = "serialize", derive(Serialize, Tsify))]

crates/oxc_ast/src/ast_builder.rs

+19-3
Original file line numberDiff line numberDiff line change
@@ -1914,7 +1914,7 @@ impl<'a> AstBuilder<'a> {
19141914
}
19151915

19161916
#[inline]
1917-
pub fn ts_this_keyword(self, span: Span) -> TSType<'a> {
1917+
pub fn ts_this_type(self, span: Span) -> TSType<'a> {
19181918
TSType::TSThisType(self.alloc(TSThisType { span }))
19191919
}
19201920

@@ -2040,14 +2040,16 @@ impl<'a> AstBuilder<'a> {
20402040
pub fn ts_import_type(
20412041
self,
20422042
span: Span,
2043-
argument: TSType<'a>,
2043+
is_type_of: bool,
2044+
parameter: TSType<'a>,
20442045
qualifier: Option<TSTypeName<'a>>,
20452046
attributes: Option<TSImportAttributes<'a>>,
20462047
type_parameters: Option<Box<'a, TSTypeParameterInstantiation<'a>>>,
20472048
) -> TSType<'a> {
20482049
TSType::TSImportType(self.alloc(TSImportType {
20492050
span,
2050-
argument,
2051+
is_type_of,
2052+
parameter,
20512053
qualifier,
20522054
attributes,
20532055
type_parameters,
@@ -2194,6 +2196,20 @@ impl<'a> AstBuilder<'a> {
21942196
TSType::JSDocNullableType(self.alloc(JSDocNullableType { span, type_annotation, postfix }))
21952197
}
21962198

2199+
#[inline]
2200+
pub fn js_doc_non_nullable_type(
2201+
self,
2202+
span: Span,
2203+
type_annotation: TSType<'a>,
2204+
postfix: bool,
2205+
) -> TSType<'a> {
2206+
TSType::JSDocNonNullableType(self.alloc(JSDocNonNullableType {
2207+
span,
2208+
type_annotation,
2209+
postfix,
2210+
}))
2211+
}
2212+
21972213
#[inline]
21982214
pub fn js_doc_unknown_type(self, span: Span) -> TSType<'a> {
21992215
TSType::JSDocUnknownType(self.alloc(JSDocUnknownType { span }))

crates/oxc_ast/src/generated/span.rs

+9
Original file line numberDiff line numberDiff line change
@@ -1385,6 +1385,7 @@ impl<'a> GetSpan for TSType<'a> {
13851385
Self::TSTypeReference(it) => it.span(),
13861386
Self::TSUnionType(it) => it.span(),
13871387
Self::JSDocNullableType(it) => it.span(),
1388+
Self::JSDocNonNullableType(it) => it.span(),
13881389
Self::JSDocUnknownType(it) => it.span(),
13891390
}
13901391
}
@@ -1500,6 +1501,7 @@ impl<'a> GetSpan for TSTupleElement<'a> {
15001501
Self::TSTypeReference(it) => it.span(),
15011502
Self::TSUnionType(it) => it.span(),
15021503
Self::JSDocNullableType(it) => it.span(),
1504+
Self::JSDocNonNullableType(it) => it.span(),
15031505
Self::JSDocUnknownType(it) => it.span(),
15041506
}
15051507
}
@@ -1960,6 +1962,13 @@ impl<'a> GetSpan for JSDocNullableType<'a> {
19601962
}
19611963
}
19621964

1965+
impl<'a> GetSpan for JSDocNonNullableType<'a> {
1966+
#[inline]
1967+
fn span(&self) -> Span {
1968+
self.span
1969+
}
1970+
}
1971+
19631972
impl GetSpan for JSDocUnknownType {
19641973
#[inline]
19651974
fn span(&self) -> Span {

crates/oxc_ast/src/visit/visit.rs

+5-3
Original file line numberDiff line numberDiff line change
@@ -2816,7 +2816,9 @@ pub mod walk {
28162816
TSType::TSTypeReference(ty) => visitor.visit_ts_type_reference(ty),
28172817
TSType::TSUnionType(ty) => visitor.visit_ts_union_type(ty),
28182818
// JSDoc
2819-
TSType::JSDocNullableType(_) | TSType::JSDocUnknownType(_) => { /* TODO */ }
2819+
TSType::JSDocNullableType(_)
2820+
| TSType::JSDocNonNullableType(_)
2821+
| TSType::JSDocUnknownType(_) => { /* TODO */ }
28202822
}
28212823
}
28222824

@@ -3124,7 +3126,7 @@ pub mod walk {
31243126
pub fn walk_ts_import_type<'a, V: Visit<'a>>(visitor: &mut V, ty: &TSImportType<'a>) {
31253127
let kind = AstKind::TSImportType(visitor.alloc(ty));
31263128
visitor.enter_node(kind);
3127-
visitor.visit_ts_type(&ty.argument);
3129+
visitor.visit_ts_type(&ty.parameter);
31283130
if let Some(name) = &ty.qualifier {
31293131
visitor.visit_ts_type_name(name);
31303132
}
@@ -3244,7 +3246,7 @@ pub mod walk {
32443246
let kind = AstKind::TSNamedTupleMember(visitor.alloc(ty));
32453247
visitor.enter_node(kind);
32463248
visitor.visit_identifier_name(&ty.label);
3247-
visitor.visit_ts_type(&ty.element_type);
3249+
visitor.visit_ts_tuple_element(&ty.element_type);
32483250
visitor.leave_node(kind);
32493251
}
32503252

crates/oxc_ast/src/visit/visit_mut.rs

+1-1
Original file line numberDiff line numberDiff line change
@@ -3202,7 +3202,7 @@ pub mod walk_mut {
32023202
) {
32033203
let kind = AstType::TSImportType;
32043204
visitor.enter_node(kind);
3205-
visitor.visit_ts_type(&mut ty.argument);
3205+
visitor.visit_ts_type(&mut ty.parameter);
32063206
if let Some(name) = &mut ty.qualifier {
32073207
visitor.visit_ts_type_name(name);
32083208
}

crates/oxc_codegen/src/gen.rs

+17-1
Original file line numberDiff line numberDiff line change
@@ -2697,6 +2697,7 @@ impl<'a, const MINIFY: bool> Gen<MINIFY> for TSType<'a> {
26972697
Self::TSTypeQuery(ty) => ty.gen(p, ctx),
26982698
Self::TSTypeReference(ty) => ty.gen(p, ctx),
26992699
Self::JSDocNullableType(ty) => ty.gen(p, ctx),
2700+
Self::JSDocNonNullableType(ty) => ty.gen(p, ctx),
27002701
Self::JSDocUnknownType(_ty) => p.print_str(b"unknown"),
27012702
}
27022703
}
@@ -2904,6 +2905,18 @@ impl<'a, const MINIFY: bool> Gen<MINIFY> for JSDocNullableType<'a> {
29042905
}
29052906
}
29062907

2908+
impl<'a, const MINIFY: bool> Gen<MINIFY> for JSDocNonNullableType<'a> {
2909+
fn gen(&self, p: &mut Codegen<{ MINIFY }>, ctx: Context) {
2910+
if self.postfix {
2911+
self.type_annotation.gen(p, ctx);
2912+
p.print_str(b"!");
2913+
} else {
2914+
p.print_str(b"!");
2915+
self.type_annotation.gen(p, ctx);
2916+
}
2917+
}
2918+
}
2919+
29072920
impl<'a, const MINIFY: bool> Gen<MINIFY> for TSTemplateLiteralType<'a> {
29082921
fn gen(&self, p: &mut Codegen<{ MINIFY }>, ctx: Context) {
29092922
p.print_str(b"`");
@@ -3145,8 +3158,11 @@ impl<'a, const MINIFY: bool> Gen<MINIFY> for TSTypeQueryExprName<'a> {
31453158

31463159
impl<'a, const MINIFY: bool> Gen<MINIFY> for TSImportType<'a> {
31473160
fn gen(&self, p: &mut Codegen<{ MINIFY }>, ctx: Context) {
3161+
if self.is_type_of {
3162+
p.print_str(b"typeof ");
3163+
}
31483164
p.print_str(b"import(");
3149-
self.argument.gen(p, ctx);
3165+
self.parameter.gen(p, ctx);
31503166
if let Some(attributes) = &self.attributes {
31513167
p.print_str(", ");
31523168
attributes.gen(p, ctx);

crates/oxc_parser/src/js/arrow.rs

+1-1
Original file line numberDiff line numberDiff line change
@@ -258,7 +258,7 @@ impl<'a> ParserImpl<'a> {
258258
self.error(diagnostics::ts_arrow_function_this_parameter(this_param.span));
259259
}
260260

261-
let return_type = self.parse_ts_return_type_annotation()?;
261+
let return_type = self.parse_ts_return_type_annotation(Kind::Arrow, false)?;
262262

263263
self.ctx = self.ctx.and_await(has_await);
264264

crates/oxc_parser/src/js/expression.rs

+4-1
Original file line numberDiff line numberDiff line change
@@ -414,7 +414,10 @@ impl<'a> ParserImpl<'a> {
414414
Ok(TemplateLiteral { span: self.end_span(span), quasis, expressions })
415415
}
416416

417-
fn parse_template_literal_expression(&mut self, tagged: bool) -> Result<Expression<'a>> {
417+
pub(crate) fn parse_template_literal_expression(
418+
&mut self,
419+
tagged: bool,
420+
) -> Result<Expression<'a>> {
418421
self.parse_template_literal(tagged)
419422
.map(|template_literal| self.ast.template_literal_expression(template_literal))
420423
}

crates/oxc_parser/src/js/function.rs

+2-1
Original file line numberDiff line numberDiff line change
@@ -73,7 +73,8 @@ impl<'a> ParserImpl<'a> {
7373
let (this_param, params) =
7474
self.parse_formal_parameters(FormalParameterKind::FormalParameter)?;
7575

76-
let return_type = self.parse_ts_return_type_annotation()?;
76+
let return_type =
77+
self.parse_ts_return_type_annotation(Kind::Colon, /* is_type */ true)?;
7778

7879
let body = if self.at(Kind::LCurly) { Some(self.parse_function_body()?) } else { None };
7980

crates/oxc_parser/src/lexer/kind.rs

+7-3
Original file line numberDiff line numberDiff line change
@@ -76,7 +76,7 @@ pub enum Kind {
7676
Out,
7777
Readonly,
7878
Require,
79-
Number,
79+
Number, // the "number" keyword for TypeScript
8080
Object,
8181
Satisfies,
8282
String, // the "string" keyword for TypeScript
@@ -87,7 +87,7 @@ pub enum Kind {
8787
Using,
8888
Unknown,
8989
Global,
90-
BigInt,
90+
BigInt, // the "bigint" keyword for TypeScript
9191
Override,
9292
// Future keywords (strict mode reserved words)
9393
Implements,
@@ -104,7 +104,7 @@ pub enum Kind {
104104
Amp2,
105105
Amp2Eq,
106106
AmpEq,
107-
Bang,
107+
Bang, // !
108108
Caret,
109109
CaretEq,
110110
Colon,
@@ -367,6 +367,10 @@ impl Kind {
367367
| Export | In | Out | Public | Private | Protected | Readonly | Static | Override)
368368
}
369369

370+
pub fn is_binding_identifier_or_private_identifier_or_pattern(self) -> bool {
371+
matches!(self, LCurly | LBrack | PrivateIdentifier) || self.is_binding_identifier()
372+
}
373+
370374
pub fn match_keyword(s: &str) -> Self {
371375
let len = s.len();
372376
if len <= 1 || len >= 12 || !s.as_bytes()[0].is_ascii_lowercase() {

crates/oxc_parser/src/ts/list.rs

+2-48
Original file line numberDiff line numberDiff line change
@@ -50,54 +50,8 @@ impl<'a> SeparatedList<'a> for TSTupleElementList<'a> {
5050
}
5151

5252
fn parse_element(&mut self, p: &mut ParserImpl<'a>) -> Result<()> {
53-
let span = p.start_span();
54-
if p.is_at_named_tuple_element() {
55-
if p.eat(Kind::Dot3) {
56-
let member_span = p.start_span();
57-
let label = p.parse_identifier_name()?;
58-
p.expect(Kind::Colon)?;
59-
let element_type = p.parse_ts_type()?;
60-
self.elements.push(TSTupleElement::TSRestType(p.ast.alloc(TSRestType {
61-
span: p.end_span(span),
62-
type_annotation: TSType::TSNamedTupleMember(p.ast.alloc(TSNamedTupleMember {
63-
span: p.end_span(member_span),
64-
element_type,
65-
label,
66-
optional: false, // A tuple member cannot be both optional and rest. (TS5085)
67-
})),
68-
})));
69-
return Ok(());
70-
}
71-
72-
let label = p.parse_identifier_name()?;
73-
let optional = p.eat(Kind::Question);
74-
p.expect(Kind::Colon)?;
75-
76-
let element_type = p.parse_ts_type()?;
77-
self.elements.push(TSTupleElement::TSNamedTupleMember(p.ast.alloc(
78-
TSNamedTupleMember { span: p.end_span(span), element_type, label, optional },
79-
)));
80-
81-
return Ok(());
82-
}
83-
84-
if p.eat(Kind::Dot3) {
85-
let type_annotation = p.parse_ts_type()?;
86-
self.elements.push(TSTupleElement::TSRestType(
87-
p.ast.alloc(TSRestType { span: p.end_span(span), type_annotation }),
88-
));
89-
return Ok(());
90-
}
91-
92-
let type_annotation = p.parse_ts_type()?;
93-
if p.eat(Kind::Question) {
94-
self.elements.push(TSTupleElement::TSOptionalType(
95-
p.ast.alloc(TSOptionalType { span: p.end_span(span), type_annotation }),
96-
));
97-
} else {
98-
self.elements.push(TSTupleElement::from(type_annotation));
99-
}
100-
53+
let ty = p.parse_tuple_element_name_or_tuple_element_type()?;
54+
self.elements.push(ty);
10155
Ok(())
10256
}
10357
}

0 commit comments

Comments
 (0)