@@ -1432,14 +1432,7 @@ module ts {
1432
1432
1433
1433
function createNode ( kind : SyntaxKind , pos ?: number ) : Node {
1434
1434
nodeCount ++ ;
1435
- let node = new ( nodeConstructors [ kind ] || ( nodeConstructors [ kind ] = objectAllocator . getNodeConstructor ( kind ) ) ) ( ) ;
1436
- if ( ! ( pos >= 0 ) ) {
1437
- pos = scanner . getStartPos ( ) ;
1438
- }
1439
-
1440
- node . pos = pos ;
1441
- node . end = pos ;
1442
- return node ;
1435
+ return createNodeAtPosition ( scanner , kind , pos ) ;
1443
1436
}
1444
1437
1445
1438
function finishNode < T extends Node > ( node : T ) : T {
@@ -5390,4 +5383,344 @@ module ts {
5390
5383
export function isAssignmentOperator ( token : SyntaxKind ) : boolean {
5391
5384
return token >= SyntaxKind . FirstAssignment && token <= SyntaxKind . LastAssignment ;
5392
5385
}
5386
+
5387
+ // Parses out a JSDoc type expression. The starting position should be right at the open
5388
+ // curly in the type expression. Returns 'undefined' if it encounters any errors while parsing.
5389
+ function parseJSDocTypeExpression ( content : string , start : number ) : JSDocType {
5390
+ let scanner = createScanner ( ScriptTarget . Latest , /*skipTrivia:*/ true , content ) ;
5391
+ scanner . setTextPos ( start ) ;
5392
+
5393
+ // Prime the first token for us to start processing.
5394
+ let token = nextToken ( ) ;
5395
+ let error = false ;
5396
+
5397
+ parseExpected ( SyntaxKind . OpenBraceToken ) ;
5398
+ let type = parseJSDocType ( ) ;
5399
+ parseExpected ( SyntaxKind . CloseBraceToken ) ;
5400
+
5401
+ return error ? undefined : type ;
5402
+
5403
+ function nextToken ( ) : SyntaxKind {
5404
+ return token = scanner . scan ( ) ;
5405
+ }
5406
+
5407
+ function createNode ( kind : SyntaxKind , pos ?: number ) : Node {
5408
+ return createNodeAtPosition ( scanner , kind , pos ) ;
5409
+ }
5410
+
5411
+ function parseExpected ( kind : SyntaxKind ) : void {
5412
+ if ( token === kind ) {
5413
+ nextToken ( ) ;
5414
+ }
5415
+ else {
5416
+ error = true ;
5417
+ }
5418
+ }
5419
+
5420
+ function isIdentifier ( ) {
5421
+ if ( token === SyntaxKind . Identifier ) {
5422
+ return true ;
5423
+ }
5424
+
5425
+ return token > SyntaxKind . LastReservedWord && token <= SyntaxKind . LastKeyword ;
5426
+ }
5427
+
5428
+ function isIdentifierOrKeyword ( ) {
5429
+ if ( token === SyntaxKind . Identifier ) {
5430
+ return true ;
5431
+ }
5432
+
5433
+ return token >= SyntaxKind . FirstKeyword && token <= SyntaxKind . LastKeyword ;
5434
+ }
5435
+
5436
+ function parseJSDocType ( ) : JSDocType {
5437
+ let type = parseJSDocType ( ) ;
5438
+ if ( type && token === SyntaxKind . EqualsToken ) {
5439
+ return parseJSDocOptionalType ( type ) ;
5440
+ }
5441
+
5442
+ return type ;
5443
+ }
5444
+
5445
+ function parseJSDocTypeCore ( ) : JSDocType {
5446
+ switch ( token ) {
5447
+ case SyntaxKind . AsteriskToken :
5448
+ return parseJSDocAllType ( ) ;
5449
+ case SyntaxKind . QuestionToken :
5450
+ return parseJSDocUnknownOrNullableType ( ) ;
5451
+ case SyntaxKind . OpenParenToken :
5452
+ return parseJSDocUnionType ( ) ;
5453
+ case SyntaxKind . ExclamationToken :
5454
+ return parseJSDocNonNullableType ( ) ;
5455
+ case SyntaxKind . OpenBraceToken :
5456
+ return parseJSDocRecordType ( ) ;
5457
+ case SyntaxKind . FunctionKeyword :
5458
+ return parseJSDocFunctionType ( ) ;
5459
+ case SyntaxKind . DotDotDotToken :
5460
+ return parseJSDocVariadicType ( ) ;
5461
+ case SyntaxKind . NewKeyword :
5462
+ return parseJSDocConstructorType ( ) ;
5463
+ case SyntaxKind . ThisKeyword :
5464
+ return parseJSDocThisType ( ) ;
5465
+ }
5466
+
5467
+ if ( isIdentifier ( ) ) {
5468
+ return parseJSDocTypeReference ( ) ;
5469
+ }
5470
+
5471
+ error = true ;
5472
+ return undefined ;
5473
+ }
5474
+
5475
+ function parseJSDocThisType ( ) : JSDocThisType {
5476
+ let result = < JSDocThisType > createNode ( SyntaxKind . JSDocThisType ) ;
5477
+ nextToken ( ) ;
5478
+ parseExpected ( SyntaxKind . ColonToken ) ;
5479
+ result . type = parseJSDocType ( ) ;
5480
+ return finishNode ( result ) ;
5481
+ }
5482
+
5483
+ function parseJSDocConstructorType ( ) : JSDocConstructorType {
5484
+ let result = < JSDocConstructorType > createNode ( SyntaxKind . JSDocConstructorType ) ;
5485
+ nextToken ( ) ;
5486
+ parseExpected ( SyntaxKind . ColonToken ) ;
5487
+ result . type = parseJSDocType ( ) ;
5488
+ return finishNode ( result ) ;
5489
+ }
5490
+
5491
+ function parseJSDocVariadicType ( ) : JSDocVariadicType {
5492
+ let result = < JSDocVariadicType > createNode ( SyntaxKind . JSDocVariadicType ) ;
5493
+ nextToken ( ) ;
5494
+ result . type = parseJSDocType ( ) ;
5495
+ return finishNode ( result ) ;
5496
+ }
5497
+
5498
+ function parseJSDocFunctionType ( ) : JSDocFunctionType {
5499
+ let result = < JSDocFunctionType > createNode ( SyntaxKind . JSDocFunctionType ) ;
5500
+ nextToken ( ) ;
5501
+ parseExpected ( SyntaxKind . OpenParenToken ) ;
5502
+
5503
+ let parameters = < NodeArray < JSDocType > > [ ] ;
5504
+ parameters . pos = scanner . getStartPos ( ) ;
5505
+
5506
+ while ( ! error && token !== SyntaxKind . CloseParenToken && token !== SyntaxKind . EndOfFileToken ) {
5507
+ if ( parameters . length > 0 ) {
5508
+ parseExpected ( SyntaxKind . CommaToken ) ;
5509
+ }
5510
+
5511
+ parameters . push ( parseJSDocType ( ) ) ;
5512
+ }
5513
+
5514
+ parameters . end = scanner . getStartPos ( ) ;
5515
+ parseExpected ( SyntaxKind . CloseParenToken ) ;
5516
+
5517
+ if ( token === SyntaxKind . ColonToken ) {
5518
+ nextToken ( ) ;
5519
+ result . type = parseJSDocType ( ) ;
5520
+ }
5521
+
5522
+ return finishNode ( result ) ;
5523
+ }
5524
+
5525
+ function parseJSDocOptionalType ( type : JSDocType ) : JSDocOptionalType {
5526
+ let result = < JSDocOptionalType > createNode ( SyntaxKind . JSDocOptionalType , type . pos ) ;
5527
+ nextToken ( ) ;
5528
+ return finishNode ( result ) ;
5529
+ }
5530
+
5531
+ function parseJSDocTypeReference ( ) : JSDocTypeReference {
5532
+ let result = < JSDocTypeReference > createNode ( SyntaxKind . JSDocTypeReference ) ;
5533
+ result . name = parseIdentifier ( ) ;
5534
+
5535
+ while ( ! error && result . name && token === SyntaxKind . DotToken ) {
5536
+ if ( isIdentifierOrKeyword ( ) ) {
5537
+ result . name = parseQualifiedName ( result . name ) ;
5538
+ }
5539
+ else if ( token === SyntaxKind . LessThanToken ) {
5540
+ result . typeArguments = parseTypeArguments ( ) ;
5541
+ break ;
5542
+ }
5543
+ else {
5544
+ error = true ;
5545
+ return undefined ;
5546
+ }
5547
+ }
5548
+
5549
+ return finishNode ( result ) ;
5550
+ }
5551
+
5552
+ function parseTypeArguments ( ) {
5553
+ // Move past the <
5554
+ nextToken ( ) ;
5555
+
5556
+ let typeArguments = < NodeArray < JSDocType > > [ ] ;
5557
+ typeArguments . pos = scanner . getStartPos ( ) ;
5558
+
5559
+ typeArguments . push ( parseJSDocType ( ) ) ;
5560
+ while ( ! error && token === SyntaxKind . CommaToken ) {
5561
+ nextToken ( ) ;
5562
+ typeArguments . push ( parseJSDocType ( ) ) ;
5563
+ }
5564
+
5565
+ typeArguments . end = scanner . getStartPos ( ) ;
5566
+
5567
+ parseExpected ( SyntaxKind . GreaterThanToken ) ;
5568
+
5569
+ return typeArguments ;
5570
+ }
5571
+
5572
+ function parseQualifiedName ( left : EntityName ) : QualifiedName {
5573
+ // Move past the .
5574
+ nextToken ( ) ;
5575
+
5576
+ let result = < QualifiedName > createNode ( SyntaxKind . QualifiedName , left . pos ) ;
5577
+ result . left = left ;
5578
+ result . right = parseIdentifierOrKeyword ( ) ;
5579
+
5580
+ return finishNode ( result ) ;
5581
+ }
5582
+
5583
+ function parseIdentifierOrKeyword ( ) : Identifier {
5584
+ return parseIdentifierHelper ( isIdentifierOrKeyword ( ) ) ;
5585
+ }
5586
+
5587
+ function parseIdentifier ( ) : Identifier {
5588
+ return parseIdentifierHelper ( isIdentifier ( ) ) ;
5589
+ }
5590
+
5591
+ function parseIdentifierHelper ( isIdentifier : boolean ) : Identifier {
5592
+ if ( isIdentifier ) {
5593
+ let result = < Identifier > createNode ( SyntaxKind . Identifier ) ;
5594
+ result . text = scanner . getTokenValue ( ) ;
5595
+ nextToken ( ) ;
5596
+ return finishNode ( result ) ;
5597
+ }
5598
+ else {
5599
+ error = true ;
5600
+ return undefined ;
5601
+ }
5602
+ }
5603
+
5604
+ function parseJSDocRecordType ( ) : JSDocRecordType {
5605
+ let result = < JSDocRecordType > createNode ( SyntaxKind . JSDocRecordType ) ;
5606
+ nextToken ( ) ;
5607
+
5608
+ let members = < NodeArray < JSDocMember > > [ ] ;
5609
+ members . pos = scanner . getStartPos ( ) ;
5610
+
5611
+ while ( token !== SyntaxKind . CloseBraceToken && token !== SyntaxKind . EndOfFileToken && ! error ) {
5612
+ members . push ( parseJSDocMember ( ) ) ;
5613
+ }
5614
+
5615
+ members . end = scanner . getStartPos ( ) ;
5616
+
5617
+ parseExpected ( SyntaxKind . CloseBraceToken ) ;
5618
+ return finishNode ( result ) ;
5619
+ }
5620
+
5621
+ function parseJSDocMember ( ) : JSDocMember {
5622
+ let result = < JSDocMember > createNode ( SyntaxKind . JSDocMember ) ;
5623
+ result . name = parsePropertyName ( ) ;
5624
+
5625
+ if ( token === SyntaxKind . ColonToken ) {
5626
+ nextToken ( ) ;
5627
+ result . type = parseJSDocType ( ) ;
5628
+ }
5629
+
5630
+ return finishNode ( result ) ;
5631
+ }
5632
+
5633
+ function parsePropertyName ( ) : Identifier | LiteralExpression {
5634
+ if ( token === SyntaxKind . Identifier || token === SyntaxKind . StringLiteral || token === SyntaxKind . NumericLiteral ) {
5635
+ let result = < Identifier | LiteralExpression > createNode ( token ) ;
5636
+ nextToken ( ) ;
5637
+ return finishNode ( result ) ;
5638
+ }
5639
+ else {
5640
+ error = true ;
5641
+ return undefined ;
5642
+ }
5643
+ }
5644
+
5645
+ function parseJSDocNonNullableType ( ) : JSDocNonNullableType {
5646
+ let result = < JSDocNonNullableType > createNode ( SyntaxKind . JSDocNonNullableType ) ;
5647
+ nextToken ( ) ;
5648
+ result . type = parseJSDocType ( ) ;
5649
+ return finishNode ( result ) ;
5650
+ }
5651
+
5652
+ function parseJSDocUnionType ( ) : JSDocUnionType {
5653
+ let result = < JSDocUnionType > createNode ( SyntaxKind . JSDocUnionType ) ;
5654
+ nextToken ( ) ;
5655
+
5656
+ let types = < NodeArray < JSDocType > > [ ] ;
5657
+ types . pos = scanner . getStartPos ( ) ;
5658
+
5659
+ types . push ( parseJSDocType ( ) ) ;
5660
+ while ( token === SyntaxKind . BarToken ) {
5661
+ nextToken ( ) ;
5662
+ types . push ( parseJSDocType ( ) ) ;
5663
+ }
5664
+
5665
+ types . end = scanner . getStartPos ( ) ;
5666
+
5667
+ parseExpected ( SyntaxKind . CloseParenToken ) ;
5668
+
5669
+ return finishNode ( result ) ;
5670
+ }
5671
+
5672
+ function parseJSDocAllType ( ) : JSDocAllType {
5673
+ let result = < JSDocAllType > createNode ( SyntaxKind . JSDocAllType ) ;
5674
+ nextToken ( ) ;
5675
+ return finishNode ( result ) ;
5676
+ }
5677
+
5678
+ function parseJSDocUnknownOrNullableType ( ) : JSDocUnknownType | JSDocNullableType {
5679
+ let pos = scanner . getStartPos ( ) ;
5680
+ // skip the ?
5681
+ nextToken ( ) ;
5682
+
5683
+ // Need to lookahead to decide if this is a nullable or unknown type.
5684
+
5685
+ // Here are cases where we'll pick the unknown type:
5686
+ //
5687
+ // Foo(?,
5688
+ // { a: ? }
5689
+ // Foo(?)
5690
+ // Foo<?>
5691
+ // Foo(?=
5692
+ // (?|
5693
+ if ( token === SyntaxKind . CommaToken ||
5694
+ token === SyntaxKind . CloseBraceToken ||
5695
+ token === SyntaxKind . CloseParenToken ||
5696
+ token === SyntaxKind . GreaterThanToken ||
5697
+ token === SyntaxKind . EqualsToken ||
5698
+ token === SyntaxKind . BarToken ) {
5699
+
5700
+ let result = < JSDocUnknownType > createNode ( SyntaxKind . JSDocUnknownType , pos ) ;
5701
+ return finishNode ( result ) ;
5702
+ }
5703
+ else {
5704
+ let result = < JSDocNullableType > createNode ( SyntaxKind . JSDocNullableType , pos ) ;
5705
+ result . type = parseJSDocType ( ) ;
5706
+ return finishNode ( result ) ;
5707
+ }
5708
+ }
5709
+
5710
+ function finishNode < T extends Node > ( node : T ) : T {
5711
+ node . end = scanner . getStartPos ( ) ;
5712
+ return node ;
5713
+ }
5714
+ }
5715
+
5716
+ function createNodeAtPosition ( scanner : Scanner , kind : SyntaxKind , pos ?: number ) : Node {
5717
+ let node = new ( nodeConstructors [ kind ] || ( nodeConstructors [ kind ] = objectAllocator . getNodeConstructor ( kind ) ) ) ( ) ;
5718
+ if ( ! ( pos >= 0 ) ) {
5719
+ pos = scanner . getStartPos ( ) ;
5720
+ }
5721
+
5722
+ node . pos = pos ;
5723
+ node . end = pos ;
5724
+ return node ;
5725
+ }
5393
5726
}
0 commit comments