• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1// There's lots of funny stuff due to the typing of ts.Node
2/* eslint-disable @typescript-eslint/no-explicit-any */
3import * as ts from 'typescript';
4import {
5  canContainDirective,
6  createError,
7  findNextToken,
8  getBinaryExpressionType,
9  getDeclarationKind,
10  getLastModifier,
11  getLineAndCharacterFor,
12  getLocFor,
13  getRange,
14  getTextForTokenKind,
15  getTSNodeAccessibility,
16  hasModifier,
17  isChildUnwrappableOptionalChain,
18  isComma,
19  isComputedProperty,
20  isESTreeClassMember,
21  isOptional,
22  TSError,
23  unescapeStringLiteralText,
24  isChainExpression,
25} from './node-utils';
26import { ParserWeakMap, ParserWeakMapESTreeToTSNode } from './parser-options';
27import {
28  AST_NODE_TYPES,
29  TSESTree,
30  TSNode,
31  TSESTreeToTSNode,
32} from './ts-estree';
33import { typescriptVersionIsAtLeast } from './version-check';
34
35const SyntaxKind = ts.SyntaxKind;
36
37interface ConverterOptions {
38  errorOnUnknownASTType: boolean;
39  useJSXTextNode: boolean;
40  shouldPreserveNodeMaps: boolean;
41}
42
43/**
44 * Extends and formats a given error object
45 * @param error the error object
46 * @returns converted error object
47 */
48export function convertError(error: any): TSError {
49  return createError(
50    error.file,
51    error.start,
52    error.message || error.messageText,
53  );
54}
55
56export interface ASTMaps {
57  esTreeNodeToTSNodeMap: ParserWeakMapESTreeToTSNode;
58  tsNodeToESTreeNodeMap: ParserWeakMap<TSNode, TSESTree.Node>;
59}
60
61export class Converter {
62  private readonly ast: ts.SourceFile;
63  private readonly options: ConverterOptions;
64  private readonly esTreeNodeToTSNodeMap = new WeakMap();
65  private readonly tsNodeToESTreeNodeMap = new WeakMap();
66
67  private allowPattern = false;
68  private inTypeMode = false;
69
70  /**
71   * Converts a TypeScript node into an ESTree node
72   * @param ast the full TypeScript AST
73   * @param options additional options for the conversion
74   * @returns the converted ESTreeNode
75   */
76  constructor(ast: ts.SourceFile, options: ConverterOptions) {
77    this.ast = ast;
78    this.options = { ...options };
79  }
80
81  getASTMaps(): ASTMaps {
82    return {
83      esTreeNodeToTSNodeMap: this.esTreeNodeToTSNodeMap,
84      tsNodeToESTreeNodeMap: this.tsNodeToESTreeNodeMap,
85    };
86  }
87
88  convertProgram(): TSESTree.Program {
89    return this.converter(this.ast) as TSESTree.Program;
90  }
91
92  /**
93   * Converts a TypeScript node into an ESTree node.
94   * @param node the child ts.Node
95   * @param parent parentNode
96   * @param inTypeMode flag to determine if we are in typeMode
97   * @param allowPattern flag to determine if patterns are allowed
98   * @returns the converted ESTree node
99   */
100  private converter(
101    node?: ts.Node,
102    parent?: ts.Node,
103    inTypeMode?: boolean,
104    allowPattern?: boolean,
105  ): any {
106    /**
107     * Exit early for null and undefined
108     */
109    if (!node) {
110      return null;
111    }
112
113    const typeMode = this.inTypeMode;
114    const pattern = this.allowPattern;
115    if (inTypeMode !== undefined) {
116      this.inTypeMode = inTypeMode;
117    }
118    if (allowPattern !== undefined) {
119      this.allowPattern = allowPattern;
120    }
121
122    const result = this.convertNode(
123      node as TSNode,
124      (parent ?? node.parent) as TSNode,
125    );
126
127    this.registerTSNodeInNodeMap(node, result);
128
129    this.inTypeMode = typeMode;
130    this.allowPattern = pattern;
131    return result;
132  }
133
134  /**
135   * Fixes the exports of the given ts.Node
136   * @param node the ts.Node
137   * @param result result
138   * @returns the ESTreeNode with fixed exports
139   */
140  private fixExports<T extends TSESTree.ExportDeclaration>(
141    node:
142      | ts.FunctionDeclaration
143      | ts.VariableStatement
144      | ts.ClassDeclaration
145      | ts.ClassExpression
146      | ts.TypeAliasDeclaration
147      | ts.InterfaceDeclaration
148      | ts.EnumDeclaration
149      | ts.ModuleDeclaration,
150    result: T,
151  ): TSESTree.ExportDefaultDeclaration | TSESTree.ExportNamedDeclaration | T {
152    // check for exports
153    if (node.modifiers && node.modifiers[0].kind === SyntaxKind.ExportKeyword) {
154      /**
155       * Make sure that original node is registered instead of export
156       */
157      this.registerTSNodeInNodeMap(node, result);
158
159      const exportKeyword = node.modifiers[0];
160      const nextModifier = node.modifiers[1];
161      const declarationIsDefault =
162        nextModifier && nextModifier.kind === SyntaxKind.DefaultKeyword;
163
164      const varToken = declarationIsDefault
165        ? findNextToken(nextModifier, this.ast, this.ast)
166        : findNextToken(exportKeyword, this.ast, this.ast);
167
168      result.range[0] = varToken!.getStart(this.ast);
169      result.loc = getLocFor(result.range[0], result.range[1], this.ast);
170
171      if (declarationIsDefault) {
172        return this.createNode<TSESTree.ExportDefaultDeclaration>(node, {
173          type: AST_NODE_TYPES.ExportDefaultDeclaration,
174          declaration: result,
175          range: [exportKeyword.getStart(this.ast), result.range[1]],
176          exportKind: 'value',
177        });
178      } else {
179        const isType =
180          result.type === AST_NODE_TYPES.TSInterfaceDeclaration ||
181          result.type === AST_NODE_TYPES.TSTypeAliasDeclaration;
182        const isDeclare = result.declare === true;
183        return this.createNode<TSESTree.ExportNamedDeclaration>(node, {
184          type: AST_NODE_TYPES.ExportNamedDeclaration,
185          declaration: result,
186          specifiers: [],
187          source: null,
188          exportKind: isType || isDeclare ? 'type' : 'value',
189          range: [exportKeyword.getStart(this.ast), result.range[1]],
190        });
191      }
192    }
193
194    return result;
195  }
196
197  /**
198   * Register specific TypeScript node into map with first ESTree node provided
199   */
200  private registerTSNodeInNodeMap(
201    node: ts.Node,
202    result: TSESTree.BaseNode | null,
203  ): void {
204    if (result && this.options.shouldPreserveNodeMaps) {
205      if (!this.tsNodeToESTreeNodeMap.has(node)) {
206        this.tsNodeToESTreeNodeMap.set(node, result);
207      }
208    }
209  }
210
211  /**
212   * Converts a TypeScript node into an ESTree node.
213   * @param child the child ts.Node
214   * @param parent parentNode
215   * @returns the converted ESTree node
216   */
217  private convertPattern(child?: ts.Node, parent?: ts.Node): any | null {
218    return this.converter(child, parent, this.inTypeMode, true);
219  }
220
221  /**
222   * Converts a TypeScript node into an ESTree node.
223   * @param child the child ts.Node
224   * @param parent parentNode
225   * @returns the converted ESTree node
226   */
227  private convertChild(child?: ts.Node, parent?: ts.Node): any | null {
228    return this.converter(child, parent, this.inTypeMode, false);
229  }
230
231  /**
232   * Converts a TypeScript node into an ESTree node.
233   * @param child the child ts.Node
234   * @param parent parentNode
235   * @returns the converted ESTree node
236   */
237  private convertType(child?: ts.Node, parent?: ts.Node): any | null {
238    return this.converter(child, parent, true, false);
239  }
240
241  private createNode<T extends TSESTree.Node = TSESTree.Node>(
242    node: TSESTreeToTSNode<T>,
243    data: TSESTree.OptionalRangeAndLoc<T>,
244  ): T {
245    const result = data;
246    if (!result.range) {
247      result.range = getRange(
248        // this is completely valid, but TS hates it
249        node as never,
250        this.ast,
251      );
252    }
253    if (!result.loc) {
254      result.loc = getLocFor(result.range[0], result.range[1], this.ast);
255    }
256
257    if (result && this.options.shouldPreserveNodeMaps) {
258      this.esTreeNodeToTSNodeMap.set(result, node);
259    }
260    return result as T;
261  }
262
263  private convertBindingNameWithTypeAnnotation(
264    name: ts.BindingName,
265    tsType: ts.TypeNode | undefined,
266    parent?: ts.Node,
267  ): TSESTree.BindingName {
268    const id = this.convertPattern(name);
269
270    if (tsType) {
271      id.typeAnnotation = this.convertTypeAnnotation(tsType, parent);
272      this.fixParentLocation(id, id.typeAnnotation.range);
273    }
274
275    return id;
276  }
277
278  /**
279   * Converts a child into a type annotation. This creates an intermediary
280   * TypeAnnotation node to match what Flow does.
281   * @param child The TypeScript AST node to convert.
282   * @param parent parentNode
283   * @returns The type annotation node.
284   */
285  private convertTypeAnnotation(
286    child: ts.TypeNode,
287    parent: ts.Node | undefined,
288  ): TSESTree.TSTypeAnnotation {
289    // in FunctionType and ConstructorType typeAnnotation has 2 characters `=>` and in other places is just colon
290    const offset =
291      parent?.kind === SyntaxKind.FunctionType ||
292      parent?.kind === SyntaxKind.ConstructorType
293        ? 2
294        : 1;
295    const annotationStartCol = child.getFullStart() - offset;
296
297    const loc = getLocFor(annotationStartCol, child.end, this.ast);
298    return {
299      type: AST_NODE_TYPES.TSTypeAnnotation,
300      loc,
301      range: [annotationStartCol, child.end],
302      typeAnnotation: this.convertType(child),
303    };
304  }
305
306  /**
307   * Coverts body Nodes and add a directive field to StringLiterals
308   * @param nodes of ts.Node
309   * @param parent parentNode
310   * @returns Array of body statements
311   */
312  private convertBodyExpressions(
313    nodes: ts.NodeArray<ts.Statement>,
314    parent: ts.SourceFile | ts.Block | ts.ModuleBlock,
315  ): TSESTree.Statement[] {
316    let allowDirectives = canContainDirective(parent);
317
318    return (
319      nodes
320        .map(statement => {
321          const child = this.convertChild(statement);
322          if (allowDirectives) {
323            if (
324              child?.expression &&
325              ts.isExpressionStatement(statement) &&
326              ts.isStringLiteral(statement.expression)
327            ) {
328              const raw = child.expression.raw;
329              child.directive = raw.slice(1, -1);
330              return child; // child can be null, but it's filtered below
331            } else {
332              allowDirectives = false;
333            }
334          }
335          return child; // child can be null, but it's filtered below
336        })
337        // filter out unknown nodes for now
338        .filter(statement => statement)
339    );
340  }
341
342  /**
343   * Converts a ts.Node's typeArguments to TSTypeParameterInstantiation node
344   * @param typeArguments ts.NodeArray typeArguments
345   * @param node parent used to create this node
346   * @returns TypeParameterInstantiation node
347   */
348  private convertTypeArgumentsToTypeParameters(
349    typeArguments: ts.NodeArray<ts.TypeNode>,
350    node: TSESTreeToTSNode<TSESTree.TSTypeParameterInstantiation>,
351  ): TSESTree.TSTypeParameterInstantiation {
352    const greaterThanToken = findNextToken(typeArguments, this.ast, this.ast)!;
353
354    return this.createNode<TSESTree.TSTypeParameterInstantiation>(node, {
355      type: AST_NODE_TYPES.TSTypeParameterInstantiation,
356      range: [typeArguments.pos - 1, greaterThanToken.end],
357      params: typeArguments.map(typeArgument => this.convertType(typeArgument)),
358    });
359  }
360
361  /**
362   * Converts a ts.Node's typeParameters to TSTypeParameterDeclaration node
363   * @param typeParameters ts.Node typeParameters
364   * @returns TypeParameterDeclaration node
365   */
366  private convertTSTypeParametersToTypeParametersDeclaration(
367    typeParameters: ts.NodeArray<ts.TypeParameterDeclaration>,
368  ): TSESTree.TSTypeParameterDeclaration {
369    const greaterThanToken = findNextToken(typeParameters, this.ast, this.ast)!;
370
371    return {
372      type: AST_NODE_TYPES.TSTypeParameterDeclaration,
373      range: [typeParameters.pos - 1, greaterThanToken.end],
374      loc: getLocFor(typeParameters.pos - 1, greaterThanToken.end, this.ast),
375      params: typeParameters.map(typeParameter =>
376        this.convertType(typeParameter),
377      ),
378    };
379  }
380
381  /**
382   * Converts an array of ts.Node parameters into an array of ESTreeNode params
383   * @param parameters An array of ts.Node params to be converted
384   * @returns an array of converted ESTreeNode params
385   */
386  private convertParameters(
387    parameters: ts.NodeArray<ts.ParameterDeclaration>,
388  ): TSESTree.Parameter[] {
389    if (!parameters || !parameters.length) {
390      return [];
391    }
392    return parameters.map(param => {
393      const convertedParam = this.convertChild(param) as TSESTree.Parameter;
394
395      if (param.decorators?.length) {
396        convertedParam.decorators = param.decorators.map(el =>
397          this.convertChild(el),
398        );
399      }
400      return convertedParam;
401    });
402  }
403
404  private convertChainExpression(
405    node: TSESTree.ChainElement,
406    tsNode:
407      | ts.PropertyAccessExpression
408      | ts.ElementAccessExpression
409      | ts.CallExpression
410      | ts.NonNullExpression,
411  ): TSESTree.ChainExpression | TSESTree.ChainElement {
412    const { child, isOptional } = ((): {
413      child: TSESTree.Node;
414      isOptional: boolean;
415    } => {
416      if (node.type === AST_NODE_TYPES.MemberExpression) {
417        return { child: node.object, isOptional: node.optional };
418      }
419      if (node.type === AST_NODE_TYPES.CallExpression) {
420        return { child: node.callee, isOptional: node.optional };
421      }
422      return { child: node.expression, isOptional: false };
423    })();
424    const isChildUnwrappable = isChildUnwrappableOptionalChain(tsNode, child);
425
426    if (!isChildUnwrappable && !isOptional) {
427      return node;
428    }
429
430    if (isChildUnwrappable && isChainExpression(child)) {
431      // unwrap the chain expression child
432      const newChild = child.expression;
433      if (node.type === AST_NODE_TYPES.MemberExpression) {
434        node.object = newChild;
435      } else if (node.type === AST_NODE_TYPES.CallExpression) {
436        node.callee = newChild;
437      } else {
438        node.expression = newChild;
439      }
440    }
441
442    return this.createNode<TSESTree.ChainExpression>(tsNode, {
443      type: AST_NODE_TYPES.ChainExpression,
444      expression: node,
445    });
446  }
447
448  /**
449   * For nodes that are copied directly from the TypeScript AST into
450   * ESTree mostly as-is. The only difference is the addition of a type
451   * property instead of a kind property. Recursively copies all children.
452   */
453  private deeplyCopy(node: TSNode): any {
454    if (node.kind === ts.SyntaxKind.JSDocFunctionType) {
455      throw createError(
456        this.ast,
457        node.pos,
458        'JSDoc types can only be used inside documentation comments.',
459      );
460    }
461
462    const customType = `TS${SyntaxKind[node.kind]}` as AST_NODE_TYPES;
463
464    /**
465     * If the "errorOnUnknownASTType" option is set to true, throw an error,
466     * otherwise fallback to just including the unknown type as-is.
467     */
468    if (this.options.errorOnUnknownASTType && !AST_NODE_TYPES[customType]) {
469      throw new Error(`Unknown AST_NODE_TYPE: "${customType}"`);
470    }
471
472    const result = this.createNode<any>(node, {
473      type: customType,
474    });
475
476    if ('type' in node) {
477      result.typeAnnotation =
478        node.type && 'kind' in node.type && ts.isTypeNode(node.type)
479          ? this.convertTypeAnnotation(node.type, node)
480          : null;
481    }
482    if ('typeArguments' in node) {
483      result.typeParameters =
484        node.typeArguments && 'pos' in node.typeArguments
485          ? this.convertTypeArgumentsToTypeParameters(node.typeArguments, node)
486          : null;
487    }
488    if ('typeParameters' in node) {
489      result.typeParameters =
490        node.typeParameters && 'pos' in node.typeParameters
491          ? this.convertTSTypeParametersToTypeParametersDeclaration(
492              node.typeParameters,
493            )
494          : null;
495    }
496    if ('decorators' in node && node.decorators && node.decorators.length) {
497      result.decorators = node.decorators.map(el => this.convertChild(el));
498    }
499
500    Object.entries<any>(node)
501      .filter(
502        ([key]) =>
503          !/^(?:_children|kind|parent|pos|end|flags|modifierFlagsCache|jsDoc|type|typeArguments|typeParameters|decorators)$/.test(
504            key,
505          ),
506      )
507      .forEach(([key, value]) => {
508        if (Array.isArray(value)) {
509          result[key] = value.map(el => this.convertChild(el));
510        } else if (value && typeof value === 'object' && value.kind) {
511          // need to check node[key].kind to ensure we don't try to convert a symbol
512          result[key] = this.convertChild(value);
513        } else {
514          result[key] = value;
515        }
516      });
517    return result;
518  }
519
520  /**
521   * Converts a TypeScript JSX node.tagName into an ESTree node.name
522   * @param node the tagName object from a JSX ts.Node
523   * @param parent
524   * @returns the converted ESTree name object
525   */
526  private convertJSXTagName(
527    node: ts.JsxTagNameExpression,
528    parent: ts.Node,
529  ): TSESTree.JSXMemberExpression | TSESTree.JSXIdentifier {
530    let result: TSESTree.JSXMemberExpression | TSESTree.JSXIdentifier;
531    switch (node.kind) {
532      case SyntaxKind.PropertyAccessExpression:
533        if (node.name.kind === SyntaxKind.PrivateIdentifier) {
534          // This is one of the few times where TS explicitly errors, and doesn't even gracefully handle the syntax.
535          // So we shouldn't ever get into this state to begin with.
536          throw new Error('Non-private identifier expected.');
537        }
538
539        result = this.createNode<TSESTree.JSXMemberExpression>(node, {
540          type: AST_NODE_TYPES.JSXMemberExpression,
541          object: this.convertJSXTagName(node.expression, parent),
542          property: this.convertJSXTagName(
543            node.name,
544            parent,
545          ) as TSESTree.JSXIdentifier,
546        });
547        break;
548
549      case SyntaxKind.ThisKeyword:
550        result = this.createNode<TSESTree.JSXIdentifier>(node, {
551          type: AST_NODE_TYPES.JSXIdentifier,
552          name: 'this',
553        });
554        break;
555
556      case SyntaxKind.Identifier:
557      default:
558        result = this.createNode<TSESTree.JSXIdentifier>(node, {
559          type: AST_NODE_TYPES.JSXIdentifier,
560          name: node.text,
561        });
562        break;
563    }
564
565    this.registerTSNodeInNodeMap(node, result);
566    return result;
567  }
568
569  /**
570   * Applies the given TS modifiers to the given result object.
571   * @param result
572   * @param modifiers original ts.Nodes from the node.modifiers array
573   * @returns the current result object will be mutated
574   * @deprecated This method adds not standardized `modifiers` property in nodes
575   */
576  private applyModifiersToResult(
577    result: TSESTree.TSEnumDeclaration | TSESTree.TSModuleDeclaration,
578    modifiers?: ts.ModifiersArray,
579  ): void {
580    if (!modifiers || !modifiers.length) {
581      return;
582    }
583    /**
584     * Some modifiers are explicitly handled by applying them as
585     * boolean values on the result node. As well as adding them
586     * to the result, we remove them from the array, so that they
587     * are not handled twice.
588     */
589    const handledModifierIndices: { [key: number]: boolean } = {};
590    for (let i = 0; i < modifiers.length; i++) {
591      const modifier = modifiers[i];
592      switch (modifier.kind) {
593        /**
594         * Ignore ExportKeyword and DefaultKeyword, they are handled
595         * via the fixExports utility function
596         */
597        case SyntaxKind.ExportKeyword:
598        case SyntaxKind.DefaultKeyword:
599          handledModifierIndices[i] = true;
600          break;
601        case SyntaxKind.ConstKeyword:
602          (result as any).const = true;
603          handledModifierIndices[i] = true;
604          break;
605        case SyntaxKind.DeclareKeyword:
606          result.declare = true;
607          handledModifierIndices[i] = true;
608          break;
609        default:
610      }
611    }
612    /**
613     * If there are still valid modifiers available which have
614     * not been explicitly handled above, we just convert and
615     * add the modifiers array to the result node.
616     */
617    const remainingModifiers = modifiers.filter(
618      (_, i) => !handledModifierIndices[i],
619    );
620    if (!remainingModifiers || !remainingModifiers.length) {
621      return;
622    }
623    result.modifiers = remainingModifiers.map(el => this.convertChild(el));
624  }
625
626  /**
627   * Uses the provided range location to adjust the location data of the given Node
628   * @param result The node that will have its location data mutated
629   * @param childRange The child node range used to expand location
630   */
631  private fixParentLocation(
632    result: TSESTree.BaseNode,
633    childRange: [number, number],
634  ): void {
635    if (childRange[0] < result.range[0]) {
636      result.range[0] = childRange[0];
637      result.loc.start = getLineAndCharacterFor(result.range[0], this.ast);
638    }
639    if (childRange[1] > result.range[1]) {
640      result.range[1] = childRange[1];
641      result.loc.end = getLineAndCharacterFor(result.range[1], this.ast);
642    }
643  }
644
645  /**
646   * Converts a TypeScript node into an ESTree node.
647   * The core of the conversion logic:
648   * Identify and convert each relevant TypeScript SyntaxKind
649   * @param node the child ts.Node
650   * @param parent parentNode
651   * @returns the converted ESTree node
652   */
653  private convertNode(node: TSNode, parent: TSNode): TSESTree.Node | null {
654    switch (node.kind) {
655      case SyntaxKind.SourceFile: {
656        return this.createNode<TSESTree.Program>(node, {
657          type: AST_NODE_TYPES.Program,
658          body: this.convertBodyExpressions(node.statements, node),
659          sourceType: node.externalModuleIndicator ? 'module' : 'script',
660          range: [node.getStart(this.ast), node.endOfFileToken.end],
661        });
662      }
663
664      case SyntaxKind.Block: {
665        return this.createNode<TSESTree.BlockStatement>(node, {
666          type: AST_NODE_TYPES.BlockStatement,
667          body: this.convertBodyExpressions(node.statements, node),
668        });
669      }
670
671      case SyntaxKind.Identifier: {
672        return this.createNode<TSESTree.Identifier>(node, {
673          type: AST_NODE_TYPES.Identifier,
674          name: node.text,
675        });
676      }
677
678      case SyntaxKind.WithStatement:
679        return this.createNode<TSESTree.WithStatement>(node, {
680          type: AST_NODE_TYPES.WithStatement,
681          object: this.convertChild(node.expression),
682          body: this.convertChild(node.statement),
683        });
684
685      // Control Flow
686
687      case SyntaxKind.ReturnStatement:
688        return this.createNode<TSESTree.ReturnStatement>(node, {
689          type: AST_NODE_TYPES.ReturnStatement,
690          argument: this.convertChild(node.expression),
691        });
692
693      case SyntaxKind.LabeledStatement:
694        return this.createNode<TSESTree.LabeledStatement>(node, {
695          type: AST_NODE_TYPES.LabeledStatement,
696          label: this.convertChild(node.label),
697          body: this.convertChild(node.statement),
698        });
699
700      case SyntaxKind.ContinueStatement:
701        return this.createNode<TSESTree.ContinueStatement>(node, {
702          type: AST_NODE_TYPES.ContinueStatement,
703          label: this.convertChild(node.label),
704        });
705
706      case SyntaxKind.BreakStatement:
707        return this.createNode<TSESTree.BreakStatement>(node, {
708          type: AST_NODE_TYPES.BreakStatement,
709          label: this.convertChild(node.label),
710        });
711
712      // Choice
713
714      case SyntaxKind.IfStatement:
715        return this.createNode<TSESTree.IfStatement>(node, {
716          type: AST_NODE_TYPES.IfStatement,
717          test: this.convertChild(node.expression),
718          consequent: this.convertChild(node.thenStatement),
719          alternate: this.convertChild(node.elseStatement),
720        });
721
722      case SyntaxKind.SwitchStatement:
723        return this.createNode<TSESTree.SwitchStatement>(node, {
724          type: AST_NODE_TYPES.SwitchStatement,
725          discriminant: this.convertChild(node.expression),
726          cases: node.caseBlock.clauses.map(el => this.convertChild(el)),
727        });
728
729      case SyntaxKind.CaseClause:
730      case SyntaxKind.DefaultClause:
731        return this.createNode<TSESTree.SwitchCase>(node, {
732          type: AST_NODE_TYPES.SwitchCase,
733          // expression is present in case only
734          test:
735            node.kind === SyntaxKind.CaseClause
736              ? this.convertChild(node.expression)
737              : null,
738          consequent: node.statements.map(el => this.convertChild(el)),
739        });
740
741      // Exceptions
742
743      case SyntaxKind.ThrowStatement:
744        return this.createNode<TSESTree.ThrowStatement>(node, {
745          type: AST_NODE_TYPES.ThrowStatement,
746          argument: this.convertChild(node.expression),
747        });
748
749      case SyntaxKind.TryStatement:
750        return this.createNode<TSESTree.TryStatement>(node, {
751          type: AST_NODE_TYPES.TryStatement,
752          block: this.convertChild(node.tryBlock),
753          handler: this.convertChild(node.catchClause),
754          finalizer: this.convertChild(node.finallyBlock),
755        });
756
757      case SyntaxKind.CatchClause:
758        return this.createNode<TSESTree.CatchClause>(node, {
759          type: AST_NODE_TYPES.CatchClause,
760          param: node.variableDeclaration
761            ? this.convertBindingNameWithTypeAnnotation(
762                node.variableDeclaration.name,
763                node.variableDeclaration.type,
764              )
765            : null,
766          body: this.convertChild(node.block),
767        });
768
769      // Loops
770
771      case SyntaxKind.WhileStatement:
772        return this.createNode<TSESTree.WhileStatement>(node, {
773          type: AST_NODE_TYPES.WhileStatement,
774          test: this.convertChild(node.expression),
775          body: this.convertChild(node.statement),
776        });
777
778      /**
779       * Unlike other parsers, TypeScript calls a "DoWhileStatement"
780       * a "DoStatement"
781       */
782      case SyntaxKind.DoStatement:
783        return this.createNode<TSESTree.DoWhileStatement>(node, {
784          type: AST_NODE_TYPES.DoWhileStatement,
785          test: this.convertChild(node.expression),
786          body: this.convertChild(node.statement),
787        });
788
789      case SyntaxKind.ForStatement:
790        return this.createNode<TSESTree.ForStatement>(node, {
791          type: AST_NODE_TYPES.ForStatement,
792          init: this.convertChild(node.initializer),
793          test: this.convertChild(node.condition),
794          update: this.convertChild(node.incrementor),
795          body: this.convertChild(node.statement),
796        });
797
798      case SyntaxKind.ForInStatement:
799        return this.createNode<TSESTree.ForInStatement>(node, {
800          type: AST_NODE_TYPES.ForInStatement,
801          left: this.convertPattern(node.initializer),
802          right: this.convertChild(node.expression),
803          body: this.convertChild(node.statement),
804        });
805
806      case SyntaxKind.ForOfStatement:
807        return this.createNode<TSESTree.ForOfStatement>(node, {
808          type: AST_NODE_TYPES.ForOfStatement,
809          left: this.convertPattern(node.initializer),
810          right: this.convertChild(node.expression),
811          body: this.convertChild(node.statement),
812          await: Boolean(
813            node.awaitModifier &&
814              node.awaitModifier.kind === SyntaxKind.AwaitKeyword,
815          ),
816        });
817
818      // Declarations
819
820      case SyntaxKind.FunctionDeclaration: {
821        const isDeclare = hasModifier(SyntaxKind.DeclareKeyword, node);
822
823        const result = this.createNode<
824          TSESTree.TSDeclareFunction | TSESTree.FunctionDeclaration
825        >(node, {
826          type:
827            isDeclare || !node.body
828              ? AST_NODE_TYPES.TSDeclareFunction
829              : AST_NODE_TYPES.FunctionDeclaration,
830          id: this.convertChild(node.name),
831          generator: !!node.asteriskToken,
832          expression: false,
833          async: hasModifier(SyntaxKind.AsyncKeyword, node),
834          params: this.convertParameters(node.parameters),
835          body: this.convertChild(node.body) || undefined,
836        });
837
838        // Process returnType
839        if (node.type) {
840          result.returnType = this.convertTypeAnnotation(node.type, node);
841        }
842
843        if (isDeclare) {
844          result.declare = true;
845        }
846
847        // Process typeParameters
848        if (node.typeParameters) {
849          result.typeParameters = this.convertTSTypeParametersToTypeParametersDeclaration(
850            node.typeParameters,
851          );
852        }
853
854        // check for exports
855        return this.fixExports(node, result);
856      }
857
858      case SyntaxKind.VariableDeclaration: {
859        const result = this.createNode<TSESTree.VariableDeclarator>(node, {
860          type: AST_NODE_TYPES.VariableDeclarator,
861          id: this.convertBindingNameWithTypeAnnotation(
862            node.name,
863            node.type,
864            node,
865          ),
866          init: this.convertChild(node.initializer),
867        });
868
869        if (node.exclamationToken) {
870          result.definite = true;
871        }
872
873        return result;
874      }
875
876      case SyntaxKind.VariableStatement: {
877        const result = this.createNode<TSESTree.VariableDeclaration>(node, {
878          type: AST_NODE_TYPES.VariableDeclaration,
879          declarations: node.declarationList.declarations.map(el =>
880            this.convertChild(el),
881          ),
882          kind: getDeclarationKind(node.declarationList),
883        });
884
885        /**
886         * Semantically, decorators are not allowed on variable declarations,
887         * but the TypeScript compiler will parse them and produce a valid AST,
888         * so we handle them here too.
889         */
890        if (node.decorators) {
891          (result as any).decorators = node.decorators.map(el =>
892            this.convertChild(el),
893          );
894        }
895
896        if (hasModifier(SyntaxKind.DeclareKeyword, node)) {
897          result.declare = true;
898        }
899
900        // check for exports
901        return this.fixExports(node, result);
902      }
903
904      // mostly for for-of, for-in
905      case SyntaxKind.VariableDeclarationList:
906        return this.createNode<TSESTree.VariableDeclaration>(node, {
907          type: AST_NODE_TYPES.VariableDeclaration,
908          declarations: node.declarations.map(el => this.convertChild(el)),
909          kind: getDeclarationKind(node),
910        });
911
912      // Expressions
913
914      case SyntaxKind.ExpressionStatement:
915        return this.createNode<TSESTree.ExpressionStatement>(node, {
916          type: AST_NODE_TYPES.ExpressionStatement,
917          expression: this.convertChild(node.expression),
918        });
919
920      case SyntaxKind.ThisKeyword:
921        return this.createNode<TSESTree.ThisExpression>(node, {
922          type: AST_NODE_TYPES.ThisExpression,
923        });
924
925      case SyntaxKind.ArrayLiteralExpression: {
926        // TypeScript uses ArrayLiteralExpression in destructuring assignment, too
927        if (this.allowPattern) {
928          return this.createNode<TSESTree.ArrayPattern>(node, {
929            type: AST_NODE_TYPES.ArrayPattern,
930            elements: node.elements.map(el => this.convertPattern(el)),
931          });
932        } else {
933          return this.createNode<TSESTree.ArrayExpression>(node, {
934            type: AST_NODE_TYPES.ArrayExpression,
935            elements: node.elements.map(el => this.convertChild(el)),
936          });
937        }
938      }
939
940      case SyntaxKind.ObjectLiteralExpression: {
941        // TypeScript uses ObjectLiteralExpression in destructuring assignment, too
942        if (this.allowPattern) {
943          return this.createNode<TSESTree.ObjectPattern>(node, {
944            type: AST_NODE_TYPES.ObjectPattern,
945            properties: node.properties.map(el => this.convertPattern(el)),
946          });
947        } else {
948          return this.createNode<TSESTree.ObjectExpression>(node, {
949            type: AST_NODE_TYPES.ObjectExpression,
950            properties: node.properties.map(el => this.convertChild(el)),
951          });
952        }
953      }
954
955      case SyntaxKind.PropertyAssignment:
956        return this.createNode<TSESTree.Property>(node, {
957          type: AST_NODE_TYPES.Property,
958          key: this.convertChild(node.name),
959          value: this.converter(
960            node.initializer,
961            node,
962            this.inTypeMode,
963            this.allowPattern,
964          ),
965          computed: isComputedProperty(node.name),
966          method: false,
967          shorthand: false,
968          kind: 'init',
969        });
970
971      case SyntaxKind.ShorthandPropertyAssignment: {
972        if (node.objectAssignmentInitializer) {
973          return this.createNode<TSESTree.Property>(node, {
974            type: AST_NODE_TYPES.Property,
975            key: this.convertChild(node.name),
976            value: this.createNode<TSESTree.AssignmentPattern>(node, {
977              type: AST_NODE_TYPES.AssignmentPattern,
978              left: this.convertPattern(node.name),
979              right: this.convertChild(node.objectAssignmentInitializer),
980            }),
981            computed: false,
982            method: false,
983            shorthand: true,
984            kind: 'init',
985          });
986        } else {
987          return this.createNode<TSESTree.Property>(node, {
988            type: AST_NODE_TYPES.Property,
989            key: this.convertChild(node.name),
990            value: this.convertChild(node.name),
991            computed: false,
992            method: false,
993            shorthand: true,
994            kind: 'init',
995          });
996        }
997      }
998
999      case SyntaxKind.ComputedPropertyName:
1000        return this.convertChild(node.expression);
1001
1002      case SyntaxKind.PropertyDeclaration: {
1003        const isAbstract = hasModifier(SyntaxKind.AbstractKeyword, node);
1004        const result = this.createNode<
1005          TSESTree.TSAbstractClassProperty | TSESTree.ClassProperty
1006        >(node, {
1007          type: isAbstract
1008            ? AST_NODE_TYPES.TSAbstractClassProperty
1009            : AST_NODE_TYPES.ClassProperty,
1010          key: this.convertChild(node.name),
1011          value: this.convertChild(node.initializer),
1012          computed: isComputedProperty(node.name),
1013          static: hasModifier(SyntaxKind.StaticKeyword, node),
1014          readonly: hasModifier(SyntaxKind.ReadonlyKeyword, node) || undefined,
1015          declare: hasModifier(SyntaxKind.DeclareKeyword, node),
1016        });
1017
1018        if (node.type) {
1019          result.typeAnnotation = this.convertTypeAnnotation(node.type, node);
1020        }
1021
1022        if (node.decorators) {
1023          result.decorators = node.decorators.map(el => this.convertChild(el));
1024        }
1025
1026        const accessibility = getTSNodeAccessibility(node);
1027        if (accessibility) {
1028          result.accessibility = accessibility;
1029        }
1030
1031        if (
1032          (node.name.kind === SyntaxKind.Identifier ||
1033            node.name.kind === SyntaxKind.ComputedPropertyName) &&
1034          node.questionToken
1035        ) {
1036          result.optional = true;
1037        }
1038
1039        if (node.exclamationToken) {
1040          result.definite = true;
1041        }
1042
1043        if (result.key.type === AST_NODE_TYPES.Literal && node.questionToken) {
1044          result.optional = true;
1045        }
1046        return result;
1047      }
1048
1049      case SyntaxKind.GetAccessor:
1050      case SyntaxKind.SetAccessor:
1051      case SyntaxKind.MethodDeclaration: {
1052        const method = this.createNode<
1053          TSESTree.TSEmptyBodyFunctionExpression | TSESTree.FunctionExpression
1054        >(node, {
1055          type: !node.body
1056            ? AST_NODE_TYPES.TSEmptyBodyFunctionExpression
1057            : AST_NODE_TYPES.FunctionExpression,
1058          id: null,
1059          generator: !!node.asteriskToken,
1060          expression: false, // ESTreeNode as ESTreeNode here
1061          async: hasModifier(SyntaxKind.AsyncKeyword, node),
1062          body: this.convertChild(node.body),
1063          range: [node.parameters.pos - 1, node.end],
1064          params: [],
1065        });
1066
1067        if (node.type) {
1068          method.returnType = this.convertTypeAnnotation(node.type, node);
1069        }
1070
1071        // Process typeParameters
1072        if (node.typeParameters) {
1073          method.typeParameters = this.convertTSTypeParametersToTypeParametersDeclaration(
1074            node.typeParameters,
1075          );
1076          this.fixParentLocation(method, method.typeParameters.range);
1077        }
1078
1079        let result:
1080          | TSESTree.Property
1081          | TSESTree.TSAbstractMethodDefinition
1082          | TSESTree.MethodDefinition;
1083
1084        if (parent.kind === SyntaxKind.ObjectLiteralExpression) {
1085          method.params = node.parameters.map(el => this.convertChild(el));
1086
1087          result = this.createNode<TSESTree.Property>(node, {
1088            type: AST_NODE_TYPES.Property,
1089            key: this.convertChild(node.name),
1090            value: method,
1091            computed: isComputedProperty(node.name),
1092            method: node.kind === SyntaxKind.MethodDeclaration,
1093            shorthand: false,
1094            kind: 'init',
1095          });
1096        } else {
1097          // class
1098
1099          /**
1100           * Unlike in object literal methods, class method params can have decorators
1101           */
1102          method.params = this.convertParameters(node.parameters);
1103
1104          /**
1105           * TypeScript class methods can be defined as "abstract"
1106           */
1107          const methodDefinitionType = hasModifier(
1108            SyntaxKind.AbstractKeyword,
1109            node,
1110          )
1111            ? AST_NODE_TYPES.TSAbstractMethodDefinition
1112            : AST_NODE_TYPES.MethodDefinition;
1113
1114          result = this.createNode<
1115            TSESTree.TSAbstractMethodDefinition | TSESTree.MethodDefinition
1116          >(node, {
1117            type: methodDefinitionType,
1118            key: this.convertChild(node.name),
1119            value: method,
1120            computed: isComputedProperty(node.name),
1121            static: hasModifier(SyntaxKind.StaticKeyword, node),
1122            kind: 'method',
1123          });
1124
1125          if (node.decorators) {
1126            result.decorators = node.decorators.map(el =>
1127              this.convertChild(el),
1128            );
1129          }
1130
1131          const accessibility = getTSNodeAccessibility(node);
1132          if (accessibility) {
1133            result.accessibility = accessibility;
1134          }
1135        }
1136
1137        if (node.questionToken) {
1138          result.optional = true;
1139        }
1140
1141        if (node.kind === SyntaxKind.GetAccessor) {
1142          result.kind = 'get';
1143        } else if (node.kind === SyntaxKind.SetAccessor) {
1144          result.kind = 'set';
1145        } else if (
1146          !(result as TSESTree.MethodDefinition).static &&
1147          node.name.kind === SyntaxKind.StringLiteral &&
1148          node.name.text === 'constructor' &&
1149          result.type !== AST_NODE_TYPES.Property
1150        ) {
1151          result.kind = 'constructor';
1152        }
1153        return result;
1154      }
1155
1156      // TypeScript uses this even for static methods named "constructor"
1157      case SyntaxKind.Constructor: {
1158        const lastModifier = getLastModifier(node);
1159        const constructorToken =
1160          (lastModifier && findNextToken(lastModifier, node, this.ast)) ||
1161          node.getFirstToken()!;
1162
1163        const constructor = this.createNode<
1164          TSESTree.TSEmptyBodyFunctionExpression | TSESTree.FunctionExpression
1165        >(node, {
1166          type: !node.body
1167            ? AST_NODE_TYPES.TSEmptyBodyFunctionExpression
1168            : AST_NODE_TYPES.FunctionExpression,
1169          id: null,
1170          params: this.convertParameters(node.parameters),
1171          generator: false,
1172          expression: false, // is not present in ESTreeNode
1173          async: false,
1174          body: this.convertChild(node.body),
1175          range: [node.parameters.pos - 1, node.end],
1176        });
1177
1178        // Process typeParameters
1179        if (node.typeParameters) {
1180          constructor.typeParameters = this.convertTSTypeParametersToTypeParametersDeclaration(
1181            node.typeParameters,
1182          );
1183          this.fixParentLocation(constructor, constructor.typeParameters.range);
1184        }
1185
1186        // Process returnType
1187        if (node.type) {
1188          constructor.returnType = this.convertTypeAnnotation(node.type, node);
1189        }
1190
1191        const constructorKey = this.createNode<TSESTree.Identifier>(node, {
1192          type: AST_NODE_TYPES.Identifier,
1193          name: 'constructor',
1194          range: [constructorToken.getStart(this.ast), constructorToken.end],
1195        });
1196
1197        const isStatic = hasModifier(SyntaxKind.StaticKeyword, node);
1198        const result = this.createNode<
1199          TSESTree.TSAbstractMethodDefinition | TSESTree.MethodDefinition
1200        >(node, {
1201          type: hasModifier(SyntaxKind.AbstractKeyword, node)
1202            ? AST_NODE_TYPES.TSAbstractMethodDefinition
1203            : AST_NODE_TYPES.MethodDefinition,
1204          key: constructorKey,
1205          value: constructor,
1206          computed: false,
1207          static: isStatic,
1208          kind: isStatic ? 'method' : 'constructor',
1209        });
1210
1211        const accessibility = getTSNodeAccessibility(node);
1212        if (accessibility) {
1213          result.accessibility = accessibility;
1214        }
1215
1216        return result;
1217      }
1218
1219      case SyntaxKind.FunctionExpression: {
1220        const result = this.createNode<TSESTree.FunctionExpression>(node, {
1221          type: AST_NODE_TYPES.FunctionExpression,
1222          id: this.convertChild(node.name),
1223          generator: !!node.asteriskToken,
1224          params: this.convertParameters(node.parameters),
1225          body: this.convertChild(node.body),
1226          async: hasModifier(SyntaxKind.AsyncKeyword, node),
1227          expression: false,
1228        });
1229
1230        // Process returnType
1231        if (node.type) {
1232          result.returnType = this.convertTypeAnnotation(node.type, node);
1233        }
1234
1235        // Process typeParameters
1236        if (node.typeParameters) {
1237          result.typeParameters = this.convertTSTypeParametersToTypeParametersDeclaration(
1238            node.typeParameters,
1239          );
1240        }
1241        return result;
1242      }
1243
1244      case SyntaxKind.SuperKeyword:
1245        return this.createNode<TSESTree.Super>(node, {
1246          type: AST_NODE_TYPES.Super,
1247        });
1248
1249      case SyntaxKind.ArrayBindingPattern:
1250        return this.createNode<TSESTree.ArrayPattern>(node, {
1251          type: AST_NODE_TYPES.ArrayPattern,
1252          elements: node.elements.map(el => this.convertPattern(el)),
1253        });
1254
1255      // occurs with missing array elements like [,]
1256      case SyntaxKind.OmittedExpression:
1257        return null;
1258
1259      case SyntaxKind.ObjectBindingPattern:
1260        return this.createNode<TSESTree.ObjectPattern>(node, {
1261          type: AST_NODE_TYPES.ObjectPattern,
1262          properties: node.elements.map(el => this.convertPattern(el)),
1263        });
1264
1265      case SyntaxKind.BindingElement: {
1266        if (parent.kind === SyntaxKind.ArrayBindingPattern) {
1267          const arrayItem = this.convertChild(node.name, parent);
1268
1269          if (node.initializer) {
1270            return this.createNode<TSESTree.AssignmentPattern>(node, {
1271              type: AST_NODE_TYPES.AssignmentPattern,
1272              left: arrayItem,
1273              right: this.convertChild(node.initializer),
1274            });
1275          } else if (node.dotDotDotToken) {
1276            return this.createNode<TSESTree.RestElement>(node, {
1277              type: AST_NODE_TYPES.RestElement,
1278              argument: arrayItem,
1279            });
1280          } else {
1281            return arrayItem;
1282          }
1283        } else {
1284          let result: TSESTree.RestElement | TSESTree.Property;
1285          if (node.dotDotDotToken) {
1286            result = this.createNode<TSESTree.RestElement>(node, {
1287              type: AST_NODE_TYPES.RestElement,
1288              argument: this.convertChild(node.propertyName ?? node.name),
1289            });
1290          } else {
1291            result = this.createNode<TSESTree.Property>(node, {
1292              type: AST_NODE_TYPES.Property,
1293              key: this.convertChild(node.propertyName ?? node.name),
1294              value: this.convertChild(node.name),
1295              computed: Boolean(
1296                node.propertyName &&
1297                  node.propertyName.kind === SyntaxKind.ComputedPropertyName,
1298              ),
1299              method: false,
1300              shorthand: !node.propertyName,
1301              kind: 'init',
1302            });
1303          }
1304
1305          if (node.initializer) {
1306            result.value = this.createNode<TSESTree.AssignmentPattern>(node, {
1307              type: AST_NODE_TYPES.AssignmentPattern,
1308              left: this.convertChild(node.name),
1309              right: this.convertChild(node.initializer),
1310              range: [node.name.getStart(this.ast), node.initializer.end],
1311            });
1312          }
1313          return result;
1314        }
1315      }
1316
1317      case SyntaxKind.ArrowFunction: {
1318        const result = this.createNode<TSESTree.ArrowFunctionExpression>(node, {
1319          type: AST_NODE_TYPES.ArrowFunctionExpression,
1320          generator: false,
1321          id: null,
1322          params: this.convertParameters(node.parameters),
1323          body: this.convertChild(node.body),
1324          async: hasModifier(SyntaxKind.AsyncKeyword, node),
1325          expression: node.body.kind !== SyntaxKind.Block,
1326        });
1327
1328        // Process returnType
1329        if (node.type) {
1330          result.returnType = this.convertTypeAnnotation(node.type, node);
1331        }
1332
1333        // Process typeParameters
1334        if (node.typeParameters) {
1335          result.typeParameters = this.convertTSTypeParametersToTypeParametersDeclaration(
1336            node.typeParameters,
1337          );
1338        }
1339        return result;
1340      }
1341
1342      case SyntaxKind.YieldExpression:
1343        return this.createNode<TSESTree.YieldExpression>(node, {
1344          type: AST_NODE_TYPES.YieldExpression,
1345          delegate: !!node.asteriskToken,
1346          argument: this.convertChild(node.expression),
1347        });
1348
1349      case SyntaxKind.AwaitExpression:
1350        return this.createNode<TSESTree.AwaitExpression>(node, {
1351          type: AST_NODE_TYPES.AwaitExpression,
1352          argument: this.convertChild(node.expression),
1353        });
1354
1355      // Template Literals
1356
1357      case SyntaxKind.NoSubstitutionTemplateLiteral:
1358        return this.createNode<TSESTree.TemplateLiteral>(node, {
1359          type: AST_NODE_TYPES.TemplateLiteral,
1360          quasis: [
1361            this.createNode<TSESTree.TemplateElement>(node, {
1362              type: AST_NODE_TYPES.TemplateElement,
1363              value: {
1364                raw: this.ast.text.slice(
1365                  node.getStart(this.ast) + 1,
1366                  node.end - 1,
1367                ),
1368                cooked: node.text,
1369              },
1370              tail: true,
1371            }),
1372          ],
1373          expressions: [],
1374        });
1375
1376      case SyntaxKind.TemplateExpression: {
1377        const result = this.createNode<TSESTree.TemplateLiteral>(node, {
1378          type: AST_NODE_TYPES.TemplateLiteral,
1379          quasis: [this.convertChild(node.head)],
1380          expressions: [],
1381        });
1382
1383        node.templateSpans.forEach(templateSpan => {
1384          result.expressions.push(this.convertChild(templateSpan.expression));
1385          result.quasis.push(this.convertChild(templateSpan.literal));
1386        });
1387        return result;
1388      }
1389
1390      case SyntaxKind.TaggedTemplateExpression:
1391        return this.createNode<TSESTree.TaggedTemplateExpression>(node, {
1392          type: AST_NODE_TYPES.TaggedTemplateExpression,
1393          typeParameters: node.typeArguments
1394            ? this.convertTypeArgumentsToTypeParameters(
1395                node.typeArguments,
1396                node,
1397              )
1398            : undefined,
1399          tag: this.convertChild(node.tag),
1400          quasi: this.convertChild(node.template),
1401        });
1402
1403      case SyntaxKind.TemplateHead:
1404      case SyntaxKind.TemplateMiddle:
1405      case SyntaxKind.TemplateTail: {
1406        const tail = node.kind === SyntaxKind.TemplateTail;
1407        return this.createNode<TSESTree.TemplateElement>(node, {
1408          type: AST_NODE_TYPES.TemplateElement,
1409          value: {
1410            raw: this.ast.text.slice(
1411              node.getStart(this.ast) + 1,
1412              node.end - (tail ? 1 : 2),
1413            ),
1414            cooked: node.text,
1415          },
1416          tail,
1417        });
1418      }
1419
1420      // Patterns
1421
1422      case SyntaxKind.SpreadAssignment:
1423      case SyntaxKind.SpreadElement: {
1424        if (this.allowPattern) {
1425          return this.createNode<TSESTree.RestElement>(node, {
1426            type: AST_NODE_TYPES.RestElement,
1427            argument: this.convertPattern(node.expression),
1428          });
1429        } else {
1430          return this.createNode<TSESTree.SpreadElement>(node, {
1431            type: AST_NODE_TYPES.SpreadElement,
1432            argument: this.convertChild(node.expression),
1433          });
1434        }
1435      }
1436
1437      case SyntaxKind.Parameter: {
1438        let parameter: TSESTree.RestElement | TSESTree.BindingName;
1439        let result: TSESTree.RestElement | TSESTree.AssignmentPattern;
1440
1441        if (node.dotDotDotToken) {
1442          parameter = result = this.createNode<TSESTree.RestElement>(node, {
1443            type: AST_NODE_TYPES.RestElement,
1444            argument: this.convertChild(node.name),
1445          });
1446        } else if (node.initializer) {
1447          parameter = this.convertChild(node.name) as TSESTree.BindingName;
1448          result = this.createNode<TSESTree.AssignmentPattern>(node, {
1449            type: AST_NODE_TYPES.AssignmentPattern,
1450            left: parameter,
1451            right: this.convertChild(node.initializer),
1452          });
1453
1454          if (node.modifiers) {
1455            // AssignmentPattern should not contain modifiers in range
1456            result.range[0] = parameter.range[0];
1457            result.loc = getLocFor(result.range[0], result.range[1], this.ast);
1458          }
1459        } else {
1460          parameter = result = this.convertChild(node.name, parent);
1461        }
1462
1463        if (node.type) {
1464          parameter.typeAnnotation = this.convertTypeAnnotation(
1465            node.type,
1466            node,
1467          );
1468          this.fixParentLocation(parameter, parameter.typeAnnotation.range);
1469        }
1470
1471        if (node.questionToken) {
1472          if (node.questionToken.end > parameter.range[1]) {
1473            parameter.range[1] = node.questionToken.end;
1474            parameter.loc.end = getLineAndCharacterFor(
1475              parameter.range[1],
1476              this.ast,
1477            );
1478          }
1479          parameter.optional = true;
1480        }
1481
1482        if (node.modifiers) {
1483          return this.createNode<TSESTree.TSParameterProperty>(node, {
1484            type: AST_NODE_TYPES.TSParameterProperty,
1485            accessibility: getTSNodeAccessibility(node) ?? undefined,
1486            readonly:
1487              hasModifier(SyntaxKind.ReadonlyKeyword, node) || undefined,
1488            static: hasModifier(SyntaxKind.StaticKeyword, node) || undefined,
1489            export: hasModifier(SyntaxKind.ExportKeyword, node) || undefined,
1490            parameter: result,
1491          });
1492        }
1493        return result;
1494      }
1495
1496      // Classes
1497
1498      case SyntaxKind.ClassDeclaration:
1499      case SyntaxKind.ClassExpression: {
1500        const heritageClauses = node.heritageClauses ?? [];
1501        const classNodeType =
1502          node.kind === SyntaxKind.ClassDeclaration
1503            ? AST_NODE_TYPES.ClassDeclaration
1504            : AST_NODE_TYPES.ClassExpression;
1505
1506        const superClass = heritageClauses.find(
1507          clause => clause.token === SyntaxKind.ExtendsKeyword,
1508        );
1509
1510        const implementsClause = heritageClauses.find(
1511          clause => clause.token === SyntaxKind.ImplementsKeyword,
1512        );
1513
1514        const result = this.createNode<
1515          TSESTree.ClassDeclaration | TSESTree.ClassExpression
1516        >(node, {
1517          type: classNodeType,
1518          id: this.convertChild(node.name),
1519          body: this.createNode<TSESTree.ClassBody>(node, {
1520            type: AST_NODE_TYPES.ClassBody,
1521            body: [],
1522            range: [node.members.pos - 1, node.end],
1523          }),
1524          superClass: superClass?.types[0]
1525            ? this.convertChild(superClass.types[0].expression)
1526            : null,
1527        });
1528
1529        if (superClass) {
1530          if (superClass.types.length > 1) {
1531            throw createError(
1532              this.ast,
1533              superClass.types[1].pos,
1534              'Classes can only extend a single class.',
1535            );
1536          }
1537
1538          if (superClass.types[0]?.typeArguments) {
1539            result.superTypeParameters = this.convertTypeArgumentsToTypeParameters(
1540              superClass.types[0].typeArguments,
1541              superClass.types[0],
1542            );
1543          }
1544        }
1545
1546        if (node.typeParameters) {
1547          result.typeParameters = this.convertTSTypeParametersToTypeParametersDeclaration(
1548            node.typeParameters,
1549          );
1550        }
1551
1552        if (implementsClause) {
1553          result.implements = implementsClause.types.map(el =>
1554            this.convertChild(el),
1555          );
1556        }
1557
1558        /**
1559         * TypeScript class declarations can be defined as "abstract"
1560         */
1561        if (hasModifier(SyntaxKind.AbstractKeyword, node)) {
1562          result.abstract = true;
1563        }
1564
1565        if (hasModifier(SyntaxKind.DeclareKeyword, node)) {
1566          result.declare = true;
1567        }
1568
1569        if (node.decorators) {
1570          result.decorators = node.decorators.map(el => this.convertChild(el));
1571        }
1572
1573        const filteredMembers = node.members.filter(isESTreeClassMember);
1574
1575        if (filteredMembers.length) {
1576          result.body.body = filteredMembers.map(el => this.convertChild(el));
1577        }
1578
1579        // check for exports
1580        return this.fixExports(node, result);
1581      }
1582
1583      // Modules
1584      case SyntaxKind.ModuleBlock:
1585        return this.createNode<TSESTree.TSModuleBlock>(node, {
1586          type: AST_NODE_TYPES.TSModuleBlock,
1587          body: this.convertBodyExpressions(node.statements, node),
1588        });
1589
1590      case SyntaxKind.ImportDeclaration: {
1591        const result = this.createNode<TSESTree.ImportDeclaration>(node, {
1592          type: AST_NODE_TYPES.ImportDeclaration,
1593          source: this.convertChild(node.moduleSpecifier),
1594          specifiers: [],
1595          importKind: 'value',
1596        });
1597
1598        if (node.importClause) {
1599          if (node.importClause.isTypeOnly) {
1600            result.importKind = 'type';
1601          }
1602
1603          if (node.importClause.name) {
1604            result.specifiers.push(this.convertChild(node.importClause));
1605          }
1606
1607          if (node.importClause.namedBindings) {
1608            switch (node.importClause.namedBindings.kind) {
1609              case SyntaxKind.NamespaceImport:
1610                result.specifiers.push(
1611                  this.convertChild(node.importClause.namedBindings),
1612                );
1613                break;
1614              case SyntaxKind.NamedImports:
1615                result.specifiers = result.specifiers.concat(
1616                  node.importClause.namedBindings.elements.map(el =>
1617                    this.convertChild(el),
1618                  ),
1619                );
1620                break;
1621            }
1622          }
1623        }
1624        return result;
1625      }
1626
1627      case SyntaxKind.NamespaceImport:
1628        return this.createNode<TSESTree.ImportNamespaceSpecifier>(node, {
1629          type: AST_NODE_TYPES.ImportNamespaceSpecifier,
1630          local: this.convertChild(node.name),
1631        });
1632
1633      case SyntaxKind.ImportSpecifier:
1634        return this.createNode<TSESTree.ImportSpecifier>(node, {
1635          type: AST_NODE_TYPES.ImportSpecifier,
1636          local: this.convertChild(node.name),
1637          imported: this.convertChild(node.propertyName ?? node.name),
1638        });
1639
1640      case SyntaxKind.ImportClause: {
1641        const local = this.convertChild(node.name);
1642        return this.createNode<TSESTree.ImportDefaultSpecifier>(node, {
1643          type: AST_NODE_TYPES.ImportDefaultSpecifier,
1644          local,
1645          range: local.range,
1646        });
1647      }
1648
1649      case SyntaxKind.ExportDeclaration:
1650        if (node.exportClause?.kind === SyntaxKind.NamedExports) {
1651          return this.createNode<TSESTree.ExportNamedDeclaration>(node, {
1652            type: AST_NODE_TYPES.ExportNamedDeclaration,
1653            source: this.convertChild(node.moduleSpecifier),
1654            specifiers: node.exportClause.elements.map(el =>
1655              this.convertChild(el),
1656            ),
1657            exportKind: node.isTypeOnly ? 'type' : 'value',
1658            declaration: null,
1659          });
1660        } else {
1661          return this.createNode<TSESTree.ExportAllDeclaration>(node, {
1662            type: AST_NODE_TYPES.ExportAllDeclaration,
1663            source: this.convertChild(node.moduleSpecifier),
1664            exportKind: node.isTypeOnly ? 'type' : 'value',
1665            exported:
1666              // note - for compat with 3.7.x, where node.exportClause is always undefined and
1667              //        SyntaxKind.NamespaceExport does not exist yet (i.e. is undefined), this
1668              //        cannot be shortened to an optional chain, or else you end up with
1669              //        undefined === undefined, and the true path will hard error at runtime
1670              node.exportClause &&
1671              node.exportClause.kind === SyntaxKind.NamespaceExport
1672                ? this.convertChild(node.exportClause.name)
1673                : null,
1674          });
1675        }
1676
1677      case SyntaxKind.ExportSpecifier:
1678        return this.createNode<TSESTree.ExportSpecifier>(node, {
1679          type: AST_NODE_TYPES.ExportSpecifier,
1680          local: this.convertChild(node.propertyName ?? node.name),
1681          exported: this.convertChild(node.name),
1682        });
1683
1684      case SyntaxKind.ExportAssignment:
1685        if (node.isExportEquals) {
1686          return this.createNode<TSESTree.TSExportAssignment>(node, {
1687            type: AST_NODE_TYPES.TSExportAssignment,
1688            expression: this.convertChild(node.expression),
1689          });
1690        } else {
1691          return this.createNode<TSESTree.ExportDefaultDeclaration>(node, {
1692            type: AST_NODE_TYPES.ExportDefaultDeclaration,
1693            declaration: this.convertChild(node.expression),
1694            exportKind: 'value',
1695          });
1696        }
1697
1698      // Unary Operations
1699
1700      case SyntaxKind.PrefixUnaryExpression:
1701      case SyntaxKind.PostfixUnaryExpression: {
1702        const operator = getTextForTokenKind(node.operator);
1703        /**
1704         * ESTree uses UpdateExpression for ++/--
1705         */
1706        if (operator === '++' || operator === '--') {
1707          return this.createNode<TSESTree.UpdateExpression>(node, {
1708            type: AST_NODE_TYPES.UpdateExpression,
1709            operator,
1710            prefix: node.kind === SyntaxKind.PrefixUnaryExpression,
1711            argument: this.convertChild(node.operand),
1712          });
1713        } else {
1714          return this.createNode<TSESTree.UnaryExpression>(node, {
1715            type: AST_NODE_TYPES.UnaryExpression,
1716            operator,
1717            prefix: node.kind === SyntaxKind.PrefixUnaryExpression,
1718            argument: this.convertChild(node.operand),
1719          });
1720        }
1721      }
1722
1723      case SyntaxKind.DeleteExpression:
1724        return this.createNode<TSESTree.UnaryExpression>(node, {
1725          type: AST_NODE_TYPES.UnaryExpression,
1726          operator: 'delete',
1727          prefix: true,
1728          argument: this.convertChild(node.expression),
1729        });
1730
1731      case SyntaxKind.VoidExpression:
1732        return this.createNode<TSESTree.UnaryExpression>(node, {
1733          type: AST_NODE_TYPES.UnaryExpression,
1734          operator: 'void',
1735          prefix: true,
1736          argument: this.convertChild(node.expression),
1737        });
1738
1739      case SyntaxKind.TypeOfExpression:
1740        return this.createNode<TSESTree.UnaryExpression>(node, {
1741          type: AST_NODE_TYPES.UnaryExpression,
1742          operator: 'typeof',
1743          prefix: true,
1744          argument: this.convertChild(node.expression),
1745        });
1746
1747      case SyntaxKind.TypeOperator:
1748        return this.createNode<TSESTree.TSTypeOperator>(node, {
1749          type: AST_NODE_TYPES.TSTypeOperator,
1750          operator: getTextForTokenKind(node.operator),
1751          typeAnnotation: this.convertChild(node.type),
1752        });
1753
1754      // Binary Operations
1755
1756      case SyntaxKind.BinaryExpression: {
1757        // TypeScript uses BinaryExpression for sequences as well
1758        if (isComma(node.operatorToken)) {
1759          const result = this.createNode<TSESTree.SequenceExpression>(node, {
1760            type: AST_NODE_TYPES.SequenceExpression,
1761            expressions: [],
1762          });
1763
1764          const left = this.convertChild(node.left);
1765          if (
1766            left.type === AST_NODE_TYPES.SequenceExpression &&
1767            node.left.kind !== SyntaxKind.ParenthesizedExpression
1768          ) {
1769            result.expressions = result.expressions.concat(left.expressions);
1770          } else {
1771            result.expressions.push(left);
1772          }
1773
1774          result.expressions.push(this.convertChild(node.right));
1775          return result;
1776        } else {
1777          const type = getBinaryExpressionType(node.operatorToken);
1778          if (
1779            this.allowPattern &&
1780            type === AST_NODE_TYPES.AssignmentExpression
1781          ) {
1782            return this.createNode<TSESTree.AssignmentPattern>(node, {
1783              type: AST_NODE_TYPES.AssignmentPattern,
1784              left: this.convertPattern(node.left, node),
1785              right: this.convertChild(node.right),
1786            });
1787          }
1788          return this.createNode<
1789            | TSESTree.AssignmentExpression
1790            | TSESTree.LogicalExpression
1791            | TSESTree.BinaryExpression
1792          >(node, {
1793            type,
1794            operator: getTextForTokenKind(node.operatorToken.kind),
1795            left: this.converter(
1796              node.left,
1797              node,
1798              this.inTypeMode,
1799              type === AST_NODE_TYPES.AssignmentExpression,
1800            ),
1801            right: this.convertChild(node.right),
1802          });
1803        }
1804      }
1805
1806      case SyntaxKind.PropertyAccessExpression: {
1807        const object = this.convertChild(node.expression);
1808        const property = this.convertChild(node.name);
1809        const computed = false;
1810
1811        const result = this.createNode<TSESTree.MemberExpression>(node, {
1812          type: AST_NODE_TYPES.MemberExpression,
1813          object,
1814          property,
1815          computed,
1816          optional: node.questionDotToken !== undefined,
1817        });
1818
1819        return this.convertChainExpression(result, node);
1820      }
1821
1822      case SyntaxKind.ElementAccessExpression: {
1823        const object = this.convertChild(node.expression);
1824        const property = this.convertChild(node.argumentExpression);
1825        const computed = true;
1826
1827        const result = this.createNode<TSESTree.MemberExpression>(node, {
1828          type: AST_NODE_TYPES.MemberExpression,
1829          object,
1830          property,
1831          computed,
1832          optional: node.questionDotToken !== undefined,
1833        });
1834
1835        return this.convertChainExpression(result, node);
1836      }
1837
1838      case SyntaxKind.CallExpression: {
1839        if (node.expression.kind === SyntaxKind.ImportKeyword) {
1840          if (node.arguments.length !== 1) {
1841            throw createError(
1842              this.ast,
1843              node.arguments.pos,
1844              'Dynamic import must have one specifier as an argument.',
1845            );
1846          }
1847          return this.createNode<TSESTree.ImportExpression>(node, {
1848            type: AST_NODE_TYPES.ImportExpression,
1849            source: this.convertChild(node.arguments[0]),
1850          });
1851        }
1852
1853        const callee = this.convertChild(node.expression);
1854        const args = node.arguments.map(el => this.convertChild(el));
1855
1856        const result = this.createNode<TSESTree.CallExpression>(node, {
1857          type: AST_NODE_TYPES.CallExpression,
1858          callee,
1859          arguments: args,
1860          optional: node.questionDotToken !== undefined,
1861        });
1862
1863        if (node.typeArguments) {
1864          result.typeParameters = this.convertTypeArgumentsToTypeParameters(
1865            node.typeArguments,
1866            node,
1867          );
1868        }
1869
1870        return this.convertChainExpression(result, node);
1871      }
1872
1873      case SyntaxKind.NewExpression: {
1874        // NOTE - NewExpression cannot have an optional chain in it
1875        const result = this.createNode<TSESTree.NewExpression>(node, {
1876          type: AST_NODE_TYPES.NewExpression,
1877          callee: this.convertChild(node.expression),
1878          arguments: node.arguments
1879            ? node.arguments.map(el => this.convertChild(el))
1880            : [],
1881        });
1882        if (node.typeArguments) {
1883          result.typeParameters = this.convertTypeArgumentsToTypeParameters(
1884            node.typeArguments,
1885            node,
1886          );
1887        }
1888        return result;
1889      }
1890
1891      case SyntaxKind.ConditionalExpression:
1892        return this.createNode<TSESTree.ConditionalExpression>(node, {
1893          type: AST_NODE_TYPES.ConditionalExpression,
1894          test: this.convertChild(node.condition),
1895          consequent: this.convertChild(node.whenTrue),
1896          alternate: this.convertChild(node.whenFalse),
1897        });
1898
1899      case SyntaxKind.MetaProperty: {
1900        return this.createNode<TSESTree.MetaProperty>(node, {
1901          type: AST_NODE_TYPES.MetaProperty,
1902          meta: this.createNode<TSESTree.Identifier>(
1903            // TODO: do we really want to convert it to Token?
1904            node.getFirstToken()! as ts.Token<typeof node.keywordToken>,
1905            {
1906              type: AST_NODE_TYPES.Identifier,
1907              name: getTextForTokenKind(node.keywordToken),
1908            },
1909          ),
1910          property: this.convertChild(node.name),
1911        });
1912      }
1913
1914      case SyntaxKind.Decorator: {
1915        return this.createNode<TSESTree.Decorator>(node, {
1916          type: AST_NODE_TYPES.Decorator,
1917          expression: this.convertChild(node.expression),
1918        });
1919      }
1920
1921      // Literals
1922
1923      case SyntaxKind.StringLiteral: {
1924        const result = this.createNode<TSESTree.Literal>(node, {
1925          type: AST_NODE_TYPES.Literal,
1926          raw: '',
1927          value: '',
1928        });
1929        result.raw = this.ast.text.slice(result.range[0], result.range[1]);
1930        if ('name' in parent && parent.name === node) {
1931          result.value = node.text;
1932        } else {
1933          result.value = unescapeStringLiteralText(node.text);
1934        }
1935        return result;
1936      }
1937
1938      case SyntaxKind.NumericLiteral: {
1939        return this.createNode<TSESTree.Literal>(node, {
1940          type: AST_NODE_TYPES.Literal,
1941          value: Number(node.text),
1942          raw: node.getText(),
1943        });
1944      }
1945
1946      case SyntaxKind.BigIntLiteral: {
1947        const range = getRange(node, this.ast);
1948        const rawValue = this.ast.text.slice(range[0], range[1]);
1949        const bigint = rawValue
1950          // remove suffix `n`
1951          .slice(0, -1)
1952          // `BigInt` doesn't accept numeric separator
1953          // and `bigint` property should not include numeric separator
1954          .replace(/_/g, '');
1955        const value = typeof BigInt !== 'undefined' ? BigInt(bigint) : null;
1956        return this.createNode<TSESTree.BigIntLiteral>(node, {
1957          type: AST_NODE_TYPES.Literal,
1958          raw: rawValue,
1959          value: value,
1960          bigint: value === null ? bigint : String(value),
1961          range,
1962        });
1963      }
1964
1965      case SyntaxKind.RegularExpressionLiteral: {
1966        const pattern = node.text.slice(1, node.text.lastIndexOf('/'));
1967        const flags = node.text.slice(node.text.lastIndexOf('/') + 1);
1968
1969        let regex = null;
1970        try {
1971          regex = new RegExp(pattern, flags);
1972        } catch (exception) {
1973          regex = null;
1974        }
1975
1976        return this.createNode<TSESTree.Literal>(node, {
1977          type: AST_NODE_TYPES.Literal,
1978          value: regex,
1979          raw: node.text,
1980          regex: {
1981            pattern,
1982            flags,
1983          },
1984        });
1985      }
1986
1987      case SyntaxKind.TrueKeyword:
1988        return this.createNode<TSESTree.Literal>(node, {
1989          type: AST_NODE_TYPES.Literal,
1990          value: true,
1991          raw: 'true',
1992        });
1993
1994      case SyntaxKind.FalseKeyword:
1995        return this.createNode<TSESTree.Literal>(node, {
1996          type: AST_NODE_TYPES.Literal,
1997          value: false,
1998          raw: 'false',
1999        });
2000
2001      case SyntaxKind.NullKeyword: {
2002        if (!typescriptVersionIsAtLeast['4.0'] && this.inTypeMode) {
2003          // 4.0 started nesting null types inside a LiteralType node, but we still need to support pre-4.0
2004          return this.createNode<TSESTree.TSNullKeyword>(node, {
2005            type: AST_NODE_TYPES.TSNullKeyword,
2006          });
2007        }
2008
2009        return this.createNode<TSESTree.Literal>(node, {
2010          type: AST_NODE_TYPES.Literal,
2011          value: null,
2012          raw: 'null',
2013        });
2014      }
2015
2016      case SyntaxKind.EmptyStatement:
2017        return this.createNode<TSESTree.EmptyStatement>(node, {
2018          type: AST_NODE_TYPES.EmptyStatement,
2019        });
2020
2021      case SyntaxKind.DebuggerStatement:
2022        return this.createNode<TSESTree.DebuggerStatement>(node, {
2023          type: AST_NODE_TYPES.DebuggerStatement,
2024        });
2025
2026      // JSX
2027
2028      case SyntaxKind.JsxElement:
2029        return this.createNode<TSESTree.JSXElement>(node, {
2030          type: AST_NODE_TYPES.JSXElement,
2031          openingElement: this.convertChild(node.openingElement),
2032          closingElement: this.convertChild(node.closingElement),
2033          children: node.children.map(el => this.convertChild(el)),
2034        });
2035
2036      case SyntaxKind.JsxFragment:
2037        return this.createNode<TSESTree.JSXFragment>(node, {
2038          type: AST_NODE_TYPES.JSXFragment,
2039          openingFragment: this.convertChild(node.openingFragment),
2040          closingFragment: this.convertChild(node.closingFragment),
2041          children: node.children.map(el => this.convertChild(el)),
2042        });
2043
2044      case SyntaxKind.JsxSelfClosingElement: {
2045        return this.createNode<TSESTree.JSXElement>(node, {
2046          type: AST_NODE_TYPES.JSXElement,
2047          /**
2048           * Convert SyntaxKind.JsxSelfClosingElement to SyntaxKind.JsxOpeningElement,
2049           * TypeScript does not seem to have the idea of openingElement when tag is self-closing
2050           */
2051          openingElement: this.createNode<TSESTree.JSXOpeningElement>(node, {
2052            type: AST_NODE_TYPES.JSXOpeningElement,
2053            typeParameters: node.typeArguments
2054              ? this.convertTypeArgumentsToTypeParameters(
2055                  node.typeArguments,
2056                  node,
2057                )
2058              : undefined,
2059            selfClosing: true,
2060            name: this.convertJSXTagName(node.tagName, node),
2061            attributes: node.attributes.properties.map(el =>
2062              this.convertChild(el),
2063            ),
2064            range: getRange(node, this.ast),
2065          }),
2066          closingElement: null,
2067          children: [],
2068        });
2069      }
2070
2071      case SyntaxKind.JsxOpeningElement:
2072        return this.createNode<TSESTree.JSXOpeningElement>(node, {
2073          type: AST_NODE_TYPES.JSXOpeningElement,
2074          typeParameters: node.typeArguments
2075            ? this.convertTypeArgumentsToTypeParameters(
2076                node.typeArguments,
2077                node,
2078              )
2079            : undefined,
2080          selfClosing: false,
2081          name: this.convertJSXTagName(node.tagName, node),
2082          attributes: node.attributes.properties.map(el =>
2083            this.convertChild(el),
2084          ),
2085        });
2086
2087      case SyntaxKind.JsxClosingElement:
2088        return this.createNode<TSESTree.JSXClosingElement>(node, {
2089          type: AST_NODE_TYPES.JSXClosingElement,
2090          name: this.convertJSXTagName(node.tagName, node),
2091        });
2092
2093      case SyntaxKind.JsxOpeningFragment:
2094        return this.createNode<TSESTree.JSXOpeningFragment>(node, {
2095          type: AST_NODE_TYPES.JSXOpeningFragment,
2096        });
2097
2098      case SyntaxKind.JsxClosingFragment:
2099        return this.createNode<TSESTree.JSXClosingFragment>(node, {
2100          type: AST_NODE_TYPES.JSXClosingFragment,
2101        });
2102
2103      case SyntaxKind.JsxExpression: {
2104        const expression = node.expression
2105          ? this.convertChild(node.expression)
2106          : this.createNode<TSESTree.JSXEmptyExpression>(node, {
2107              type: AST_NODE_TYPES.JSXEmptyExpression,
2108              range: [node.getStart(this.ast) + 1, node.getEnd() - 1],
2109            });
2110
2111        if (node.dotDotDotToken) {
2112          return this.createNode<TSESTree.JSXSpreadChild>(node, {
2113            type: AST_NODE_TYPES.JSXSpreadChild,
2114            expression,
2115          });
2116        } else {
2117          return this.createNode<TSESTree.JSXExpressionContainer>(node, {
2118            type: AST_NODE_TYPES.JSXExpressionContainer,
2119            expression,
2120          });
2121        }
2122      }
2123
2124      case SyntaxKind.JsxAttribute: {
2125        const attributeName = this.convertChild(node.name);
2126        attributeName.type = AST_NODE_TYPES.JSXIdentifier;
2127
2128        return this.createNode<TSESTree.JSXAttribute>(node, {
2129          type: AST_NODE_TYPES.JSXAttribute,
2130          name: attributeName,
2131          value: this.convertChild(node.initializer),
2132        });
2133      }
2134
2135      /**
2136       * The JSX AST changed the node type for string literals
2137       * inside a JSX Element from `Literal` to `JSXText`. We
2138       * provide a flag to support both types until `Literal`
2139       * node type is deprecated in ESLint v5.
2140       */
2141      case SyntaxKind.JsxText: {
2142        const start = node.getFullStart();
2143        const end = node.getEnd();
2144
2145        if (this.options.useJSXTextNode) {
2146          return this.createNode<TSESTree.JSXText>(node, {
2147            type: AST_NODE_TYPES.JSXText,
2148            value: this.ast.text.slice(start, end),
2149            raw: this.ast.text.slice(start, end),
2150            range: [start, end],
2151          });
2152        } else {
2153          return this.createNode<TSESTree.Literal>(node, {
2154            type: AST_NODE_TYPES.Literal,
2155            value: this.ast.text.slice(start, end),
2156            raw: this.ast.text.slice(start, end),
2157            range: [start, end],
2158          });
2159        }
2160      }
2161
2162      case SyntaxKind.JsxSpreadAttribute:
2163        return this.createNode<TSESTree.JSXSpreadAttribute>(node, {
2164          type: AST_NODE_TYPES.JSXSpreadAttribute,
2165          argument: this.convertChild(node.expression),
2166        });
2167
2168      case SyntaxKind.QualifiedName: {
2169        return this.createNode<TSESTree.TSQualifiedName>(node, {
2170          type: AST_NODE_TYPES.TSQualifiedName,
2171          left: this.convertChild(node.left),
2172          right: this.convertChild(node.right),
2173        });
2174      }
2175
2176      // TypeScript specific
2177
2178      case SyntaxKind.TypeReference: {
2179        return this.createNode<TSESTree.TSTypeReference>(node, {
2180          type: AST_NODE_TYPES.TSTypeReference,
2181          typeName: this.convertType(node.typeName),
2182          typeParameters: node.typeArguments
2183            ? this.convertTypeArgumentsToTypeParameters(
2184                node.typeArguments,
2185                node,
2186              )
2187            : undefined,
2188        });
2189      }
2190
2191      case SyntaxKind.TypeParameter: {
2192        return this.createNode<TSESTree.TSTypeParameter>(node, {
2193          type: AST_NODE_TYPES.TSTypeParameter,
2194          name: this.convertType(node.name),
2195          constraint: node.constraint
2196            ? this.convertType(node.constraint)
2197            : undefined,
2198          default: node.default ? this.convertType(node.default) : undefined,
2199        });
2200      }
2201
2202      case SyntaxKind.ThisType:
2203        return this.createNode<TSESTree.TSThisType>(node, {
2204          type: AST_NODE_TYPES.TSThisType,
2205        });
2206
2207      case SyntaxKind.AnyKeyword:
2208      case SyntaxKind.BigIntKeyword:
2209      case SyntaxKind.BooleanKeyword:
2210      case SyntaxKind.NeverKeyword:
2211      case SyntaxKind.NumberKeyword:
2212      case SyntaxKind.ObjectKeyword:
2213      case SyntaxKind.StringKeyword:
2214      case SyntaxKind.SymbolKeyword:
2215      case SyntaxKind.UnknownKeyword:
2216      case SyntaxKind.VoidKeyword:
2217      case SyntaxKind.UndefinedKeyword: {
2218        return this.createNode<any>(node, {
2219          type: AST_NODE_TYPES[`TS${SyntaxKind[node.kind]}` as AST_NODE_TYPES],
2220        });
2221      }
2222
2223      case SyntaxKind.NonNullExpression: {
2224        const nnExpr = this.createNode<TSESTree.TSNonNullExpression>(node, {
2225          type: AST_NODE_TYPES.TSNonNullExpression,
2226          expression: this.convertChild(node.expression),
2227        });
2228
2229        return this.convertChainExpression(nnExpr, node);
2230      }
2231
2232      case SyntaxKind.TypeLiteral: {
2233        return this.createNode<TSESTree.TSTypeLiteral>(node, {
2234          type: AST_NODE_TYPES.TSTypeLiteral,
2235          members: node.members.map(el => this.convertChild(el)),
2236        });
2237      }
2238
2239      case SyntaxKind.ArrayType: {
2240        return this.createNode<TSESTree.TSArrayType>(node, {
2241          type: AST_NODE_TYPES.TSArrayType,
2242          elementType: this.convertType(node.elementType),
2243        });
2244      }
2245
2246      case SyntaxKind.IndexedAccessType: {
2247        return this.createNode<TSESTree.TSIndexedAccessType>(node, {
2248          type: AST_NODE_TYPES.TSIndexedAccessType,
2249          objectType: this.convertType(node.objectType),
2250          indexType: this.convertType(node.indexType),
2251        });
2252      }
2253
2254      case SyntaxKind.ConditionalType: {
2255        return this.createNode<TSESTree.TSConditionalType>(node, {
2256          type: AST_NODE_TYPES.TSConditionalType,
2257          checkType: this.convertType(node.checkType),
2258          extendsType: this.convertType(node.extendsType),
2259          trueType: this.convertType(node.trueType),
2260          falseType: this.convertType(node.falseType),
2261        });
2262      }
2263
2264      case SyntaxKind.TypeQuery: {
2265        return this.createNode<TSESTree.TSTypeQuery>(node, {
2266          type: AST_NODE_TYPES.TSTypeQuery,
2267          exprName: this.convertType(node.exprName),
2268        });
2269      }
2270
2271      case SyntaxKind.MappedType: {
2272        const result = this.createNode<TSESTree.TSMappedType>(node, {
2273          type: AST_NODE_TYPES.TSMappedType,
2274          typeParameter: this.convertType(node.typeParameter),
2275          nameType: this.convertType(node.nameType) ?? null,
2276        });
2277
2278        if (node.readonlyToken) {
2279          if (node.readonlyToken.kind === SyntaxKind.ReadonlyKeyword) {
2280            result.readonly = true;
2281          } else {
2282            result.readonly = getTextForTokenKind(node.readonlyToken.kind);
2283          }
2284        }
2285
2286        if (node.questionToken) {
2287          if (node.questionToken.kind === SyntaxKind.QuestionToken) {
2288            result.optional = true;
2289          } else {
2290            result.optional = getTextForTokenKind(node.questionToken.kind);
2291          }
2292        }
2293
2294        if (node.type) {
2295          result.typeAnnotation = this.convertType(node.type);
2296        }
2297        return result;
2298      }
2299
2300      case SyntaxKind.ParenthesizedExpression:
2301        return this.convertChild(node.expression, parent);
2302
2303      case SyntaxKind.TypeAliasDeclaration: {
2304        const result = this.createNode<TSESTree.TSTypeAliasDeclaration>(node, {
2305          type: AST_NODE_TYPES.TSTypeAliasDeclaration,
2306          id: this.convertChild(node.name),
2307          typeAnnotation: this.convertType(node.type),
2308        });
2309
2310        if (hasModifier(SyntaxKind.DeclareKeyword, node)) {
2311          result.declare = true;
2312        }
2313
2314        // Process typeParameters
2315        if (node.typeParameters) {
2316          result.typeParameters = this.convertTSTypeParametersToTypeParametersDeclaration(
2317            node.typeParameters,
2318          );
2319        }
2320
2321        // check for exports
2322        return this.fixExports(node, result);
2323      }
2324
2325      case SyntaxKind.MethodSignature: {
2326        const result = this.createNode<TSESTree.TSMethodSignature>(node, {
2327          type: AST_NODE_TYPES.TSMethodSignature,
2328          computed: isComputedProperty(node.name),
2329          key: this.convertChild(node.name),
2330          params: this.convertParameters(node.parameters),
2331        });
2332
2333        if (isOptional(node)) {
2334          result.optional = true;
2335        }
2336
2337        if (node.type) {
2338          result.returnType = this.convertTypeAnnotation(node.type, node);
2339        }
2340
2341        if (hasModifier(SyntaxKind.ReadonlyKeyword, node)) {
2342          result.readonly = true;
2343        }
2344
2345        if (node.typeParameters) {
2346          result.typeParameters = this.convertTSTypeParametersToTypeParametersDeclaration(
2347            node.typeParameters,
2348          );
2349        }
2350
2351        const accessibility = getTSNodeAccessibility(node);
2352        if (accessibility) {
2353          result.accessibility = accessibility;
2354        }
2355
2356        if (hasModifier(SyntaxKind.ExportKeyword, node)) {
2357          result.export = true;
2358        }
2359
2360        if (hasModifier(SyntaxKind.StaticKeyword, node)) {
2361          result.static = true;
2362        }
2363        return result;
2364      }
2365
2366      case SyntaxKind.PropertySignature: {
2367        const result = this.createNode<TSESTree.TSPropertySignature>(node, {
2368          type: AST_NODE_TYPES.TSPropertySignature,
2369          optional: isOptional(node) || undefined,
2370          computed: isComputedProperty(node.name),
2371          key: this.convertChild(node.name),
2372          typeAnnotation: node.type
2373            ? this.convertTypeAnnotation(node.type, node)
2374            : undefined,
2375          initializer: this.convertChild(node.initializer) || undefined,
2376          readonly: hasModifier(SyntaxKind.ReadonlyKeyword, node) || undefined,
2377          static: hasModifier(SyntaxKind.StaticKeyword, node) || undefined,
2378          export: hasModifier(SyntaxKind.ExportKeyword, node) || undefined,
2379        });
2380
2381        const accessibility = getTSNodeAccessibility(node);
2382        if (accessibility) {
2383          result.accessibility = accessibility;
2384        }
2385
2386        return result;
2387      }
2388
2389      case SyntaxKind.IndexSignature: {
2390        const result = this.createNode<TSESTree.TSIndexSignature>(node, {
2391          type: AST_NODE_TYPES.TSIndexSignature,
2392          parameters: node.parameters.map(el => this.convertChild(el)),
2393        });
2394
2395        if (node.type) {
2396          result.typeAnnotation = this.convertTypeAnnotation(node.type, node);
2397        }
2398
2399        if (hasModifier(SyntaxKind.ReadonlyKeyword, node)) {
2400          result.readonly = true;
2401        }
2402
2403        const accessibility = getTSNodeAccessibility(node);
2404        if (accessibility) {
2405          result.accessibility = accessibility;
2406        }
2407
2408        if (hasModifier(SyntaxKind.ExportKeyword, node)) {
2409          result.export = true;
2410        }
2411
2412        if (hasModifier(SyntaxKind.StaticKeyword, node)) {
2413          result.static = true;
2414        }
2415        return result;
2416      }
2417      case SyntaxKind.ConstructorType:
2418      case SyntaxKind.FunctionType:
2419      case SyntaxKind.ConstructSignature:
2420      case SyntaxKind.CallSignature: {
2421        let type: AST_NODE_TYPES;
2422        switch (node.kind) {
2423          case SyntaxKind.ConstructSignature:
2424            type = AST_NODE_TYPES.TSConstructSignatureDeclaration;
2425            break;
2426          case SyntaxKind.CallSignature:
2427            type = AST_NODE_TYPES.TSCallSignatureDeclaration;
2428            break;
2429          case SyntaxKind.FunctionType:
2430            type = AST_NODE_TYPES.TSFunctionType;
2431            break;
2432          case SyntaxKind.ConstructorType:
2433          default:
2434            type = AST_NODE_TYPES.TSConstructorType;
2435            break;
2436        }
2437        const result = this.createNode<
2438          | TSESTree.TSConstructSignatureDeclaration
2439          | TSESTree.TSCallSignatureDeclaration
2440          | TSESTree.TSFunctionType
2441          | TSESTree.TSConstructorType
2442        >(node, {
2443          type: type,
2444          params: this.convertParameters(node.parameters),
2445        });
2446
2447        if (node.type) {
2448          result.returnType = this.convertTypeAnnotation(node.type, node);
2449        }
2450
2451        if (node.typeParameters) {
2452          result.typeParameters = this.convertTSTypeParametersToTypeParametersDeclaration(
2453            node.typeParameters,
2454          );
2455        }
2456
2457        return result;
2458      }
2459
2460      case SyntaxKind.ExpressionWithTypeArguments: {
2461        const result = this.createNode<
2462          TSESTree.TSInterfaceHeritage | TSESTree.TSClassImplements
2463        >(node, {
2464          type:
2465            parent && parent.kind === SyntaxKind.InterfaceDeclaration
2466              ? AST_NODE_TYPES.TSInterfaceHeritage
2467              : AST_NODE_TYPES.TSClassImplements,
2468          expression: this.convertChild(node.expression),
2469        });
2470
2471        if (node.typeArguments) {
2472          result.typeParameters = this.convertTypeArgumentsToTypeParameters(
2473            node.typeArguments,
2474            node,
2475          );
2476        }
2477        return result;
2478      }
2479
2480      case SyntaxKind.InterfaceDeclaration: {
2481        const interfaceHeritageClauses = node.heritageClauses ?? [];
2482        const result = this.createNode<TSESTree.TSInterfaceDeclaration>(node, {
2483          type: AST_NODE_TYPES.TSInterfaceDeclaration,
2484          body: this.createNode<TSESTree.TSInterfaceBody>(node, {
2485            type: AST_NODE_TYPES.TSInterfaceBody,
2486            body: node.members.map(member => this.convertChild(member)),
2487            range: [node.members.pos - 1, node.end],
2488          }),
2489          id: this.convertChild(node.name),
2490        });
2491
2492        if (node.typeParameters) {
2493          result.typeParameters = this.convertTSTypeParametersToTypeParametersDeclaration(
2494            node.typeParameters,
2495          );
2496        }
2497
2498        if (interfaceHeritageClauses.length > 0) {
2499          const interfaceExtends: TSESTree.TSInterfaceHeritage[] = [];
2500          const interfaceImplements: TSESTree.TSInterfaceHeritage[] = [];
2501
2502          for (const heritageClause of interfaceHeritageClauses) {
2503            if (heritageClause.token === SyntaxKind.ExtendsKeyword) {
2504              for (const n of heritageClause.types) {
2505                interfaceExtends.push(this.convertChild(n, node));
2506              }
2507            } else {
2508              for (const n of heritageClause.types) {
2509                interfaceImplements.push(this.convertChild(n, node));
2510              }
2511            }
2512          }
2513
2514          if (interfaceExtends.length) {
2515            result.extends = interfaceExtends;
2516          }
2517
2518          if (interfaceImplements.length) {
2519            result.implements = interfaceImplements;
2520          }
2521        }
2522
2523        if (hasModifier(SyntaxKind.AbstractKeyword, node)) {
2524          result.abstract = true;
2525        }
2526        if (hasModifier(SyntaxKind.DeclareKeyword, node)) {
2527          result.declare = true;
2528        }
2529        // check for exports
2530        return this.fixExports(node, result);
2531      }
2532
2533      case SyntaxKind.TypePredicate: {
2534        const result = this.createNode<TSESTree.TSTypePredicate>(node, {
2535          type: AST_NODE_TYPES.TSTypePredicate,
2536          asserts: node.assertsModifier !== undefined,
2537          parameterName: this.convertChild(node.parameterName),
2538          typeAnnotation: null,
2539        });
2540        /**
2541         * Specific fix for type-guard location data
2542         */
2543        if (node.type) {
2544          result.typeAnnotation = this.convertTypeAnnotation(node.type, node);
2545          result.typeAnnotation.loc = result.typeAnnotation.typeAnnotation.loc;
2546          result.typeAnnotation.range =
2547            result.typeAnnotation.typeAnnotation.range;
2548        }
2549        return result;
2550      }
2551
2552      case SyntaxKind.ImportType:
2553        return this.createNode<TSESTree.TSImportType>(node, {
2554          type: AST_NODE_TYPES.TSImportType,
2555          isTypeOf: !!node.isTypeOf,
2556          parameter: this.convertChild(node.argument),
2557          qualifier: this.convertChild(node.qualifier),
2558          typeParameters: node.typeArguments
2559            ? this.convertTypeArgumentsToTypeParameters(
2560                node.typeArguments,
2561                node,
2562              )
2563            : null,
2564        });
2565
2566      case SyntaxKind.EnumDeclaration: {
2567        const result = this.createNode<TSESTree.TSEnumDeclaration>(node, {
2568          type: AST_NODE_TYPES.TSEnumDeclaration,
2569          id: this.convertChild(node.name),
2570          members: node.members.map(el => this.convertChild(el)),
2571        });
2572        // apply modifiers first...
2573        this.applyModifiersToResult(result, node.modifiers);
2574        // ...then check for exports
2575        return this.fixExports(node, result);
2576      }
2577
2578      case SyntaxKind.EnumMember: {
2579        const result = this.createNode<TSESTree.TSEnumMember>(node, {
2580          type: AST_NODE_TYPES.TSEnumMember,
2581          id: this.convertChild(node.name),
2582        });
2583        if (node.initializer) {
2584          result.initializer = this.convertChild(node.initializer);
2585        }
2586        if (node.name.kind === ts.SyntaxKind.ComputedPropertyName) {
2587          result.computed = true;
2588        }
2589        return result;
2590      }
2591
2592      case SyntaxKind.ModuleDeclaration: {
2593        const result = this.createNode<TSESTree.TSModuleDeclaration>(node, {
2594          type: AST_NODE_TYPES.TSModuleDeclaration,
2595          id: this.convertChild(node.name),
2596        });
2597        if (node.body) {
2598          result.body = this.convertChild(node.body);
2599        }
2600        // apply modifiers first...
2601        this.applyModifiersToResult(result, node.modifiers);
2602        if (node.flags & ts.NodeFlags.GlobalAugmentation) {
2603          result.global = true;
2604        }
2605        // ...then check for exports
2606        return this.fixExports(node, result);
2607      }
2608
2609      // TypeScript specific types
2610      case SyntaxKind.ParenthesizedType: {
2611        return this.createNode<TSESTree.TSParenthesizedType>(node, {
2612          type: AST_NODE_TYPES.TSParenthesizedType,
2613          typeAnnotation: this.convertType(node.type),
2614        });
2615      }
2616      case SyntaxKind.UnionType: {
2617        return this.createNode<TSESTree.TSUnionType>(node, {
2618          type: AST_NODE_TYPES.TSUnionType,
2619          types: node.types.map(el => this.convertType(el)),
2620        });
2621      }
2622      case SyntaxKind.IntersectionType: {
2623        return this.createNode<TSESTree.TSIntersectionType>(node, {
2624          type: AST_NODE_TYPES.TSIntersectionType,
2625          types: node.types.map(el => this.convertType(el)),
2626        });
2627      }
2628      case SyntaxKind.AsExpression: {
2629        return this.createNode<TSESTree.TSAsExpression>(node, {
2630          type: AST_NODE_TYPES.TSAsExpression,
2631          expression: this.convertChild(node.expression),
2632          typeAnnotation: this.convertType(node.type),
2633        });
2634      }
2635      case SyntaxKind.InferType: {
2636        return this.createNode<TSESTree.TSInferType>(node, {
2637          type: AST_NODE_TYPES.TSInferType,
2638          typeParameter: this.convertType(node.typeParameter),
2639        });
2640      }
2641      case SyntaxKind.LiteralType: {
2642        if (
2643          typescriptVersionIsAtLeast['4.0'] &&
2644          node.literal.kind === SyntaxKind.NullKeyword
2645        ) {
2646          // 4.0 started nesting null types inside a LiteralType node
2647          // but our AST is designed around the old way of null being a keyword
2648          return this.createNode<TSESTree.TSNullKeyword>(
2649            node.literal as ts.NullLiteral,
2650            {
2651              type: AST_NODE_TYPES.TSNullKeyword,
2652            },
2653          );
2654        } else {
2655          return this.createNode<TSESTree.TSLiteralType>(node, {
2656            type: AST_NODE_TYPES.TSLiteralType,
2657            literal: this.convertType(node.literal),
2658          });
2659        }
2660      }
2661      case SyntaxKind.TypeAssertionExpression: {
2662        return this.createNode<TSESTree.TSTypeAssertion>(node, {
2663          type: AST_NODE_TYPES.TSTypeAssertion,
2664          typeAnnotation: this.convertType(node.type),
2665          expression: this.convertChild(node.expression),
2666        });
2667      }
2668      case SyntaxKind.ImportEqualsDeclaration: {
2669        return this.createNode<TSESTree.TSImportEqualsDeclaration>(node, {
2670          type: AST_NODE_TYPES.TSImportEqualsDeclaration,
2671          id: this.convertChild(node.name),
2672          moduleReference: this.convertChild(node.moduleReference),
2673          isExport: hasModifier(SyntaxKind.ExportKeyword, node),
2674        });
2675      }
2676      case SyntaxKind.ExternalModuleReference: {
2677        return this.createNode<TSESTree.TSExternalModuleReference>(node, {
2678          type: AST_NODE_TYPES.TSExternalModuleReference,
2679          expression: this.convertChild(node.expression),
2680        });
2681      }
2682      case SyntaxKind.NamespaceExportDeclaration: {
2683        return this.createNode<TSESTree.TSNamespaceExportDeclaration>(node, {
2684          type: AST_NODE_TYPES.TSNamespaceExportDeclaration,
2685          id: this.convertChild(node.name),
2686        });
2687      }
2688      case SyntaxKind.AbstractKeyword: {
2689        return this.createNode<TSESTree.TSAbstractKeyword>(node, {
2690          type: AST_NODE_TYPES.TSAbstractKeyword,
2691        });
2692      }
2693
2694      // Tuple
2695      case SyntaxKind.TupleType: {
2696        // In TS 4.0, the `elementTypes` property was changed to `elements`.
2697        // To support both at compile time, we cast to access the newer version
2698        // if the former does not exist.
2699        const elementTypes =
2700          'elementTypes' in node
2701            ? (node as any).elementTypes.map((el: ts.Node) =>
2702                this.convertType(el),
2703              )
2704            : node.elements.map((el: ts.Node) => this.convertType(el));
2705
2706        return this.createNode<TSESTree.TSTupleType>(node, {
2707          type: AST_NODE_TYPES.TSTupleType,
2708          elementTypes,
2709        });
2710      }
2711      case SyntaxKind.NamedTupleMember: {
2712        const member = this.createNode<TSESTree.TSNamedTupleMember>(node, {
2713          type: AST_NODE_TYPES.TSNamedTupleMember,
2714          elementType: this.convertType(node.type, node),
2715          label: this.convertChild(node.name, node),
2716          optional: node.questionToken != null,
2717        });
2718
2719        if (node.dotDotDotToken) {
2720          // adjust the start to account for the "..."
2721          member.range[0] = member.label.range[0];
2722          member.loc.start = member.label.loc.start;
2723          return this.createNode<TSESTree.TSRestType>(node, {
2724            type: AST_NODE_TYPES.TSRestType,
2725            typeAnnotation: member,
2726          });
2727        }
2728
2729        return member;
2730      }
2731      case SyntaxKind.OptionalType: {
2732        return this.createNode<TSESTree.TSOptionalType>(node, {
2733          type: AST_NODE_TYPES.TSOptionalType,
2734          typeAnnotation: this.convertType(node.type),
2735        });
2736      }
2737      case SyntaxKind.RestType: {
2738        return this.createNode<TSESTree.TSRestType>(node, {
2739          type: AST_NODE_TYPES.TSRestType,
2740          typeAnnotation: this.convertType(node.type),
2741        });
2742      }
2743
2744      // Template Literal Types
2745      case SyntaxKind.TemplateLiteralType: {
2746        const result = this.createNode<TSESTree.TSTemplateLiteralType>(node, {
2747          type: AST_NODE_TYPES.TSTemplateLiteralType,
2748          quasis: [this.convertChild(node.head)],
2749          types: [],
2750        });
2751
2752        node.templateSpans.forEach(templateSpan => {
2753          result.types.push(this.convertChild(templateSpan.type));
2754          result.quasis.push(this.convertChild(templateSpan.literal));
2755        });
2756        return result;
2757      }
2758
2759      default:
2760        return this.deeplyCopy(node);
2761    }
2762  }
2763}
2764