namespace Utils { export function encodeString ( s ) { return ts . sys . bufferFrom ! ( s ) . toString ( "utf8" ) ; } export function byteLength ( s , encoding ? ) { return Buffer . byteLength ( s , encoding as ts . BufferEncoding | undefined ) ; } export function evalFile ( fileContents , fileName , nodeContext ? ) { const vm = require ( "vm" ) ; if ( nodeContext ) { vm . runInNewContext ( fileContents , nodeContext , fileName ) ; } else { vm . runInThisContext ( fileContents , fileName ) ; } } /** Splits the given string on \r\n, or on only \n if that fails, or on only \r if *that* fails. */ export function splitContentByNewlines ( content ) { let lines = content . split ( "\r\n" ) ; if ( lines . length === 1 ) { lines = content . split ( "\n" ) ; if ( lines . length === 1 ) { lines = content . split ( "\r" ) ; } } return lines ; } /** Reads a file under /tests */ export function readTestFile ( path ) { if ( path . indexOf ( "tests" ) < 0 ) { path = "tests/" + path ; } let content ; try { content = Harness . IO . readFile ( Harness . userSpecifiedRoot + path ) ; } catch ( err ) { return undefined ; } return content ; } export function memoize < T extends ts . AnyFunction > ( f , memoKey ) { const cache = new ts . Map < string , any > ( ) ; return ( function ( this , ... args ) { const key = memoKey ( ... args ) ; if ( cache . has ( key ) ) { return cache . get ( key ) ; } else { const value = f . apply ( this , args ) ; cache . set ( key , value ) ; return value ; } } as any ) ; } export const canonicalizeForHarness = ts . createGetCanonicalFileName ( false ) ; export function assertInvariants ( node , parent ) { const queue = [ [ node , parent ] ] ; for ( const [ node , parent ] of queue ) { assertInvariantsWorker ( node , parent ) ; } function assertInvariantsWorker ( node , parent ) { if ( node ) { assert . isFalse ( node . pos < 0 , "node.pos < 0" ) ; assert . isFalse ( node . end < 0 , "node.end < 0" ) ; assert . isFalse ( node . end < node . pos , "node.end < node.pos" ) ; assert . equal ( node . parent , parent , "node.parent !== parent" ) ; if ( parent ) { assert . isFalse ( node . pos < parent . pos , "node.pos < parent.pos" ) ; assert . isFalse ( node . end > parent . end , "node.end > parent.end" ) ; } ts . forEachChild ( node , child => { queue . push ( [ child , node ] ) ; } ) ; let currentPos = 0 ; ts . forEachChild ( node , child => { assert . isFalse ( child . pos < currentPos , "child.pos < currentPos" ) ; currentPos = child . end ; } , array => { assert . isFalse ( array . pos < node . pos , "array.pos < node.pos" ) ; assert . isFalse ( array . end > node . end , "array.end > node.end" ) ; assert . isFalse ( array . pos < currentPos , "array.pos < currentPos" ) ; for ( const item of array ) { assert . isFalse ( item . pos < currentPos , "array[i].pos < currentPos" ) ; currentPos = item . end ; } currentPos = array . end ; } ) ; const childNodesAndArrays = [ ] ; ts . forEachChild ( node , child => { childNodesAndArrays . push ( child ) ; } , array => { childNodesAndArrays . push ( array ) ; } ) ; for ( const childName in node ) { if ( childName === "parent" || childName === "nextContainer" || childName === "modifiers" || childName === "externalModuleIndicator" || childName === "jsDocComment" || childName === "checkJsDirective" || childName === "commonJsModuleIndicator" ) { continue ; } const child = ( node as any ) [ childName ] ; if ( isNodeOrArray ( child ) ) { assert . isFalse ( childNodesAndArrays . indexOf ( child ) < 0 , "Missing child when forEach'ing over node: " + ( ts as any ) . SyntaxKind [ node . kind ] + "-" + childName ) ; } } } } } function isNodeOrArray ( a ) { return a !== undefined && typeof a . pos === "number" ; } export function convertDiagnostics ( diagnostics ) { return diagnostics . map ( convertDiagnostic ) ; } function convertDiagnostic ( diagnostic ) { return { start : diagnostic . start , length : diagnostic . length , messageText : ts . flattenDiagnosticMessageText ( diagnostic . messageText , Harness . IO . newLine ( ) ) , category : ts . diagnosticCategoryName ( diagnostic , false ) , code : diagnostic . code } ; } export function sourceFileToJSON ( file ) { return JSON . stringify ( file , ( _ , v ) => isNodeOrArray ( v ) ? serializeNode ( v ) : v , "    " ) ; function getKindName ( k ) { if ( ts . isString ( k ) ) { return k ; } if ( k === ( ts as any ) . SyntaxKind . FirstJSDocNode || k === ( ts as any ) . SyntaxKind . LastJSDocNode || k === ( ts as any ) . SyntaxKind . FirstJSDocTagNode || k === ( ts as any ) . SyntaxKind . LastJSDocTagNode ) { for ( const kindName in ( ts as any ) . SyntaxKind ) { if ( ( ts as any ) . SyntaxKind [ kindName ] === k ) { return kindName ; } } } return ( ts as any ) . SyntaxKind [ k ] ; } function getFlagName ( flags , f ) { if ( f === 0 ) { return 0 ; } let result = "" ; ts . forEach ( Object . getOwnPropertyNames ( flags ) , ( v ) => { if ( isFinite ( v ) ) { v = + v ; if ( f === + v ) { result = flags [ v ] ; return true ; } else if ( ( f & v ) > 0 ) { if ( result . length ) { result += " | " ; } result += flags [ v ] ; return false ; } } } ) ; return result ; } function getNodeFlagName ( f ) { return getFlagName ( ( ts as any ) . NodeFlags , f ) ; } function serializeNode ( n ) { const o = { kind : getKindName ( n . kind ) } ; if ( ts . containsParseError ( n ) ) { o . containsParseError = true ; } for ( const propertyName of Object . getOwnPropertyNames ( n ) as readonly ( keyof ts . SourceFile | keyof ts . Identifier ) [ ] ) { switch ( propertyName ) { case "parent" : case "symbol" : case "locals" : case "localSymbol" : case "kind" : case "id" : case "nodeCount" : case "symbolCount" : case "identifierCount" : case "scriptSnapshot" : break ; case "originalKeywordKind" : o [ propertyName ] = getKindName ( ( n as any ) [ propertyName ] ) ; break ; case "flags" : const flags = n . flags & ~ ( ts . NodeFlags . JavaScriptFile | ts . NodeFlags . HasAggregatedChildData ) ; if ( flags ) { o [ propertyName ] = getNodeFlagName ( flags ) ; } break ; case "parseDiagnostics" : o [ propertyName ] = convertDiagnostics ( ( n as any ) [ propertyName ] ) ; break ; case "nextContainer" : if ( n . nextContainer ) { o [ propertyName ] = { kind : n . nextContainer . kind , pos : n . nextContainer . pos , end : n . nextContainer . end } ; } break ; case "text" : if ( n . kind !== ts . SyntaxKind . SourceFile ) { o [ propertyName ] = ( n as any ) [ propertyName ] ; } break ; default : o [ propertyName ] = ( n as any ) [ propertyName ] ; } } return o ; } } export function assertDiagnosticsEquals ( array1 , array2 ) { if ( array1 === array2 ) { return ; } assert ( array1 , "array1" ) ; assert ( array2 , "array2" ) ; assert . equal ( array1 . length , array2 . length , "array1.length !== array2.length" ) ; for ( let i = 0 ; i < array1 . length ; i ++ ) { const d1 = array1 [ i ] ; const d2 = array2 [ i ] ; assert . equal ( d1 . start , d2 . start , "d1.start !== d2.start" ) ; assert . equal ( d1 . length , d2 . length , "d1.length !== d2.length" ) ; assert . equal ( ts . flattenDiagnosticMessageText ( d1 . messageText , Harness . IO . newLine ( ) ) , ts . flattenDiagnosticMessageText ( d2 . messageText , Harness . IO . newLine ( ) ) , "d1.messageText !== d2.messageText" ) ; assert . equal ( d1 . category , d2 . category , "d1.category !== d2.category" ) ; assert . equal ( d1 . code , d2 . code , "d1.code !== d2.code" ) ; } } export function assertStructuralEquals ( node1 , node2 ) { if ( node1 === node2 ) { return ; } assert ( node1 , "node1" ) ; assert ( node2 , "node2" ) ; assert . equal ( node1 . pos , node2 . pos , "node1.pos !== node2.pos" ) ; assert . equal ( node1 . end , node2 . end , "node1.end !== node2.end" ) ; assert . equal ( node1 . kind , node2 . kind , "node1.kind !== node2.kind" ) ; assert . equal ( ts . containsParseError ( node1 ) , ts . containsParseError ( node2 ) ) ; assert . equal ( node1 . flags & ~ ts . NodeFlags . ReachabilityAndEmitFlags , node2 . flags & ~ ts . NodeFlags . ReachabilityAndEmitFlags , "node1.flags !== node2.flags" ) ; ts . forEachChild ( node1 , child1 => { const childName = findChildName ( node1 , child1 ) ; const child2 = ( node2 as any ) [ childName ] ; assertStructuralEquals ( child1 , child2 ) ; } , array1 => { const childName = findChildName ( node1 , array1 ) ; const array2 = ( node2 as any ) [ childName ] ; assertArrayStructuralEquals ( array1 , array2 ) ; } ) ; } function assertArrayStructuralEquals ( array1 , array2 ) { if ( array1 === array2 ) { return ; } assert ( array1 , "array1" ) ; assert ( array2 , "array2" ) ; assert . equal ( array1 . pos , array2 . pos , "array1.pos !== array2.pos" ) ; assert . equal ( array1 . end , array2 . end , "array1.end !== array2.end" ) ; assert . equal ( array1 . length , array2 . length , "array1.length !== array2.length" ) ; for ( let i = 0 ; i < array1 . length ; i ++ ) { assertStructuralEquals ( array1 [ i ] , array2 [ i ] ) ; } } function findChildName ( parent , child ) { for ( const name in parent ) { if ( parent . hasOwnProperty ( name ) && parent [ name ] === child ) { return name ; } } throw new Error ( "Could not find child in parent" ) ; } const maxHarnessFrames = 1 ; export function filterStack ( error , stackTraceLimit = Infinity ) { const stack = ( error as any ) . stack as string ; if ( stack ) { const lines = stack . split ( /\r\n?|\n/g ) ; const filtered = [ ] ; let frameCount = 0 ; let harnessFrameCount = 0 ; for ( let line of lines ) { if ( isStackFrame ( line ) ) { if ( frameCount >= stackTraceLimit || isMocha ( line ) || isNode ( line ) ) { continue ; } if ( isHarness ( line ) ) { if ( harnessFrameCount >= maxHarnessFrames ) { continue ; } harnessFrameCount ++ ; } line = line . replace ( /\bfile:\/\/\/(.*?)(?=(:\d+)*($|\)))/ , ( _ , path ) => ts . sys . resolvePath ( path ) ) ; frameCount ++ ; } filtered . push ( line ) ; } ( error as any ) . stack = filtered . join ( Harness . IO . newLine ( ) ) ; } return error ; } function isStackFrame ( line ) { return /^\s+at\s/ . test ( line ) ; } function isMocha ( line ) { return /[\\/](node_modules|components)[\\/]mocha(js)?[\\/]|[\\/]mocha\.js/ . test ( line ) ; } function isNode ( line ) { return /\((timers|events|node|module)\.js:/ . test ( line ) ; } function isHarness ( line ) { return /[\\/]src[\\/]harness[\\/]|[\\/]run\.js/ . test ( line ) ; } }