module ts { export const enum Ternary { False = 0 , Maybe = 1 , True = - 1 } export const enum Comparison { LessThan = - 1 , EqualTo = 0 , GreaterThan = 1 } export interface StringSet extends Map < any > { } export function forEach < T , U > ( array , callback ) { if ( array ) { for ( var i = 0 , len = array . length ; i < len ; i ++ ) { var result = callback ( array [ i ] ) ; if ( result ) { return result ; } } } return undefined ; } export function contains < T > ( array , value ) { if ( array ) { for ( var i = 0 , len = array . length ; i < len ; i ++ ) { if ( array [ i ] === value ) { return true ; } } } return false ; } export function indexOf < T > ( array , value ) { if ( array ) { for ( var i = 0 , len = array . length ; i < len ; i ++ ) { if ( array [ i ] === value ) { return i ; } } } return - 1 ; } export function countWhere < T > ( array , predicate ) { var count = 0 ; if ( array ) { for ( var i = 0 , len = array . length ; i < len ; i ++ ) { if ( predicate ( array [ i ] ) ) { count ++ ; } } } return count ; } export function filter < T > ( array , f ) { if ( array ) { var result = [ ] ; for ( var i = 0 , len = array . length ; i < len ; i ++ ) { var item = array [ i ] ; if ( f ( item ) ) { result . push ( item ) ; } } } return result ; } export function map < T , U > ( array , f ) { if ( array ) { var result = [ ] ; for ( var i = 0 , len = array . length ; i < len ; i ++ ) { result . push ( f ( array [ i ] ) ) ; } } return result ; } export function concatenate < T > ( array1 , array2 ) { if ( ! array2 || ! array2 . length ) return array1 ; if ( ! array1 || ! array1 . length ) return array2 ; return array1 . concat ( array2 ) ; } export function deduplicate < T > ( array ) { if ( array ) { var result = [ ] ; for ( var i = 0 , len = array . length ; i < len ; i ++ ) { var item = array [ i ] ; if ( ! contains ( result , item ) ) result . push ( item ) ; } } return result ; } export function sum ( array , prop ) { var result = 0 ; for ( var i = 0 ; i < array . length ; i ++ ) { result += array [ i ] [ prop ] ; } return result ; } /**
     * Returns the last element of an array if non-empty, undefined otherwise.
     */ export function lastOrUndefined < T > ( array ) { if ( array . length === 0 ) { return undefined ; } return array [ array . length - 1 ] ; } export function binarySearch ( array , value ) { var low = 0 ; var high = array . length - 1 ; while ( low <= high ) { var middle = low + ( ( high - low ) >> 1 ) ; var midValue = array [ middle ] ; if ( midValue === value ) { return middle ; } else if ( midValue > value ) { high = middle - 1 ; } else { low = middle + 1 ; } } return ~ low ; } var hasOwnProperty = Object . prototype . hasOwnProperty ; export function hasProperty < T > ( map , key ) { return hasOwnProperty . call ( map , key ) ; } export function getProperty < T > ( map , key ) { return hasOwnProperty . call ( map , key ) ? map [ key ] : undefined ; } export function isEmpty < T > ( map ) { for ( var id in map ) { if ( hasProperty ( map , id ) ) { return false ; } } return true ; } export function clone < T > ( object ) { var result = { } ; for ( var id in object ) { result [ id ] = ( < any > object ) [ id ] ; } return < T > result ; } export function forEachValue < T , U > ( map , callback ) { var result ; for ( var id in map ) { if ( result = callback ( map [ id ] ) ) break ; } return result ; } export function forEachKey < T , U > ( map , callback ) { var result ; for ( var id in map ) { if ( result = callback ( id ) ) break ; } return result ; } export function lookUp < T > ( map , key ) { return hasProperty ( map , key ) ? map [ key ] : undefined ; } export function mapToArray < T > ( map ) { var result = [ ] ; for ( var id in map ) { result . push ( map [ id ] ) ; } return result ; } param array param makeKey export function arrayToMap < T > ( array , makeKey ) { var result = { } ; forEach ( array , value => { result [ makeKey ( value ) ] = value ; } ) ; return result ; } function formatStringFromArgs ( text , args , baseIndex ? ) { baseIndex = baseIndex || 0 ; return text . replace ( /{(\d+)}/g , ( match , index ? ) => args [ + index + baseIndex ] ) ; } export var localizedDiagnosticMessages = undefined ; export function getLocaleSpecificMessage ( message ) { return localizedDiagnosticMessages && localizedDiagnosticMessages [ message ] ? localizedDiagnosticMessages [ message ] : message ; } export function createFileDiagnostic ( file , start , length , message , ... args ) ; export function createFileDiagnostic ( file , start , length , message ) { Debug . assert ( start >= 0 , "start must be non-negative, is " + start ) ; Debug . assert ( length >= 0 , "length must be non-negative, is " + length ) ; var text = getLocaleSpecificMessage ( message . key ) ; if ( arguments . length > 4 ) { text = formatStringFromArgs ( text , arguments , 4 ) ; } return { file , start , length , messageText : text , category : message . category , code : message . code , isEarly : message . isEarly } ; } export function createCompilerDiagnostic ( message , ... args ) ; export function createCompilerDiagnostic ( message ) { var text = getLocaleSpecificMessage ( message . key ) ; if ( arguments . length > 1 ) { text = formatStringFromArgs ( text , arguments , 1 ) ; } return { file : undefined , start : undefined , length : undefined , messageText : text , category : message . category , code : message . code , isEarly : message . isEarly } ; } export function chainDiagnosticMessages ( details , message , ... args ) ; export function chainDiagnosticMessages ( details , message ) { var text = getLocaleSpecificMessage ( message . key ) ; if ( arguments . length > 2 ) { text = formatStringFromArgs ( text , arguments , 2 ) ; } return { messageText : text , category : message . category , code : message . code , next : details } ; } export function concatenateDiagnosticMessageChains ( headChain , tailChain ) { Debug . assert ( ! headChain . next ) ; headChain . next = tailChain ; return headChain ; } export function flattenDiagnosticChain ( file , start , length , diagnosticChain , newLine ) { Debug . assert ( start >= 0 , "start must be non-negative, is " + start ) ; Debug . assert ( length >= 0 , "length must be non-negative, is " + length ) ; var code = diagnosticChain . code ; var category = diagnosticChain . category ; var messageText = "" ; var indent = 0 ; while ( diagnosticChain ) { if ( indent ) { messageText += newLine ; for ( var i = 0 ; i < indent ; i ++ ) { messageText += "  " ; } } messageText += diagnosticChain . messageText ; indent ++ ; diagnosticChain = diagnosticChain . next ; } return { file , start , length , code , category , messageText } ; } export function compareValues < T > ( a , b ) { if ( a === b ) return Comparison . EqualTo ; if ( a === undefined ) return Comparison . LessThan ; if ( b === undefined ) return Comparison . GreaterThan ; return a < b ? Comparison . LessThan : Comparison . GreaterThan ; } function getDiagnosticFilename ( diagnostic ) { return diagnostic . file ? diagnostic . file . filename : undefined ; } export function compareDiagnostics ( d1 , d2 ) { return compareValues ( getDiagnosticFilename ( d1 ) , getDiagnosticFilename ( d2 ) ) || compareValues ( d1 . start , d2 . start ) || compareValues ( d1 . length , d2 . length ) || compareValues ( d1 . code , d2 . code ) || compareValues ( d1 . messageText , d2 . messageText ) || 0 ; } export function deduplicateSortedDiagnostics ( diagnostics ) { if ( diagnostics . length < 2 ) { return diagnostics ; } var newDiagnostics = [ diagnostics [ 0 ] ] ; var previousDiagnostic = diagnostics [ 0 ] ; for ( var i = 1 ; i < diagnostics . length ; i ++ ) { var currentDiagnostic = diagnostics [ i ] ; var isDupe = compareDiagnostics ( currentDiagnostic , previousDiagnostic ) === Comparison . EqualTo ; if ( ! isDupe ) { newDiagnostics . push ( currentDiagnostic ) ; previousDiagnostic = currentDiagnostic ; } } return newDiagnostics ; } export function normalizeSlashes ( path ) { return path . replace ( /\\/g , "/" ) ; } export function getRootLength ( path ) { if ( path . charCodeAt ( 0 ) === CharacterCodes . slash ) { if ( path . charCodeAt ( 1 ) !== CharacterCodes . slash ) return 1 ; var p1 = path . indexOf ( "/" , 2 ) ; if ( p1 < 0 ) return 2 ; var p2 = path . indexOf ( "/" , p1 + 1 ) ; if ( p2 < 0 ) return p1 + 1 ; return p2 + 1 ; } if ( path . charCodeAt ( 1 ) === CharacterCodes . colon ) { if ( path . charCodeAt ( 2 ) === CharacterCodes . slash ) return 3 ; return 2 ; } return 0 ; } export var directorySeparator = "/" ; function getNormalizedParts ( normalizedSlashedPath , rootLength ) { var parts = normalizedSlashedPath . substr ( rootLength ) . split ( directorySeparator ) ; var normalized = [ ] ; for ( var i = 0 ; i < parts . length ; i ++ ) { var part = parts [ i ] ; if ( part !== "." ) { if ( part === ".." && normalized . length > 0 && normalized [ normalized . length - 1 ] !== ".." ) { normalized . pop ( ) ; } else { normalized . push ( part ) ; } } } return normalized ; } export function normalizePath ( path ) { var path = normalizeSlashes ( path ) ; var rootLength = getRootLength ( path ) ; var normalized = getNormalizedParts ( path , rootLength ) ; return path . substr ( 0 , rootLength ) + normalized . join ( directorySeparator ) ; } export function getDirectoryPath ( path ) { return path . substr ( 0 , Math . max ( getRootLength ( path ) , path . lastIndexOf ( directorySeparator ) ) ) ; } export function isUrl ( path ) { return path && ! isRootedDiskPath ( path ) && path . indexOf ( "://" ) !== - 1 ; } export function isRootedDiskPath ( path ) { return getRootLength ( path ) !== 0 ; } function normalizedPathComponents ( path , rootLength ) { var normalizedParts = getNormalizedParts ( path , rootLength ) ; return [ path . substr ( 0 , rootLength ) ] . concat ( normalizedParts ) ; } export function getNormalizedPathComponents ( path , currentDirectory ) { var path = normalizeSlashes ( path ) ; var rootLength = getRootLength ( path ) ; if ( rootLength == 0 ) { path = combinePaths ( normalizeSlashes ( currentDirectory ) , path ) ; rootLength = getRootLength ( path ) ; } return normalizedPathComponents ( path , rootLength ) ; } export function getNormalizedAbsolutePath ( filename , currentDirectory ) { return getNormalizedPathFromPathComponents ( getNormalizedPathComponents ( filename , currentDirectory ) ) ; } export function getNormalizedPathFromPathComponents ( pathComponents ) { if ( pathComponents && pathComponents . length ) { return pathComponents [ 0 ] + pathComponents . slice ( 1 ) . join ( directorySeparator ) ; } } function getNormalizedPathComponentsOfUrl ( url ) { var urlLength = url . length ; var rootLength = url . indexOf ( "://" ) + "://" . length ; while ( rootLength < urlLength ) { if ( url . charCodeAt ( rootLength ) === CharacterCodes . slash ) { rootLength ++ ; } else { break ; } } if ( rootLength === urlLength ) { return [ url ] ; } var indexOfNextSlash = url . indexOf ( directorySeparator , rootLength ) ; if ( indexOfNextSlash !== - 1 ) { rootLength = indexOfNextSlash + 1 ; return normalizedPathComponents ( url , rootLength ) ; } else { return [ url + directorySeparator ] ; } } function getNormalizedPathOrUrlComponents ( pathOrUrl , currentDirectory ) { if ( isUrl ( pathOrUrl ) ) { return getNormalizedPathComponentsOfUrl ( pathOrUrl ) ; } else { return getNormalizedPathComponents ( pathOrUrl , currentDirectory ) ; } } export function getRelativePathToDirectoryOrUrl ( directoryPathOrUrl , relativeOrAbsolutePath , currentDirectory , getCanonicalFileName , isAbsolutePathAnUrl ) { var pathComponents = getNormalizedPathOrUrlComponents ( relativeOrAbsolutePath , currentDirectory ) ; var directoryComponents = getNormalizedPathOrUrlComponents ( directoryPathOrUrl , currentDirectory ) ; if ( directoryComponents . length > 1 && directoryComponents [ directoryComponents . length - 1 ] === "" ) { directoryComponents . length -- ; } for ( var joinStartIndex = 0 ; joinStartIndex < pathComponents . length && joinStartIndex < directoryComponents . length ; joinStartIndex ++ ) { if ( getCanonicalFileName ( directoryComponents [ joinStartIndex ] ) !== getCanonicalFileName ( pathComponents [ joinStartIndex ] ) ) { break ; } } if ( joinStartIndex ) { var relativePath = "" ; var relativePathComponents = pathComponents . slice ( joinStartIndex , pathComponents . length ) ; for ( ; joinStartIndex < directoryComponents . length ; joinStartIndex ++ ) { if ( directoryComponents [ joinStartIndex ] !== "" ) { relativePath = relativePath + ".." + directorySeparator ; } } return relativePath + relativePathComponents . join ( directorySeparator ) ; } var absolutePath = getNormalizedPathFromPathComponents ( pathComponents ) ; if ( isAbsolutePathAnUrl && isRootedDiskPath ( absolutePath ) ) { absolutePath = "file:///" + absolutePath ; } return absolutePath ; } export function getBaseFilename ( path ) { var i = path . lastIndexOf ( directorySeparator ) ; return i < 0 ? path : path . substring ( i + 1 ) ; } export function combinePaths ( path1 , path2 ) { if ( ! ( path1 && path1 . length ) ) return path2 ; if ( ! ( path2 && path2 . length ) ) return path1 ; if ( path2 . charAt ( 0 ) === directorySeparator ) return path2 ; if ( path1 . charAt ( path1 . length - 1 ) === directorySeparator ) return path1 + path2 ; return path1 + directorySeparator + path2 ; } export function fileExtensionIs ( path , extension ) { var pathLen = path . length ; var extLen = extension . length ; return pathLen > extLen && path . substr ( pathLen - extLen , extLen ) === extension ; } var supportedExtensions = [ ".d.ts" , ".ts" , ".js" ] ; export function removeFileExtension ( path ) { for ( var i = 0 ; i < supportedExtensions . length ; i ++ ) { var ext = supportedExtensions [ i ] ; if ( fileExtensionIs ( path , ext ) ) { return path . substr ( 0 , path . length - ext . length ) ; } } return path ; } var escapedCharsRegExp = /[\t\v\f\b\0\r\n\"\\\u2028\u2029\u0085]/g ; var escapedCharsMap = { "\t" : "\\t" , "\v" : "\\v" , "\f" : "\\f" , "\b" : "\\b" , "\0" : "\\0" , "\r" : "\\r" , "\n" : "\\n" , "\"" : "\\\"" , "\u2028" : "\\u2028" , "\u2029" : "\\u2029" , "\u0085" : "\\u0085" } ; /** NOTE: This *does not* support the full escape characters, it only supports the subset that can be used in file names
      * or string literals. If the information encoded in the map changes, this needs to be revisited. */ export function escapeString ( s ) { return escapedCharsRegExp . test ( s ) ? s . replace ( escapedCharsRegExp , c => { return escapedCharsMap [ c ] || c ; } ) : s ; } export interface ObjectAllocator { getNodeConstructor ( kind ) : new ( ) => Node ; getSymbolConstructor ( ) : new ( flags , name ) => Symbol ; getTypeConstructor ( ) : new ( checker , flags ) => Type ; getSignatureConstructor ( ) : new ( checker ) => Signature ; } function Symbol ( flags , name ) { this . flags = flags ; this . name = name ; this . declarations = undefined ; } function Type ( checker , flags ) { this . flags = flags ; } function Signature ( checker ) { } export var objectAllocator = { getNodeConstructor : kind => { function Node ( ) { } Node . prototype = { kind : kind , pos : 0 , end : 0 , flags : 0 , parent : undefined , } ; return < any > Node ; } , getSymbolConstructor : ( ) => < any > Symbol , getTypeConstructor : ( ) => < any > Type , getSignatureConstructor : ( ) => < any > Signature } ; export const enum AssertionLevel { None = 0 , Normal = 1 , Aggressive = 2 , VeryAggressive = 3 } export module Debug { var currentAssertionLevel = AssertionLevel . None ; export function shouldAssert ( level ) { return currentAssertionLevel >= level ; } export function assert ( expression , message ? , verboseDebugInfo ? ) { if ( ! expression ) { var verboseDebugString = "" ; if ( verboseDebugInfo ) { verboseDebugString = "\r\nVerbose Debug Information: " + verboseDebugInfo ( ) ; } throw new Error ( "Debug Failure. False expression: " + ( message || "" ) + verboseDebugString ) ; } } export function fail ( message ? ) { Debug . assert ( false , message ) ; } } }