Feedback from the PR

This commit is contained in:
Sheetal Nandi 2017-08-07 14:47:32 -07:00
parent ae87838f45
commit 65521bc259
6 changed files with 91 additions and 44 deletions

View File

@ -1478,7 +1478,11 @@ namespace ts {
}
}
export function getErrorForNoInputFiles({ includeSpecs, excludeSpecs }: ConfigFileSpecs, configFileName?: string) {
export function isErrorNoInputFiles(error: Diagnostic) {
return error.code === Diagnostics.No_inputs_were_found_in_config_file_0_Specified_include_paths_were_1_and_exclude_paths_were_2.code;
}
export function getErrorForNoInputFiles({ includeSpecs, excludeSpecs }: ConfigFileSpecs, configFileName: string | undefined) {
return createCompilerDiagnostic(
Diagnostics.No_inputs_were_found_in_config_file_0_Specified_include_paths_were_1_and_exclude_paths_were_2,
configFileName || "tsconfig.json",

View File

@ -3930,9 +3930,9 @@ namespace ts {
}
export interface ResolvedModuleWithFailedLookupLocations {
resolvedModule: ResolvedModuleFull | undefined;
readonly resolvedModule: ResolvedModuleFull | undefined;
/* @internal */
failedLookupLocations: string[];
readonly failedLookupLocations: string[];
/*@internal*/
isInvalidated?: boolean;
}
@ -3945,8 +3945,8 @@ namespace ts {
}
export interface ResolvedTypeReferenceDirectiveWithFailedLookupLocations {
resolvedTypeReferenceDirective: ResolvedTypeReferenceDirective;
failedLookupLocations: string[];
readonly resolvedTypeReferenceDirective: ResolvedTypeReferenceDirective;
readonly failedLookupLocations: string[];
/*@internal*/
isInvalidated?: boolean;
}

View File

@ -23,11 +23,9 @@ namespace ts.projectSystem {
function checkDiagnosticsWithLinePos(errors: server.protocol.DiagnosticWithLinePosition[], expectedErrors: string[]) {
assert.equal(errors ? errors.length : 0, expectedErrors.length, `expected ${expectedErrors.length} error in the list`);
if (expectedErrors.length) {
for (let i = 0; i < errors.length; i++) {
const actualMessage = errors[i].message;
const expectedMessage = expectedErrors[i];
assert.isTrue(actualMessage.indexOf(errors[i].message) === 0, `error message does not match, expected ${actualMessage} to start with ${expectedMessage}`);
}
zipWith(errors, expectedErrors, ({ message: actualMessage }, expectedMessage) => {
assert.isTrue(startsWith(actualMessage, actualMessage), `error message does not match, expected ${actualMessage} to start with ${expectedMessage}`);
});
}
}
@ -40,12 +38,11 @@ namespace ts.projectSystem {
path: "/a/b/applib.ts",
content: ""
};
// only file1 exists - expect error
const host = createServerHost([file1, libFile]);
const session = createSession(host);
const projectService = session.getProjectService();
const projectFileName = "/a/b/test.csproj";
const compilerOptionsRequest = <server.protocol.CompilerOptionsDiagnosticsRequest>{
const compilerOptionsRequest: server.protocol.CompilerOptionsDiagnosticsRequest = {
type: "request",
command: server.CommandNames.CompilerOptionsDiagnosticsFull,
seq: 2,
@ -61,19 +58,20 @@ namespace ts.projectSystem {
checkNumberOfProjects(projectService, { externalProjects: 1 });
const diags = session.executeCommand(compilerOptionsRequest).response;
// only file1 exists - expect error
checkDiagnosticsWithLinePos(diags, ["File '/a/b/applib.ts' not found."]);
}
// only file2 exists - expect error
host.reloadFS([file2, libFile]);
{
// only file2 exists - expect error
checkNumberOfProjects(projectService, { externalProjects: 1 });
const diags = session.executeCommand(compilerOptionsRequest).response;
checkDiagnosticsWithLinePos(diags, ["File '/a/b/app.ts' not found."]);
}
// both files exist - expect no errors
host.reloadFS([file1, file2, libFile]);
{
// both files exist - expect no errors
checkNumberOfProjects(projectService, { externalProjects: 1 });
const diags = session.executeCommand(compilerOptionsRequest).response;
checkDiagnosticsWithLinePos(diags, []);
@ -99,7 +97,7 @@ namespace ts.projectSystem {
openFilesForSession([file1], session);
checkNumberOfProjects(projectService, { configuredProjects: 1 });
const project = configuredProjectAt(projectService, 0);
const compilerOptionsRequest = <server.protocol.CompilerOptionsDiagnosticsRequest>{
const compilerOptionsRequest: server.protocol.CompilerOptionsDiagnosticsRequest = {
type: "request",
command: server.CommandNames.CompilerOptionsDiagnosticsFull,
seq: 2,

View File

@ -253,29 +253,19 @@ namespace ts.projectSystem {
entries: FSEntry[];
}
export function isFolder(s: FSEntry): s is Folder {
export function isFolder(s: FSEntry | undefined): s is Folder {
return s && isArray((<Folder>s).entries);
}
export function isFile(s: FSEntry): s is File {
export function isFile(s: FSEntry | undefined): s is File {
return s && typeof (<File>s).content === "string";
}
function invokeDirectoryWatcher(callbacks: DirectoryWatcherCallback[], getRelativeFilePath: () => string) {
function invokeWatcherCallbacks<T>(callbacks: T[], invokeCallback: (cb: T) => void): void {
if (callbacks) {
const cbs = callbacks.slice();
for (const cb of cbs) {
const fileName = getRelativeFilePath();
cb(fileName);
}
}
}
function invokeFileWatcher(callbacks: FileWatcherCallback[], fileName: string, eventId: FileWatcherEventKind) {
if (callbacks) {
const cbs = callbacks.slice();
for (const cb of cbs) {
cb(fileName, eventId);
invokeCallback(cb);
}
}
}
@ -380,7 +370,7 @@ namespace ts.projectSystem {
private readonly output: string[] = [];
private fs: Map<FSEntry> = createMap<FSEntry>();
private fs = createMap<FSEntry>();
private getCanonicalFileName: (s: string) => string;
private toPath: (f: string) => Path;
private timeoutCallbacks = new Callbacks();
@ -510,8 +500,12 @@ namespace ts.projectSystem {
}
else {
Debug.assert(fileOrFolder.entries.length === 0);
invokeDirectoryWatcher(this.watchedDirectories.get(fileOrFolder.path), () => this.getRelativePathToDirectory(fileOrFolder.fullPath, fileOrFolder.fullPath));
invokeDirectoryWatcher(this.watchedDirectoriesRecursive.get(fileOrFolder.path), () => this.getRelativePathToDirectory(fileOrFolder.fullPath, fileOrFolder.fullPath));
const relativePath = this.getRelativePathToDirectory(fileOrFolder.fullPath, fileOrFolder.fullPath);
// Invoke directory and recursive directory watcher for the folder
// Here we arent invoking recursive directory watchers for the base folders
// since that is something we would want to do for both file as well as folder we are deleting
invokeWatcherCallbacks(this.watchedDirectories.get(fileOrFolder.path), cb => cb(relativePath));
invokeWatcherCallbacks(this.watchedDirectoriesRecursive.get(fileOrFolder.path), cb => cb(relativePath));
}
if (basePath !== fileOrFolder.path) {
@ -524,22 +518,31 @@ namespace ts.projectSystem {
}
}
private invokeFileWatcher(fileFullPath: string, eventId: FileWatcherEventKind) {
private invokeFileWatcher(fileFullPath: string, eventKind: FileWatcherEventKind) {
const callbacks = this.watchedFiles.get(this.toPath(fileFullPath));
invokeFileWatcher(callbacks, getBaseFileName(fileFullPath), eventId);
const fileName = getBaseFileName(fileFullPath);
invokeWatcherCallbacks(callbacks, cb => cb(fileName, eventKind));
}
private getRelativePathToDirectory(directoryFullPath: string, fileFullPath: string) {
return getRelativePathToDirectoryOrUrl(directoryFullPath, fileFullPath, this.currentDirectory, this.getCanonicalFileName, /*isAbsolutePathAnUrl*/ false);
}
/**
* This will call the directory watcher for the foldeFullPath and recursive directory watchers for this and base folders
*/
private invokeDirectoryWatcher(folderFullPath: string, fileName: string) {
invokeDirectoryWatcher(this.watchedDirectories.get(this.toPath(folderFullPath)), () => this.getRelativePathToDirectory(folderFullPath, fileName));
const relativePath = this.getRelativePathToDirectory(folderFullPath, fileName);
invokeWatcherCallbacks(this.watchedDirectories.get(this.toPath(folderFullPath)), cb => cb(relativePath));
this.invokeRecursiveDirectoryWatcher(folderFullPath, fileName);
}
/**
* This will call the recursive directory watcher for this directory as well as all the base directories
*/
private invokeRecursiveDirectoryWatcher(fullPath: string, fileName: string) {
invokeDirectoryWatcher(this.watchedDirectoriesRecursive.get(this.toPath(fullPath)), () => this.getRelativePathToDirectory(fullPath, fileName));
const relativePath = this.getRelativePathToDirectory(fullPath, fileName);
invokeWatcherCallbacks(this.watchedDirectoriesRecursive.get(this.toPath(fullPath)), cb => cb(relativePath));
const basePath = getDirectoryPath(fullPath);
if (this.getCanonicalFileName(fullPath) !== this.getCanonicalFileName(basePath)) {
this.invokeRecursiveDirectoryWatcher(basePath, fileName);
@ -885,6 +888,45 @@ namespace ts.projectSystem {
checkWatchedDirectories(host, [getDirectoryPath(configFile.path)], /*recursive*/ true);
});
it("create configured project with the file list", () => {
const configFile: FileOrFolder = {
path: "/a/b/tsconfig.json",
content: `
{
"compilerOptions": {},
"include": ["*.ts"]
}`
};
const file1: FileOrFolder = {
path: "/a/b/f1.ts",
content: "let x = 1"
};
const file2: FileOrFolder = {
path: "/a/b/f2.ts",
content: "let y = 1"
};
const file3: FileOrFolder = {
path: "/a/b/c/f3.ts",
content: "let z = 1"
};
const host = createServerHost([configFile, libFile, file1, file2, file3]);
const projectService = createProjectService(host);
const { configFileName, configFileErrors } = projectService.openClientFile(file1.path);
assert(configFileName, "should find config file");
assert.isTrue(!configFileErrors, `expect no errors in config file, got ${JSON.stringify(configFileErrors)}`);
checkNumberOfInferredProjects(projectService, 0);
checkNumberOfConfiguredProjects(projectService, 1);
const project = configuredProjectAt(projectService, 0);
checkProjectActualFiles(project, [file1.path, libFile.path, file2.path, configFile.path]);
checkProjectRootFiles(project, [file1.path, file2.path]);
// watching all files except one that was open
checkWatchedFiles(host, [configFile.path, file2.path, libFile.path]);
checkWatchedDirectories(host, [getDirectoryPath(configFile.path)], /*recursive*/ false);
});
it("add and then remove a config file in a folder with loose files", () => {
const configFile: FileOrFolder = {
path: "/a/b/tsconfig.json",

View File

@ -665,14 +665,7 @@ namespace ts.server {
const configFileSpecs = project.configFileSpecs;
const result = getFileNamesFromConfigSpecs(configFileSpecs, getDirectoryPath(configFilename), project.getCompilerOptions(), project.getCachedServerHost(), this.hostConfiguration.extraFileExtensions);
const errors = project.getAllProjectErrors();
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;
if (result.fileNames.length !== 0) {
filterMutate(errors, error => !isErrorNoInputFiles(error));
}
else if (!configFileSpecs.filesSpecs && !some(errors, isErrorNoInputFiles)) {
errors.push(getErrorForNoInputFiles(configFileSpecs, configFilename));
}
project.updateErrorOnNoInputFiles(result.fileNames.length !== 0);
this.updateNonInferredProjectFiles(project, result.fileNames, fileNamePropertyReader, /*clientFileName*/ undefined);
this.delayUpdateProjectGraphAndInferredProjectsRefresh(project);
}

View File

@ -1226,6 +1226,16 @@ namespace ts.server {
getEffectiveTypeRoots() {
return getEffectiveTypeRoots(this.getCompilerOptions(), this.lsHost.host) || [];
}
/*@internal*/
updateErrorOnNoInputFiles(hasFileNames: boolean) {
if (hasFileNames) {
filterMutate(this.projectErrors, error => !isErrorNoInputFiles(error));
}
else if (!this.configFileSpecs.filesSpecs && !some(this.projectErrors, isErrorNoInputFiles)) {
this.projectErrors.push(getErrorForNoInputFiles(this.configFileSpecs, this.getConfigFilePath()));
}
}
}
/**