namespace ts { const base64UrlRegExp = /^data:(?:application\/json(?:;charset=[uU][tT][fF]-8);base64,([A-Za-z0-9+\/=]+)$)?/ ; export interface SourceMapper { toLineColumnOffset ( fileName , position ) : LineAndCharacter ; tryGetSourcePosition ( info ) : DocumentPosition | undefined ; tryGetGeneratedPosition ( info ) : DocumentPosition | undefined ; clearCache ( ) : void ; } export interface SourceMapperHost { useCaseSensitiveFileNames ( ) : boolean ; getCurrentDirectory ( ) : string ; getProgram ( ) : Program | undefined ; fileExists ? ( path ) : boolean ; readFile ? ( path , encoding ? ) : string | undefined ; getSourceFileLike ? ( fileName ) : SourceFileLike | undefined ; getDocumentPositionMapper ? ( generatedFileName , sourceFileName ? ) : DocumentPositionMapper | undefined ; log ( s ) : void ; } export function getSourceMapper ( host ) { const getCanonicalFileName = createGetCanonicalFileName ( host . useCaseSensitiveFileNames ( ) ) ; const currentDirectory = host . getCurrentDirectory ( ) ; const sourceFileLike = new Map < string , SourceFileLike | false > ( ) ; const documentPositionMappers = new Map < string , DocumentPositionMapper > ( ) ; return { tryGetSourcePosition , tryGetGeneratedPosition , toLineColumnOffset , clearCache } ; function toPath ( fileName ) { return ts . toPath ( fileName , currentDirectory , getCanonicalFileName ) ; } function getDocumentPositionMapper ( generatedFileName , sourceFileName ? ) { const path = toPath ( generatedFileName ) ; const value = documentPositionMappers . get ( path ) ; if ( value ) return value ; let mapper ; if ( host . getDocumentPositionMapper ) { mapper = host . getDocumentPositionMapper ( generatedFileName , sourceFileName ) ; } else if ( host . readFile ) { const file = getSourceFileLike ( generatedFileName ) ; mapper = file && ts . getDocumentPositionMapper ( { getSourceFileLike , getCanonicalFileName , log : s => host . log ( s ) } , generatedFileName , getLineInfo ( file . text , getLineStarts ( file ) ) , f => ! host . fileExists || host . fileExists ( f ) ? host . readFile ! ( f ) : undefined ) ; } documentPositionMappers . set ( path , mapper || identitySourceMapConsumer ) ; return mapper || identitySourceMapConsumer ; } function tryGetSourcePosition ( info ) { if ( ! isDeclarationFileName ( info . fileName ) ) return undefined ; const file = getSourceFile ( info . fileName ) ; if ( ! file ) return undefined ; const newLoc = getDocumentPositionMapper ( info . fileName ) . getSourcePosition ( info ) ; return ! newLoc || newLoc === info ? undefined : tryGetSourcePosition ( newLoc ) || newLoc ; } function tryGetGeneratedPosition ( info ) { if ( isDeclarationFileName ( info . fileName ) ) return undefined ; const sourceFile = getSourceFile ( info . fileName ) ; if ( ! sourceFile ) return undefined ; const program = host . getProgram ( ) ! ; if ( program . isSourceOfProjectReferenceRedirect ( sourceFile . fileName ) ) { return undefined ; } const options = program . getCompilerOptions ( ) ; const outPath = outFile ( options ) ; const declarationPath = outPath ? removeFileExtension ( outPath ) + Extension . Dts : getDeclarationEmitOutputFilePathWorker ( info . fileName , program . getCompilerOptions ( ) , currentDirectory , program . getCommonSourceDirectory ( ) , getCanonicalFileName ) ; if ( declarationPath === undefined ) return undefined ; const newLoc = getDocumentPositionMapper ( declarationPath , info . fileName ) . getGeneratedPosition ( info ) ; return newLoc === info ? undefined : newLoc ; } function getSourceFile ( fileName ) { const program = host . getProgram ( ) ; if ( ! program ) return undefined ; const path = toPath ( fileName ) ; const file = program . getSourceFileByPath ( path ) ; return file && file . resolvedPath === path ? file : undefined ; } function getOrCreateSourceFileLike ( fileName ) { const path = toPath ( fileName ) ; const fileFromCache = sourceFileLike . get ( path ) ; if ( fileFromCache !== undefined ) return fileFromCache ? fileFromCache : undefined ; if ( ! host . readFile || host . fileExists && ! host . fileExists ( path ) ) { sourceFileLike . set ( path , false ) ; return undefined ; } const text = host . readFile ( path ) ; const file = text ? createSourceFileLike ( text ) : false ; sourceFileLike . set ( path , file ) ; return file ? file : undefined ; } function getSourceFileLike ( fileName ) { return ! host . getSourceFileLike ? getSourceFile ( fileName ) || getOrCreateSourceFileLike ( fileName ) : host . getSourceFileLike ( fileName ) ; } function toLineColumnOffset ( fileName , position ) { const file = getSourceFileLike ( fileName ) ! ; return file . getLineAndCharacterOfPosition ( position ) ; } function clearCache ( ) { sourceFileLike . clear ( ) ; documentPositionMappers . clear ( ) ; } } /**
     * string | undefined to contents of map file to create DocumentPositionMapper from it
     * DocumentPositionMapper | false to give back cached DocumentPositionMapper
     */ export type ReadMapFile = ( mapFileName : string , mapFileNameFromDts : string | undefined ) => string | undefined | DocumentPositionMapper | false ; export function getDocumentPositionMapper ( host , generatedFileName , generatedFileLineInfo , readMapFile ) { let mapFileName = tryGetSourceMappingURL ( generatedFileLineInfo ) ; if ( mapFileName ) { const match = base64UrlRegExp . exec ( mapFileName ) ; if ( match ) { if ( match [ 1 ] ) { const base64Object = match [ 1 ] ; return convertDocumentToSourceMapper ( host , base64decode ( sys , base64Object ) , generatedFileName ) ; } mapFileName = undefined ; } } const possibleMapLocations = [ ] ; if ( mapFileName ) { possibleMapLocations . push ( mapFileName ) ; } possibleMapLocations . push ( generatedFileName + ".map" ) ; const originalMapFileName = mapFileName && getNormalizedAbsolutePath ( mapFileName , getDirectoryPath ( generatedFileName ) ) ; for ( const location of possibleMapLocations ) { const mapFileName = getNormalizedAbsolutePath ( location , getDirectoryPath ( generatedFileName ) ) ; const mapFileContents = readMapFile ( mapFileName , originalMapFileName ) ; if ( isString ( mapFileContents ) ) { return convertDocumentToSourceMapper ( host , mapFileContents , mapFileName ) ; } if ( mapFileContents !== undefined ) { return mapFileContents || undefined ; } } return undefined ; } function convertDocumentToSourceMapper ( host , contents , mapFileName ) { const map = tryParseRawSourceMap ( contents ) ; if ( ! map || ! map . sources || ! map . file || ! map . mappings ) { return undefined ; } if ( map . sourcesContent && map . sourcesContent . some ( isString ) ) return undefined ; return createDocumentPositionMapper ( host , map , mapFileName ) ; } function createSourceFileLike ( text , lineMap ? ) { return { text , lineMap , getLineAndCharacterOfPosition ( pos ) { return computeLineAndCharacterOfPosition ( getLineStarts ( this ) , pos ) ; } } ; } }