@@ -301,19 +301,19 @@ namespace ts {
301
301
return members . length > 0 && members [ 0 ] [ 0 ] === 0 ? members [ 0 ] [ 1 ] : "0" ;
302
302
}
303
303
if ( isFlags ) {
304
- let result = "" ;
304
+ const result : string [ ] = [ ] ;
305
305
let remainingFlags = value ;
306
306
for ( const [ enumValue , enumName ] of members ) {
307
307
if ( enumValue > value ) {
308
308
break ;
309
309
}
310
310
if ( enumValue !== 0 && enumValue & value ) {
311
- result = ` ${ result } ${ result ? "|" : "" } ${ enumName } ` ;
311
+ result . push ( enumName ) ;
312
312
remainingFlags &= ~ enumValue ;
313
313
}
314
314
}
315
315
if ( remainingFlags === 0 ) {
316
- return result ;
316
+ return result . join ( "|" ) ;
317
317
}
318
318
}
319
319
else {
@@ -326,7 +326,17 @@ namespace ts {
326
326
return value . toString ( ) ;
327
327
}
328
328
329
+ const enumMemberCache = new Map < any , SortedReadonlyArray < [ number , string ] > > ( ) ;
330
+
329
331
function getEnumMembers ( enumObject : any ) {
332
+ // Assuming enum objects do not change at runtime, we can cache the enum members list
333
+ // to reuse later. This saves us from reconstructing this each and every time we call
334
+ // a formatting function (which can be expensive for large enums like SyntaxKind).
335
+ const existing = enumMemberCache . get ( enumObject ) ;
336
+ if ( existing ) {
337
+ return existing ;
338
+ }
339
+
330
340
const result : [ number , string ] [ ] = [ ] ;
331
341
for ( const name in enumObject ) {
332
342
const value = enumObject [ name ] ;
@@ -335,7 +345,9 @@ namespace ts {
335
345
}
336
346
}
337
347
338
- return stableSort < [ number , string ] > ( result , ( x , y ) => compareValues ( x [ 0 ] , y [ 0 ] ) ) ;
348
+ const sorted = stableSort < [ number , string ] > ( result , ( x , y ) => compareValues ( x [ 0 ] , y [ 0 ] ) ) ;
349
+ enumMemberCache . set ( enumObject , sorted ) ;
350
+ return sorted ;
339
351
}
340
352
341
353
export function formatSyntaxKind ( kind : SyntaxKind | undefined ) : string {
0 commit comments