@@ -75,7 +75,7 @@ module ts {
75
75
76
76
var scanner : Scanner = createScanner ( ScriptTarget . ES5 ) ;
77
77
78
- var emptyArray : any [ ] = [ ] ;
78
+ var emptyArray : any [ ] = [ ] ;
79
79
80
80
function createNode ( kind : SyntaxKind , pos : number , end : number , flags : NodeFlags , parent ?: Node ) : NodeObject {
81
81
var node = < NodeObject > new ( getNodeConstructor ( kind ) ) ( ) ;
@@ -259,7 +259,7 @@ module ts {
259
259
getProperty ( propertyName : string ) : Symbol {
260
260
return this . checker . getPropertyOfType ( this , propertyName ) ;
261
261
}
262
- getApparentProperties ( ) : Symbol [ ] {
262
+ getApparentProperties ( ) : Symbol [ ] {
263
263
return this . checker . getAugmentedPropertiesOfApparentType ( this ) ;
264
264
}
265
265
getCallSignatures ( ) : Signature [ ] {
@@ -302,7 +302,7 @@ module ts {
302
302
}
303
303
}
304
304
305
- var incrementalParse : IncrementalParse = TypeScript . IncrementalParser . parse ;
305
+ var incrementalParse : IncrementalParse = TypeScript . IncrementalParser . parse ;
306
306
307
307
class SourceFileObject extends NodeObject implements SourceFile {
308
308
public filename : string ;
@@ -430,6 +430,9 @@ module ts {
430
430
getSemanticDiagnostics ( fileName : string ) : Diagnostic [ ] ;
431
431
getCompilerOptionsDiagnostics ( ) : Diagnostic [ ] ;
432
432
433
+ getSyntacticClassifications ( fileName : string , span : TypeScript . TextSpan ) : ClassifiedSpan [ ] ;
434
+ getSemanticClassifications ( fileName : string , span : TypeScript . TextSpan ) : ClassifiedSpan [ ] ;
435
+
433
436
getCompletionsAtPosition ( fileName : string , position : number , isMemberCompletion : boolean ) : CompletionInfo ;
434
437
getCompletionEntryDetails ( fileName : string , position : number , entryName : string ) : CompletionEntryDetails ;
435
438
@@ -467,6 +470,32 @@ module ts {
467
470
dispose ( ) : void ;
468
471
}
469
472
473
+ export class ClassificationTypeNames {
474
+ public static comment = "comment" ;
475
+ public static identifier = "identifier" ;
476
+ public static keyword = "keyword" ;
477
+ public static numericLiteral = "number" ;
478
+ public static operator = "operator" ;
479
+ public static stringLiteral = "string" ;
480
+ public static whiteSpace = "whitespace" ;
481
+ public static text = "text" ;
482
+
483
+ public static punctuation = "punctuation" ;
484
+
485
+ public static className = "class name" ;
486
+ public static enumName = "enum name" ;
487
+ public static interfaceName = "interface name" ;
488
+ public static moduleName = "module name" ;
489
+ public static typeParameterName = "type parameter name" ;
490
+ }
491
+
492
+ export class ClassifiedSpan {
493
+ constructor ( public textSpan : TypeScript . TextSpan ,
494
+ public classificationType : string ) {
495
+
496
+ }
497
+ }
498
+
470
499
export class NavigationBarItem {
471
500
constructor ( public text : string ,
472
501
public kind : string ,
@@ -3214,6 +3243,198 @@ module ts {
3214
3243
return new TypeScript . Services . NavigationBarItemGetter ( ) . getItems ( syntaxTree . sourceUnit ( ) ) ;
3215
3244
}
3216
3245
3246
+ function getSemanticClassifications ( fileName : string , span : TypeScript . TextSpan ) : ClassifiedSpan [ ] {
3247
+ synchronizeHostData ( ) ;
3248
+ fileName = TypeScript . switchToForwardSlashes ( fileName ) ;
3249
+
3250
+ var sourceFile = getSourceFile ( fileName ) ;
3251
+
3252
+ var result : ClassifiedSpan [ ] = [ ] ;
3253
+ processNode ( sourceFile ) ;
3254
+
3255
+ return result ;
3256
+
3257
+ function classifySymbol ( symbol : Symbol ) {
3258
+ var flags = symbol . getFlags ( ) ;
3259
+
3260
+ if ( flags & SymbolFlags . Class ) {
3261
+ return ClassificationTypeNames . className ;
3262
+ }
3263
+ else if ( flags & SymbolFlags . Enum ) {
3264
+ return ClassificationTypeNames . enumName ;
3265
+ }
3266
+ else if ( flags & SymbolFlags . Interface ) {
3267
+ return ClassificationTypeNames . interfaceName ;
3268
+ }
3269
+ else if ( flags & SymbolFlags . Module ) {
3270
+ return ClassificationTypeNames . moduleName ;
3271
+ }
3272
+ else if ( flags & SymbolFlags . TypeParameter ) {
3273
+ return ClassificationTypeNames . typeParameterName ;
3274
+ }
3275
+ }
3276
+
3277
+ function processNode ( node : Node ) {
3278
+ // Only walk into nodes that intersect the requested span.
3279
+ if ( node && span . intersectsWith ( node . getStart ( ) , node . getWidth ( ) ) ) {
3280
+ if ( node . kind === SyntaxKind . Identifier && node . getWidth ( ) > 0 ) {
3281
+ var symbol = typeInfoResolver . getSymbolInfo ( node ) ;
3282
+ if ( symbol ) {
3283
+ var type = classifySymbol ( symbol ) ;
3284
+ if ( type ) {
3285
+ result . push ( new ClassifiedSpan (
3286
+ new TypeScript . TextSpan ( node . getStart ( ) , node . getWidth ( ) ) ,
3287
+ type ) ) ;
3288
+ }
3289
+ }
3290
+ }
3291
+
3292
+ forEachChild ( node , processNode ) ;
3293
+ }
3294
+ }
3295
+ }
3296
+
3297
+ function getSyntacticClassifications ( fileName : string , span : TypeScript . TextSpan ) : ClassifiedSpan [ ] {
3298
+ // doesn't use compiler - no need to synchronize with host
3299
+ fileName = TypeScript . switchToForwardSlashes ( fileName ) ;
3300
+ var sourceFile = getCurrentSourceFile ( fileName ) ;
3301
+
3302
+ var result : ClassifiedSpan [ ] = [ ] ;
3303
+ processElement ( sourceFile . getSourceUnit ( ) ) ;
3304
+
3305
+ return result ;
3306
+
3307
+ function classifyTrivia ( trivia : TypeScript . ISyntaxTrivia ) {
3308
+ if ( trivia . isComment ( ) && span . intersectsWith ( trivia . fullStart ( ) , trivia . fullWidth ( ) ) ) {
3309
+ result . push ( new ClassifiedSpan (
3310
+ new TypeScript . TextSpan ( trivia . fullStart ( ) , trivia . fullWidth ( ) ) ,
3311
+ ClassificationTypeNames . comment ) ) ;
3312
+ }
3313
+ }
3314
+
3315
+ function classifyTriviaList ( trivia : TypeScript . ISyntaxTriviaList ) {
3316
+ for ( var i = 0 , n = trivia . count ( ) ; i < n ; i ++ ) {
3317
+ classifyTrivia ( trivia . syntaxTriviaAt ( i ) ) ;
3318
+ }
3319
+ }
3320
+
3321
+ function classifyToken ( token : TypeScript . ISyntaxToken ) {
3322
+ if ( token . hasLeadingComment ( ) ) {
3323
+ classifyTriviaList ( token . leadingTrivia ( ) ) ;
3324
+ }
3325
+
3326
+ if ( TypeScript . width ( token ) > 0 ) {
3327
+ var type = classifyTokenType ( token ) ;
3328
+ if ( type ) {
3329
+ result . push ( new ClassifiedSpan (
3330
+ new TypeScript . TextSpan ( TypeScript . start ( token ) , TypeScript . width ( token ) ) ,
3331
+ type ) ) ;
3332
+ }
3333
+ }
3334
+
3335
+ if ( token . hasTrailingComment ( ) ) {
3336
+ classifyTriviaList ( token . trailingTrivia ( ) ) ;
3337
+ }
3338
+ }
3339
+
3340
+ function classifyTokenType ( token : TypeScript . ISyntaxToken ) : string {
3341
+ var tokenKind = token . kind ( ) ;
3342
+ if ( TypeScript . SyntaxFacts . isAnyKeyword ( token . kind ( ) ) ) {
3343
+ return ClassificationTypeNames . keyword ;
3344
+ }
3345
+
3346
+ // Special case < and > If they appear in a generic context they are punctation,
3347
+ // not operators.
3348
+ if ( tokenKind === TypeScript . SyntaxKind . LessThanToken || tokenKind === TypeScript . SyntaxKind . GreaterThanToken ) {
3349
+ var tokenParentKind = token . parent . kind ( ) ;
3350
+ if ( tokenParentKind === TypeScript . SyntaxKind . TypeArgumentList ||
3351
+ tokenParentKind === TypeScript . SyntaxKind . TypeParameterList ) {
3352
+
3353
+ return ClassificationTypeNames . punctuation ;
3354
+ }
3355
+ }
3356
+
3357
+ if ( TypeScript . SyntaxFacts . isBinaryExpressionOperatorToken ( tokenKind ) ||
3358
+ TypeScript . SyntaxFacts . isPrefixUnaryExpressionOperatorToken ( tokenKind ) ) {
3359
+ return ClassificationTypeNames . operator ;
3360
+ }
3361
+ else if ( TypeScript . SyntaxFacts . isAnyPunctuation ( tokenKind ) ) {
3362
+ return ClassificationTypeNames . punctuation ;
3363
+ }
3364
+ else if ( tokenKind === TypeScript . SyntaxKind . NumericLiteral ) {
3365
+ return ClassificationTypeNames . numericLiteral ;
3366
+ }
3367
+ else if ( tokenKind === TypeScript . SyntaxKind . StringLiteral ) {
3368
+ return ClassificationTypeNames . stringLiteral ;
3369
+ }
3370
+ else if ( tokenKind === TypeScript . SyntaxKind . RegularExpressionLiteral ) {
3371
+ // TODO: we shoudl get another classification type for these literals.
3372
+ return ClassificationTypeNames . stringLiteral ;
3373
+ }
3374
+ else if ( tokenKind === TypeScript . SyntaxKind . IdentifierName ) {
3375
+ var current : TypeScript . ISyntaxNodeOrToken = token ;
3376
+ var parent = token . parent ;
3377
+ while ( parent . kind ( ) === TypeScript . SyntaxKind . QualifiedName ) {
3378
+ current = parent ;
3379
+ parent = parent . parent ;
3380
+ }
3381
+
3382
+ switch ( parent . kind ( ) ) {
3383
+ case TypeScript . SyntaxKind . SimplePropertyAssignment :
3384
+ if ( ( < TypeScript . SimplePropertyAssignmentSyntax > parent ) . propertyName === token ) {
3385
+ return ClassificationTypeNames . identifier ;
3386
+ }
3387
+ return ;
3388
+ case TypeScript . SyntaxKind . ClassDeclaration :
3389
+ if ( ( < TypeScript . ClassDeclarationSyntax > parent ) . identifier === token ) {
3390
+ return ClassificationTypeNames . className ;
3391
+ }
3392
+ return ;
3393
+ case TypeScript . SyntaxKind . TypeParameter :
3394
+ if ( ( < TypeScript . TypeParameterSyntax > parent ) . identifier === token ) {
3395
+ return ClassificationTypeNames . typeParameterName ;
3396
+ }
3397
+ return ;
3398
+ case TypeScript . SyntaxKind . InterfaceDeclaration :
3399
+ if ( ( < TypeScript . InterfaceDeclarationSyntax > parent ) . identifier === token ) {
3400
+ return ClassificationTypeNames . interfaceName ;
3401
+ }
3402
+ return ;
3403
+ case TypeScript . SyntaxKind . EnumDeclaration :
3404
+ if ( ( < TypeScript . EnumDeclarationSyntax > parent ) . identifier === token ) {
3405
+ return ClassificationTypeNames . enumName ;
3406
+ }
3407
+ return ;
3408
+ case TypeScript . SyntaxKind . ModuleDeclaration :
3409
+ if ( ( < TypeScript . ModuleDeclarationSyntax > parent ) . name === current ) {
3410
+ return ClassificationTypeNames . moduleName ;
3411
+ }
3412
+ return ;
3413
+ default :
3414
+ return ClassificationTypeNames . text ;
3415
+ }
3416
+ }
3417
+ }
3418
+
3419
+ function processElement ( element : TypeScript . ISyntaxElement ) {
3420
+ // Ignore nodes that don't intersect the original span to classify.
3421
+ if ( ! TypeScript . isShared ( element ) && span . intersectsWith ( TypeScript . fullStart ( element ) , TypeScript . fullWidth ( element ) ) ) {
3422
+ for ( var i = 0 , n = TypeScript . childCount ( element ) ; i < n ; i ++ ) {
3423
+ var child = TypeScript . childAt ( element , i ) ;
3424
+ if ( child ) {
3425
+ if ( TypeScript . isToken ( child ) ) {
3426
+ classifyToken ( < TypeScript . ISyntaxToken > child ) ;
3427
+ }
3428
+ else {
3429
+ // Recurse into our child nodes.
3430
+ processElement ( child ) ;
3431
+ }
3432
+ }
3433
+ }
3434
+ }
3435
+ }
3436
+ }
3437
+
3217
3438
function getOutliningSpans ( filename : string ) : OutliningSpan [ ] {
3218
3439
// doesn't use compiler - no need to synchronize with host
3219
3440
filename = TypeScript . switchToForwardSlashes ( filename ) ;
@@ -3461,6 +3682,8 @@ module ts {
3461
3682
getSyntacticDiagnostics : getSyntacticDiagnostics ,
3462
3683
getSemanticDiagnostics : getSemanticDiagnostics ,
3463
3684
getCompilerOptionsDiagnostics : getCompilerOptionsDiagnostics ,
3685
+ getSyntacticClassifications : getSyntacticClassifications ,
3686
+ getSemanticClassifications : getSemanticClassifications ,
3464
3687
getCompletionsAtPosition : getCompletionsAtPosition ,
3465
3688
getCompletionEntryDetails : getCompletionEntryDetails ,
3466
3689
getTypeAtPosition : getTypeAtPosition ,
0 commit comments