internal namespace ts . classifier . v2020 { export const enum TokenEncodingConsts { typeOffset = 8 , modifierMask = ( 1 << typeOffset ) - 1 } export const enum TokenType { class , enum , interface , namespace , typeParameter , type , parameter , variable , enumMember , property , function , member } export const enum TokenModifier { declaration , static , async , readonly , defaultLibrary , local } /** This is mainly used internally for testing */ export function getSemanticClassifications ( program , cancellationToken , sourceFile , span ) { const classifications = getEncodedSemanticClassifications ( program , cancellationToken , sourceFile , span ) ; Debug . assert ( classifications . spans . length % 3 === 0 ) ; const dense = classifications . spans ; const result = [ ] ; for ( let i = 0 ; i < dense . length ; i += 3 ) { result . push ( { textSpan : createTextSpan ( dense [ i ] , dense [ i + 1 ] ) , classificationType : dense [ i + 2 ] } ) ; } return result ; } export function getEncodedSemanticClassifications ( program , cancellationToken , sourceFile , span ) { return { spans : getSemanticTokens ( program , sourceFile , span , cancellationToken ) , endOfLineState : EndOfLineState . None } ; } function getSemanticTokens ( program , sourceFile , span , cancellationToken ) { const resultTokens = [ ] ; const collector = ( node , typeIdx , modifierSet ) => { resultTokens . push ( node . getStart ( sourceFile ) , node . getWidth ( sourceFile ) , ( ( typeIdx + 1 ) << TokenEncodingConsts . typeOffset ) + modifierSet ) ; } ; if ( program && sourceFile ) { collectTokens ( program , sourceFile , span , collector , cancellationToken ) ; } return resultTokens ; } function collectTokens ( program , sourceFile , span , collector , cancellationToken ) { const typeChecker = program . getTypeChecker ( ) ; let inJSXElement = false ; function visit ( node ) { switch ( node . kind ) { case SyntaxKind . ModuleDeclaration : case SyntaxKind . ClassDeclaration : case SyntaxKind . InterfaceDeclaration : case SyntaxKind . FunctionDeclaration : case SyntaxKind . ClassExpression : case SyntaxKind . FunctionExpression : case SyntaxKind . ArrowFunction : cancellationToken . throwIfCancellationRequested ( ) ; } if ( ! node || ! textSpanIntersectsWith ( span , node . pos , node . getFullWidth ( ) ) || node . getFullWidth ( ) === 0 ) { return ; } const prevInJSXElement = inJSXElement ; if ( isJsxElement ( node ) || isJsxSelfClosingElement ( node ) ) { inJSXElement = true ; } if ( isJsxExpression ( node ) ) { inJSXElement = false ; } if ( isIdentifier ( node ) && ! inJSXElement && ! inImportClause ( node ) && ! isInfinityOrNaNString ( node . escapedText ) ) { let symbol = typeChecker . getSymbolAtLocation ( node ) ; if ( symbol ) { if ( symbol . flags & SymbolFlags . Alias ) { symbol = typeChecker . getAliasedSymbol ( symbol ) ; } let typeIdx = classifySymbol ( symbol , getMeaningFromLocation ( node ) ) ; if ( typeIdx !== undefined ) { let modifierSet = 0 ; if ( node . parent ) { const parentIsDeclaration = ( isBindingElement ( node . parent ) || tokenFromDeclarationMapping . get ( node . parent . kind ) === typeIdx ) ; if ( parentIsDeclaration && ( node . parent as NamedDeclaration ) . name === node ) { modifierSet = 1 << TokenModifier . declaration ; } } if ( typeIdx === TokenType . parameter && isRightSideOfQualifiedNameOrPropertyAccess ( node ) ) { typeIdx = TokenType . property ; } typeIdx = reclassifyByType ( typeChecker , node , typeIdx ) ; const decl = symbol . valueDeclaration ; if ( decl ) { const modifiers = getCombinedModifierFlags ( decl ) ; const nodeFlags = getCombinedNodeFlags ( decl ) ; if ( modifiers & ModifierFlags . Static ) { modifierSet |= 1 << TokenModifier . static ; } if ( modifiers & ModifierFlags . Async ) { modifierSet |= 1 << TokenModifier . async ; } if ( typeIdx !== TokenType . class && typeIdx !== TokenType . interface ) { if ( ( modifiers & ModifierFlags . Readonly ) || ( nodeFlags & NodeFlags . Const ) || ( symbol . getFlags ( ) & SymbolFlags . EnumMember ) ) { modifierSet |= 1 << TokenModifier . readonly ; } } if ( ( typeIdx === TokenType . variable || typeIdx === TokenType . function ) && isLocalDeclaration ( decl , sourceFile ) ) { modifierSet |= 1 << TokenModifier . local ; } if ( program . isSourceFileDefaultLibrary ( decl . getSourceFile ( ) ) ) { modifierSet |= 1 << TokenModifier . defaultLibrary ; } } else if ( symbol . declarations && symbol . declarations . some ( d => program . isSourceFileDefaultLibrary ( d . getSourceFile ( ) ) ) ) { modifierSet |= 1 << TokenModifier . defaultLibrary ; } collector ( node , typeIdx , modifierSet ) ; } } } forEachChild ( node , visit ) ; inJSXElement = prevInJSXElement ; } visit ( sourceFile ) ; } function classifySymbol ( symbol , meaning ) { const flags = symbol . getFlags ( ) ; if ( flags & SymbolFlags . Class ) { return TokenType . class ; } else if ( flags & SymbolFlags . Enum ) { return TokenType . enum ; } else if ( flags & SymbolFlags . TypeAlias ) { return TokenType . type ; } else if ( flags & SymbolFlags . Interface ) { if ( meaning & SemanticMeaning . Type ) { return TokenType . interface ; } } else if ( flags & SymbolFlags . TypeParameter ) { return TokenType . typeParameter ; } let decl = symbol . valueDeclaration || symbol . declarations && symbol . declarations [ 0 ] ; if ( decl && isBindingElement ( decl ) ) { decl = getDeclarationForBindingElement ( decl ) ; } return decl && tokenFromDeclarationMapping . get ( decl . kind ) ; } function reclassifyByType ( typeChecker , node , typeIdx ) { if ( typeIdx === TokenType . variable || typeIdx === TokenType . property || typeIdx === TokenType . parameter ) { const type = typeChecker . getTypeAtLocation ( node ) ; if ( type ) { const test = ( condition ) => { return condition ( type ) || type . isUnion ( ) && type . types . some ( condition ) ; } ; if ( typeIdx !== TokenType . parameter && test ( t => t . getConstructSignatures ( ) . length > 0 ) ) { return TokenType . class ; } if ( test ( t => t . getCallSignatures ( ) . length > 0 ) && ! test ( t => t . getProperties ( ) . length > 0 ) || isExpressionInCallExpression ( node ) ) { return typeIdx === TokenType . property ? TokenType . member : TokenType . function ; } } } return typeIdx ; } function isLocalDeclaration ( decl , sourceFile ) { if ( isBindingElement ( decl ) ) { decl = getDeclarationForBindingElement ( decl ) ; } if ( isVariableDeclaration ( decl ) ) { return ( ! isSourceFile ( decl . parent . parent . parent ) || isCatchClause ( decl . parent ) ) && decl . getSourceFile ( ) === sourceFile ; } else if ( isFunctionDeclaration ( decl ) ) { return ! isSourceFile ( decl . parent ) && decl . getSourceFile ( ) === sourceFile ; } return false ; } function getDeclarationForBindingElement ( element ) { while ( true ) { if ( isBindingElement ( element . parent . parent ) ) { element = element . parent . parent ; } else { return element . parent . parent ; } } } function inImportClause ( node ) { const parent = node . parent ; return parent && ( isImportClause ( parent ) || isImportSpecifier ( parent ) || isNamespaceImport ( parent ) ) ; } function isExpressionInCallExpression ( node ) { while ( isRightSideOfQualifiedNameOrPropertyAccess ( node ) ) { node = node . parent ; } return isCallExpression ( node . parent ) && node . parent . expression === node ; } function isRightSideOfQualifiedNameOrPropertyAccess ( node ) { return ( isQualifiedName ( node . parent ) && node . parent . right === node ) || ( isPropertyAccessExpression ( node . parent ) && node . parent . name === node ) ; } const tokenFromDeclarationMapping = new Map < SyntaxKind , TokenType > ( [ [ SyntaxKind . VariableDeclaration , TokenType . variable ] , [ SyntaxKind . Parameter , TokenType . parameter ] , [ SyntaxKind . PropertyDeclaration , TokenType . property ] , [ SyntaxKind . ModuleDeclaration , TokenType . namespace ] , [ SyntaxKind . EnumDeclaration , TokenType . enum ] , [ SyntaxKind . EnumMember , TokenType . enumMember ] , [ SyntaxKind . ClassDeclaration , TokenType . class ] , [ SyntaxKind . MethodDeclaration , TokenType . member ] , [ SyntaxKind . FunctionDeclaration , TokenType . function ] , [ SyntaxKind . FunctionExpression , TokenType . function ] , [ SyntaxKind . MethodSignature , TokenType . member ] , [ SyntaxKind . GetAccessor , TokenType . property ] , [ SyntaxKind . SetAccessor , TokenType . property ] , [ SyntaxKind . PropertySignature , TokenType . property ] , [ SyntaxKind . InterfaceDeclaration , TokenType . interface ] , [ SyntaxKind . TypeAliasDeclaration , TokenType . type ] , [ SyntaxKind . TypeParameter , TokenType . typeParameter ] , [ SyntaxKind . PropertyAssignment , TokenType . property ] , [ SyntaxKind . ShorthandPropertyAssignment , TokenType . property ] ] ) ; }