mirror of
https://github.com/microsoft/TypeScript.git
synced 2025-11-18 17:21:48 +00:00
introduce Path as branded string type, switch FileMap to use Path
This commit is contained in:
+33
-23
@@ -17,45 +17,55 @@ namespace ts {
|
||||
True = -1
|
||||
}
|
||||
|
||||
export function createFileMap<T>(getCanonicalFileName: (fileName: string) => string, currentDirectory: string): FileMap<T> {
|
||||
export function createFileMap<T>(keyMapper?: (key: string) => string): FileMap<T> {
|
||||
let files: Map<T> = {};
|
||||
return {
|
||||
get,
|
||||
set,
|
||||
contains,
|
||||
remove,
|
||||
clear,
|
||||
forEachValue: forEachValueInMap
|
||||
getPath,
|
||||
setPath,
|
||||
containsPath,
|
||||
removePath,
|
||||
forEachValue: forEachValueInMap,
|
||||
clear
|
||||
};
|
||||
|
||||
function set(fileName: string, value: T) {
|
||||
files[normalizeKey(fileName)] = value;
|
||||
function forEachValueInMap(f: (key: Path, value: T) => void) {
|
||||
for (let key in files) {
|
||||
f(<Path>key, files[key]);
|
||||
}
|
||||
}
|
||||
|
||||
function get(fileName: string) {
|
||||
return files[normalizeKey(fileName)];
|
||||
// path should already be well-formed so it does not need to be normalized
|
||||
function getPath(path: Path): T {
|
||||
return files[toKey(path)];
|
||||
}
|
||||
|
||||
function contains(fileName: string) {
|
||||
return hasProperty(files, normalizeKey(fileName));
|
||||
function setPath(path: Path, value: T) {
|
||||
files[toKey(path)] = value;
|
||||
}
|
||||
|
||||
function remove (fileName: string) {
|
||||
let key = normalizeKey(fileName);
|
||||
function containsPath(path: Path) {
|
||||
return hasProperty(files, toKey(path));
|
||||
}
|
||||
|
||||
function removePath(path: Path) {
|
||||
const key = toKey(path);
|
||||
delete files[key];
|
||||
}
|
||||
|
||||
function forEachValueInMap(f: (value: T) => void) {
|
||||
forEachValue(files, f);
|
||||
}
|
||||
|
||||
function normalizeKey(key: string) {
|
||||
return getCanonicalFileName(getNormalizedAbsolutePath(key, currentDirectory));
|
||||
}
|
||||
|
||||
function clear() {
|
||||
files = {};
|
||||
}
|
||||
|
||||
function toKey(path: Path): string {
|
||||
return keyMapper ? keyMapper(path) : path;
|
||||
}
|
||||
}
|
||||
|
||||
export function toPath(fileName: string, basePath: string, getCanonicalFileName: (path: string) => string): Path {
|
||||
const nonCanonicalizedPath = isRootedDiskPath(fileName)
|
||||
? normalizePath(fileName)
|
||||
: getNormalizedAbsolutePath(fileName, basePath);
|
||||
return <Path>getCanonicalFileName(nonCanonicalizedPath);
|
||||
}
|
||||
|
||||
export const enum Comparison {
|
||||
|
||||
+21
-23
@@ -346,10 +346,10 @@ namespace ts {
|
||||
? ((moduleNames: string[], containingFile: string) => host.resolveModuleNames(moduleNames, containingFile))
|
||||
: ((moduleNames: string[], containingFile: string) => map(moduleNames, moduleName => resolveModuleName(moduleName, containingFile, options, host).resolvedModule));
|
||||
|
||||
let filesByName = createFileMap<SourceFile>(getCanonicalFileName, currentDirectory);
|
||||
let filesByName = createFileMap<SourceFile>();
|
||||
// stores 'filename -> file association' ignoring case
|
||||
// used to track cases when two file names differ only in casing
|
||||
let filesByNameIgnoreCase = host.useCaseSensitiveFileNames() ? createFileMap<SourceFile>(fileName => fileName.toLowerCase(), currentDirectory) : undefined;
|
||||
let filesByNameIgnoreCase = host.useCaseSensitiveFileNames() ? createFileMap<SourceFile>(fileName => fileName.toLowerCase()) : undefined;
|
||||
|
||||
if (oldProgram) {
|
||||
// check properties that can affect structure of the program or module resolution strategy
|
||||
@@ -384,7 +384,7 @@ namespace ts {
|
||||
|
||||
program = {
|
||||
getRootFileNames: () => rootNames,
|
||||
getSourceFile: getSourceFile,
|
||||
getSourceFile,
|
||||
getSourceFiles: () => files,
|
||||
getCompilerOptions: () => options,
|
||||
getSyntacticDiagnostics,
|
||||
@@ -435,7 +435,7 @@ namespace ts {
|
||||
|
||||
// check if program source files has changed in the way that can affect structure of the program
|
||||
let newSourceFiles: SourceFile[] = [];
|
||||
let normalizedAbsoluteFileNames: string[] = [];
|
||||
let filePaths: Path[] = [];
|
||||
let modifiedSourceFiles: SourceFile[] = [];
|
||||
|
||||
for (let oldSourceFile of oldProgram.getSourceFiles()) {
|
||||
@@ -444,8 +444,8 @@ namespace ts {
|
||||
return false;
|
||||
}
|
||||
|
||||
const normalizedAbsolutePath = getNormalizedAbsolutePath(newSourceFile.fileName, currentDirectory);
|
||||
normalizedAbsoluteFileNames.push(normalizedAbsolutePath);
|
||||
newSourceFile.path = oldSourceFile.path;
|
||||
filePaths.push(newSourceFile.path);
|
||||
|
||||
if (oldSourceFile !== newSourceFile) {
|
||||
if (oldSourceFile.hasNoDefaultLib !== newSourceFile.hasNoDefaultLib) {
|
||||
@@ -469,7 +469,7 @@ namespace ts {
|
||||
|
||||
if (resolveModuleNamesWorker) {
|
||||
let moduleNames = map(newSourceFile.imports, name => name.text);
|
||||
let resolutions = resolveModuleNamesWorker(moduleNames, normalizedAbsolutePath);
|
||||
let resolutions = resolveModuleNamesWorker(moduleNames, getNormalizedAbsolutePath(newSourceFile.fileName, currentDirectory));
|
||||
// ensure that module resolution results are still correct
|
||||
for (let i = 0; i < moduleNames.length; ++i) {
|
||||
let newResolution = resolutions[i];
|
||||
@@ -500,7 +500,7 @@ namespace ts {
|
||||
|
||||
// update fileName -> file mapping
|
||||
for (let i = 0, len = newSourceFiles.length; i < len; ++i) {
|
||||
filesByName.set(normalizedAbsoluteFileNames[i], newSourceFiles[i]);
|
||||
filesByName.setPath(filePaths[i], newSourceFiles[i]);
|
||||
}
|
||||
|
||||
files = newSourceFiles;
|
||||
@@ -570,7 +570,7 @@ namespace ts {
|
||||
}
|
||||
|
||||
function getSourceFile(fileName: string): SourceFile {
|
||||
return filesByName.get(getNormalizedAbsolutePath(fileName, currentDirectory));
|
||||
return filesByName.getPath(toPath(fileName, currentDirectory, getCanonicalFileName));
|
||||
}
|
||||
|
||||
function getDiagnosticsHelper(
|
||||
@@ -741,7 +741,7 @@ namespace ts {
|
||||
diagnostic = Diagnostics.File_0_has_unsupported_extension_The_only_supported_extensions_are_1;
|
||||
diagnosticArgument = [fileName, "'" + supportedExtensions.join("', '") + "'"];
|
||||
}
|
||||
else if (!findSourceFile(fileName, getNormalizedAbsolutePath(fileName, currentDirectory), isDefaultLib, refFile, refPos, refEnd)) {
|
||||
else if (!findSourceFile(fileName, toPath(fileName, currentDirectory, getCanonicalFileName), isDefaultLib, refFile, refPos, refEnd)) {
|
||||
diagnostic = Diagnostics.File_0_not_found;
|
||||
diagnosticArgument = [fileName];
|
||||
}
|
||||
@@ -751,13 +751,13 @@ namespace ts {
|
||||
}
|
||||
}
|
||||
else {
|
||||
let nonTsFile: SourceFile = options.allowNonTsExtensions && findSourceFile(fileName, getNormalizedAbsolutePath(fileName, currentDirectory), isDefaultLib, refFile, refPos, refEnd);
|
||||
let nonTsFile: SourceFile = options.allowNonTsExtensions && findSourceFile(fileName, toPath(fileName, currentDirectory, getCanonicalFileName), isDefaultLib, refFile, refPos, refEnd);
|
||||
if (!nonTsFile) {
|
||||
if (options.allowNonTsExtensions) {
|
||||
diagnostic = Diagnostics.File_0_not_found;
|
||||
diagnosticArgument = [fileName];
|
||||
}
|
||||
else if (!forEach(supportedExtensions, extension => findSourceFile(fileName + extension, getNormalizedAbsolutePath(fileName + extension, currentDirectory), isDefaultLib, refFile, refPos, refEnd))) {
|
||||
else if (!forEach(supportedExtensions, extension => findSourceFile(fileName + extension, toPath(fileName + extension, currentDirectory, getCanonicalFileName), isDefaultLib, refFile, refPos, refEnd))) {
|
||||
diagnostic = Diagnostics.File_0_not_found;
|
||||
fileName += ".ts";
|
||||
diagnosticArgument = [fileName];
|
||||
@@ -786,9 +786,9 @@ namespace ts {
|
||||
}
|
||||
|
||||
// Get source file from normalized fileName
|
||||
function findSourceFile(fileName: string, normalizedAbsolutePath: string, isDefaultLib: boolean, refFile?: SourceFile, refPos?: number, refEnd?: number): SourceFile {
|
||||
if (filesByName.contains(normalizedAbsolutePath)) {
|
||||
const file = filesByName.get(normalizedAbsolutePath);
|
||||
function findSourceFile(fileName: string, normalizedAbsolutePath: Path, isDefaultLib: boolean, refFile?: SourceFile, refPos?: number, refEnd?: number): SourceFile {
|
||||
if (filesByName.containsPath(normalizedAbsolutePath)) {
|
||||
const file = filesByName.getPath(normalizedAbsolutePath);
|
||||
// try to check if we've already seen this file but with a different casing in path
|
||||
// NOTE: this only makes sense for case-insensitive file systems
|
||||
if (file && options.forceConsistentCasingInFileNames && getNormalizedAbsolutePath(file.fileName, currentDirectory) !== normalizedAbsolutePath) {
|
||||
@@ -809,16 +809,18 @@ namespace ts {
|
||||
}
|
||||
});
|
||||
|
||||
filesByName.set(normalizedAbsolutePath, file);
|
||||
filesByName.setPath(normalizedAbsolutePath, file);
|
||||
if (file) {
|
||||
file.path = normalizedAbsolutePath;
|
||||
|
||||
if (host.useCaseSensitiveFileNames()) {
|
||||
// for case-sensitive file systems check if we've already seen some file with similar filename ignoring case
|
||||
const existingFile = filesByNameIgnoreCase.get(normalizedAbsolutePath);
|
||||
const existingFile = filesByNameIgnoreCase.getPath(normalizedAbsolutePath);
|
||||
if (existingFile) {
|
||||
reportFileNamesDifferOnlyInCasingError(fileName, existingFile.fileName, refFile, refPos, refEnd);
|
||||
}
|
||||
else {
|
||||
filesByNameIgnoreCase.set(normalizedAbsolutePath, file);
|
||||
filesByNameIgnoreCase.setPath(normalizedAbsolutePath, file);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -865,11 +867,7 @@ namespace ts {
|
||||
let resolution = resolutions[i];
|
||||
setResolvedModule(file, moduleNames[i], resolution);
|
||||
if (resolution && !options.noResolve) {
|
||||
const absoluteImportPath = isRootedDiskPath(resolution.resolvedFileName)
|
||||
? resolution.resolvedFileName
|
||||
: getNormalizedAbsolutePath(resolution.resolvedFileName, currentDirectory);
|
||||
|
||||
const importedFile = findSourceFile(resolution.resolvedFileName, absoluteImportPath, /* isDefaultLib */ false, file, skipTrivia(file.text, file.imports[i].pos), file.imports[i].end);
|
||||
const importedFile = findSourceFile(resolution.resolvedFileName, toPath(resolution.resolvedFileName, currentDirectory, getCanonicalFileName), /* isDefaultLib */ false, file, skipTrivia(file.text, file.imports[i].pos), file.imports[i].end);
|
||||
|
||||
if (importedFile && resolution.isExternalLibraryImport) {
|
||||
if (!isExternalModule(importedFile)) {
|
||||
|
||||
+11
-5
@@ -3,12 +3,17 @@ namespace ts {
|
||||
[index: string]: T;
|
||||
}
|
||||
|
||||
// branded string type used to store absolute, normalized and canonicalized paths
|
||||
// arbitrary file name can be converted to Path via toPath function
|
||||
export type Path = string & { __pathBrand: any };
|
||||
|
||||
export interface FileMap<T> {
|
||||
get(fileName: string): T;
|
||||
set(fileName: string, value: T): void;
|
||||
contains(fileName: string): boolean;
|
||||
remove(fileName: string): void;
|
||||
forEachValue(f: (v: T) => void): void;
|
||||
getPath(fileName: Path): T;
|
||||
setPath(fileName: Path, value: T): void;
|
||||
containsPath(fileName: Path): boolean;
|
||||
removePath(fileName: Path): void;
|
||||
|
||||
forEachValue(f: (key: Path, v: T) => void): void;
|
||||
clear(): void;
|
||||
}
|
||||
|
||||
@@ -1250,6 +1255,7 @@ namespace ts {
|
||||
endOfFileToken: Node;
|
||||
|
||||
fileName: string;
|
||||
/* internal */ path: Path;
|
||||
text: string;
|
||||
|
||||
amdDependencies: {path: string; name: string}[];
|
||||
|
||||
@@ -1357,7 +1357,6 @@ namespace ts {
|
||||
export function tryResolveScriptReference(host: ScriptReferenceHost, sourceFile: SourceFile, reference: FileReference) {
|
||||
if (!host.getCompilerOptions().noResolve) {
|
||||
let referenceFileName = isRootedDiskPath(reference.fileName) ? reference.fileName : combinePaths(getDirectoryPath(sourceFile.fileName), reference.fileName);
|
||||
referenceFileName = getNormalizedAbsolutePath(referenceFileName, host.getCurrentDirectory());
|
||||
return host.getSourceFile(referenceFileName);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -33,8 +33,10 @@ namespace ts.server {
|
||||
defaultProject: Project; // project to use by default for file
|
||||
fileWatcher: FileWatcher;
|
||||
formatCodeOptions = ts.clone(CompilerService.defaultFormatCodeOptions);
|
||||
path: Path;
|
||||
|
||||
constructor(private host: ServerHost, public fileName: string, public content: string, public isOpen = false) {
|
||||
this.path = toPath(fileName, host.getCurrentDirectory(), createGetCanonicalFileName(host.useCaseSensitiveFileNames));
|
||||
this.svc = ScriptVersionCache.fromString(host, content);
|
||||
}
|
||||
|
||||
@@ -90,11 +92,12 @@ namespace ts.server {
|
||||
roots: ScriptInfo[] = [];
|
||||
private resolvedModuleNames: ts.FileMap<Map<TimestampedResolvedModule>>;
|
||||
private moduleResolutionHost: ts.ModuleResolutionHost;
|
||||
private getCanonicalFileName: (fileName: string) => string;
|
||||
|
||||
constructor(public host: ServerHost, public project: Project) {
|
||||
const getCanonicalFileName = createGetCanonicalFileName(host.useCaseSensitiveFileNames);
|
||||
this.resolvedModuleNames = createFileMap<Map<TimestampedResolvedModule>>(getCanonicalFileName, host.getCurrentDirectory());
|
||||
this.filenameToScript = createFileMap<ScriptInfo>(getCanonicalFileName, host.getCurrentDirectory());
|
||||
this.getCanonicalFileName = createGetCanonicalFileName(host.useCaseSensitiveFileNames);
|
||||
this.resolvedModuleNames = createFileMap<Map<TimestampedResolvedModule>>();
|
||||
this.filenameToScript = createFileMap<ScriptInfo>();
|
||||
this.moduleResolutionHost = {
|
||||
fileExists: fileName => this.fileExists(fileName),
|
||||
readFile: fileName => this.host.readFile(fileName)
|
||||
@@ -102,7 +105,8 @@ namespace ts.server {
|
||||
}
|
||||
|
||||
resolveModuleNames(moduleNames: string[], containingFile: string): ResolvedModule[] {
|
||||
let currentResolutionsInFile = this.resolvedModuleNames.get(containingFile);
|
||||
let path = toPath(containingFile, this.host.getCurrentDirectory(), this.getCanonicalFileName);
|
||||
let currentResolutionsInFile = this.resolvedModuleNames.getPath(path);
|
||||
|
||||
let newResolutions: Map<TimestampedResolvedModule> = {};
|
||||
let resolvedModules: ResolvedModule[] = [];
|
||||
@@ -131,7 +135,7 @@ namespace ts.server {
|
||||
}
|
||||
|
||||
// replace old results with a new one
|
||||
this.resolvedModuleNames.set(containingFile, newResolutions);
|
||||
this.resolvedModuleNames.setPath(path, newResolutions);
|
||||
return resolvedModules;
|
||||
|
||||
function moduleResolutionIsValid(resolution: TimestampedResolvedModule): boolean {
|
||||
@@ -201,34 +205,35 @@ namespace ts.server {
|
||||
|
||||
removeReferencedFile(info: ScriptInfo) {
|
||||
if (!info.isOpen) {
|
||||
this.filenameToScript.remove(info.fileName);
|
||||
this.resolvedModuleNames.remove(info.fileName);
|
||||
this.filenameToScript.removePath(info.path);
|
||||
this.resolvedModuleNames.removePath(info.path);
|
||||
}
|
||||
}
|
||||
|
||||
getScriptInfo(filename: string): ScriptInfo {
|
||||
let scriptInfo = this.filenameToScript.get(filename);
|
||||
let path = toPath(filename, this.host.getCurrentDirectory(), this.getCanonicalFileName);
|
||||
let scriptInfo = this.filenameToScript.getPath(path);
|
||||
if (!scriptInfo) {
|
||||
scriptInfo = this.project.openReferencedFile(filename);
|
||||
if (scriptInfo) {
|
||||
this.filenameToScript.set(scriptInfo.fileName, scriptInfo);
|
||||
this.filenameToScript.setPath(path, scriptInfo);
|
||||
}
|
||||
}
|
||||
return scriptInfo;
|
||||
}
|
||||
|
||||
addRoot(info: ScriptInfo) {
|
||||
if (!this.filenameToScript.contains(info.fileName)) {
|
||||
this.filenameToScript.set(info.fileName, info);
|
||||
if (!this.filenameToScript.containsPath(info.path)) {
|
||||
this.filenameToScript.setPath(info.path, info);
|
||||
this.roots.push(info);
|
||||
}
|
||||
}
|
||||
|
||||
removeRoot(info: ScriptInfo) {
|
||||
if (!this.filenameToScript.contains(info.fileName)) {
|
||||
this.filenameToScript.remove(info.fileName);
|
||||
if (!this.filenameToScript.containsPath(info.path)) {
|
||||
this.filenameToScript.removePath(info.path);
|
||||
this.roots = copyListRemovingItem(info, this.roots);
|
||||
this.resolvedModuleNames.remove(info.fileName);
|
||||
this.resolvedModuleNames.removePath(info.path);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -277,7 +282,8 @@ namespace ts.server {
|
||||
* @param line 1 based index
|
||||
*/
|
||||
lineToTextSpan(filename: string, line: number): ts.TextSpan {
|
||||
const script: ScriptInfo = this.filenameToScript.get(filename);
|
||||
let path = toPath(filename, this.host.getCurrentDirectory(), this.getCanonicalFileName);
|
||||
const script: ScriptInfo = this.filenameToScript.getPath(path);
|
||||
const index = script.snap().index;
|
||||
|
||||
const lineInfo = index.lineNumberToInfo(line + 1);
|
||||
@@ -297,7 +303,8 @@ namespace ts.server {
|
||||
* @param offset 1 based index
|
||||
*/
|
||||
lineOffsetToPosition(filename: string, line: number, offset: number): number {
|
||||
const script: ScriptInfo = this.filenameToScript.get(filename);
|
||||
let path = toPath(filename, this.host.getCurrentDirectory(), this.getCanonicalFileName);
|
||||
const script: ScriptInfo = this.filenameToScript.getPath(path);
|
||||
const index = script.snap().index;
|
||||
|
||||
const lineInfo = index.lineNumberToInfo(line);
|
||||
@@ -310,7 +317,8 @@ namespace ts.server {
|
||||
* @param offset 1-based index
|
||||
*/
|
||||
positionToLineOffset(filename: string, position: number): ILineInfo {
|
||||
const script: ScriptInfo = this.filenameToScript.get(filename);
|
||||
let path = toPath(filename, this.host.getCurrentDirectory(), this.getCanonicalFileName);
|
||||
const script: ScriptInfo = this.filenameToScript.getPath(path);
|
||||
const index = script.snap().index;
|
||||
const lineOffset = index.charOffsetToLineNumberAndPos(position);
|
||||
return { line: lineOffset.line, offset: lineOffset.offset + 1 };
|
||||
|
||||
+39
-33
@@ -773,6 +773,7 @@ namespace ts {
|
||||
class SourceFileObject extends NodeObject implements SourceFile {
|
||||
public _declarationBrand: any;
|
||||
public fileName: string;
|
||||
public path: Path;
|
||||
public text: string;
|
||||
public scriptSnapshot: IScriptSnapshot;
|
||||
public lineMap: number[];
|
||||
@@ -1695,15 +1696,17 @@ namespace ts {
|
||||
class HostCache {
|
||||
private fileNameToEntry: FileMap<HostFileInformation>;
|
||||
private _compilationSettings: CompilerOptions;
|
||||
private currentDirectory: string;
|
||||
|
||||
constructor(private host: LanguageServiceHost, getCanonicalFileName: (fileName: string) => string) {
|
||||
constructor(private host: LanguageServiceHost, private getCanonicalFileName: (fileName: string) => string) {
|
||||
// script id => script index
|
||||
this.fileNameToEntry = createFileMap<HostFileInformation>(getCanonicalFileName, host.getCurrentDirectory());
|
||||
this.currentDirectory = host.getCurrentDirectory();
|
||||
this.fileNameToEntry = createFileMap<HostFileInformation>();
|
||||
|
||||
// Initialize the list with the root file names
|
||||
let rootFileNames = host.getScriptFileNames();
|
||||
for (let fileName of rootFileNames) {
|
||||
this.createEntry(fileName);
|
||||
this.createEntry(fileName, toPath(fileName, this.currentDirectory, getCanonicalFileName));
|
||||
}
|
||||
|
||||
// store the compilation settings
|
||||
@@ -1714,7 +1717,7 @@ namespace ts {
|
||||
return this._compilationSettings;
|
||||
}
|
||||
|
||||
private createEntry(fileName: string) {
|
||||
private createEntry(fileName: string, path: Path) {
|
||||
let entry: HostFileInformation;
|
||||
let scriptSnapshot = this.host.getScriptSnapshot(fileName);
|
||||
if (scriptSnapshot) {
|
||||
@@ -1725,30 +1728,31 @@ namespace ts {
|
||||
};
|
||||
}
|
||||
|
||||
this.fileNameToEntry.set(fileName, entry);
|
||||
this.fileNameToEntry.setPath(path, entry);
|
||||
return entry;
|
||||
}
|
||||
|
||||
private getEntry(fileName: string): HostFileInformation {
|
||||
return this.fileNameToEntry.get(fileName);
|
||||
private getEntry(path: Path): HostFileInformation {
|
||||
return this.fileNameToEntry.getPath(path);
|
||||
}
|
||||
|
||||
private contains(fileName: string): boolean {
|
||||
return this.fileNameToEntry.contains(fileName);
|
||||
private contains(path: Path): boolean {
|
||||
return this.fileNameToEntry.containsPath(path);
|
||||
}
|
||||
|
||||
public getOrCreateEntry(fileName: string): HostFileInformation {
|
||||
if (this.contains(fileName)) {
|
||||
return this.getEntry(fileName);
|
||||
let path = toPath(fileName, this.currentDirectory, this.getCanonicalFileName)
|
||||
if (this.contains(path)) {
|
||||
return this.getEntry(path);
|
||||
}
|
||||
|
||||
return this.createEntry(fileName);
|
||||
return this.createEntry(fileName, path);
|
||||
}
|
||||
|
||||
public getRootFileNames(): string[] {
|
||||
let fileNames: string[] = [];
|
||||
|
||||
this.fileNameToEntry.forEachValue(value => {
|
||||
this.fileNameToEntry.forEachValue((path, value) => {
|
||||
if (value) {
|
||||
fileNames.push(value.hostFileName);
|
||||
}
|
||||
@@ -1757,13 +1761,13 @@ namespace ts {
|
||||
return fileNames;
|
||||
}
|
||||
|
||||
public getVersion(fileName: string): string {
|
||||
let file = this.getEntry(fileName);
|
||||
public getVersion(path: Path): string {
|
||||
let file = this.getEntry(path);
|
||||
return file && file.version;
|
||||
}
|
||||
|
||||
public getScriptSnapshot(fileName: string): IScriptSnapshot {
|
||||
let file = this.getEntry(fileName);
|
||||
public getScriptSnapshot(path: Path): IScriptSnapshot {
|
||||
let file = this.getEntry(path);
|
||||
return file && file.scriptSnapshot;
|
||||
}
|
||||
}
|
||||
@@ -2007,7 +2011,7 @@ namespace ts {
|
||||
let key = getKeyFromCompilationSettings(settings);
|
||||
let bucket = lookUp(buckets, key);
|
||||
if (!bucket && createIfMissing) {
|
||||
buckets[key] = bucket = createFileMap<DocumentRegistryEntry>(getCanonicalFileName, currentDirectory);
|
||||
buckets[key] = bucket = createFileMap<DocumentRegistryEntry>();
|
||||
}
|
||||
return bucket;
|
||||
}
|
||||
@@ -2016,14 +2020,13 @@ namespace ts {
|
||||
let bucketInfoArray = Object.keys(buckets).filter(name => name && name.charAt(0) === '_').map(name => {
|
||||
let entries = lookUp(buckets, name);
|
||||
let sourceFiles: { name: string; refCount: number; references: string[]; }[] = [];
|
||||
for (let i in entries) {
|
||||
let entry = entries.get(i);
|
||||
entries.forEachValue((key, entry) => {
|
||||
sourceFiles.push({
|
||||
name: i,
|
||||
name: key,
|
||||
refCount: entry.languageServiceRefCount,
|
||||
references: entry.owners.slice(0)
|
||||
});
|
||||
}
|
||||
});
|
||||
sourceFiles.sort((x, y) => y.refCount - x.refCount);
|
||||
return {
|
||||
bucket: name,
|
||||
@@ -2049,7 +2052,8 @@ namespace ts {
|
||||
acquiring: boolean): SourceFile {
|
||||
|
||||
let bucket = getBucketForCompilationSettings(compilationSettings, /*createIfMissing*/ true);
|
||||
let entry = bucket.get(fileName);
|
||||
let path = toPath(fileName, currentDirectory, getCanonicalFileName);
|
||||
let entry = bucket.getPath(path);
|
||||
if (!entry) {
|
||||
Debug.assert(acquiring, "How could we be trying to update a document that the registry doesn't have?");
|
||||
|
||||
@@ -2061,7 +2065,7 @@ namespace ts {
|
||||
languageServiceRefCount: 0,
|
||||
owners: []
|
||||
};
|
||||
bucket.set(fileName, entry);
|
||||
bucket.setPath(path, entry);
|
||||
}
|
||||
else {
|
||||
// We have an entry for this file. However, it may be for a different version of
|
||||
@@ -2089,12 +2093,14 @@ namespace ts {
|
||||
let bucket = getBucketForCompilationSettings(compilationSettings, false);
|
||||
Debug.assert(bucket !== undefined);
|
||||
|
||||
let entry = bucket.get(fileName);
|
||||
let path = toPath(fileName, currentDirectory, getCanonicalFileName);
|
||||
|
||||
let entry = bucket.getPath(path);
|
||||
entry.languageServiceRefCount--;
|
||||
|
||||
Debug.assert(entry.languageServiceRefCount >= 0);
|
||||
if (entry.languageServiceRefCount === 0) {
|
||||
bucket.remove(fileName);
|
||||
bucket.removePath(path);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -2567,6 +2573,7 @@ namespace ts {
|
||||
let useCaseSensitivefileNames = false;
|
||||
let cancellationToken = new CancellationTokenObject(host.getCancellationToken && host.getCancellationToken());
|
||||
|
||||
let currentDirectory = host.getCurrentDirectory();
|
||||
// Check if the localized messages json is set, otherwise query the host for it
|
||||
if (!localizedDiagnosticMessages && host.getLocalizedDiagnosticMessages) {
|
||||
localizedDiagnosticMessages = host.getLocalizedDiagnosticMessages();
|
||||
@@ -2581,8 +2588,7 @@ namespace ts {
|
||||
let getCanonicalFileName = createGetCanonicalFileName(useCaseSensitivefileNames);
|
||||
|
||||
function getValidSourceFile(fileName: string): SourceFile {
|
||||
fileName = normalizeSlashes(fileName);
|
||||
let sourceFile = program.getSourceFile(getCanonicalFileName(fileName));
|
||||
let sourceFile = program.getSourceFile(fileName);
|
||||
if (!sourceFile) {
|
||||
throw new Error("Could not find file: '" + fileName + "'.");
|
||||
}
|
||||
@@ -2643,7 +2649,7 @@ namespace ts {
|
||||
getNewLine: () => getNewLineOrDefaultFromHost(host),
|
||||
getDefaultLibFileName: (options) => host.getDefaultLibFileName(options),
|
||||
writeFile: (fileName, data, writeByteOrderMark) => { },
|
||||
getCurrentDirectory: () => host.getCurrentDirectory(),
|
||||
getCurrentDirectory: () => currentDirectory,
|
||||
fileExists: (fileName): boolean => {
|
||||
// stub missing host functionality
|
||||
Debug.assert(!host.resolveModuleNames);
|
||||
@@ -2667,9 +2673,8 @@ namespace ts {
|
||||
if (program) {
|
||||
let oldSourceFiles = program.getSourceFiles();
|
||||
for (let oldSourceFile of oldSourceFiles) {
|
||||
let fileName = oldSourceFile.fileName;
|
||||
if (!newProgram.getSourceFile(fileName) || changesInCompilationSettingsAffectSyntax) {
|
||||
documentRegistry.releaseDocument(fileName, oldSettings);
|
||||
if (!newProgram.getSourceFile(oldSourceFile.fileName) || changesInCompilationSettingsAffectSyntax) {
|
||||
documentRegistry.releaseDocument(oldSourceFile.fileName, oldSettings);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -2734,7 +2739,8 @@ namespace ts {
|
||||
}
|
||||
|
||||
function sourceFileUpToDate(sourceFile: SourceFile): boolean {
|
||||
return sourceFile && sourceFile.version === hostCache.getVersion(sourceFile.fileName);
|
||||
let path = sourceFile.path || toPath(sourceFile.fileName, currentDirectory, getCanonicalFileName);
|
||||
return sourceFile && sourceFile.version === hostCache.getVersion(path);
|
||||
}
|
||||
|
||||
function programUpToDate(): boolean {
|
||||
|
||||
Reference in New Issue
Block a user