Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
8 changes: 6 additions & 2 deletions src/compiler/core.ts
Original file line number Diff line number Diff line change
Expand Up @@ -1762,6 +1762,10 @@ namespace ts {
return compareComparableValues(a, b);
}

export function getStringComparer(ignoreCase?: boolean) {
return ignoreCase ? compareStringsCaseInsensitive : compareStringsCaseSensitive;
}

/**
* Creates a string comparer for use with string collation in the UI.
*/
Expand Down Expand Up @@ -2274,7 +2278,7 @@ namespace ts {
const aComponents = getNormalizedPathComponents(a, currentDirectory);
const bComponents = getNormalizedPathComponents(b, currentDirectory);
const sharedLength = Math.min(aComponents.length, bComponents.length);
const comparer = ignoreCase ? compareStringsCaseInsensitive : compareStringsCaseSensitive;
const comparer = getStringComparer(ignoreCase);
for (let i = 0; i < sharedLength; i++) {
const result = comparer(aComponents[i], bComponents[i]);
if (result !== Comparison.EqualTo) {
Expand Down Expand Up @@ -2615,7 +2619,7 @@ namespace ts {
}

// Sort the offsets array using either the literal or canonical path representations.
includeBasePaths.sort(useCaseSensitiveFileNames ? compareStringsCaseSensitive : compareStringsCaseInsensitive);
includeBasePaths.sort(getStringComparer(!useCaseSensitiveFileNames));

// Iterate over each include base path and include unique base paths that are not a
// subpath of an existing base path
Expand Down
2 changes: 1 addition & 1 deletion src/compiler/sys.ts
Original file line number Diff line number Diff line change
Expand Up @@ -698,7 +698,7 @@ namespace ts {
createWatchDirectoryUsing(dynamicPollingWatchFile || createDynamicPriorityPollingWatchFile({ getModifiedTime, setTimeout })) :
watchDirectoryUsingFsWatch;
const watchDirectoryRecursively = createRecursiveDirectoryWatcher({
filePathComparer: useCaseSensitiveFileNames ? compareStringsCaseSensitive : compareStringsCaseInsensitive,
filePathComparer: getStringComparer(!useCaseSensitiveFileNames),
directoryExists,
getAccessibleSortedChildDirectories: path => getAccessibleFileSystemEntries(path).directories,
watchDirectory,
Expand Down
171 changes: 129 additions & 42 deletions src/harness/unittests/tsserverProjectSystem.ts

Large diffs are not rendered by default.

157 changes: 87 additions & 70 deletions src/server/editorServices.ts

Large diffs are not rendered by default.

25 changes: 23 additions & 2 deletions src/server/project.ts
Original file line number Diff line number Diff line change
Expand Up @@ -591,6 +591,11 @@ namespace ts.server {
return this.rootFiles && this.rootFiles.length > 0;
}

/*@internal*/
isOrphan() {
return false;
}

getRootFiles() {
return this.rootFiles && this.rootFiles.map(info => info.fileName);
}
Expand Down Expand Up @@ -834,6 +839,10 @@ namespace ts.server {

/*@internal*/
updateTypingFiles(typingFiles: SortedReadonlyArray<string>) {
enumerateInsertsAndDeletes(typingFiles, this.typingFiles, getStringComparer(!this.useCaseSensitiveFileNames()),
/*inserted*/ noop,
removed => this.detachScriptInfoFromProject(removed)
);
this.typingFiles = typingFiles;
// Invalidate files with unresolved imports
this.resolutionCache.setFilesWithInvalidatedNonRelativeUnresolvedImports(this.cachedUnresolvedImportsPerFile);
Expand Down Expand Up @@ -894,7 +903,7 @@ namespace ts.server {

const oldExternalFiles = this.externalFiles || emptyArray as SortedReadonlyArray<string>;
this.externalFiles = this.getExternalFiles();
enumerateInsertsAndDeletes(this.externalFiles, oldExternalFiles, compareStringsCaseSensitive,
enumerateInsertsAndDeletes(this.externalFiles, oldExternalFiles, getStringComparer(!this.useCaseSensitiveFileNames()),
// Ensure a ScriptInfo is created for new external files. This is performed indirectly
// by the LSHost for files in the program when the program is retrieved above but
// the program doesn't contain external files so this must be done explicitly.
Expand Down Expand Up @@ -1169,6 +1178,10 @@ namespace ts.server {
/** this is canonical project root path */
readonly projectRootPath: string | undefined;

/*@internal*/
/** stored only if their is no projectRootPath and this isnt single inferred project */
readonly canonicalCurrentDirectory: string | undefined;

/*@internal*/
constructor(
projectService: ProjectService,
Expand All @@ -1187,12 +1200,15 @@ namespace ts.server {
projectService.host,
currentDirectory);
this.projectRootPath = projectRootPath && projectService.toCanonicalFileName(projectRootPath);
if (!projectRootPath && !projectService.useSingleInferredProject) {
this.canonicalCurrentDirectory = projectService.toCanonicalFileName(this.currentDirectory);
}
this.enableGlobalPlugins();
}

addRoot(info: ScriptInfo) {
Debug.assert(info.isScriptOpen());
this.projectService.startWatchingConfigFilesForInferredProjectRoot(info, this.projectService.openFiles.get(info.path));
this.projectService.startWatchingConfigFilesForInferredProjectRoot(info);
if (!this._isJsInferredProject && info.isJavaScript()) {
this.toggleJsInferredProject(/*isJsInferredProject*/ true);
}
Expand All @@ -1209,6 +1225,11 @@ namespace ts.server {
}
}

/*@internal*/
isOrphan() {
return !this.hasRoots();
}

isProjectWithSingleRoot() {
// - when useSingleInferredProject is not set and projectRootPath is not set,
// we can guarantee that this will be the only root
Expand Down
2 changes: 1 addition & 1 deletion src/server/scriptInfo.ts
Original file line number Diff line number Diff line change
Expand Up @@ -460,7 +460,7 @@ namespace ts.server {
}

isOrphan() {
return this.containingProjects.length === 0;
return !forEach(this.containingProjects, p => !p.isOrphan());
}

/**
Expand Down
4 changes: 2 additions & 2 deletions src/server/session.ts
Original file line number Diff line number Diff line change
Expand Up @@ -865,7 +865,7 @@ namespace ts.server {
symLinkedProjects = this.projectService.getSymlinkedProjects(scriptInfo);
}
// filter handles case when 'projects' is undefined
projects = filter(projects, p => p.languageServiceEnabled);
projects = filter(projects, p => p.languageServiceEnabled && !p.isOrphan());
if ((!projects || !projects.length) && !symLinkedProjects) {
return Errors.ThrowNoProject();
}
Expand Down Expand Up @@ -1336,7 +1336,7 @@ namespace ts.server {
symLinkedProjects ? { projects, symLinkedProjects } : projects,
(project, info) => {
let result: protocol.CompileOnSaveAffectedFileListSingleProject;
if (project.compileOnSaveEnabled && project.languageServiceEnabled && !project.getCompilationSettings().noEmit) {
if (project.compileOnSaveEnabled && project.languageServiceEnabled && !project.isOrphan() && !project.getCompilationSettings().noEmit) {
result = {
projectFileName: project.getProjectName(),
fileNames: project.getCompileOnSaveAffectedFileList(info),
Expand Down
2 changes: 1 addition & 1 deletion tests/baselines/reference/api/tsserverlibrary.d.ts
Original file line number Diff line number Diff line change
Expand Up @@ -8067,7 +8067,6 @@ declare namespace ts.server {
* @param info The file that has been closed or newly configured
*/
private closeOpenFile;
private deleteOrphanScriptInfoNotInAnyProject;
private deleteScriptInfo;
private configFileExists;
private setConfigFileExistenceByNewConfiguredProject;
Expand Down Expand Up @@ -8124,6 +8123,7 @@ declare namespace ts.server {
private sendConfigFileDiagEvent;
private getOrCreateInferredProjectForProjectRootPathIfEnabled;
private getOrCreateSingleInferredProjectIfEnabled;
private getOrCreateSingleInferredWithoutProjectRoot;
private createInferredProject;
getScriptInfo(uncheckedFileName: string): ScriptInfo;
private watchClosedScriptInfo;
Expand Down