refactor(parser): improve parsing of TypeScript types (#3903)

- [x] fix everything
This commit is contained in:
Boshen 2024-06-26 05:58:16 +00:00
parent 1061baabbf
commit 4cf3c7645f
22 changed files with 917 additions and 594 deletions

View file

@ -185,7 +185,7 @@ criterion2 = { version = "0.11.0", default-features = false }
daachorse = { version = "1.0.0" }
[workspace.metadata.cargo-shear]
ignored = ["napi", "oxc_traverse", "oxc_ast_codegen", "prettyplease"]
ignored = ["napi", "oxc_ast_codegen", "oxc_traverse", "prettyplease"]
[profile.dev]
# Disabling debug info speeds up local and CI builds,

View file

@ -621,7 +621,9 @@ macro_rules! inherit_variants {
/// Inherited from [`TSType`]
JSDocNullableType(Box<'a, JSDocNullableType<'a>>) = 34,
/// Inherited from [`TSType`]
JSDocUnknownType(Box<'a, JSDocUnknownType>) = 35,
JSDocNonNullableType(Box<'a, JSDocNonNullableType<'a>>) = 35,
/// Inherited from [`TSType`]
JSDocUnknownType(Box<'a, JSDocUnknownType>) = 36,
$($rest)*
}
@ -671,6 +673,7 @@ macro_rules! inherit_variants {
TSTypeReference,
TSUnionType,
JSDocNullableType,
JSDocNonNullableType,
JSDocUnknownType,
]
);

View file

@ -174,7 +174,8 @@ pub enum TSType<'a> {
TSUnionType(Box<'a, TSUnionType<'a>>) = 33,
// JSDoc
JSDocNullableType(Box<'a, JSDocNullableType<'a>>) = 34,
JSDocUnknownType(Box<'a, JSDocUnknownType>) = 35,
JSDocNonNullableType(Box<'a, JSDocNonNullableType<'a>>) = 35,
JSDocUnknownType(Box<'a, JSDocUnknownType>) = 36,
}
/// Macro for matching `TSType`'s variants.
@ -216,6 +217,7 @@ macro_rules! match_ts_type {
| $ty::TSTypeReference(_)
| $ty::TSUnionType(_)
| $ty::JSDocNullableType(_)
| $ty::JSDocNonNullableType(_)
| $ty::JSDocUnknownType(_)
};
}
@ -333,7 +335,7 @@ pub struct TSTupleType<'a> {
pub struct TSNamedTupleMember<'a> {
#[cfg_attr(feature = "serialize", serde(flatten))]
pub span: Span,
pub element_type: TSType<'a>,
pub element_type: TSTupleElement<'a>,
pub label: IdentifierName<'a>,
pub optional: bool,
}
@ -909,7 +911,8 @@ pub enum TSTypeQueryExprName<'a> {
pub struct TSImportType<'a> {
#[cfg_attr(feature = "serialize", serde(flatten))]
pub span: Span,
pub argument: TSType<'a>,
pub is_type_of: bool, // `typeof import("foo")`
pub parameter: TSType<'a>,
pub qualifier: Option<TSTypeName<'a>>,
pub attributes: Option<TSImportAttributes<'a>>,
pub type_parameters: Option<Box<'a, TSTypeParameterInstantiation<'a>>>,
@ -1160,6 +1163,18 @@ pub struct JSDocNullableType<'a> {
pub postfix: bool,
}
/// `type foo = ty!` or `type foo = !ty`
#[visited_node]
#[derive(Debug, Hash)]
#[cfg_attr(feature = "serialize", derive(Serialize, Tsify))]
#[cfg_attr(feature = "serialize", serde(tag = "type", rename_all = "camelCase"))]
pub struct JSDocNonNullableType<'a> {
#[cfg_attr(feature = "serialize", serde(flatten))]
pub span: Span,
pub type_annotation: TSType<'a>,
pub postfix: bool,
}
#[visited_node]
#[derive(Debug, Hash)]
#[cfg_attr(feature = "serialize", derive(Serialize, Tsify))]

View file

