diff --git a/src/compiler/program.ts b/src/compiler/program.ts index c8ff2496725..1397d46af1c 100644 --- a/src/compiler/program.ts +++ b/src/compiler/program.ts @@ -984,11 +984,18 @@ namespace ts { return true; } - if (defaultLibraryPath && defaultLibraryPath.length !== 0) { - return containsPath(defaultLibraryPath, file.path, currentDirectory, /*ignoreCase*/ !host.useCaseSensitiveFileNames()); + if (!options.noLib) { + return false; } - return compareStrings(file.fileName, getDefaultLibraryFileName(), /*ignoreCase*/ !host.useCaseSensitiveFileNames()) === Comparison.EqualTo; + // If '--lib' is not specified, include default library file according to '--target' + // otherwise, using options specified in '--lib' instead of '--target' default library file + if (!options.lib) { + return compareStrings(file.fileName, getDefaultLibraryFileName(), /*ignoreCase*/ !host.useCaseSensitiveFileNames()) === Comparison.EqualTo; + } + else { + return forEach(options.lib, libFileName => compareStrings(file.fileName, combinePaths(defaultLibraryPath, libFileName), /*ignoreCase*/ !host.useCaseSensitiveFileNames()) === Comparison.EqualTo); + } } function getDiagnosticsProducingTypeChecker() { diff --git a/src/harness/unittests/compileOnSave.ts b/src/harness/unittests/compileOnSave.ts index 89b980f23f8..dddcd64cd39 100644 --- a/src/harness/unittests/compileOnSave.ts +++ b/src/harness/unittests/compileOnSave.ts @@ -567,7 +567,7 @@ namespace ts.projectSystem { path: "/a/b/file3.js", content: "console.log('file3');" }; - const externalProjectName = "externalproject"; + const externalProjectName = "/a/b/externalproject"; const host = createServerHost([file1, file2, file3, libFile]); const session = createSession(host); const projectService = session.getProjectService(); diff --git a/src/harness/unittests/session.ts b/src/harness/unittests/session.ts index f37c9ea2392..417591cdb6f 100644 --- a/src/harness/unittests/session.ts +++ b/src/harness/unittests/session.ts @@ -16,8 +16,8 @@ namespace ts.server { directoryExists: () => false, getDirectories: () => [], createDirectory: noop, - getExecutingFilePath(): string { return void 0; }, - getCurrentDirectory(): string { return void 0; }, + getExecutingFilePath(): string { return ""; }, + getCurrentDirectory(): string { return ""; }, getEnvironmentVariable(): string { return ""; }, readDirectory() { return []; }, exit: noop, diff --git a/src/server/builder.ts b/src/server/builder.ts index 5cf65611fb3..0279f08bfab 100644 --- a/src/server/builder.ts +++ b/src/server/builder.ts @@ -148,9 +148,8 @@ namespace ts.server { const { emitSkipped, outputFiles } = this.project.getFileEmitOutput(fileInfo.scriptInfo, /*emitOnlyDtsFiles*/ false); if (!emitSkipped) { - const projectRootPath = this.project.getProjectRootPath(); for (const outputFile of outputFiles) { - const outputFileAbsoluteFileName = getNormalizedAbsolutePath(outputFile.name, projectRootPath ? projectRootPath : getDirectoryPath(scriptInfo.fileName)); + const outputFileAbsoluteFileName = getNormalizedAbsolutePath(outputFile.name, this.project.currentDirectory); writeFile(outputFileAbsoluteFileName, outputFile.text, outputFile.writeByteOrderMark); } } diff --git a/src/server/editorServices.ts b/src/server/editorServices.ts index d86f45a9ad9..9a12c4cab7c 100644 --- a/src/server/editorServices.ts +++ b/src/server/editorServices.ts @@ -417,7 +417,7 @@ namespace ts.server { this.globalPlugins = opts.globalPlugins || emptyArray; this.pluginProbeLocations = opts.pluginProbeLocations || emptyArray; this.allowLocalPluginLoads = !!opts.allowLocalPluginLoads; - this.typesMapLocation = (opts.typesMapLocation === undefined) ? combinePaths(this.host.getExecutingFilePath(), "../typesMap.json") : opts.typesMapLocation; + this.typesMapLocation = (opts.typesMapLocation === undefined) ? combinePaths(this.getExecutingFilePath(), "../typesMap.json") : opts.typesMapLocation; Debug.assert(!!this.host.createHash, "'ServerHost.createHash' is required for ProjectService"); @@ -442,6 +442,16 @@ namespace ts.server { this.documentRegistry = createDocumentRegistry(this.host.useCaseSensitiveFileNames, this.host.getCurrentDirectory()); } + /*@internal*/ + getExecutingFilePath() { + return this.getNormalizedAbsolutePath(this.host.getExecutingFilePath()); + } + + /*@internal*/ + getNormalizedAbsolutePath(fileName: string) { + return getNormalizedAbsolutePath(fileName, this.host.getCurrentDirectory()); + } + /* @internal */ getChangedFiles_TestOnly() { return this.changedFiles; @@ -924,6 +934,14 @@ namespace ts.server { }); } + /*@internal*/ getScriptInfoPaths() { + const result: Path[] = []; + this.filenameToScriptInfo.forEach(info => { + result.push(info.path); + }); + return result; + } + /** * This function tries to search for a tsconfig.json for the given file. If we found it, * we first detect if there is already a configured project created for it: if so, we re-read @@ -1365,7 +1383,7 @@ namespace ts.server { return project; } } - return this.createInferredProject(/*isSingleInferredProject*/ false, projectRootPath); + return this.createInferredProject(projectRootPath, /*isSingleInferredProject*/ false, projectRootPath); } // we don't have an explicit root path, so we should try to find an inferred project @@ -1402,12 +1420,13 @@ namespace ts.server { return this.inferredProjects[0]; } - return this.createInferredProject(/*isSingleInferredProject*/ true); + // Single inferred project does not have a project root. + return this.createInferredProject(/*currentDirectory*/ undefined, /*isSingleInferredProject*/ true); } - private createInferredProject(isSingleInferredProject?: boolean, projectRootPath?: string): InferredProject { + private createInferredProject(currentDirectory: string | undefined, isSingleInferredProject?: boolean, projectRootPath?: string): InferredProject { const compilerOptions = projectRootPath && this.compilerOptionsForInferredProjectsPerProjectRoot.get(projectRootPath) || this.compilerOptionsForInferredProjects; - const project = new InferredProject(this, this.documentRegistry, compilerOptions, projectRootPath); + const project = new InferredProject(this, this.documentRegistry, compilerOptions, currentDirectory, projectRootPath); if (isSingleInferredProject) { this.inferredProjects.unshift(project); } @@ -1419,8 +1438,8 @@ namespace ts.server { createInferredProjectWithRootFileIfNecessary(root: ScriptInfo, projectRootPath?: string) { const project = this.getOrCreateInferredProjectForProjectRootPathIfEnabled(root, projectRootPath) || - this.getOrCreateSingleInferredProjectIfEnabled() || - this.createInferredProject(); + this.getOrCreateSingleInferredProjectIfEnabled() || + this.createInferredProject(getDirectoryPath(root.path)); project.addRoot(root); diff --git a/src/server/lsHost.ts b/src/server/lsHost.ts index 13b9505a658..08dd5000cba 100644 --- a/src/server/lsHost.ts +++ b/src/server/lsHost.ts @@ -173,7 +173,7 @@ namespace ts.server { } getDefaultLibFileName() { - const nodeModuleBinDir = getDirectoryPath(normalizePath(this.host.getExecutingFilePath())); + const nodeModuleBinDir = getDirectoryPath(this.project.projectService.getExecutingFilePath()); return combinePaths(nodeModuleBinDir, getDefaultLibFileName(this.compilationSettings)); } @@ -203,7 +203,7 @@ namespace ts.server { } getCurrentDirectory(): string { - return this.host.getCurrentDirectory(); + return this.project.currentDirectory; } resolvePath(path: string): string { diff --git a/src/server/project.ts b/src/server/project.ts index 9ef79530e51..084193a97f5 100644 --- a/src/server/project.ts +++ b/src/server/project.ts @@ -177,6 +177,9 @@ namespace ts.server { return result.module; } + /*@internal*/ + readonly currentDirectory: string; + constructor( private readonly projectName: string, readonly projectKind: ProjectKind, @@ -185,8 +188,9 @@ namespace ts.server { hasExplicitListOfFiles: boolean, languageServiceEnabled: boolean, private compilerOptions: CompilerOptions, - public compileOnSaveEnabled: boolean) { - + public compileOnSaveEnabled: boolean, + currentDirectory: string | undefined) { + this.currentDirectory = this.projectService.getNormalizedAbsolutePath(currentDirectory || ""); if (!this.compilerOptions) { this.compilerOptions = getDefaultCompilerOptions(); this.compilerOptions.allowNonTsExtensions = true; @@ -268,7 +272,6 @@ namespace ts.server { getProjectName() { return this.projectName; } - abstract getProjectRootPath(): string | undefined; abstract getTypeAcquisition(): TypeAcquisition; getExternalFiles(): SortedReadonlyArray { @@ -363,7 +366,7 @@ namespace ts.server { return map(this.program.getSourceFiles(), sourceFile => { const scriptInfo = this.projectService.getScriptInfoForPath(sourceFile.path); if (!scriptInfo) { - Debug.fail(`scriptInfo for a file '${sourceFile.fileName}' is missing.`); + Debug.fail(`scriptInfo for a file '${sourceFile.fileName}' Path: '${sourceFile.path}' is missing.\nProgram currentDirectory: '${this.program.getCurrentDirectory()}'\nCurrentScriptInfos: ${this.projectService.getScriptInfoPaths()}\ncurrentDirectory: ${this.projectService.host.getCurrentDirectory()}`); } return scriptInfo; }); @@ -842,8 +845,6 @@ namespace ts.server { * the file and its imports/references are put into an InferredProject. */ export class InferredProject extends Project { - public readonly projectRootPath: string | undefined; - private static readonly newName = (() => { let nextId = 1; return () => { @@ -882,7 +883,7 @@ namespace ts.server { // Used to keep track of what directories are watched for this project directoriesWatchedForTsconfig: string[] = []; - constructor(projectService: ProjectService, documentRegistry: DocumentRegistry, compilerOptions: CompilerOptions, projectRootPath?: string) { + constructor(projectService: ProjectService, documentRegistry: DocumentRegistry, compilerOptions: CompilerOptions, currentDirectory: string | undefined, readonly projectRootPath: string | undefined) { super(InferredProject.newName(), ProjectKind.Inferred, projectService, @@ -890,7 +891,8 @@ namespace ts.server { /*files*/ undefined, /*languageServiceEnabled*/ true, compilerOptions, - /*compileOnSaveEnabled*/ false); + /*compileOnSaveEnabled*/ false, + currentDirectory); this.projectRootPath = projectRootPath; } @@ -910,15 +912,6 @@ namespace ts.server { super.removeRoot(info); } - getProjectRootPath() { - // Single inferred project does not have a project root. - if (this.projectService.useSingleInferredProject) { - return undefined; - } - const rootFiles = this.getRootFiles(); - return getDirectoryPath(rootFiles[0]); - } - close() { super.close(); @@ -962,7 +955,15 @@ namespace ts.server { private wildcardDirectories: Map, languageServiceEnabled: boolean, public compileOnSaveEnabled: boolean) { - super(configFileName, ProjectKind.Configured, projectService, documentRegistry, hasExplicitListOfFiles, languageServiceEnabled, compilerOptions, compileOnSaveEnabled); + super(configFileName, + ProjectKind.Configured, + projectService, + documentRegistry, + hasExplicitListOfFiles, + languageServiceEnabled, + compilerOptions, + compileOnSaveEnabled, + getDirectoryPath(configFileName)); this.canonicalConfigFilePath = asNormalizedPath(projectService.toCanonicalFileName(configFileName)); this.enablePlugins(); } @@ -982,7 +983,7 @@ namespace ts.server { // Search our peer node_modules, then any globally-specified probe paths // ../../.. to walk from X/node_modules/typescript/lib/tsserver.js to X/node_modules/ - const searchPaths = [combinePaths(host.getExecutingFilePath(), "../../.."), ...this.projectService.pluginProbeLocations]; + const searchPaths = [combinePaths(this.projectService.getExecutingFilePath(), "../../.."), ...this.projectService.pluginProbeLocations]; if (this.projectService.allowLocalPluginLoads) { const local = getDirectoryPath(this.canonicalConfigFilePath); @@ -1062,10 +1063,6 @@ namespace ts.server { } } - getProjectRootPath() { - return getDirectoryPath(this.getConfigFilePath()); - } - setProjectErrors(projectErrors: ReadonlyArray) { this.projectErrors = projectErrors; } @@ -1196,25 +1193,22 @@ namespace ts.server { compilerOptions: CompilerOptions, languageServiceEnabled: boolean, public compileOnSaveEnabled: boolean, - private readonly projectFilePath?: string) { - super(externalProjectName, ProjectKind.External, projectService, documentRegistry, /*hasExplicitListOfFiles*/ true, languageServiceEnabled, compilerOptions, compileOnSaveEnabled); - + projectFilePath?: string) { + super(externalProjectName, + ProjectKind.External, + projectService, + documentRegistry, + /*hasExplicitListOfFiles*/ true, + languageServiceEnabled, + compilerOptions, + compileOnSaveEnabled, + getDirectoryPath(projectFilePath || normalizeSlashes(externalProjectName))); } getExcludedFiles() { return this.excludedFiles; } - getProjectRootPath() { - if (this.projectFilePath) { - return getDirectoryPath(this.projectFilePath); - } - // if the projectFilePath is not given, we make the assumption that the project name - // is the path of the project file. AS the project name is provided by VS, we need to - // normalize slashes before using it as a file name. - return getDirectoryPath(normalizeSlashes(this.getProjectName())); - } - getTypeAcquisition() { return this.typeAcquisition; } diff --git a/tests/cases/fourslash/server/projectInfo01.ts b/tests/cases/fourslash/server/projectInfo01.ts index 0d8707bf8a1..036aa5f0d4d 100644 --- a/tests/cases/fourslash/server/projectInfo01.ts +++ b/tests/cases/fourslash/server/projectInfo01.ts @@ -14,11 +14,11 @@ ////console.log("nothing"); goTo.file("a.ts") -verify.ProjectInfo(["lib.d.ts", "a.ts"]) +verify.ProjectInfo(["/lib.d.ts", "a.ts"]) goTo.file("b.ts") -verify.ProjectInfo(["lib.d.ts", "a.ts", "b.ts"]) +verify.ProjectInfo(["/lib.d.ts", "a.ts", "b.ts"]) goTo.file("c.ts") -verify.ProjectInfo(["lib.d.ts", "a.ts", "b.ts", "c.ts"]) +verify.ProjectInfo(["/lib.d.ts", "a.ts", "b.ts", "c.ts"]) goTo.file("d.ts") -verify.ProjectInfo(["lib.d.ts", "d.ts"]) +verify.ProjectInfo(["/lib.d.ts", "d.ts"]) diff --git a/tests/cases/fourslash/server/projectInfo02.ts b/tests/cases/fourslash/server/projectInfo02.ts index 3077deb453c..fb7c9cf8257 100644 --- a/tests/cases/fourslash/server/projectInfo02.ts +++ b/tests/cases/fourslash/server/projectInfo02.ts @@ -10,4 +10,4 @@ ////{ "files": ["a.ts", "b.ts"] } goTo.file("a.ts") -verify.ProjectInfo(["lib.d.ts", "a.ts", "b.ts", "tsconfig.json"]) +verify.ProjectInfo(["/lib.d.ts", "a.ts", "b.ts", "tsconfig.json"]) diff --git a/tests/cases/fourslash/server/projectWithNonExistentFiles.ts b/tests/cases/fourslash/server/projectWithNonExistentFiles.ts index 0e263d9aca6..a52c5f8918f 100644 --- a/tests/cases/fourslash/server/projectWithNonExistentFiles.ts +++ b/tests/cases/fourslash/server/projectWithNonExistentFiles.ts @@ -10,4 +10,4 @@ ////{ "files": ["a.ts", "c.ts", "b.ts"] } goTo.file("a.ts"); -verify.ProjectInfo(["lib.d.ts", "a.ts", "b.ts", "tsconfig.json"]) +verify.ProjectInfo(["/lib.d.ts", "a.ts", "b.ts", "tsconfig.json"])