@@ -1510,6 +1510,7 @@ module ts {
1510
1510
public static typeParameterName = "type parameter name" ;
1511
1511
public static typeAliasName = "type alias name" ;
1512
1512
public static parameterName = "parameter name" ;
1513
+ public static docCommentTagName = "doc comment tag name" ;
1513
1514
}
1514
1515
1515
1516
export const enum ClassificationType {
@@ -1529,7 +1530,8 @@ module ts {
1529
1530
moduleName = 14 ,
1530
1531
typeParameterName = 15 ,
1531
1532
typeAliasName = 16 ,
1532
- parameterName = 17
1533
+ parameterName = 17 ,
1534
+ docCommentTagName = 18 ,
1533
1535
}
1534
1536
1535
1537
/// Language Service
@@ -1813,7 +1815,8 @@ module ts {
1813
1815
}
1814
1816
1815
1817
export function createLanguageServiceSourceFile ( fileName : string , scriptSnapshot : IScriptSnapshot , scriptTarget : ScriptTarget , version : string , setNodeParents : boolean ) : SourceFile {
1816
- let sourceFile = createSourceFile ( fileName , scriptSnapshot . getText ( 0 , scriptSnapshot . getLength ( ) ) , scriptTarget , setNodeParents ) ;
1818
+ let text = scriptSnapshot . getText ( 0 , scriptSnapshot . getLength ( ) ) ;
1819
+ let sourceFile = createSourceFile ( fileName , text , scriptTarget , setNodeParents ) ;
1817
1820
setSourceFileFields ( sourceFile , scriptSnapshot , version ) ;
1818
1821
// after full parsing we can use table with interned strings as name table
1819
1822
sourceFile . nameTable = sourceFile . identifiers ;
@@ -2837,6 +2840,7 @@ module ts {
2837
2840
let typeChecker = program . getTypeChecker ( ) ;
2838
2841
let syntacticStart = new Date ( ) . getTime ( ) ;
2839
2842
let sourceFile = getValidSourceFile ( fileName ) ;
2843
+ let isJavaScriptFile = isJavaScript ( fileName ) ;
2840
2844
2841
2845
let start = new Date ( ) . getTime ( ) ;
2842
2846
let currentToken = getTokenAtPosition ( sourceFile , position ) ;
@@ -2937,13 +2941,29 @@ module ts {
2937
2941
}
2938
2942
2939
2943
let type = typeChecker . getTypeAtLocation ( node ) ;
2944
+ addTypeProperties ( type ) ;
2945
+ }
2946
+
2947
+ function addTypeProperties ( type : Type ) {
2940
2948
if ( type ) {
2941
2949
// Filter private properties
2942
- forEach ( type . getApparentProperties ( ) , symbol => {
2950
+ for ( let symbol of type . getApparentProperties ( ) ) {
2943
2951
if ( typeChecker . isValidPropertyAccess ( < PropertyAccessExpression > ( node . parent ) , symbol . name ) ) {
2944
2952
symbols . push ( symbol ) ;
2945
2953
}
2946
- } ) ;
2954
+ }
2955
+
2956
+ if ( isJavaScriptFile && type . flags & TypeFlags . Union ) {
2957
+ // In javascript files, for union types, we don't just get the members that
2958
+ // the individual types have in common, we also include all the members that
2959
+ // each individual type has. This is because we're going to add all identifiers
2960
+ // anyways. So we might as well elevate the members that were at least part
2961
+ // of the individual types to a higher status since we know what they are.
2962
+ let unionType = < UnionType > type ;
2963
+ for ( let elementType of unionType . types ) {
2964
+ addTypeProperties ( elementType ) ;
2965
+ }
2966
+ }
2947
2967
}
2948
2968
}
2949
2969
@@ -6040,6 +6060,7 @@ module ts {
6040
6060
case ClassificationType . typeParameterName : return ClassificationTypeNames . typeParameterName ;
6041
6061
case ClassificationType . typeAliasName : return ClassificationTypeNames . typeAliasName ;
6042
6062
case ClassificationType . parameterName : return ClassificationTypeNames . parameterName ;
6063
+ case ClassificationType . docCommentTagName : return ClassificationTypeNames . docCommentTagName ;
6043
6064
}
6044
6065
}
6045
6066
@@ -6102,8 +6123,7 @@ module ts {
6102
6123
// Only bother with the trivia if it at least intersects the span of interest.
6103
6124
if ( textSpanIntersectsWith ( span , start , width ) ) {
6104
6125
if ( isComment ( kind ) ) {
6105
- // Simple comment. Just add as is.
6106
- pushClassification ( start , width , ClassificationType . comment ) ;
6126
+ classifyComment ( token , kind , start , width ) ;
6107
6127
continue ;
6108
6128
}
6109
6129
@@ -6127,6 +6147,92 @@ module ts {
6127
6147
}
6128
6148
}
6129
6149
6150
+ function classifyComment ( token : Node , kind : SyntaxKind , start : number , width : number ) {
6151
+ if ( kind === SyntaxKind . MultiLineCommentTrivia ) {
6152
+ // See if this is a doc comment. If so, we'll classify certain portions of it
6153
+ // specially.
6154
+ let docCommentAndDiagnostics = parseIsolatedJSDocComment ( sourceFile . text , start , width ) ;
6155
+ if ( docCommentAndDiagnostics && docCommentAndDiagnostics . jsDocComment ) {
6156
+ docCommentAndDiagnostics . jsDocComment . parent = token ;
6157
+ classifyJSDocComment ( docCommentAndDiagnostics . jsDocComment ) ;
6158
+ return ;
6159
+ }
6160
+ }
6161
+
6162
+ // Simple comment. Just add as is.
6163
+ pushCommentRange ( start , width ) ;
6164
+ }
6165
+
6166
+ function pushCommentRange ( start : number , width : number ) {
6167
+ pushClassification ( start , width , ClassificationType . comment ) ;
6168
+ }
6169
+
6170
+ function classifyJSDocComment ( docComment : JSDocComment ) {
6171
+ let pos = docComment . pos ;
6172
+
6173
+ for ( let tag of docComment . tags ) {
6174
+ // As we walk through each tag, classify the portion of text from the end of
6175
+ // the last tag (or the start of the entire doc comment) as 'comment'.
6176
+ if ( tag . pos !== pos ) {
6177
+ pushCommentRange ( pos , tag . pos - pos ) ;
6178
+ }
6179
+
6180
+ pushClassification ( tag . atToken . pos , tag . atToken . end - tag . atToken . pos , ClassificationType . punctuation ) ;
6181
+ pushClassification ( tag . tagName . pos , tag . tagName . end - tag . tagName . pos , ClassificationType . docCommentTagName ) ;
6182
+
6183
+ pos = tag . tagName . end ;
6184
+
6185
+ switch ( tag . kind ) {
6186
+ case SyntaxKind . JSDocParameterTag :
6187
+ processJSDocParameterTag ( < JSDocParameterTag > tag ) ;
6188
+ break ;
6189
+ case SyntaxKind . JSDocTemplateTag :
6190
+ processJSDocTemplateTag ( < JSDocTemplateTag > tag ) ;
6191
+ break ;
6192
+ case SyntaxKind . JSDocTypeTag :
6193
+ processElement ( ( < JSDocTypeTag > tag ) . typeExpression ) ;
6194
+ break ;
6195
+ case SyntaxKind . JSDocReturnTag :
6196
+ processElement ( ( < JSDocReturnTag > tag ) . typeExpression ) ;
6197
+ break ;
6198
+ }
6199
+
6200
+ pos = tag . end ;
6201
+ }
6202
+
6203
+ if ( pos !== docComment . end ) {
6204
+ pushCommentRange ( pos , docComment . end - pos ) ;
6205
+ }
6206
+
6207
+ return ;
6208
+
6209
+ function processJSDocParameterTag ( tag : JSDocParameterTag ) {
6210
+ if ( tag . preParameterName ) {
6211
+ pushCommentRange ( pos , tag . preParameterName . pos - pos ) ;
6212
+ pushClassification ( tag . preParameterName . pos , tag . preParameterName . end - tag . preParameterName . pos , ClassificationType . parameterName ) ;
6213
+ pos = tag . preParameterName . end ;
6214
+ }
6215
+
6216
+ if ( tag . typeExpression ) {
6217
+ pushCommentRange ( pos , tag . typeExpression . pos - pos ) ;
6218
+ processElement ( tag . typeExpression ) ;
6219
+ pos = tag . typeExpression . end ;
6220
+ }
6221
+
6222
+ if ( tag . postParameterName ) {
6223
+ pushCommentRange ( pos , tag . postParameterName . pos - pos ) ;
6224
+ pushClassification ( tag . postParameterName . pos , tag . postParameterName . end - tag . postParameterName . pos , ClassificationType . parameterName ) ;
6225
+ pos = tag . postParameterName . end ;
6226
+ }
6227
+ }
6228
+ }
6229
+
6230
+ function processJSDocTemplateTag ( tag : JSDocTemplateTag ) {
6231
+ for ( let child of tag . getChildren ( ) ) {
6232
+ processElement ( child ) ;
6233
+ }
6234
+ }
6235
+
6130
6236
function classifyDisabledMergeCode ( text : string , start : number , end : number ) {
6131
6237
// Classify the line that the ======= marker is on as a comment. Then just lex
6132
6238
// all further tokens and add them to the result.
@@ -6260,9 +6366,13 @@ module ts {
6260
6366
}
6261
6367
6262
6368
function processElement ( element : Node ) {
6369
+ if ( ! element ) {
6370
+ return ;
6371
+ }
6372
+
6263
6373
// Ignore nodes that don't intersect the original span to classify.
6264
6374
if ( textSpanIntersectsWith ( span , element . getFullStart ( ) , element . getFullWidth ( ) ) ) {
6265
- let children = element . getChildren ( ) ;
6375
+ let children = element . getChildren ( sourceFile ) ;
6266
6376
for ( let child of children ) {
6267
6377
if ( isToken ( child ) ) {
6268
6378
classifyToken ( child ) ;
0 commit comments