@ -1915,7 +1915,7 @@ impl<'a> AstBuilder<'a> {
}
#[inline]
pub fn ts_this_keyword(self, span: Span) -> TSType<'a> {
pub fn ts_this_type(self, span: Span) -> TSType<'a> {
TSType::TSThisType(self.alloc(TSThisType { span }))
}
@ -2041,14 +2041,16 @@ impl<'a> AstBuilder<'a> {
pub fn ts_import_type(
self,
span: Span,
argument: TSType<'a>,
is_type_of: bool,
parameter: TSType<'a>,
qualifier: Option<TSTypeName<'a>>,
attributes: Option<TSImportAttributes<'a>>,
type_parameters: Option<Box<'a, TSTypeParameterInstantiation<'a>>>,
) -> TSType<'a> {
TSType::TSImportType(self.alloc(TSImportType {
span,
argument,
is_type_of,
parameter,
qualifier,
attributes,
type_parameters,
@ -2195,6 +2197,20 @@ impl<'a> AstBuilder<'a> {
TSType::JSDocNullableType(self.alloc(JSDocNullableType { span, type_annotation, postfix }))
}
#[inline]
pub fn js_doc_non_nullable_type(
self,
span: Span,
type_annotation: TSType<'a>,
postfix: bool,
) -> TSType<'a> {
TSType::JSDocNonNullableType(self.alloc(JSDocNonNullableType {
span,
type_annotation,
postfix,
}))
}
#[inline]
pub fn js_doc_unknown_type(self, span: Span) -> TSType<'a> {
TSType::JSDocUnknownType(self.alloc(JSDocUnknownType { span }))

View file

@ -1385,6 +1385,7 @@ impl<'a> GetSpan for TSType<'a> {
Self::TSTypeReference(it) => it.span(),
Self::TSUnionType(it) => it.span(),
Self::JSDocNullableType(it) => it.span(),
Self::JSDocNonNullableType(it) => it.span(),
Self::JSDocUnknownType(it) => it.span(),
}
}
@ -1500,6 +1501,7 @@ impl<'a> GetSpan for TSTupleElement<'a> {
Self::TSTypeReference(it) => it.span(),
Self::TSUnionType(it) => it.span(),
Self::JSDocNullableType(it) => it.span(),
Self::JSDocNonNullableType(it) => it.span(),
Self::JSDocUnknownType(it) => it.span(),
}
}
@ -1960,6 +1962,13 @@ impl<'a> GetSpan for JSDocNullableType<'a> {
}
}
impl<'a> GetSpan for JSDocNonNullableType<'a> {
#[inline]
fn span(&self) -> Span {
self.span
}
}
impl GetSpan for JSDocUnknownType {
#[inline]
fn span(&self) -> Span {

View file

@ -2816,7 +2816,9 @@ pub mod walk {
TSType::TSTypeReference(ty) => visitor.visit_ts_type_reference(ty),
TSType::TSUnionType(ty) => visitor.visit_ts_union_type(ty),
// JSDoc
TSType::JSDocNullableType(_) | TSType::JSDocUnknownType(_) => { /* TODO */ }
TSType::JSDocNullableType(_)
| TSType::JSDocNonNullableType(_)
| TSType::JSDocUnknownType(_) => { /* TODO */ }
}
}
@ -3124,7 +3126,7 @@ pub mod walk {
pub fn walk_ts_import_type<'a, V: Visit<'a>>(visitor: &mut V, ty: &TSImportType<'a>) {
let kind = AstKind::TSImportType(visitor.alloc(ty));
visitor.enter_node(kind);
visitor.visit_ts_type(&ty.argument);
visitor.visit_ts_type(&ty.parameter);
if let Some(name) = &ty.qualifier {
visitor.visit_ts_type_name(name);
}
@ -3244,7 +3246,7 @@ pub mod walk {
let kind = AstKind::TSNamedTupleMember(visitor.alloc(ty));
visitor.enter_node(kind);
visitor.visit_identifier_name(&ty.label);
visitor.visit_ts_type(&ty.element_type);
visitor.visit_ts_tuple_element(&ty.element_type);
visitor.leave_node(kind);
}

View file

@ -3202,7 +3202,7 @@ pub mod walk_mut {
) {
let kind = AstType::TSImportType;
visitor.enter_node(kind);
visitor.visit_ts_type(&mut ty.argument);
visitor.visit_ts_type(&mut ty.parameter);
if let Some(name) = &mut ty.qualifier {
visitor.visit_ts_type_name(name);
}

View file

@ -2697,6 +2697,7 @@ impl<'a, const MINIFY: bool> Gen<MINIFY> for TSType<'a> {
Self::TSTypeQuery(ty) => ty.gen(p, ctx),
Self::TSTypeReference(ty) => ty.gen(p, ctx),
Self::JSDocNullableType(ty) => ty.gen(p, ctx),
Self::JSDocNonNullableType(ty) => ty.gen(p, ctx),
Self::JSDocUnknownType(_ty) => p.print_str(b"unknown"),
}
}
@ -2904,6 +2905,18 @@ impl<'a, const MINIFY: bool> Gen<MINIFY> for JSDocNullableType<'a> {
}
}
impl<'a, const MINIFY: bool> Gen<MINIFY> for JSDocNonNullableType<'a> {
fn gen(&self, p: &mut Codegen<{ MINIFY }>, ctx: Context) {
if self.postfix {
self.type_annotation.gen(p, ctx);
p.print_str(b"!");
} else {
p.print_str(b"!");
self.type_annotation.gen(p, ctx);
}
}
}
impl<'a, const MINIFY: bool> Gen<MINIFY> for TSTemplateLiteralType<'a> {
fn gen(&self, p: &mut Codegen<{ MINIFY }>, ctx: Context) {
p.print_str(b"`");
@ -3145,8 +3158,11 @@ impl<'a, const MINIFY: bool> Gen<MINIFY> for TSTypeQueryExprName<'a> {
impl<'a, const MINIFY: bool> Gen<MINIFY> for TSImportType<'a> {
fn gen(&self, p: &mut Codegen<{ MINIFY }>, ctx: Context) {
if self.is_type_of {
p.print_str(b"typeof ");
}
p.print_str(b"import(");
self.argument.gen(p, ctx);
self.parameter.gen(p, ctx);
if let Some(attributes) = &self.attributes {
p.print_str(", ");
attributes.gen(p, ctx);

View file

@ -258,7 +258,7 @@ impl<'a> ParserImpl<'a> {
self.error(diagnostics::ts_arrow_function_this_parameter(this_param.span));
}
let return_type = self.parse_ts_return_type_annotation()?;
let return_type = self.parse_ts_return_type_annotation(Kind::Arrow, false)?;
self.ctx = self.ctx.and_await(has_await);

View file

@ -414,7 +414,10 @@ impl<'a> ParserImpl<'a> {
Ok(TemplateLiteral { span: self.end_span(span), quasis, expressions })
}
fn parse_template_literal_expression(&mut self, tagged: bool) -> Result<Expression<'a>> {
pub(crate) fn parse_template_literal_expression(
&mut self,
tagged: bool,
) -> Result<Expression<'a>> {
self.parse_template_literal(tagged)
.map(|template_literal| self.ast.template_literal_expression(template_literal))
}

View file

@ -73,7 +73,8 @@ impl<'a> ParserImpl<'a> {
let (this_param, params) =
self.parse_formal_parameters(FormalParameterKind::FormalParameter)?;
let return_type = self.parse_ts_return_type_annotation()?;
let return_type =
self.parse_ts_return_type_annotation(Kind::Colon, /* is_type */ true)?;
let body = if self.at(Kind::LCurly) { Some(self.parse_function_body()?) } else { None };

View file

@ -76,7 +76,7 @@ pub enum Kind {
Out,
Readonly,
Require,
Number,
Number, // the "number" keyword for TypeScript
Object,
Satisfies,
String, // the "string" keyword for TypeScript
@ -87,7 +87,7 @@ pub enum Kind {
Using,
Unknown,
Global,
BigInt,
BigInt, // the "bigint" keyword for TypeScript
Override,
// Future keywords (strict mode reserved words)
Implements,
@ -104,7 +104,7 @@ pub enum Kind {
Amp2,
Amp2Eq,
AmpEq,
Bang,
Bang, // !
Caret,
CaretEq,
Colon,
@ -367,6 +367,10 @@ impl Kind {
| Export | In | Out | Public | Private | Protected | Readonly | Static | Override)
}
pub fn is_binding_identifier_or_private_identifier_or_pattern(self) -> bool {
matches!(self, LCurly | LBrack | PrivateIdentifier) || self.is_binding_identifier()
}
pub fn match_keyword(s: &str) -> Self {
let len = s.len();
if len <= 1 || len >= 12 || !s.as_bytes()[0].is_ascii_lowercase() {

View file

@ -50,54 +50,8 @@ impl<'a> SeparatedList<'a> for TSTupleElementList<'a> {
}
fn parse_element(&mut self, p: &mut ParserImpl<'a>) -> Result<()> {
let span = p.start_span();
if p.is_at_named_tuple_element() {
if p.eat(Kind::Dot3) {
let member_span = p.start_span();
let label = p.parse_identifier_name()?;
p.expect(Kind::Colon)?;
let element_type = p.parse_ts_type()?;
self.elements.push(TSTupleElement::TSRestType(p.ast.alloc(TSRestType {
span: p.end_span(span),
type_annotation: TSType::TSNamedTupleMember(p.ast.alloc(TSNamedTupleMember {
span: p.end_span(member_span),
element_type,
label,
optional: false, // A tuple member cannot be both optional and rest. (TS5085)
})),
})));
return Ok(());
}
let label = p.parse_identifier_name()?;
let optional = p.eat(Kind::Question);
p.expect(Kind::Colon)?;
let element_type = p.parse_ts_type()?;
self.elements.push(TSTupleElement::TSNamedTupleMember(p.ast.alloc(
TSNamedTupleMember { span: p.end_span(span), element_type, label, optional },
)));
return Ok(());
}
if p.eat(Kind::Dot3) {
let type_annotation = p.parse_ts_type()?;
self.elements.push(TSTupleElement::TSRestType(
p.ast.alloc(TSRestType { span: p.end_span(span), type_annotation }),
));
return Ok(());
}
let type_annotation = p.parse_ts_type()?;
if p.eat(Kind::Question) {
self.elements.push(TSTupleElement::TSOptionalType(
p.ast.alloc(TSOptionalType { span: p.end_span(span), type_annotation }),
));
} else {
self.elements.push(TSTupleElement::from(type_annotation));
}
let ty = p.parse_tuple_element_name_or_tuple_element_type()?;
self.elements.push(ty);
Ok(())
}
}

File diff suppressed because it is too large Load diff

View file

@ -687,6 +687,7 @@ impl<'a> Format<'a> for TSType<'a> {
TSType::TSTypeReference(v) => v.format(p),
TSType::TSUnionType(v) => v.format(p),
TSType::JSDocNullableType(v) => v.format(p),
TSType::JSDocNonNullableType(v) => v.format(p),
TSType::JSDocUnknownType(v) => v.format(p),
}
}
@ -931,6 +932,12 @@ impl<'a> Format<'a> for JSDocNullableType<'a> {
}
}
impl<'a> Format<'a> for JSDocNonNullableType<'a> {
fn format(&self, p: &mut Prettier<'a>) -> Doc<'a> {
line!()
}
}
impl<'a> Format<'a> for JSDocUnknownType {
fn format(&self, p: &mut Prettier<'a>) -> Doc<'a> {
line!()

View file

@ -287,7 +287,7 @@ pub(crate) enum AncestorType {
TSInferTypeTypeParameter = 255,
TSTypeQueryExprName = 256,
TSTypeQueryTypeParameters = 257,
TSImportTypeArgument = 258,
TSImportTypeParameter = 258,
TSImportTypeQualifier = 259,
TSImportTypeAttributes = 260,
TSImportTypeTypeParameters = 261,
@ -322,6 +322,7 @@ pub(crate) enum AncestorType {
TSInstantiationExpressionExpression = 290,
TSInstantiationExpressionTypeParameters = 291,
JSDocNullableTypeTypeAnnotation = 292,
JSDocNonNullableTypeTypeAnnotation = 293,
}
/// Ancestor type used in AST traversal.
@ -792,8 +793,8 @@ pub enum Ancestor<'a> {
TSTypeQueryExprName(TSTypeQueryWithoutExprName<'a>) = AncestorType::TSTypeQueryExprName as u16,
TSTypeQueryTypeParameters(TSTypeQueryWithoutTypeParameters<'a>) =
AncestorType::TSTypeQueryTypeParameters as u16,
TSImportTypeArgument(TSImportTypeWithoutArgument<'a>) =
AncestorType::TSImportTypeArgument as u16,
TSImportTypeParameter(TSImportTypeWithoutParameter<'a>) =
AncestorType::TSImportTypeParameter as u16,
TSImportTypeQualifier(TSImportTypeWithoutQualifier<'a>) =
AncestorType::TSImportTypeQualifier as u16,
TSImportTypeAttributes(TSImportTypeWithoutAttributes<'a>) =
@ -861,6 +862,8 @@ pub enum Ancestor<'a> {
AncestorType::TSInstantiationExpressionTypeParameters as u16,
JSDocNullableTypeTypeAnnotation(JSDocNullableTypeWithoutTypeAnnotation<'a>) =
AncestorType::JSDocNullableTypeTypeAnnotation as u16,
JSDocNonNullableTypeTypeAnnotation(JSDocNonNullableTypeWithoutTypeAnnotation<'a>) =
AncestorType::JSDocNonNullableTypeTypeAnnotation as u16,
}
impl<'a> Ancestor<'a> {
@ -1706,7 +1709,7 @@ impl<'a> Ancestor<'a> {
pub fn is_ts_import_type(&self) -> bool {
matches!(
self,
Self::TSImportTypeArgument(_)
Self::TSImportTypeParameter(_)
| Self::TSImportTypeQualifier(_)
| Self::TSImportTypeAttributes(_)
| Self::TSImportTypeTypeParameters(_)
@ -1825,6 +1828,11 @@ impl<'a> Ancestor<'a> {
matches!(self, Self::JSDocNullableTypeTypeAnnotation(_))
}
#[inline]
pub fn is_js_doc_non_nullable_type(&self) -> bool {
matches!(self, Self::JSDocNonNullableTypeTypeAnnotation(_))
}
#[inline]
pub fn is_via_statement(&self) -> bool {
matches!(
@ -2084,14 +2092,13 @@ impl<'a> Ancestor<'a> {
| Self::TSArrayTypeElementType(_)
| Self::TSIndexedAccessTypeObjectType(_)
| Self::TSIndexedAccessTypeIndexType(_)
| Self::TSNamedTupleMemberElementType(_)
| Self::TSOptionalTypeTypeAnnotation(_)
| Self::TSRestTypeTypeAnnotation(_)
| Self::TSTypeParameterInstantiationParams(_)
| Self::TSTypeParameterConstraint(_)
| Self::TSTypeParameterDefault(_)
| Self::TSTypeAliasDeclarationTypeAnnotation(_)
| Self::TSImportTypeArgument(_)
| Self::TSImportTypeParameter(_)
| Self::TSMappedTypeNameType(_)
| Self::TSMappedTypeTypeAnnotation(_)
| Self::TSTemplateLiteralTypeTypes(_)
@ -2099,6 +2106,7 @@ impl<'a> Ancestor<'a> {
| Self::TSSatisfiesExpressionTypeAnnotation(_)
| Self::TSTypeAssertionTypeAnnotation(_)
| Self::JSDocNullableTypeTypeAnnotation(_)
| Self::JSDocNonNullableTypeTypeAnnotation(_)
)
}
@ -2109,7 +2117,7 @@ impl<'a> Ancestor<'a> {
#[inline]
pub fn is_via_ts_tuple_element(&self) -> bool {
matches!(self, Self::TSTupleTypeElementTypes(_))
matches!(self, Self::TSTupleTypeElementTypes(_) | Self::TSNamedTupleMemberElementType(_))
}
#[inline]
@ -9128,10 +9136,10 @@ impl<'a> TSNamedTupleMemberWithoutLabel<'a> {
}
#[inline]
pub fn element_type(&self) -> &TSType<'a> {
pub fn element_type(&self) -> &TSTupleElement<'a> {
unsafe {
&*((self.0 as *const u8).add(OFFSET_TS_NAMED_TUPLE_MEMBER_ELEMENT_TYPE)
as *const TSType<'a>)
as *const TSTupleElement<'a>)
}
}
@ -10897,7 +10905,8 @@ impl<'a> TSTypeQueryWithoutTypeParameters<'a> {
}
pub(crate) const OFFSET_TS_IMPORT_TYPE_SPAN: usize = offset_of!(TSImportType, span);
pub(crate) const OFFSET_TS_IMPORT_TYPE_ARGUMENT: usize = offset_of!(TSImportType, argument);
pub(crate) const OFFSET_TS_IMPORT_TYPE_IS_TYPE_OF: usize = offset_of!(TSImportType, is_type_of);
pub(crate) const OFFSET_TS_IMPORT_TYPE_PARAMETER: usize = offset_of!(TSImportType, parameter);
pub(crate) const OFFSET_TS_IMPORT_TYPE_QUALIFIER: usize = offset_of!(TSImportType, qualifier);
pub(crate) const OFFSET_TS_IMPORT_TYPE_ATTRIBUTES: usize = offset_of!(TSImportType, attributes);
pub(crate) const OFFSET_TS_IMPORT_TYPE_TYPE_PARAMETERS: usize =
@ -10905,14 +10914,19 @@ pub(crate) const OFFSET_TS_IMPORT_TYPE_TYPE_PARAMETERS: usize =
#[repr(transparent)]
#[derive(Debug)]
pub struct TSImportTypeWithoutArgument<'a>(pub(crate) *const TSImportType<'a>);
pub struct TSImportTypeWithoutParameter<'a>(pub(crate) *const TSImportType<'a>);
impl<'a> TSImportTypeWithoutArgument<'a> {
impl<'a> TSImportTypeWithoutParameter<'a> {
#[inline]
pub fn span(&self) -> &Span {
unsafe { &*((self.0 as *const u8).add(OFFSET_TS_IMPORT_TYPE_SPAN) as *const Span) }
}
#[inline]
pub fn is_type_of(&self) -> &bool {
unsafe { &*((self.0 as *const u8).add(OFFSET_TS_IMPORT_TYPE_IS_TYPE_OF) as *const bool) }
}
#[inline]
pub fn qualifier(&self) -> &Option<TSTypeName<'a>> {
unsafe {
@ -10949,9 +10963,14 @@ impl<'a> TSImportTypeWithoutQualifier<'a> {
}
#[inline]
pub fn argument(&self) -> &TSType<'a> {
pub fn is_type_of(&self) -> &bool {
unsafe { &*((self.0 as *const u8).add(OFFSET_TS_IMPORT_TYPE_IS_TYPE_OF) as *const bool) }
}
#[inline]
pub fn parameter(&self) -> &TSType<'a> {
unsafe {
&*((self.0 as *const u8).add(OFFSET_TS_IMPORT_TYPE_ARGUMENT) as *const TSType<'a>)
&*((self.0 as *const u8).add(OFFSET_TS_IMPORT_TYPE_PARAMETER) as *const TSType<'a>)
}
}
@ -10983,9 +11002,14 @@ impl<'a> TSImportTypeWithoutAttributes<'a> {
}
#[inline]
pub fn argument(&self) -> &TSType<'a> {
pub fn is_type_of(&self) -> &bool {
unsafe { &*((self.0 as *const u8).add(OFFSET_TS_IMPORT_TYPE_IS_TYPE_OF) as *const bool) }
}
#[inline]
pub fn parameter(&self) -> &TSType<'a> {
unsafe {
&*((self.0 as *const u8).add(OFFSET_TS_IMPORT_TYPE_ARGUMENT) as *const TSType<'a>)
&*((self.0 as *const u8).add(OFFSET_TS_IMPORT_TYPE_PARAMETER) as *const TSType<'a>)
}
}
@ -11017,9 +11041,14 @@ impl<'a> TSImportTypeWithoutTypeParameters<'a> {
}
#[inline]
pub fn argument(&self) -> &TSType<'a> {
pub fn is_type_of(&self) -> &bool {
unsafe { &*((self.0 as *const u8).add(OFFSET_TS_IMPORT_TYPE_IS_TYPE_OF) as *const bool) }
}
#[inline]
pub fn parameter(&self) -> &TSType<'a> {
unsafe {
&*((self.0 as *const u8).add(OFFSET_TS_IMPORT_TYPE_ARGUMENT) as *const TSType<'a>)
&*((self.0 as *const u8).add(OFFSET_TS_IMPORT_TYPE_PARAMETER) as *const TSType<'a>)
}
}
@ -11898,3 +11927,32 @@ impl<'a> JSDocNullableTypeWithoutTypeAnnotation<'a> {
unsafe { &*((self.0 as *const u8).add(OFFSET_JS_DOC_NULLABLE_TYPE_POSTFIX) as *const bool) }
}
}
pub(crate) const OFFSET_JS_DOC_NON_NULLABLE_TYPE_SPAN: usize =
offset_of!(JSDocNonNullableType, span);
pub(crate) const OFFSET_JS_DOC_NON_NULLABLE_TYPE_TYPE_ANNOTATION: usize =
offset_of!(JSDocNonNullableType, type_annotation);
pub(crate) const OFFSET_JS_DOC_NON_NULLABLE_TYPE_POSTFIX: usize =
offset_of!(JSDocNonNullableType, postfix);
#[repr(transparent)]
#[derive(Debug)]
pub struct JSDocNonNullableTypeWithoutTypeAnnotation<'a>(
pub(crate) *const JSDocNonNullableType<'a>,
);
impl<'a> JSDocNonNullableTypeWithoutTypeAnnotation<'a> {
#[inline]
pub fn span(&self) -> &Span {
unsafe {
&*((self.0 as *const u8).add(OFFSET_JS_DOC_NON_NULLABLE_TYPE_SPAN) as *const Span)
}
}
#[inline]
pub fn postfix(&self) -> &bool {
unsafe {
&*((self.0 as *const u8).add(OFFSET_JS_DOC_NON_NULLABLE_TYPE_POSTFIX) as *const bool)
}
}
}

View file

@ -2405,6 +2405,21 @@ pub trait Traverse<'a> {
) {
}
#[inline]
fn enter_js_doc_non_nullable_type(
&mut self,
node: &mut JSDocNonNullableType<'a>,
ctx: &mut TraverseCtx<'a>,
) {
}
#[inline]
fn exit_js_doc_non_nullable_type(
&mut self,
node: &mut JSDocNonNullableType<'a>,
ctx: &mut TraverseCtx<'a>,
) {
}
#[inline]
fn enter_js_doc_unknown_type(
&mut self,

View file

@ -3899,6 +3899,9 @@ pub(crate) unsafe fn walk_ts_type<'a, Tr: Traverse<'a>>(
TSType::JSDocNullableType(node) => {
walk_js_doc_nullable_type(traverser, (&mut **node) as *mut _, ctx)
}
TSType::JSDocNonNullableType(node) => {
walk_js_doc_non_nullable_type(traverser, (&mut **node) as *mut _, ctx)
}
TSType::JSDocUnknownType(node) => {
walk_js_doc_unknown_type(traverser, (&mut **node) as *mut _, ctx)
}
@ -4063,9 +4066,10 @@ pub(crate) unsafe fn walk_ts_named_tuple_member<'a, Tr: Traverse<'a>>(
ctx.push_stack(Ancestor::TSNamedTupleMemberElementType(
ancestor::TSNamedTupleMemberWithoutElementType(node),
));
walk_ts_type(
walk_ts_tuple_element(
traverser,
(node as *mut u8).add(ancestor::OFFSET_TS_NAMED_TUPLE_MEMBER_ELEMENT_TYPE) as *mut TSType,
(node as *mut u8).add(ancestor::OFFSET_TS_NAMED_TUPLE_MEMBER_ELEMENT_TYPE)
as *mut TSTupleElement,
ctx,
);
ctx.retag_stack(AncestorType::TSNamedTupleMemberLabel);
@ -4162,6 +4166,7 @@ pub(crate) unsafe fn walk_ts_tuple_element<'a, Tr: Traverse<'a>>(
| TSTupleElement::TSTypeReference(_)
| TSTupleElement::TSUnionType(_)
| TSTupleElement::JSDocNullableType(_)
| TSTupleElement::JSDocNonNullableType(_)
| TSTupleElement::JSDocUnknownType(_) => walk_ts_type(traverser, node as *mut _, ctx),
}
traverser.exit_ts_tuple_element(&mut *node, ctx);
@ -5004,10 +5009,10 @@ pub(crate) unsafe fn walk_ts_import_type<'a, Tr: Traverse<'a>>(
ctx: &mut TraverseCtx<'a>,
) {
traverser.enter_ts_import_type(&mut *node, ctx);
ctx.push_stack(Ancestor::TSImportTypeArgument(ancestor::TSImportTypeWithoutArgument(node)));
ctx.push_stack(Ancestor::TSImportTypeParameter(ancestor::TSImportTypeWithoutParameter(node)));
walk_ts_type(
traverser,
(node as *mut u8).add(ancestor::OFFSET_TS_IMPORT_TYPE_ARGUMENT) as *mut TSType,
(node as *mut u8).add(ancestor::OFFSET_TS_IMPORT_TYPE_PARAMETER) as *mut TSType,
ctx,
);
if let Some(field) = &mut *((node as *mut u8).add(ancestor::OFFSET_TS_IMPORT_TYPE_QUALIFIER)
@ -5474,6 +5479,25 @@ pub(crate) unsafe fn walk_js_doc_nullable_type<'a, Tr: Traverse<'a>>(
traverser.exit_js_doc_nullable_type(&mut *node, ctx);
}
pub(crate) unsafe fn walk_js_doc_non_nullable_type<'a, Tr: Traverse<'a>>(
traverser: &mut Tr,
node: *mut JSDocNonNullableType<'a>,
ctx: &mut TraverseCtx<'a>,
) {
traverser.enter_js_doc_non_nullable_type(&mut *node, ctx);
ctx.push_stack(Ancestor::JSDocNonNullableTypeTypeAnnotation(
ancestor::JSDocNonNullableTypeWithoutTypeAnnotation(node),
));
walk_ts_type(
traverser,
(node as *mut u8).add(ancestor::OFFSET_JS_DOC_NON_NULLABLE_TYPE_TYPE_ANNOTATION)
as *mut TSType,
ctx,
);
ctx.pop_stack();
traverser.exit_js_doc_non_nullable_type(&mut *node, ctx);
}
pub(crate) unsafe fn walk_js_doc_unknown_type<'a, Tr: Traverse<'a>>(
traverser: &mut Tr,
node: *mut JSDocUnknownType,

View file

@ -14,14 +14,22 @@ name = "oxc_ast_codegen"
test = false
[dependencies]
syn = { workspace = true, features = ["full", "extra-traits", "clone-impls", "derive", "parsing", "printing", "proc-macro"] }
quote = { workspace = true }
proc-macro2 = { workspace = true }
itertools = { workspace = true }
serde = { workspace = true, features = ["derive"] }
regex = { workspace = true }
syn = { workspace = true, features = [
"clone-impls",
"derive",
"extra-traits",
"full",
"parsing",
"printing",
"proc-macro",
] }
quote = { workspace = true }
proc-macro2 = { workspace = true }
itertools = { workspace = true }
serde = { workspace = true, features = ["derive"] }
regex = { workspace = true }
prettyplease = { workspace = true }
lazy_static = { workspace = true }
lazy_static = { workspace = true }
[package.metadata.cargo-shear]
ignored = ["prettyplease"]

View file

@ -8,7 +8,7 @@ use super::generated_header;
pub struct AstKindGenerator;
const BLACK_LIST: [&str; 68] = [
const BLACK_LIST: [&str; 69] = [
"Expression",
"ObjectPropertyKind",
"TemplateElement",
@ -69,6 +69,7 @@ const BLACK_LIST: [&str; 68] = [
"TSExportAssignment",
"TSNamespaceExportDeclaration",
"JSDocNullableType",
"JSDocNonNullableType",
"JSDocUnknownType",
"JSXExpression",
"JSXEmptyExpression",

View file

@ -3,7 +3,7 @@ commit: 12619ffe
parser_babel Summary:
AST Parsed : 2095/2101 (99.71%)
Positive Passed: 2087/2101 (99.33%)
Negative Passed: 1365/1501 (90.94%)
Negative Passed: 1364/1501 (90.87%)
Expect Syntax Error: "annex-b/disabled/1.1-html-comments-close/input.js"
Expect Syntax Error: "annex-b/disabled/3.1-sloppy-labeled-functions/input.js"
Expect Syntax Error: "annex-b/disabled/3.1-sloppy-labeled-functions-if-body/input.js"
@ -138,6 +138,7 @@ Expect Syntax Error: "typescript/types/read-only-1/input.ts"
Expect Syntax Error: "typescript/types/read-only-2/input.ts"
Expect Syntax Error: "typescript/types/read-only-3/input.ts"
Expect Syntax Error: "typescript/types/read-only-4/input.ts"
Expect Syntax Error: "typescript/types/tuple-labeled-invalid-optional/input.ts"
Expect Syntax Error: "typescript/types/tuple-optional-invalid/input.ts"
Expect Syntax Error: "typescript/types/tuple-required-after-labeled-optional/input.ts"
Expect to Parse: "core/opts/allowNewTargetOutsideFunction-true/input.js"
@ -10668,13 +10669,6 @@ Expect to Parse: "typescript/types/const-type-parameters-babel-7/input.ts"
· ╰── `,` expected
╰────
× Expected `,` but found `?`
╭─[typescript/types/tuple-labeled-invalid-optional/input.ts:1:15]
1 │ type T = [x: A?];
· ┬
· ╰── `,` expected
╰────
× Expected `,` but found `Identifier`
╭─[typescript/types/variance-annotations/input.ts:95:17]
94 │
@ -10711,22 +10705,22 @@ Expect to Parse: "typescript/types/const-type-parameters-babel-7/input.ts"
99 │ type T21<in out in T> = T; // Error
╰────
× Expected `)` but found `EOF`
× Expected `]` but found `EOF`
╭─[typescript/types-arrow-function/invalid-incomplete-array-like/input.ts:2:1]
1 │ type F = ([
╰────
× Expected `)` but found `EOF`
× Expected `}` but found `EOF`
╭─[typescript/types-arrow-function/invalid-incomplete-object-like/input.ts:2:1]
1 │ type F = ({
╰────
× Expected `)` but found `EOF`
× Expected `]` but found `EOF`
╭─[typescript/types-arrow-function-babel-7/invalid-incomplete-array-like/input.ts:2:1]
1 │ type F = ([
╰────
× Expected `)` but found `EOF`
× Expected `}` but found `EOF`
╭─[typescript/types-arrow-function-babel-7/invalid-incomplete-object-like/input.ts:2:1]
1 │ type F = ({
╰────

View file

@ -3,7 +3,7 @@ commit: d8086f14
parser_typescript Summary:
AST Parsed : 5280/5283 (99.94%)
Positive Passed: 5273/5283 (99.81%)
Negative Passed: 1073/4875 (22.01%)
Negative Passed: 1069/4875 (21.93%)
Expect Syntax Error: "compiler/ClassDeclaration10.ts"
Expect Syntax Error: "compiler/ClassDeclaration11.ts"
Expect Syntax Error: "compiler/ClassDeclaration13.ts"
@ -1391,6 +1391,8 @@ Expect Syntax Error: "compiler/paramterDestrcuturingDeclaration.ts"
Expect Syntax Error: "compiler/parenthesizedJSDocCastDoesNotNarrow.ts"
Expect Syntax Error: "compiler/parseCommaSeparatedNewlineNumber.ts"
Expect Syntax Error: "compiler/parseCommaSeparatedNewlineString.ts"
Expect Syntax Error: "compiler/parseInvalidNonNullableTypes.ts"
Expect Syntax Error: "compiler/parseInvalidNullableTypes.ts"
Expect Syntax Error: "compiler/parseJsxExtends2.ts"
Expect Syntax Error: "compiler/parseTypes.ts"
Expect Syntax Error: "compiler/parseUnaryExpressionNoTypeAssertionInJsx1.ts"
@ -3631,8 +3633,10 @@ Expect Syntax Error: "conformance/types/tuple/contextualTypeWithTuple.ts"
Expect Syntax Error: "conformance/types/tuple/emptyTuples/emptyTuplesTypeAssertion01.ts"
Expect Syntax Error: "conformance/types/tuple/emptyTuples/emptyTuplesTypeAssertion02.ts"
Expect Syntax Error: "conformance/types/tuple/indexerWithTuple.ts"
Expect Syntax Error: "conformance/types/tuple/named/namedTupleMembersErrors.ts"
Expect Syntax Error: "conformance/types/tuple/optionalTupleElements1.ts"
Expect Syntax Error: "conformance/types/tuple/readonlyArraysAndTuples.ts"
Expect Syntax Error: "conformance/types/tuple/restTupleElements1.ts"
Expect Syntax Error: "conformance/types/tuple/strictTupleLength.ts"
Expect Syntax Error: "conformance/types/tuple/tupleLengthCheck.ts"
Expect Syntax Error: "conformance/types/tuple/unionsOfTupleTypes1.ts"
@ -6712,13 +6716,13 @@ Expect to Parse: "conformance/salsa/plainJSRedeclare3.ts"
3 │ function f() {
╰────
× Expected `=>` but found `)`
╭─[compiler/functionTypesLackingReturnTypes.ts:2:17]
1 │ // Error (no '=>')
2 │ function f(x: ()) {
·
· ╰── `=>` expected
3 │ }
× Expected `,` but found `var`
╭─[compiler/functionTypesLackingReturnTypes.ts:6:1]
5 │ // Error (no '=>')
6 │ var g: (param);
· ─┬─
· ╰── `,` expected
7 │
╰────
× Identifier `total` has already been declared
@ -8540,23 +8544,6 @@ Expect to Parse: "conformance/salsa/plainJSRedeclare3.ts"
╰────
help: Try insert a semicolon here
× Expected a semicolon or an implicit semicolon after a statement, but found none
╭─[compiler/parseInvalidNonNullableTypes.ts:1:36]
1 │ function f1(a: string): a is string! {
· ▲
2 │ return true;
╰────
help: Try insert a semicolon here
× Expected `,` but found `?`
╭─[compiler/parseInvalidNullableTypes.ts:5:22]
4 │
5 │ function f2(a: string?) {}
· ┬
· ╰── `,` expected
6 │ function f3(a: number?) {}
╰────
× Expected `>` but found `EOF`
╭─[compiler/parseJsxElementInUnaryExpressionNoCrash1.ts:1:5]
1 │ ~< <
@ -12073,11 +12060,12 @@ Expect to Parse: "conformance/salsa/plainJSRedeclare3.ts"
25 │ a = b; // Error
╰────
× Unexpected token
× Expected `]` but found `#identifier`
╭─[conformance/classes/members/privateNames/privateNamesAndIndexedAccess.ts:7:28]
6 │ // not supported yet, could support in future:
7 │ const badForNow: C[#bar] = 3; // Error
· ────
· ──┬─
· ╰── `]` expected
8 │ // will never use this syntax, already taken:
╰────
@ -12397,14 +12385,13 @@ Expect to Parse: "conformance/salsa/plainJSRedeclare3.ts"
╰────
help: Try insert a semicolon here
× Expected a semicolon or an implicit semicolon after a statement, but found none
╭─[conformance/decorators/decoratorMetadata-jsdoc.ts:5:15]
4 │ @decorator()
5 │ a?: string?;
· ▲
6 │ @decorator()
╰────
help: Try insert a semicolon here
× Unexpected token
╭─[conformance/decorators/decoratorMetadata-jsdoc.ts:9:9]
8 │ @decorator()
9 │ c?: *;
· ─
10 │ }
╰────
× Unexpected token
╭─[conformance/decorators/invalid/decoratorOnArrowFunction.ts:3:17]
@ -20820,24 +20807,6 @@ Expect to Parse: "conformance/salsa/plainJSRedeclare3.ts"
169 │ function restParam(...this: C): number { return this.n; }
╰────
× Expected `,` but found `?`
╭─[conformance/types/tuple/named/namedTupleMembersErrors.ts:10:35]
9 │
10 │ export type Opt = [element: string?]; // question mark on element disallowed
· ┬
· ╰── `,` expected
11 │
╰────
× Expected `,` but found `?`
╭─[conformance/types/tuple/restTupleElements1.ts:10:22]
9 │ type T08 = [...string]; // Error
10 │ type T09 = [...string?]; // Error
· ┬
· ╰── `,` expected
11 │ type T10 = [string, ...[...string[]]];
╰────
× Expected a semicolon or an implicit semicolon after a statement, but found none
╭─[conformance/types/typeAliases/reservedNamesInAliases.ts:6:5]
5 │ type string = I;