@@ -10,16 +10,27 @@ function endsWith(s: string, suffix: string) {
1010class DeclarationsWalker {
1111 private visitedTypes : ts . Type [ ] = [ ] ;
1212 private text = "" ;
13+ private removedTypes : ts . Type [ ] = [ ] ;
14+
1315 private constructor ( private typeChecker : ts . TypeChecker , private protocolFile : ts . SourceFile ) {
1416 }
1517
1618 static getExtraDeclarations ( typeChecker : ts . TypeChecker , protocolFile : ts . SourceFile ) : string {
1719 let text = "declare namespace ts.server.protocol {\n" ;
1820 var walker = new DeclarationsWalker ( typeChecker , protocolFile ) ;
1921 walker . visitTypeNodes ( protocolFile ) ;
20- return walker . text
22+ text = walker . text
2123 ? `declare namespace ts.server.protocol {\n${ walker . text } }`
2224 : "" ;
25+ if ( walker . removedTypes ) {
26+ text += "\ndeclare namespace ts {\n" ;
27+ text += " // these types are empty stubs for types from services and should not be used directly\n"
28+ for ( const type of walker . removedTypes ) {
29+ text += ` export type ${ type . symbol . name } = never;\n` ;
30+ }
31+ text += "}"
32+ }
33+ return text ;
2334 }
2435
2536 private processType ( type : ts . Type ) : void {
@@ -41,19 +52,18 @@ class DeclarationsWalker {
4152 if ( sourceFile === this . protocolFile || path . basename ( sourceFile . fileName ) === "lib.d.ts" ) {
4253 return ;
4354 }
44- // splice declaration in final d.ts file
45- let text = decl . getFullText ( ) ;
46- if ( decl . kind === ts . SyntaxKind . EnumDeclaration && ! ( decl . flags & ts . NodeFlags . Const ) ) {
47- // patch enum declaration to make them constan
48- const declStart = decl . getStart ( ) - decl . getFullStart ( ) ;
49- const prefix = text . substring ( 0 , declStart ) ;
50- const suffix = text . substring ( declStart + "enum" . length , decl . getEnd ( ) - decl . getFullStart ( ) ) ;
51- text = prefix + "const enum" + suffix ;
55+ if ( decl . kind === ts . SyntaxKind . EnumDeclaration ) {
56+ this . removedTypes . push ( type ) ;
57+ return ;
5258 }
53- this . text += `${ text } \n` ;
59+ else {
60+ // splice declaration in final d.ts file
61+ let text = decl . getFullText ( ) ;
62+ this . text += `${ text } \n` ;
63+ // recursively pull all dependencies into result dts file
5464
55- // recursively pull all dependencies into result dts file
56- this . visitTypeNodes ( decl ) ;
65+ this . visitTypeNodes ( decl ) ;
66+ }
5767 }
5868 }
5969 }
@@ -69,15 +79,37 @@ class DeclarationsWalker {
6979 case ts . SyntaxKind . Parameter :
7080 case ts . SyntaxKind . IndexSignature :
7181 if ( ( ( < ts . VariableDeclaration | ts . MethodDeclaration | ts . PropertyDeclaration | ts . ParameterDeclaration | ts . PropertySignature | ts . MethodSignature | ts . IndexSignatureDeclaration > node . parent ) . type ) === node ) {
72- const type = this . typeChecker . getTypeAtLocation ( node ) ;
73- if ( type && ! ( type . flags & ts . TypeFlags . TypeParameter ) ) {
74- this . processType ( type ) ;
75- }
82+ this . processTypeOfNode ( node ) ;
7683 }
7784 break ;
85+ case ts . SyntaxKind . InterfaceDeclaration :
86+ const heritageClauses = ( < ts . InterfaceDeclaration > node . parent ) . heritageClauses ;
87+ if ( heritageClauses ) {
88+ if ( heritageClauses [ 0 ] . token !== ts . SyntaxKind . ExtendsKeyword ) {
89+ throw new Error ( `Unexpected kind of heritage clause: ${ ts . SyntaxKind [ heritageClauses [ 0 ] . kind ] } ` ) ;
90+ }
91+ for ( const type of heritageClauses [ 0 ] . types ) {
92+ this . processTypeOfNode ( type ) ;
93+ }
94+ }
95+ break ;
7896 }
7997 }
8098 ts . forEachChild ( node , n => this . visitTypeNodes ( n ) ) ;
99+ }
100+
101+ private processTypeOfNode ( node : ts . Node ) : void {
102+ if ( node . kind === ts . SyntaxKind . UnionType ) {
103+ for ( const t of ( < ts . UnionTypeNode > node ) . types ) {
104+ this . processTypeOfNode ( t ) ;
105+ }
106+ }
107+ else {
108+ const type = this . typeChecker . getTypeAtLocation ( node ) ;
109+ if ( type && ! ( type . flags & ( ts . TypeFlags . TypeParameter ) ) ) {
110+ this . processType ( type ) ;
111+ }
112+ }
81113 }
82114}
83115
@@ -128,9 +160,12 @@ function generateProtocolFile(protocolTs: string, typeScriptServicesDts: string)
128160 if ( extraDeclarations ) {
129161 protocolDts += extraDeclarations ;
130162 }
163+ protocolDts += "\nimport protocol = ts.server.protocol;" ;
164+ protocolDts += "\nexport = protocol;" ;
165+ protocolDts += "\nexport as namespace protocol;" ;
131166 // do sanity check and try to compile generated text as standalone program
132167 const sanityCheckProgram = getProgramWithProtocolText ( protocolDts , /*includeTypeScriptServices*/ false ) ;
133- const diagnostics = [ ...program . getSyntacticDiagnostics ( ) , ...program . getSemanticDiagnostics ( ) , ...program . getGlobalDiagnostics ( ) ] ;
168+ const diagnostics = [ ...sanityCheckProgram . getSyntacticDiagnostics ( ) , ...sanityCheckProgram . getSemanticDiagnostics ( ) , ...sanityCheckProgram . getGlobalDiagnostics ( ) ] ;
134169 if ( diagnostics . length ) {
135170 const flattenedDiagnostics = diagnostics . map ( d => ts . flattenDiagnosticMessageText ( d . messageText , "\n" ) ) . join ( "\n" ) ;
136171 throw new Error ( `Unexpected errors during sanity check: ${ flattenedDiagnostics } ` ) ;
0 commit comments