1
+ /* @internal */
2
+ namespace ts {
3
+ export namespace Debug {
4
+ export function formatSymbol ( symbol : Symbol ) : string {
5
+ return `{ name: ${ unescapeLeadingUnderscores ( symbol . escapedName ) } ; flags: ${ formatSymbolFlags ( symbol . flags ) } ; declarations: ${ map ( symbol . declarations , node => formatSyntaxKind ( node . kind ) ) } }` ;
6
+ }
7
+
8
+ /**
9
+ * Formats an enum value as a string for debugging and debug assertions.
10
+ */
11
+ export function formatEnum ( value = 0 , enumObject : any , isFlags ?: boolean ) {
12
+ const members = getEnumMembers ( enumObject ) ;
13
+ if ( value === 0 ) {
14
+ return members . length > 0 && members [ 0 ] [ 0 ] === 0 ? members [ 0 ] [ 1 ] : "0" ;
15
+ }
16
+ if ( isFlags ) {
17
+ let result = "" ;
18
+ let remainingFlags = value ;
19
+ for ( let i = members . length - 1 ; i >= 0 && remainingFlags !== 0 ; i -- ) {
20
+ const [ enumValue , enumName ] = members [ i ] ;
21
+ if ( enumValue !== 0 && ( remainingFlags & enumValue ) === enumValue ) {
22
+ remainingFlags &= ~ enumValue ;
23
+ result = `${ enumName } ${ result ? "|" : "" } ${ result } ` ;
24
+ }
25
+ }
26
+ if ( remainingFlags === 0 ) {
27
+ return result ;
28
+ }
29
+ }
30
+ else {
31
+ for ( const [ enumValue , enumName ] of members ) {
32
+ if ( enumValue === value ) {
33
+ return enumName ;
34
+ }
35
+ }
36
+ }
37
+ return value . toString ( ) ;
38
+ }
39
+
40
+ function getEnumMembers ( enumObject : any ) {
41
+ const result : [ number , string ] [ ] = [ ] ;
42
+ for ( const name in enumObject ) {
43
+ const value = enumObject [ name ] ;
44
+ if ( typeof value === "number" ) {
45
+ result . push ( [ value , name ] ) ;
46
+ }
47
+ }
48
+
49
+ return stableSort < [ number , string ] > ( result , ( x , y ) => compareValues ( x [ 0 ] , y [ 0 ] ) ) ;
50
+ }
51
+
52
+ export function formatSyntaxKind ( kind : SyntaxKind | undefined ) : string {
53
+ return formatEnum ( kind , ( < any > ts ) . SyntaxKind , /*isFlags*/ false ) ;
54
+ }
55
+
56
+ export function formatNodeFlags ( flags : NodeFlags | undefined ) : string {
57
+ return formatEnum ( flags , ( < any > ts ) . NodeFlags , /*isFlags*/ true ) ;
58
+ }
59
+
60
+ export function formatModifierFlags ( flags : ModifierFlags | undefined ) : string {
61
+ return formatEnum ( flags , ( < any > ts ) . ModifierFlags , /*isFlags*/ true ) ;
62
+ }
63
+
64
+ export function formatTransformFlags ( flags : TransformFlags | undefined ) : string {
65
+ return formatEnum ( flags , ( < any > ts ) . TransformFlags , /*isFlags*/ true ) ;
66
+ }
67
+
68
+ export function formatEmitFlags ( flags : EmitFlags | undefined ) : string {
69
+ return formatEnum ( flags , ( < any > ts ) . EmitFlags , /*isFlags*/ true ) ;
70
+ }
71
+
72
+ export function formatSymbolFlags ( flags : SymbolFlags | undefined ) : string {
73
+ return formatEnum ( flags , ( < any > ts ) . SymbolFlags , /*isFlags*/ true ) ;
74
+ }
75
+
76
+ export function formatTypeFlags ( flags : TypeFlags | undefined ) : string {
77
+ return formatEnum ( flags , ( < any > ts ) . TypeFlags , /*isFlags*/ true ) ;
78
+ }
79
+
80
+ export function formatObjectFlags ( flags : ObjectFlags | undefined ) : string {
81
+ return formatEnum ( flags , ( < any > ts ) . ObjectFlags , /*isFlags*/ true ) ;
82
+ }
83
+
84
+ export function failBadSyntaxKind ( node : Node , message ?: string ) : never {
85
+ return fail (
86
+ `${ message || "Unexpected node." } \r\nNode ${ formatSyntaxKind ( node . kind ) } was unexpected.` ,
87
+ failBadSyntaxKind ) ;
88
+ }
89
+
90
+ export const assertEachNode = shouldAssert ( AssertionLevel . Normal )
91
+ ? ( nodes : Node [ ] , test : ( node : Node ) => boolean , message ?: string ) : void => assert (
92
+ test === undefined || every ( nodes , test ) ,
93
+ message || "Unexpected node." ,
94
+ ( ) => `Node array did not pass test '${ getFunctionName ( test ) } '.` ,
95
+ assertEachNode )
96
+ : noop ;
97
+
98
+ export const assertNode = shouldAssert ( AssertionLevel . Normal )
99
+ ? ( node : Node | undefined , test : ( ( node : Node | undefined ) => boolean ) | undefined , message ?: string ) : void => assert (
100
+ test === undefined || test ( node ) ,
101
+ message || "Unexpected node." ,
102
+ ( ) => `Node ${ formatSyntaxKind ( node ! . kind ) } did not pass test '${ getFunctionName ( test ! ) } '.` ,
103
+ assertNode )
104
+ : noop ;
105
+
106
+ export const assertOptionalNode = shouldAssert ( AssertionLevel . Normal )
107
+ ? ( node : Node , test : ( node : Node ) => boolean , message ?: string ) : void => assert (
108
+ test === undefined || node === undefined || test ( node ) ,
109
+ message || "Unexpected node." ,
110
+ ( ) => `Node ${ formatSyntaxKind ( node . kind ) } did not pass test '${ getFunctionName ( test ) } '.` ,
111
+ assertOptionalNode )
112
+ : noop ;
113
+
114
+ export const assertOptionalToken = shouldAssert ( AssertionLevel . Normal )
115
+ ? ( node : Node , kind : SyntaxKind , message ?: string ) : void => assert (
116
+ kind === undefined || node === undefined || node . kind === kind ,
117
+ message || "Unexpected node." ,
118
+ ( ) => `Node ${ formatSyntaxKind ( node . kind ) } was not a '${ formatSyntaxKind ( kind ) } ' token.` ,
119
+ assertOptionalToken )
120
+ : noop ;
121
+
122
+ export const assertMissingNode = shouldAssert ( AssertionLevel . Normal )
123
+ ? ( node : Node , message ?: string ) : void => assert (
124
+ node === undefined ,
125
+ message || "Unexpected node." ,
126
+ ( ) => `Node ${ formatSyntaxKind ( node . kind ) } was unexpected'.` ,
127
+ assertMissingNode )
128
+ : noop ;
129
+
130
+ let isDebugInfoEnabled = false ;
131
+
132
+ /**
133
+ * Injects debug information into frequently used types.
134
+ */
135
+ export function enableDebugInfo ( ) {
136
+ if ( isDebugInfoEnabled ) return ;
137
+
138
+ // Add additional properties in debug mode to assist with debugging.
139
+ Object . defineProperties ( objectAllocator . getSymbolConstructor ( ) . prototype , {
140
+ __debugFlags : { get ( this : Symbol ) { return formatSymbolFlags ( this . flags ) ; } }
141
+ } ) ;
142
+
143
+ Object . defineProperties ( objectAllocator . getTypeConstructor ( ) . prototype , {
144
+ __debugFlags : { get ( this : Type ) { return formatTypeFlags ( this . flags ) ; } } ,
145
+ __debugObjectFlags : { get ( this : Type ) { return this . flags & TypeFlags . Object ? formatObjectFlags ( ( < ObjectType > this ) . objectFlags ) : "" ; } } ,
146
+ __debugTypeToString : { value ( this : Type ) { return this . checker . typeToString ( this ) ; } } ,
147
+ } ) ;
148
+
149
+ const nodeConstructors = [
150
+ objectAllocator . getNodeConstructor ( ) ,
151
+ objectAllocator . getIdentifierConstructor ( ) ,
152
+ objectAllocator . getTokenConstructor ( ) ,
153
+ objectAllocator . getSourceFileConstructor ( )
154
+ ] ;
155
+
156
+ for ( const ctor of nodeConstructors ) {
157
+ if ( ! ctor . prototype . hasOwnProperty ( "__debugKind" ) ) {
158
+ Object . defineProperties ( ctor . prototype , {
159
+ __debugKind : { get ( this : Node ) { return formatSyntaxKind ( this . kind ) ; } } ,
160
+ __debugNodeFlags : { get ( this : Node ) { return formatNodeFlags ( this . flags ) ; } } ,
161
+ __debugModifierFlags : { get ( this : Node ) { return formatModifierFlags ( getModifierFlagsNoCache ( this ) ) ; } } ,
162
+ __debugTransformFlags : { get ( this : Node ) { return formatTransformFlags ( this . transformFlags ) ; } } ,
163
+ __debugIsParseTreeNode : { get ( this : Node ) { return isParseTreeNode ( this ) ; } } ,
164
+ __debugEmitFlags : { get ( this : Node ) { return formatEmitFlags ( getEmitFlags ( this ) ) ; } } ,
165
+ __debugGetText : {
166
+ value ( this : Node , includeTrivia ?: boolean ) {
167
+ if ( nodeIsSynthesized ( this ) ) return "" ;
168
+ const parseNode = getParseTreeNode ( this ) ;
169
+ const sourceFile = parseNode && getSourceFileOfNode ( parseNode ) ;
170
+ return sourceFile ? getSourceTextOfNodeFromSourceFile ( sourceFile , parseNode , includeTrivia ) : "" ;
171
+ }
172
+ }
173
+ } ) ;
174
+ }
175
+ }
176
+
177
+ isDebugInfoEnabled = true ;
178
+ }
179
+ }
180
+ }
0 commit comments