31
31
//------------------------------------------------------------------------------
32
32
33
33
var ts = require ( "typescript" ) ,
34
- assign = require ( "object-assign" ) ;
34
+ assign = require ( "object-assign" ) ,
35
+ unescape = require ( "lodash.unescape" ) ;
35
36
36
37
//------------------------------------------------------------------------------
37
38
// Private
@@ -309,7 +310,16 @@ function getTokenType(token) {
309
310
case SyntaxKind . NumericLiteral :
310
311
return "Numeric" ;
311
312
313
+ case SyntaxKind . JsxText :
314
+ return "JSXText" ;
315
+
312
316
case SyntaxKind . StringLiteral :
317
+ // A TypeScript-StringLiteral token with a TypeScript-JsxAttribute or TypeScript-JsxElement parent,
318
+ // must actually be an ESTree-JSXText token
319
+ if ( token . parent && ( token . parent . kind === SyntaxKind . JsxAttribute || token . parent . kind === SyntaxKind . JsxElement ) ) {
320
+ return "JSXText" ;
321
+ }
322
+
313
323
return "String" ;
314
324
315
325
case SyntaxKind . RegularExpressionLiteral :
@@ -323,6 +333,23 @@ function getTokenType(token) {
323
333
default :
324
334
}
325
335
336
+ // Some JSX tokens have to be determined based on their parent
337
+ if ( token . parent ) {
338
+ if ( token . kind === SyntaxKind . Identifier && token . parent . kind === SyntaxKind . FirstNode ) {
339
+ return "JSXIdentifier" ;
340
+ }
341
+
342
+ if ( token . parent . kind >= SyntaxKind . JsxElement && token . parent . kind <= SyntaxKind . JsxAttribute ) {
343
+ if ( token . kind === SyntaxKind . FirstNode ) {
344
+ return "JSXMemberExpression" ;
345
+ }
346
+
347
+ if ( token . kind === SyntaxKind . Identifier ) {
348
+ return "JSXIdentifier" ;
349
+ }
350
+ }
351
+ }
352
+
326
353
return "Identifier" ;
327
354
}
328
355
@@ -368,7 +395,6 @@ function convertTokens(ast) {
368
395
if ( converted ) {
369
396
result . push ( converted ) ;
370
397
}
371
-
372
398
token = ts . findNextToken ( token , ast ) ;
373
399
}
374
400
@@ -424,6 +450,38 @@ module.exports = function(ast, extra) {
424
450
return convert ( child , node ) ;
425
451
}
426
452
453
+ /**
454
+ * Converts a TypeScript JSX node.tagName into an ESTree node.name
455
+ * @param {Object } tagName the tagName object from a JSX TSNode
456
+ * @param {Object } ast the AST object
457
+ * @returns {Object } the converted ESTree name object
458
+ */
459
+ function convertTypeScriptJSXTagNameToESTreeName ( tagName ) {
460
+ var tagNameToken = convertToken ( tagName , ast ) ;
461
+
462
+ if ( tagNameToken . type === "JSXMemberExpression" ) {
463
+
464
+ var isNestedMemberExpression = ( node . tagName . left . kind === SyntaxKind . FirstNode ) ;
465
+
466
+ // Convert TSNode left and right objects into ESTreeNode object
467
+ // and property objects
468
+ tagNameToken . object = convertChild ( node . tagName . left ) ;
469
+ tagNameToken . property = convertChild ( node . tagName . right ) ;
470
+
471
+ // Assign the appropriate types
472
+ tagNameToken . object . type = ( isNestedMemberExpression ) ? "JSXMemberExpression" : "JSXIdentifier" ;
473
+ tagNameToken . property . type = "JSXIdentifier" ;
474
+
475
+ } else {
476
+
477
+ tagNameToken . name = tagNameToken . value ;
478
+ }
479
+
480
+ delete tagNameToken . value ;
481
+
482
+ return tagNameToken ;
483
+ }
484
+
427
485
switch ( node . kind ) {
428
486
case SyntaxKind . SourceFile :
429
487
assign ( result , {
@@ -1318,7 +1376,7 @@ module.exports = function(ast, extra) {
1318
1376
case SyntaxKind . StringLiteral :
1319
1377
assign ( result , {
1320
1378
type : "Literal" ,
1321
- value : node . text ,
1379
+ value : unescape ( node . text ) ,
1322
1380
raw : ast . text . slice ( result . range [ 0 ] , result . range [ 1 ] )
1323
1381
} ) ;
1324
1382
break ;
@@ -1369,13 +1427,132 @@ module.exports = function(ast, extra) {
1369
1427
simplyCopy ( ) ;
1370
1428
break ;
1371
1429
1430
+ // JSX
1431
+
1432
+ case SyntaxKind . JsxElement :
1433
+ assign ( result , {
1434
+ type : "JSXElement" ,
1435
+ openingElement : convertChild ( node . openingElement ) ,
1436
+ closingElement : convertChild ( node . closingElement ) ,
1437
+ children : node . children . map ( convertChild )
1438
+ } ) ;
1439
+
1440
+ break ;
1441
+
1442
+ case SyntaxKind . JsxSelfClosingElement :
1443
+ // Convert SyntaxKind.JsxSelfClosingElement to SyntaxKind.JsxOpeningElement,
1444
+ // TypeScript does not seem to have the idea of openingElement when tag is self-closing
1445
+ node . kind = SyntaxKind . JsxOpeningElement ;
1446
+ assign ( result , {
1447
+ type : "JSXElement" ,
1448
+ openingElement : convertChild ( node ) ,
1449
+ closingElement : null ,
1450
+ children : [ ]
1451
+ } ) ;
1452
+
1453
+ break ;
1454
+
1455
+ case SyntaxKind . JsxOpeningElement :
1456
+ var openingTagName = convertTypeScriptJSXTagNameToESTreeName ( node . tagName ) ;
1457
+ assign ( result , {
1458
+ type : "JSXOpeningElement" ,
1459
+ selfClosing : ! ( node . parent && node . parent . closingElement ) ,
1460
+ name : openingTagName ,
1461
+ attributes : node . attributes . map ( convertChild )
1462
+ } ) ;
1463
+
1464
+ break ;
1465
+
1466
+ case SyntaxKind . JsxClosingElement :
1467
+ var closingTagName = convertTypeScriptJSXTagNameToESTreeName ( node . tagName ) ;
1468
+ assign ( result , {
1469
+ type : "JSXClosingElement" ,
1470
+ name : closingTagName
1471
+ } ) ;
1472
+
1473
+ break ;
1474
+
1475
+ case SyntaxKind . JsxExpression :
1476
+ var eloc = ast . getLineAndCharacterOfPosition ( result . range [ 0 ] + 1 ) ;
1477
+ var expression = ( node . expression ) ? convertChild ( node . expression ) : {
1478
+ type : "JSXEmptyExpression" ,
1479
+ loc : {
1480
+ start : {
1481
+ line : eloc . line + 1 ,
1482
+ column : eloc . character
1483
+ } ,
1484
+ end : {
1485
+ line : result . loc . end . line ,
1486
+ column : result . loc . end . column - 1
1487
+ }
1488
+ } ,
1489
+ range : [ result . range [ 0 ] + 1 , result . range [ 1 ] - 1 ]
1490
+ } ;
1491
+
1492
+ assign ( result , {
1493
+ type : "JSXExpressionContainer" ,
1494
+ expression : expression
1495
+ } ) ;
1496
+
1497
+ break ;
1498
+
1499
+ case SyntaxKind . JsxAttribute :
1500
+ var attributeName = convertToken ( node . name , ast ) ;
1501
+ attributeName . name = attributeName . value ;
1502
+ delete attributeName . value ;
1503
+
1504
+ assign ( result , {
1505
+ type : "JSXAttribute" ,
1506
+ name : attributeName ,
1507
+ value : convertChild ( node . initializer )
1508
+ } ) ;
1509
+
1510
+ break ;
1511
+
1512
+ case SyntaxKind . JsxText :
1513
+ assign ( result , {
1514
+ type : "Literal" ,
1515
+ value : ast . text . slice ( node . pos , node . end ) ,
1516
+ raw : ast . text . slice ( node . pos , node . end )
1517
+ } ) ;
1518
+
1519
+ result . loc . start . column = node . pos ;
1520
+ result . range [ 0 ] = node . pos ;
1521
+
1522
+ break ;
1523
+
1524
+ case SyntaxKind . JsxSpreadAttribute :
1525
+ assign ( result , {
1526
+ type : "JSXSpreadAttribute" ,
1527
+ argument : convertChild ( node . expression )
1528
+ } ) ;
1529
+
1530
+ break ;
1531
+
1532
+ case SyntaxKind . FirstNode :
1533
+ var jsxMemberExpressionObject = convertChild ( node . left ) ;
1534
+ jsxMemberExpressionObject . type = "JSXIdentifier" ;
1535
+ delete jsxMemberExpressionObject . value ;
1536
+
1537
+ var jsxMemberExpressionProperty = convertChild ( node . right ) ;
1538
+ jsxMemberExpressionProperty . type = "JSXIdentifier" ;
1539
+ delete jsxMemberExpressionObject . value ;
1540
+
1541
+ assign ( result , {
1542
+ type : "JSXMemberExpression" ,
1543
+ object : jsxMemberExpressionObject ,
1544
+ property : jsxMemberExpressionProperty
1545
+ } ) ;
1546
+
1547
+ break ;
1548
+
1372
1549
// TypeScript specific
1373
1550
1374
1551
case SyntaxKind . ParenthesizedExpression :
1375
1552
return convert ( node . expression , parent ) ;
1376
1553
1377
1554
default :
1378
- console . log ( node . kind ) ;
1555
+ console . log ( "unsupported node.kind:" , node . kind ) ;
1379
1556
result = null ;
1380
1557
}
1381
1558
0 commit comments