UNPKG

83 kBJavaScriptView Raw
1/**
2 * @fileoverview Converts TypeScript AST into ESTree format.
3 * @author Nicholas C. Zakas
4 * @author James Henry <https://github.com/JamesHenry>
5 * @copyright jQuery Foundation and other contributors, https://jquery.org/
6 * MIT License
7 */
8
9"use strict";
10
11//------------------------------------------------------------------------------
12// Requirements
13//------------------------------------------------------------------------------
14
15const nodeUtils = require("./node-utils"),
16 AST_NODE_TYPES = require("./ast-node-types");
17
18//------------------------------------------------------------------------------
19// Private
20//------------------------------------------------------------------------------
21
22const SyntaxKind = nodeUtils.SyntaxKind;
23
24//------------------------------------------------------------------------------
25// Public
26//------------------------------------------------------------------------------
27
28/**
29 * Converts a TypeScript node into an ESTree node
30 * @param {Object} config configuration options for the conversion
31 * @param {TSNode} config.node the TSNode
32 * @param {TSNode} config.parent the parent TSNode
33 * @param {TSNode} config.ast the full TypeScript AST
34 * @param {Object} config.additionalOptions additional options for the conversion
35 * @param {Object} config.additionalOptions.errorOnUnknownASTType whether whether or not to throw an error if an unknown AST Node Type is encountered
36 * @returns {ESTreeNode} the converted ESTreeNode
37 */
38module.exports = function convert(config) {
39
40 const node = config.node;
41 const parent = config.parent;
42 const ast = config.ast;
43 const additionalOptions = config.additionalOptions || {};
44
45 /**
46 * Exit early for null and undefined
47 */
48 if (!node) {
49 return null;
50 }
51
52 /**
53 * Create a new ESTree node
54 */
55 let result = {
56 type: "",
57 range: [node.getStart(), node.end],
58 loc: nodeUtils.getLoc(node, ast)
59 };
60
61 /**
62 * Copies the result object into an ESTree node with just a type property.
63 * This is used only for leaf nodes that have no other properties.
64 * @returns {void}
65 */
66 function simplyCopy() {
67 Object.assign(result, {
68 type: SyntaxKind[node.kind]
69 });
70 }
71
72 /**
73 * If we are parsing for ESLint we need to perform a custom namespacing step
74 * on functions which have no body so that we do not break any ESLint rules which
75 * rely on them to have one.
76 *
77 * @param {ESTreeNode} functionNode the converted ESTreeNode
78 * @returns {void}
79 */
80 function namespaceEmptyBodyFunctionForESLint(functionNode) {
81 if (!config.additionalOptions.parseForESLint || functionNode.body) {
82 return;
83 }
84 functionNode.type = `TSEmptyBody${functionNode.type}`;
85 }
86
87 /**
88 * Converts a TypeScript node into an ESTree node.
89 * @param {TSNode} child the child TSNode
90 * @returns {ESTreeNode} the converted ESTree node
91 */
92 function convertChild(child) {
93 return convert({ node: child, parent: node, ast, additionalOptions });
94 }
95
96 /**
97 * Converts a child into a type annotation. This creates an intermediary
98 * TypeAnnotation node to match what Flow does.
99 * @param {TSNode} child The TypeScript AST node to convert.
100 * @returns {ESTreeNode} The type annotation node.
101 */
102 function convertTypeAnnotation(child) {
103 const annotation = convertChild(child);
104 const annotationStartCol = child.getFullStart() - 1;
105 const loc = nodeUtils.getLocFor(annotationStartCol, child.end, ast);
106 return {
107 type: AST_NODE_TYPES.TSTypeAnnotation,
108 loc,
109 range: [annotationStartCol, child.end],
110 typeAnnotation: annotation
111 };
112 }
113
114 /**
115 * Converts a TSNode's typeArguments array to a flow-like typeParameters node
116 * @param {TSNode[]} typeArguments TSNode typeArguments
117 * @returns {TypeParameterInstantiation} TypeParameterInstantiation node
118 */
119 function convertTypeArgumentsToTypeParameters(typeArguments) {
120 /**
121 * Even if typeArguments is an empty array, TypeScript sets a `pos` and `end`
122 * property on the array object so we can safely read the values here
123 */
124 const start = typeArguments.pos - 1;
125 let end = typeArguments.end + 1;
126 if (typeArguments && typeArguments.length) {
127 const firstTypeArgument = typeArguments[0];
128 const typeArgumentsParent = firstTypeArgument.parent;
129 /**
130 * In the case of the parent being a CallExpression or a TypeReference we have to use
131 * slightly different logic to calculate the correct end position
132 */
133 if (typeArgumentsParent && (typeArgumentsParent.kind === SyntaxKind.CallExpression || typeArgumentsParent.kind === SyntaxKind.TypeReference)) {
134 const lastTypeArgument = typeArguments[typeArguments.length - 1];
135 const greaterThanToken = nodeUtils.findNextToken(lastTypeArgument, ast);
136 end = greaterThanToken.end;
137 }
138 }
139 return {
140 type: AST_NODE_TYPES.TSTypeParameterInstantiation,
141 range: [
142 start,
143 end
144 ],
145 loc: nodeUtils.getLocFor(start, end, ast),
146 params: typeArguments.map(typeArgument => {
147 if (nodeUtils.isTypeKeyword(typeArgument.kind)) {
148 return {
149 type: AST_NODE_TYPES[`TS${SyntaxKind[typeArgument.kind]}`],
150 range: [
151 typeArgument.getStart(),
152 typeArgument.getEnd()
153 ],
154 loc: nodeUtils.getLoc(typeArgument, ast)
155 };
156 }
157 return {
158 type: AST_NODE_TYPES.TSTypeReference,
159 range: [
160 typeArgument.getStart(),
161 typeArgument.getEnd()
162 ],
163 loc: nodeUtils.getLoc(typeArgument, ast),
164 typeName: convertChild(typeArgument.typeName || typeArgument),
165 typeParameters: (typeArgument.typeArguments)
166 ? convertTypeArgumentsToTypeParameters(typeArgument.typeArguments)
167 : undefined
168 };
169 })
170 };
171 }
172
173 /**
174 * Converts a TSNode's typeParameters array to a flow-like TypeParameterDeclaration node
175 * @param {TSNode[]} typeParameters TSNode typeParameters
176 * @returns {TypeParameterDeclaration} TypeParameterDeclaration node
177 */
178 function convertTSTypeParametersToTypeParametersDeclaration(typeParameters) {
179 const firstTypeParameter = typeParameters[0];
180 const lastTypeParameter = typeParameters[typeParameters.length - 1];
181
182 const greaterThanToken = nodeUtils.findNextToken(lastTypeParameter, ast);
183
184 return {
185 type: AST_NODE_TYPES.TSTypeParameterDeclaration,
186 range: [
187 firstTypeParameter.pos - 1,
188 greaterThanToken.end
189 ],
190 loc: nodeUtils.getLocFor(firstTypeParameter.pos - 1, greaterThanToken.end, ast),
191 params: typeParameters.map(typeParameter => {
192 const name = nodeUtils.unescapeIdentifier(typeParameter.name.text);
193
194 const constraint = typeParameter.constraint
195 ? convert({ node: typeParameter.constraint, parent: typeParameter, ast, additionalOptions })
196 : undefined;
197
198 const defaultParameter = typeParameter.default
199 ? convert({ node: typeParameter.default, parent: typeParameter, ast, additionalOptions })
200 : typeParameter.default;
201
202 return {
203 type: AST_NODE_TYPES.TSTypeParameter,
204 range: [
205 typeParameter.getStart(),
206 typeParameter.getEnd()
207 ],
208 loc: nodeUtils.getLoc(typeParameter, ast),
209 name,
210 constraint,
211 default: defaultParameter
212 };
213 })
214 };
215 }
216
217 /**
218 * Converts a child into a class implements node. This creates an intermediary
219 * ClassImplements node to match what Flow does.
220 * @param {TSNode} child The TypeScript AST node to convert.
221 * @returns {ESTreeNode} The type annotation node.
222 */
223 function convertClassImplements(child) {
224 const id = convertChild(child.expression);
225 const classImplementsNode = {
226 type: AST_NODE_TYPES.ClassImplements,
227 loc: id.loc,
228 range: id.range,
229 id
230 };
231 if (child.typeArguments && child.typeArguments.length) {
232 classImplementsNode.typeParameters = convertTypeArgumentsToTypeParameters(child.typeArguments);
233 }
234 return classImplementsNode;
235 }
236
237 /**
238 * Converts a child into a interface heritage node.
239 * @param {TSNode} child The TypeScript AST node to convert.
240 * @returns {ESTreeNode} The type annotation node.
241 */
242 function convertInterfaceHeritageClause(child) {
243 const id = convertChild(child.expression);
244 const classImplementsNode = {
245 type: AST_NODE_TYPES.TSInterfaceHeritage,
246 loc: id.loc,
247 range: id.range,
248 id
249 };
250
251 if (child.typeArguments && child.typeArguments.length) {
252 classImplementsNode.typeParameters = convertTypeArgumentsToTypeParameters(child.typeArguments);
253 }
254 return classImplementsNode;
255 }
256
257 /**
258 * Converts an array of TSNode decorators into an array of ESTreeNode decorators
259 * @param {TSNode[]} decorators An array of TSNode decorators to be converted
260 * @returns {ESTreeNode[]} an array of converted ESTreeNode decorators
261 */
262 function convertDecorators(decorators) {
263 if (!decorators || !decorators.length) {
264 return [];
265 }
266 return decorators.map(decorator => {
267 const expression = convertChild(decorator.expression);
268 return {
269 type: AST_NODE_TYPES.Decorator,
270 range: [decorator.getStart(), decorator.end],
271 loc: nodeUtils.getLoc(decorator, ast),
272 expression
273 };
274 });
275 }
276
277 /**
278 * Converts an array of TSNode parameters into an array of ESTreeNode params
279 * @param {TSNode[]} parameters An array of TSNode params to be converted
280 * @returns {ESTreeNode[]} an array of converted ESTreeNode params
281 */
282 function convertParameters(parameters) {
283 if (!parameters || !parameters.length) {
284 return [];
285 }
286 return parameters.map(param => {
287 const convertedParam = convertChild(param);
288 if (!param.decorators || !param.decorators.length) {
289 return convertedParam;
290 }
291 return Object.assign(convertedParam, {
292 decorators: convertDecorators(param.decorators)
293 });
294 });
295 }
296
297 /**
298 * For nodes that are copied directly from the TypeScript AST into
299 * ESTree mostly as-is. The only difference is the addition of a type
300 * property instead of a kind property. Recursively copies all children.
301 * @returns {void}
302 */
303 function deeplyCopy() {
304 const customType = `TS${SyntaxKind[node.kind]}`;
305 /**
306 * If the "errorOnUnknownASTType" option is set to true, throw an error,
307 * otherwise fallback to just inlcuding the unknown type as-is.
308 */
309 if (additionalOptions.errorOnUnknownASTType && !AST_NODE_TYPES[customType]) {
310 throw new Error(`Unknown AST_NODE_TYPE: "${customType}"`);
311 }
312 result.type = customType;
313 Object
314 .keys(node)
315 .filter(key => !(/^(?:_children|kind|parent|pos|end|flags|modifierFlagsCache|jsDoc)$/.test(key)))
316 .forEach(key => {
317 if (key === "type") {
318 result.typeAnnotation = (node.type) ? convertTypeAnnotation(node.type) : null;
319 } else if (key === "typeArguments") {
320 result.typeParameters = (node.typeArguments)
321 ? convertTypeArgumentsToTypeParameters(node.typeArguments)
322 : null;
323 } else if (key === "typeParameters") {
324 result.typeParameters = (node.typeParameters)
325 ? convertTSTypeParametersToTypeParametersDeclaration(node.typeParameters)
326 : null;
327 } else if (key === "decorators") {
328 const decorators = convertDecorators(node.decorators);
329 if (decorators && decorators.length) {
330 result.decorators = decorators;
331 }
332 } else {
333 if (Array.isArray(node[key])) {
334 result[key] = node[key].map(convertChild);
335 } else if (node[key] && typeof node[key] === "object") {
336 result[key] = convertChild(node[key]);
337 } else {
338 result[key] = node[key];
339 }
340 }
341 });
342 }
343
344 /**
345 * Converts a TypeScript JSX node.tagName into an ESTree node.name
346 * @param {Object} tagName the tagName object from a JSX TSNode
347 * @param {Object} ast the AST object
348 * @returns {Object} the converted ESTree name object
349 */
350 function convertTypeScriptJSXTagNameToESTreeName(tagName) {
351 const tagNameToken = nodeUtils.convertToken(tagName, ast);
352
353 if (tagNameToken.type === AST_NODE_TYPES.JSXMemberExpression) {
354
355 const isNestedMemberExpression = (node.tagName.expression.kind === SyntaxKind.PropertyAccessExpression);
356
357 // Convert TSNode left and right objects into ESTreeNode object
358 // and property objects
359 tagNameToken.object = convertChild(node.tagName.expression);
360 tagNameToken.property = convertChild(node.tagName.name);
361
362 // Assign the appropriate types
363 tagNameToken.object.type = (isNestedMemberExpression) ? AST_NODE_TYPES.JSXMemberExpression : AST_NODE_TYPES.JSXIdentifier;
364 tagNameToken.property.type = AST_NODE_TYPES.JSXIdentifier;
365 if (tagName.expression.kind === SyntaxKind.ThisKeyword) {
366 tagNameToken.object.name = "this";
367 }
368 } else {
369 tagNameToken.type = AST_NODE_TYPES.JSXIdentifier;
370 tagNameToken.name = tagNameToken.value;
371 }
372
373 delete tagNameToken.value;
374
375 return tagNameToken;
376 }
377
378 /**
379 * Applies the given TS modifiers to the given result object.
380 * @param {TSNode[]} modifiers original TSNodes from the node.modifiers array
381 * @returns {void} (the current result object will be mutated)
382 */
383 function applyModifiersToResult(modifiers) {
384 if (!modifiers || !modifiers.length) {
385 return;
386 }
387 /**
388 * Some modifiers are explicitly handled by applying them as
389 * boolean values on the result node. As well as adding them
390 * to the result, we remove them from the array, so that they
391 * are not handled twice.
392 */
393 const handledModifierIndices = {};
394 for (let i = 0; i < modifiers.length; i++) {
395 const modifier = modifiers[i];
396 switch (modifier.kind) {
397 /**
398 * Ignore ExportKeyword and DefaultKeyword, they are handled
399 * via the fixExports utility function
400 */
401 case SyntaxKind.ExportKeyword:
402 case SyntaxKind.DefaultKeyword:
403 handledModifierIndices[i] = true;
404 break;
405 case SyntaxKind.ConstKeyword:
406 result.const = true;
407 handledModifierIndices[i] = true;
408 break;
409 case SyntaxKind.DeclareKeyword:
410 result.declare = true;
411 handledModifierIndices[i] = true;
412 break;
413 default:
414 }
415 }
416 /**
417 * If there are still valid modifiers available which have
418 * not been explicitly handled above, we just convert and
419 * add the modifiers array to the result node.
420 */
421 const remainingModifiers = modifiers.filter((_, i) => !handledModifierIndices[i]);
422 if (!remainingModifiers || !remainingModifiers.length) {
423 return;
424 }
425 result.modifiers = remainingModifiers.map(convertChild);
426 }
427
428 /**
429 * Uses the current TSNode's end location for its `type` to adjust the location data of the given
430 * ESTreeNode, which should be the parent of the final typeAnnotation node
431 * @param {ESTreeNode} typeAnnotationParent The node that will have its location data mutated
432 * @returns {void}
433 */
434 function fixTypeAnnotationParentLocation(typeAnnotationParent) {
435 const end = node.type.getEnd();
436 typeAnnotationParent.range[1] = end;
437 const loc = nodeUtils.getLocFor(typeAnnotationParent.range[0], typeAnnotationParent.range[1], ast);
438 typeAnnotationParent.loc = loc;
439 }
440
441 /**
442 * The core of the conversion logic:
443 * Identify and convert each relevant TypeScript SyntaxKind
444 */
445 switch (node.kind) {
446
447 case SyntaxKind.SourceFile:
448 Object.assign(result, {
449 type: AST_NODE_TYPES.Program,
450 body: [],
451 sourceType: node.externalModuleIndicator ? "module" : "script"
452 });
453
454 // filter out unknown nodes for now
455 node.statements.forEach(statement => {
456 const convertedStatement = convertChild(statement);
457 if (convertedStatement) {
458 result.body.push(convertedStatement);
459 }
460 });
461
462 result.range[1] = node.endOfFileToken.end;
463 result.loc = nodeUtils.getLocFor(node.getStart(), result.range[1], ast);
464 break;
465
466 case SyntaxKind.Block:
467 Object.assign(result, {
468 type: AST_NODE_TYPES.BlockStatement,
469 body: node.statements.map(convertChild)
470 });
471 break;
472
473 case SyntaxKind.Identifier:
474 Object.assign(result, {
475 type: AST_NODE_TYPES.Identifier,
476 name: nodeUtils.unescapeIdentifier(node.text)
477 });
478 break;
479
480 case SyntaxKind.WithStatement:
481 Object.assign(result, {
482 type: AST_NODE_TYPES.WithStatement,
483 object: convertChild(node.expression),
484 body: convertChild(node.statement)
485 });
486 break;
487
488 // Control Flow
489
490 case SyntaxKind.ReturnStatement:
491 Object.assign(result, {
492 type: AST_NODE_TYPES.ReturnStatement,
493 argument: convertChild(node.expression)
494 });
495 break;
496
497 case SyntaxKind.LabeledStatement:
498 Object.assign(result, {
499 type: AST_NODE_TYPES.LabeledStatement,
500 label: convertChild(node.label),
501 body: convertChild(node.statement)
502 });
503 break;
504
505 case SyntaxKind.BreakStatement:
506 case SyntaxKind.ContinueStatement:
507 Object.assign(result, {
508 type: SyntaxKind[node.kind],
509 label: convertChild(node.label)
510 });
511 break;
512
513 // Choice
514
515 case SyntaxKind.IfStatement:
516 Object.assign(result, {
517 type: AST_NODE_TYPES.IfStatement,
518 test: convertChild(node.expression),
519 consequent: convertChild(node.thenStatement),
520 alternate: convertChild(node.elseStatement)
521 });
522 break;
523
524 case SyntaxKind.SwitchStatement:
525 Object.assign(result, {
526 type: AST_NODE_TYPES.SwitchStatement,
527 discriminant: convertChild(node.expression),
528 cases: node.caseBlock.clauses.map(convertChild)
529 });
530 break;
531
532 case SyntaxKind.CaseClause:
533 case SyntaxKind.DefaultClause:
534 Object.assign(result, {
535 type: AST_NODE_TYPES.SwitchCase,
536 test: convertChild(node.expression),
537 consequent: node.statements.map(convertChild)
538 });
539 break;
540
541 // Exceptions
542
543 case SyntaxKind.ThrowStatement:
544 Object.assign(result, {
545 type: AST_NODE_TYPES.ThrowStatement,
546 argument: convertChild(node.expression)
547 });
548 break;
549
550 case SyntaxKind.TryStatement:
551 Object.assign(result, {
552 type: AST_NODE_TYPES.TryStatement,
553 block: convert({ node: node.tryBlock, parent: null, ast, additionalOptions }),
554 handler: convertChild(node.catchClause),
555 finalizer: convertChild(node.finallyBlock)
556 });
557 break;
558
559 case SyntaxKind.CatchClause:
560 Object.assign(result, {
561 type: AST_NODE_TYPES.CatchClause,
562 param: node.variableDeclaration ? convertChild(node.variableDeclaration.name) : null,
563 body: convertChild(node.block)
564 });
565 break;
566
567 // Loops
568
569 case SyntaxKind.WhileStatement:
570 Object.assign(result, {
571 type: AST_NODE_TYPES.WhileStatement,
572 test: convertChild(node.expression),
573 body: convertChild(node.statement)
574 });
575 break;
576
577 /**
578 * Unlike other parsers, TypeScript calls a "DoWhileStatement"
579 * a "DoStatement"
580 */
581 case SyntaxKind.DoStatement:
582 Object.assign(result, {
583 type: AST_NODE_TYPES.DoWhileStatement,
584 test: convertChild(node.expression),
585 body: convertChild(node.statement)
586 });
587 break;
588
589 case SyntaxKind.ForStatement:
590 Object.assign(result, {
591 type: AST_NODE_TYPES.ForStatement,
592 init: convertChild(node.initializer),
593 test: convertChild(node.condition),
594 update: convertChild(node.incrementor),
595 body: convertChild(node.statement)
596 });
597 break;
598
599 case SyntaxKind.ForInStatement:
600 case SyntaxKind.ForOfStatement: {
601 const isAwait = !!(node.awaitModifier && node.awaitModifier.kind === SyntaxKind.AwaitKeyword);
602 Object.assign(result, {
603 type: SyntaxKind[node.kind],
604 left: convertChild(node.initializer),
605 right: convertChild(node.expression),
606 body: convertChild(node.statement),
607 await: isAwait
608 });
609 break;
610 }
611
612 // Declarations
613
614 case SyntaxKind.FunctionDeclaration: {
615
616 let functionDeclarationType = AST_NODE_TYPES.FunctionDeclaration;
617
618 if (node.modifiers && node.modifiers.length) {
619 const isDeclareFunction = nodeUtils.hasModifier(SyntaxKind.DeclareKeyword, node);
620 if (isDeclareFunction) {
621 functionDeclarationType = AST_NODE_TYPES.DeclareFunction;
622 }
623 }
624
625 Object.assign(result, {
626 type: functionDeclarationType,
627 id: convertChild(node.name),
628 generator: !!node.asteriskToken,
629 expression: false,
630 async: nodeUtils.hasModifier(SyntaxKind.AsyncKeyword, node),
631 params: convertParameters(node.parameters),
632 body: convertChild(node.body)
633 });
634
635 // Process returnType
636 if (node.type) {
637 result.returnType = convertTypeAnnotation(node.type);
638 }
639
640 // Process typeParameters
641 if (node.typeParameters && node.typeParameters.length) {
642 result.typeParameters = convertTSTypeParametersToTypeParametersDeclaration(node.typeParameters);
643 }
644
645 namespaceEmptyBodyFunctionForESLint(result);
646
647 // check for exports
648 result = nodeUtils.fixExports(node, result, ast);
649
650 break;
651
652 }
653
654 case SyntaxKind.VariableDeclaration: {
655 Object.assign(result, {
656 type: AST_NODE_TYPES.VariableDeclarator,
657 id: convertChild(node.name),
658 init: convertChild(node.initializer)
659 });
660
661 if (node.exclamationToken) {
662 result.definite = true;
663 }
664
665 if (node.type) {
666 result.id.typeAnnotation = convertTypeAnnotation(node.type);
667 fixTypeAnnotationParentLocation(result.id);
668 }
669 break;
670 }
671
672 case SyntaxKind.VariableStatement:
673 Object.assign(result, {
674 type: AST_NODE_TYPES.VariableDeclaration,
675 declarations: node.declarationList.declarations.map(convertChild),
676 kind: nodeUtils.getDeclarationKind(node.declarationList)
677 });
678
679 // check for exports
680 result = nodeUtils.fixExports(node, result, ast);
681 break;
682
683 // mostly for for-of, for-in
684 case SyntaxKind.VariableDeclarationList:
685 Object.assign(result, {
686 type: AST_NODE_TYPES.VariableDeclaration,
687 declarations: node.declarations.map(convertChild),
688 kind: nodeUtils.getDeclarationKind(node)
689 });
690 break;
691
692 // Expressions
693
694 case SyntaxKind.ExpressionStatement:
695 Object.assign(result, {
696 type: AST_NODE_TYPES.ExpressionStatement,
697 expression: convertChild(node.expression)
698 });
699 break;
700
701 case SyntaxKind.ThisKeyword:
702 Object.assign(result, {
703 type: AST_NODE_TYPES.ThisExpression
704 });
705 break;
706
707 case SyntaxKind.ArrayLiteralExpression: {
708
709 const arrayAssignNode = nodeUtils.findAncestorOfKind(node, SyntaxKind.BinaryExpression);
710 const arrayIsInForOf = node.parent && node.parent.kind === SyntaxKind.ForOfStatement;
711 const arrayIsInForIn = node.parent && node.parent.kind === SyntaxKind.ForInStatement;
712 let arrayIsInAssignment;
713
714 if (arrayAssignNode) {
715 if (arrayAssignNode.left === node) {
716 arrayIsInAssignment = true;
717 } else {
718 arrayIsInAssignment = (nodeUtils.findChildOfKind(arrayAssignNode.left, SyntaxKind.ArrayLiteralExpression, ast) === node);
719 }
720 }
721
722 // TypeScript uses ArrayLiteralExpression in destructuring assignment, too
723 if (arrayIsInAssignment || arrayIsInForOf || arrayIsInForIn) {
724 Object.assign(result, {
725 type: AST_NODE_TYPES.ArrayPattern,
726 elements: node.elements.map(convertChild)
727 });
728 } else {
729 Object.assign(result, {
730 type: AST_NODE_TYPES.ArrayExpression,
731 elements: node.elements.map(convertChild)
732 });
733 }
734 break;
735
736 }
737
738 case SyntaxKind.ObjectLiteralExpression: {
739
740 const ancestorNode = nodeUtils.findFirstMatchingAncestor(
741 node,
742 parentNode =>
743 (parentNode.kind === SyntaxKind.BinaryExpression || parentNode.kind === SyntaxKind.ArrowFunction)
744 );
745 const objectAssignNode = (
746 ancestorNode &&
747 ancestorNode.kind === SyntaxKind.BinaryExpression &&
748 ancestorNode.operatorToken.kind === SyntaxKind.FirstAssignment
749 ) ? ancestorNode : null;
750
751 let objectIsInAssignment = false;
752
753 if (objectAssignNode) {
754 if (objectAssignNode.left === node) {
755 objectIsInAssignment = true;
756 } else {
757 objectIsInAssignment = (nodeUtils.findChildOfKind(objectAssignNode.left, SyntaxKind.ObjectLiteralExpression, ast) === node);
758 }
759 }
760
761 // TypeScript uses ObjectLiteralExpression in destructuring assignment, too
762 if (objectIsInAssignment) {
763 Object.assign(result, {
764 type: AST_NODE_TYPES.ObjectPattern,
765 properties: node.properties.map(convertChild)
766 });
767 } else {
768 Object.assign(result, {
769 type: AST_NODE_TYPES.ObjectExpression,
770 properties: node.properties.map(convertChild)
771 });
772 }
773
774 break;
775
776 }
777
778 case SyntaxKind.PropertyAssignment:
779 Object.assign(result, {
780 type: AST_NODE_TYPES.Property,
781 key: convertChild(node.name),
782 value: convertChild(node.initializer),
783 computed: nodeUtils.isComputedProperty(node.name),
784 method: false,
785 shorthand: false,
786 kind: "init"
787 });
788 break;
789
790 case SyntaxKind.ShorthandPropertyAssignment: {
791 if (node.objectAssignmentInitializer) {
792 Object.assign(result, {
793 type: AST_NODE_TYPES.Property,
794 key: convertChild(node.name),
795 value: {
796 type: AST_NODE_TYPES.AssignmentPattern,
797 left: convertChild(node.name),
798 right: convertChild(node.objectAssignmentInitializer),
799 loc: result.loc,
800 range: result.range
801 },
802 computed: false,
803 method: false,
804 shorthand: true,
805 kind: "init"
806 });
807 } else {
808 Object.assign(result, {
809 type: AST_NODE_TYPES.Property,
810 key: convertChild(node.name),
811 value: convertChild(node.initializer || node.name),
812 computed: false,
813 method: false,
814 shorthand: true,
815 kind: "init"
816 });
817 }
818 break;
819 }
820
821 case SyntaxKind.ComputedPropertyName:
822
823 if (parent.kind === SyntaxKind.ObjectLiteralExpression) {
824 Object.assign(result, {
825 type: AST_NODE_TYPES.Property,
826 key: convertChild(node.name),
827 value: convertChild(node.name),
828 computed: false,
829 method: false,
830 shorthand: true,
831 kind: "init"
832 });
833 } else {
834 return convertChild(node.expression);
835 }
836 break;
837
838 case SyntaxKind.PropertyDeclaration: {
839 const isAbstract = nodeUtils.hasModifier(SyntaxKind.AbstractKeyword, node);
840 Object.assign(result, {
841 type: (isAbstract) ? AST_NODE_TYPES.TSAbstractClassProperty : AST_NODE_TYPES.ClassProperty,
842 key: convertChild(node.name),
843 value: convertChild(node.initializer),
844 computed: nodeUtils.isComputedProperty(node.name),
845 static: nodeUtils.hasStaticModifierFlag(node),
846 readonly: nodeUtils.hasModifier(SyntaxKind.ReadonlyKeyword, node) || undefined
847 });
848
849 if (node.type) {
850 result.typeAnnotation = convertTypeAnnotation(node.type);
851 }
852
853 if (node.decorators) {
854 result.decorators = convertDecorators(node.decorators);
855 }
856
857 const accessibility = nodeUtils.getTSNodeAccessibility(node);
858 if (accessibility) {
859 result.accessibility = accessibility;
860 }
861
862 if (node.name.kind === SyntaxKind.Identifier && node.questionToken) {
863 result.key.optional = true;
864 }
865
866 if (node.exclamationToken) {
867 result.definite = true;
868 }
869
870 if (result.key.type === AST_NODE_TYPES.Literal && node.questionToken) {
871 result.optional = true;
872 }
873 break;
874 }
875
876 case SyntaxKind.GetAccessor:
877 case SyntaxKind.SetAccessor:
878 case SyntaxKind.MethodDeclaration: {
879
880 const openingParen = nodeUtils.findFirstMatchingToken(node.name, ast, token => {
881 if (!token || !token.kind) {
882 return false;
883 }
884 return nodeUtils.getTextForTokenKind(token.kind) === "(";
885 });
886
887 const methodLoc = ast.getLineAndCharacterOfPosition(openingParen.getStart()),
888 nodeIsMethod = (node.kind === SyntaxKind.MethodDeclaration),
889 method = {
890 type: AST_NODE_TYPES.FunctionExpression,
891 id: null,
892 generator: !!node.asteriskToken,
893 expression: false,
894 async: nodeUtils.hasModifier(SyntaxKind.AsyncKeyword, node),
895 body: convertChild(node.body),
896 range: [node.parameters.pos - 1, result.range[1]],
897 loc: {
898 start: {
899 line: methodLoc.line + 1,
900 column: methodLoc.character
901 },
902 end: result.loc.end
903 }
904 };
905
906 if (node.type) {
907 method.returnType = convertTypeAnnotation(node.type);
908 }
909
910 if (parent.kind === SyntaxKind.ObjectLiteralExpression) {
911
912 method.params = node.parameters.map(convertChild);
913
914 Object.assign(result, {
915 type: AST_NODE_TYPES.Property,
916 key: convertChild(node.name),
917 value: method,
918 computed: nodeUtils.isComputedProperty(node.name),
919 method: nodeIsMethod,
920 shorthand: false,
921 kind: "init"
922 });
923
924 } else { // class
925
926 /**
927 * Unlike in object literal methods, class method params can have decorators
928 */
929 method.params = convertParameters(node.parameters);
930
931 /**
932 * TypeScript class methods can be defined as "abstract"
933 */
934 const methodDefinitionType = nodeUtils.hasModifier(SyntaxKind.AbstractKeyword, node)
935 ? AST_NODE_TYPES.TSAbstractMethodDefinition
936 : AST_NODE_TYPES.MethodDefinition;
937
938 Object.assign(result, {
939 type: methodDefinitionType,
940 key: convertChild(node.name),
941 value: method,
942 computed: nodeUtils.isComputedProperty(node.name),
943 static: nodeUtils.hasStaticModifierFlag(node),
944 kind: "method"
945 });
946
947 if (node.decorators) {
948 result.decorators = convertDecorators(node.decorators);
949 }
950
951 const accessibility = nodeUtils.getTSNodeAccessibility(node);
952 if (accessibility) {
953 result.accessibility = accessibility;
954 }
955
956 }
957
958 if (result.key.type === AST_NODE_TYPES.Identifier && node.questionToken) {
959 result.key.optional = true;
960 }
961
962 if (node.kind === SyntaxKind.GetAccessor) {
963 result.kind = "get";
964 } else if (node.kind === SyntaxKind.SetAccessor) {
965 result.kind = "set";
966 } else if (!result.static && node.name.kind === SyntaxKind.StringLiteral && node.name.text === "constructor") {
967 result.kind = "constructor";
968 }
969
970 // Process typeParameters
971 if (node.typeParameters && node.typeParameters.length) {
972 method.typeParameters = convertTSTypeParametersToTypeParametersDeclaration(node.typeParameters);
973 }
974
975 namespaceEmptyBodyFunctionForESLint(result.value);
976
977 break;
978
979 }
980
981 // TypeScript uses this even for static methods named "constructor"
982 case SyntaxKind.Constructor: {
983
984 const constructorIsStatic = nodeUtils.hasStaticModifierFlag(node),
985 constructorIsAbstract = nodeUtils.hasModifier(SyntaxKind.AbstractKeyword, node),
986 firstConstructorToken = constructorIsStatic ? nodeUtils.findNextToken(node.getFirstToken(), ast) : node.getFirstToken(),
987 constructorLoc = ast.getLineAndCharacterOfPosition(node.parameters.pos - 1),
988 constructor = {
989 type: AST_NODE_TYPES.FunctionExpression,
990 id: null,
991 params: convertParameters(node.parameters),
992 generator: false,
993 expression: false,
994 async: false,
995 body: convertChild(node.body),
996 range: [node.parameters.pos - 1, result.range[1]],
997 loc: {
998 start: {
999 line: constructorLoc.line + 1,
1000 column: constructorLoc.character
1001 },
1002 end: result.loc.end
1003 }
1004 };
1005
1006 const constructorIdentifierLocStart = ast.getLineAndCharacterOfPosition(firstConstructorToken.getStart()),
1007 constructorIdentifierLocEnd = ast.getLineAndCharacterOfPosition(firstConstructorToken.getEnd()),
1008 constructorIsComputed = !!node.name && nodeUtils.isComputedProperty(node.name);
1009
1010 let constructorKey;
1011
1012 if (constructorIsComputed) {
1013 constructorKey = {
1014 type: AST_NODE_TYPES.Literal,
1015 value: "constructor",
1016 raw: node.name.getText(),
1017 range: [firstConstructorToken.getStart(), firstConstructorToken.end],
1018 loc: {
1019 start: {
1020 line: constructorIdentifierLocStart.line + 1,
1021 column: constructorIdentifierLocStart.character
1022 },
1023 end: {
1024 line: constructorIdentifierLocEnd.line + 1,
1025 column: constructorIdentifierLocEnd.character
1026 }
1027 }
1028 };
1029 } else {
1030 constructorKey = {
1031 type: AST_NODE_TYPES.Identifier,
1032 name: "constructor",
1033 range: [firstConstructorToken.getStart(), firstConstructorToken.end],
1034 loc: {
1035 start: {
1036 line: constructorIdentifierLocStart.line + 1,
1037 column: constructorIdentifierLocStart.character
1038 },
1039 end: {
1040 line: constructorIdentifierLocEnd.line + 1,
1041 column: constructorIdentifierLocEnd.character
1042 }
1043 }
1044 };
1045 }
1046
1047 Object.assign(result, {
1048 type: constructorIsAbstract ? AST_NODE_TYPES.TSAbstractMethodDefinition : AST_NODE_TYPES.MethodDefinition,
1049 key: constructorKey,
1050 value: constructor,
1051 computed: constructorIsComputed,
1052 static: constructorIsStatic,
1053 kind: (constructorIsStatic || constructorIsComputed) ? "method" : "constructor"
1054 });
1055
1056 const accessibility = nodeUtils.getTSNodeAccessibility(node);
1057 if (accessibility) {
1058 result.accessibility = accessibility;
1059 }
1060
1061 namespaceEmptyBodyFunctionForESLint(result.value);
1062
1063 break;
1064
1065 }
1066
1067 case SyntaxKind.FunctionExpression:
1068 Object.assign(result, {
1069 type: AST_NODE_TYPES.FunctionExpression,
1070 id: convertChild(node.name),
1071 generator: !!node.asteriskToken,
1072 params: convertParameters(node.parameters),
1073 body: convertChild(node.body),
1074 async: nodeUtils.hasModifier(SyntaxKind.AsyncKeyword, node),
1075 expression: false
1076 });
1077
1078 // Process returnType
1079 if (node.type) {
1080 result.returnType = convertTypeAnnotation(node.type);
1081 }
1082
1083 // Process typeParameters
1084 if (node.typeParameters && node.typeParameters.length) {
1085 result.typeParameters = convertTSTypeParametersToTypeParametersDeclaration(node.typeParameters);
1086 }
1087 break;
1088
1089 case SyntaxKind.SuperKeyword:
1090 Object.assign(result, {
1091 type: AST_NODE_TYPES.Super
1092 });
1093 break;
1094
1095 case SyntaxKind.ArrayBindingPattern:
1096 Object.assign(result, {
1097 type: AST_NODE_TYPES.ArrayPattern,
1098 elements: node.elements.map(convertChild)
1099 });
1100 break;
1101
1102 // occurs with missing array elements like [,]
1103 case SyntaxKind.OmittedExpression:
1104 return null;
1105
1106 case SyntaxKind.ObjectBindingPattern:
1107 Object.assign(result, {
1108 type: AST_NODE_TYPES.ObjectPattern,
1109 properties: node.elements.map(convertChild)
1110 });
1111 break;
1112
1113 case SyntaxKind.BindingElement:
1114
1115 if (parent.kind === SyntaxKind.ArrayBindingPattern) {
1116 const arrayItem = convert({ node: node.name, parent, ast, additionalOptions });
1117
1118 if (node.initializer) {
1119 Object.assign(result, {
1120 type: AST_NODE_TYPES.AssignmentPattern,
1121 left: arrayItem,
1122 right: convertChild(node.initializer)
1123 });
1124 } else if (node.dotDotDotToken) {
1125 Object.assign(result, {
1126 type: AST_NODE_TYPES.RestElement,
1127 argument: arrayItem
1128 });
1129 } else {
1130 return arrayItem;
1131 }
1132 } else if (parent.kind === SyntaxKind.ObjectBindingPattern) {
1133
1134 if (node.dotDotDotToken) {
1135 Object.assign(result, {
1136 type: AST_NODE_TYPES.ExperimentalRestProperty,
1137 argument: convertChild(node.propertyName || node.name),
1138 computed: Boolean(node.propertyName && node.propertyName.kind === SyntaxKind.ComputedPropertyName),
1139 shorthand: !node.propertyName
1140 });
1141 } else {
1142 Object.assign(result, {
1143 type: AST_NODE_TYPES.Property,
1144 key: convertChild(node.propertyName || node.name),
1145 value: convertChild(node.name),
1146 computed: Boolean(node.propertyName && node.propertyName.kind === SyntaxKind.ComputedPropertyName),
1147 method: false,
1148 shorthand: !node.propertyName,
1149 kind: "init"
1150 });
1151 }
1152
1153 if (node.initializer) {
1154 result.value = {
1155 type: AST_NODE_TYPES.AssignmentPattern,
1156 left: convertChild(node.name),
1157 right: convertChild(node.initializer),
1158 range: [node.name.getStart(), node.initializer.end],
1159 loc: nodeUtils.getLocFor(node.name.getStart(), node.initializer.end, ast)
1160 };
1161 }
1162 }
1163 break;
1164
1165
1166 case SyntaxKind.ArrowFunction:
1167 Object.assign(result, {
1168 type: AST_NODE_TYPES.ArrowFunctionExpression,
1169 generator: false,
1170 id: null,
1171 params: convertParameters(node.parameters),
1172 body: convertChild(node.body),
1173 async: nodeUtils.hasModifier(SyntaxKind.AsyncKeyword, node),
1174 expression: node.body.kind !== SyntaxKind.Block
1175 });
1176
1177 // Process returnType
1178 if (node.type) {
1179 result.returnType = convertTypeAnnotation(node.type);
1180 }
1181
1182 // Process typeParameters
1183 if (node.typeParameters && node.typeParameters.length) {
1184 result.typeParameters = convertTSTypeParametersToTypeParametersDeclaration(node.typeParameters);
1185 }
1186 break;
1187
1188 case SyntaxKind.YieldExpression:
1189 Object.assign(result, {
1190 type: AST_NODE_TYPES.YieldExpression,
1191 delegate: !!node.asteriskToken,
1192 argument: convertChild(node.expression)
1193 });
1194 break;
1195
1196 case SyntaxKind.AwaitExpression:
1197 Object.assign(result, {
1198 type: AST_NODE_TYPES.AwaitExpression,
1199 argument: convertChild(node.expression)
1200 });
1201 break;
1202
1203 // Template Literals
1204
1205 case SyntaxKind.NoSubstitutionTemplateLiteral:
1206 Object.assign(result, {
1207 type: AST_NODE_TYPES.TemplateLiteral,
1208 quasis: [
1209 {
1210 type: AST_NODE_TYPES.TemplateElement,
1211 value: {
1212 raw: ast.text.slice(node.getStart() + 1, node.end - 1),
1213 cooked: node.text
1214 },
1215 tail: true,
1216 range: result.range,
1217 loc: result.loc
1218 }
1219 ],
1220 expressions: []
1221 });
1222 break;
1223
1224 case SyntaxKind.TemplateExpression:
1225 Object.assign(result, {
1226 type: AST_NODE_TYPES.TemplateLiteral,
1227 quasis: [convertChild(node.head)],
1228 expressions: []
1229 });
1230
1231 node.templateSpans.forEach(templateSpan => {
1232 result.expressions.push(convertChild(templateSpan.expression));
1233 result.quasis.push(convertChild(templateSpan.literal));
1234 });
1235 break;
1236
1237 case SyntaxKind.TaggedTemplateExpression:
1238 Object.assign(result, {
1239 type: AST_NODE_TYPES.TaggedTemplateExpression,
1240 tag: convertChild(node.tag),
1241 quasi: convertChild(node.template)
1242 });
1243 break;
1244
1245 case SyntaxKind.TemplateHead:
1246 case SyntaxKind.TemplateMiddle:
1247 case SyntaxKind.TemplateTail: {
1248 const tail = (node.kind === SyntaxKind.TemplateTail);
1249 Object.assign(result, {
1250 type: AST_NODE_TYPES.TemplateElement,
1251 value: {
1252 raw: ast.text.slice(node.getStart() + 1, node.end - (tail ? 1 : 2)),
1253 cooked: node.text
1254 },
1255 tail
1256 });
1257 break;
1258 }
1259
1260 // Patterns
1261
1262 case SyntaxKind.SpreadElement: {
1263 let type = AST_NODE_TYPES.SpreadElement;
1264
1265 if (node.parent &&
1266 node.parent.parent &&
1267 node.parent.parent.kind === SyntaxKind.BinaryExpression
1268 ) {
1269 if (node.parent.parent.left === node.parent) {
1270 type = AST_NODE_TYPES.RestElement;
1271 } else if (node.parent.parent.right === node.parent) {
1272 type = AST_NODE_TYPES.SpreadElement;
1273 }
1274 }
1275
1276 Object.assign(result, {
1277 type,
1278 argument: convertChild(node.expression)
1279 });
1280 break;
1281 }
1282 case SyntaxKind.SpreadAssignment: {
1283 let type = AST_NODE_TYPES.ExperimentalSpreadProperty;
1284
1285 if (node.parent &&
1286 node.parent.parent &&
1287 node.parent.parent.kind === SyntaxKind.BinaryExpression
1288 ) {
1289 if (node.parent.parent.right === node.parent) {
1290 type = AST_NODE_TYPES.ExperimentalSpreadProperty;
1291 } else if (node.parent.parent.left === node.parent) {
1292 type = AST_NODE_TYPES.ExperimentalRestProperty;
1293 }
1294 }
1295
1296 Object.assign(result, {
1297 type,
1298 argument: convertChild(node.expression)
1299 });
1300 break;
1301 }
1302
1303 case SyntaxKind.Parameter: {
1304 let parameter;
1305
1306 if (node.dotDotDotToken) {
1307 parameter = convertChild(node.name);
1308 Object.assign(result, {
1309 type: AST_NODE_TYPES.RestElement,
1310 argument: parameter
1311 });
1312 } else if (node.initializer) {
1313 parameter = convertChild(node.name);
1314 Object.assign(result, {
1315 type: AST_NODE_TYPES.AssignmentPattern,
1316 left: parameter,
1317 right: convertChild(node.initializer)
1318 });
1319 } else {
1320 parameter = convert({ node: node.name, parent, ast, additionalOptions });
1321 result = parameter;
1322 }
1323
1324 if (node.type) {
1325 parameter.typeAnnotation = convertTypeAnnotation(node.type);
1326 fixTypeAnnotationParentLocation(parameter);
1327 }
1328
1329 if (node.questionToken) {
1330 parameter.optional = true;
1331 }
1332
1333 if (node.modifiers) {
1334 return {
1335 type: AST_NODE_TYPES.TSParameterProperty,
1336 range: [node.getStart(), node.end],
1337 loc: nodeUtils.getLoc(node, ast),
1338 accessibility: nodeUtils.getTSNodeAccessibility(node) || undefined,
1339 readonly: nodeUtils.hasModifier(SyntaxKind.ReadonlyKeyword, node) || undefined,
1340 static: nodeUtils.hasModifier(SyntaxKind.StaticKeyword, node) || undefined,
1341 export: nodeUtils.hasModifier(SyntaxKind.ExportKeyword, node) || undefined,
1342 parameter: result
1343 };
1344 }
1345
1346 break;
1347
1348 }
1349
1350 // Classes
1351
1352 case SyntaxKind.ClassDeclaration:
1353 case SyntaxKind.ClassExpression: {
1354
1355 const heritageClauses = node.heritageClauses || [];
1356
1357 let classNodeType = SyntaxKind[node.kind];
1358 let lastClassToken = heritageClauses.length ? heritageClauses[heritageClauses.length - 1] : node.name;
1359
1360 if (node.typeParameters && node.typeParameters.length) {
1361 const lastTypeParameter = node.typeParameters[node.typeParameters.length - 1];
1362
1363 if (!lastClassToken || lastTypeParameter.pos > lastClassToken.pos) {
1364 lastClassToken = nodeUtils.findNextToken(lastTypeParameter, ast);
1365 }
1366 result.typeParameters = convertTSTypeParametersToTypeParametersDeclaration(node.typeParameters);
1367 }
1368
1369 if (node.modifiers && node.modifiers.length) {
1370
1371 /**
1372 * TypeScript class declarations can be defined as "abstract"
1373 */
1374 if (node.kind === SyntaxKind.ClassDeclaration) {
1375 if (nodeUtils.hasModifier(SyntaxKind.AbstractKeyword, node)) {
1376 classNodeType = `TSAbstract${classNodeType}`;
1377 }
1378 }
1379
1380 /**
1381 * We need check for modifiers, and use the last one, as there
1382 * could be multiple before the open brace
1383 */
1384 const lastModifier = node.modifiers[node.modifiers.length - 1];
1385
1386 if (!lastClassToken || lastModifier.pos > lastClassToken.pos) {
1387 lastClassToken = nodeUtils.findNextToken(lastModifier, ast);
1388 }
1389
1390 } else if (!lastClassToken) { // no name
1391 lastClassToken = node.getFirstToken();
1392 }
1393
1394 const openBrace = nodeUtils.findNextToken(lastClassToken, ast);
1395 const superClass = heritageClauses.find(clause => clause.token === SyntaxKind.ExtendsKeyword);
1396
1397 if (superClass && superClass.types[0] && superClass.types[0].typeArguments) {
1398 result.superTypeParameters = convertTypeArgumentsToTypeParameters(superClass.types[0].typeArguments);
1399 }
1400
1401 const implementsClause = heritageClauses.find(clause => clause.token === SyntaxKind.ImplementsKeyword);
1402
1403 Object.assign(result, {
1404 type: classNodeType,
1405 id: convertChild(node.name),
1406 body: {
1407 type: AST_NODE_TYPES.ClassBody,
1408 body: [],
1409
1410 // TODO: Fix location info
1411 range: [openBrace.getStart(), result.range[1]],
1412 loc: nodeUtils.getLocFor(openBrace.getStart(), node.end, ast)
1413 },
1414 superClass: (superClass && superClass.types[0] ? convertChild(superClass.types[0].expression) : null)
1415 });
1416
1417 if (implementsClause) {
1418 result.implements = implementsClause.types.map(convertClassImplements);
1419 }
1420
1421 if (node.decorators) {
1422 result.decorators = convertDecorators(node.decorators);
1423 }
1424
1425 const filteredMembers = node.members.filter(nodeUtils.isESTreeClassMember);
1426
1427 if (filteredMembers.length) {
1428 result.body.body = filteredMembers.map(convertChild);
1429 }
1430
1431 // check for exports
1432 result = nodeUtils.fixExports(node, result, ast);
1433
1434 break;
1435
1436 }
1437
1438 // Modules
1439 case SyntaxKind.ModuleBlock:
1440 Object.assign(result, {
1441 type: AST_NODE_TYPES.TSModuleBlock,
1442 body: node.statements.map(convertChild)
1443 });
1444 break;
1445
1446 case SyntaxKind.ImportDeclaration:
1447 Object.assign(result, {
1448 type: AST_NODE_TYPES.ImportDeclaration,
1449 source: convertChild(node.moduleSpecifier),
1450 specifiers: []
1451 });
1452
1453 if (node.importClause) {
1454 if (node.importClause.name) {
1455 result.specifiers.push(convertChild(node.importClause));
1456 }
1457
1458 if (node.importClause.namedBindings) {
1459 if (node.importClause.namedBindings.kind === SyntaxKind.NamespaceImport) {
1460 result.specifiers.push(convertChild(node.importClause.namedBindings));
1461 } else {
1462 result.specifiers = result.specifiers.concat(node.importClause.namedBindings.elements.map(convertChild));
1463 }
1464 }
1465 }
1466
1467 break;
1468
1469 case SyntaxKind.NamespaceImport:
1470 Object.assign(result, {
1471 type: AST_NODE_TYPES.ImportNamespaceSpecifier,
1472 local: convertChild(node.name)
1473 });
1474 break;
1475
1476 case SyntaxKind.ImportSpecifier:
1477 Object.assign(result, {
1478 type: AST_NODE_TYPES.ImportSpecifier,
1479 local: convertChild(node.name),
1480 imported: convertChild(node.propertyName || node.name)
1481 });
1482 break;
1483
1484 case SyntaxKind.ImportClause:
1485 Object.assign(result, {
1486 type: AST_NODE_TYPES.ImportDefaultSpecifier,
1487 local: convertChild(node.name)
1488 });
1489
1490 // have to adjust location information due to tree differences
1491 result.range[1] = node.name.end;
1492 result.loc = nodeUtils.getLocFor(result.range[0], result.range[1], ast);
1493 break;
1494
1495 case SyntaxKind.NamedImports:
1496 Object.assign(result, {
1497 type: AST_NODE_TYPES.ImportDefaultSpecifier,
1498 local: convertChild(node.name)
1499 });
1500 break;
1501
1502 case SyntaxKind.ExportDeclaration:
1503 if (node.exportClause) {
1504 Object.assign(result, {
1505 type: AST_NODE_TYPES.ExportNamedDeclaration,
1506 source: convertChild(node.moduleSpecifier),
1507 specifiers: node.exportClause.elements.map(convertChild),
1508 declaration: null
1509 });
1510 } else {
1511 Object.assign(result, {
1512 type: AST_NODE_TYPES.ExportAllDeclaration,
1513 source: convertChild(node.moduleSpecifier)
1514 });
1515 }
1516 break;
1517
1518 case SyntaxKind.ExportSpecifier:
1519 Object.assign(result, {
1520 type: AST_NODE_TYPES.ExportSpecifier,
1521 local: convertChild(node.propertyName || node.name),
1522 exported: convertChild(node.name)
1523 });
1524 break;
1525
1526 case SyntaxKind.ExportAssignment:
1527 if (node.isExportEquals) {
1528 Object.assign(result, {
1529 type: AST_NODE_TYPES.TSExportAssignment,
1530 expression: convertChild(node.expression)
1531 });
1532 } else {
1533 Object.assign(result, {
1534 type: AST_NODE_TYPES.ExportDefaultDeclaration,
1535 declaration: convertChild(node.expression)
1536 });
1537 }
1538 break;
1539
1540 // Unary Operations
1541
1542 case SyntaxKind.PrefixUnaryExpression:
1543 case SyntaxKind.PostfixUnaryExpression: {
1544 const operator = nodeUtils.getTextForTokenKind(node.operator);
1545 Object.assign(result, {
1546 /**
1547 * ESTree uses UpdateExpression for ++/--
1548 */
1549 type: /^(?:\+\+|--)$/.test(operator) ? AST_NODE_TYPES.UpdateExpression : AST_NODE_TYPES.UnaryExpression,
1550 operator,
1551 prefix: node.kind === SyntaxKind.PrefixUnaryExpression,
1552 argument: convertChild(node.operand)
1553 });
1554 break;
1555 }
1556
1557 case SyntaxKind.DeleteExpression:
1558 Object.assign(result, {
1559 type: AST_NODE_TYPES.UnaryExpression,
1560 operator: "delete",
1561 prefix: true,
1562 argument: convertChild(node.expression)
1563 });
1564 break;
1565
1566 case SyntaxKind.VoidExpression:
1567 Object.assign(result, {
1568 type: AST_NODE_TYPES.UnaryExpression,
1569 operator: "void",
1570 prefix: true,
1571 argument: convertChild(node.expression)
1572 });
1573 break;
1574
1575 case SyntaxKind.TypeOfExpression:
1576 Object.assign(result, {
1577 type: AST_NODE_TYPES.UnaryExpression,
1578 operator: "typeof",
1579 prefix: true,
1580 argument: convertChild(node.expression)
1581 });
1582 break;
1583
1584 case SyntaxKind.TypeOperator:
1585 Object.assign(result, {
1586 type: AST_NODE_TYPES.TSTypeOperator,
1587 operator: nodeUtils.getTextForTokenKind(node.operator),
1588 typeAnnotation: convertChild(node.type)
1589 });
1590 break;
1591
1592 // Binary Operations
1593
1594 case SyntaxKind.BinaryExpression:
1595
1596 // TypeScript uses BinaryExpression for sequences as well
1597 if (nodeUtils.isComma(node.operatorToken)) {
1598 Object.assign(result, {
1599 type: AST_NODE_TYPES.SequenceExpression,
1600 expressions: []
1601 });
1602
1603 const left = convertChild(node.left),
1604 right = convertChild(node.right);
1605
1606 if (left.type === AST_NODE_TYPES.SequenceExpression) {
1607 result.expressions = result.expressions.concat(left.expressions);
1608 } else {
1609 result.expressions.push(left);
1610 }
1611
1612 if (right.type === AST_NODE_TYPES.SequenceExpression) {
1613 result.expressions = result.expressions.concat(right.expressions);
1614 } else {
1615 result.expressions.push(right);
1616 }
1617
1618 } else if (node.operatorToken && node.operatorToken.kind === SyntaxKind.AsteriskAsteriskEqualsToken) {
1619 Object.assign(result, {
1620 type: AST_NODE_TYPES.AssignmentExpression,
1621 operator: nodeUtils.getTextForTokenKind(node.operatorToken.kind),
1622 left: convertChild(node.left),
1623 right: convertChild(node.right)
1624 });
1625 } else {
1626 Object.assign(result, {
1627 type: nodeUtils.getBinaryExpressionType(node.operatorToken),
1628 operator: nodeUtils.getTextForTokenKind(node.operatorToken.kind),
1629 left: convertChild(node.left),
1630 right: convertChild(node.right)
1631 });
1632
1633 // if the binary expression is in a destructured array, switch it
1634 if (result.type === AST_NODE_TYPES.AssignmentExpression) {
1635 const upperArrayNode = nodeUtils.findAncestorOfKind(node, SyntaxKind.ArrayLiteralExpression),
1636 upperArrayAssignNode = upperArrayNode && nodeUtils.findAncestorOfKind(upperArrayNode, SyntaxKind.BinaryExpression);
1637
1638 let upperArrayIsInAssignment;
1639
1640 if (upperArrayAssignNode) {
1641 if (upperArrayAssignNode.left === upperArrayNode) {
1642 upperArrayIsInAssignment = true;
1643 } else {
1644 upperArrayIsInAssignment = (nodeUtils.findChildOfKind(upperArrayAssignNode.left, SyntaxKind.ArrayLiteralExpression, ast) === upperArrayNode);
1645 }
1646 }
1647
1648 if (upperArrayIsInAssignment) {
1649 delete result.operator;
1650 result.type = AST_NODE_TYPES.AssignmentPattern;
1651 }
1652 }
1653 }
1654 break;
1655
1656 case SyntaxKind.PropertyAccessExpression:
1657 if (nodeUtils.isJSXToken(parent)) {
1658 const jsxMemberExpression = {
1659 type: AST_NODE_TYPES.MemberExpression,
1660 object: convertChild(node.expression),
1661 property: convertChild(node.name)
1662 };
1663 const isNestedMemberExpression = (node.expression.kind === SyntaxKind.PropertyAccessExpression);
1664 if (node.expression.kind === SyntaxKind.ThisKeyword) {
1665 jsxMemberExpression.object.name = "this";
1666 }
1667
1668 jsxMemberExpression.object.type = (isNestedMemberExpression) ? AST_NODE_TYPES.MemberExpression : AST_NODE_TYPES.JSXIdentifier;
1669 jsxMemberExpression.property.type = AST_NODE_TYPES.JSXIdentifier;
1670 Object.assign(result, jsxMemberExpression);
1671 } else {
1672 Object.assign(result, {
1673 type: AST_NODE_TYPES.MemberExpression,
1674 object: convertChild(node.expression),
1675 property: convertChild(node.name),
1676 computed: false
1677 });
1678 }
1679 break;
1680
1681 case SyntaxKind.ElementAccessExpression:
1682 Object.assign(result, {
1683 type: AST_NODE_TYPES.MemberExpression,
1684 object: convertChild(node.expression),
1685 property: convertChild(node.argumentExpression),
1686 computed: true
1687 });
1688 break;
1689
1690 case SyntaxKind.ConditionalExpression:
1691 Object.assign(result, {
1692 type: AST_NODE_TYPES.ConditionalExpression,
1693 test: convertChild(node.condition),
1694 consequent: convertChild(node.whenTrue),
1695 alternate: convertChild(node.whenFalse)
1696 });
1697 break;
1698
1699 case SyntaxKind.CallExpression:
1700 Object.assign(result, {
1701 type: AST_NODE_TYPES.CallExpression,
1702 callee: convertChild(node.expression),
1703 arguments: node.arguments.map(convertChild)
1704 });
1705 if (node.typeArguments && node.typeArguments.length) {
1706 result.typeParameters = convertTypeArgumentsToTypeParameters(node.typeArguments);
1707 }
1708 break;
1709
1710 case SyntaxKind.NewExpression:
1711 Object.assign(result, {
1712 type: AST_NODE_TYPES.NewExpression,
1713 callee: convertChild(node.expression),
1714 arguments: (node.arguments) ? node.arguments.map(convertChild) : []
1715 });
1716 if (node.typeArguments && node.typeArguments.length) {
1717 result.typeParameters = convertTypeArgumentsToTypeParameters(node.typeArguments);
1718 }
1719 break;
1720
1721 case SyntaxKind.MetaProperty: {
1722 const newToken = nodeUtils.convertToken(node.getFirstToken(), ast);
1723 Object.assign(result, {
1724 type: AST_NODE_TYPES.MetaProperty,
1725 meta: {
1726 type: AST_NODE_TYPES.Identifier,
1727 range: newToken.range,
1728 loc: newToken.loc,
1729 name: "new"
1730 },
1731 property: convertChild(node.name)
1732 });
1733 break;
1734 }
1735
1736 // Literals
1737
1738 case SyntaxKind.StringLiteral:
1739 Object.assign(result, {
1740 type: AST_NODE_TYPES.Literal,
1741 raw: ast.text.slice(result.range[0], result.range[1])
1742 });
1743 if (parent.name && parent.name === node) {
1744 result.value = nodeUtils.unescapeIdentifier(node.text);
1745 } else {
1746 result.value = nodeUtils.unescapeStringLiteralText(node.text);
1747 }
1748 break;
1749
1750 case SyntaxKind.NumericLiteral:
1751 Object.assign(result, {
1752 type: AST_NODE_TYPES.Literal,
1753 value: Number(node.text),
1754 raw: ast.text.slice(result.range[0], result.range[1])
1755 });
1756 break;
1757
1758 case SyntaxKind.RegularExpressionLiteral: {
1759 const pattern = node.text.slice(1, node.text.lastIndexOf("/"));
1760 const flags = node.text.slice(node.text.lastIndexOf("/") + 1);
1761
1762 let regex = null;
1763 try {
1764 regex = new RegExp(pattern, flags);
1765 } catch (exception) {
1766 regex = null;
1767 }
1768
1769 Object.assign(result, {
1770 type: AST_NODE_TYPES.Literal,
1771 value: regex,
1772 raw: node.text,
1773 regex: {
1774 pattern,
1775 flags
1776 }
1777 });
1778 break;
1779 }
1780
1781 case SyntaxKind.TrueKeyword:
1782 Object.assign(result, {
1783 type: AST_NODE_TYPES.Literal,
1784 value: true,
1785 raw: "true"
1786 });
1787 break;
1788
1789 case SyntaxKind.FalseKeyword:
1790 Object.assign(result, {
1791 type: AST_NODE_TYPES.Literal,
1792 value: false,
1793 raw: "false"
1794 });
1795 break;
1796
1797 case SyntaxKind.NullKeyword: {
1798 if (nodeUtils.isWithinTypeAnnotation(node)) {
1799 Object.assign(result, {
1800 type: AST_NODE_TYPES.TSNullKeyword
1801 });
1802 } else {
1803 Object.assign(result, {
1804 type: AST_NODE_TYPES.Literal,
1805 value: null,
1806 raw: "null"
1807 });
1808 }
1809 break;
1810 }
1811
1812 case SyntaxKind.ImportKeyword:
1813 Object.assign(result, {
1814 type: AST_NODE_TYPES.Import
1815 });
1816 break;
1817
1818 case SyntaxKind.EmptyStatement:
1819 case SyntaxKind.DebuggerStatement:
1820 simplyCopy();
1821 break;
1822
1823 // JSX
1824
1825 case SyntaxKind.JsxElement:
1826 Object.assign(result, {
1827 type: AST_NODE_TYPES.JSXElement,
1828 openingElement: convertChild(node.openingElement),
1829 closingElement: convertChild(node.closingElement),
1830 children: node.children.map(convertChild)
1831 });
1832
1833 break;
1834
1835 case SyntaxKind.JsxSelfClosingElement: {
1836 /**
1837 * Convert SyntaxKind.JsxSelfClosingElement to SyntaxKind.JsxOpeningElement,
1838 * TypeScript does not seem to have the idea of openingElement when tag is self-closing
1839 */
1840 node.kind = SyntaxKind.JsxOpeningElement;
1841
1842 const openingElement = convertChild(node);
1843 openingElement.selfClosing = true;
1844
1845 Object.assign(result, {
1846 type: AST_NODE_TYPES.JSXElement,
1847 openingElement,
1848 closingElement: null,
1849 children: []
1850 });
1851
1852 break;
1853
1854 }
1855
1856 case SyntaxKind.JsxOpeningElement:
1857 Object.assign(result, {
1858 type: AST_NODE_TYPES.JSXOpeningElement,
1859 selfClosing: false,
1860 name: convertTypeScriptJSXTagNameToESTreeName(node.tagName),
1861 attributes: node.attributes.properties.map(convertChild)
1862 });
1863 break;
1864
1865 case SyntaxKind.JsxClosingElement:
1866 Object.assign(result, {
1867 type: AST_NODE_TYPES.JSXClosingElement,
1868 name: convertTypeScriptJSXTagNameToESTreeName(node.tagName)
1869 });
1870 break;
1871
1872 case SyntaxKind.JsxExpression: {
1873 const eloc = ast.getLineAndCharacterOfPosition(result.range[0] + 1);
1874 const expression = (node.expression) ? convertChild(node.expression) : {
1875 type: AST_NODE_TYPES.JSXEmptyExpression,
1876 loc: {
1877 start: {
1878 line: eloc.line + 1,
1879 column: eloc.character
1880 },
1881 end: {
1882 line: result.loc.end.line,
1883 column: result.loc.end.column - 1
1884 }
1885 },
1886 range: [result.range[0] + 1, result.range[1] - 1]
1887 };
1888
1889 Object.assign(result, {
1890 type: AST_NODE_TYPES.JSXExpressionContainer,
1891 expression
1892 });
1893
1894 break;
1895
1896 }
1897
1898 case SyntaxKind.JsxAttribute: {
1899 const attributeName = nodeUtils.convertToken(node.name, ast);
1900 attributeName.type = AST_NODE_TYPES.JSXIdentifier;
1901 attributeName.name = attributeName.value;
1902 delete attributeName.value;
1903
1904 Object.assign(result, {
1905 type: AST_NODE_TYPES.JSXAttribute,
1906 name: attributeName,
1907 value: convertChild(node.initializer)
1908 });
1909
1910 break;
1911
1912 }
1913
1914 /**
1915 * The JSX AST changed the node type for string literals
1916 * inside a JSX Element from `Literal` to `JSXText`. We
1917 * provide a flag to support both types until `Literal`
1918 * node type is deprecated in ESLint v5.
1919 */
1920 case SyntaxKind.JsxText: {
1921 const start = node.getFullStart();
1922 const end = node.getEnd();
1923
1924 const type = (additionalOptions.useJSXTextNode)
1925 ? AST_NODE_TYPES.JSXText : AST_NODE_TYPES.Literal;
1926
1927 Object.assign(result, {
1928 type,
1929 value: ast.text.slice(start, end),
1930 raw: ast.text.slice(start, end)
1931 });
1932
1933 result.loc = nodeUtils.getLocFor(start, end, ast);
1934 result.range = [start, end];
1935
1936 break;
1937 }
1938
1939 case SyntaxKind.JsxSpreadAttribute:
1940 Object.assign(result, {
1941 type: AST_NODE_TYPES.JSXSpreadAttribute,
1942 argument: convertChild(node.expression)
1943 });
1944
1945 break;
1946
1947 case SyntaxKind.FirstNode: {
1948 Object.assign(result, {
1949 type: AST_NODE_TYPES.TSQualifiedName,
1950 left: convertChild(node.left),
1951 right: convertChild(node.right)
1952 });
1953
1954 break;
1955 }
1956
1957 // TypeScript specific
1958
1959 case SyntaxKind.ParenthesizedExpression:
1960 return convert({ node: node.expression, parent, ast, additionalOptions });
1961
1962 /**
1963 * Convert TypeAliasDeclaration node into VariableDeclaration
1964 * to allow core rules such as "semi" to work automatically
1965 */
1966 case SyntaxKind.TypeAliasDeclaration: {
1967 const typeAliasDeclarator = {
1968 type: AST_NODE_TYPES.VariableDeclarator,
1969 id: convertChild(node.name),
1970 init: convertChild(node.type),
1971 range: [node.name.getStart(), node.end]
1972 };
1973
1974 typeAliasDeclarator.loc = nodeUtils.getLocFor(typeAliasDeclarator.range[0], typeAliasDeclarator.range[1], ast);
1975
1976 // Process typeParameters
1977 if (node.typeParameters && node.typeParameters.length) {
1978 typeAliasDeclarator.typeParameters = convertTSTypeParametersToTypeParametersDeclaration(node.typeParameters);
1979 }
1980
1981 Object.assign(result, {
1982 type: AST_NODE_TYPES.VariableDeclaration,
1983 kind: nodeUtils.getDeclarationKind(node),
1984 declarations: [typeAliasDeclarator]
1985 });
1986
1987 // check for exports
1988 result = nodeUtils.fixExports(node, result, ast);
1989
1990 break;
1991
1992 }
1993
1994 case SyntaxKind.MethodSignature: {
1995 Object.assign(result, {
1996 type: AST_NODE_TYPES.TSMethodSignature,
1997 optional: nodeUtils.isOptional(node),
1998 computed: nodeUtils.isComputedProperty(node.name),
1999 key: convertChild(node.name),
2000 params: convertParameters(node.parameters),
2001 typeAnnotation: (node.type) ? convertTypeAnnotation(node.type) : null,
2002 readonly: nodeUtils.hasModifier(SyntaxKind.ReadonlyKeyword, node) || undefined,
2003 static: nodeUtils.hasModifier(SyntaxKind.StaticKeyword, node),
2004 export: nodeUtils.hasModifier(SyntaxKind.ExportKeyword, node) || undefined
2005 });
2006
2007 const accessibility = nodeUtils.getTSNodeAccessibility(node);
2008 if (accessibility) {
2009 result.accessibility = accessibility;
2010 }
2011
2012 if (node.typeParameters) {
2013 result.typeParameters = convertTSTypeParametersToTypeParametersDeclaration(node.typeParameters);
2014 }
2015
2016 break;
2017 }
2018
2019 case SyntaxKind.PropertySignature: {
2020 Object.assign(result, {
2021 type: AST_NODE_TYPES.TSPropertySignature,
2022 optional: nodeUtils.isOptional(node) || undefined,
2023 computed: nodeUtils.isComputedProperty(node.name),
2024 key: convertChild(node.name),
2025 typeAnnotation: (node.type) ? convertTypeAnnotation(node.type) : undefined,
2026 initializer: convertChild(node.initializer) || undefined,
2027 readonly: nodeUtils.hasModifier(SyntaxKind.ReadonlyKeyword, node) || undefined,
2028 static: nodeUtils.hasModifier(SyntaxKind.StaticKeyword, node) || undefined,
2029 export: nodeUtils.hasModifier(SyntaxKind.ExportKeyword, node) || undefined
2030 });
2031
2032 const accessibility = nodeUtils.getTSNodeAccessibility(node);
2033 if (accessibility) {
2034 result.accessibility = accessibility;
2035 }
2036
2037 break;
2038 }
2039
2040 case SyntaxKind.IndexSignature: {
2041 Object.assign(result, {
2042 type: AST_NODE_TYPES.TSIndexSignature,
2043 index: convertChild(node.parameters[0]),
2044 typeAnnotation: (node.type) ? convertTypeAnnotation(node.type) : null,
2045 readonly: nodeUtils.hasModifier(SyntaxKind.ReadonlyKeyword, node) || undefined,
2046 static: nodeUtils.hasModifier(SyntaxKind.StaticKeyword, node),
2047 export: nodeUtils.hasModifier(SyntaxKind.ExportKeyword, node) || undefined
2048 });
2049
2050 const accessibility = nodeUtils.getTSNodeAccessibility(node);
2051 if (accessibility) {
2052 result.accessibility = accessibility;
2053 }
2054
2055 break;
2056 }
2057
2058 case SyntaxKind.ConstructSignature: {
2059 Object.assign(result, {
2060 type: AST_NODE_TYPES.TSConstructSignature,
2061 params: convertParameters(node.parameters),
2062 typeAnnotation: (node.type) ? convertTypeAnnotation(node.type) : null
2063 });
2064
2065 if (node.typeParameters) {
2066 result.typeParameters = convertTSTypeParametersToTypeParametersDeclaration(node.typeParameters);
2067 }
2068
2069 break;
2070 }
2071
2072 case SyntaxKind.InterfaceDeclaration: {
2073 const interfaceHeritageClauses = node.heritageClauses || [];
2074
2075 let interfaceLastClassToken = interfaceHeritageClauses.length ? interfaceHeritageClauses[interfaceHeritageClauses.length - 1] : node.name;
2076
2077 if (node.typeParameters && node.typeParameters.length) {
2078 const interfaceLastTypeParameter = node.typeParameters[node.typeParameters.length - 1];
2079
2080 if (!interfaceLastClassToken || interfaceLastTypeParameter.pos > interfaceLastClassToken.pos) {
2081 interfaceLastClassToken = nodeUtils.findNextToken(interfaceLastTypeParameter, ast);
2082 }
2083 result.typeParameters = convertTSTypeParametersToTypeParametersDeclaration(node.typeParameters);
2084 }
2085
2086 const hasImplementsClause = interfaceHeritageClauses.length > 0;
2087 const hasAbstractKeyword = nodeUtils.hasModifier(SyntaxKind.AbstractKeyword, node);
2088 const interfaceOpenBrace = nodeUtils.findNextToken(interfaceLastClassToken, ast);
2089
2090 const interfaceBody = {
2091 type: AST_NODE_TYPES.TSInterfaceBody,
2092 body: node.members.map(member => convertChild(member)),
2093 range: [interfaceOpenBrace.getStart(), result.range[1]],
2094 loc: nodeUtils.getLocFor(interfaceOpenBrace.getStart(), node.end, ast)
2095 };
2096
2097 Object.assign(result, {
2098 abstract: hasAbstractKeyword,
2099 type: AST_NODE_TYPES.TSInterfaceDeclaration,
2100 body: interfaceBody,
2101 id: convertChild(node.name),
2102 heritage: hasImplementsClause ? interfaceHeritageClauses[0].types.map(convertInterfaceHeritageClause) : []
2103 });
2104 /**
2105 * Semantically, decorators are not allowed on interface declarations,
2106 * but the TypeScript compiler will parse them and produce a valid AST,
2107 * so we handle them here too.
2108 */
2109 if (node.decorators) {
2110 result.decorators = convertDecorators(node.decorators);
2111 }
2112 // check for exports
2113 result = nodeUtils.fixExports(node, result, ast);
2114
2115 break;
2116
2117 }
2118
2119 case SyntaxKind.FirstTypeNode:
2120 Object.assign(result, {
2121 type: AST_NODE_TYPES.TSTypePredicate,
2122 parameterName: convertChild(node.parameterName),
2123 typeAnnotation: convertTypeAnnotation(node.type)
2124 });
2125 /**
2126 * Specific fix for type-guard location data
2127 */
2128 result.typeAnnotation.loc = result.typeAnnotation.typeAnnotation.loc;
2129 result.typeAnnotation.range = result.typeAnnotation.typeAnnotation.range;
2130 break;
2131
2132 case SyntaxKind.EnumDeclaration: {
2133 Object.assign(result, {
2134 type: AST_NODE_TYPES.TSEnumDeclaration,
2135 id: convertChild(node.name),
2136 members: node.members.map(convertChild)
2137 });
2138 // apply modifiers first...
2139 applyModifiersToResult(node.modifiers);
2140 // ...then check for exports
2141 result = nodeUtils.fixExports(node, result, ast);
2142 /**
2143 * Semantically, decorators are not allowed on enum declarations,
2144 * but the TypeScript compiler will parse them and produce a valid AST,
2145 * so we handle them here too.
2146 */
2147 if (node.decorators) {
2148 result.decorators = convertDecorators(node.decorators);
2149 }
2150 break;
2151 }
2152
2153 case SyntaxKind.EnumMember: {
2154 Object.assign(result, {
2155 type: AST_NODE_TYPES.TSEnumMember,
2156 id: convertChild(node.name)
2157 });
2158 if (node.initializer) {
2159 result.initializer = convertChild(node.initializer);
2160 }
2161 break;
2162 }
2163
2164 case SyntaxKind.AbstractKeyword: {
2165 Object.assign(result, {
2166 type: AST_NODE_TYPES.TSAbstractKeyword
2167 });
2168 break;
2169 }
2170
2171 case SyntaxKind.ModuleDeclaration: {
2172 Object.assign(result, {
2173 type: AST_NODE_TYPES.TSModuleDeclaration,
2174 id: convertChild(node.name)
2175 });
2176 if (node.body) {
2177 result.body = convertChild(node.body);
2178 }
2179 // apply modifiers first...
2180 applyModifiersToResult(node.modifiers);
2181 // ...then check for exports
2182 result = nodeUtils.fixExports(node, result, ast);
2183 break;
2184 }
2185
2186 default:
2187 deeplyCopy();
2188 }
2189
2190 return result;
2191
2192};