Skip to content

Commit 9b98d00

Browse files
author
Paul van Brenk
committed
Merge branch 'master' into pvb/codeaction/api
2 parents dc516c0 + 2671668 commit 9b98d00

File tree

9 files changed

+513
-47
lines changed

9 files changed

+513
-47
lines changed

src/compiler/binder.ts

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -2223,9 +2223,9 @@ namespace ts {
22232223
if (currentFlow) {
22242224
node.flowNode = currentFlow;
22252225
}
2226-
checkStrictModeFunctionName(<FunctionExpression>node);
2227-
const bindingName = (<FunctionExpression>node).name ? (<FunctionExpression>node).name.text : "__function";
2228-
return bindAnonymousDeclaration(<FunctionExpression>node, SymbolFlags.Function, bindingName);
2226+
checkStrictModeFunctionName(node);
2227+
const bindingName = node.name ? node.name.text : "__function";
2228+
return bindAnonymousDeclaration(node, SymbolFlags.Function, bindingName);
22292229
}
22302230

22312231
function bindPropertyOrMethodOrAccessor(node: Declaration, symbolFlags: SymbolFlags, symbolExcludes: SymbolFlags) {

src/compiler/parser.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5352,7 +5352,7 @@ namespace ts {
53525352
parseExpected(SyntaxKind.EqualsToken);
53535353
node.type = parseType();
53545354
parseSemicolon();
5355-
return finishNode(node);
5355+
return addJSDocComment(finishNode(node));
53565356
}
53575357

53585358
// In an ambient declaration, the grammar only allows integer literals as initializers.

src/harness/unittests/tsserverProjectSystem.ts

Lines changed: 192 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
/// <reference path="..\harness.ts" />
1+
/// <reference path="..\harness.ts" />
22
/// <reference path="../../server/typingsInstaller/typingsInstaller.ts" />
33

44
namespace ts.projectSystem {
@@ -136,6 +136,19 @@ namespace ts.projectSystem {
136136
return map(fileNames, toExternalFile);
137137
}
138138

139+
export class TestServerEventManager {
140+
private events: server.ProjectServiceEvent[] = [];
141+
142+
handler: server.ProjectServiceEventHandler = (event: server.ProjectServiceEvent) => {
143+
this.events.push(event);
144+
}
145+
146+
checkEventCountOfType(eventType: "context" | "configFileDiag", expectedCount: number) {
147+
const eventsOfType = filter(this.events, e => e.eventName === eventType);
148+
assert.equal(eventsOfType.length, expectedCount, `The actual event counts of type ${eventType} is ${eventsOfType.length}, while expected ${expectedCount}`);
149+
}
150+
}
151+
139152
export interface TestServerHostCreationParameters {
140153
useCaseSensitiveFileNames?: boolean;
141154
executingFilePath?: string;
@@ -159,11 +172,11 @@ namespace ts.projectSystem {
159172
return host;
160173
}
161174

162-
export function createSession(host: server.ServerHost, typingsInstaller?: server.ITypingsInstaller) {
175+
export function createSession(host: server.ServerHost, typingsInstaller?: server.ITypingsInstaller, projectServiceEventHandler?: server.ProjectServiceEventHandler) {
163176
if (typingsInstaller === undefined) {
164177
typingsInstaller = new TestTypingsInstaller("/a/data/", /*throttleLimit*/5, host);
165178
}
166-
return new server.Session(host, nullCancellationToken, /*useSingleInferredProject*/ false, typingsInstaller, Utils.byteLength, process.hrtime, nullLogger, /*canUseEvents*/ false);
179+
return new server.Session(host, nullCancellationToken, /*useSingleInferredProject*/ false, typingsInstaller, Utils.byteLength, process.hrtime, nullLogger, /*canUseEvents*/ projectServiceEventHandler !== undefined, projectServiceEventHandler);
167180
}
168181

169182
export interface CreateProjectServiceParameters {
@@ -2084,7 +2097,7 @@ namespace ts.projectSystem {
20842097
const projectFileName = "externalProject";
20852098
const host = createServerHost([f]);
20862099
const projectService = createProjectService(host);
2087-
// create a project
2100+
// create a project
20882101
projectService.openExternalProject({ projectFileName, rootFiles: [toExternalFile(f.path)], options: {} });
20892102
projectService.checkNumberOfProjects({ externalProjects: 1 });
20902103

@@ -2121,4 +2134,179 @@ namespace ts.projectSystem {
21212134
projectService.inferredProjects[0].getLanguageService().getProgram();
21222135
});
21232136
});
2137+
2138+
describe("rename a module file and rename back", () => {
2139+
it("should restore the states for inferred projects", () => {
2140+
const moduleFile = {
2141+
path: "/a/b/moduleFile.ts",
2142+
content: "export function bar() { };"
2143+
};
2144+
const file1 = {
2145+
path: "/a/b/file1.ts",
2146+
content: "import * as T from './moduleFile'; T.bar();"
2147+
};
2148+
const host = createServerHost([moduleFile, file1]);
2149+
const session = createSession(host);
2150+
2151+
openFilesForSession([file1], session);
2152+
const getErrRequest = makeSessionRequest<server.protocol.SemanticDiagnosticsSyncRequestArgs>(
2153+
server.CommandNames.SemanticDiagnosticsSync,
2154+
{ file: file1.path }
2155+
);
2156+
let diags = <server.protocol.Diagnostic[]>session.executeCommand(getErrRequest).response;
2157+
assert.equal(diags.length, 0);
2158+
2159+
const moduleFileOldPath = moduleFile.path;
2160+
const moduleFileNewPath = "/a/b/moduleFile1.ts";
2161+
moduleFile.path = moduleFileNewPath;
2162+
host.reloadFS([moduleFile, file1]);
2163+
host.triggerFileWatcherCallback(moduleFileOldPath);
2164+
host.triggerDirectoryWatcherCallback("/a/b", moduleFile.path);
2165+
host.runQueuedTimeoutCallbacks();
2166+
diags = <server.protocol.Diagnostic[]>session.executeCommand(getErrRequest).response;
2167+
assert.equal(diags.length, 1);
2168+
2169+
moduleFile.path = moduleFileOldPath;
2170+
host.reloadFS([moduleFile, file1]);
2171+
host.triggerFileWatcherCallback(moduleFileNewPath);
2172+
host.triggerDirectoryWatcherCallback("/a/b", moduleFile.path);
2173+
host.runQueuedTimeoutCallbacks();
2174+
2175+
// Make a change to trigger the program rebuild
2176+
const changeRequest = makeSessionRequest<server.protocol.ChangeRequestArgs>(
2177+
server.CommandNames.Change,
2178+
{ file: file1.path, line: 1, offset: 44, endLine: 1, endOffset: 44, insertString: "\n" }
2179+
);
2180+
session.executeCommand(changeRequest);
2181+
host.runQueuedTimeoutCallbacks();
2182+
2183+
diags = <server.protocol.Diagnostic[]>session.executeCommand(getErrRequest).response;
2184+
assert.equal(diags.length, 0);
2185+
});
2186+
2187+
it("should restore the states for configured projects", () => {
2188+
const moduleFile = {
2189+
path: "/a/b/moduleFile.ts",
2190+
content: "export function bar() { };"
2191+
};
2192+
const file1 = {
2193+
path: "/a/b/file1.ts",
2194+
content: "import * as T from './moduleFile'; T.bar();"
2195+
};
2196+
const configFile = {
2197+
path: "/a/b/tsconfig.json",
2198+
content: `{}`
2199+
};
2200+
const host = createServerHost([moduleFile, file1, configFile]);
2201+
const session = createSession(host);
2202+
2203+
openFilesForSession([file1], session);
2204+
const getErrRequest = makeSessionRequest<server.protocol.SemanticDiagnosticsSyncRequestArgs>(
2205+
server.CommandNames.SemanticDiagnosticsSync,
2206+
{ file: file1.path }
2207+
);
2208+
let diags = <server.protocol.Diagnostic[]>session.executeCommand(getErrRequest).response;
2209+
assert.equal(diags.length, 0);
2210+
2211+
const moduleFileOldPath = moduleFile.path;
2212+
const moduleFileNewPath = "/a/b/moduleFile1.ts";
2213+
moduleFile.path = moduleFileNewPath;
2214+
host.reloadFS([moduleFile, file1, configFile]);
2215+
host.triggerFileWatcherCallback(moduleFileOldPath);
2216+
host.triggerDirectoryWatcherCallback("/a/b", moduleFile.path);
2217+
host.runQueuedTimeoutCallbacks();
2218+
diags = <server.protocol.Diagnostic[]>session.executeCommand(getErrRequest).response;
2219+
assert.equal(diags.length, 1);
2220+
2221+
moduleFile.path = moduleFileOldPath;
2222+
host.reloadFS([moduleFile, file1, configFile]);
2223+
host.triggerFileWatcherCallback(moduleFileNewPath);
2224+
host.triggerDirectoryWatcherCallback("/a/b", moduleFile.path);
2225+
host.runQueuedTimeoutCallbacks();
2226+
diags = <server.protocol.Diagnostic[]>session.executeCommand(getErrRequest).response;
2227+
assert.equal(diags.length, 0);
2228+
});
2229+
2230+
});
2231+
2232+
describe("add the missing module file for inferred project", () => {
2233+
it("should remove the `module not found` error", () => {
2234+
const moduleFile = {
2235+
path: "/a/b/moduleFile.ts",
2236+
content: "export function bar() { };"
2237+
};
2238+
const file1 = {
2239+
path: "/a/b/file1.ts",
2240+
content: "import * as T from './moduleFile'; T.bar();"
2241+
};
2242+
const host = createServerHost([file1]);
2243+
const session = createSession(host);
2244+
openFilesForSession([file1], session);
2245+
const getErrRequest = makeSessionRequest<server.protocol.SemanticDiagnosticsSyncRequestArgs>(
2246+
server.CommandNames.SemanticDiagnosticsSync,
2247+
{ file: file1.path }
2248+
);
2249+
let diags = <server.protocol.Diagnostic[]>session.executeCommand(getErrRequest).response;
2250+
assert.equal(diags.length, 1);
2251+
2252+
host.reloadFS([file1, moduleFile]);
2253+
host.triggerDirectoryWatcherCallback(getDirectoryPath(file1.path), moduleFile.path);
2254+
host.runQueuedTimeoutCallbacks();
2255+
2256+
// Make a change to trigger the program rebuild
2257+
const changeRequest = makeSessionRequest<server.protocol.ChangeRequestArgs>(
2258+
server.CommandNames.Change,
2259+
{ file: file1.path, line: 1, offset: 44, endLine: 1, endOffset: 44, insertString: "\n" }
2260+
);
2261+
session.executeCommand(changeRequest);
2262+
2263+
// Recheck
2264+
diags = <server.protocol.Diagnostic[]>session.executeCommand(getErrRequest).response;
2265+
assert.equal(diags.length, 0);
2266+
});
2267+
});
2268+
2269+
describe("Configure file diagnostics events", () => {
2270+
2271+
it("are generated when the config file has errors", () => {
2272+
const serverEventManager = new TestServerEventManager();
2273+
const file = {
2274+
path: "/a/b/app.ts",
2275+
content: "let x = 10"
2276+
};
2277+
const configFile = {
2278+
path: "/a/b/tsconfig.json",
2279+
content: `{
2280+
"compilerOptions": {
2281+
"foo": "bar",
2282+
"allowJS": true
2283+
}
2284+
}`
2285+
};
2286+
2287+
const host = createServerHost([file, configFile]);
2288+
const session = createSession(host, /*typingsInstaller*/ undefined, serverEventManager.handler);
2289+
openFilesForSession([file], session);
2290+
serverEventManager.checkEventCountOfType("configFileDiag", 1);
2291+
});
2292+
2293+
it("are generated when the config file doesn't have errors", () => {
2294+
const serverEventManager = new TestServerEventManager();
2295+
const file = {
2296+
path: "/a/b/app.ts",
2297+
content: "let x = 10"
2298+
};
2299+
const configFile = {
2300+
path: "/a/b/tsconfig.json",
2301+
content: `{
2302+
"compilerOptions": {}
2303+
}`
2304+
};
2305+
2306+
const host = createServerHost([file, configFile]);
2307+
const session = createSession(host, /*typingsInstaller*/ undefined, serverEventManager.handler);
2308+
openFilesForSession([file], session);
2309+
serverEventManager.checkEventCountOfType("configFileDiag", 1);
2310+
});
2311+
});
21242312
}

src/server/editorServices.ts

Lines changed: 12 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -180,6 +180,8 @@ namespace ts.server {
180180

181181
private toCanonicalFileName: (f: string) => string;
182182

183+
public lastDeletedFile: ScriptInfo;
184+
183185
constructor(public readonly host: ServerHost,
184186
public readonly logger: Logger,
185187
public readonly cancellationToken: HostCancellationToken,
@@ -272,7 +274,7 @@ namespace ts.server {
272274
else {
273275
projectsToUpdate = [];
274276
for (const f of this.changedFiles) {
275-
projectsToUpdate = projectsToUpdate.concat(f.containingProjects);
277+
projectsToUpdate = projectsToUpdate.concat(f.containingProjects);
276278
}
277279
}
278280
this.updateProjectGraphs(projectsToUpdate);
@@ -342,6 +344,7 @@ namespace ts.server {
342344

343345
if (!info.isOpen) {
344346
this.filenameToScriptInfo.remove(info.path);
347+
this.lastDeletedFile = info;
345348

346349
// capture list of projects since detachAllProjects will wipe out original list
347350
const containingProjects = info.containingProjects.slice();
@@ -350,6 +353,7 @@ namespace ts.server {
350353

351354
// update projects to make sure that set of referenced files is correct
352355
this.updateProjectGraphs(containingProjects);
356+
this.lastDeletedFile = undefined;
353357

354358
if (!this.eventHandler) {
355359
return;
@@ -755,12 +759,14 @@ namespace ts.server {
755759
}
756760

757761
private reportConfigFileDiagnostics(configFileName: string, diagnostics: Diagnostic[], triggerFile?: string) {
758-
if (diagnostics && diagnostics.length > 0) {
759-
this.eventHandler({
760-
eventName: "configFileDiag",
761-
data: { configFileName, diagnostics, triggerFile }
762-
});
762+
if (!this.eventHandler) {
763+
return;
763764
}
765+
766+
this.eventHandler({
767+
eventName: "configFileDiag",
768+
data: { configFileName, diagnostics: diagnostics || [], triggerFile }
769+
});
764770
}
765771

766772
private createAndAddConfiguredProject(configFileName: NormalizedPath, projectOptions: ProjectOptions, configFileErrors: Diagnostic[], clientFileName?: string) {

src/server/lsHost.ts

Lines changed: 7 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -52,7 +52,7 @@ namespace ts.server {
5252
};
5353
}
5454

55-
private resolveNamesWithLocalCache<T extends { failedLookupLocations: string[] }, R>(
55+
private resolveNamesWithLocalCache<T extends { failedLookupLocations: string[] }, R extends { resolvedFileName?: string }>(
5656
names: string[],
5757
containingFile: string,
5858
cache: ts.FileMap<Map<T>>,
@@ -65,6 +65,7 @@ namespace ts.server {
6565
const newResolutions: Map<T> = createMap<T>();
6666
const resolvedModules: R[] = [];
6767
const compilerOptions = this.getCompilationSettings();
68+
const lastDeletedFileName = this.project.projectService.lastDeletedFile && this.project.projectService.lastDeletedFile.fileName;
6869

6970
for (const name of names) {
7071
// check if this is a duplicate entry in the list
@@ -94,8 +95,11 @@ namespace ts.server {
9495
return false;
9596
}
9697

97-
if (getResult(resolution)) {
98-
// TODO: consider checking failedLookupLocations
98+
const result = getResult(resolution);
99+
if (result) {
100+
if (result.resolvedFileName && result.resolvedFileName === lastDeletedFileName) {
101+
return false;
102+
}
99103
return true;
100104
}
101105

0 commit comments

Comments
 (0)