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