diff --git a/Jakefile.js b/Jakefile.js index 0aebcff67c0..372058271ca 100644 --- a/Jakefile.js +++ b/Jakefile.js @@ -96,7 +96,7 @@ var servicesSources = [ return path.join(servicesDirectory, f); })); -var serverSources = [ +var serverCoreSources = [ "node.d.ts", "editorServices.ts", "protocol.d.ts", @@ -104,7 +104,9 @@ var serverSources = [ "server.ts" ].map(function (f) { return path.join(serverDirectory, f); -}).concat(servicesSources); +}); + +var serverSources = serverCoreSources.concat(servicesSources); var languageServiceLibrarySources = [ "editorServices.ts", @@ -903,7 +905,9 @@ function lintFileAsync(options, path, cb) { }); } -var lintTargets = compilerSources.concat(harnessCoreSources); +var lintTargets = compilerSources + .concat(harnessCoreSources) + .concat(serverCoreSources); desc("Runs tslint on the compiler sources"); task("lint", ["build-rules"], function() { diff --git a/src/compiler/checker.ts b/src/compiler/checker.ts index ee632f09a2a..821c7ca7e7b 100644 --- a/src/compiler/checker.ts +++ b/src/compiler/checker.ts @@ -12647,7 +12647,7 @@ namespace ts { error(node.expression, Diagnostics.Setters_cannot_return_a_value); } else if (func.kind === SyntaxKind.Constructor) { - if (!isTypeAssignableTo(exprType, returnType)) { + if (!checkTypeAssignableTo(exprType, returnType, node.expression)) { error(node.expression, Diagnostics.Return_type_of_constructor_signature_must_be_assignable_to_the_instance_type_of_the_class); } } diff --git a/src/compiler/core.ts b/src/compiler/core.ts index 68c9bd06825..068ab1865bb 100644 --- a/src/compiler/core.ts +++ b/src/compiler/core.ts @@ -17,45 +17,55 @@ namespace ts { True = -1 } - export function createFileMap(getCanonicalFileName: (fileName: string) => string): FileMap { + export function createFileMap(keyMapper?: (key: string) => string): FileMap { let files: Map = {}; return { get, set, contains, remove, - clear, - forEachValue: forEachValueInMap + 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(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 get(path: Path): T { + return files[toKey(path)]; } - function contains(fileName: string) { - return hasProperty(files, normalizeKey(fileName)); + function set(path: Path, value: T) { + files[toKey(path)] = value; } - function remove (fileName: string) { - let key = normalizeKey(fileName); + function contains(path: Path) { + return hasProperty(files, toKey(path)); + } + + function remove(path: Path) { + const key = toKey(path); delete files[key]; } - function forEachValueInMap(f: (value: T) => void) { - forEachValue(files, f); - } - - function normalizeKey(key: string) { - return getCanonicalFileName(normalizeSlashes(key)); - } - 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 getCanonicalFileName(nonCanonicalizedPath); } export const enum Comparison { diff --git a/src/compiler/program.ts b/src/compiler/program.ts index 6a6e8d5bca6..e34e95e5f37 100644 --- a/src/compiler/program.ts +++ b/src/compiler/program.ts @@ -346,7 +346,7 @@ 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(getCanonicalFileName); + let filesByName = createFileMap(); // stores 'filename -> file association' ignoring case // used to track cases when two file names differ only in casing let filesByNameIgnoreCase = host.useCaseSensitiveFileNames() ? createFileMap(fileName => fileName.toLowerCase()) : undefined; @@ -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.set(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.get(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,7 +786,7 @@ namespace ts { } // Get source file from normalized fileName - function findSourceFile(fileName: string, normalizedAbsolutePath: string, isDefaultLib: boolean, refFile?: SourceFile, refPos?: number, refEnd?: number): SourceFile { + function findSourceFile(fileName: string, normalizedAbsolutePath: Path, isDefaultLib: boolean, refFile?: SourceFile, refPos?: number, refEnd?: number): SourceFile { if (filesByName.contains(normalizedAbsolutePath)) { const file = filesByName.get(normalizedAbsolutePath); // try to check if we've already seen this file but with a different casing in path @@ -811,6 +811,8 @@ namespace ts { filesByName.set(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); @@ -865,14 +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); - - // convert an absolute import path to path that is relative to current directory - // this was host still can locate it but files names in user output will be shorter (and thus look nicer). - const relativePath = getRelativePathToDirectoryOrUrl(currentDirectory, absoluteImportPath, currentDirectory, getCanonicalFileName, false); - const importedFile = findSourceFile(relativePath, 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)) { diff --git a/src/compiler/tsc.ts b/src/compiler/tsc.ts index c493cf8f87f..232360116f3 100644 --- a/src/compiler/tsc.ts +++ b/src/compiler/tsc.ts @@ -81,12 +81,16 @@ namespace ts { return diagnostic.messageText; } - function reportDiagnostic(diagnostic: Diagnostic) { + function reportDiagnostic(diagnostic: Diagnostic, host: CompilerHost) { let output = ""; if (diagnostic.file) { let loc = getLineAndCharacterOfPosition(diagnostic.file, diagnostic.start); - output += `${ diagnostic.file.fileName }(${ loc.line + 1 },${ loc.character + 1 }): `; + const relativeFileName = host + ? convertToRelativePath(diagnostic.file.fileName, host.getCurrentDirectory(), fileName => host.getCanonicalFileName(fileName)) + : diagnostic.file.fileName; + + output += `${ relativeFileName }(${ loc.line + 1 },${ loc.character + 1 }): `; } let category = DiagnosticCategory[diagnostic.category].toLowerCase(); @@ -95,9 +99,9 @@ namespace ts { sys.write(output); } - function reportDiagnostics(diagnostics: Diagnostic[]) { + function reportDiagnostics(diagnostics: Diagnostic[], host: CompilerHost) { for (let i = 0; i < diagnostics.length; i++) { - reportDiagnostic(diagnostics[i]); + reportDiagnostic(diagnostics[i], host); } } @@ -166,7 +170,7 @@ namespace ts { if (commandLine.options.locale) { if (!isJSONSupported()) { - reportDiagnostic(createCompilerDiagnostic(Diagnostics.The_current_host_does_not_support_the_0_option, "--locale")); + reportDiagnostic(createCompilerDiagnostic(Diagnostics.The_current_host_does_not_support_the_0_option, "--locale"), /* compilerHost */ undefined); return sys.exit(ExitStatus.DiagnosticsPresent_OutputsSkipped); } validateLocaleAndSetLanguage(commandLine.options.locale, commandLine.errors); @@ -175,7 +179,7 @@ namespace ts { // If there are any errors due to command line parsing and/or // setting up localization, report them and quit. if (commandLine.errors.length > 0) { - reportDiagnostics(commandLine.errors); + reportDiagnostics(commandLine.errors, compilerHost); return sys.exit(ExitStatus.DiagnosticsPresent_OutputsSkipped); } @@ -185,7 +189,7 @@ namespace ts { } if (commandLine.options.version) { - reportDiagnostic(createCompilerDiagnostic(Diagnostics.Version_0, ts.version)); + reportDiagnostic(createCompilerDiagnostic(Diagnostics.Version_0, ts.version), /* compilerHost */ undefined); return sys.exit(ExitStatus.Success); } @@ -197,12 +201,12 @@ namespace ts { if (commandLine.options.project) { if (!isJSONSupported()) { - reportDiagnostic(createCompilerDiagnostic(Diagnostics.The_current_host_does_not_support_the_0_option, "--project")); + reportDiagnostic(createCompilerDiagnostic(Diagnostics.The_current_host_does_not_support_the_0_option, "--project"), /* compilerHost */ undefined); return sys.exit(ExitStatus.DiagnosticsPresent_OutputsSkipped); } configFileName = normalizePath(combinePaths(commandLine.options.project, "tsconfig.json")); if (commandLine.fileNames.length !== 0) { - reportDiagnostic(createCompilerDiagnostic(Diagnostics.Option_project_cannot_be_mixed_with_source_files_on_a_command_line)); + reportDiagnostic(createCompilerDiagnostic(Diagnostics.Option_project_cannot_be_mixed_with_source_files_on_a_command_line), /* compilerHost */ undefined); return sys.exit(ExitStatus.DiagnosticsPresent_OutputsSkipped); } } @@ -220,7 +224,7 @@ namespace ts { // Firefox has Object.prototype.watch if (commandLine.options.watch && commandLine.options.hasOwnProperty("watch")) { if (!sys.watchFile) { - reportDiagnostic(createCompilerDiagnostic(Diagnostics.The_current_host_does_not_support_the_0_option, "--watch")); + reportDiagnostic(createCompilerDiagnostic(Diagnostics.The_current_host_does_not_support_the_0_option, "--watch"), /* compilerHost */ undefined); return sys.exit(ExitStatus.DiagnosticsPresent_OutputsSkipped); } if (configFileName) { @@ -256,7 +260,7 @@ namespace ts { let configObject = result.config; let configParseResult = parseJsonConfigFileContent(configObject, sys, getDirectoryPath(configFileName)); if (configParseResult.errors.length > 0) { - reportDiagnostics(configParseResult.errors); + reportDiagnostics(configParseResult.errors, /* compilerHost */ undefined); sys.exit(ExitStatus.DiagnosticsPresent_OutputsSkipped); return; } @@ -463,7 +467,7 @@ namespace ts { } } - reportDiagnostics(diagnostics); + reportDiagnostics(diagnostics, compilerHost); // If the user doesn't want us to emit, then we're done at this point. if (compilerOptions.noEmit) { @@ -474,7 +478,7 @@ namespace ts { // Otherwise, emit and report any errors we ran into. let emitOutput = program.emit(); - reportDiagnostics(emitOutput.diagnostics); + reportDiagnostics(emitOutput.diagnostics, compilerHost); // If the emitter didn't emit anything, then pass that value along. if (emitOutput.emitSkipped) { @@ -587,7 +591,7 @@ namespace ts { let currentDirectory = sys.getCurrentDirectory(); let file = normalizePath(combinePaths(currentDirectory, "tsconfig.json")); if (sys.fileExists(file)) { - reportDiagnostic(createCompilerDiagnostic(Diagnostics.A_tsconfig_json_file_is_already_defined_at_Colon_0, file)); + reportDiagnostic(createCompilerDiagnostic(Diagnostics.A_tsconfig_json_file_is_already_defined_at_Colon_0, file), /* compilerHost */ undefined); } else { let compilerOptions = extend(options, defaultInitCompilerOptions); @@ -602,7 +606,7 @@ namespace ts { } sys.writeFile(file, JSON.stringify(configurations, undefined, 4)); - reportDiagnostic(createCompilerDiagnostic(Diagnostics.Successfully_created_a_tsconfig_json_file)); + reportDiagnostic(createCompilerDiagnostic(Diagnostics.Successfully_created_a_tsconfig_json_file), /* compilerHost */ undefined); } return; diff --git a/src/compiler/types.ts b/src/compiler/types.ts index 401f500de65..50d34286fa1 100644 --- a/src/compiler/types.ts +++ b/src/compiler/types.ts @@ -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 { - get(fileName: string): T; - set(fileName: string, value: T): void; - contains(fileName: string): boolean; - remove(fileName: string): void; - forEachValue(f: (v: T) => void): void; + get(fileName: Path): T; + set(fileName: Path, value: T): void; + contains(fileName: Path): boolean; + remove(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}[]; diff --git a/src/compiler/utilities.ts b/src/compiler/utilities.ts index a6e1d062a04..9638b618629 100644 --- a/src/compiler/utilities.ts +++ b/src/compiler/utilities.ts @@ -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); } } @@ -2193,6 +2192,12 @@ namespace ts { return result; } + export function convertToRelativePath(absoluteOrRelativePath: string, basePath: string, getCanonicalFileName: (path: string) => string): string { + return !isRootedDiskPath(absoluteOrRelativePath) + ? absoluteOrRelativePath + : getRelativePathToDirectoryOrUrl(basePath, absoluteOrRelativePath, basePath, getCanonicalFileName, /* isAbsolutePathAnUrl */ false); + } + const carriageReturnLineFeed = "\r\n"; const lineFeed = "\n"; export function getNewLineCharacter(options: CompilerOptions): string { diff --git a/src/harness/projectsRunner.ts b/src/harness/projectsRunner.ts index 036e3e0b054..aca90c92f8e 100644 --- a/src/harness/projectsRunner.ts +++ b/src/harness/projectsRunner.ts @@ -234,12 +234,15 @@ class ProjectRunner extends RunnerBase { } function writeFile(fileName: string, data: string, writeByteOrderMark: boolean) { + // convert file name to rooted name + // if filename is not rooted - concat it with project root and then expand project root relative to current directory let diskFileName = ts.isRootedDiskPath(fileName) ? fileName - : ts.normalizeSlashes(testCase.projectRoot) + "/" + ts.normalizeSlashes(fileName); + : Harness.IO.resolvePath(ts.normalizeSlashes(testCase.projectRoot) + "/" + ts.normalizeSlashes(fileName)); - let diskRelativeName = ts.getRelativePathToDirectoryOrUrl(testCase.projectRoot, diskFileName, - getCurrentDirectory(), Harness.Compiler.getCanonicalFileName, /*isAbsolutePathAnUrl*/ false); + let currentDirectory = getCurrentDirectory(); + // compute file name relative to current directory (expanded project root) + let diskRelativeName = ts.getRelativePathToDirectoryOrUrl(currentDirectory, diskFileName, currentDirectory, Harness.Compiler.getCanonicalFileName, /*isAbsolutePathAnUrl*/ false); if (ts.isRootedDiskPath(diskRelativeName) || diskRelativeName.substr(0, 3) === "../") { // If the generated output file resides in the parent folder or is rooted path, // we need to instead create files that can live in the project reference folder @@ -376,8 +379,12 @@ class ProjectRunner extends RunnerBase { runTest: testCase.runTest, bug: testCase.bug, rootDir: testCase.rootDir, - resolvedInputFiles: ts.map(compilerResult.program.getSourceFiles(), inputFile => inputFile.fileName), - emittedFiles: ts.map(compilerResult.outputFiles, outputFile => outputFile.emittedFileName) + resolvedInputFiles: ts.map(compilerResult.program.getSourceFiles(), inputFile => { + return ts.convertToRelativePath(inputFile.fileName, getCurrentDirectory(), path => Harness.Compiler.getCanonicalFileName(path)); + }), + emittedFiles: ts.map(compilerResult.outputFiles, outputFile => { + return ts.convertToRelativePath(outputFile.emittedFileName, getCurrentDirectory(), path => Harness.Compiler.getCanonicalFileName(path)); + }) }; return resolutionInfo; diff --git a/src/server/editorServices.ts b/src/server/editorServices.ts index eb7bdb0f718..df3b63903c5 100644 --- a/src/server/editorServices.ts +++ b/src/server/editorServices.ts @@ -15,12 +15,12 @@ namespace ts.server { msg(s: string, type?: string): void; } - var lineCollectionCapacity = 4; + const lineCollectionCapacity = 4; function mergeFormatOptions(formatCodeOptions: FormatCodeOptions, formatOptions: protocol.FormatOptions): void { - var hasOwnProperty = Object.prototype.hasOwnProperty; + const hasOwnProperty = Object.prototype.hasOwnProperty; Object.keys(formatOptions).forEach((key) => { - var codeKey = key.charAt(0).toUpperCase() + key.substring(1); + const codeKey = key.charAt(0).toUpperCase() + key.substring(1); if (hasOwnProperty.call(formatCodeOptions, codeKey)) { formatCodeOptions[codeKey] = formatOptions[key]; } @@ -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); } @@ -57,12 +59,12 @@ namespace ts.server { } getText() { - var snap = this.snap(); + const snap = this.snap(); return snap.getText(0, snap.getLength()); } getLineInfo(line: number) { - var snap = this.snap(); + const snap = this.snap(); return snap.index.lineNumberToInfo(line); } @@ -84,17 +86,18 @@ namespace ts.server { } export class LSHost implements ts.LanguageServiceHost { - ls: ts.LanguageService = null; + ls: ts.LanguageService; compilationSettings: ts.CompilerOptions; filenameToScript: ts.FileMap; roots: ScriptInfo[] = []; private resolvedModuleNames: ts.FileMap>; private moduleResolutionHost: ts.ModuleResolutionHost; + private getCanonicalFileName: (fileName: string) => string; constructor(public host: ServerHost, public project: Project) { - var getCanonicalFileName = createGetCanonicalFileName(host.useCaseSensitiveFileNames); - this.resolvedModuleNames = createFileMap>(getCanonicalFileName); - this.filenameToScript = createFileMap(getCanonicalFileName); + this.getCanonicalFileName = createGetCanonicalFileName(host.useCaseSensitiveFileNames); + this.resolvedModuleNames = createFileMap>(); + this.filenameToScript = createFileMap(); 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.get(path); let newResolutions: Map = {}; let resolvedModules: ResolvedModule[] = []; @@ -129,9 +133,9 @@ namespace ts.server { resolvedModules.push(resolution.resolvedModule); } - + // replace old results with a new one - this.resolvedModuleNames.set(containingFile, newResolutions); + this.resolvedModuleNames.set(path, newResolutions); return resolvedModules; function moduleResolutionIsValid(resolution: TimestampedResolvedModule): boolean { @@ -144,7 +148,7 @@ namespace ts.server { // TODO: use lastCheckTime to track expiration for module name resolution return true; } - + // consider situation if we have no candidate locations as valid resolution. // after all there is no point to invalidate it if we have no idea where to look for the module. return resolution.failedLookupLocations.length === 0; @@ -152,12 +156,12 @@ namespace ts.server { } getDefaultLibFileName() { - var nodeModuleBinDir = ts.getDirectoryPath(ts.normalizePath(this.host.getExecutingFilePath())); + const nodeModuleBinDir = ts.getDirectoryPath(ts.normalizePath(this.host.getExecutingFilePath())); return ts.combinePaths(nodeModuleBinDir, ts.getDefaultLibFileName(this.compilationSettings)); } getScriptSnapshot(filename: string): ts.IScriptSnapshot { - var scriptInfo = this.getScriptInfo(filename); + const scriptInfo = this.getScriptInfo(filename); if (scriptInfo) { return scriptInfo.snap(); } @@ -170,10 +174,10 @@ namespace ts.server { } lineAffectsRefs(filename: string, line: number) { - var info = this.getScriptInfo(filename); - var lineInfo = info.getLineInfo(line); + const info = this.getScriptInfo(filename); + const lineInfo = info.getLineInfo(line); if (lineInfo && lineInfo.text) { - var regex = /reference|import|\/\*|\*\//; + const regex = /reference|import|\/\*|\*\//; return regex.test(lineInfo.text); } } @@ -201,54 +205,55 @@ namespace ts.server { removeReferencedFile(info: ScriptInfo) { if (!info.isOpen) { - this.filenameToScript.remove(info.fileName); - this.resolvedModuleNames.remove(info.fileName); + this.filenameToScript.remove(info.path); + this.resolvedModuleNames.remove(info.path); } } getScriptInfo(filename: string): ScriptInfo { - var scriptInfo = this.filenameToScript.get(filename); + let path = toPath(filename, this.host.getCurrentDirectory(), this.getCanonicalFileName); + let scriptInfo = this.filenameToScript.get(path); if (!scriptInfo) { scriptInfo = this.project.openReferencedFile(filename); if (scriptInfo) { - this.filenameToScript.set(scriptInfo.fileName, scriptInfo); + this.filenameToScript.set(path, scriptInfo); } } return scriptInfo; } addRoot(info: ScriptInfo) { - if (!this.filenameToScript.contains(info.fileName)) { - this.filenameToScript.set(info.fileName, info); + if (!this.filenameToScript.contains(info.path)) { + this.filenameToScript.set(info.path, info); this.roots.push(info); } } removeRoot(info: ScriptInfo) { - if (!this.filenameToScript.contains(info.fileName)) { - this.filenameToScript.remove(info.fileName); + if (!this.filenameToScript.contains(info.path)) { + this.filenameToScript.remove(info.path); this.roots = copyListRemovingItem(info, this.roots); - this.resolvedModuleNames.remove(info.fileName); + this.resolvedModuleNames.remove(info.path); } } saveTo(filename: string, tmpfilename: string) { - var script = this.getScriptInfo(filename); + const script = this.getScriptInfo(filename); if (script) { - var snap = script.snap(); + const snap = script.snap(); this.host.writeFile(tmpfilename, snap.getText(0, snap.getLength())); } } reloadScript(filename: string, tmpfilename: string, cb: () => any) { - var script = this.getScriptInfo(filename); + const script = this.getScriptInfo(filename); if (script) { script.svc.reloadFromFile(tmpfilename, cb); } } editScript(filename: string, start: number, end: number, newText: string) { - var script = this.getScriptInfo(filename); + const script = this.getScriptInfo(filename); if (script) { script.editContent(start, end, newText); return; @@ -258,14 +263,14 @@ namespace ts.server { } resolvePath(path: string): string { - var start = new Date().getTime(); - var result = this.host.resolvePath(path); + const start = new Date().getTime(); + const result = this.host.resolvePath(path); return result; } fileExists(path: string): boolean { - var start = new Date().getTime(); - var result = this.host.fileExists(path); + const start = new Date().getTime(); + const result = this.host.fileExists(path); return result; } @@ -277,16 +282,17 @@ namespace ts.server { * @param line 1 based index */ lineToTextSpan(filename: string, line: number): ts.TextSpan { - var script: ScriptInfo = this.filenameToScript.get(filename); - var index = script.snap().index; + let path = toPath(filename, this.host.getCurrentDirectory(), this.getCanonicalFileName); + const script: ScriptInfo = this.filenameToScript.get(path); + const index = script.snap().index; - var lineInfo = index.lineNumberToInfo(line + 1); - var len: number; + const lineInfo = index.lineNumberToInfo(line + 1); + let len: number; if (lineInfo.leaf) { len = lineInfo.leaf.text.length; } else { - var nextLineInfo = index.lineNumberToInfo(line + 2); + const nextLineInfo = index.lineNumberToInfo(line + 2); len = nextLineInfo.offset - lineInfo.offset; } return ts.createTextSpan(lineInfo.offset, len); @@ -297,10 +303,11 @@ namespace ts.server { * @param offset 1 based index */ lineOffsetToPosition(filename: string, line: number, offset: number): number { - var script: ScriptInfo = this.filenameToScript.get(filename); - var index = script.snap().index; + let path = toPath(filename, this.host.getCurrentDirectory(), this.getCanonicalFileName); + const script: ScriptInfo = this.filenameToScript.get(path); + const index = script.snap().index; - var lineInfo = index.lineNumberToInfo(line); + const lineInfo = index.lineNumberToInfo(line); // TODO: assert this offset is actually on the line return (lineInfo.offset + offset - 1); } @@ -310,36 +317,37 @@ namespace ts.server { * @param offset 1-based index */ positionToLineOffset(filename: string, position: number): ILineInfo { - var script: ScriptInfo = this.filenameToScript.get(filename); - var index = script.snap().index; - var lineOffset = index.charOffsetToLineNumberAndPos(position); + let path = toPath(filename, this.host.getCurrentDirectory(), this.getCanonicalFileName); + const script: ScriptInfo = this.filenameToScript.get(path); + const index = script.snap().index; + const lineOffset = index.charOffsetToLineNumberAndPos(position); return { line: lineOffset.line, offset: lineOffset.offset + 1 }; } } // assumes normalized paths function getAbsolutePath(filename: string, directory: string) { - var rootLength = ts.getRootLength(filename); + const rootLength = ts.getRootLength(filename); if (rootLength > 0) { return filename; } else { - var splitFilename = filename.split('/'); - var splitDir = directory.split('/'); - var i = 0; - var dirTail = 0; - var sflen = splitFilename.length; - while ((i < sflen) && (splitFilename[i].charAt(0) == '.')) { - var dots = splitFilename[i]; - if (dots == '..') { + const splitFilename = filename.split("/"); + const splitDir = directory.split("/"); + let i = 0; + let dirTail = 0; + const sflen = splitFilename.length; + while ((i < sflen) && (splitFilename[i].charAt(0) == ".")) { + const dots = splitFilename[i]; + if (dots == "..") { dirTail++; } - else if (dots != '.') { + else if (dots != ".") { return undefined; } i++; } - return splitDir.slice(0, splitDir.length - dirTail).concat(splitFilename.slice(i)).join('/'); + return splitDir.slice(0, splitDir.length - dirTail).concat(splitFilename.slice(i)).join("/"); } } @@ -384,7 +392,7 @@ namespace ts.server { } getFileNames() { - var sourceFiles = this.program.getSourceFiles(); + const sourceFiles = this.program.getSourceFiles(); return sourceFiles.map(sourceFile => sourceFile.fileName); } @@ -393,7 +401,7 @@ namespace ts.server { } getSourceFileFromName(filename: string, requireOpen?: boolean) { - var info = this.projectService.getScriptInfo(filename); + const info = this.projectService.getScriptInfo(filename); if (info) { if ((!requireOpen) || info.isOpen) { return this.getSourceFile(info); @@ -412,9 +420,9 @@ namespace ts.server { updateFileMap() { this.filenameToSourceFile = {}; - var sourceFiles = this.program.getSourceFiles(); - for (var i = 0, len = sourceFiles.length; i < len; i++) { - var normFilename = ts.normalizePath(sourceFiles[i].fileName); + const sourceFiles = this.program.getSourceFiles(); + for (let i = 0, len = sourceFiles.length; i < len; i++) { + const normFilename = ts.normalizePath(sourceFiles[i].fileName); this.filenameToSourceFile[normFilename] = sourceFiles[i]; } } @@ -437,14 +445,14 @@ namespace ts.server { addRoot(info: ScriptInfo) { this.compilerService.host.addRoot(info); } - + // remove a root file from project removeRoot(info: ScriptInfo) { this.compilerService.host.removeRoot(info); } filesToString() { - var strBuilder = ""; + let strBuilder = ""; ts.forEachValue(this.filenameToSourceFile, sourceFile => { strBuilder += sourceFile.fileName + "\n"; }); return strBuilder; @@ -465,8 +473,8 @@ namespace ts.server { } function copyListRemovingItem(item: T, list: T[]) { - var copiedList: T[] = []; - for (var i = 0, len = list.length; i < len; i++) { + const copiedList: T[] = []; + for (let i = 0, len = list.length; i < len; i++) { if (list[i] != item) { copiedList.push(list[i]); } @@ -512,12 +520,12 @@ namespace ts.server { this.hostConfiguration = { formatCodeOptions: ts.clone(CompilerService.defaultFormatCodeOptions), hostInfo: "Unknown host" - } + }; } getFormatCodeOptions(file?: string) { if (file) { - var info = this.filenameToScriptInfo[file]; + const info = this.filenameToScriptInfo[file]; if (info) { return info.formatCodeOptions; } @@ -526,7 +534,7 @@ namespace ts.server { } watchedFileChanged(fileName: string) { - var info = this.filenameToScriptInfo[fileName]; + const info = this.filenameToScriptInfo[fileName]; if (!info) { this.psLogger.info("Error: got watch notification for unknown file: " + fileName); } @@ -629,7 +637,7 @@ namespace ts.server { setHostConfiguration(args: ts.server.protocol.ConfigureRequestArguments) { if (args.file) { - var info = this.filenameToScriptInfo[args.file]; + const info = this.filenameToScriptInfo[args.file]; if (info) { info.setFormatOptions(args.formatOptions); this.log("Host configuration update for file " + args.file, "Info"); @@ -652,7 +660,7 @@ namespace ts.server { } createInferredProject(root: ScriptInfo) { - var project = new Project(this); + const project = new Project(this); project.addRoot(root); let currentPath = ts.getDirectoryPath(root.fileName); @@ -687,21 +695,21 @@ namespace ts.server { if (!info.isOpen) { this.filenameToScriptInfo[info.fileName] = undefined; - var referencingProjects = this.findReferencingProjects(info); + const referencingProjects = this.findReferencingProjects(info); if (info.defaultProject) { info.defaultProject.removeRoot(info); } - for (var i = 0, len = referencingProjects.length; i < len; i++) { + for (let i = 0, len = referencingProjects.length; i < len; i++) { referencingProjects[i].removeReferencedFile(info); } - for (var j = 0, flen = this.openFileRoots.length; j < flen; j++) { - var openFile = this.openFileRoots[j]; + for (let j = 0, flen = this.openFileRoots.length; j < flen; j++) { + const openFile = this.openFileRoots[j]; if (this.eventHandler) { this.eventHandler("context", openFile.defaultProject, openFile.fileName); } } - for (var j = 0, flen = this.openFilesReferenced.length; j < flen; j++) { - var openFile = this.openFilesReferenced[j]; + for (let j = 0, flen = this.openFilesReferenced.length; j < flen; j++) { + const openFile = this.openFilesReferenced[j]; if (this.eventHandler) { this.eventHandler("context", openFile.defaultProject, openFile.fileName); } @@ -712,8 +720,8 @@ namespace ts.server { } updateConfiguredProjectList() { - var configuredProjects: Project[] = []; - for (var i = 0, len = this.configuredProjects.length; i < len; i++) { + const configuredProjects: Project[] = []; + for (let i = 0, len = this.configuredProjects.length; i < len; i++) { if (this.configuredProjects[i].openRefCount > 0) { configuredProjects.push(this.configuredProjects[i]); } @@ -750,7 +758,7 @@ namespace ts.server { } setConfiguredProjectRoot(info: ScriptInfo) { - for (var i = 0, len = this.configuredProjects.length; i < len; i++) { + for (let i = 0, len = this.configuredProjects.length; i < len; i++) { let configuredProject = this.configuredProjects[i]; if (configuredProject.isRoot(info)) { info.defaultProject = configuredProject; @@ -773,10 +781,10 @@ namespace ts.server { else { // create new inferred project p with the newly opened file as root info.defaultProject = this.createInferredProject(info); - var openFileRoots: ScriptInfo[] = []; + const openFileRoots: ScriptInfo[] = []; // for each inferred project root r - for (var i = 0, len = this.openFileRoots.length; i < len; i++) { - var r = this.openFileRoots[i]; + for (let i = 0, len = this.openFileRoots.length; i < len; i++) { + const r = this.openFileRoots[i]; // if r referenced by the new project if (info.defaultProject.getSourceFile(r)) { // remove project rooted at r @@ -808,9 +816,9 @@ namespace ts.server { // to the disk, and the server's version of the file can be out of sync. info.svc.reloadFromFile(info.fileName); - var openFileRoots: ScriptInfo[] = []; - var removedProject: Project; - for (var i = 0, len = this.openFileRoots.length; i < len; i++) { + const openFileRoots: ScriptInfo[] = []; + let removedProject: Project; + for (let i = 0, len = this.openFileRoots.length; i < len; i++) { // if closed file is root of project if (info === this.openFileRoots[i]) { // remove that project and remember it @@ -822,9 +830,9 @@ namespace ts.server { } this.openFileRoots = openFileRoots; if (!removedProject) { - var openFileRootsConfigured: ScriptInfo[] = []; + const openFileRootsConfigured: ScriptInfo[] = []; - for (var i = 0, len = this.openFileRootsConfigured.length; i < len; i++) { + for (let i = 0, len = this.openFileRootsConfigured.length; i < len; i++) { if (info === this.openFileRootsConfigured[i]) { if (info.defaultProject.deleteOpenRef() === 0) { removedProject = info.defaultProject; @@ -839,11 +847,11 @@ namespace ts.server { } if (removedProject) { this.removeProject(removedProject); - var openFilesReferenced: ScriptInfo[] = []; - var orphanFiles: ScriptInfo[] = []; + const openFilesReferenced: ScriptInfo[] = []; + const orphanFiles: ScriptInfo[] = []; // for all open, referenced files f - for (var i = 0, len = this.openFilesReferenced.length; i < len; i++) { - var f = this.openFilesReferenced[i]; + for (let i = 0, len = this.openFilesReferenced.length; i < len; i++) { + const f = this.openFilesReferenced[i]; // if f was referenced by the removed project, remember it if (f.defaultProject === removedProject || !f.defaultProject) { f.defaultProject = undefined; @@ -856,7 +864,7 @@ namespace ts.server { } this.openFilesReferenced = openFilesReferenced; // treat orphaned files as newly opened - for (var i = 0, len = orphanFiles.length; i < len; i++) { + for (let i = 0, len = orphanFiles.length; i < len; i++) { this.addOpenFile(orphanFiles[i]); } } @@ -867,10 +875,10 @@ namespace ts.server { } findReferencingProjects(info: ScriptInfo, excludedProject?: Project) { - var referencingProjects: Project[] = []; + const referencingProjects: Project[] = []; info.defaultProject = undefined; - for (var i = 0, len = this.inferredProjects.length; i < len; i++) { - var inferredProject = this.inferredProjects[i]; + for (let i = 0, len = this.inferredProjects.length; i < len; i++) { + const inferredProject = this.inferredProjects[i]; inferredProject.updateGraph(); if (inferredProject !== excludedProject) { if (inferredProject.getSourceFile(info)) { @@ -879,8 +887,8 @@ namespace ts.server { } } } - for (var i = 0, len = this.configuredProjects.length; i < len; i++) { - var configuredProject = this.configuredProjects[i]; + for (let i = 0, len = this.configuredProjects.length; i < len; i++) { + const configuredProject = this.configuredProjects[i]; configuredProject.updateGraph(); if (configuredProject.getSourceFile(info)) { info.defaultProject = configuredProject; @@ -928,11 +936,11 @@ namespace ts.server { // project roots. For each referenced file, see if the default project still // references that file. If so, then just keep the file in the referenced list. // If not, add the file to an unattached list, to be rechecked later. - var openFilesReferenced: ScriptInfo[] = []; - for (var i = 0, len = this.openFilesReferenced.length; i < len; i++) { - var referencedFile = this.openFilesReferenced[i]; + const openFilesReferenced: ScriptInfo[] = []; + for (let i = 0, len = this.openFilesReferenced.length; i < len; i++) { + const referencedFile = this.openFilesReferenced[i]; referencedFile.defaultProject.updateGraph(); - var sourceFile = referencedFile.defaultProject.getSourceFile(referencedFile); + const sourceFile = referencedFile.defaultProject.getSourceFile(referencedFile); if (sourceFile) { openFilesReferenced.push(referencedFile); } @@ -949,11 +957,11 @@ namespace ts.server { // projects newly references the file, remove its project from the // inferred projects list (since it is no longer a root) and add // the file to the open, referenced file list. - var openFileRoots: ScriptInfo[] = []; - for (var i = 0, len = this.openFileRoots.length; i < len; i++) { - var rootFile = this.openFileRoots[i]; - var rootedProject = rootFile.defaultProject; - var referencingProjects = this.findReferencingProjects(rootFile, rootedProject); + const openFileRoots: ScriptInfo[] = []; + for (let i = 0, len = this.openFileRoots.length; i < len; i++) { + const rootFile = this.openFileRoots[i]; + const rootedProject = rootFile.defaultProject; + const referencingProjects = this.findReferencingProjects(rootFile, rootedProject); if (rootFile.defaultProject && rootFile.defaultProject.isConfiguredProject()) { // If the root file has already been added into a configured project, @@ -980,7 +988,7 @@ namespace ts.server { // Finally, if we found any open, referenced files that are no longer // referenced by their default project, treat them as newly opened // by the editor. - for (var i = 0, len = unattachedOpenFiles.length; i < len; i++) { + for (let i = 0, len = unattachedOpenFiles.length; i < len; i++) { this.addOpenFile(unattachedOpenFiles[i]); } this.printProjects(); @@ -996,9 +1004,9 @@ namespace ts.server { */ openFile(fileName: string, openedByClient: boolean) { fileName = ts.normalizePath(fileName); - var info = ts.lookUp(this.filenameToScriptInfo, fileName); + let info = ts.lookUp(this.filenameToScriptInfo, fileName); if (!info) { - var content: string; + let content: string; if (this.host.fileExists(fileName)) { content = this.host.readFile(fileName); } @@ -1008,7 +1016,7 @@ namespace ts.server { } } if (content !== undefined) { - var indentSize: number; + let indentSize: number; info = new ScriptInfo(this.host, fileName, content, openedByClient); info.setFormatOptions(this.getFormatCodeOptions()); this.filenameToScriptInfo[fileName] = info; @@ -1032,11 +1040,11 @@ namespace ts.server { // the newly opened file. findConfigFile(searchPath: string): string { while (true) { - var fileName = ts.combinePaths(searchPath, "tsconfig.json"); + const fileName = ts.combinePaths(searchPath, "tsconfig.json"); if (this.host.fileExists(fileName)) { return fileName; } - var parentPath = ts.getDirectoryPath(searchPath); + const parentPath = ts.getDirectoryPath(searchPath); if (parentPath === searchPath) { break; } @@ -1051,7 +1059,7 @@ namespace ts.server { */ openClientFile(fileName: string) { this.openOrUpdateConfiguredProjectForFile(fileName); - var info = this.openFile(fileName, true); + const info = this.openFile(fileName, true); this.addOpenFile(info); this.printProjects(); return info; @@ -1070,7 +1078,7 @@ namespace ts.server { this.log("Config file name: " + configFileName, "Info"); let project = this.findConfiguredProjectByConfigFile(configFileName); if (!project) { - var configResult = this.openConfigFile(configFileName, fileName); + const configResult = this.openConfigFile(configFileName, fileName); if (!configResult.success) { this.log("Error opening config file " + configFileName + " " + configResult.errorMsg); } @@ -1094,7 +1102,7 @@ namespace ts.server { */ closeClientFile(filename: string) { - var info = ts.lookUp(this.filenameToScriptInfo, filename); + const info = ts.lookUp(this.filenameToScriptInfo, filename); if (info) { this.closeOpenFile(info); info.isOpen = false; @@ -1103,19 +1111,19 @@ namespace ts.server { } getProjectForFile(filename: string) { - var scriptInfo = ts.lookUp(this.filenameToScriptInfo, filename); + const scriptInfo = ts.lookUp(this.filenameToScriptInfo, filename); if (scriptInfo) { return scriptInfo.defaultProject; } } printProjectsForFile(filename: string) { - var scriptInfo = ts.lookUp(this.filenameToScriptInfo, filename); + const scriptInfo = ts.lookUp(this.filenameToScriptInfo, filename); if (scriptInfo) { this.psLogger.startGroup(); - this.psLogger.info("Projects for " + filename) - var projects = this.findReferencingProjects(scriptInfo); - for (var i = 0, len = projects.length; i < len; i++) { + this.psLogger.info("Projects for " + filename); + const projects = this.findReferencingProjects(scriptInfo); + for (let i = 0, len = projects.length; i < len; i++) { this.psLogger.info("Project " + i.toString()); } this.psLogger.endGroup(); @@ -1130,34 +1138,34 @@ namespace ts.server { return; } this.psLogger.startGroup(); - for (var i = 0, len = this.inferredProjects.length; i < len; i++) { - var project = this.inferredProjects[i]; + for (let i = 0, len = this.inferredProjects.length; i < len; i++) { + const project = this.inferredProjects[i]; project.updateGraph(); this.psLogger.info("Project " + i.toString()); this.psLogger.info(project.filesToString()); this.psLogger.info("-----------------------------------------------"); } - for (var i = 0, len = this.configuredProjects.length; i < len; i++) { - var project = this.configuredProjects[i]; + for (let i = 0, len = this.configuredProjects.length; i < len; i++) { + const project = this.configuredProjects[i]; project.updateGraph(); this.psLogger.info("Project (configured) " + (i + this.inferredProjects.length).toString()); this.psLogger.info(project.filesToString()); this.psLogger.info("-----------------------------------------------"); } - this.psLogger.info("Open file roots of inferred projects: ") - for (var i = 0, len = this.openFileRoots.length; i < len; i++) { + this.psLogger.info("Open file roots of inferred projects: "); + for (let i = 0, len = this.openFileRoots.length; i < len; i++) { this.psLogger.info(this.openFileRoots[i].fileName); } - this.psLogger.info("Open files referenced by inferred or configured projects: ") - for (var i = 0, len = this.openFilesReferenced.length; i < len; i++) { - var fileInfo = this.openFilesReferenced[i].fileName; + this.psLogger.info("Open files referenced by inferred or configured projects: "); + for (let i = 0, len = this.openFilesReferenced.length; i < len; i++) { + let fileInfo = this.openFilesReferenced[i].fileName; if (this.openFilesReferenced[i].defaultProject.isConfiguredProject()) { fileInfo += " (configured)"; } this.psLogger.info(fileInfo); } - this.psLogger.info("Open file roots of configured projects: ") - for (var i = 0, len = this.openFileRootsConfigured.length; i < len; i++) { + this.psLogger.info("Open file roots of configured projects: "); + for (let i = 0, len = this.openFileRootsConfigured.length; i < len; i++) { this.psLogger.info(this.openFileRootsConfigured[i].fileName); } this.psLogger.endGroup(); @@ -1168,7 +1176,7 @@ namespace ts.server { } findConfiguredProjectByConfigFile(configFileName: string) { - for (var i = 0, len = this.configuredProjects.length; i < len; i++) { + for (let i = 0, len = this.configuredProjects.length; i < len; i++) { if (this.configuredProjects[i].projectFilename == configFileName) { return this.configuredProjects[i]; } @@ -1179,22 +1187,24 @@ namespace ts.server { configFileToProjectOptions(configFilename: string): { succeeded: boolean, projectOptions?: ProjectOptions, error?: ProjectOpenResult } { configFilename = ts.normalizePath(configFilename); // file references will be relative to dirPath (or absolute) - var dirPath = ts.getDirectoryPath(configFilename); - var contents = this.host.readFile(configFilename) - var rawConfig: { config?: ProjectOptions; error?: Diagnostic; } = ts.parseConfigFileTextToJson(configFilename, contents); + const dirPath = ts.getDirectoryPath(configFilename); + const contents = this.host.readFile(configFilename); + const rawConfig: { config?: ProjectOptions; error?: Diagnostic; } = ts.parseConfigFileTextToJson(configFilename, contents); if (rawConfig.error) { return { succeeded: false, error: rawConfig.error }; } else { - var parsedCommandLine = ts.parseJsonConfigFileContent(rawConfig.config, this.host, dirPath); + const parsedCommandLine = ts.parseJsonConfigFileContent(rawConfig.config, this.host, dirPath); + Debug.assert(!!parsedCommandLine.fileNames); + if (parsedCommandLine.errors && (parsedCommandLine.errors.length > 0)) { return { succeeded: false, error: { errorMsg: "tsconfig option errors" } }; } - else if (parsedCommandLine.fileNames == null) { + else if (parsedCommandLine.fileNames.length === 0) { return { succeeded: false, error: { errorMsg: "no files found" } }; } else { - var projectOptions: ProjectOptions = { + const projectOptions: ProjectOptions = { files: parsedCommandLine.fileNames, compilerOptions: parsedCommandLine.options }; @@ -1287,7 +1297,7 @@ namespace ts.server { } createProject(projectFilename: string, projectOptions?: ProjectOptions) { - var project = new Project(this, projectOptions); + const project = new Project(this, projectOptions); project.projectFilename = projectFilename; return project; } @@ -1319,14 +1329,14 @@ namespace ts.server { } isExternalModule(filename: string): boolean { - var sourceFile = this.languageService.getSourceFile(filename); + const sourceFile = this.languageService.getSourceFile(filename); return ts.isExternalModule(sourceFile); } static defaultFormatCodeOptions: ts.FormatCodeOptions = { IndentSize: 4, TabSize: 4, - NewLineCharacter: ts.sys ? ts.sys.newLine : '\n', + NewLineCharacter: ts.sys ? ts.sys.newLine : "\n", ConvertTabsToSpaces: true, IndentStyle: ts.IndentStyle.Smart, InsertSpaceAfterCommaDelimiter: true, @@ -1338,7 +1348,7 @@ namespace ts.server { InsertSpaceAfterOpeningAndBeforeClosingNonemptyBrackets: false, PlaceOpenBraceOnNewLineForFunctions: false, PlaceOpenBraceOnNewLineForControlBlocks: false, - } + }; } export interface LineCollection { @@ -1412,17 +1422,17 @@ namespace ts.server { else { insertedText = this.initialText + this.trailingText; } - var lm = LineIndex.linesFromText(insertedText); - var lines = lm.lines; + const lm = LineIndex.linesFromText(insertedText); + const lines = lm.lines; if (lines.length > 1) { if (lines[lines.length - 1] == "") { lines.length--; } } - var branchParent: LineNode; - var lastZeroCount: LineCollection; + let branchParent: LineNode; + let lastZeroCount: LineCollection; - for (var k = this.endBranch.length - 1; k >= 0; k--) { + for (let k = this.endBranch.length - 1; k >= 0; k--) { (this.endBranch[k]).updateCounts(); if (this.endBranch[k].charCount() === 0) { lastZeroCount = this.endBranch[k]; @@ -1439,29 +1449,29 @@ namespace ts.server { } // path at least length two (root and leaf) - var insertionNode = this.startPath[this.startPath.length - 2]; - var leafNode = this.startPath[this.startPath.length - 1]; - var len = lines.length; + let insertionNode = this.startPath[this.startPath.length - 2]; + const leafNode = this.startPath[this.startPath.length - 1]; + const len = lines.length; if (len > 0) { leafNode.text = lines[0]; if (len > 1) { - var insertedNodes = new Array(len - 1); - var startNode = leafNode; - for (var i = 1, len = lines.length; i < len; i++) { + let insertedNodes = new Array(len - 1); + let startNode = leafNode; + for (let i = 1, len = lines.length; i < len; i++) { insertedNodes[i - 1] = new LineLeaf(lines[i]); } - var pathIndex = this.startPath.length - 2; + let pathIndex = this.startPath.length - 2; while (pathIndex >= 0) { insertionNode = this.startPath[pathIndex]; insertedNodes = insertionNode.insertAt(startNode, insertedNodes); pathIndex--; startNode = insertionNode; } - var insertedNodesLen = insertedNodes.length; + let insertedNodesLen = insertedNodes.length; while (insertedNodesLen > 0) { - var newRoot = new LineNode(); + const newRoot = new LineNode(); newRoot.add(this.lineIndex.root); insertedNodes = newRoot.insertAt(this.lineIndex.root, insertedNodes); insertedNodesLen = insertedNodes.length; @@ -1470,7 +1480,7 @@ namespace ts.server { this.lineIndex.root.updateCounts(); } else { - for (var j = this.startPath.length - 2; j >= 0; j--) { + for (let j = this.startPath.length - 2; j >= 0; j--) { (this.startPath[j]).updateCounts(); } } @@ -1478,7 +1488,7 @@ namespace ts.server { else { // no content for leaf node, so delete it insertionNode.remove(leafNode); - for (var j = this.startPath.length - 2; j >= 0; j--) { + for (let j = this.startPath.length - 2; j >= 0; j--) { (this.startPath[j]).updateCounts(); } } @@ -1499,7 +1509,7 @@ namespace ts.server { pre(relativeStart: number, relativeLength: number, lineCollection: LineCollection, parent: LineCollection, nodeType: CharRangeSection) { // currentNode corresponds to parent, but in the new tree - var currentNode = this.stack[this.stack.length - 1]; + const currentNode = this.stack[this.stack.length - 1]; if ((this.state === CharRangeSection.Entire) && (nodeType === CharRangeSection.Start)) { // if range is on single line, we will never make this state transition @@ -1508,7 +1518,7 @@ namespace ts.server { this.lineCollectionAtBranch = lineCollection; } - var child: LineCollection; + let child: LineCollection; function fresh(node: LineCollection): LineCollection { if (node.isLeaf()) { return new LineLeaf(""); @@ -1633,7 +1643,7 @@ namespace ts.server { } reloadFromFile(filename: string, cb?: () => any) { - var content = this.host.readFile(filename); + const content = this.host.readFile(filename); this.reload(content); if (cb) cb(); @@ -1643,13 +1653,13 @@ namespace ts.server { reload(script: string) { this.currentVersion++; this.changes = []; // history wiped out by reload - var snap = new LineIndexSnapshot(this.currentVersion, this); + const snap = new LineIndexSnapshot(this.currentVersion, this); this.versions[this.currentVersion] = snap; snap.index = new LineIndex(); - var lm = LineIndex.linesFromText(script); + const lm = LineIndex.linesFromText(script); snap.index.load(lm.lines); // REVIEW: could use linked list - for (var i = this.minVersion; i < this.currentVersion; i++) { + for (let i = this.minVersion; i < this.currentVersion; i++) { this.versions[i] = undefined; } this.minVersion = this.currentVersion; @@ -1657,11 +1667,11 @@ namespace ts.server { } getSnapshot() { - var snap = this.versions[this.currentVersion]; + let snap = this.versions[this.currentVersion]; if (this.changes.length > 0) { - var snapIndex = this.latest().index; - for (var i = 0, len = this.changes.length; i < len; i++) { - var change = this.changes[i]; + let snapIndex = this.latest().index; + for (let i = 0, len = this.changes.length; i < len; i++) { + const change = this.changes[i]; snapIndex = snapIndex.edit(change.pos, change.deleteLen, change.insertedText); } snap = new LineIndexSnapshot(this.currentVersion + 1, this); @@ -1671,9 +1681,9 @@ namespace ts.server { this.versions[snap.version] = snap; this.changes = []; if ((this.currentVersion - this.minVersion) >= ScriptVersionCache.maxVersions) { - var oldMin = this.minVersion; + const oldMin = this.minVersion; this.minVersion = (this.currentVersion - ScriptVersionCache.maxVersions) + 1; - for (var j = oldMin; j < this.minVersion; j++) { + for (let j = oldMin; j < this.minVersion; j++) { this.versions[j] = undefined; } } @@ -1684,11 +1694,11 @@ namespace ts.server { getTextChangesBetweenVersions(oldVersion: number, newVersion: number) { if (oldVersion < newVersion) { if (oldVersion >= this.minVersion) { - var textChangeRanges: ts.TextChangeRange[] = []; - for (var i = oldVersion + 1; i <= newVersion; i++) { - var snap = this.versions[i]; - for (var j = 0, len = snap.changesSincePreviousVersion.length; j < len; j++) { - var textChange = snap.changesSincePreviousVersion[j]; + const textChangeRanges: ts.TextChangeRange[] = []; + for (let i = oldVersion + 1; i <= newVersion; i++) { + const snap = this.versions[i]; + for (let j = 0, len = snap.changesSincePreviousVersion.length; j < len; j++) { + const textChange = snap.changesSincePreviousVersion[j]; textChangeRanges[textChangeRanges.length] = textChange.getTextChangeRange(); } } @@ -1704,12 +1714,12 @@ namespace ts.server { } static fromString(host: ServerHost, script: string) { - var svc = new ScriptVersionCache(); - var snap = new LineIndexSnapshot(0, svc); + const svc = new ScriptVersionCache(); + const snap = new LineIndexSnapshot(0, svc); svc.versions[svc.currentVersion] = snap; svc.host = host; snap.index = new LineIndex(); - var lm = LineIndex.linesFromText(script); + const lm = LineIndex.linesFromText(script); snap.index.load(lm.lines); return svc; } @@ -1732,9 +1742,9 @@ namespace ts.server { // this requires linear space so don't hold on to these getLineStartPositions(): number[] { - var starts: number[] = [-1]; - var count = 1; - var pos = 0; + const starts: number[] = [-1]; + let count = 1; + let pos = 0; this.index.every((ll, s, len) => { starts[count++] = pos; pos += ll.text.length; @@ -1758,7 +1768,7 @@ namespace ts.server { } } getChangeRange(oldSnapshot: ts.IScriptSnapshot): ts.TextChangeRange { - var oldSnap = oldSnapshot; + const oldSnap = oldSnapshot; return this.getTextChangeRangeSinceVersion(oldSnap.version); } } @@ -1773,9 +1783,9 @@ namespace ts.server { } lineNumberToInfo(lineNumber: number): ILineInfo { - var lineCount = this.root.lineCount(); + const lineCount = this.root.lineCount(); if (lineNumber <= lineCount) { - var lineInfo = this.root.lineNumberToInfo(lineNumber, 0); + const lineInfo = this.root.lineNumberToInfo(lineNumber, 0); lineInfo.line = lineNumber; return lineInfo; } @@ -1783,14 +1793,14 @@ namespace ts.server { return { line: lineNumber, offset: this.root.charCount() - } + }; } } load(lines: string[]) { if (lines.length > 0) { - var leaves: LineLeaf[] = []; - for (var i = 0, len = lines.length; i < len; i++) { + const leaves: LineLeaf[] = []; + for (let i = 0, len = lines.length; i < len; i++) { leaves[i] = new LineLeaf(lines[i]); } this.root = LineIndex.buildTreeFromBottom(leaves); @@ -1805,7 +1815,7 @@ namespace ts.server { } getText(rangeStart: number, rangeLength: number) { - var accum = ""; + let accum = ""; if ((rangeLength > 0) && (rangeStart < this.root.charCount())) { this.walk(rangeStart, rangeLength, { goSubtree: true, @@ -1826,7 +1836,7 @@ namespace ts.server { if (!rangeEnd) { rangeEnd = this.root.charCount(); } - var walkFns = { + const walkFns = { goSubtree: true, done: false, leaf: function (relativeStart: number, relativeLength: number, ll: LineLeaf) { @@ -1834,7 +1844,7 @@ namespace ts.server { this.done = true; } } - } + }; this.walk(rangeStart, rangeEnd - rangeStart, walkFns); return !walkFns.done; } @@ -1851,14 +1861,15 @@ namespace ts.server { } } else { + let checkText: string; if (this.checkEdits) { - var checkText = editFlat(this.getText(0, this.root.charCount()), pos, deleteLength, newText); + checkText = editFlat(this.getText(0, this.root.charCount()), pos, deleteLength, newText); } - var walker = new EditWalker(); + const walker = new EditWalker(); if (pos >= this.root.charCount()) { // insert at end pos = this.root.charCount() - 1; - var endString = this.getText(pos, 1); + const endString = this.getText(pos, 1); if (newText) { newText = endString + newText; } @@ -1870,8 +1881,8 @@ namespace ts.server { } else if (deleteLength > 0) { // check whether last characters deleted are line break - var e = pos + deleteLength; - var lineInfo = this.charOffsetToLineNumberAndPos(e); + const e = pos + deleteLength; + const lineInfo = this.charOffsetToLineNumberAndPos(e); if ((lineInfo && (lineInfo.offset === 0))) { // move range end just past line that will merge with previous line deleteLength += lineInfo.text.length; @@ -1889,7 +1900,7 @@ namespace ts.server { walker.insertLines(newText); } if (this.checkEdits) { - var updatedText = this.getText(0, this.root.charCount()); + const updatedText = this.getText(0, this.root.charCount()); Debug.assert(checkText == updatedText, "buffer edit mismatch"); } return walker.lineIndex; @@ -1897,14 +1908,14 @@ namespace ts.server { } static buildTreeFromBottom(nodes: LineCollection[]): LineNode { - var nodeCount = Math.ceil(nodes.length / lineCollectionCapacity); - var interiorNodes: LineNode[] = []; - var nodeIndex = 0; - for (var i = 0; i < nodeCount; i++) { + const nodeCount = Math.ceil(nodes.length / lineCollectionCapacity); + const interiorNodes: LineNode[] = []; + let nodeIndex = 0; + for (let i = 0; i < nodeCount; i++) { interiorNodes[i] = new LineNode(); - var charCount = 0; - var lineCount = 0; - for (var j = 0; j < lineCollectionCapacity; j++) { + let charCount = 0; + let lineCount = 0; + for (let j = 0; j < lineCollectionCapacity; j++) { if (nodeIndex < nodes.length) { interiorNodes[i].add(nodes[nodeIndex]); charCount += nodes[nodeIndex].charCount(); @@ -1927,18 +1938,18 @@ namespace ts.server { } static linesFromText(text: string) { - var lineStarts = ts.computeLineStarts(text); + const lineStarts = ts.computeLineStarts(text); if (lineStarts.length === 0) { return { lines: [], lineMap: lineStarts }; } - var lines = new Array(lineStarts.length); - var lc = lineStarts.length - 1; - for (var lmi = 0; lmi < lc; lmi++) { + const lines = new Array(lineStarts.length); + const lc = lineStarts.length - 1; + for (let lmi = 0; lmi < lc; lmi++) { lines[lmi] = text.substring(lineStarts[lmi], lineStarts[lmi + 1]); } - var endText = text.substring(lineStarts[lc]); + const endText = text.substring(lineStarts[lc]); if (endText.length > 0) { lines[lc] = endText; } @@ -1961,8 +1972,8 @@ namespace ts.server { updateCounts() { this.totalChars = 0; this.totalLines = 0; - for (var i = 0, len = this.children.length; i < len; i++) { - var child = this.children[i]; + for (let i = 0, len = this.children.length; i < len; i++) { + const child = this.children[i]; this.totalChars += child.charCount(); this.totalLines += child.lineCount(); } @@ -1993,11 +2004,11 @@ namespace ts.server { walk(rangeStart: number, rangeLength: number, walkFns: ILineIndexWalker) { // assume (rangeStart < this.totalChars) && (rangeLength <= this.totalChars) - var childIndex = 0; - var child = this.children[0]; - var childCharCount = child.charCount(); + let childIndex = 0; + let child = this.children[0]; + let childCharCount = child.charCount(); // find sub-tree containing start - var adjustedStart = rangeStart; + let adjustedStart = rangeStart; while (adjustedStart >= childCharCount) { this.skipChild(adjustedStart, rangeLength, childIndex, walkFns, CharRangeSection.PreStart); adjustedStart -= childCharCount; @@ -2015,7 +2026,7 @@ namespace ts.server { if (this.execWalk(adjustedStart, childCharCount - adjustedStart, walkFns, childIndex, CharRangeSection.Start)) { return; } - var adjustedLength = rangeLength - (childCharCount - adjustedStart); + let adjustedLength = rangeLength - (childCharCount - adjustedStart); child = this.children[++childIndex]; childCharCount = child.charCount(); while (adjustedLength > childCharCount) { @@ -2034,9 +2045,9 @@ namespace ts.server { } // Process any subtrees after the one containing range end if (walkFns.pre) { - var clen = this.children.length; + const clen = this.children.length; if (childIndex < (clen - 1)) { - for (var ej = childIndex + 1; ej < clen; ej++) { + for (let ej = childIndex + 1; ej < clen; ej++) { this.skipChild(0, 0, ej, walkFns, CharRangeSection.PostEnd); } } @@ -2044,12 +2055,12 @@ namespace ts.server { } charOffsetToLineNumberAndPos(lineNumber: number, charOffset: number): ILineInfo { - var childInfo = this.childFromCharOffset(lineNumber, charOffset); + const childInfo = this.childFromCharOffset(lineNumber, charOffset); if (!childInfo.child) { return { line: lineNumber, offset: charOffset, - } + }; } else if (childInfo.childIndex < this.children.length) { if (childInfo.child.isLeaf()) { @@ -2061,23 +2072,23 @@ namespace ts.server { }; } else { - var lineNode = (childInfo.child); + const lineNode = (childInfo.child); return lineNode.charOffsetToLineNumberAndPos(childInfo.lineNumber, childInfo.charOffset); } } else { - var lineInfo = this.lineNumberToInfo(this.lineCount(), 0); + const lineInfo = this.lineNumberToInfo(this.lineCount(), 0); return { line: this.lineCount(), offset: lineInfo.leaf.charCount() }; } } lineNumberToInfo(lineNumber: number, charOffset: number): ILineInfo { - var childInfo = this.childFromLineNumber(lineNumber, charOffset); + const childInfo = this.childFromLineNumber(lineNumber, charOffset); if (!childInfo.child) { return { line: lineNumber, offset: charOffset - } + }; } else if (childInfo.child.isLeaf()) { return { @@ -2085,20 +2096,22 @@ namespace ts.server { offset: childInfo.charOffset, text: ((childInfo.child)).text, leaf: ((childInfo.child)) - } + }; } else { - var lineNode = (childInfo.child); + const lineNode = (childInfo.child); return lineNode.lineNumberToInfo(childInfo.relativeLineNumber, childInfo.charOffset); } } childFromLineNumber(lineNumber: number, charOffset: number) { - var child: LineCollection; - var relativeLineNumber = lineNumber; - for (var i = 0, len = this.children.length; i < len; i++) { + let child: LineCollection; + let relativeLineNumber = lineNumber; + let i: number; + let len: number; + for (i = 0, len = this.children.length; i < len; i++) { child = this.children[i]; - var childLineCount = child.lineCount(); + const childLineCount = child.lineCount(); if (childLineCount >= relativeLineNumber) { break; } @@ -2116,8 +2129,10 @@ namespace ts.server { } childFromCharOffset(lineNumber: number, charOffset: number) { - var child: LineCollection; - for (var i = 0, len = this.children.length; i < len; i++) { + let child: LineCollection; + let i: number; + let len: number; + for (i = 0, len = this.children.length; i < len; i++) { child = this.children[i]; if (child.charCount() > charOffset) { break; @@ -2132,14 +2147,14 @@ namespace ts.server { childIndex: i, charOffset: charOffset, lineNumber: lineNumber - } + }; } splitAfter(childIndex: number) { - var splitNode: LineNode; - var clen = this.children.length; + let splitNode: LineNode; + const clen = this.children.length; childIndex++; - var endLength = childIndex; + const endLength = childIndex; if (childIndex < clen) { splitNode = new LineNode(); while (childIndex < clen) { @@ -2152,10 +2167,10 @@ namespace ts.server { } remove(child: LineCollection) { - var childIndex = this.findChildIndex(child); - var clen = this.children.length; + const childIndex = this.findChildIndex(child); + const clen = this.children.length; if (childIndex < (clen - 1)) { - for (var i = childIndex; i < (clen - 1); i++) { + for (let i = childIndex; i < (clen - 1); i++) { this.children[i] = this.children[i + 1]; } } @@ -2163,16 +2178,16 @@ namespace ts.server { } findChildIndex(child: LineCollection) { - var childIndex = 0; - var clen = this.children.length; + let childIndex = 0; + const clen = this.children.length; while ((this.children[childIndex] !== child) && (childIndex < clen)) childIndex++; return childIndex; } insertAt(child: LineCollection, nodes: LineCollection[]) { - var childIndex = this.findChildIndex(child); - var clen = this.children.length; - var nodeCount = nodes.length; + let childIndex = this.findChildIndex(child); + const clen = this.children.length; + const nodeCount = nodes.length; // if child is last and there is more room and only one node to place, place it if ((clen < lineCollectionCapacity) && (childIndex === (clen - 1)) && (nodeCount === 1)) { this.add(nodes[0]); @@ -2180,22 +2195,22 @@ namespace ts.server { return []; } else { - var shiftNode = this.splitAfter(childIndex); - var nodeIndex = 0; + const shiftNode = this.splitAfter(childIndex); + let nodeIndex = 0; childIndex++; while ((childIndex < lineCollectionCapacity) && (nodeIndex < nodeCount)) { this.children[childIndex++] = nodes[nodeIndex++]; } - var splitNodes: LineNode[] = []; - var splitNodeCount = 0; + let splitNodes: LineNode[] = []; + let splitNodeCount = 0; if (nodeIndex < nodeCount) { splitNodeCount = Math.ceil((nodeCount - nodeIndex) / lineCollectionCapacity); splitNodes = new Array(splitNodeCount); - var splitNodeIndex = 0; - for (var i = 0; i < splitNodeCount; i++) { + let splitNodeIndex = 0; + for (let i = 0; i < splitNodeCount; i++) { splitNodes[i] = new LineNode(); } - var splitNode = splitNodes[0]; + let splitNode = splitNodes[0]; while (nodeIndex < nodeCount) { splitNode.add(nodes[nodeIndex++]); if (splitNode.children.length === lineCollectionCapacity) { @@ -2203,7 +2218,7 @@ namespace ts.server { splitNode = splitNodes[splitNodeIndex]; } } - for (i = splitNodes.length - 1; i >= 0; i--) { + for (let i = splitNodes.length - 1; i >= 0; i--) { if (splitNodes[i].children.length === 0) { splitNodes.length--; } @@ -2213,7 +2228,7 @@ namespace ts.server { splitNodes[splitNodes.length] = shiftNode; } this.updateCounts(); - for (i = 0; i < splitNodeCount; i++) { + for (let i = 0; i < splitNodeCount; i++) { (splitNodes[i]).updateCounts(); } return splitNodes; diff --git a/src/server/node.d.ts b/src/server/node.d.ts index 438b152a1f4..0bde0bb6602 100644 --- a/src/server/node.d.ts +++ b/src/server/node.d.ts @@ -62,14 +62,14 @@ declare var SlowBuffer: { // Buffer class interface Buffer extends NodeBuffer { } interface BufferConstructor { - new (str: string, encoding ?: string): Buffer; + new (str: string, encoding?: string): Buffer; new (size: number): Buffer; new (size: Uint8Array): Buffer; new (array: any[]): Buffer; prototype: Buffer; isBuffer(obj: any): boolean; - byteLength(string: string, encoding ?: string): number; - concat(list: Buffer[], totalLength ?: number): Buffer; + byteLength(string: string, encoding?: string): number; + concat(list: Buffer[], totalLength?: number): Buffer; } declare var Buffer: BufferConstructor; @@ -78,7 +78,7 @@ declare var Buffer: BufferConstructor; * GLOBAL INTERFACES * * * ************************************************/ -declare module NodeJS { +declare namespace NodeJS { export interface ErrnoException extends Error { errno?: any; code?: string; @@ -245,7 +245,7 @@ interface NodeBuffer { fill(value: any, offset?: number, end?: number): void; } -declare module NodeJS { +declare namespace NodeJS { export interface Path { normalize(p: string): string; join(...paths: any[]): string; @@ -258,7 +258,7 @@ declare module NodeJS { } } -declare module NodeJS { +declare namespace NodeJS { export interface ReadLineInstance extends EventEmitter { setPrompt(prompt: string, length: number): void; prompt(preserveCursor?: boolean): void; @@ -280,8 +280,8 @@ declare module NodeJS { } } -declare module NodeJS { - module events { +declare namespace NodeJS { + namespace events { export class EventEmitter implements NodeJS.EventEmitter { static listenerCount(emitter: EventEmitter, event: string): number; @@ -297,8 +297,8 @@ declare module NodeJS { } } -declare module NodeJS { - module stream { +declare namespace NodeJS { + namespace stream { export interface Stream extends events.EventEmitter { pipe(destination: T, options?: { end?: boolean; }): T; @@ -397,8 +397,8 @@ declare module NodeJS { } } -declare module NodeJS { - module fs { +declare namespace NodeJS { + namespace fs { interface Stats { isFile(): boolean; isDirectory(): boolean; @@ -547,8 +547,8 @@ declare module NodeJS { } } -declare module NodeJS { - module path { +declare namespace NodeJS { + namespace path { export function normalize(p: string): string; export function join(...paths: any[]): string; export function resolve(...pathSegments: any[]): string; @@ -560,8 +560,8 @@ declare module NodeJS { } } -declare module NodeJS { - module _debugger { +declare namespace NodeJS { + namespace _debugger { export interface Packet { raw: string; headers: string[]; diff --git a/src/server/protocol.d.ts b/src/server/protocol.d.ts index ce918abda3c..ad1fc5e92de 100644 --- a/src/server/protocol.d.ts +++ b/src/server/protocol.d.ts @@ -16,7 +16,7 @@ declare namespace ts.server.protocol { */ type: string; } - + /** * Client-initiated request message */ @@ -31,7 +31,7 @@ declare namespace ts.server.protocol { */ arguments?: any; } - + /** * Request to reload the project structure for all the opened files */ @@ -107,7 +107,7 @@ declare namespace ts.server.protocol { * A request to get the project information of the current file */ export interface ProjectInfoRequest extends Request { - arguments: ProjectInfoRequestArgs + arguments: ProjectInfoRequestArgs; } /** @@ -200,7 +200,7 @@ declare namespace ts.server.protocol { /** * Object found in response messages defining a span of text in source code. */ - export interface TextSpan { + export interface TextSpan { /** * First character of the definition. */ @@ -261,18 +261,18 @@ declare namespace ts.server.protocol { * in the file at a given line and column. */ export interface DocumentHighlightsRequest extends FileLocationRequest { - arguments: DocumentHighlightsRequestArgs + arguments: DocumentHighlightsRequestArgs; } export interface HighlightSpan extends TextSpan { - kind: string + kind: string; } export interface DocumentHighlightsItem { /** * File containing highlight spans. */ - file: string, + file: string; /** * Spans to highlight in file. @@ -422,76 +422,76 @@ declare namespace ts.server.protocol { * Editor options */ export interface EditorOptions { - + /** Number of spaces for each tab. Default value is 4. */ tabSize?: number; - + /** Number of spaces to indent during formatting. Default value is 4. */ indentSize?: number; - + /** The new line character to be used. Default value is the OS line delimiter. */ newLineCharacter?: string; - + /** Whether tabs should be converted to spaces. Default value is true. */ - convertTabsToSpaces?: boolean; + convertTabsToSpaces?: boolean; } - + /** * Format options */ export interface FormatOptions extends EditorOptions { - + /** Defines space handling after a comma delimiter. Default value is true. */ insertSpaceAfterCommaDelimiter?: boolean; - + /** Defines space handling after a semicolon in a for statemen. Default value is true */ insertSpaceAfterSemicolonInForStatements?: boolean; - + /** Defines space handling after a binary operator. Default value is true. */ insertSpaceBeforeAndAfterBinaryOperators?: boolean; - + /** Defines space handling after keywords in control flow statement. Default value is true. */ insertSpaceAfterKeywordsInControlFlowStatements?: boolean; - + /** Defines space handling after function keyword for anonymous functions. Default value is false. */ insertSpaceAfterFunctionKeywordForAnonymousFunctions?: boolean; - + /** Defines space handling after opening and before closing non empty parenthesis. Default value is false. */ insertSpaceAfterOpeningAndBeforeClosingNonemptyParenthesis?: boolean; /** Defines space handling after opening and before closing non empty brackets. Default value is false. */ insertSpaceAfterOpeningAndBeforeClosingNonemptyBrackets?: boolean; - + /** Defines whether an open brace is put onto a new line for functions or not. Default value is false. */ placeOpenBraceOnNewLineForFunctions?: boolean; - + /** Defines whether an open brace is put onto a new line for control blocks or not. Default value is false. */ placeOpenBraceOnNewLineForControlBlocks?: boolean; - + /** Index operator */ - [key:string] : string | number | boolean; + [key: string] : string | number | boolean; } - + /** * Information found in a configure request. */ export interface ConfigureRequestArguments { - + /** * Information about the host, for example 'Emacs 24.4' or * 'Sublime Text version 3075' */ hostInfo?: string; - + /** * If present, tab settings apply only to this file. */ file?: string; - + /** * The format options to use during formatting and other code editing features. */ - formatOptions?: FormatOptions; + formatOptions?: FormatOptions; } /** @@ -561,27 +561,27 @@ declare namespace ts.server.protocol { * The symbol's kind (such as 'className' or 'parameterName' or plain 'text'). */ kind: string; - + /** * Optional modifiers for the kind (such as 'public'). */ kindModifiers: string; - + /** * Starting file location of symbol. */ start: Location; - + /** * One past last character of symbol. */ end: Location; - + /** * Type and kind of symbol. */ displayString: string; - + /** * Documentation associated with symbol. */ @@ -603,7 +603,7 @@ declare namespace ts.server.protocol { * Last line of range for which to format text in file. */ endLine: number; - + /** * Character offset on last line of range for which to format text in file. */ @@ -619,7 +619,7 @@ declare namespace ts.server.protocol { */ export interface FormatRequest extends FileLocationRequest { arguments: FormatRequestArgs; - } + } /** * Object found in response messages defining an editing @@ -638,7 +638,7 @@ declare namespace ts.server.protocol { * One character past last character of the text span to edit. */ end: Location; - + /** * Replace the span defined above with this string (may be * the empty string). @@ -723,7 +723,7 @@ declare namespace ts.server.protocol { * Text of an item describing the symbol. */ text: string; - + /** * The symbol's kind (such as 'className' or 'parameterName' or plain 'text'). */ @@ -773,7 +773,7 @@ declare namespace ts.server.protocol { * Display parts of the symbol (similar to quick info). */ displayParts: SymbolDisplayPart[]; - + /** * Documentation strings for the symbol. */ @@ -790,94 +790,94 @@ declare namespace ts.server.protocol { /** * Signature help information for a single parameter - */ + */ export interface SignatureHelpParameter { - + /** * The parameter's name - */ + */ name: string; - + /** * Documentation of the parameter. */ documentation: SymbolDisplayPart[]; - + /** * Display parts of the parameter. */ displayParts: SymbolDisplayPart[]; - + /** * Whether the parameter is optional or not. - */ + */ isOptional: boolean; } - + /** * Represents a single signature to show in signature help. - */ + */ export interface SignatureHelpItem { - + /** * Whether the signature accepts a variable number of arguments. - */ + */ isVariadic: boolean; - + /** * The prefix display parts. - */ + */ prefixDisplayParts: SymbolDisplayPart[]; - + /** * The suffix disaply parts. - */ + */ suffixDisplayParts: SymbolDisplayPart[]; - + /** * The separator display parts. - */ + */ separatorDisplayParts: SymbolDisplayPart[]; - + /** * The signature helps items for the parameters. - */ + */ parameters: SignatureHelpParameter[]; - + /** * The signature's documentation */ documentation: SymbolDisplayPart[]; } - + /** * Signature help items found in the response of a signature help request. */ export interface SignatureHelpItems { - + /** * The signature help items. - */ + */ items: SignatureHelpItem[]; - + /** * The span for which signature help should appear on a signature - */ + */ applicableSpan: TextSpan; - + /** * The item selected in the set of available help items. - */ + */ selectedItemIndex: number; - + /** * The argument selected in the set of parameters. - */ + */ argumentIndex: number; - + /** * The argument count - */ + */ argumentCount: number; } @@ -885,9 +885,9 @@ declare namespace ts.server.protocol { * Arguments of a signature help request. */ export interface SignatureHelpRequestArgs extends FileLocationRequestArgs { - + } - + /** * Signature help request; value of command field is "signatureHelp". * Given a file location (file, line, col), return the signature @@ -899,7 +899,7 @@ declare namespace ts.server.protocol { /** * Repsonse object for a SignatureHelpRequest. - */ + */ export interface SignatureHelpResponse extends Response { body?: SignatureHelpItems; } @@ -926,9 +926,9 @@ declare namespace ts.server.protocol { * it request for every file in this project. */ export interface GeterrForProjectRequest extends Request { - arguments: GeterrForProjectRequestArgs + arguments: GeterrForProjectRequestArgs; } - + /** * Arguments for geterr messages. */ @@ -968,12 +968,12 @@ declare namespace ts.server.protocol { * Starting file location at which text appies. */ start: Location; - + /** * The last file location at which the text applies. */ end: Location; - + /** * Text of diagnostic message. */ @@ -985,7 +985,7 @@ declare namespace ts.server.protocol { * The file for which diagnostic information is reported. */ file: string; - + /** * An array of diagnostic information items. */ @@ -999,7 +999,7 @@ declare namespace ts.server.protocol { export interface DiagnosticEvent extends Event { body?: DiagnosticEventBody; } - + /** * Arguments for reload request. */ @@ -1083,12 +1083,12 @@ declare namespace ts.server.protocol { * The symbol's name. */ name: string; - + /** * The symbol's kind (such as 'className' or 'parameterName'). */ kind: string; - + /** * exact, substring, or prefix. */ @@ -1098,39 +1098,39 @@ declare namespace ts.server.protocol { * If this was a case sensitive or insensitive match. */ isCaseSensitive?: boolean; - + /** * Optional modifiers for the kind (such as 'public'). */ kindModifiers?: string; - + /** * The file in which the symbol is found. */ file: string; - + /** * The location within file at which the symbol is found. */ start: Location; - + /** * One past the last character of the symbol. */ end: Location; - + /** * Name of symbol's container symbol (if any); for example, * the class name if symbol is a class member. */ containerName?: string; - + /** * Kind of symbol's container symbol (if any). */ containerKind?: string; } - + /** * Navto response message. Body is an array of navto items. Each * item gives a symbol that matched the search term. @@ -1208,7 +1208,7 @@ declare namespace ts.server.protocol { childItems?: NavigationBarItem[]; } - export interface NavBarResponse extends Response { + export interface NavBarResponse extends Response { body?: NavigationBarItem[]; } } diff --git a/src/server/server.ts b/src/server/server.ts index f48be53520e..842dfef28c0 100644 --- a/src/server/server.ts +++ b/src/server/server.ts @@ -1,13 +1,15 @@ /// /// +// used in fs.writeSync +/* tslint:disable:no-null */ namespace ts.server { - var nodeproto: typeof NodeJS._debugger = require('_debugger'); - var readline: NodeJS.ReadLine = require('readline'); - var path: NodeJS.Path = require('path'); - var fs: typeof NodeJS.fs = require('fs'); + const nodeproto: typeof NodeJS._debugger = require("_debugger"); + const readline: NodeJS.ReadLine = require("readline"); + const path: NodeJS.Path = require("path"); + const fs: typeof NodeJS.fs = require("fs"); - var rl = readline.createInterface({ + const rl = readline.createInterface({ input: process.stdin, output: process.stdout, terminal: false, @@ -68,7 +70,7 @@ namespace ts.server { } if (this.fd >= 0) { s = s + "\n"; - var prefix = Logger.padStringRight(type + " " + this.seq.toString(), " "); + const prefix = Logger.padStringRight(type + " " + this.seq.toString(), " "); if (this.firstInGroup) { s = prefix + s; this.firstInGroup = false; @@ -77,7 +79,7 @@ namespace ts.server { this.seq++; this.firstInGroup = true; } - var buf = new Buffer(s); + const buf = new Buffer(s); fs.writeSync(this.fd, buf, 0, buf.length, null); } } @@ -95,12 +97,12 @@ namespace ts.server { } listen() { - rl.on('line', (input: string) => { - var message = input.trim(); + rl.on("line", (input: string) => { + const message = input.trim(); this.onMessage(message); }); - rl.on('close', () => { + rl.on("close", () => { this.exit(); }); } @@ -112,11 +114,11 @@ namespace ts.server { } function parseLoggingEnvironmentString(logEnvStr: string): LogOptions { - var logEnv: LogOptions = {}; - var args = logEnvStr.split(' '); - for (var i = 0, len = args.length; i < (len - 1); i += 2) { - var option = args[i]; - var value = args[i + 1]; + const logEnv: LogOptions = {}; + const args = logEnvStr.split(" "); + for (let i = 0, len = args.length; i < (len - 1); i += 2) { + const option = args[i]; + const value = args[i + 1]; if (option && value) { switch (option) { case "-file": @@ -133,11 +135,11 @@ namespace ts.server { // TSS_LOG "{ level: "normal | verbose | terse", file?: string}" function createLoggerFromEnv() { - var fileName: string = undefined; - var detailLevel = "normal"; - var logEnvStr = process.env["TSS_LOG"]; + let fileName: string = undefined; + let detailLevel = "normal"; + const logEnvStr = process.env["TSS_LOG"]; if (logEnvStr) { - var logEnv = parseLoggingEnvironmentString(logEnvStr); + const logEnv = parseLoggingEnvironmentString(logEnvStr); if (logEnv.file) { fileName = logEnv.file; } @@ -153,7 +155,7 @@ namespace ts.server { // This places log file in the directory containing editorServices.js // TODO: check that this location is writable - var logger = createLoggerFromEnv(); + const logger = createLoggerFromEnv(); let pending: string[] = []; let canWrite = true; @@ -177,8 +179,8 @@ namespace ts.server { // Override sys.write because fs.writeSync is not reliable on Node 4 ts.sys.write = (s: string) => writeMessage(s); - var ioSession = new IOSession(ts.sys, logger); - process.on('uncaughtException', function(err: Error) { + const ioSession = new IOSession(ts.sys, logger); + process.on("uncaughtException", function(err: Error) { ioSession.logError(err, "unknown"); }); // Start listening diff --git a/src/server/session.ts b/src/server/session.ts index 550b551e51a..694fcebf630 100644 --- a/src/server/session.ts +++ b/src/server/session.ts @@ -4,7 +4,7 @@ /// namespace ts.server { - var spaceCache:string[] = []; + const spaceCache: string[] = []; interface StackTraceError extends Error { stack?: string; @@ -12,30 +12,31 @@ namespace ts.server { export function generateSpaces(n: number): string { if (!spaceCache[n]) { - var strBuilder = ""; - for (var i = 0; i < n; i++) { + let strBuilder = ""; + for (let i = 0; i < n; i++) { strBuilder += " "; } spaceCache[n] = strBuilder; - } + } return spaceCache[n]; } export function generateIndentString(n: number, editorOptions: EditorOptions): string { if (editorOptions.ConvertTabsToSpaces) { return generateSpaces(n); - } else { - var result = ""; - for (var i = 0; i < Math.floor(n / editorOptions.TabSize); i++) { + } + else { + let result = ""; + for (let i = 0; i < Math.floor(n / editorOptions.TabSize); i++) { result += "\t"; } - for (var i = 0; i < n % editorOptions.TabSize; i++) { + for (let i = 0; i < n % editorOptions.TabSize; i++) { result += " "; } return result; } } - + interface FileStart { file: string; start: ILineInfo; @@ -56,7 +57,7 @@ namespace ts.server { return -1; } else if (a.file == b.file) { - var n = compareNumber(a.start.line, b.start.line); + const n = compareNumber(a.start.line, b.start.line); if (n === 0) { return compareNumber(a.start.offset, b.start.offset); } @@ -66,7 +67,7 @@ namespace ts.server { return 1; } } - + function formatDiag(fileName: string, project: Project, diag: ts.Diagnostic) { return { start: project.compilerService.host.positionToLineOffset(fileName, diag.start), @@ -81,7 +82,7 @@ namespace ts.server { } function allEditsBeforePos(edits: ts.TextChange[], pos: number) { - for (var i = 0, len = edits.length; i < len; i++) { + for (let i = 0, len = edits.length; i < len; i++) { if (ts.textSpanEnd(edits[i].span) >= pos) { return false; } @@ -89,7 +90,7 @@ namespace ts.server { return true; } - export module CommandNames { + export namespace CommandNames { export const Brace = "brace"; export const Change = "change"; export const Close = "close"; @@ -119,8 +120,8 @@ namespace ts.server { export const Unknown = "unknown"; } - module Errors { - export var NoProject = new Error("No Project."); + namespace Errors { + export const NoProject = new Error("No Project."); } export interface ServerHost extends ts.System { @@ -136,13 +137,13 @@ namespace ts.server { private changeSeq = 0; constructor( - private host: ServerHost, - private byteLength: (buf: string, encoding?: string) => number, - private hrtime: (start?: number[]) => number[], + private host: ServerHost, + private byteLength: (buf: string, encoding?: string) => number, + private hrtime: (start?: number[]) => number[], private logger: Logger ) { this.projectService = - new ProjectService(host, logger, (eventName,project,fileName) => { + new ProjectService(host, logger, (eventName, project, fileName) => { this.handleEvent(eventName, project, fileName); }); } @@ -156,8 +157,8 @@ namespace ts.server { } public logError(err: Error, cmd: string) { - var typedErr = err; - var msg = "Exception on executing command " + cmd; + const typedErr = err; + let msg = "Exception on executing command " + cmd; if (typedErr.message) { msg += ":\n" + typedErr.message; if (typedErr.stack) { @@ -172,16 +173,16 @@ namespace ts.server { } public send(msg: protocol.Message) { - var json = JSON.stringify(msg); + const json = JSON.stringify(msg); if (this.logger.isVerbose()) { this.logger.info(msg.type + ": " + json); } - this.sendLineToClient('Content-Length: ' + (1 + this.byteLength(json, 'utf8')) + - '\r\n\r\n' + json); + this.sendLineToClient("Content-Length: " + (1 + this.byteLength(json, "utf8")) + + "\r\n\r\n" + json); } public event(info: any, eventName: string) { - var ev: protocol.Event = { + const ev: protocol.Event = { seq: 0, type: "event", event: eventName, @@ -191,13 +192,13 @@ namespace ts.server { } private response(info: any, cmdName: string, reqSeq = 0, errorMsg?: string) { - var res: protocol.Response = { + const res: protocol.Response = { seq: 0, type: "response", command: cmdName, request_seq: reqSeq, success: !errorMsg, - } + }; if (!errorMsg) { res.body = info; } @@ -213,10 +214,10 @@ namespace ts.server { private semanticCheck(file: string, project: Project) { try { - var diags = project.compilerService.languageService.getSemanticDiagnostics(file); + const diags = project.compilerService.languageService.getSemanticDiagnostics(file); if (diags) { - var bakedDiags = diags.map((diag) => formatDiag(file, project, diag)); + const bakedDiags = diags.map((diag) => formatDiag(file, project, diag)); this.event({ file: file, diagnostics: bakedDiags }, "semanticDiag"); } } @@ -227,9 +228,9 @@ namespace ts.server { private syntacticCheck(file: string, project: Project) { try { - var diags = project.compilerService.languageService.getSyntacticDiagnostics(file); + const diags = project.compilerService.languageService.getSyntacticDiagnostics(file); if (diags) { - var bakedDiags = diags.map((diag) => formatDiag(file, project, diag)); + const bakedDiags = diags.map((diag) => formatDiag(file, project, diag)); this.event({ file: file, diagnostics: bakedDiags }, "syntaxDiag"); } } @@ -242,7 +243,7 @@ namespace ts.server { this.syntacticCheck(file, project); this.semanticCheck(file, project); } - + private reloadProjects() { this.projectService.reloadProjects(); } @@ -267,10 +268,10 @@ namespace ts.server { clearImmediate(this.immediateId); this.immediateId = undefined; } - var index = 0; - var checkOne = () => { + let index = 0; + const checkOne = () => { if (matchSeq(seq)) { - var checkSpec = checkList[index++]; + const checkSpec = checkList[index++]; if (checkSpec.project.getSourceFileFromName(checkSpec.fileName, requireOpen)) { this.syntacticCheck(checkSpec.fileName, checkSpec.project); this.immediateId = setImmediate(() => { @@ -285,23 +286,23 @@ namespace ts.server { }); } } - } + }; if ((checkList.length > index) && (matchSeq(seq))) { this.errorTimer = setTimeout(checkOne, ms); } } private getDefinition(line: number, offset: number, fileName: string): protocol.FileSpan[] { - var file = ts.normalizePath(fileName); - var project = this.projectService.getProjectForFile(file); + const file = ts.normalizePath(fileName); + const project = this.projectService.getProjectForFile(file); if (!project) { throw Errors.NoProject; } - var compilerService = project.compilerService; - var position = compilerService.host.lineOffsetToPosition(file, line, offset); + const compilerService = project.compilerService; + const position = compilerService.host.lineOffsetToPosition(file, line, offset); - var definitions = compilerService.languageService.getDefinitionAtPosition(file, position); + const definitions = compilerService.languageService.getDefinitionAtPosition(file, position); if (!definitions) { return undefined; } @@ -314,16 +315,16 @@ namespace ts.server { } private getTypeDefinition(line: number, offset: number, fileName: string): protocol.FileSpan[] { - var file = ts.normalizePath(fileName); - var project = this.projectService.getProjectForFile(file); + const file = ts.normalizePath(fileName); + const project = this.projectService.getProjectForFile(file); if (!project) { throw Errors.NoProject; } - var compilerService = project.compilerService; - var position = compilerService.host.lineOffsetToPosition(file, line, offset); + const compilerService = project.compilerService; + const position = compilerService.host.lineOffsetToPosition(file, line, offset); - var definitions = compilerService.languageService.getTypeDefinitionAtPosition(file, position); + const definitions = compilerService.languageService.getTypeDefinitionAtPosition(file, position); if (!definitions) { return undefined; } @@ -361,7 +362,7 @@ namespace ts.server { end, file: fileName, isWriteAccess - } + }; }); } @@ -375,9 +376,9 @@ namespace ts.server { let { compilerService } = project; let position = compilerService.host.lineOffsetToPosition(fileName, line, offset); - + let documentHighlights = compilerService.languageService.getDocumentHighlights(fileName, position, filesToSearch); - + if (!documentHighlights) { return undefined; } @@ -402,12 +403,12 @@ namespace ts.server { } private getProjectInfo(fileName: string, needFileNameList: boolean): protocol.ProjectInfo { - fileName = ts.normalizePath(fileName) - let project = this.projectService.getProjectForFile(fileName) + fileName = ts.normalizePath(fileName); + let project = this.projectService.getProjectForFile(fileName); let projectInfo: protocol.ProjectInfo = { configFileName: project.projectFilename - } + }; if (needFileNameList) { projectInfo.fileNames = project.getFileNames(); @@ -416,16 +417,16 @@ namespace ts.server { return projectInfo; } - private getRenameLocations(line: number, offset: number, fileName: string,findInComments: boolean, findInStrings: boolean): protocol.RenameResponseBody { - var file = ts.normalizePath(fileName); - var project = this.projectService.getProjectForFile(file); + private getRenameLocations(line: number, offset: number, fileName: string, findInComments: boolean, findInStrings: boolean): protocol.RenameResponseBody { + const file = ts.normalizePath(fileName); + const project = this.projectService.getProjectForFile(file); if (!project) { throw Errors.NoProject; } - var compilerService = project.compilerService; - var position = compilerService.host.lineOffsetToPosition(file, line, offset); - var renameInfo = compilerService.languageService.getRenameInfo(file, position); + const compilerService = project.compilerService; + const position = compilerService.host.lineOffsetToPosition(file, line, offset); + const renameInfo = compilerService.languageService.getRenameInfo(file, position); if (!renameInfo) { return undefined; } @@ -437,12 +438,12 @@ namespace ts.server { }; } - var renameLocations = compilerService.languageService.findRenameLocations(file, position, findInStrings, findInComments); + const renameLocations = compilerService.languageService.findRenameLocations(file, position, findInStrings, findInComments); if (!renameLocations) { return undefined; } - var bakedRenameLocs = renameLocations.map(location => ({ + const bakedRenameLocs = renameLocations.map(location => ({ file: location.fileName, start: compilerService.host.positionToLineOffset(location.fileName, location.textSpan.start), end: compilerService.host.positionToLineOffset(location.fileName, ts.textSpanEnd(location.textSpan)), @@ -466,7 +467,7 @@ namespace ts.server { } } }).reduce((accum: protocol.SpanGroup[], cur: protocol.FileSpan) => { - var curFileAccum: protocol.SpanGroup; + let curFileAccum: protocol.SpanGroup; if (accum.length > 0) { curFileAccum = accum[accum.length - 1]; if (curFileAccum.file != cur.file) { @@ -487,34 +488,34 @@ namespace ts.server { private getReferences(line: number, offset: number, fileName: string): protocol.ReferencesResponseBody { // TODO: get all projects for this file; report refs for all projects deleting duplicates // can avoid duplicates by eliminating same ref file from subsequent projects - var file = ts.normalizePath(fileName); - var project = this.projectService.getProjectForFile(file); + const file = ts.normalizePath(fileName); + const project = this.projectService.getProjectForFile(file); if (!project) { throw Errors.NoProject; } - var compilerService = project.compilerService; - var position = compilerService.host.lineOffsetToPosition(file, line, offset); + const compilerService = project.compilerService; + const position = compilerService.host.lineOffsetToPosition(file, line, offset); - var references = compilerService.languageService.getReferencesAtPosition(file, position); + const references = compilerService.languageService.getReferencesAtPosition(file, position); if (!references) { return undefined; } - var nameInfo = compilerService.languageService.getQuickInfoAtPosition(file, position); + const nameInfo = compilerService.languageService.getQuickInfoAtPosition(file, position); if (!nameInfo) { return undefined; } - var displayString = ts.displayPartsToString(nameInfo.displayParts); - var nameSpan = nameInfo.textSpan; - var nameColStart = compilerService.host.positionToLineOffset(file, nameSpan.start).offset; - var nameText = compilerService.host.getScriptSnapshot(file).getText(nameSpan.start, ts.textSpanEnd(nameSpan)); - var bakedRefs: protocol.ReferencesResponseItem[] = references.map(ref => { - var start = compilerService.host.positionToLineOffset(ref.fileName, ref.textSpan.start); - var refLineSpan = compilerService.host.lineToTextSpan(ref.fileName, start.line - 1); - var snap = compilerService.host.getScriptSnapshot(ref.fileName); - var lineText = snap.getText(refLineSpan.start, ts.textSpanEnd(refLineSpan)).replace(/\r|\n/g, ""); + const displayString = ts.displayPartsToString(nameInfo.displayParts); + const nameSpan = nameInfo.textSpan; + const nameColStart = compilerService.host.positionToLineOffset(file, nameSpan.start).offset; + const nameText = compilerService.host.getScriptSnapshot(file).getText(nameSpan.start, ts.textSpanEnd(nameSpan)); + const bakedRefs: protocol.ReferencesResponseItem[] = references.map(ref => { + const start = compilerService.host.positionToLineOffset(ref.fileName, ref.textSpan.start); + const refLineSpan = compilerService.host.lineToTextSpan(ref.fileName, start.line - 1); + const snap = compilerService.host.getScriptSnapshot(ref.fileName); + const lineText = snap.getText(refLineSpan.start, ts.textSpanEnd(refLineSpan)).replace(/\r|\n/g, ""); return { file: ref.fileName, start: start, @@ -532,26 +533,26 @@ namespace ts.server { } private openClientFile(fileName: string) { - var file = ts.normalizePath(fileName); + const file = ts.normalizePath(fileName); this.projectService.openClientFile(file); } private getQuickInfo(line: number, offset: number, fileName: string): protocol.QuickInfoResponseBody { - var file = ts.normalizePath(fileName); - var project = this.projectService.getProjectForFile(file); + const file = ts.normalizePath(fileName); + const project = this.projectService.getProjectForFile(file); if (!project) { throw Errors.NoProject; } - var compilerService = project.compilerService; - var position = compilerService.host.lineOffsetToPosition(file, line, offset); - var quickInfo = compilerService.languageService.getQuickInfoAtPosition(file, position); + const compilerService = project.compilerService; + const position = compilerService.host.lineOffsetToPosition(file, line, offset); + const quickInfo = compilerService.languageService.getQuickInfoAtPosition(file, position); if (!quickInfo) { return undefined; } - var displayString = ts.displayPartsToString(quickInfo.displayParts); - var docString = ts.displayPartsToString(quickInfo.documentation); + const displayString = ts.displayPartsToString(quickInfo.displayParts); + const docString = ts.displayPartsToString(quickInfo.documentation); return { kind: quickInfo.kind, kindModifiers: quickInfo.kindModifiers, @@ -563,18 +564,18 @@ namespace ts.server { } private getFormattingEditsForRange(line: number, offset: number, endLine: number, endOffset: number, fileName: string): protocol.CodeEdit[] { - var file = ts.normalizePath(fileName); - var project = this.projectService.getProjectForFile(file); + const file = ts.normalizePath(fileName); + const project = this.projectService.getProjectForFile(file); if (!project) { throw Errors.NoProject; } - var compilerService = project.compilerService; - var startPosition = compilerService.host.lineOffsetToPosition(file, line, offset); - var endPosition = compilerService.host.lineOffsetToPosition(file, endLine, endOffset); - + const compilerService = project.compilerService; + const startPosition = compilerService.host.lineOffsetToPosition(file, line, offset); + const endPosition = compilerService.host.lineOffsetToPosition(file, endLine, endOffset); + // TODO: avoid duplicate code (with formatonkey) - var edits = compilerService.languageService.getFormattingEditsForRange(file, startPosition, endPosition, + const edits = compilerService.languageService.getFormattingEditsForRange(file, startPosition, endPosition, this.projectService.getFormatCodeOptions(file)); if (!edits) { return undefined; @@ -590,17 +591,17 @@ namespace ts.server { } private getFormattingEditsAfterKeystroke(line: number, offset: number, key: string, fileName: string): protocol.CodeEdit[] { - var file = ts.normalizePath(fileName); + const file = ts.normalizePath(fileName); - var project = this.projectService.getProjectForFile(file); + const project = this.projectService.getProjectForFile(file); if (!project) { throw Errors.NoProject; } - var compilerService = project.compilerService; - var position = compilerService.host.lineOffsetToPosition(file, line, offset); - var formatOptions = this.projectService.getFormatCodeOptions(file); - var edits = compilerService.languageService.getFormattingEditsAfterKeystroke(file, position, key, + const compilerService = project.compilerService; + const position = compilerService.host.lineOffsetToPosition(file, line, offset); + const formatOptions = this.projectService.getFormatCodeOptions(file); + const edits = compilerService.languageService.getFormattingEditsAfterKeystroke(file, position, key, formatOptions); // Check whether we should auto-indent. This will be when // the position is on a line containing only whitespace. @@ -609,23 +610,24 @@ namespace ts.server { // only to the previous line. If all this is true, then // add edits necessary to properly indent the current line. if ((key == "\n") && ((!edits) || (edits.length === 0) || allEditsBeforePos(edits, position))) { - var scriptInfo = compilerService.host.getScriptInfo(file); + const scriptInfo = compilerService.host.getScriptInfo(file); if (scriptInfo) { - var lineInfo = scriptInfo.getLineInfo(line); + const lineInfo = scriptInfo.getLineInfo(line); if (lineInfo && (lineInfo.leaf) && (lineInfo.leaf.text)) { - var lineText = lineInfo.leaf.text; + const lineText = lineInfo.leaf.text; if (lineText.search("\\S") < 0) { // TODO: get these options from host - var editorOptions: ts.EditorOptions = { + const editorOptions: ts.EditorOptions = { IndentSize: formatOptions.IndentSize, TabSize: formatOptions.TabSize, NewLineCharacter: "\n", ConvertTabsToSpaces: formatOptions.ConvertTabsToSpaces, IndentStyle: ts.IndentStyle.Smart, }; - var preferredIndent = compilerService.languageService.getIndentationAtPosition(file, position, editorOptions); - var hasIndent = 0; - for (var i = 0, len = lineText.length; i < len; i++) { + const preferredIndent = compilerService.languageService.getIndentationAtPosition(file, position, editorOptions); + let hasIndent = 0; + let i: number, len: number; + for (i = 0, len = lineText.length; i < len; i++) { if (lineText.charAt(i) == " ") { hasIndent++; } @@ -638,7 +640,7 @@ namespace ts.server { } // i points to the first non whitespace character if (preferredIndent !== hasIndent) { - var firstNoWhiteSpacePosition = lineInfo.offset + i; + let firstNoWhiteSpacePosition = lineInfo.offset + i; edits.push({ span: ts.createTextSpanFromBounds(lineInfo.offset, firstNoWhiteSpacePosition), newText: generateIndentString(preferredIndent, editorOptions) @@ -668,16 +670,16 @@ namespace ts.server { if (!prefix) { prefix = ""; } - var file = ts.normalizePath(fileName); - var project = this.projectService.getProjectForFile(file); + const file = ts.normalizePath(fileName); + const project = this.projectService.getProjectForFile(file); if (!project) { throw Errors.NoProject; } - var compilerService = project.compilerService; - var position = compilerService.host.lineOffsetToPosition(file, line, offset); + const compilerService = project.compilerService; + const position = compilerService.host.lineOffsetToPosition(file, line, offset); - var completions = compilerService.languageService.getCompletionsAtPosition(file, position); + const completions = compilerService.languageService.getCompletionsAtPosition(file, position); if (!completions) { return undefined; } @@ -692,17 +694,17 @@ namespace ts.server { private getCompletionEntryDetails(line: number, offset: number, entryNames: string[], fileName: string): protocol.CompletionEntryDetails[] { - var file = ts.normalizePath(fileName); - var project = this.projectService.getProjectForFile(file); + const file = ts.normalizePath(fileName); + const project = this.projectService.getProjectForFile(file); if (!project) { throw Errors.NoProject; } - var compilerService = project.compilerService; - var position = compilerService.host.lineOffsetToPosition(file, line, offset); + const compilerService = project.compilerService; + const position = compilerService.host.lineOffsetToPosition(file, line, offset); return entryNames.reduce((accum: protocol.CompletionEntryDetails[], entryName: string) => { - var details = compilerService.languageService.getCompletionEntryDetails(file, position, entryName); + const details = compilerService.languageService.getCompletionEntryDetails(file, position, entryName); if (details) { accum.push(details); } @@ -711,21 +713,21 @@ namespace ts.server { } private getSignatureHelpItems(line: number, offset: number, fileName: string): protocol.SignatureHelpItems { - var file = ts.normalizePath(fileName); - var project = this.projectService.getProjectForFile(file); + const file = ts.normalizePath(fileName); + const project = this.projectService.getProjectForFile(file); if (!project) { throw Errors.NoProject; } - - var compilerService = project.compilerService; - var position = compilerService.host.lineOffsetToPosition(file, line, offset); - var helpItems = compilerService.languageService.getSignatureHelpItems(file, position); + + const compilerService = project.compilerService; + const position = compilerService.host.lineOffsetToPosition(file, line, offset); + const helpItems = compilerService.languageService.getSignatureHelpItems(file, position); if (!helpItems) { return undefined; } - - var span = helpItems.applicableSpan; - var result: protocol.SignatureHelpItems = { + + const span = helpItems.applicableSpan; + const result: protocol.SignatureHelpItems = { items: helpItems.items, applicableSpan: { start: compilerService.host.positionToLineOffset(file, span.start), @@ -734,15 +736,15 @@ namespace ts.server { selectedItemIndex: helpItems.selectedItemIndex, argumentIndex: helpItems.argumentIndex, argumentCount: helpItems.argumentCount, - } - + }; + return result; } - + private getDiagnostics(delay: number, fileNames: string[]) { - var checkList = fileNames.reduce((accum: PendingErrorCheck[], fileName: string) => { + const checkList = fileNames.reduce((accum: PendingErrorCheck[], fileName: string) => { fileName = ts.normalizePath(fileName); - var project = this.projectService.getProjectForFile(fileName); + const project = this.projectService.getProjectForFile(fileName); if (project) { accum.push({ fileName, project }); } @@ -750,17 +752,17 @@ namespace ts.server { }, []); if (checkList.length > 0) { - this.updateErrorCheck(checkList, this.changeSeq,(n) => n === this.changeSeq, delay) + this.updateErrorCheck(checkList, this.changeSeq, (n) => n === this.changeSeq, delay); } } private change(line: number, offset: number, endLine: number, endOffset: number, insertString: string, fileName: string) { - var file = ts.normalizePath(fileName); - var project = this.projectService.getProjectForFile(file); + const file = ts.normalizePath(fileName); + const project = this.projectService.getProjectForFile(file); if (project) { - var compilerService = project.compilerService; - var start = compilerService.host.lineOffsetToPosition(file, line, offset); - var end = compilerService.host.lineOffsetToPosition(file, endLine, endOffset); + const compilerService = project.compilerService; + const start = compilerService.host.lineOffsetToPosition(file, line, offset); + const end = compilerService.host.lineOffsetToPosition(file, endLine, endOffset); if (start >= 0) { compilerService.host.editScript(file, start, end, insertString); this.changeSeq++; @@ -770,9 +772,9 @@ namespace ts.server { } private reload(fileName: string, tempFileName: string, reqSeq = 0) { - var file = ts.normalizePath(fileName); - var tmpfile = ts.normalizePath(tempFileName); - var project = this.projectService.getProjectForFile(file); + const file = ts.normalizePath(fileName); + const tmpfile = ts.normalizePath(tempFileName); + const project = this.projectService.getProjectForFile(file); if (project) { this.changeSeq++; // make sure no changes happen before this one is finished @@ -783,10 +785,10 @@ namespace ts.server { } private saveToTmp(fileName: string, tempFileName: string) { - var file = ts.normalizePath(fileName); - var tmpfile = ts.normalizePath(tempFileName); + const file = ts.normalizePath(fileName); + const tmpfile = ts.normalizePath(tempFileName); - var project = this.projectService.getProjectForFile(file); + const project = this.projectService.getProjectForFile(file); if (project) { project.compilerService.host.saveTo(file, tmpfile); } @@ -794,7 +796,7 @@ namespace ts.server { private closeClientFile(fileName: string) { if (!fileName) { return; } - var file = ts.normalizePath(fileName); + const file = ts.normalizePath(fileName); this.projectService.closeClientFile(file); } @@ -803,7 +805,7 @@ namespace ts.server { return undefined; } - var compilerService = project.compilerService; + const compilerService = project.compilerService; return items.map(item => ({ text: item.text, @@ -818,14 +820,14 @@ namespace ts.server { } private getNavigationBarItems(fileName: string): protocol.NavigationBarItem[] { - var file = ts.normalizePath(fileName); - var project = this.projectService.getProjectForFile(file); + const file = ts.normalizePath(fileName); + const project = this.projectService.getProjectForFile(file); if (!project) { throw Errors.NoProject; } - var compilerService = project.compilerService; - var items = compilerService.languageService.getNavigationBarItems(file); + const compilerService = project.compilerService; + const items = compilerService.languageService.getNavigationBarItems(file); if (!items) { return undefined; } @@ -834,22 +836,22 @@ namespace ts.server { } private getNavigateToItems(searchValue: string, fileName: string, maxResultCount?: number): protocol.NavtoItem[] { - var file = ts.normalizePath(fileName); - var project = this.projectService.getProjectForFile(file); + const file = ts.normalizePath(fileName); + const project = this.projectService.getProjectForFile(file); if (!project) { throw Errors.NoProject; } - var compilerService = project.compilerService; - var navItems = compilerService.languageService.getNavigateToItems(searchValue, maxResultCount); + const compilerService = project.compilerService; + const navItems = compilerService.languageService.getNavigateToItems(searchValue, maxResultCount); if (!navItems) { return undefined; } return navItems.map((navItem) => { - var start = compilerService.host.positionToLineOffset(navItem.fileName, navItem.textSpan.start); - var end = compilerService.host.positionToLineOffset(navItem.fileName, ts.textSpanEnd(navItem.textSpan)); - var bakedItem: protocol.NavtoItem = { + const start = compilerService.host.positionToLineOffset(navItem.fileName, navItem.textSpan.start); + const end = compilerService.host.positionToLineOffset(navItem.fileName, ts.textSpanEnd(navItem.textSpan)); + const bakedItem: protocol.NavtoItem = { name: navItem.name, kind: navItem.kind, file: navItem.fileName, @@ -859,7 +861,7 @@ namespace ts.server { if (navItem.kindModifiers && (navItem.kindModifiers != "")) { bakedItem.kindModifiers = navItem.kindModifiers; } - if (navItem.matchKind != 'none') { + if (navItem.matchKind !== "none") { bakedItem.matchKind = navItem.matchKind; } if (navItem.containerName && (navItem.containerName.length > 0)) { @@ -873,21 +875,21 @@ namespace ts.server { } private getBraceMatching(line: number, offset: number, fileName: string): protocol.TextSpan[] { - var file = ts.normalizePath(fileName); - - var project = this.projectService.getProjectForFile(file); + const file = ts.normalizePath(fileName); + + const project = this.projectService.getProjectForFile(file); if (!project) { throw Errors.NoProject; } - - var compilerService = project.compilerService; - var position = compilerService.host.lineOffsetToPosition(file, line, offset); - - var spans = compilerService.languageService.getBraceMatchingAtPosition(file, position); + + const compilerService = project.compilerService; + const position = compilerService.host.lineOffsetToPosition(file, line, offset); + + const spans = compilerService.languageService.getBraceMatchingAtPosition(file, position); if (!spans) { return undefined; } - + return spans.map(span => ({ start: compilerService.host.positionToLineOffset(file, span.start), end: compilerService.host.positionToLineOffset(file, span.start + span.length) @@ -943,59 +945,59 @@ namespace ts.server { exit() { } - private handlers : Map<(request: protocol.Request) => {response?: any, responseRequired?: boolean}> = { + private handlers: Map<(request: protocol.Request) => {response?: any, responseRequired?: boolean}> = { [CommandNames.Exit]: () => { this.exit(); return { responseRequired: false}; }, [CommandNames.Definition]: (request: protocol.Request) => { - var defArgs = request.arguments; + const defArgs = request.arguments; return {response: this.getDefinition(defArgs.line, defArgs.offset, defArgs.file), responseRequired: true}; }, [CommandNames.TypeDefinition]: (request: protocol.Request) => { - var defArgs = request.arguments; + const defArgs = request.arguments; return {response: this.getTypeDefinition(defArgs.line, defArgs.offset, defArgs.file), responseRequired: true}; }, [CommandNames.References]: (request: protocol.Request) => { - var defArgs = request.arguments; + const defArgs = request.arguments; return {response: this.getReferences(defArgs.line, defArgs.offset, defArgs.file), responseRequired: true}; }, [CommandNames.Rename]: (request: protocol.Request) => { - var renameArgs = request.arguments; - return {response: this.getRenameLocations(renameArgs.line, renameArgs.offset, renameArgs.file, renameArgs.findInComments, renameArgs.findInStrings), responseRequired: true} + const renameArgs = request.arguments; + return {response: this.getRenameLocations(renameArgs.line, renameArgs.offset, renameArgs.file, renameArgs.findInComments, renameArgs.findInStrings), responseRequired: true}; }, [CommandNames.Open]: (request: protocol.Request) => { - var openArgs = request.arguments; + const openArgs = request.arguments; this.openClientFile(openArgs.file); - return {responseRequired: false} + return {responseRequired: false}; }, [CommandNames.Quickinfo]: (request: protocol.Request) => { - var quickinfoArgs = request.arguments; + const quickinfoArgs = request.arguments; return {response: this.getQuickInfo(quickinfoArgs.line, quickinfoArgs.offset, quickinfoArgs.file), responseRequired: true}; }, [CommandNames.Format]: (request: protocol.Request) => { - var formatArgs = request.arguments; + const formatArgs = request.arguments; return {response: this.getFormattingEditsForRange(formatArgs.line, formatArgs.offset, formatArgs.endLine, formatArgs.endOffset, formatArgs.file), responseRequired: true}; }, [CommandNames.Formatonkey]: (request: protocol.Request) => { - var formatOnKeyArgs = request.arguments; + const formatOnKeyArgs = request.arguments; return {response: this.getFormattingEditsAfterKeystroke(formatOnKeyArgs.line, formatOnKeyArgs.offset, formatOnKeyArgs.key, formatOnKeyArgs.file), responseRequired: true}; }, [CommandNames.Completions]: (request: protocol.Request) => { - var completionsArgs = request.arguments; - return {response: this.getCompletions(completionsArgs.line, completionsArgs.offset, completionsArgs.prefix, completionsArgs.file), responseRequired: true} + const completionsArgs = request.arguments; + return {response: this.getCompletions(completionsArgs.line, completionsArgs.offset, completionsArgs.prefix, completionsArgs.file), responseRequired: true}; }, [CommandNames.CompletionDetails]: (request: protocol.Request) => { - var completionDetailsArgs = request.arguments; - return {response: this.getCompletionEntryDetails(completionDetailsArgs.line,completionDetailsArgs.offset, - completionDetailsArgs.entryNames,completionDetailsArgs.file), responseRequired: true} + const completionDetailsArgs = request.arguments; + return {response: this.getCompletionEntryDetails(completionDetailsArgs.line, completionDetailsArgs.offset, + completionDetailsArgs.entryNames, completionDetailsArgs.file), responseRequired: true}; }, [CommandNames.SignatureHelp]: (request: protocol.Request) => { - var signatureHelpArgs = request.arguments; - return {response: this.getSignatureHelpItems(signatureHelpArgs.line, signatureHelpArgs.offset, signatureHelpArgs.file), responseRequired: true} + const signatureHelpArgs = request.arguments; + return {response: this.getSignatureHelpItems(signatureHelpArgs.line, signatureHelpArgs.offset, signatureHelpArgs.file), responseRequired: true}; }, [CommandNames.Geterr]: (request: protocol.Request) => { - var geterrArgs = request.arguments; + const geterrArgs = request.arguments; return {response: this.getDiagnostics(geterrArgs.delay, geterrArgs.files), responseRequired: false}; }, [CommandNames.GeterrForProject]: (request: protocol.Request) => { @@ -1003,54 +1005,54 @@ namespace ts.server { return {response: this.getDiagnosticsForProject(delay, file), responseRequired: false}; }, [CommandNames.Change]: (request: protocol.Request) => { - var changeArgs = request.arguments; + const changeArgs = request.arguments; this.change(changeArgs.line, changeArgs.offset, changeArgs.endLine, changeArgs.endOffset, changeArgs.insertString, changeArgs.file); - return {responseRequired: false} + return {responseRequired: false}; }, [CommandNames.Configure]: (request: protocol.Request) => { - var configureArgs = request.arguments; + const configureArgs = request.arguments; this.projectService.setHostConfiguration(configureArgs); this.output(undefined, CommandNames.Configure, request.seq); - return {responseRequired: false} + return {responseRequired: false}; }, [CommandNames.Reload]: (request: protocol.Request) => { - var reloadArgs = request.arguments; + const reloadArgs = request.arguments; this.reload(reloadArgs.file, reloadArgs.tmpfile, request.seq); - return {responseRequired: false} + return {responseRequired: false}; }, [CommandNames.Saveto]: (request: protocol.Request) => { - var savetoArgs = request.arguments; + const savetoArgs = request.arguments; this.saveToTmp(savetoArgs.file, savetoArgs.tmpfile); - return {responseRequired: false} + return {responseRequired: false}; }, [CommandNames.Close]: (request: protocol.Request) => { - var closeArgs = request.arguments; + const closeArgs = request.arguments; this.closeClientFile(closeArgs.file); return {responseRequired: false}; }, [CommandNames.Navto]: (request: protocol.Request) => { - var navtoArgs = request.arguments; + const navtoArgs = request.arguments; return {response: this.getNavigateToItems(navtoArgs.searchValue, navtoArgs.file, navtoArgs.maxResultCount), responseRequired: true}; }, [CommandNames.Brace]: (request: protocol.Request) => { - var braceArguments = request.arguments; + const braceArguments = request.arguments; return {response: this.getBraceMatching(braceArguments.line, braceArguments.offset, braceArguments.file), responseRequired: true}; }, [CommandNames.NavBar]: (request: protocol.Request) => { - var navBarArgs = request.arguments; + const navBarArgs = request.arguments; return {response: this.getNavigationBarItems(navBarArgs.file), responseRequired: true}; }, [CommandNames.Occurrences]: (request: protocol.Request) => { - var { line, offset, file: fileName } = request.arguments; + const { line, offset, file: fileName } = request.arguments; return {response: this.getOccurrences(line, offset, fileName), responseRequired: true}; }, [CommandNames.DocumentHighlights]: (request: protocol.Request) => { - var { line, offset, file: fileName, filesToSearch } = request.arguments; + const { line, offset, file: fileName, filesToSearch } = request.arguments; return {response: this.getDocumentHighlights(line, offset, fileName, filesToSearch), responseRequired: true}; }, [CommandNames.ProjectInfo]: (request: protocol.Request) => { - var { file, needFileNameList } = request.arguments; + const { file, needFileNameList } = request.arguments; return {response: this.getProjectInfo(file, needFileNameList), responseRequired: true}; }, [CommandNames.ReloadProjects]: (request: protocol.ReloadProjectsRequest) => { @@ -1065,11 +1067,12 @@ namespace ts.server { this.handlers[command] = handler; } - public executeCommand(request: protocol.Request) : {response?: any, responseRequired?: boolean} { - var handler = this.handlers[request.command]; + public executeCommand(request: protocol.Request): {response?: any, responseRequired?: boolean} { + const handler = this.handlers[request.command]; if (handler) { return handler(request); - } else { + } + else { this.projectService.log("Unrecognized JSON command: " + JSON.stringify(request)); this.output(undefined, CommandNames.Unknown, request.seq, "Unrecognized JSON command: " + request.command); return {responseRequired: false}; @@ -1077,20 +1080,22 @@ namespace ts.server { } public onMessage(message: string) { + let start: number[]; if (this.logger.isVerbose()) { this.logger.info("request: " + message); - var start = this.hrtime(); + start = this.hrtime(); } + let request: protocol.Request; try { - var request = JSON.parse(message); - var {response, responseRequired} = this.executeCommand(request); + request = JSON.parse(message); + const {response, responseRequired} = this.executeCommand(request); if (this.logger.isVerbose()) { - var elapsed = this.hrtime(start); - var seconds = elapsed[0] - var nanoseconds = elapsed[1]; - var elapsedMs = ((1e9 * seconds) + nanoseconds)/1000000.0; - var leader = "Elapsed time (in milliseconds)"; + const elapsed = this.hrtime(start); + const seconds = elapsed[0]; + const nanoseconds = elapsed[1]; + const elapsedMs = ((1e9 * seconds) + nanoseconds) / 1000000.0; + let leader = "Elapsed time (in milliseconds)"; if (!responseRequired) { leader = "Async elapsed time (in milliseconds)"; } @@ -1102,7 +1107,8 @@ namespace ts.server { else if (responseRequired) { this.output(undefined, request.command, request.seq, "No content available."); } - } catch (err) { + } + catch (err) { if (err instanceof OperationCanceledException) { // Handle cancellation exceptions } diff --git a/src/services/services.ts b/src/services/services.ts index 5815e2ab1d1..6b7aa0ecbff 100644 --- a/src/services/services.ts +++ b/src/services/services.ts @@ -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; 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(getCanonicalFileName); + this.currentDirectory = host.getCurrentDirectory(); + this.fileNameToEntry = createFileMap(); // 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.set(path, entry); return entry; } - private getEntry(fileName: string): HostFileInformation { - return this.fileNameToEntry.get(fileName); + private getEntry(path: Path): HostFileInformation { + return this.fileNameToEntry.get(path); } - private contains(fileName: string): boolean { - return this.fileNameToEntry.contains(fileName); + private contains(path: Path): boolean { + return this.fileNameToEntry.contains(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; } } @@ -1993,7 +1997,7 @@ namespace ts { } - export function createDocumentRegistry(useCaseSensitiveFileNames?: boolean): DocumentRegistry { + export function createDocumentRegistry(useCaseSensitiveFileNames?: boolean, currentDirectory = ""): DocumentRegistry { // Maps from compiler setting target (ES3, ES5, etc.) to all the cached documents we have // for those settings. let buckets: Map> = {}; @@ -2007,7 +2011,7 @@ namespace ts { let key = getKeyFromCompilationSettings(settings); let bucket = lookUp(buckets, key); if (!bucket && createIfMissing) { - buckets[key] = bucket = createFileMap(getCanonicalFileName); + buckets[key] = bucket = createFileMap(); } 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.get(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.set(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.get(path); entry.languageServiceRefCount--; Debug.assert(entry.languageServiceRefCount >= 0); if (entry.languageServiceRefCount === 0) { - bucket.remove(fileName); + bucket.remove(path); } } @@ -2556,7 +2562,9 @@ namespace ts { } } - export function createLanguageService(host: LanguageServiceHost, documentRegistry: DocumentRegistry = createDocumentRegistry()): LanguageService { + export function createLanguageService(host: LanguageServiceHost, + documentRegistry: DocumentRegistry = createDocumentRegistry(host.useCaseSensitiveFileNames && host.useCaseSensitiveFileNames(), host.getCurrentDirectory())): LanguageService { + let syntaxTreeCache: SyntaxTreeCache = new SyntaxTreeCache(host); let ruleProvider: formatting.RulesProvider; let program: Program; @@ -2565,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(); @@ -2579,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 + "'."); } @@ -2641,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); @@ -2665,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); } } } @@ -2732,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 { diff --git a/tests/baselines/reference/constructorReturnsInvalidType.errors.txt b/tests/baselines/reference/constructorReturnsInvalidType.errors.txt index 2ebd59b3d93..a8fe1de4700 100644 --- a/tests/baselines/reference/constructorReturnsInvalidType.errors.txt +++ b/tests/baselines/reference/constructorReturnsInvalidType.errors.txt @@ -1,11 +1,16 @@ +tests/cases/compiler/constructorReturnsInvalidType.ts(3,16): error TS2322: Type 'number' is not assignable to type 'X'. + Property 'foo' is missing in type 'Number'. tests/cases/compiler/constructorReturnsInvalidType.ts(3,16): error TS2409: Return type of constructor signature must be assignable to the instance type of the class -==== tests/cases/compiler/constructorReturnsInvalidType.ts (1 errors) ==== +==== tests/cases/compiler/constructorReturnsInvalidType.ts (2 errors) ==== class X { constructor() { return 1; ~ +!!! error TS2322: Type 'number' is not assignable to type 'X'. +!!! error TS2322: Property 'foo' is missing in type 'Number'. + ~ !!! error TS2409: Return type of constructor signature must be assignable to the instance type of the class } foo() { } diff --git a/tests/baselines/reference/constructorWithAssignableReturnExpression.errors.txt b/tests/baselines/reference/constructorWithAssignableReturnExpression.errors.txt index f5ef669d31b..1f7d7133bd7 100644 --- a/tests/baselines/reference/constructorWithAssignableReturnExpression.errors.txt +++ b/tests/baselines/reference/constructorWithAssignableReturnExpression.errors.txt @@ -1,8 +1,13 @@ +tests/cases/conformance/classes/constructorDeclarations/constructorWithAssignableReturnExpression.ts(12,16): error TS2322: Type 'number' is not assignable to type 'D'. + Property 'x' is missing in type 'Number'. tests/cases/conformance/classes/constructorDeclarations/constructorWithAssignableReturnExpression.ts(12,16): error TS2409: Return type of constructor signature must be assignable to the instance type of the class +tests/cases/conformance/classes/constructorDeclarations/constructorWithAssignableReturnExpression.ts(26,16): error TS2322: Type '{ x: number; }' is not assignable to type 'F'. + Types of property 'x' are incompatible. + Type 'number' is not assignable to type 'T'. tests/cases/conformance/classes/constructorDeclarations/constructorWithAssignableReturnExpression.ts(26,16): error TS2409: Return type of constructor signature must be assignable to the instance type of the class -==== tests/cases/conformance/classes/constructorDeclarations/constructorWithAssignableReturnExpression.ts (2 errors) ==== +==== tests/cases/conformance/classes/constructorDeclarations/constructorWithAssignableReturnExpression.ts (4 errors) ==== // a class constructor may return an expression, it must be assignable to the class instance type to be valid class C { @@ -16,6 +21,9 @@ tests/cases/conformance/classes/constructorDeclarations/constructorWithAssignabl constructor() { return 1; // error ~ +!!! error TS2322: Type 'number' is not assignable to type 'D'. +!!! error TS2322: Property 'x' is missing in type 'Number'. + ~ !!! error TS2409: Return type of constructor signature must be assignable to the instance type of the class } } @@ -32,6 +40,10 @@ tests/cases/conformance/classes/constructorDeclarations/constructorWithAssignabl constructor() { return { x: 1 }; // error ~~~~~~~~ +!!! error TS2322: Type '{ x: number; }' is not assignable to type 'F'. +!!! error TS2322: Types of property 'x' are incompatible. +!!! error TS2322: Type 'number' is not assignable to type 'T'. + ~~~~~~~~ !!! error TS2409: Return type of constructor signature must be assignable to the instance type of the class } } diff --git a/tests/baselines/reference/returnInConstructor1.errors.txt b/tests/baselines/reference/returnInConstructor1.errors.txt index eca0037b4a3..dbe3b9e5ee8 100644 --- a/tests/baselines/reference/returnInConstructor1.errors.txt +++ b/tests/baselines/reference/returnInConstructor1.errors.txt @@ -1,10 +1,20 @@ +tests/cases/compiler/returnInConstructor1.ts(11,16): error TS2322: Type 'number' is not assignable to type 'B'. + Property 'foo' is missing in type 'Number'. tests/cases/compiler/returnInConstructor1.ts(11,16): error TS2409: Return type of constructor signature must be assignable to the instance type of the class +tests/cases/compiler/returnInConstructor1.ts(25,16): error TS2322: Type 'string' is not assignable to type 'D'. + Property 'foo' is missing in type 'String'. tests/cases/compiler/returnInConstructor1.ts(25,16): error TS2409: Return type of constructor signature must be assignable to the instance type of the class +tests/cases/compiler/returnInConstructor1.ts(39,16): error TS2322: Type '{ foo: number; }' is not assignable to type 'F'. + Types of property 'foo' are incompatible. + Type 'number' is not assignable to type 'string'. tests/cases/compiler/returnInConstructor1.ts(39,16): error TS2409: Return type of constructor signature must be assignable to the instance type of the class +tests/cases/compiler/returnInConstructor1.ts(55,16): error TS2322: Type 'G' is not assignable to type 'H'. + Types of property 'foo' are incompatible. + Type '() => void' is not assignable to type 'string'. tests/cases/compiler/returnInConstructor1.ts(55,16): error TS2409: Return type of constructor signature must be assignable to the instance type of the class -==== tests/cases/compiler/returnInConstructor1.ts (4 errors) ==== +==== tests/cases/compiler/returnInConstructor1.ts (8 errors) ==== class A { foo() { } constructor() { @@ -17,6 +27,9 @@ tests/cases/compiler/returnInConstructor1.ts(55,16): error TS2409: Return type o constructor() { return 1; // error ~ +!!! error TS2322: Type 'number' is not assignable to type 'B'. +!!! error TS2322: Property 'foo' is missing in type 'Number'. + ~ !!! error TS2409: Return type of constructor signature must be assignable to the instance type of the class } } @@ -33,6 +46,9 @@ tests/cases/compiler/returnInConstructor1.ts(55,16): error TS2409: Return type o constructor() { return "test"; // error ~~~~~~ +!!! error TS2322: Type 'string' is not assignable to type 'D'. +!!! error TS2322: Property 'foo' is missing in type 'String'. + ~~~~~~ !!! error TS2409: Return type of constructor signature must be assignable to the instance type of the class } } @@ -49,6 +65,10 @@ tests/cases/compiler/returnInConstructor1.ts(55,16): error TS2409: Return type o constructor() { return { foo: 1 }; //error ~~~~~~~~~~ +!!! error TS2322: Type '{ foo: number; }' is not assignable to type 'F'. +!!! error TS2322: Types of property 'foo' are incompatible. +!!! error TS2322: Type 'number' is not assignable to type 'string'. + ~~~~~~~~~~ !!! error TS2409: Return type of constructor signature must be assignable to the instance type of the class } } @@ -67,6 +87,10 @@ tests/cases/compiler/returnInConstructor1.ts(55,16): error TS2409: Return type o super(); return new G(); //error ~~~~~~~ +!!! error TS2322: Type 'G' is not assignable to type 'H'. +!!! error TS2322: Types of property 'foo' are incompatible. +!!! error TS2322: Type '() => void' is not assignable to type 'string'. + ~~~~~~~ !!! error TS2409: Return type of constructor signature must be assignable to the instance type of the class } } diff --git a/tests/baselines/reference/typeGuardFunctionErrors.errors.txt b/tests/baselines/reference/typeGuardFunctionErrors.errors.txt index b178b02c6b4..a1427dc2526 100644 --- a/tests/baselines/reference/typeGuardFunctionErrors.errors.txt +++ b/tests/baselines/reference/typeGuardFunctionErrors.errors.txt @@ -25,6 +25,8 @@ tests/cases/conformance/expressions/typeGuards/typeGuardFunctionErrors.ts(96,9): tests/cases/conformance/expressions/typeGuards/typeGuardFunctionErrors.ts(97,16): error TS1228: A type predicate is only allowed in return type position for functions and methods. tests/cases/conformance/expressions/typeGuards/typeGuardFunctionErrors.ts(98,20): error TS1228: A type predicate is only allowed in return type position for functions and methods. tests/cases/conformance/expressions/typeGuards/typeGuardFunctionErrors.ts(104,25): error TS1228: A type predicate is only allowed in return type position for functions and methods. +tests/cases/conformance/expressions/typeGuards/typeGuardFunctionErrors.ts(105,16): error TS2322: Type 'boolean' is not assignable to type 'D'. + Property 'm1' is missing in type 'Boolean'. tests/cases/conformance/expressions/typeGuards/typeGuardFunctionErrors.ts(105,16): error TS2409: Return type of constructor signature must be assignable to the instance type of the class tests/cases/conformance/expressions/typeGuards/typeGuardFunctionErrors.ts(107,20): error TS1228: A type predicate is only allowed in return type position for functions and methods. tests/cases/conformance/expressions/typeGuards/typeGuardFunctionErrors.ts(110,20): error TS1228: A type predicate is only allowed in return type position for functions and methods. @@ -37,7 +39,7 @@ tests/cases/conformance/expressions/typeGuards/typeGuardFunctionErrors.ts(133,34 tests/cases/conformance/expressions/typeGuards/typeGuardFunctionErrors.ts(137,39): error TS1230: A type predicate cannot reference element 'p1' in a binding pattern. -==== tests/cases/conformance/expressions/typeGuards/typeGuardFunctionErrors.ts (31 errors) ==== +==== tests/cases/conformance/expressions/typeGuards/typeGuardFunctionErrors.ts (32 errors) ==== class A { propA: number; @@ -192,6 +194,9 @@ tests/cases/conformance/expressions/typeGuards/typeGuardFunctionErrors.ts(137,39 !!! error TS1228: A type predicate is only allowed in return type position for functions and methods. return true; ~~~~ +!!! error TS2322: Type 'boolean' is not assignable to type 'D'. +!!! error TS2322: Property 'm1' is missing in type 'Boolean'. + ~~~~ !!! error TS2409: Return type of constructor signature must be assignable to the instance type of the class } get m1(p1: A): p1 is C {