Repository: denoland/deno
Pull request: feat(unstable): align lint ast with TSEStree

This PR fixes deviations in our AST format compared to TSEStree. They are mostly a leftover for when I first started working on it and based it off of babel instead.

One of the key changes why the changeset is a bit bigger is that TSEStree uses `undefined` instead of `null` as the empty value for type nodes. This is likely influenced by `tsc` which use `undefined` everywhere. The rest of the nodes use `null` though. It's a little weird, but for now it might be better to align.

(extracted from https://github.com/denoland/deno/pull/27977)

Changed files:
filename: cli/tools/lint/ast_buffer/buffer.rs
patch: @@ -485,6 +485,22 @@ impl SerializeCtx {
     };
   }
 
+  /// Helper for writing optional node offsets with undefined as empty value
+  pub fn write_maybe_undef_ref<P>(
+    &mut self,
+    prop: P,
+    parent: &PendingRef,
+    value: Option<NodeRef>,
+  ) where
+    P: Into<u8> + Display + Clone,
+  {
+    if let Some(v) = value {
+      self.write_ref(prop, parent, v);
+    } else {
+      self.write_undefined(prop);
+    };
+  }
+
   /// Write a vec of node offsets into the property. The necessary space
   /// has been reserved earlier.
   pub fn write_ref_vec<P>(

filename: cli/tools/lint/ast_buffer/swc.rs
patch: @@ -80,6 +80,7 @@ use deno_ast::swc::common::SyntaxContext;
 use deno_ast::view::Accessibility;
 use deno_ast::view::AssignOp;
 use deno_ast::view::BinaryOp;
+use deno_ast::view::MetaPropKind;
 use deno_ast::view::MethodKind;
 use deno_ast::view::TsKeywordTypeKind;
 use deno_ast::view::TsTypeOperatorOp;
@@ -91,8 +92,11 @@ use deno_ast::ParsedSource;
 use super::buffer::AstBufSerializer;
 use super::buffer::NodeRef;
 use super::ts_estree::AstNode;
+use super::ts_estree::MethodKind as TsEstreeMethodKind;
+use super::ts_estree::PropertyKind;
 use super::ts_estree::TsEsTreeBuilder;
 use super::ts_estree::TsKeywordKind;
+use super::ts_estree::TsModuleKind;
 use crate::util::text_encoding::Utf16Map;
 
 pub fn serialize_swc_to_buffer(
@@ -175,8 +179,26 @@ fn serialize_module_decl(
       ctx.write_import_decl(&node.span, node.type_only, src, specifiers, attrs)
     }
     ModuleDecl::ExportDecl(node) => {
+      let is_type_only = match &node.decl {
+        Decl::Class(_) => false,
+        Decl::Fn(_) => false,
+        Decl::Var(_) => false,
+        Decl::Using(_) => false,
+        Decl::TsInterface(_) => true,
+        Decl::TsTypeAlias(_) => true,
+        Decl::TsEnum(_) => true,
+        Decl::TsModule(_) => true,
+      };
       let decl = serialize_decl(ctx, &node.decl);
-      ctx.write_export_decl(&node.span, decl)
+
+      ctx.write_export_named_decl(
+        &node.span,
+        is_type_only,
+        vec![],
+        None,
+        vec![],
+        Some(decl),
+      )
     }
     ModuleDecl::ExportNamed(node) => {
       let attrs = serialize_import_attrs(ctx, &node.with);
@@ -224,7 +246,14 @@ fn serialize_module_decl(
           })
           .collect::<Vec<_>>();
 
-        ctx.write_export_named_decl(&node.span, specifiers, source, attrs)
+        ctx.write_export_named_decl(
+          &node.span,
+          node.type_only,
+          specifiers,
+          source,
+          attrs,
+          None,
+        )
       }
     }
     ModuleDecl::ExportDefaultDecl(node) => {
@@ -293,17 +322,30 @@ fn serialize_module_decl(
             .as_ref()
             .map(|block| serialize_stmt(ctx, &Stmt::Block(block.clone())));
 
-          let decl = ctx.write_fn_decl(
-            &fn_obj.span,
-            false,
-            fn_obj.is_async,
-            fn_obj.is_generator,
-            ident,
-            type_params,
-            return_type,
-            body,
-            params,
-          );
+          let decl = if let Some(body) = body {
+            ctx.write_fn_decl(
+              &fn_obj.span,
+              false,
+              fn_obj.is_async,
+              fn_obj.is_generator,
+              ident,
+              type_params,
+              return_type,
+              body,
+              params,
+            )
+          } else {
+            ctx.write_ts_decl_fn(
+              &fn_obj.span,
+              false,
+              fn_obj.is_async,
+              fn_obj.is_generator,
+              ident,
+              type_params,
+              return_type,
+              params,
+            )
+          };
 
           (false, decl)
         }
@@ -797,7 +839,7 @@ fn serialize_expr(ctx: &mut TsEsTreeBuilder, expr: &Expr) -> NodeRef {
         let options = node
           .args
           .get(1)
-          .map_or(NodeRef(0), |arg| serialize_expr_or_spread(ctx, arg));
+          .map(|arg| serialize_expr_or_spread(ctx, arg));
 
         ctx.write_import_expr(&node.span, source, options)
       } else {
@@ -919,12 +961,21 @@ fn serialize_expr(ctx: &mut TsEsTreeBuilder, expr: &Expr) -> NodeRef {
         .as_ref()
         .map(|ident| serialize_ident(ctx, ident, None));
 
+      let type_params =
+        maybe_serialize_ts_type_param_decl(ctx, &node.class.type_params);
+
       let super_class = node
         .class
         .super_class
         .as_ref()
         .map(|expr| serialize_expr(ctx, expr.as_ref()));
 
+      let super_type_args = node
+        .class
+        .super_type_params
+        .as_ref()
+        .map(|param| serialize_ts_param_inst(ctx, param.as_ref()));
+
       let implements = node
         .class
         .implements
@@ -947,6 +998,8 @@ fn serialize_expr(ctx: &mut TsEsTreeBuilder, expr: &Expr) -> NodeRef {
         node.class.is_abstract,
         ident,
         super_class,
+        super_type_args,
+        type_params,
         implements,
         body,
       )
@@ -960,8 +1013,17 @@ fn serialize_expr(ctx: &mut TsEsTreeBuilder, expr: &Expr) -> NodeRef {
       ctx.write_yield_expr(&node.span, node.delegate, arg)
     }
     Expr::MetaProp(node) => {
-      let prop = ctx.write_identifier(&node.span, "meta", false, None);
-      ctx.write_meta_prop(&node.span, prop)
+      let (meta, prop) = match node.kind {
+        MetaPropKind::NewTarget => (
+          ctx.write_identifier(&node.span, "new", false, None),
+          ctx.write_identifier(&node.span, "target", false, None),
+        ),
+        MetaPropKind::ImportMeta => (
+          ctx.write_identifier(&node.span, "import", false, None),
+          ctx.write_identifier(&node.span, "meta", false, None),
+        ),
+      };
+      ctx.write_meta_prop(&node.span, meta, prop)
     }
     Expr::Await(node) => {
       let arg = serialize_expr(ctx, node.arg.as_ref());
@@ -1001,9 +1063,10 @@ fn serialize_expr(ctx: &mut TsEsTreeBuilder, expr: &Expr) -> NodeRef {
 
       ctx.write_ts_as_expr(&node.span, expr, type_ann)
     }
-    Expr::TsInstantiation(_) => {
-      // Invalid syntax
-      unreachable!()
+    Expr::TsInstantiation(node) => {
+      let expr = serialize_expr(ctx, &node.expr);
+      let type_args = serialize_ts_param_inst(ctx, node.type_args.as_ref());
+      ctx.write_ts_inst_expr(&node.span, expr, type_args)
     }
     Expr::TsSatisfies(node) => {
       let expr = serialize_expr(ctx, node.expr.as_ref());
@@ -1057,7 +1120,7 @@ fn serialize_prop_or_spread(
       let mut shorthand = false;
       let mut computed = false;
       let mut method = false;
-      let mut kind = "init";
+      let mut kind = PropertyKind::Init;
 
       let (key, value) = match prop.as_ref() {
         Prop::Shorthand(ident) => {
@@ -1086,7 +1149,7 @@ fn serialize_prop_or_spread(
           (left, child_pos)
         }
         Prop::Getter(getter_prop) => {
-          kind = "get";
+          kind = PropertyKind::Get;
 
           let key = serialize_prop_name(ctx, &getter_prop.key);
 
@@ -1111,7 +1174,7 @@ fn serialize_prop_or_spread(
           (key, value)
         }
         Prop::Setter(setter_prop) => {
-          kind = "set";
+          kind = PropertyKind::Set;
 
           let key_id = serialize_prop_name(ctx, &setter_prop.key);
 
@@ -1280,17 +1343,30 @@ fn serialize_decl(ctx: &mut TsEsTreeBuilder, decl: &Decl) -> NodeRef {
         .map(|param| serialize_pat(ctx, &param.pat))
         .collect::<Vec<_>>();
 
-      ctx.write_fn_decl(
-        &node.function.span,
-        node.declare,
-        node.function.is_async,
-        node.function.is_generator,
-        Some(ident_id),
-        type_param_id,
-        return_type,
-        body,
-        params,
-      )
+      if let Some(body) = body {
+        ctx.write_fn_decl(
+          &node.function.span,
+          node.declare,
+          node.function.is_async,
+          node.function.is_generator,
+          Some(ident_id),
+          type_param_id,
+          return_type,
+          body,
+          params,
+        )
+      } else {
+        ctx.write_ts_decl_fn(
+          &node.function.span,
+          node.declare,
+          node.function.is_async,
+          node.function.is_generator,
+          Some(ident_id),
+          type_param_id,
+          return_type,
+          params,
+        )
+      }
     }
     Decl::Var(node) => {
       let children = node
@@ -1303,7 +1379,7 @@ fn serialize_decl(ctx: &mut TsEsTreeBuilder, decl: &Decl) -> NodeRef {
             .as_ref()
             .map(|init| serialize_expr(ctx, init.as_ref()));
 
-          ctx.write_var_declarator(&decl.span, ident, init)
+          ctx.write_var_declarator(&decl.span, ident, init, decl.definite)
         })
         .collect::<Vec<_>>();
 
@@ -1332,7 +1408,7 @@ fn serialize_decl(ctx: &mut TsEsTreeBuilder, decl: &Decl) -> NodeRef {
             .as_ref()
             .map(|init| serialize_expr(ctx, init.as_ref()));
 
-          ctx.write_var_declarator(&decl.span, ident, init)
+          ctx.write_var_declarator(&decl.span, ident, init, decl.definite)
         })
         .collect::<Vec<_>>();
 
@@ -1366,7 +1442,7 @@ fn serialize_decl(ctx: &mut TsEsTreeBuilder, decl: &Decl) -> NodeRef {
 
       let body_pos =
         ctx.write_ts_interface_body(&node.body.span, body_elem_ids);
-      ctx.write_ts_interface(
+      ctx.write_ts_interface_decl(
         &node.span,
         node.declare,
         ident_id,
@@ -1428,7 +1504,11 @@ fn serialize_decl(ctx: &mut TsEsTreeBuilder, decl: &Decl) -> NodeRef {
       ctx.write_ts_module_decl(
         &node.span,
         node.declare,
-        node.global,
+        if node.global {
+          TsModuleKind::Global
+        } else {
+          TsModuleKind::Module
+        },
         ident,
         body,
       )
@@ -1460,7 +1540,7 @@ fn serialize_ts_namespace_body(
       ctx.write_ts_module_decl(
         &node.span,
         node.declare,
-        node.global,
+        TsModuleKind::Namespace,
         ident,
         Some(body),
       )
@@ -1562,7 +1642,13 @@ fn serialize_ts_index_sig(
     .collect::<Vec<_>>();
   let type_ann = maybe_serialize_ts_type_ann(ctx, &node.type_ann);
 
-  ctx.write_ts_index_sig(&node.span, node.readonly, params, type_ann)
+  ctx.write_ts_index_sig(
+    &node.span,
+    node.is_static,
+    node.readonly,
+    params,
+    type_ann,
+  )
 }
 
 fn accessibility_to_str(accessibility: &Accessibility) -> String {
@@ -1785,7 +1871,7 @@ fn serialize_pat(ctx: &mut TsEsTreeBuilder, pat: &Pat) -> NodeRef {
               false,
               computed,
               false,
-              "init",
+              PropertyKind::Init,
               key,
               value,
             )
@@ -1803,7 +1889,7 @@ fn serialize_pat(ctx: &mut TsEsTreeBuilder, pat: &Pat) -> NodeRef {
               false,
               false,
               false,
-              "init",
+              PropertyKind::Init,
               ident,
               value,
             )
@@ -1995,7 +2081,7 @@ fn serialize_class_member(
         node.is_optional,
         false,
         false,
-        "constructor",
+        TsEstreeMethodKind::Constructor,
         a11y,
         key,
         value,
@@ -2045,19 +2131,41 @@ fn serialize_class_member(
         .map(|deco| serialize_decorator(ctx, deco))
         .collect::<Vec<_>>();
 
-      Some(ctx.write_class_prop(
-        &node.span,
-        node.declare,
-        false,
-        node.is_optional,
-        node.is_override,
-        node.readonly,
-        node.is_static,
-        a11y,
-        decorators,
-        key,
-        value,
-      ))
+      let type_ann = maybe_serialize_ts_type_ann(ctx, &node.type_ann);
+
+      let out = if node.is_abstract {
+        ctx.write_ts_abstract_prop_def(
+          &node.span,
+          false,
+          node.is_optional,
+          node.is_override,
+          node.is_static,
+          node.definite,
+          node.readonly,
+          node.declare,
+          a11y,
+          decorators,
+          key,
+          type_ann,
+        )
+      } else {
+        ctx.write_class_prop(
+          &node.span,
+          node.declare,
+          false,
+          node.is_optional,
+          node.is_override,
+          node.readonly,
+          node.is_static,
+          a11y,
+          decorators,
+          key,
+          value,
+          type_ann,
+        )
+      };
+
+      Some(out)
     }
     ClassMember::PrivateProp(node) => {
       let a11y = node.accessibility.as_ref().map(accessibility_to_str);
@@ -2072,6 +2180,8 @@ fn serialize_class_member(
 
       let value = node.value.as_ref().map(|expr| serialize_expr(ctx, expr));
 
+      let type_ann = maybe_serialize_ts_type_ann(ctx, &node.type_ann);
+
       Some(ctx.write_class_prop(
         &node.span,
         false,
@@ -2084,6 +2194,7 @@ fn serialize_class_member(
         decorators,
         key,
         value,
+        type_ann,
       ))
     }
     ClassMember::TsIndexSignature(node) => {
@@ -2140,9 +2251,9 @@ fn serialize_class_method(
   function: &Function,
 ) -> NodeRef {
   let kind = match method_kind {
-    MethodKind::Method => "method",
-    MethodKind::Getter => "getter",
-    MethodKind::Setter => "setter",
+    MethodKind::Method => TsEstreeMethodKind::Method,
+    MethodKind::Getter => TsEstreeMethodKind::Get,
+    MethodKind::Setter => TsEstreeMethodKind::Set,
   };
 
   let type_params =
@@ -2178,7 +2289,6 @@ fn serialize_class_method(
       false,
       function.is_async,
       function.is_generator,
-      None,
       type_params,
       params,
       return_type,
@@ -2283,7 +2393,18 @@ fn serialize_ts_type(ctx: &mut TsEsTreeBuilder, node: &TsType) -> NodeRef {
           .map(|param| serialize_ts_fn_param(ctx, param))
           .collect::<Vec<_>>();
 
-        ctx.write_ts_fn_type(&node.span, param_ids)
+        let type_params = node
+          .type_params
+          .as_ref()
+          .map(|param| serialize_ts_type_param_decl(ctx, param));
+        let return_type = serialize_ts_type_ann(ctx, node.type_ann.as_ref());
+
+        ctx.write_ts_fn_type(
+          &node.span,
+          type_params,
+          param_ids,
+          Some(return_type),
+        )
       }
       TsFnOrConstructorType::TsConstructorType(node) => {
         // interface Foo { new<T>(arg1: any): any }
@@ -2349,10 +2470,17 @@ fn serialize_ts_type(ctx: &mut TsEsTreeBuilder, node: &TsType) -> NodeRef {
         .iter()
         .map(|elem| {
           if let Some(label) = &elem.label {
+            let optional = match label {
+              Pat::Ident(binding_ident) => binding_ident.optional,
+              Pat::Array(array_pat) => array_pat.optional,
+              Pat::Object(object_pat) => object_pat.optional,
+              _ => false,
+            };
             let label = serialize_pat(ctx, label);
             let type_id = serialize_ts_type(ctx, elem.ty.as_ref());
 
-            ctx.write_ts_named_tuple_member(&elem.span, label, type_id)
+            ctx
+              .write_ts_named_tuple_member(&elem.span, label, type_id, optional)
           } else {
             serialize_ts_type(ctx, elem.ty.as_ref())
           }
@@ -2425,15 +2553,21 @@ fn serialize_ts_type(ctx: &mut TsEsTreeBuilder, node: &TsType) -> NodeRef {
     TsType::TsMappedType(node) => {
       let name = maybe_serialize_ts_type(ctx, &node.name_type);
       let type_ann = maybe_serialize_ts_type(ctx, &node.type_ann);
-      let type_param = serialize_ts_type_param(ctx, &node.type_param);
+      let key = serialize_ident(ctx, &node.type_param.name, None);
+      let constraint = node
+        .type_param
+        .constraint
+        .as_ref()
+        .map_or(NodeRef(0), |node| serialize_ts_type(ctx, node));
 
       ctx.write_ts_mapped_type(
         &node.span,
         node.readonly,
         node.optional,
         name,
         type_ann,
-        type_param,
+        key,
+        constraint,
       )
     }
     TsType::TsLitType(node) => serialize_ts_lit_type(ctx, node),

filename: cli/tools/lint/ast_buffer/ts_estree.rs
patch: @@ -173,12 +173,15 @@ pub enum AstNode {
   TSArrayType,
   TSClassImplements,
   TSAbstractMethodDefinition,
+  TSAbstractPropertyDefinition,
   TSEmptyBodyFunctionExpression,
   TSParameterProperty,
   TSConstructSignatureDeclaration,
   TSQualifiedName,
   TSOptionalType,
   TSTemplateLiteralType,
+  TSDeclareFunction,
+  TSInstantiationExpression,
 
   TSAnyKeyword,
   TSBigIntKeyword,
@@ -582,12 +585,6 @@ impl TsEsTreeBuilder {
     self.ctx.commit_node(id)
   }
 
-  pub fn write_export_decl(&mut self, span: &Span, decl: NodeRef) -> NodeRef {
-    let id = self.ctx.append_node(AstNode::ExportNamedDeclaration, span);
-    self.ctx.write_ref(AstProp::Declaration, &id, decl);
-    self.ctx.commit_node(id)
-  }
-
   pub fn write_export_all_decl(
     &mut self,
     span: &Span,
@@ -626,14 +623,21 @@ impl TsEsTreeBuilder {
   pub fn write_export_named_decl(
     &mut self,
     span: &Span,
+    is_type_only: bool,
     specifiers: Vec<NodeRef>,
     source: Option<NodeRef>,
     attributes: Vec<NodeRef>,
+    declaration: Option<NodeRef>,
   ) -> NodeRef {
     let id = self.ctx.append_node(AstNode::ExportNamedDeclaration, span);
 
+    let value = if is_type_only { "type" } else { "value" };
+    self.ctx.write_str(AstProp::ExportKind, value);
     self.ctx.write_ref_vec(AstProp::Specifiers, &id, specifiers);
     self.ctx.write_maybe_ref(AstProp::Source, &id, source);
+    self
+      .ctx
+      .write_maybe_ref(AstProp::Declaration, &id, declaration);
     self.ctx.write_ref_vec(AstProp::Attributes, &id, attributes);
 
     self.ctx.commit_node(id)
@@ -721,11 +725,43 @@ impl TsEsTreeBuilder {
     span: &Span,
     ident: NodeRef,
     init: Option<NodeRef>,
+    definite: bool,
   ) -> NodeRef {
     let id = self.ctx.append_node(AstNode::VariableDeclarator, span);
 
     self.ctx.write_ref(AstProp::Id, &id, ident);
     self.ctx.write_maybe_ref(AstProp::Init, &id, init);
+    self.ctx.write_bool(AstProp::Definite, definite);
+
+    self.ctx.commit_node(id)
+  }
+
+  #[allow(clippy::too_many_arguments)]
+  pub fn write_ts_decl_fn(
+    &mut self,
+    span: &Span,
+    is_declare: bool,
+    is_async: bool,
+    is_generator: bool,
+    ident: Option<NodeRef>,
+    type_param: Option<NodeRef>,
+    return_type: Option<NodeRef>,
+    params: Vec<NodeRef>,
+  ) -> NodeRef {
+    let id = self.ctx.append_node(AstNode::TSDeclareFunction, span);
+
+    self.ctx.write_bool(AstProp::Declare, is_declare);
+    self.ctx.write_bool(AstProp::Async, is_async);
+    self.ctx.write_bool(AstProp::Generator, is_generator);
+    self.ctx.write_maybe_ref(AstProp::Id, &id, ident);
+    self
+      .ctx
+      .write_maybe_undef_ref(AstProp::TypeParameters, &id, type_param);
+    self
+      .ctx
+      .write_maybe_undef_ref(AstProp::ReturnType, &id, return_type);
+    self.ctx.write_undefined(AstProp::Body);
+    self.ctx.write_ref_vec(AstProp::Params, &id, params);
 
     self.ctx.commit_node(id)
   }
@@ -742,7 +778,7 @@ impl TsEsTreeBuilder {
     ident: Option<NodeRef>,
     type_param: Option<NodeRef>,
     return_type: Option<NodeRef>,
-    body: Option<NodeRef>,
+    body: NodeRef,
     params: Vec<NodeRef>,
   ) -> NodeRef {
     let id = self.ctx.append_node(AstNode::FunctionDeclaration, span);
@@ -753,11 +789,11 @@ impl TsEsTreeBuilder {
     self.ctx.write_maybe_ref(AstProp::Id, &id, ident);
     self
       .ctx
-      .write_maybe_ref(AstProp::TypeParameters, &id, type_param);
+      .write_maybe_undef_ref(AstProp::TypeParameters, &id, type_param);
     self
       .ctx
-      .write_maybe_ref(AstProp::ReturnType, &id, return_type);
-    self.ctx.write_maybe_ref(AstProp::Body, &id, body);
+      .write_maybe_undef_ref(AstProp::ReturnType, &id, return_type);
+    self.ctx.write_ref(AstProp::Body, &id, body);
     self.ctx.write_ref_vec(AstProp::Params, &id, params);
 
     self.ctx.commit_node(id)
@@ -803,6 +839,8 @@ impl TsEsTreeBuilder {
     is_abstract: bool,
     ident: Option<NodeRef>,
     super_class: Option<NodeRef>,
+    super_type_args: Option<NodeRef>,
+    type_params: Option<NodeRef>,
     implements: Vec<NodeRef>,
     body: NodeRef,
   ) -> NodeRef {
@@ -813,6 +851,14 @@ impl TsEsTreeBuilder {
     self
       .ctx
       .write_maybe_ref(AstProp::SuperClass, &id, super_class);
+    self.ctx.write_maybe_undef_ref(
+      AstProp::SuperTypeArguments,
+      &id,
+      super_type_args,
+    );
+    self
+      .ctx
+      .write_maybe_undef_ref(AstProp::TypeParameters, &id, type_params);
     self.ctx.write_ref_vec(AstProp::Implements, &id, implements);
     self.ctx.write_ref(AstProp::Body, &id, body);
 
@@ -880,6 +926,7 @@ impl TsEsTreeBuilder {
     decorators: Vec<NodeRef>,
     key: NodeRef,
     value: Option<NodeRef>,
+    type_ann: Option<NodeRef>,
   ) -> NodeRef {
     let id = self.ctx.append_node(AstNode::PropertyDefinition, span);
 
@@ -895,6 +942,9 @@ impl TsEsTreeBuilder {
 
     self.ctx.write_ref(AstProp::Key, &id, key);
     self.ctx.write_maybe_ref(AstProp::Value, &id, value);
+    self
+      .ctx
+      .write_maybe_undef_ref(AstProp::TypeAnnotation, &id, type_ann);
 
     self.ctx.commit_node(id)
   }
@@ -908,7 +958,7 @@ impl TsEsTreeBuilder {
     is_optional: bool,
     is_override: bool,
     is_static: bool,
-    kind: &str,
+    kind: MethodKind,
     accessibility: Option<String>,
     key: NodeRef,
     value: NodeRef,
@@ -920,10 +970,17 @@ impl TsEsTreeBuilder {
     self.ctx.write_bool(AstProp::Optional, is_optional);
     self.ctx.write_bool(AstProp::Override, is_override);
     self.ctx.write_bool(AstProp::Static, is_static);
-    self.ctx.write_str(AstProp::Kind, kind);
+    let kind_str = match kind {
+      MethodKind::Constructor => "constructor",
+      MethodKind::Get => "get",
+      MethodKind::Method => "method",
+      MethodKind::Set => "set",
+    };
+    self.ctx.write_str(AstProp::Kind, kind_str);
     self.write_accessibility(accessibility);
     self.ctx.write_ref(AstProp::Key, &id, key);
     self.ctx.write_ref(AstProp::Value, &id, value);
+    self.ctx.write_ref_vec(AstProp::Decorators, &id, vec![]);
 
     self.ctx.commit_node(id)
   }
@@ -1238,11 +1295,11 @@ impl TsEsTreeBuilder {
     self.ctx.write_maybe_ref(AstProp::Id, &id, ident);
     self
       .ctx
-      .write_maybe_ref(AstProp::TypeParameters, &id, type_params);
+      .write_maybe_undef_ref(AstProp::TypeParameters, &id, type_params);
     self.ctx.write_ref_vec(AstProp::Params, &id, params);
     self
       .ctx
-      .write_maybe_ref(AstProp::ReturnType, &id, return_type);
+      .write_maybe_undef_ref(AstProp::ReturnType, &id, return_type);
     self.ctx.write_maybe_ref(AstProp::Body, &id, body);
 
     self.ctx.commit_node(id)
@@ -1265,11 +1322,11 @@ impl TsEsTreeBuilder {
     self.ctx.write_bool(AstProp::Generator, is_generator);
     self
       .ctx
-      .write_maybe_ref(AstProp::TypeParameters, &id, type_params);
+      .write_maybe_undef_ref(AstProp::TypeParameters, &id, type_params);
     self.ctx.write_ref_vec(AstProp::Params, &id, params);
     self
       .ctx
-      .write_maybe_ref(AstProp::ReturnType, &id, return_type);
+      .write_maybe_undef_ref(AstProp::ReturnType, &id, return_type);
     self.ctx.write_ref(AstProp::Body, &id, body);
 
     self.ctx.commit_node(id)
@@ -1311,7 +1368,7 @@ impl TsEsTreeBuilder {
     self.ctx.write_ref(AstProp::Callee, &id, callee);
     self
       .ctx
-      .write_maybe_ref(AstProp::TypeArguments, &id, type_args);
+      .write_maybe_undef_ref(AstProp::TypeArguments, &id, type_args);
     self.ctx.write_ref_vec(AstProp::Arguments, &id, args);
 
     self.ctx.commit_node(id)
@@ -1321,12 +1378,12 @@ impl TsEsTreeBuilder {
     &mut self,
     span: &Span,
     source: NodeRef,
-    options: NodeRef,
+    options: Option<NodeRef>,
   ) -> NodeRef {
     let id = self.ctx.append_node(AstNode::ImportExpression, span);
 
     self.ctx.write_ref(AstProp::Source, &id, source);
-    self.ctx.write_ref(AstProp::Options, &id, options);
+    self.ctx.write_maybe_ref(AstProp::Options, &id, options);
 
     self.ctx.commit_node(id)
   }
@@ -1477,7 +1534,7 @@ impl TsEsTreeBuilder {
     self.ctx.write_ref(AstProp::Tag, &id, tag);
     self
       .ctx
-      .write_maybe_ref(AstProp::TypeArguments, &id, type_args);
+      .write_maybe_undef_ref(AstProp::TypeArguments, &id, type_args);
     self.ctx.write_ref(AstProp::Quasi, &id, quasi);
 
     self.ctx.commit_node(id)
@@ -1503,8 +1560,14 @@ impl TsEsTreeBuilder {
     self.ctx.commit_node(id)
   }
 
-  pub fn write_meta_prop(&mut self, span: &Span, prop: NodeRef) -> NodeRef {
+  pub fn write_meta_prop(
+    &mut self,
+    span: &Span,
+    meta: NodeRef,
+    prop: NodeRef,
+  ) -> NodeRef {
     let id = self.ctx.append_node(AstNode::MetaProperty, span);
+    self.ctx.write_ref(AstProp::Meta, &id, meta);
     self.ctx.write_ref(AstProp::Property, &id, prop);
     self.ctx.commit_node(id)
   }
@@ -1520,9 +1583,11 @@ impl TsEsTreeBuilder {
 
     self.ctx.write_str(AstProp::Name, name);
     self.ctx.write_bool(AstProp::Optional, optional);
-    self
-      .ctx
-      .write_maybe_ref(AstProp::TypeAnnotation, &id, type_annotation);
+    self.ctx.write_maybe_undef_ref(
+      AstProp::TypeAnnotation,
+      &id,
+      type_annotation,
+    );
 
     self.ctx.commit_node(id)
   }
@@ -1563,7 +1628,7 @@ impl TsEsTreeBuilder {
     self.ctx.write_bool(AstProp::Optional, optional);
     self
       .ctx
-      .write_maybe_ref(AstProp::TypeAnnotation, &id, type_ann);
+      .write_maybe_undef_ref(AstProp::TypeAnnotation, &id, type_ann);
     self.ctx.write_ref_vec(AstProp::Elements, &id, elems);
 
     self.ctx.commit_node(id)
@@ -1581,7 +1646,7 @@ impl TsEsTreeBuilder {
     self.ctx.write_bool(AstProp::Optional, optional);
     self
       .ctx
-      .write_maybe_ref(AstProp::TypeAnnotation, &id, type_ann);
+      .write_maybe_undef_ref(AstProp::TypeAnnotation, &id, type_ann);
     self.ctx.write_ref_vec(AstProp::Properties, &id, props);
 
     self.ctx.commit_node(id)
@@ -1597,7 +1662,7 @@ impl TsEsTreeBuilder {
 
     self
       .ctx
-      .write_maybe_ref(AstProp::TypeAnnotation, &id, type_ann);
+      .write_maybe_undef_ref(AstProp::TypeAnnotation, &id, type_ann);
     self.ctx.write_ref(AstProp::Argument, &id, arg);
 
     self.ctx.commit_node(id)
@@ -1616,7 +1681,7 @@ impl TsEsTreeBuilder {
     shorthand: bool,
     computed: bool,
     method: bool,
-    kind: &str,
+    kind: PropertyKind,
     key: NodeRef,
     value: NodeRef,
   ) -> NodeRef {
@@ -1625,7 +1690,12 @@ impl TsEsTreeBuilder {
     self.ctx.write_bool(AstProp::Shorthand, shorthand);
     self.ctx.write_bool(AstProp::Computed, computed);
     self.ctx.write_bool(AstProp::Method, method);
-    self.ctx.write_str(AstProp::Kind, kind);
+    let kind_str = match kind {
+      PropertyKind::Get => "get",
+      PropertyKind::Init => "init",
+      PropertyKind::Set => "set",
+    };
+    self.ctx.write_str(AstProp::Kind, kind_str);
     self.ctx.write_ref(AstProp::Key, &id, key);
     self.ctx.write_ref(AstProp::Value, &id, value);
 
@@ -1773,7 +1843,7 @@ impl TsEsTreeBuilder {
     self.ctx.write_ref_vec(AstProp::Attributes, &id, attrs);
     self
       .ctx
-      .write_maybe_ref(AstProp::TypeArguments, &id, type_args);
+      .write_maybe_undef_ref(AstProp::TypeArguments, &id, type_args);
 
     self.ctx.commit_node(id)
   }
@@ -1880,16 +1950,21 @@ impl TsEsTreeBuilder {
     &mut self,
     span: &Span,
     is_declare: bool,
-    is_global: bool,
+    kind: TsModuleKind,
     ident: NodeRef,
     body: Option<NodeRef>,
   ) -> NodeRef {
     let id = self.ctx.append_node(AstNode::TSModuleDeclaration, span);
 
     self.ctx.write_bool(AstProp::Declare, is_declare);
-    self.ctx.write_bool(AstProp::Global, is_global);
+    let kind_str = match kind {
+      TsModuleKind::Global => "global",
+      TsModuleKind::Namespace => "namespace",
+      TsModuleKind::Module => "module",
+    };
+    self.ctx.write_str(AstProp::Kind, kind_str);
     self.ctx.write_ref(AstProp::Id, &id, ident);
-    self.ctx.write_maybe_ref(AstProp::Body, &id, body);
+    self.ctx.write_maybe_undef_ref(AstProp::Body, &id, body);
     self.ctx.commit_node(id)
   }
 
@@ -1914,7 +1989,7 @@ impl TsEsTreeBuilder {
     self.ctx.write_ref(AstProp::Expression, &id, expr);
     self
       .ctx
-      .write_maybe_ref(AstProp::TypeArguments, &id, type_args);
+      .write_maybe_undef_ref(AstProp::TypeArguments, &id, type_args);
 
     self.ctx.commit_node(id)
   }
@@ -1944,7 +2019,47 @@ impl TsEsTreeBuilder {
 
     self.ctx.write_str(AstProp::Kind, "method");
     self.ctx.write_ref(AstProp::Key, &id, key);
-    self.ctx.write_ref(AstProp::Key, &id, value);
+    self.ctx.write_ref(AstProp::Value, &id, value);
+
+    self.ctx.commit_node(id)
+  }
+
+  #[allow(clippy::too_many_arguments)]
+  pub fn write_ts_abstract_prop_def(
+    &mut self,
+    span: &Span,
+    is_computed: bool,
+    is_optional: bool,
+    is_override: bool,
+    is_static: bool,
+    is_definite: bool,
+    is_readonly: bool,
+    is_declare: bool,
+    accessibility: Option<String>,
+    decorators: Vec<NodeRef>,
+    key: NodeRef,
+    type_ann: Option<NodeRef>,
+  ) -> NodeRef {
+    let id = self
+      .ctx
+      .append_node(AstNode::TSAbstractPropertyDefinition, span);
+
+    self.ctx.write_bool(AstProp::Computed, is_computed);
+    self.ctx.write_bool(AstProp::Optional, is_optional);
+    self.ctx.write_bool(AstProp::Override, is_override);
+    self.ctx.write_bool(AstProp::Static, is_static);
+    self.ctx.write_bool(AstProp::Definite, is_definite);
+    self.ctx.write_bool(AstProp::Declare, is_declare);
+    self.ctx.write_bool(AstProp::Readonly, is_readonly);
+
+    self.write_accessibility(accessibility);
+    self.ctx.write_ref_vec(AstProp::Decorators, &id, decorators);
+
+    self.ctx.write_ref(AstProp::Key, &id, key);
+    self.ctx.write_null(AstProp::Value);
+    self
+      .ctx
+      .write_maybe_undef_ref(AstProp::TypeAnnotation, &id, type_ann);
 
     self.ctx.commit_node(id)
   }
@@ -1957,7 +2072,6 @@ impl TsEsTreeBuilder {
     is_expression: bool,
     is_async: bool,
     is_generator: bool,
-    ident: Option<NodeRef>,
     type_params: Option<NodeRef>,
     params: Vec<NodeRef>,
     return_type: Option<NodeRef>,
@@ -1970,14 +2084,15 @@ impl TsEsTreeBuilder {
     self.ctx.write_bool(AstProp::Expression, is_expression);
     self.ctx.write_bool(AstProp::Async, is_async);
     self.ctx.write_bool(AstProp::Generator, is_generator);
-    self.ctx.write_maybe_ref(AstProp::Id, &id, ident);
+    self.ctx.write_null(AstProp::Id);
     self
       .ctx
-      .write_maybe_ref(AstProp::TypeParameters, &id, type_params);
+      .write_maybe_undef_ref(AstProp::TypeParameters, &id, type_params);
     self.ctx.write_ref_vec(AstProp::Params, &id, params);
     self
       .ctx
-      .write_maybe_ref(AstProp::ReturnType, &id, return_type);
+      .write_maybe_undef_ref(AstProp::ReturnType, &id, return_type);
+    self.ctx.write_null(AstProp::Body);
 
     self.ctx.commit_node(id)
   }
@@ -2016,11 +2131,11 @@ impl TsEsTreeBuilder {
 
     self
       .ctx
-      .write_maybe_ref(AstProp::TypeAnnotation, &id, type_ann);
+      .write_maybe_undef_ref(AstProp::TypeParameters, &id, type_ann);
     self.ctx.write_ref_vec(AstProp::Params, &id, params);
     self
       .ctx
-      .write_maybe_ref(AstProp::ReturnType, &id, return_type);
+      .write_maybe_undef_ref(AstProp::ReturnType, &id, return_type);
 
     self.ctx.commit_node(id)
   }
@@ -2045,7 +2160,7 @@ impl TsEsTreeBuilder {
     self.ctx.write_ref(AstProp::Key, &id, key);
     self
       .ctx
-      .write_maybe_ref(AstProp::TypeAnnotation, &id, type_ann);
+      .write_maybe_undef_ref(AstProp::TypeAnnotation, &id, type_ann);
 
     self.ctx.commit_node(id)
   }
@@ -2087,7 +2202,9 @@ impl TsEsTreeBuilder {
     let id = self.ctx.append_node(AstNode::TSEnumMember, span);
 
     self.ctx.write_ref(AstProp::Id, &id, ident);
-    self.ctx.write_maybe_ref(AstProp::Initializer, &id, init);
+    self
+      .ctx
+      .write_maybe_undef_ref(AstProp::Initializer, &id, init);
 
     self.ctx.commit_node(id)
   }
@@ -2134,7 +2251,7 @@ impl TsEsTreeBuilder {
     self.ctx.write_ref(AstProp::Id, &id, ident);
     self
       .ctx
-      .write_maybe_ref(AstProp::TypeParameters, &id, type_param);
+      .write_maybe_undef_ref(AstProp::TypeParameters, &id, type_param);
     self.ctx.write_ref(AstProp::TypeAnnotation, &id, type_ann);
 
     self.ctx.commit_node(id)
@@ -2154,6 +2271,22 @@ impl TsEsTreeBuilder {
     self.ctx.commit_node(id)
   }
 
+  pub fn write_ts_inst_expr(
+    &mut self,
+    span: &Span,
+    expr: NodeRef,
+    type_arg: NodeRef,
+  ) -> NodeRef {
+    let id = self
+      .ctx
+      .append_node(AstNode::TSInstantiationExpression, span);
+
+    self.ctx.write_ref(AstProp::Expression, &id, expr);
+    self.ctx.write_ref(AstProp::TypeArguments, &id, type_arg);
+
+    self.ctx.commit_node(id)
+  }
+
   pub fn write_ts_as_expr(
     &mut self,
     span: &Span,
@@ -2179,28 +2312,6 @@ impl TsEsTreeBuilder {
     self.ctx.commit_node(id)
   }
 
-  pub fn write_ts_interface(
-    &mut self,
-    span: &Span,
-    declare: bool,
-    ident: NodeRef,
-    type_param: Option<NodeRef>,
-    extends: Vec<NodeRef>,
-    body: NodeRef,
-  ) -> NodeRef {
-    let id = self.ctx.append_node(AstNode::TSInterface, span);
-
-    self.ctx.write_bool(AstProp::Declare, declare);
-    self.ctx.write_ref(AstProp::Id, &id, ident);
-    self.ctx.write_maybe_ref(AstProp::Extends, &id, type_param);
-    self
-      .ctx
-      .write_ref_vec(AstProp::TypeParameters, &id, extends);
-    self.ctx.write_ref(AstProp::Body, &id, body);
-
-    self.ctx.commit_node(id)
-  }
-
   pub fn write_ts_interface_decl(
     &mut self,
     span: &Span,
@@ -2214,10 +2325,10 @@ impl TsEsTreeBuilder {
 
     self.ctx.write_bool(AstProp::Declare, declare);
     self.ctx.write_ref(AstProp::Id, &id, ident);
-    self.ctx.write_maybe_ref(AstProp::Extends, &id, type_param);
     self
       .ctx
-      .write_ref_vec(AstProp::TypeParameters, &id, extends);
+      .write_maybe_undef_ref(AstProp::TypeParameters, &id, type_param);
+    self.ctx.write_ref_vec(AstProp::Extends, &id, extends);
     self.ctx.write_ref(AstProp::Body, &id, body);
 
     self.ctx.commit_node(id)
@@ -2245,7 +2356,7 @@ impl TsEsTreeBuilder {
       .append_node(AstNode::TSConstructSignatureDeclaration, span);
     self
       .ctx
-      .write_maybe_ref(AstProp::TypeParameters, &id, type_params);
+      .write_maybe_undef_ref(AstProp::TypeParameters, &id, type_params);
     self.ctx.write_ref_vec(AstProp::Params, &id, params);
     self.ctx.write_ref(AstProp::ReturnType, &id, return_type);
     self.ctx.commit_node(id)
@@ -2263,11 +2374,13 @@ impl TsEsTreeBuilder {
     self.ctx.write_bool(AstProp::Optional, false);
     self.ctx.write_bool(AstProp::Readonly, false);
     self.ctx.write_bool(AstProp::Static, false);
-    self.ctx.write_str(AstProp::Kind, "getter");
+    self.ctx.write_str(AstProp::Kind, "get");
     self.ctx.write_ref(AstProp::Key, &id, key);
+    self.ctx.write_ref_vec(AstProp::Params, &id, vec![]);
     self
       .ctx
-      .write_maybe_ref(AstProp::ReturnType, &id, return_type);
+      .write_maybe_undef_ref(AstProp::ReturnType, &id, return_type);
+    self.ctx.write_undefined(AstProp::TypeParameters);
 
     self.ctx.commit_node(id)
   }
@@ -2284,9 +2397,11 @@ impl TsEsTreeBuilder {
     self.ctx.write_bool(AstProp::Optional, false);
     self.ctx.write_bool(AstProp::Readonly, false);
     self.ctx.write_bool(AstProp::Static, false);
-    self.ctx.write_str(AstProp::Kind, "setter");
+    self.ctx.write_str(AstProp::Kind, "set");
     self.ctx.write_ref(AstProp::Key, &id, key);
     self.ctx.write_ref_vec(AstProp::Params, &id, vec![param]);
+    self.ctx.write_undefined(AstProp::ReturnType);
+    self.ctx.write_undefined(AstProp::TypeParameters);
 
     self.ctx.commit_node(id)
   }
@@ -2316,7 +2431,7 @@ impl TsEsTreeBuilder {
     self.ctx.write_ref_vec(AstProp::Params, &id, params);
     self
       .ctx
-      .write_maybe_ref(AstProp::ReturnType, &id, return_type);
+      .write_maybe_undef_ref(AstProp::ReturnType, &id, return_type);
 
     self.ctx.commit_node(id)
   }
@@ -2332,25 +2447,27 @@ impl TsEsTreeBuilder {
     self.ctx.write_ref(AstProp::Expression, &id, expr);
     self
       .ctx
-      .write_maybe_ref(AstProp::TypeArguments, &id, type_args);
+      .write_maybe_undef_ref(AstProp::TypeArguments, &id, type_args);
 
     self.ctx.commit_node(id)
   }
 
   pub fn write_ts_index_sig(
     &mut self,
     span: &Span,
+    is_static: bool,
     is_readonly: bool,
     params: Vec<NodeRef>,
     type_ann: Option<NodeRef>,
   ) -> NodeRef {
     let id = self.ctx.append_node(AstNode::TSIndexSignature, span);
 
+    self.ctx.write_bool(AstProp::Static, is_static);
     self.ctx.write_bool(AstProp::Readonly, is_readonly);
     self.ctx.write_ref_vec(AstProp::Parameters, &id, params);
     self
       .ctx
-      .write_maybe_ref(AstProp::TypeAnnotation, &id, type_ann);
+      .write_maybe_undef_ref(AstProp::TypeAnnotation, &id, type_ann);
 
     self.ctx.commit_node(id)
   }
@@ -2466,14 +2583,16 @@ impl TsEsTreeBuilder {
     self.ctx.commit_node(id)
   }
 
+  #[allow(clippy::too_many_arguments)]
   pub fn write_ts_mapped_type(
     &mut self,
     span: &Span,
     readonly: Option<TruePlusMinus>,
     optional: Option<TruePlusMinus>,
     name: Option<NodeRef>,
     type_ann: Option<NodeRef>,
-    type_param: NodeRef,
+    key: NodeRef,
+    constraint: NodeRef,
   ) -> NodeRef {
     let id = self.ctx.append_node(AstNode::TSMappedType, span);
 
@@ -2482,8 +2601,9 @@ impl TsEsTreeBuilder {
     self.ctx.write_maybe_ref(AstProp::NameType, &id, name);
     self
       .ctx
-      .write_maybe_ref(AstProp::TypeAnnotation, &id, type_ann);
-    self.ctx.write_ref(AstProp::TypeParameter, &id, type_param);
+      .write_maybe_undef_ref(AstProp::TypeAnnotation, &id, type_ann);
+    self.ctx.write_ref(AstProp::Key, &id, key);
+    self.ctx.write_ref(AstProp::Constraint, &id, constraint);
 
     self.ctx.commit_node(id)
   }
@@ -2559,7 +2679,7 @@ impl TsEsTreeBuilder {
     self.ctx.write_ref(AstProp::ExprName, &id, expr_name);
     self
       .ctx
-      .write_maybe_ref(AstProp::TypeArguments, &id, type_arg);
+      .write_maybe_undef_ref(AstProp::TypeArguments, &id, type_arg);
 
     self.ctx.commit_node(id)
   }
@@ -2575,7 +2695,7 @@ impl TsEsTreeBuilder {
     self.ctx.write_ref(AstProp::TypeName, &id, type_name);
     self
       .ctx
-      .write_maybe_ref(AstProp::TypeArguments, &id, type_arg);
+      .write_maybe_undef_ref(AstProp::TypeArguments, &id, type_arg);
 
     self.ctx.commit_node(id)
   }
@@ -2593,7 +2713,7 @@ impl TsEsTreeBuilder {
     self.ctx.write_ref(AstProp::ParameterName, &id, param_name);
     self
       .ctx
-      .write_maybe_ref(AstProp::TypeAnnotation, &id, type_ann);
+      .write_maybe_undef_ref(AstProp::TypeAnnotation, &id, type_ann);
 
     self.ctx.commit_node(id)
   }
@@ -2617,9 +2737,11 @@ impl TsEsTreeBuilder {
     span: &Span,
     label: NodeRef,
     elem_type: NodeRef,
+    optional: bool,
   ) -> NodeRef {
     let id = self.ctx.append_node(AstNode::TSNamedTupleMember, span);
 
+    self.ctx.write_bool(AstProp::Optional, optional);
     self.ctx.write_ref(AstProp::Label, &id, label);
     self.ctx.write_ref(AstProp::ElementType, &id, elem_type);
 
@@ -2692,10 +2814,18 @@ impl TsEsTreeBuilder {
   pub fn write_ts_fn_type(
     &mut self,
     span: &Span,
+    type_params: Option<NodeRef>,
     params: Vec<NodeRef>,
+    return_type: Option<NodeRef>,
   ) -> NodeRef {
     let id = self.ctx.append_node(AstNode::TSFunctionType, span);
     self.ctx.write_ref_vec(AstProp::Params, &id, params);
+    self
+      .ctx
+      .write_maybe_undef_ref(AstProp::ReturnType, &id, return_type);
+    self
+      .ctx
+      .write_maybe_undef_ref(AstProp::TypeParameters, &id, type_params);
     self.ctx.commit_node(id)
   }
 
@@ -2751,3 +2881,25 @@ pub enum TsKeywordKind {
   Never,
   Intrinsic,
 }
+
+#[derive(Debug)]
+pub enum TsModuleKind {
+  Global,
+  Namespace,
+  Module,
+}
+
+#[derive(Debug)]
+pub enum PropertyKind {
+  Get,
+  Init,
+  Set,
+}
+
+#[derive(Debug)]
+pub enum MethodKind {
+  Constructor,
+  Get,
+  Method,
+  Set,
+}

filename: tests/unit/lint_plugin_test.ts
patch: @@ -550,6 +550,11 @@ Deno.test("Plugin - ClassExpression", async (t) => {
   );
   await testSnapshot(t, "a = class { #foo: number = bar }", "ClassExpression");
   await testSnapshot(t, "a = class { static foo = bar }", "ClassExpression");
+  await testSnapshot(
+    t,
+    "a = class { static [key: string]: any }",
+    "ClassExpression",
+  );
   await testSnapshot(
     t,
     "a = class { static foo; static { foo = bar } }",
@@ -597,6 +602,7 @@ Deno.test("Plugin - MemberExpression", async (t) => {
 
 Deno.test("Plugin - MetaProperty", async (t) => {
   await testSnapshot(t, "import.meta", "MetaProperty");
+  await testSnapshot(t, "new.target", "MetaProperty");
 });
 
 Deno.test("Plugin - NewExpression", async (t) => {
@@ -680,6 +686,36 @@ Deno.test("Plugin - Literal", async (t) => {
   await testSnapshot(t, "/foo/g", "Literal");
 });
 
+// Stage 1 Proposal: https://github.com/tc39/proposal-grouped-and-auto-accessors
+Deno.test.ignore(
+  "Plugin - AccessorProperty + TSAbstractAccessorProperty",
+  async (t) => {
+    await testSnapshot(
+      t,
+      `class Foo { accessor foo = 1; }`,
+      "AccessorProperty",
+    );
+    await testSnapshot(
+      t,
+      `abstract class Foo { abstract accessor foo: number = 1; }`,
+      "TSAbstractAccessorProperty",
+    );
+  },
+);
+
+Deno.test("Plugin - Abstract class", async (t) => {
+  await testSnapshot(
+    t,
+    `abstract class SomeClass { abstract prop: string; }`,
+    "ClassDeclaration",
+  );
+  await testSnapshot(
+    t,
+    `abstract class SomeClass { abstract method(): string; }`,
+    "ClassDeclaration",
+  );
+});
+
 Deno.test("Plugin - JSXElement + JSXOpeningElement + JSXClosingElement + JSXAttr", async (t) => {
   await testSnapshot(t, "<div />", "JSXElement");
   await testSnapshot(t, "<div></div>", "JSXElement");
@@ -715,28 +751,60 @@ Deno.test("Plugin - TSEnumDeclaration", async (t) => {
   );
 });
 
-Deno.test("Plugin - TSInterface", async (t) => {
-  await testSnapshot(t, "interface A {}", "TSInterface");
-  await testSnapshot(t, "interface A<T> {}", "TSInterface");
-  await testSnapshot(t, "interface A extends Foo<T>, Bar<T> {}", "TSInterface");
-  await testSnapshot(t, "interface A { foo: any, bar?: any }", "TSInterface");
+Deno.test("Plugin - TSInterfaceDeclaration", async (t) => {
+  await testSnapshot(t, "interface A {}", "TSInterfaceDeclaration");
+  await testSnapshot(t, "interface A<T> {}", "TSInterfaceDeclaration");
+  await testSnapshot(
+    t,
+    "interface A extends Foo<T>, Bar<T> {}",
+    "TSInterfaceDeclaration",
+  );
+  await testSnapshot(
+    t,
+    "interface A { foo: any, bar?: any }",
+    "TSInterfaceDeclaration",
+  );
   await testSnapshot(
     t,
     "interface A { readonly [key: string]: any }",
-    "TSInterface",
+    "TSInterfaceDeclaration",
   );
 
-  await testSnapshot(t, "interface A { readonly a: any }", "TSInterface");
-  await testSnapshot(t, "interface A { <T>(a: T): T }", "TSInterface");
-  await testSnapshot(t, "interface A { new <T>(a: T): T }", "TSInterface");
-  await testSnapshot(t, "interface A { a: new <T>(a: T) => T }", "TSInterface");
-  await testSnapshot(t, "interface A { get a(): string }", "TSInterface");
-  await testSnapshot(t, "interface A { set a(v: string) }", "TSInterface");
+  await testSnapshot(
+    t,
+    "interface A { readonly a: any }",
+    "TSInterfaceDeclaration",
+  );
+  await testSnapshot(
+    t,
+    "interface A { <T>(a: T): T }",
+    "TSInterfaceDeclaration",
+  );
+  await testSnapshot(
+    t,
+    "interface A { new <T>(a: T): T }",
+    "TSInterfaceDeclaration",
+  );
+  await testSnapshot(
+    t,
+    "interface A { a: new <T>(a: T) => T }",
+    "TSInterfaceDeclaration",
+  );
+  await testSnapshot(
+    t,
+    "interface A { get a(): string }",
+    "TSInterfaceDeclaration",
+  );
+  await testSnapshot(
+    t,
+    "interface A { set a(v: string) }",
+    "TSInterfaceDeclaration",
+  );
 
   await testSnapshot(
     t,
     "interface A { a<T>(arg?: any, ...args: any[]): any }",
-    "TSInterface",
+    "TSInterfaceDeclaration",
   );
 });
 
@@ -762,6 +830,16 @@ Deno.test("Plugin - TSIntersectionType", async (t) => {
   await testSnapshot(t, "type A = B & C", "TSIntersectionType");
 });
 
+Deno.test("Plugin - TSInstantiationExpression", async (t) => {
+  await testSnapshot(t, "a<b>;", "TSInstantiationExpression");
+  await testSnapshot(t, "(a<b>)<c>;", "TSInstantiationExpression");
+  await testSnapshot(t, "(a<b>)<c>();", "TSInstantiationExpression");
+  await testSnapshot(t, "(a<b>)<c>();", "TSInstantiationExpression");
+  await testSnapshot(t, "(a<b>)<c>?.();", "TSInstantiationExpression");
+  await testSnapshot(t, "(a?.b<c>)<d>();", "TSInstantiationExpression");
+  await testSnapshot(t, "new (a<b>)<c>();", "TSInstantiationExpression");
+});
+
 Deno.test("Plugin - TSModuleDeclaration", async (t) => {
   await testSnapshot(t, "module A {}", "TSModuleDeclaration");
   await testSnapshot(
@@ -771,6 +849,15 @@ Deno.test("Plugin - TSModuleDeclaration", async (t) => {
   );
 });
 
+Deno.test("Plugin - TSDeclareFunction", async (t) => {
+  await testSnapshot(
+    t,
+    `async function foo(): any;
+async function foo(): any {}`,
+    "TSDeclareFunction",
+  );
+});
+
 Deno.test("Plugin - TSModuleDeclaration + TSModuleBlock", async (t) => {
   await testSnapshot(t, "module A {}", "TSModuleDeclaration");
   await testSnapshot(
@@ -871,6 +958,7 @@ Deno.test("Plugin - TSTupleType + TSArrayType", async (t) => {
   await testSnapshot(t, "type A = [number]", "TSTupleType");
   await testSnapshot(t, "type A = [x: number]", "TSTupleType");
   await testSnapshot(t, "type A = [x: number]", "TSTupleType");
+  await testSnapshot(t, "type A = [x?: number]", "TSTupleType");
   await testSnapshot(t, "type A = [...x: number[]]", "TSTupleType");
 });