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