@@ -4,64 +4,73 @@ import tsc from "typescript";
44
55export type TypeMap = Map < string , string > ;
66
7- function forEachNode ( ast : tsc . Node , callback : ( node : tsc . Node ) => void ) : void {
8- function visit ( node : tsc . Node ) {
9- tsc . forEachChild ( node , visit ) ;
10- callback ( node ) ;
11- }
12-
13- visit ( ast ) ;
14- }
7+ export default class TscUtils {
8+ private readonly program : tsc . Program ;
9+ private readonly typeChecker : tsc . TypeChecker ;
1510
16- function safeTypeToString ( node : tsc . Type , typeChecker : tsc . TypeChecker ) : string {
17- try {
18- const tpe : string = typeChecker . typeToString ( node , undefined , Defaults . DEFAULT_TSC_TYPE_OPTIONS ) ;
19- if ( tpe . length === 0 ) return Defaults . ANY
20- if ( tpe == Defaults . UNKNOWN ) return Defaults . ANY
21- if ( Defaults . STRING_REGEX . test ( tpe ) ) return "string" ;
22- if ( Defaults . ARRAY_REGEX . test ( tpe ) ) return "__ecma.Array" ;
23- return tpe ;
24- } catch ( err ) {
25- return Defaults . ANY ;
11+ constructor ( files : string [ ] ) {
12+ this . program = tsc . createProgram ( files , Defaults . DEFAULT_TSC_OPTIONS ) ;
13+ this . typeChecker = this . program . getTypeChecker ( ) ;
2614 }
27- }
2815
29- function isSignatureDeclaration ( node : tsc . Node ) : node is tsc . SignatureDeclaration {
30- return tsc . isSetAccessor ( node ) || tsc . isGetAccessor ( node ) ||
31- tsc . isConstructSignatureDeclaration ( node ) || tsc . isMethodDeclaration ( node ) ||
32- tsc . isFunctionDeclaration ( node ) || tsc . isConstructorDeclaration ( node )
33- }
34-
35- export function typeMapForFile ( file : string ) : TypeMap {
36- function addType ( node : tsc . Node ) : void {
37- if ( tsc . isSourceFile ( node ) ) return ;
38- let typeStr ;
39- if ( isSignatureDeclaration ( node ) ) {
40- const signature : tsc . Signature = typeChecker . getSignatureFromDeclaration ( node ) ! ;
41- const returnType : tsc . Type = typeChecker . getReturnTypeOfSignature ( signature ) ;
42- typeStr = safeTypeToString ( returnType , typeChecker ) ;
43- } else if ( tsc . isFunctionLike ( node ) ) {
44- const funcType : tsc . Type = typeChecker . getTypeAtLocation ( node ) ;
45- const funcSignature : tsc . Signature = typeChecker . getSignaturesOfType ( funcType , tsc . SignatureKind . Call ) [ 0 ] ;
46- if ( funcSignature ) {
47- typeStr = safeTypeToString ( funcSignature . getReturnType ( ) , typeChecker ) ;
16+ typeMapForFile ( file : string ) : TypeMap {
17+ let addType : ( node : tsc . Node ) => void = ( node : tsc . Node ) : void => {
18+ if ( tsc . isSourceFile ( node ) ) return ;
19+ let typeStr ;
20+ if ( this . isSignatureDeclaration ( node ) ) {
21+ const signature : tsc . Signature = this . typeChecker . getSignatureFromDeclaration ( node ) ! ;
22+ const returnType : tsc . Type = this . typeChecker . getReturnTypeOfSignature ( signature ) ;
23+ typeStr = this . safeTypeToString ( returnType ) ;
24+ } else if ( tsc . isFunctionLike ( node ) ) {
25+ const funcType : tsc . Type = this . typeChecker . getTypeAtLocation ( node ) ;
26+ const funcSignature : tsc . Signature = this . typeChecker . getSignaturesOfType ( funcType , tsc . SignatureKind . Call ) [ 0 ] ;
27+ if ( funcSignature ) {
28+ typeStr = this . safeTypeToString ( funcSignature . getReturnType ( ) ) ;
29+ } else {
30+ typeStr = this . safeTypeToString ( this . typeChecker . getTypeAtLocation ( node ) ) ;
31+ }
4832 } else {
49- typeStr = safeTypeToString ( typeChecker . getTypeAtLocation ( node ) , typeChecker ) ;
33+ typeStr = this . safeTypeToString ( this . typeChecker . getTypeAtLocation ( node ) ) ;
34+ }
35+ if ( typeStr !== Defaults . ANY ) {
36+ const pos = `${ node . getStart ( ) } :${ node . getEnd ( ) } ` ;
37+ seenTypes . set ( pos , typeStr ) ;
5038 }
51- } else {
52- typeStr = safeTypeToString ( typeChecker . getTypeAtLocation ( node ) , typeChecker ) ;
5339 }
54- if ( typeStr !== Defaults . ANY ) {
55- const pos = `${ node . getStart ( ) } :${ node . getEnd ( ) } ` ;
56- seenTypes . set ( pos , typeStr ) ;
40+
41+ const seenTypes = new Map < string , string > ( ) ;
42+ this . forEachNode ( this . program . getSourceFile ( file ) ! , addType )
43+ return seenTypes
44+ }
45+
46+ private forEachNode ( ast : tsc . Node , callback : ( node : tsc . Node ) => void ) : void {
47+ function visit ( node : tsc . Node ) {
48+ tsc . forEachChild ( node , visit ) ;
49+ callback ( node ) ;
5750 }
51+
52+ visit ( ast ) ;
5853 }
5954
60- const program : tsc . Program = tsc . createProgram ( [ file ] , Defaults . DEFAULT_TSC_OPTIONS ) ;
61- const typeChecker : tsc . TypeChecker = program . getTypeChecker ( ) ;
62- const seenTypes = new Map < string , string > ( ) ;
55+ private safeTypeToString ( node : tsc . Type ) : string {
56+ try {
57+ const tpe : string = this . typeChecker . typeToString ( node , undefined , Defaults . DEFAULT_TSC_TYPE_OPTIONS ) ;
58+ if ( tpe . length === 0 ) return Defaults . ANY
59+ if ( tpe == Defaults . UNKNOWN ) return Defaults . ANY
60+ if ( tpe . startsWith ( Defaults . UNRESOLVED ) ) return Defaults . ANY
61+ if ( Defaults . STRING_REGEX . test ( tpe ) ) return "string" ;
62+ if ( Defaults . ARRAY_REGEX . test ( tpe ) ) return "__ecma.Array" ;
63+ return tpe ;
64+ } catch ( err ) {
65+ return Defaults . ANY ;
66+ }
67+ }
68+
69+ private isSignatureDeclaration ( node : tsc . Node ) : node is tsc . SignatureDeclaration {
70+ return tsc . isSetAccessor ( node ) || tsc . isGetAccessor ( node ) ||
71+ tsc . isConstructSignatureDeclaration ( node ) || tsc . isMethodDeclaration ( node ) ||
72+ tsc . isFunctionDeclaration ( node ) || tsc . isConstructorDeclaration ( node )
73+ }
6374
64- forEachNode ( program . getSourceFile ( file ) ! , addType )
65- return seenTypes
6675}
6776
0 commit comments