1
+ /* @internal */
2
+ namespace ts {
3
+ export namespace Debug {
4
+ export let currentAssertionLevel = AssertionLevel . None ;
5
+ export let isDebugging = false ;
6
+
7
+ export function shouldAssert ( level : AssertionLevel ) : boolean {
8
+ return currentAssertionLevel >= level ;
9
+ }
10
+
11
+ export function assert ( expression : boolean , message ?: string , verboseDebugInfo ?: string | ( ( ) => string ) , stackCrawlMark ?: AnyFunction ) : void {
12
+ if ( ! expression ) {
13
+ if ( verboseDebugInfo ) {
14
+ message += "\r\nVerbose Debug Information: " + ( typeof verboseDebugInfo === "string" ? verboseDebugInfo : verboseDebugInfo ( ) ) ;
15
+ }
16
+ fail ( message ? "False expression: " + message : "False expression." , stackCrawlMark || assert ) ;
17
+ }
18
+ }
19
+
20
+ export function assertEqual < T > ( a : T , b : T , msg ?: string , msg2 ?: string ) : void {
21
+ if ( a !== b ) {
22
+ const message = msg ? msg2 ? `${ msg } ${ msg2 } ` : msg : "" ;
23
+ fail ( `Expected ${ a } === ${ b } . ${ message } ` ) ;
24
+ }
25
+ }
26
+
27
+ export function assertLessThan ( a : number , b : number , msg ?: string ) : void {
28
+ if ( a >= b ) {
29
+ fail ( `Expected ${ a } < ${ b } . ${ msg || "" } ` ) ;
30
+ }
31
+ }
32
+
33
+ export function assertLessThanOrEqual ( a : number , b : number ) : void {
34
+ if ( a > b ) {
35
+ fail ( `Expected ${ a } <= ${ b } ` ) ;
36
+ }
37
+ }
38
+
39
+ export function assertGreaterThanOrEqual ( a : number , b : number ) : void {
40
+ if ( a < b ) {
41
+ fail ( `Expected ${ a } >= ${ b } ` ) ;
42
+ }
43
+ }
44
+
45
+ export function fail ( message ?: string , stackCrawlMark ?: AnyFunction ) : never {
46
+ debugger ;
47
+ const e = new Error ( message ? `Debug Failure. ${ message } ` : "Debug Failure." ) ;
48
+ if ( ( < any > Error ) . captureStackTrace ) {
49
+ ( < any > Error ) . captureStackTrace ( e , stackCrawlMark || fail ) ;
50
+ }
51
+ throw e ;
52
+ }
53
+
54
+ export function assertDefined < T > ( value : T | null | undefined , message ?: string ) : T {
55
+ if ( value === undefined || value === null ) return fail ( message ) ;
56
+ return value ;
57
+ }
58
+
59
+ export function assertEachDefined < T , A extends ReadonlyArray < T > > ( value : A , message ?: string ) : A {
60
+ for ( const v of value ) {
61
+ assertDefined ( v , message ) ;
62
+ }
63
+ return value ;
64
+ }
65
+
66
+ export function assertNever ( member : never , message = "Illegal value:" , stackCrawlMark ?: AnyFunction ) : never {
67
+ const detail = typeof member === "object" && "kind" in member && "pos" in member && formatSyntaxKind ? "SyntaxKind: " + formatSyntaxKind ( ( member as Node ) . kind ) : JSON . stringify ( member ) ;
68
+ return fail ( `${ message } ${ detail } ` , stackCrawlMark || assertNever ) ;
69
+ }
70
+
71
+ export function getFunctionName ( func : AnyFunction ) {
72
+ if ( typeof func !== "function" ) {
73
+ return "" ;
74
+ }
75
+ else if ( func . hasOwnProperty ( "name" ) ) {
76
+ return ( < any > func ) . name ;
77
+ }
78
+ else {
79
+ const text = Function . prototype . toString . call ( func ) ;
80
+ const match = / ^ f u n c t i o n \s + ( [ \w \$ ] + ) \s * \( / . exec ( text ) ;
81
+ return match ? match [ 1 ] : "" ;
82
+ }
83
+ }
84
+
85
+ export function formatSymbol ( symbol : Symbol ) : string {
86
+ return `{ name: ${ unescapeLeadingUnderscores ( symbol . escapedName ) } ; flags: ${ formatSymbolFlags ( symbol . flags ) } ; declarations: ${ map ( symbol . declarations , node => formatSyntaxKind ( node . kind ) ) } }` ;
87
+ }
88
+
89
+ /**
90
+ * Formats an enum value as a string for debugging and debug assertions.
91
+ */
92
+ export function formatEnum ( value = 0 , enumObject : any , isFlags ?: boolean ) {
93
+ const members = getEnumMembers ( enumObject ) ;
94
+ if ( value === 0 ) {
95
+ return members . length > 0 && members [ 0 ] [ 0 ] === 0 ? members [ 0 ] [ 1 ] : "0" ;
96
+ }
97
+ if ( isFlags ) {
98
+ let result = "" ;
99
+ let remainingFlags = value ;
100
+ for ( let i = members . length - 1 ; i >= 0 && remainingFlags !== 0 ; i -- ) {
101
+ const [ enumValue , enumName ] = members [ i ] ;
102
+ if ( enumValue !== 0 && ( remainingFlags & enumValue ) === enumValue ) {
103
+ remainingFlags &= ~ enumValue ;
104
+ result = `${ enumName } ${ result ? "|" : "" } ${ result } ` ;
105
+ }
106
+ }
107
+ if ( remainingFlags === 0 ) {
108
+ return result ;
109
+ }
110
+ }
111
+ else {
112
+ for ( const [ enumValue , enumName ] of members ) {
113
+ if ( enumValue === value ) {
114
+ return enumName ;
115
+ }
116
+ }
117
+ }
118
+ return value . toString ( ) ;
119
+ }
120
+
121
+ function getEnumMembers ( enumObject : any ) {
122
+ const result : [ number , string ] [ ] = [ ] ;
123
+ for ( const name in enumObject ) {
124
+ const value = enumObject [ name ] ;
125
+ if ( typeof value === "number" ) {
126
+ result . push ( [ value , name ] ) ;
127
+ }
128
+ }
129
+
130
+ return stableSort < [ number , string ] > ( result , ( x , y ) => compareValues ( x [ 0 ] , y [ 0 ] ) ) ;
131
+ }
132
+
133
+ export function formatSyntaxKind ( kind : SyntaxKind | undefined ) : string {
134
+ return formatEnum ( kind , ( < any > ts ) . SyntaxKind , /*isFlags*/ false ) ;
135
+ }
136
+
137
+ export function formatNodeFlags ( flags : NodeFlags | undefined ) : string {
138
+ return formatEnum ( flags , ( < any > ts ) . NodeFlags , /*isFlags*/ true ) ;
139
+ }
140
+
141
+ export function formatModifierFlags ( flags : ModifierFlags | undefined ) : string {
142
+ return formatEnum ( flags , ( < any > ts ) . ModifierFlags , /*isFlags*/ true ) ;
143
+ }
144
+
145
+ export function formatTransformFlags ( flags : TransformFlags | undefined ) : string {
146
+ return formatEnum ( flags , ( < any > ts ) . TransformFlags , /*isFlags*/ true ) ;
147
+ }
148
+
149
+ export function formatEmitFlags ( flags : EmitFlags | undefined ) : string {
150
+ return formatEnum ( flags , ( < any > ts ) . EmitFlags , /*isFlags*/ true ) ;
151
+ }
152
+
153
+ export function formatSymbolFlags ( flags : SymbolFlags | undefined ) : string {
154
+ return formatEnum ( flags , ( < any > ts ) . SymbolFlags , /*isFlags*/ true ) ;
155
+ }
156
+
157
+ export function formatTypeFlags ( flags : TypeFlags | undefined ) : string {
158
+ return formatEnum ( flags , ( < any > ts ) . TypeFlags , /*isFlags*/ true ) ;
159
+ }
160
+
161
+ export function formatObjectFlags ( flags : ObjectFlags | undefined ) : string {
162
+ return formatEnum ( flags , ( < any > ts ) . ObjectFlags , /*isFlags*/ true ) ;
163
+ }
164
+
165
+ export function failBadSyntaxKind ( node : Node , message ?: string ) : never {
166
+ return fail (
167
+ `${ message || "Unexpected node." } \r\nNode ${ formatSyntaxKind ( node . kind ) } was unexpected.` ,
168
+ failBadSyntaxKind ) ;
169
+ }
170
+
171
+ export const assertEachNode = shouldAssert ( AssertionLevel . Normal )
172
+ ? ( nodes : Node [ ] , test : ( node : Node ) => boolean , message ?: string ) : void => assert (
173
+ test === undefined || every ( nodes , test ) ,
174
+ message || "Unexpected node." ,
175
+ ( ) => `Node array did not pass test '${ getFunctionName ( test ) } '.` ,
176
+ assertEachNode )
177
+ : noop ;
178
+
179
+ export const assertNode = shouldAssert ( AssertionLevel . Normal )
180
+ ? ( node : Node | undefined , test : ( ( node : Node | undefined ) => boolean ) | undefined , message ?: string ) : void => assert (
181
+ test === undefined || test ( node ) ,
182
+ message || "Unexpected node." ,
183
+ ( ) => `Node ${ formatSyntaxKind ( node ! . kind ) } did not pass test '${ getFunctionName ( test ! ) } '.` ,
184
+ assertNode )
185
+ : noop ;
186
+
187
+ export const assertOptionalNode = shouldAssert ( AssertionLevel . Normal )
188
+ ? ( node : Node , test : ( node : Node ) => boolean , message ?: string ) : void => assert (
189
+ test === undefined || node === undefined || test ( node ) ,
190
+ message || "Unexpected node." ,
191
+ ( ) => `Node ${ formatSyntaxKind ( node . kind ) } did not pass test '${ getFunctionName ( test ) } '.` ,
192
+ assertOptionalNode )
193
+ : noop ;
194
+
195
+ export const assertOptionalToken = shouldAssert ( AssertionLevel . Normal )
196
+ ? ( node : Node , kind : SyntaxKind , message ?: string ) : void => assert (
197
+ kind === undefined || node === undefined || node . kind === kind ,
198
+ message || "Unexpected node." ,
199
+ ( ) => `Node ${ formatSyntaxKind ( node . kind ) } was not a '${ formatSyntaxKind ( kind ) } ' token.` ,
200
+ assertOptionalToken )
201
+ : noop ;
202
+
203
+ export const assertMissingNode = shouldAssert ( AssertionLevel . Normal )
204
+ ? ( node : Node , message ?: string ) : void => assert (
205
+ node === undefined ,
206
+ message || "Unexpected node." ,
207
+ ( ) => `Node ${ formatSyntaxKind ( node . kind ) } was unexpected'.` ,
208
+ assertMissingNode )
209
+ : noop ;
210
+
211
+ let isDebugInfoEnabled = false ;
212
+
213
+ /**
214
+ * Injects debug information into frequently used types.
215
+ */
216
+ export function enableDebugInfo ( ) {
217
+ if ( isDebugInfoEnabled ) return ;
218
+
219
+ // Add additional properties in debug mode to assist with debugging.
220
+ Object . defineProperties ( objectAllocator . getSymbolConstructor ( ) . prototype , {
221
+ __debugFlags : { get ( this : Symbol ) { return formatSymbolFlags ( this . flags ) ; } }
222
+ } ) ;
223
+
224
+ Object . defineProperties ( objectAllocator . getTypeConstructor ( ) . prototype , {
225
+ __debugFlags : { get ( this : Type ) { return formatTypeFlags ( this . flags ) ; } } ,
226
+ __debugObjectFlags : { get ( this : Type ) { return this . flags & TypeFlags . Object ? formatObjectFlags ( ( < ObjectType > this ) . objectFlags ) : "" ; } } ,
227
+ __debugTypeToString : { value ( this : Type ) { return this . checker . typeToString ( this ) ; } } ,
228
+ } ) ;
229
+
230
+ const nodeConstructors = [
231
+ objectAllocator . getNodeConstructor ( ) ,
232
+ objectAllocator . getIdentifierConstructor ( ) ,
233
+ objectAllocator . getTokenConstructor ( ) ,
234
+ objectAllocator . getSourceFileConstructor ( )
235
+ ] ;
236
+
237
+ for ( const ctor of nodeConstructors ) {
238
+ if ( ! ctor . prototype . hasOwnProperty ( "__debugKind" ) ) {
239
+ Object . defineProperties ( ctor . prototype , {
240
+ __debugKind : { get ( this : Node ) { return formatSyntaxKind ( this . kind ) ; } } ,
241
+ __debugNodeFlags : { get ( this : Node ) { return formatNodeFlags ( this . flags ) ; } } ,
242
+ __debugModifierFlags : { get ( this : Node ) { return formatModifierFlags ( getModifierFlagsNoCache ( this ) ) ; } } ,
243
+ __debugTransformFlags : { get ( this : Node ) { return formatTransformFlags ( this . transformFlags ) ; } } ,
244
+ __debugIsParseTreeNode : { get ( this : Node ) { return isParseTreeNode ( this ) ; } } ,
245
+ __debugEmitFlags : { get ( this : Node ) { return formatEmitFlags ( getEmitFlags ( this ) ) ; } } ,
246
+ __debugGetText : {
247
+ value ( this : Node , includeTrivia ?: boolean ) {
248
+ if ( nodeIsSynthesized ( this ) ) return "" ;
249
+ const parseNode = getParseTreeNode ( this ) ;
250
+ const sourceFile = parseNode && getSourceFileOfNode ( parseNode ) ;
251
+ return sourceFile ? getSourceTextOfNodeFromSourceFile ( sourceFile , parseNode , includeTrivia ) : "" ;
252
+ }
253
+ }
254
+ } ) ;
255
+ }
256
+ }
257
+
258
+ isDebugInfoEnabled = true ;
259
+ }
260
+ }
261
+ }
0 commit comments