internal/ls/source_map.go (118 lines of code) (raw):

package ls import ( "github.com/microsoft/typescript-go/internal/core" "github.com/microsoft/typescript-go/internal/debug" "github.com/microsoft/typescript-go/internal/ls/lsconv" "github.com/microsoft/typescript-go/internal/lsp/lsproto" "github.com/microsoft/typescript-go/internal/outputpaths" "github.com/microsoft/typescript-go/internal/sourcemap" "github.com/microsoft/typescript-go/internal/tspath" ) func (l *LanguageService) getMappedLocation(fileName string, fileRange core.TextRange) lsproto.Location { startPos := l.tryGetSourcePosition(fileName, core.TextPos(fileRange.Pos())) if startPos == nil { lspRange := l.createLspRangeFromRange(fileRange, l.getScript(fileName)) return lsproto.Location{ Uri: lsconv.FileNameToDocumentURI(fileName), Range: *lspRange, } } endPos := l.tryGetSourcePosition(fileName, core.TextPos(fileRange.End())) if endPos == nil { endPos = &sourcemap.DocumentPosition{ FileName: startPos.FileName, Pos: startPos.Pos + fileRange.Len(), } } debug.Assert(endPos.FileName == startPos.FileName, "start and end should be in same file") newRange := core.NewTextRange(startPos.Pos, endPos.Pos) lspRange := l.createLspRangeFromRange(newRange, l.getScript(startPos.FileName)) return lsproto.Location{ Uri: lsconv.FileNameToDocumentURI(startPos.FileName), Range: *lspRange, } } type script struct { fileName string text string } func (s *script) FileName() string { return s.fileName } func (s *script) Text() string { return s.text } func (l *LanguageService) getScript(fileName string) *script { text, ok := l.host.ReadFile(fileName) if !ok { return nil } return &script{fileName: fileName, text: text} } func (l *LanguageService) tryGetSourcePosition( fileName string, position core.TextPos, ) *sourcemap.DocumentPosition { newPos := l.tryGetSourcePositionWorker(fileName, position) if newPos != nil { if _, ok := l.ReadFile(newPos.FileName); !ok { // File doesn't exist return nil } } return newPos } func (l *LanguageService) tryGetSourcePositionWorker( fileName string, position core.TextPos, ) *sourcemap.DocumentPosition { if !tspath.IsDeclarationFileName(fileName) { return nil } positionMapper := l.GetDocumentPositionMapper(fileName) documentPos := positionMapper.GetSourcePosition(&sourcemap.DocumentPosition{FileName: fileName, Pos: int(position)}) if documentPos == nil { return nil } if newPos := l.tryGetSourcePositionWorker(documentPos.FileName, core.TextPos(documentPos.Pos)); newPos != nil { return newPos } return documentPos } func (l *LanguageService) tryGetGeneratedPosition( fileName string, position core.TextPos, ) *sourcemap.DocumentPosition { newPos := l.tryGetGeneratedPositionWorker(fileName, position) if newPos != nil { if _, ok := l.ReadFile(newPos.FileName); !ok { // File doesn't exist return nil } } return newPos } func (l *LanguageService) tryGetGeneratedPositionWorker( fileName string, position core.TextPos, ) *sourcemap.DocumentPosition { if tspath.IsDeclarationFileName(fileName) { return nil } program := l.GetProgram() if program == nil || program.GetSourceFile(fileName) == nil { return nil } path := l.toPath(fileName) // If this is source file of project reference source (instead of redirect) there is no generated position if program.IsSourceFromProjectReference(path) { return nil } declarationFileName := outputpaths.GetOutputDeclarationFileNameWorker(fileName, program.Options(), program) positionMapper := l.GetDocumentPositionMapper(declarationFileName) documentPos := positionMapper.GetGeneratedPosition(&sourcemap.DocumentPosition{FileName: fileName, Pos: int(position)}) if documentPos == nil { return nil } if newPos := l.tryGetGeneratedPositionWorker(documentPos.FileName, core.TextPos(documentPos.Pos)); newPos != nil { return newPos } return documentPos }