mirror of
https://github.com/microsoft/TypeScript.git
synced 2026-02-05 16:38:05 -06:00
Add method on host to get DocumentPositionMapper so it can be cached.
This commit is contained in:
parent
0dad79e8b3
commit
12428d45c0
@ -338,12 +338,16 @@ namespace ts {
|
||||
}
|
||||
|
||||
export function getPositionOfLineAndCharacter(sourceFile: SourceFileLike, line: number, character: number): number {
|
||||
return computePositionOfLineAndCharacter(getLineStarts(sourceFile), line, character, sourceFile.text);
|
||||
return sourceFile.getPositionOfLineAndCharacter ?
|
||||
sourceFile.getPositionOfLineAndCharacter(line, character) :
|
||||
computePositionOfLineAndCharacter(getLineStarts(sourceFile), line, character, sourceFile.text);
|
||||
}
|
||||
|
||||
/* @internal */
|
||||
export function getPositionOfLineAndCharacterWithEdits(sourceFile: SourceFileLike, line: number, character: number): number {
|
||||
return computePositionOfLineAndCharacter(getLineStarts(sourceFile), line, character, sourceFile.text, /*allowEdits*/ true);
|
||||
return sourceFile.getPositionOfLineAndCharacter ?
|
||||
sourceFile.getPositionOfLineAndCharacter(line, character) :
|
||||
computePositionOfLineAndCharacter(getLineStarts(sourceFile), line, character, sourceFile.text, /*allowEdits*/ true);
|
||||
}
|
||||
|
||||
/* @internal */
|
||||
|
||||
@ -266,14 +266,24 @@ namespace ts {
|
||||
const sourceMapCommentRegExp = /^\/\/[@#] source[M]appingURL=(.+)\s*$/;
|
||||
const whitespaceOrMapCommentRegExp = /^\s*(\/\/[@#] .*)?$/;
|
||||
|
||||
export interface LineInfo {
|
||||
getLineCount(): number;
|
||||
getLineText(line: number): string;
|
||||
}
|
||||
|
||||
export function getLineInfo(text: string, lineStarts: ReadonlyArray<number>): LineInfo {
|
||||
return {
|
||||
getLineCount: () => lineStarts.length,
|
||||
getLineText: line => text.substring(lineStarts[line], lineStarts[line + 1])
|
||||
};
|
||||
}
|
||||
|
||||
/**
|
||||
* Tries to find the sourceMappingURL comment at the end of a file.
|
||||
* @param text The source text of the file.
|
||||
* @param lineStarts The line starts of the file.
|
||||
*/
|
||||
export function tryGetSourceMappingURL(text: string, lineStarts: ReadonlyArray<number> = computeLineStarts(text)) {
|
||||
for (let index = lineStarts.length - 1; index >= 0; index--) {
|
||||
const line = text.substring(lineStarts[index], lineStarts[index + 1]);
|
||||
export function tryGetSourceMappingURL(lineInfo: LineInfo) {
|
||||
for (let index = lineInfo.getLineCount() - 1; index >= 0; index--) {
|
||||
const line = lineInfo.getLineText(index);
|
||||
const comment = sourceMapCommentRegExp.exec(line);
|
||||
if (comment) {
|
||||
return comment[1];
|
||||
|
||||
@ -2614,6 +2614,8 @@ namespace ts {
|
||||
export interface SourceFileLike {
|
||||
readonly text: string;
|
||||
lineMap?: ReadonlyArray<number>;
|
||||
/* @internal */
|
||||
getPositionOfLineAndCharacter?(line: number, character: number): number;
|
||||
}
|
||||
|
||||
|
||||
|
||||
@ -69,7 +69,7 @@ namespace Harness.SourceMapRecorder {
|
||||
SourceMapDecoder.initializeSourceMapDecoding(sourceMapData);
|
||||
sourceMapRecorder.WriteLine("===================================================================");
|
||||
sourceMapRecorder.WriteLine("JsFile: " + sourceMapData.sourceMap.file);
|
||||
sourceMapRecorder.WriteLine("mapUrl: " + ts.tryGetSourceMappingURL(jsFile.text, jsLineMap));
|
||||
sourceMapRecorder.WriteLine("mapUrl: " + ts.tryGetSourceMappingURL(ts.getLineInfo(jsFile.text, jsLineMap)));
|
||||
sourceMapRecorder.WriteLine("sourceRoot: " + sourceMapData.sourceMap.sourceRoot);
|
||||
sourceMapRecorder.WriteLine("sources: " + sourceMapData.sourceMap.sources);
|
||||
if (sourceMapData.sourceMap.sourcesContent) {
|
||||
|
||||
@ -503,6 +503,66 @@ namespace ts.server {
|
||||
return this.getLanguageService().getSourceMapper();
|
||||
}
|
||||
|
||||
/*@internal*/
|
||||
getDocumentPositionMapper(fileName: string): DocumentPositionMapper | undefined {
|
||||
const declarationInfo = this.projectService.getOrCreateScriptInfoNotOpenedByClient(fileName, this.currentDirectory, this.directoryStructureHost);
|
||||
if (!declarationInfo) return undefined;
|
||||
|
||||
declarationInfo.getSnapshot(); // Ensure synchronized
|
||||
const existingMapper = declarationInfo.textStorage.mapper;
|
||||
if (existingMapper !== undefined) {
|
||||
return existingMapper ? existingMapper : undefined;
|
||||
}
|
||||
|
||||
// Create the mapper
|
||||
declarationInfo.mapInfo = undefined;
|
||||
|
||||
const mapper = getDocumentPositionMapper({
|
||||
getCanonicalFileName: this.projectService.toCanonicalFileName,
|
||||
log: s => this.log(s),
|
||||
readMapFile: f => this.readMapFile(f, declarationInfo),
|
||||
getSourceFileLike: f => this.getSourceFileLike(f)
|
||||
}, declarationInfo.fileName, declarationInfo.textStorage.getLineInfo());
|
||||
declarationInfo.textStorage.mapper = mapper || false;
|
||||
return mapper;
|
||||
}
|
||||
|
||||
private readMapFile(fileName: string, declarationInfo: ScriptInfo) {
|
||||
const mapInfo = this.projectService.getOrCreateScriptInfoNotOpenedByClient(fileName, this.currentDirectory, this.directoryStructureHost);
|
||||
if (!mapInfo) return undefined;
|
||||
declarationInfo.mapInfo = mapInfo;
|
||||
const snap = mapInfo.getSnapshot();
|
||||
return snap.getText(0, snap.getLength());
|
||||
}
|
||||
|
||||
/*@internal*/
|
||||
getSourceFileLike(fileName: string) {
|
||||
const path = this.toPath(fileName);
|
||||
const sourceFile = this.getSourceFile(path);
|
||||
if (sourceFile && sourceFile.resolvedPath === path) return sourceFile;
|
||||
|
||||
// Need to look for other files.
|
||||
const info = this.projectService.getOrCreateScriptInfoNotOpenedByClient(fileName, this.currentDirectory, this.directoryStructureHost);
|
||||
if (!info) return undefined;
|
||||
|
||||
// Key doesnt matter since its only for text and lines
|
||||
if (info.cacheSourceFile) return info.cacheSourceFile.sourceFile;
|
||||
if (info.textStorage.sourceFileLike) return info.textStorage.sourceFileLike;
|
||||
|
||||
info.textStorage.sourceFileLike = {
|
||||
get text() {
|
||||
Debug.fail("shouldnt need text");
|
||||
return "";
|
||||
},
|
||||
getLineAndCharacterOfPosition: pos => {
|
||||
const lineOffset = info.positionToLineOffset(pos);
|
||||
return { line: lineOffset.line - 1, character: lineOffset.offset - 1 };
|
||||
},
|
||||
getPositionOfLineAndCharacter: (line, character) => info.lineOffsetToPosition(line + 1, character + 1)
|
||||
};
|
||||
return info.textStorage.sourceFileLike;
|
||||
}
|
||||
|
||||
private shouldEmitFile(scriptInfo: ScriptInfo) {
|
||||
return scriptInfo && !scriptInfo.isDynamicOrHasMixedContent();
|
||||
}
|
||||
|
||||
@ -46,6 +46,9 @@ namespace ts.server {
|
||||
*/
|
||||
private pendingReloadFromDisk = false;
|
||||
|
||||
mapper: DocumentPositionMapper | false | undefined = false;
|
||||
sourceFileLike: SourceFileLike | undefined;
|
||||
|
||||
constructor(private readonly host: ServerHost, private readonly fileName: NormalizedPath, initialVersion: ScriptInfoVersion | undefined, private readonly info: ScriptInfo) {
|
||||
this.version = initialVersion || { svc: 0, text: 0 };
|
||||
}
|
||||
@ -70,6 +73,8 @@ namespace ts.server {
|
||||
this.text = newText;
|
||||
this.lineMap = undefined;
|
||||
this.fileSize = undefined;
|
||||
this.mapper = undefined;
|
||||
this.sourceFileLike = undefined;
|
||||
this.version.text++;
|
||||
}
|
||||
|
||||
@ -79,6 +84,8 @@ namespace ts.server {
|
||||
this.text = undefined;
|
||||
this.lineMap = undefined;
|
||||
this.fileSize = undefined;
|
||||
this.mapper = undefined;
|
||||
this.sourceFileLike = undefined;
|
||||
}
|
||||
|
||||
/**
|
||||
@ -156,8 +163,8 @@ namespace ts.server {
|
||||
: ScriptSnapshot.fromString(this.getOrLoadText());
|
||||
}
|
||||
|
||||
public getLineInfo(line: number): AbsolutePositionAndLineText {
|
||||
return this.switchToScriptVersionCache().getLineInfo(line);
|
||||
public getAbsolutePositionAndLineText(line: number): AbsolutePositionAndLineText {
|
||||
return this.switchToScriptVersionCache().getAbsolutePositionAndLineText(line);
|
||||
}
|
||||
/**
|
||||
* @param line 0 based index
|
||||
@ -246,6 +253,17 @@ namespace ts.server {
|
||||
Debug.assert(!this.svc, "ScriptVersionCache should not be set");
|
||||
return this.lineMap || (this.lineMap = computeLineStarts(this.getOrLoadText()));
|
||||
}
|
||||
|
||||
getLineInfo(): LineInfo {
|
||||
if (this.svc) {
|
||||
return {
|
||||
getLineCount: () => this.svc!.getLineCount(),
|
||||
getLineText: line => this.svc!.getAbsolutePositionAndLineText(line + 1).lineText!
|
||||
};
|
||||
}
|
||||
const lineMap = this.getLineMap();
|
||||
return getLineInfo(this.text!, lineMap);
|
||||
}
|
||||
}
|
||||
|
||||
/*@internal*/
|
||||
@ -269,7 +287,7 @@ namespace ts.server {
|
||||
|
||||
/* @internal */
|
||||
fileWatcher: FileWatcher | undefined;
|
||||
private textStorage: TextStorage;
|
||||
/* @internal */ textStorage: TextStorage;
|
||||
|
||||
/*@internal*/
|
||||
readonly isDynamic: boolean;
|
||||
@ -284,6 +302,9 @@ namespace ts.server {
|
||||
/*@internal*/
|
||||
mTime?: number;
|
||||
|
||||
/*@internal*/
|
||||
mapInfo?: ScriptInfo;
|
||||
|
||||
constructor(
|
||||
private readonly host: ServerHost,
|
||||
readonly fileName: NormalizedPath,
|
||||
@ -521,8 +542,8 @@ namespace ts.server {
|
||||
}
|
||||
|
||||
/*@internal*/
|
||||
getLineInfo(line: number): AbsolutePositionAndLineText {
|
||||
return this.textStorage.getLineInfo(line);
|
||||
getAbsolutePositionAndLineText(line: number): AbsolutePositionAndLineText {
|
||||
return this.textStorage.getAbsolutePositionAndLineText(line);
|
||||
}
|
||||
|
||||
editContent(start: number, end: number, newText: string): void {
|
||||
|
||||
@ -308,8 +308,8 @@ namespace ts.server {
|
||||
return this._getSnapshot().version;
|
||||
}
|
||||
|
||||
getLineInfo(line: number): AbsolutePositionAndLineText {
|
||||
return this._getSnapshot().index.lineNumberToInfo(line);
|
||||
getAbsolutePositionAndLineText(oneBasedLine: number): AbsolutePositionAndLineText {
|
||||
return this._getSnapshot().index.lineNumberToInfo(oneBasedLine);
|
||||
}
|
||||
|
||||
lineOffsetToPosition(line: number, column: number): number {
|
||||
@ -348,6 +348,10 @@ namespace ts.server {
|
||||
}
|
||||
}
|
||||
|
||||
getLineCount() {
|
||||
return this._getSnapshot().index.getLineCount();
|
||||
}
|
||||
|
||||
static fromString(script: string) {
|
||||
const svc = new ScriptVersionCache();
|
||||
const snap = new LineIndexSnapshot(0, svc, new LineIndex());
|
||||
@ -400,8 +404,12 @@ namespace ts.server {
|
||||
return this.root.charOffsetToLineInfo(1, position);
|
||||
}
|
||||
|
||||
getLineCount() {
|
||||
return this.root.lineCount();
|
||||
}
|
||||
|
||||
lineNumberToInfo(oneBasedLine: number): AbsolutePositionAndLineText {
|
||||
const lineCount = this.root.lineCount();
|
||||
const lineCount = this.getLineCount();
|
||||
if (oneBasedLine <= lineCount) {
|
||||
const { position, leaf } = this.root.lineNumberToInfo(oneBasedLine, 0);
|
||||
return { absolutePosition: position, lineText: leaf && leaf.text };
|
||||
|
||||
@ -1474,7 +1474,7 @@ namespace ts.server {
|
||||
// only to the previous line. If all this is true, then
|
||||
// add edits necessary to properly indent the current line.
|
||||
if ((args.key === "\n") && ((!edits) || (edits.length === 0) || allEditsBeforePos(edits, position))) {
|
||||
const { lineText, absolutePosition } = scriptInfo.getLineInfo(args.line);
|
||||
const { lineText, absolutePosition } = scriptInfo.getAbsolutePositionAndLineText(args.line);
|
||||
if (lineText && lineText.search("\\S") < 0) {
|
||||
const preferredIndent = languageService.getIndentationAtPosition(file, position, formatOptions);
|
||||
let hasIndent = 0;
|
||||
|
||||
@ -603,7 +603,7 @@ namespace ts {
|
||||
}
|
||||
|
||||
public getPositionOfLineAndCharacter(line: number, character: number): number {
|
||||
return getPositionOfLineAndCharacter(this, line, character);
|
||||
return computePositionOfLineAndCharacter(getLineStarts(this), line, character, this.text);
|
||||
}
|
||||
|
||||
public getLineEndOfPosition(pos: number): number {
|
||||
@ -1143,8 +1143,10 @@ namespace ts {
|
||||
useCaseSensitiveFileNames: () => useCaseSensitiveFileNames,
|
||||
getCurrentDirectory: () => currentDirectory,
|
||||
getProgram,
|
||||
fileExists: host.fileExists ? f => host.fileExists!(f) : returnFalse,
|
||||
readFile: host.readFile ? (f, encoding) => host.readFile!(f, encoding) : () => undefined,
|
||||
fileExists: host.fileExists && (f => host.fileExists!(f)),
|
||||
readFile: host.readFile && ((f, encoding) => host.readFile!(f, encoding)),
|
||||
getDocumentPositionMapper: host.getDocumentPositionMapper && (f => host.getDocumentPositionMapper!(f)),
|
||||
getSourceFileLike: host.getSourceFileLike && (f => host.getSourceFileLike!(f)),
|
||||
log
|
||||
});
|
||||
|
||||
|
||||
@ -13,8 +13,10 @@ namespace ts {
|
||||
useCaseSensitiveFileNames(): boolean;
|
||||
getCurrentDirectory(): string;
|
||||
getProgram(): Program | undefined;
|
||||
fileExists(path: string): boolean;
|
||||
readFile(path: string, encoding?: string): string | undefined;
|
||||
fileExists?(path: string): boolean;
|
||||
readFile?(path: string, encoding?: string): string | undefined;
|
||||
getSourceFileLike?(fileName: string): SourceFileLike | undefined;
|
||||
getDocumentPositionMapper?(fileName: string): DocumentPositionMapper | undefined;
|
||||
log(s: string): void;
|
||||
}
|
||||
|
||||
@ -22,63 +24,33 @@ namespace ts {
|
||||
const getCanonicalFileName = createGetCanonicalFileName(host.useCaseSensitiveFileNames());
|
||||
const currentDirectory = host.getCurrentDirectory();
|
||||
const sourceFileLike = createMap<SourceFileLike | false>();
|
||||
const documentPositionMappers = createMap<DocumentPositionMapper>();
|
||||
return { tryGetSourcePosition, tryGetGeneratedPosition, toLineColumnOffset, clearCache };
|
||||
|
||||
function toPath(fileName: string) {
|
||||
return ts.toPath(fileName, currentDirectory, getCanonicalFileName);
|
||||
}
|
||||
|
||||
function scanForSourcemapURL(fileName: string) {
|
||||
const mappedFile = sourceFileLike.get(toPath(fileName));
|
||||
if (!mappedFile) {
|
||||
return;
|
||||
}
|
||||
function getDocumentPositionMapper(fileName: string) {
|
||||
const path = toPath(fileName);
|
||||
const value = documentPositionMappers.get(path);
|
||||
if (value) return value;
|
||||
|
||||
return tryGetSourceMappingURL(mappedFile.text, getLineStarts(mappedFile));
|
||||
}
|
||||
|
||||
function convertDocumentToSourceMapper(file: SourceFileLike, contents: string, mapFileName: string) {
|
||||
const map = tryParseRawSourceMap(contents);
|
||||
if (!map || !map.sources || !map.file || !map.mappings) {
|
||||
// obviously invalid map
|
||||
return file.sourceMapper = identitySourceMapConsumer;
|
||||
let mapper: DocumentPositionMapper | undefined;
|
||||
if (host.getDocumentPositionMapper) {
|
||||
mapper = host.getDocumentPositionMapper(fileName);
|
||||
}
|
||||
|
||||
return file.sourceMapper = createDocumentPositionMapper({
|
||||
getSourceFileLike,
|
||||
getCanonicalFileName,
|
||||
log: s => host.log(s),
|
||||
}, map, mapFileName);
|
||||
}
|
||||
|
||||
function getSourceMapper(fileName: string, file: SourceFileLike): DocumentPositionMapper {
|
||||
if (file.sourceMapper) {
|
||||
return file.sourceMapper;
|
||||
else if (host.readFile) {
|
||||
const file = getSourceFileLike(fileName);
|
||||
mapper = file && ts.getDocumentPositionMapper({
|
||||
getSourceFileLike,
|
||||
getCanonicalFileName,
|
||||
log: s => host.log(s),
|
||||
readMapFile: f => !host.fileExists || host.fileExists(f) ? host.readFile!(f) : undefined
|
||||
}, fileName, getLineInfo(file.text, getLineStarts(file)));
|
||||
}
|
||||
let mapFileName = scanForSourcemapURL(fileName);
|
||||
if (mapFileName) {
|
||||
const match = base64UrlRegExp.exec(mapFileName);
|
||||
if (match) {
|
||||
if (match[1]) {
|
||||
const base64Object = match[1];
|
||||
return convertDocumentToSourceMapper(file, base64decode(sys, base64Object), fileName);
|
||||
}
|
||||
// Not a data URL we can parse, skip it
|
||||
mapFileName = undefined;
|
||||
}
|
||||
}
|
||||
const possibleMapLocations: string[] = [];
|
||||
if (mapFileName) {
|
||||
possibleMapLocations.push(mapFileName);
|
||||
}
|
||||
possibleMapLocations.push(fileName + ".map");
|
||||
for (const location of possibleMapLocations) {
|
||||
const mapFileName = getNormalizedAbsolutePath(location, getDirectoryPath(fileName));
|
||||
if (host.fileExists(mapFileName)) {
|
||||
return convertDocumentToSourceMapper(file, host.readFile(mapFileName)!, mapFileName); // TODO: GH#18217
|
||||
}
|
||||
}
|
||||
return file.sourceMapper = identitySourceMapConsumer;
|
||||
documentPositionMappers.set(path, mapper || identitySourceMapConsumer);
|
||||
return mapper || identitySourceMapConsumer;
|
||||
}
|
||||
|
||||
function tryGetSourcePosition(info: DocumentPosition): DocumentPosition | undefined {
|
||||
@ -87,8 +59,8 @@ namespace ts {
|
||||
const file = getSourceFile(info.fileName);
|
||||
if (!file) return undefined;
|
||||
|
||||
const newLoc = getSourceMapper(info.fileName, file).getSourcePosition(info);
|
||||
return newLoc === info ? undefined : tryGetSourcePosition(newLoc) || newLoc;
|
||||
const newLoc = getDocumentPositionMapper(info.fileName).getSourcePosition(info);
|
||||
return !newLoc || newLoc === info ? undefined : tryGetSourcePosition(newLoc) || newLoc;
|
||||
}
|
||||
|
||||
function tryGetGeneratedPosition(info: DocumentPosition): DocumentPosition | undefined {
|
||||
@ -106,10 +78,7 @@ namespace ts {
|
||||
getDeclarationEmitOutputFilePathWorker(info.fileName, program.getCompilerOptions(), currentDirectory, program.getCommonSourceDirectory(), getCanonicalFileName);
|
||||
if (declarationPath === undefined) return undefined;
|
||||
|
||||
const declarationFile = getSourceFileLikeFromCache(declarationPath);
|
||||
if (!declarationFile) return undefined;
|
||||
|
||||
const newLoc = getSourceMapper(declarationPath, declarationFile).getGeneratedPosition(info);
|
||||
const newLoc = getDocumentPositionMapper(declarationPath).getGeneratedPosition(info);
|
||||
return newLoc === info ? undefined : newLoc;
|
||||
}
|
||||
|
||||
@ -123,42 +92,92 @@ namespace ts {
|
||||
return file && file.resolvedPath === path ? file : undefined;
|
||||
}
|
||||
|
||||
function getSourceFileLikeFromCache(fileName: string): SourceFileLike | undefined {
|
||||
function getOrCreateSourceFileLike(fileName: string): SourceFileLike | undefined {
|
||||
const path = toPath(fileName);
|
||||
const fileFromCache = sourceFileLike.get(path);
|
||||
if (fileFromCache !== undefined) return fileFromCache ? fileFromCache : undefined;
|
||||
|
||||
// TODO: should ask host instead?
|
||||
if (!host.fileExists(path)) {
|
||||
if (!host.readFile || host.fileExists && !host.fileExists(path)) {
|
||||
sourceFileLike.set(path, false);
|
||||
return undefined;
|
||||
}
|
||||
|
||||
// And failing that, check the disk
|
||||
const text = host.readFile(path);
|
||||
const file: SourceFileLike | false = text ? {
|
||||
text,
|
||||
lineMap: undefined,
|
||||
getLineAndCharacterOfPosition(pos: number) {
|
||||
return computeLineAndCharacterOfPosition(getLineStarts(this as SourceFileLike), pos);
|
||||
}
|
||||
} : false;
|
||||
const file = text ? createSourceFileLike(text) : false;
|
||||
sourceFileLike.set(path, file);
|
||||
return file ? file : undefined;
|
||||
}
|
||||
|
||||
// This can be called from source mapper in either source program or program that includes generated file
|
||||
function getSourceFileLike(fileName: string) {
|
||||
return getSourceFile(fileName) || getSourceFileLikeFromCache(fileName);
|
||||
return !host.getSourceFileLike ?
|
||||
getSourceFile(fileName) || getOrCreateSourceFileLike(fileName) :
|
||||
host.getSourceFileLike(fileName);
|
||||
}
|
||||
|
||||
function toLineColumnOffset(fileName: string, position: number): LineAndCharacter {
|
||||
// TODO:: shkamat
|
||||
const file = getSourceFileLike(fileName)!; // TODO: GH#18217
|
||||
return file.getLineAndCharacterOfPosition(position);
|
||||
}
|
||||
|
||||
function clearCache(): void {
|
||||
sourceFileLike.clear();
|
||||
documentPositionMappers.clear();
|
||||
}
|
||||
}
|
||||
|
||||
export interface GetDocumentPositionMapperHost extends DocumentPositionMapperHost {
|
||||
readMapFile(fileName: string): string | undefined;
|
||||
}
|
||||
|
||||
export function getDocumentPositionMapper(host: GetDocumentPositionMapperHost, generatedFileName: string, generatedFileLineInfo: LineInfo) {
|
||||
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);
|
||||
}
|
||||
// Not a data URL we can parse, skip it
|
||||
mapFileName = undefined;
|
||||
}
|
||||
}
|
||||
const possibleMapLocations: string[] = [];
|
||||
if (mapFileName) {
|
||||
possibleMapLocations.push(mapFileName);
|
||||
}
|
||||
possibleMapLocations.push(generatedFileName + ".map");
|
||||
for (const location of possibleMapLocations) {
|
||||
const mapFileName = getNormalizedAbsolutePath(location, getDirectoryPath(generatedFileName));
|
||||
const mapFileContents = host.readMapFile(mapFileName);
|
||||
if (mapFileContents) {
|
||||
return convertDocumentToSourceMapper(host, mapFileContents, mapFileName);
|
||||
}
|
||||
}
|
||||
return undefined;
|
||||
}
|
||||
|
||||
function convertDocumentToSourceMapper(host: DocumentPositionMapperHost, contents: string, mapFileName: string) {
|
||||
const map = tryParseRawSourceMap(contents);
|
||||
if (!map || !map.sources || !map.file || !map.mappings) {
|
||||
// obviously invalid map
|
||||
return undefined;
|
||||
}
|
||||
|
||||
return createDocumentPositionMapper(host, map, mapFileName);
|
||||
}
|
||||
|
||||
function createSourceFileLike(text: string, lineMap?: SourceFileLike["lineMap"]): SourceFileLike {
|
||||
return {
|
||||
text,
|
||||
lineMap,
|
||||
getLineAndCharacterOfPosition(pos: number) {
|
||||
return computeLineAndCharacterOfPosition(getLineStarts(this), pos);
|
||||
}
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
@ -91,7 +91,6 @@ namespace ts {
|
||||
|
||||
export interface SourceFileLike {
|
||||
getLineAndCharacterOfPosition(pos: number): LineAndCharacter;
|
||||
/*@internal*/ sourceMapper?: DocumentPositionMapper;
|
||||
}
|
||||
|
||||
export interface SourceMapSource {
|
||||
@ -233,6 +232,11 @@ namespace ts {
|
||||
installPackage?(options: InstallPackageOptions): Promise<ApplyCodeActionCommandResult>;
|
||||
/* @internal */ inspectValue?(options: InspectValueOptions): Promise<ValueInfo>;
|
||||
writeFile?(fileName: string, content: string): void;
|
||||
|
||||
/* @internal */
|
||||
getDocumentPositionMapper?(fileName: string): DocumentPositionMapper | undefined;
|
||||
/* @internal */
|
||||
getSourceFileLike?(fileName: string): SourceFileLike | undefined;
|
||||
}
|
||||
|
||||
/* @internal */
|
||||
|
||||
@ -60,7 +60,7 @@ namespace ts.textStorage {
|
||||
ts1.useText();
|
||||
assert.isFalse(ts1.hasScriptVersionCache_TestOnly(), "should not have script version cache - 2");
|
||||
|
||||
ts1.getLineInfo(0);
|
||||
ts1.getAbsolutePositionAndLineText(0);
|
||||
assert.isTrue(ts1.hasScriptVersionCache_TestOnly(), "have script version cache - 2");
|
||||
});
|
||||
|
||||
|
||||
@ -8046,7 +8046,6 @@ declare namespace ts.server {
|
||||
readonly containingProjects: Project[];
|
||||
private formatSettings;
|
||||
private preferences;
|
||||
private textStorage;
|
||||
constructor(host: ServerHost, fileName: NormalizedPath, scriptKind: ScriptKind, hasMixedContent: boolean, path: Path, initialVersion?: ScriptInfoVersion);
|
||||
isScriptOpen(): boolean;
|
||||
open(newText: string): void;
|
||||
@ -8211,6 +8210,7 @@ declare namespace ts.server {
|
||||
getGlobalProjectErrors(): ReadonlyArray<Diagnostic>;
|
||||
getAllProjectErrors(): ReadonlyArray<Diagnostic>;
|
||||
getLanguageService(ensureSynchronized?: boolean): LanguageService;
|
||||
private readMapFile;
|
||||
private shouldEmitFile;
|
||||
getCompileOnSaveAffectedFileList(scriptInfo: ScriptInfo): string[];
|
||||
/**
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user