@@ -10,16 +10,27 @@ function endsWith(s: string, suffix: string) {
10
10
class DeclarationsWalker {
11
11
private visitedTypes : ts . Type [ ] = [ ] ;
12
12
private text = "" ;
13
+ private removedTypes : ts . Type [ ] = [ ] ;
14
+
13
15
private constructor ( private typeChecker : ts . TypeChecker , private protocolFile : ts . SourceFile ) {
14
16
}
15
17
16
18
static getExtraDeclarations ( typeChecker : ts . TypeChecker , protocolFile : ts . SourceFile ) : string {
17
19
let text = "declare namespace ts.server.protocol {\n" ;
18
20
var walker = new DeclarationsWalker ( typeChecker , protocolFile ) ;
19
21
walker . visitTypeNodes ( protocolFile ) ;
20
- return walker . text
22
+ text = walker . text
21
23
? `declare namespace ts.server.protocol {\n${ walker . text } }`
22
24
: "" ;
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 ;
23
34
}
24
35
25
36
private processType ( type : ts . Type ) : void {
@@ -41,12 +52,18 @@ class DeclarationsWalker {
41
52
if ( sourceFile === this . protocolFile || path . basename ( sourceFile . fileName ) === "lib.d.ts" ) {
42
53
return ;
43
54
}
44
- // splice declaration in final d.ts file
45
- const text = decl . getFullText ( ) ;
46
- this . text += `${ text } \n` ;
55
+ if ( decl . kind === ts . SyntaxKind . EnumDeclaration ) {
56
+ this . removedTypes . push ( type ) ;
57
+ return ;
58
+ }
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
47
64
48
- // recursively pull all dependencies into result dts file
49
- this . visitTypeNodes ( decl ) ;
65
+ this . visitTypeNodes ( decl ) ;
66
+ }
50
67
}
51
68
}
52
69
}
@@ -62,15 +79,37 @@ class DeclarationsWalker {
62
79
case ts . SyntaxKind . Parameter :
63
80
case ts . SyntaxKind . IndexSignature :
64
81
if ( ( ( < ts . VariableDeclaration | ts . MethodDeclaration | ts . PropertyDeclaration | ts . ParameterDeclaration | ts . PropertySignature | ts . MethodSignature | ts . IndexSignatureDeclaration > node . parent ) . type ) === node ) {
65
- const type = this . typeChecker . getTypeAtLocation ( node ) ;
66
- if ( type && ! ( type . flags & ts . TypeFlags . TypeParameter ) ) {
67
- this . processType ( type ) ;
68
- }
82
+ this . processTypeOfNode ( node ) ;
69
83
}
70
84
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 ;
71
96
}
72
97
}
73
98
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
+ }
74
113
}
75
114
}
76
115
@@ -121,9 +160,12 @@ function generateProtocolFile(protocolTs: string, typeScriptServicesDts: string)
121
160
if ( extraDeclarations ) {
122
161
protocolDts += extraDeclarations ;
123
162
}
163
+ protocolDts += "\nimport protocol = ts.server.protocol;" ;
164
+ protocolDts += "\nexport = protocol;" ;
165
+ protocolDts += "\nexport as namespace protocol;" ;
124
166
// do sanity check and try to compile generated text as standalone program
125
167
const sanityCheckProgram = getProgramWithProtocolText ( protocolDts , /*includeTypeScriptServices*/ false ) ;
126
- const diagnostics = [ ...program . getSyntacticDiagnostics ( ) , ...program . getSemanticDiagnostics ( ) , ...program . getGlobalDiagnostics ( ) ] ;
168
+ const diagnostics = [ ...sanityCheckProgram . getSyntacticDiagnostics ( ) , ...sanityCheckProgram . getSemanticDiagnostics ( ) , ...sanityCheckProgram . getGlobalDiagnostics ( ) ] ;
127
169
if ( diagnostics . length ) {
128
170
const flattenedDiagnostics = diagnostics . map ( d => ts . flattenDiagnosticMessageText ( d . messageText , "\n" ) ) . join ( "\n" ) ;
129
171
throw new Error ( `Unexpected errors during sanity check: ${ flattenedDiagnostics } ` ) ;
0 commit comments