Skip to content

Commit 65521bc

Browse files
committed
Feedback from the PR
1 parent ae87838 commit 65521bc

6 files changed

Lines changed: 91 additions & 44 deletions

File tree

src/compiler/commandLineParser.ts

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1478,7 +1478,11 @@ namespace ts {
14781478
}
14791479
}
14801480

1481-
export function getErrorForNoInputFiles({ includeSpecs, excludeSpecs }: ConfigFileSpecs, configFileName?: string) {
1481+
export function isErrorNoInputFiles(error: Diagnostic) {
1482+
return error.code === Diagnostics.No_inputs_were_found_in_config_file_0_Specified_include_paths_were_1_and_exclude_paths_were_2.code;
1483+
}
1484+
1485+
export function getErrorForNoInputFiles({ includeSpecs, excludeSpecs }: ConfigFileSpecs, configFileName: string | undefined) {
14821486
return createCompilerDiagnostic(
14831487
Diagnostics.No_inputs_were_found_in_config_file_0_Specified_include_paths_were_1_and_exclude_paths_were_2,
14841488
configFileName || "tsconfig.json",

src/compiler/types.ts

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -3930,9 +3930,9 @@ namespace ts {
39303930
}
39313931

39323932
export interface ResolvedModuleWithFailedLookupLocations {
3933-
resolvedModule: ResolvedModuleFull | undefined;
3933+
readonly resolvedModule: ResolvedModuleFull | undefined;
39343934
/* @internal */
3935-
failedLookupLocations: string[];
3935+
readonly failedLookupLocations: string[];
39363936
/*@internal*/
39373937
isInvalidated?: boolean;
39383938
}
@@ -3945,8 +3945,8 @@ namespace ts {
39453945
}
39463946

39473947
export interface ResolvedTypeReferenceDirectiveWithFailedLookupLocations {
3948-
resolvedTypeReferenceDirective: ResolvedTypeReferenceDirective;
3949-
failedLookupLocations: string[];
3948+
readonly resolvedTypeReferenceDirective: ResolvedTypeReferenceDirective;
3949+
readonly failedLookupLocations: string[];
39503950
/*@internal*/
39513951
isInvalidated?: boolean;
39523952
}

src/harness/unittests/projectErrors.ts

Lines changed: 8 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -23,11 +23,9 @@ namespace ts.projectSystem {
2323
function checkDiagnosticsWithLinePos(errors: server.protocol.DiagnosticWithLinePosition[], expectedErrors: string[]) {
2424
assert.equal(errors ? errors.length : 0, expectedErrors.length, `expected ${expectedErrors.length} error in the list`);
2525
if (expectedErrors.length) {
26-
for (let i = 0; i < errors.length; i++) {
27-
const actualMessage = errors[i].message;
28-
const expectedMessage = expectedErrors[i];
29-
assert.isTrue(actualMessage.indexOf(errors[i].message) === 0, `error message does not match, expected ${actualMessage} to start with ${expectedMessage}`);
30-
}
26+
zipWith(errors, expectedErrors, ({ message: actualMessage }, expectedMessage) => {
27+
assert.isTrue(startsWith(actualMessage, actualMessage), `error message does not match, expected ${actualMessage} to start with ${expectedMessage}`);
28+
});
3129
}
3230
}
3331

@@ -40,12 +38,11 @@ namespace ts.projectSystem {
4038
path: "/a/b/applib.ts",
4139
content: ""
4240
};
43-
// only file1 exists - expect error
4441
const host = createServerHost([file1, libFile]);
4542
const session = createSession(host);
4643
const projectService = session.getProjectService();
4744
const projectFileName = "/a/b/test.csproj";
48-
const compilerOptionsRequest = <server.protocol.CompilerOptionsDiagnosticsRequest>{
45+
const compilerOptionsRequest: server.protocol.CompilerOptionsDiagnosticsRequest = {
4946
type: "request",
5047
command: server.CommandNames.CompilerOptionsDiagnosticsFull,
5148
seq: 2,
@@ -61,19 +58,20 @@ namespace ts.projectSystem {
6158

6259
checkNumberOfProjects(projectService, { externalProjects: 1 });
6360
const diags = session.executeCommand(compilerOptionsRequest).response;
61+
// only file1 exists - expect error
6462
checkDiagnosticsWithLinePos(diags, ["File '/a/b/applib.ts' not found."]);
6563
}
66-
// only file2 exists - expect error
6764
host.reloadFS([file2, libFile]);
6865
{
66+
// only file2 exists - expect error
6967
checkNumberOfProjects(projectService, { externalProjects: 1 });
7068
const diags = session.executeCommand(compilerOptionsRequest).response;
7169
checkDiagnosticsWithLinePos(diags, ["File '/a/b/app.ts' not found."]);
7270
}
7371

74-
// both files exist - expect no errors
7572
host.reloadFS([file1, file2, libFile]);
7673
{
74+
// both files exist - expect no errors
7775
checkNumberOfProjects(projectService, { externalProjects: 1 });
7876
const diags = session.executeCommand(compilerOptionsRequest).response;
7977
checkDiagnosticsWithLinePos(diags, []);
@@ -99,7 +97,7 @@ namespace ts.projectSystem {
9997
openFilesForSession([file1], session);
10098
checkNumberOfProjects(projectService, { configuredProjects: 1 });
10199
const project = configuredProjectAt(projectService, 0);
102-
const compilerOptionsRequest = <server.protocol.CompilerOptionsDiagnosticsRequest>{
100+
const compilerOptionsRequest: server.protocol.CompilerOptionsDiagnosticsRequest = {
103101
type: "request",
104102
command: server.CommandNames.CompilerOptionsDiagnosticsFull,
105103
seq: 2,

src/harness/unittests/tsserverProjectSystem.ts

Lines changed: 63 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -253,29 +253,19 @@ namespace ts.projectSystem {
253253
entries: FSEntry[];
254254
}
255255

256-
export function isFolder(s: FSEntry): s is Folder {
256+
export function isFolder(s: FSEntry | undefined): s is Folder {
257257
return s && isArray((<Folder>s).entries);
258258
}
259259

260-
export function isFile(s: FSEntry): s is File {
260+
export function isFile(s: FSEntry | undefined): s is File {
261261
return s && typeof (<File>s).content === "string";
262262
}
263263

264-
function invokeDirectoryWatcher(callbacks: DirectoryWatcherCallback[], getRelativeFilePath: () => string) {
264+
function invokeWatcherCallbacks<T>(callbacks: T[], invokeCallback: (cb: T) => void): void {
265265
if (callbacks) {
266266
const cbs = callbacks.slice();
267267
for (const cb of cbs) {
268-
const fileName = getRelativeFilePath();
269-
cb(fileName);
270-
}
271-
}
272-
}
273-
274-
function invokeFileWatcher(callbacks: FileWatcherCallback[], fileName: string, eventId: FileWatcherEventKind) {
275-
if (callbacks) {
276-
const cbs = callbacks.slice();
277-
for (const cb of cbs) {
278-
cb(fileName, eventId);
268+
invokeCallback(cb);
279269
}
280270
}
281271
}
@@ -380,7 +370,7 @@ namespace ts.projectSystem {
380370

381371
private readonly output: string[] = [];
382372

383-
private fs: Map<FSEntry> = createMap<FSEntry>();
373+
private fs = createMap<FSEntry>();
384374
private getCanonicalFileName: (s: string) => string;
385375
private toPath: (f: string) => Path;
386376
private timeoutCallbacks = new Callbacks();
@@ -510,8 +500,12 @@ namespace ts.projectSystem {
510500
}
511501
else {
512502
Debug.assert(fileOrFolder.entries.length === 0);
513-
invokeDirectoryWatcher(this.watchedDirectories.get(fileOrFolder.path), () => this.getRelativePathToDirectory(fileOrFolder.fullPath, fileOrFolder.fullPath));
514-
invokeDirectoryWatcher(this.watchedDirectoriesRecursive.get(fileOrFolder.path), () => this.getRelativePathToDirectory(fileOrFolder.fullPath, fileOrFolder.fullPath));
503+
const relativePath = this.getRelativePathToDirectory(fileOrFolder.fullPath, fileOrFolder.fullPath);
504+
// Invoke directory and recursive directory watcher for the folder
505+
// Here we arent invoking recursive directory watchers for the base folders
506+
// since that is something we would want to do for both file as well as folder we are deleting
507+
invokeWatcherCallbacks(this.watchedDirectories.get(fileOrFolder.path), cb => cb(relativePath));
508+
invokeWatcherCallbacks(this.watchedDirectoriesRecursive.get(fileOrFolder.path), cb => cb(relativePath));
515509
}
516510

517511
if (basePath !== fileOrFolder.path) {
@@ -524,22 +518,31 @@ namespace ts.projectSystem {
524518
}
525519
}
526520

527-
private invokeFileWatcher(fileFullPath: string, eventId: FileWatcherEventKind) {
521+
private invokeFileWatcher(fileFullPath: string, eventKind: FileWatcherEventKind) {
528522
const callbacks = this.watchedFiles.get(this.toPath(fileFullPath));
529-
invokeFileWatcher(callbacks, getBaseFileName(fileFullPath), eventId);
523+
const fileName = getBaseFileName(fileFullPath);
524+
invokeWatcherCallbacks(callbacks, cb => cb(fileName, eventKind));
530525
}
531526

532527
private getRelativePathToDirectory(directoryFullPath: string, fileFullPath: string) {
533528
return getRelativePathToDirectoryOrUrl(directoryFullPath, fileFullPath, this.currentDirectory, this.getCanonicalFileName, /*isAbsolutePathAnUrl*/ false);
534529
}
535530

531+
/**
532+
* This will call the directory watcher for the foldeFullPath and recursive directory watchers for this and base folders
533+
*/
536534
private invokeDirectoryWatcher(folderFullPath: string, fileName: string) {
537-
invokeDirectoryWatcher(this.watchedDirectories.get(this.toPath(folderFullPath)), () => this.getRelativePathToDirectory(folderFullPath, fileName));
535+
const relativePath = this.getRelativePathToDirectory(folderFullPath, fileName);
536+
invokeWatcherCallbacks(this.watchedDirectories.get(this.toPath(folderFullPath)), cb => cb(relativePath));
538537
this.invokeRecursiveDirectoryWatcher(folderFullPath, fileName);
539538
}
540539

540+
/**
541+
* This will call the recursive directory watcher for this directory as well as all the base directories
542+
*/
541543
private invokeRecursiveDirectoryWatcher(fullPath: string, fileName: string) {
542-
invokeDirectoryWatcher(this.watchedDirectoriesRecursive.get(this.toPath(fullPath)), () => this.getRelativePathToDirectory(fullPath, fileName));
544+
const relativePath = this.getRelativePathToDirectory(fullPath, fileName);
545+
invokeWatcherCallbacks(this.watchedDirectoriesRecursive.get(this.toPath(fullPath)), cb => cb(relativePath));
543546
const basePath = getDirectoryPath(fullPath);
544547
if (this.getCanonicalFileName(fullPath) !== this.getCanonicalFileName(basePath)) {
545548
this.invokeRecursiveDirectoryWatcher(basePath, fileName);
@@ -885,6 +888,45 @@ namespace ts.projectSystem {
885888
checkWatchedDirectories(host, [getDirectoryPath(configFile.path)], /*recursive*/ true);
886889
});
887890

891+
it("create configured project with the file list", () => {
892+
const configFile: FileOrFolder = {
893+
path: "/a/b/tsconfig.json",
894+
content: `
895+
{
896+
"compilerOptions": {},
897+
"include": ["*.ts"]
898+
}`
899+
};
900+
const file1: FileOrFolder = {
901+
path: "/a/b/f1.ts",
902+
content: "let x = 1"
903+
};
904+
const file2: FileOrFolder = {
905+
path: "/a/b/f2.ts",
906+
content: "let y = 1"
907+
};
908+
const file3: FileOrFolder = {
909+
path: "/a/b/c/f3.ts",
910+
content: "let z = 1"
911+
};
912+
913+
const host = createServerHost([configFile, libFile, file1, file2, file3]);
914+
const projectService = createProjectService(host);
915+
const { configFileName, configFileErrors } = projectService.openClientFile(file1.path);
916+
917+
assert(configFileName, "should find config file");
918+
assert.isTrue(!configFileErrors, `expect no errors in config file, got ${JSON.stringify(configFileErrors)}`);
919+
checkNumberOfInferredProjects(projectService, 0);
920+
checkNumberOfConfiguredProjects(projectService, 1);
921+
922+
const project = configuredProjectAt(projectService, 0);
923+
checkProjectActualFiles(project, [file1.path, libFile.path, file2.path, configFile.path]);
924+
checkProjectRootFiles(project, [file1.path, file2.path]);
925+
// watching all files except one that was open
926+
checkWatchedFiles(host, [configFile.path, file2.path, libFile.path]);
927+
checkWatchedDirectories(host, [getDirectoryPath(configFile.path)], /*recursive*/ false);
928+
});
929+
888930
it("add and then remove a config file in a folder with loose files", () => {
889931
const configFile: FileOrFolder = {
890932
path: "/a/b/tsconfig.json",

src/server/editorServices.ts

Lines changed: 1 addition & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -665,14 +665,7 @@ namespace ts.server {
665665

666666
const configFileSpecs = project.configFileSpecs;
667667
const result = getFileNamesFromConfigSpecs(configFileSpecs, getDirectoryPath(configFilename), project.getCompilerOptions(), project.getCachedServerHost(), this.hostConfiguration.extraFileExtensions);
668-
const errors = project.getAllProjectErrors();
669-
const isErrorNoInputFiles = (error: Diagnostic) => error.code === Diagnostics.No_inputs_were_found_in_config_file_0_Specified_include_paths_were_1_and_exclude_paths_were_2.code;
670-
if (result.fileNames.length !== 0) {
671-
filterMutate(errors, error => !isErrorNoInputFiles(error));
672-
}
673-
else if (!configFileSpecs.filesSpecs && !some(errors, isErrorNoInputFiles)) {
674-
errors.push(getErrorForNoInputFiles(configFileSpecs, configFilename));
675-
}
668+
project.updateErrorOnNoInputFiles(result.fileNames.length !== 0);
676669
this.updateNonInferredProjectFiles(project, result.fileNames, fileNamePropertyReader, /*clientFileName*/ undefined);
677670
this.delayUpdateProjectGraphAndInferredProjectsRefresh(project);
678671
}

src/server/project.ts

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1226,6 +1226,16 @@ namespace ts.server {
12261226
getEffectiveTypeRoots() {
12271227
return getEffectiveTypeRoots(this.getCompilerOptions(), this.lsHost.host) || [];
12281228
}
1229+
1230+
/*@internal*/
1231+
updateErrorOnNoInputFiles(hasFileNames: boolean) {
1232+
if (hasFileNames) {
1233+
filterMutate(this.projectErrors, error => !isErrorNoInputFiles(error));
1234+
}
1235+
else if (!this.configFileSpecs.filesSpecs && !some(this.projectErrors, isErrorNoInputFiles)) {
1236+
this.projectErrors.push(getErrorForNoInputFiles(this.configFileSpecs, this.getConfigFilePath()));
1237+
}
1238+
}
12291239
}
12301240

12311241
/**

0 commit comments

Comments
 (0)