namespace documents { export class TextDocument { public readonly meta : Map < string , string > ; public readonly file : string ; public readonly text : string ; private _lineStarts : readonly number [ ] | undefined ; private _testFile : Harness . Compiler . TestFile | undefined ; constructor ( file , text , meta ? ) { this . file = file ; this . text = text ; this . meta = meta || new Map < string , string > ( ) ; } public get lineStarts ( ) : readonly number [ ] { return this . _lineStarts || ( this . _lineStarts = ts . computeLineStarts ( this . text ) ) ; } public static fromTestFile ( file ) { return new TextDocument ( file . unitName , file . content , file . fileOptions && Object . keys ( file . fileOptions ) . reduce ( ( meta , key ) => meta . set ( key , file . fileOptions [ key ] ) , new Map < string , string > ( ) ) ) ; } public asTestFile ( ) { return this . _testFile || ( this . _testFile = { unitName : this . file , content : this . text , fileOptions : Array . from ( this . meta ) . reduce ( ( obj , [ key , value ] ) => ( obj [ key ] = value , obj ) , { } as Record < string , string > ) } ) ; } } export interface RawSourceMap { version : number ; file : string ; sourceRoot ? : string ; sources : string [ ] ; sourcesContent ? : string [ ] ; names : string [ ] ; mappings : string ; } export interface Mapping { mappingIndex : number ; emittedLine : number ; emittedColumn : number ; sourceIndex : number ; sourceLine : number ; sourceColumn : number ; nameIndex ? : number ; } export class SourceMap { public readonly raw : RawSourceMap ; public readonly mapFile : string | undefined ; public readonly version : number ; public readonly file : string ; public readonly sourceRoot : string | undefined ; public readonly sources : readonly string [ ] = [ ] ; public readonly sourcesContent : readonly string [ ] | undefined ; public readonly mappings : readonly Mapping [ ] = [ ] ; public readonly names : readonly string [ ] | undefined ; private static readonly _mappingRegExp = /([A-Za-z0-9+/]+),?|(;)|./g ; private static readonly _sourceMappingURLRegExp = /^\/\/[#@]\s*sourceMappingURL\s*=\s*(.*?)\s*$/mig ; private static readonly _dataURLRegExp = /^data:application\/json;base64,([a-z0-9+/=]+)$/i ; private static readonly _base64Chars = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/" ; private _emittedLineMappings : Mapping [ ] [ ] = [ ] ; private _sourceLineMappings : Mapping [ ] [ ] [ ] = [ ] ; constructor ( mapFile , data ) { this . raw = typeof data === "string" ? JSON . parse ( data ) as RawSourceMap : data ; this . mapFile = mapFile ; this . version = this . raw . version ; this . file = this . raw . file ; this . sourceRoot = this . raw . sourceRoot ; this . sources = this . raw . sources ; this . sourcesContent = this . raw . sourcesContent ; this . names = this . raw . names ; const mappings = [ ] ; let emittedLine = 0 ; let emittedColumn = 0 ; let sourceIndex = 0 ; let sourceLine = 0 ; let sourceColumn = 0 ; let nameIndex = 0 ; let match ; while ( match = SourceMap . _mappingRegExp . exec ( this . raw . mappings ) ) { if ( match [ 1 ] ) { const segment = SourceMap . _decodeVLQ ( match [ 1 ] ) ; if ( segment . length !== 1 && segment . length !== 4 && segment . length !== 5 ) { throw new Error ( "Invalid VLQ" ) ; } emittedColumn += segment [ 0 ] ; if ( segment . length >= 4 ) { sourceIndex += segment [ 1 ] ; sourceLine += segment [ 2 ] ; sourceColumn += segment [ 3 ] ; } const mapping = { mappingIndex : mappings . length , emittedLine , emittedColumn , sourceIndex , sourceLine , sourceColumn } ; if ( segment . length === 5 ) { nameIndex += segment [ 4 ] ; mapping . nameIndex = nameIndex ; } mappings . push ( mapping ) ; const mappingsForEmittedLine = this . _emittedLineMappings [ mapping . emittedLine ] || ( this . _emittedLineMappings [ mapping . emittedLine ] = [ ] ) ; mappingsForEmittedLine . push ( mapping ) ; const mappingsForSource = this . _sourceLineMappings [ mapping . sourceIndex ] || ( this . _sourceLineMappings [ mapping . sourceIndex ] = [ ] ) ; const mappingsForSourceLine = mappingsForSource [ mapping . sourceLine ] || ( mappingsForSource [ mapping . sourceLine ] = [ ] ) ; mappingsForSourceLine . push ( mapping ) ; } else if ( match [ 2 ] ) { emittedLine ++ ; emittedColumn = 0 ; } else { throw new Error ( `Unrecognized character '${ match [ 0 ] }'.` ) ; } } this . mappings = mappings ; } public static getUrl ( text ) { let match ; let lastMatch ; while ( match = SourceMap . _sourceMappingURLRegExp . exec ( text ) ) { lastMatch = match ; } return lastMatch ? lastMatch [ 1 ] : undefined ; } public static fromUrl ( url ) { const match = SourceMap . _dataURLRegExp . exec ( url ) ; return match ? new SourceMap ( undefined , ts . sys . base64decode ! ( match [ 1 ] ) ) : undefined ; } public static fromSource ( text ) { const url = this . getUrl ( text ) ; return url === undefined ? undefined : this . fromUrl ( url ) ; } public getMappingsForEmittedLine ( emittedLine ) { return this . _emittedLineMappings [ emittedLine ] ; } public getMappingsForSourceLine ( sourceIndex , sourceLine ) { const mappingsForSource = this . _sourceLineMappings [ sourceIndex ] ; return mappingsForSource && mappingsForSource [ sourceLine ] ; } private static _decodeVLQ ( text ) { const vlq = [ ] ; let shift = 0 ; let value = 0 ; for ( let i = 0 ; i < text . length ; i ++ ) { const currentByte = SourceMap . _base64Chars . indexOf ( text . charAt ( i ) ) ; value += ( currentByte & 31 ) << shift ; if ( ( currentByte & 32 ) === 0 ) { vlq . push ( value & 1 ? - ( value >>> 1 ) : value >>> 1 ) ; shift = 0 ; value = 0 ; } else { shift += 5 ; } } return vlq ; } } }