@@ -371,6 +371,10 @@ namespace ts {
371371 return formatEnum ( flags , ( < any > ts ) . ObjectFlags , /*isFlags*/ true ) ;
372372 }
373373
374+ export function formatFlowFlags ( flags : FlowFlags | undefined ) : string {
375+ return formatEnum ( flags , ( < any > ts ) . FlowFlags , /*isFlags*/ true ) ;
376+ }
377+
374378 let isDebugInfoEnabled = false ;
375379
376380 interface ExtendedDebugModule {
@@ -396,13 +400,87 @@ namespace ts {
396400 return extendedDebug ( ) . formatControlFlowGraph ( flowNode ) ;
397401 }
398402
399- export function attachFlowNodeDebugInfo ( flowNode : FlowNode ) {
403+ let flowNodeProto : FlowNodeBase | undefined ;
404+
405+ function attachFlowNodeDebugInfoWorker ( flowNode : FlowNodeBase ) {
406+ if ( ! ( "__debugFlowFlags" in flowNode ) ) { // eslint-disable-line no-in-operator
407+ Object . defineProperties ( flowNode , {
408+ // for use with vscode-js-debug's new customDescriptionGenerator in launch.json
409+ __tsDebuggerDisplay : {
410+ value ( this : FlowNodeBase ) {
411+ const flowHeader =
412+ this . flags & FlowFlags . Start ? "FlowStart" :
413+ this . flags & FlowFlags . BranchLabel ? "FlowBranchLabel" :
414+ this . flags & FlowFlags . LoopLabel ? "FlowLoopLabel" :
415+ this . flags & FlowFlags . Assignment ? "FlowAssignment" :
416+ this . flags & FlowFlags . TrueCondition ? "FlowTrueCondition" :
417+ this . flags & FlowFlags . FalseCondition ? "FlowFalseCondition" :
418+ this . flags & FlowFlags . SwitchClause ? "FlowSwitchClause" :
419+ this . flags & FlowFlags . ArrayMutation ? "FlowArrayMutation" :
420+ this . flags & FlowFlags . Call ? "FlowCall" :
421+ this . flags & FlowFlags . ReduceLabel ? "FlowReduceLabel" :
422+ this . flags & FlowFlags . Unreachable ? "FlowUnreachable" :
423+ "UnknownFlow" ;
424+ const remainingFlags = this . flags & ~ ( FlowFlags . Referenced - 1 ) ;
425+ return `${ flowHeader } ${ remainingFlags ? ` (${ formatFlowFlags ( remainingFlags ) } )` : "" } ` ;
426+ }
427+ } ,
428+ __debugFlowFlags : { get ( this : FlowNodeBase ) { return formatEnum ( this . flags , ( ts as any ) . FlowFlags , /*isFlags*/ true ) ; } } ,
429+ __debugToString : { value ( this : FlowNodeBase ) { return formatControlFlowGraph ( this ) ; } }
430+ } ) ;
431+ }
432+ }
433+
434+ export function attachFlowNodeDebugInfo ( flowNode : FlowNodeBase ) {
400435 if ( isDebugInfoEnabled ) {
401- if ( ! ( "__debugFlowFlags" in flowNode ) ) { // eslint-disable-line no-in-operator
402- Object . defineProperties ( flowNode , {
403- __debugFlowFlags : { get ( this : FlowNode ) { return formatEnum ( this . flags , ( ts as any ) . FlowFlags , /*isFlags*/ true ) ; } } ,
404- __debugToString : { value ( this : FlowNode ) { return formatControlFlowGraph ( this ) ; } }
405- } ) ;
436+ if ( typeof Object . setPrototypeOf === "function" ) {
437+ // if we're in es2015, attach the method to a shared prototype for `FlowNode`
438+ // so the method doesn't show up in the watch window.
439+ if ( ! flowNodeProto ) {
440+ flowNodeProto = Object . create ( Object . prototype ) as FlowNodeBase ;
441+ attachFlowNodeDebugInfoWorker ( flowNodeProto ) ;
442+ }
443+ Object . setPrototypeOf ( flowNode , flowNodeProto ) ;
444+ }
445+ else {
446+ // not running in an es2015 environment, attach the method directly.
447+ attachFlowNodeDebugInfoWorker ( flowNode ) ;
448+ }
449+ }
450+ }
451+
452+ let nodeArrayProto : NodeArray < Node > | undefined ;
453+
454+ function attachNodeArrayDebugInfoWorker ( array : NodeArray < Node > ) {
455+ if ( ! ( "__tsDebuggerDisplay" in array ) ) { // eslint-disable-line no-in-operator
456+ Object . defineProperties ( array , {
457+ __tsDebuggerDisplay : {
458+ value ( this : NodeArray < Node > , defaultValue : string ) {
459+ // An `Array` with extra properties is rendered as `[A, B, prop1: 1, prop2: 2]`. Most of
460+ // these aren't immediately useful so we trim off the `prop1: ..., prop2: ...` part from the
461+ // formatted string.
462+ defaultValue = String ( defaultValue ) . replace ( / (?: , [ \s \w \d _ ] + : [ ^ , ] + ) + \] $ / , "]" ) ;
463+ return `NodeArray ${ defaultValue } ` ;
464+ }
465+ }
466+ } ) ;
467+ }
468+ }
469+
470+ export function attachNodeArrayDebugInfo ( array : NodeArray < Node > ) {
471+ if ( isDebugInfoEnabled ) {
472+ if ( typeof Object . setPrototypeOf === "function" ) {
473+ // if we're in es2015, attach the method to a shared prototype for `NodeArray`
474+ // so the method doesn't show up in the watch window.
475+ if ( ! nodeArrayProto ) {
476+ nodeArrayProto = Object . create ( Array . prototype ) as NodeArray < Node > ;
477+ attachNodeArrayDebugInfoWorker ( nodeArrayProto ) ;
478+ }
479+ Object . setPrototypeOf ( array , nodeArrayProto ) ;
480+ }
481+ else {
482+ // not running in an es2015 environment, attach the method directly.
483+ attachNodeArrayDebugInfoWorker ( array ) ;
406484 }
407485 }
408486 }
@@ -434,10 +512,51 @@ namespace ts {
434512
435513 // Add additional properties in debug mode to assist with debugging.
436514 Object . defineProperties ( objectAllocator . getSymbolConstructor ( ) . prototype , {
515+ // for use with vscode-js-debug's new customDescriptionGenerator in launch.json
516+ __tsDebuggerDisplay : {
517+ value ( this : Symbol ) {
518+ const symbolHeader =
519+ this . flags & SymbolFlags . Transient ? "TransientSymbol" :
520+ "Symbol" ;
521+ const remainingSymbolFlags = this . flags & ~ SymbolFlags . Transient ;
522+ return `${ symbolHeader } '${ symbolName ( this ) } '${ remainingSymbolFlags ? ` (${ formatSymbolFlags ( remainingSymbolFlags ) } )` : "" } ` ;
523+ }
524+ } ,
437525 __debugFlags : { get ( this : Symbol ) { return formatSymbolFlags ( this . flags ) ; } }
438526 } ) ;
439527
440528 Object . defineProperties ( objectAllocator . getTypeConstructor ( ) . prototype , {
529+ // for use with vscode-js-debug's new customDescriptionGenerator in launch.json
530+ __tsDebuggerDisplay : {
531+ value ( this : Type ) {
532+ const typeHeader =
533+ this . flags & TypeFlags . Nullable ? "NullableType" :
534+ this . flags & TypeFlags . StringOrNumberLiteral ? `LiteralType ${ JSON . stringify ( ( this as LiteralType ) . value ) } ` :
535+ this . flags & TypeFlags . BigIntLiteral ? `LiteralType ${ ( this as BigIntLiteralType ) . value . negative ? "-" : "" } ${ ( this as BigIntLiteralType ) . value . base10Value } n` :
536+ this . flags & TypeFlags . UniqueESSymbol ? "UniqueESSymbolType" :
537+ this . flags & TypeFlags . Enum ? "EnumType" :
538+ this . flags & TypeFlags . Intrinsic ? `IntrinsicType ${ ( this as IntrinsicType ) . intrinsicName } ` :
539+ this . flags & TypeFlags . Union ? "UnionType" :
540+ this . flags & TypeFlags . Intersection ? "IntersectionType" :
541+ this . flags & TypeFlags . Index ? "IndexType" :
542+ this . flags & TypeFlags . IndexedAccess ? "IndexedAccessType" :
543+ this . flags & TypeFlags . Conditional ? "ConditionalType" :
544+ this . flags & TypeFlags . Substitution ? "SubstitutionType" :
545+ this . flags & TypeFlags . TypeParameter ? "TypeParameter" :
546+ this . flags & TypeFlags . Object ?
547+ ( this as ObjectType ) . objectFlags & ObjectFlags . ClassOrInterface ? "InterfaceType" :
548+ ( this as ObjectType ) . objectFlags & ObjectFlags . Reference ? "TypeReference" :
549+ ( this as ObjectType ) . objectFlags & ObjectFlags . Tuple ? "TupleType" :
550+ ( this as ObjectType ) . objectFlags & ObjectFlags . Anonymous ? "AnonymousType" :
551+ ( this as ObjectType ) . objectFlags & ObjectFlags . Mapped ? "MappedType" :
552+ ( this as ObjectType ) . objectFlags & ObjectFlags . ReverseMapped ? "ReverseMappedType" :
553+ ( this as ObjectType ) . objectFlags & ObjectFlags . EvolvingArray ? "EvolvingArrayType" :
554+ "ObjectType" :
555+ "Type" ;
556+ const remainingObjectFlags = this . flags & TypeFlags . Object ? ( this as ObjectType ) . objectFlags & ~ ObjectFlags . ObjectTypeKindMask : 0 ;
557+ return `${ typeHeader } ${ this . symbol ? ` '${ symbolName ( this . symbol ) } '` : "" } ${ remainingObjectFlags ? ` (${ formatObjectFlags ( remainingObjectFlags ) } )` : "" } ` ;
558+ }
559+ } ,
441560 __debugFlags : { get ( this : Type ) { return formatTypeFlags ( this . flags ) ; } } ,
442561 __debugObjectFlags : { get ( this : Type ) { return this . flags & TypeFlags . Object ? formatObjectFlags ( ( < ObjectType > this ) . objectFlags ) : "" ; } } ,
443562 __debugTypeToString : {
@@ -464,6 +583,50 @@ namespace ts {
464583 for ( const ctor of nodeConstructors ) {
465584 if ( ! ctor . prototype . hasOwnProperty ( "__debugKind" ) ) {
466585 Object . defineProperties ( ctor . prototype , {
586+ // for use with vscode-js-debug's new customDescriptionGenerator in launch.json
587+ __tsDebuggerDisplay : {
588+ value ( this : Node ) {
589+ const nodeHeader =
590+ isGeneratedIdentifier ( this ) ? "GeneratedIdentifier" :
591+ isIdentifier ( this ) ? `Identifier '${ idText ( this ) } '` :
592+ isPrivateIdentifier ( this ) ? `PrivateIdentifier '${ idText ( this ) } '` :
593+ isStringLiteral ( this ) ? `StringLiteral ${ JSON . stringify ( this . text . length < 10 ? this . text : this . text . slice ( 10 ) + "..." ) } ` :
594+ isNumericLiteral ( this ) ? `NumericLiteral ${ this . text } ` :
595+ isBigIntLiteral ( this ) ? `BigIntLiteral ${ this . text } n` :
596+ isTypeParameterDeclaration ( this ) ? "TypeParameterDeclaration" :
597+ isParameter ( this ) ? "ParameterDeclaration" :
598+ isConstructorDeclaration ( this ) ? "ConstructorDeclaration" :
599+ isGetAccessorDeclaration ( this ) ? "GetAccessorDeclaration" :
600+ isSetAccessorDeclaration ( this ) ? "SetAccessorDeclaration" :
601+ isCallSignatureDeclaration ( this ) ? "CallSignatureDeclaration" :
602+ isConstructSignatureDeclaration ( this ) ? "ConstructSignatureDeclaration" :
603+ isIndexSignatureDeclaration ( this ) ? "IndexSignatureDeclaration" :
604+ isTypePredicateNode ( this ) ? "TypePredicateNode" :
605+ isTypeReferenceNode ( this ) ? "TypeReferenceNode" :
606+ isFunctionTypeNode ( this ) ? "FunctionTypeNode" :
607+ isConstructorTypeNode ( this ) ? "ConstructorTypeNode" :
608+ isTypeQueryNode ( this ) ? "TypeQueryNode" :
609+ isTypeLiteralNode ( this ) ? "TypeLiteralNode" :
610+ isArrayTypeNode ( this ) ? "ArrayTypeNode" :
611+ isTupleTypeNode ( this ) ? "TupleTypeNode" :
612+ isOptionalTypeNode ( this ) ? "OptionalTypeNode" :
613+ isRestTypeNode ( this ) ? "RestTypeNode" :
614+ isUnionTypeNode ( this ) ? "UnionTypeNode" :
615+ isIntersectionTypeNode ( this ) ? "IntersectionTypeNode" :
616+ isConditionalTypeNode ( this ) ? "ConditionalTypeNode" :
617+ isInferTypeNode ( this ) ? "InferTypeNode" :
618+ isParenthesizedTypeNode ( this ) ? "ParenthesizedTypeNode" :
619+ isThisTypeNode ( this ) ? "ThisTypeNode" :
620+ isTypeOperatorNode ( this ) ? "TypeOperatorNode" :
621+ isIndexedAccessTypeNode ( this ) ? "IndexedAccessTypeNode" :
622+ isMappedTypeNode ( this ) ? "MappedTypeNode" :
623+ isLiteralTypeNode ( this ) ? "LiteralTypeNode" :
624+ isNamedTupleMember ( this ) ? "NamedTupleMember" :
625+ isImportTypeNode ( this ) ? "ImportTypeNode" :
626+ formatSyntaxKind ( this . kind ) ;
627+ return `${ nodeHeader } ${ this . flags ? ` (${ formatNodeFlags ( this . flags ) } )` : "" } ` ;
628+ }
629+ } ,
467630 __debugKind : { get ( this : Node ) { return formatSyntaxKind ( this . kind ) ; } } ,
468631 __debugNodeFlags : { get ( this : Node ) { return formatNodeFlags ( this . flags ) ; } } ,
469632 __debugModifierFlags : { get ( this : Node ) { return formatModifierFlags ( getEffectiveModifierFlagsNoCache ( this ) ) ; } } ,
0 commit comments