From 536d703d9ec3f208809a23b20b6058ebf38eae20 Mon Sep 17 00:00:00 2001 From: zhengbli Date: Wed, 12 Oct 2016 18:05:01 -0700 Subject: [PATCH 1/9] Set maxNodeModuleJsDepth for inferred projects --- .../unittests/tsserverProjectSystem.ts | 22 +++++++++++++++++++ src/server/project.ts | 7 ++++++ 2 files changed, 29 insertions(+) diff --git a/src/harness/unittests/tsserverProjectSystem.ts b/src/harness/unittests/tsserverProjectSystem.ts index 08e4bac7b2c..3e34b796955 100644 --- a/src/harness/unittests/tsserverProjectSystem.ts +++ b/src/harness/unittests/tsserverProjectSystem.ts @@ -2387,4 +2387,26 @@ namespace ts.projectSystem { assert.isTrue(errorResult.length === 0); }); }); + + describe("maxNodeModuleJsDepth for inferred projects", () => { + it("should be set by default", () => { + const file1: FileOrFolder = { + path: "/a/b/file1.js", + content: `var t = require("test"); t.` + }; + const moduleFile: FileOrFolder = { + path: "/a/b/node_modules/test/index.js", + content: `var v = 10; module.exports = v;` + }; + + const host = createServerHost([file1, moduleFile]); + const projectService = createProjectService(host); + projectService.openClientFile(file1.path); + + const project = projectService.inferredProjects[0]; + const sourceFile = project.getSourceFile(file1.path); + assert.isTrue("test" in sourceFile.resolvedModules); + assert.equal((sourceFile.resolvedModules["test"]).resolvedFileName, moduleFile.path); + }); + }); } \ No newline at end of file diff --git a/src/server/project.ts b/src/server/project.ts index a355d75f942..91e898bb568 100644 --- a/src/server/project.ts +++ b/src/server/project.ts @@ -126,6 +126,13 @@ namespace ts.server { this.compilerOptions.allowNonTsExtensions = true; } + if (this.projectKind === ProjectKind.Inferred) { + // Add default compiler options for inferred projects here + if (this.compilerOptions.maxNodeModuleJsDepth === undefined) { + this.compilerOptions.maxNodeModuleJsDepth = 2; + } + } + if (languageServiceEnabled) { this.enableLanguageService(); } From a8a1a826b3924c9d62841d01cd16c5b206abe3ee Mon Sep 17 00:00:00 2001 From: zhengbli Date: Wed, 28 Dec 2016 08:15:21 -0800 Subject: [PATCH 2/9] set the option when creating inferred projects --- src/server/editorServices.ts | 6 ++++++ src/server/project.ts | 7 ------- 2 files changed, 6 insertions(+), 7 deletions(-) diff --git a/src/server/editorServices.ts b/src/server/editorServices.ts index 00df53e1e35..23b172d1cfe 100644 --- a/src/server/editorServices.ts +++ b/src/server/editorServices.ts @@ -1079,6 +1079,12 @@ namespace ts.server { project, fileName => this.onConfigFileAddedForInferredProject(fileName)); + if (root.scriptKind === ScriptKind.JS || root.scriptKind === ScriptKind.JSX) { + const options = project.getCompilerOptions(); + options.maxNodeModuleJsDepth = 2; + project.setCompilerOptions(options); + } + project.updateGraph(); if (!useExistingProject) { diff --git a/src/server/project.ts b/src/server/project.ts index 2172b037d89..6085ee05159 100644 --- a/src/server/project.ts +++ b/src/server/project.ts @@ -169,13 +169,6 @@ namespace ts.server { this.compilerOptions.allowNonTsExtensions = true; } - if (this.projectKind === ProjectKind.Inferred) { - // Add default compiler options for inferred projects here - if (this.compilerOptions.maxNodeModuleJsDepth === undefined) { - this.compilerOptions.maxNodeModuleJsDepth = 2; - } - } - this.setInternalCompilerOptionsForEmittingJsFiles(); this.lsHost = new LSHost(this.projectService.host, this, this.projectService.cancellationToken); From bf5faa04a636dc9633c90a9ee4dadb1a85a78fc8 Mon Sep 17 00:00:00 2001 From: zhengbli Date: Wed, 28 Dec 2016 14:46:58 -0800 Subject: [PATCH 3/9] Use inherited setCompilerOptions for inferred project --- .../unittests/tsserverProjectSystem.ts | 8 ++++--- src/server/editorServices.ts | 10 ++++---- src/server/project.ts | 23 ++++++++++++++++--- 3 files changed, 29 insertions(+), 12 deletions(-) diff --git a/src/harness/unittests/tsserverProjectSystem.ts b/src/harness/unittests/tsserverProjectSystem.ts index e1ac647c2ac..dbf9bf670e6 100644 --- a/src/harness/unittests/tsserverProjectSystem.ts +++ b/src/harness/unittests/tsserverProjectSystem.ts @@ -3068,9 +3068,11 @@ namespace ts.projectSystem { projectService.openClientFile(file1.path); const project = projectService.inferredProjects[0]; - const sourceFile = project.getSourceFile(file1.path); - assert.isTrue("test" in sourceFile.resolvedModules); - assert.equal((sourceFile.resolvedModules["test"]).resolvedFileName, moduleFile.path); + const sourceFileForFile1 = project.getSourceFile(file1.path); + const sourceFileForModuleFile = project.getSourceFile(moduleFile.path); + + assert.isNotNull(sourceFileForFile1); + assert.isNotNull(sourceFileForModuleFile); }); }); diff --git a/src/server/editorServices.ts b/src/server/editorServices.ts index 23b172d1cfe..eba0dbb119c 100644 --- a/src/server/editorServices.ts +++ b/src/server/editorServices.ts @@ -1072,6 +1072,10 @@ namespace ts.server { ? this.inferredProjects[0] : new InferredProject(this, this.documentRegistry, this.compilerOptionsForInferredProjects); + if (root.scriptKind === ScriptKind.JS || root.scriptKind === ScriptKind.JSX) { + project.isJsInferredProject = true; + } + project.addRoot(root); this.directoryWatchers.startWatchingContainingDirectoriesForFile( @@ -1079,12 +1083,6 @@ namespace ts.server { project, fileName => this.onConfigFileAddedForInferredProject(fileName)); - if (root.scriptKind === ScriptKind.JS || root.scriptKind === ScriptKind.JSX) { - const options = project.getCompilerOptions(); - options.maxNodeModuleJsDepth = 2; - project.setCompilerOptions(options); - } - project.updateGraph(); if (!useExistingProject) { diff --git a/src/server/project.ts b/src/server/project.ts index 6085ee05159..ca3950a48a8 100644 --- a/src/server/project.ts +++ b/src/server/project.ts @@ -566,9 +566,6 @@ namespace ts.server { setCompilerOptions(compilerOptions: CompilerOptions) { if (compilerOptions) { - if (this.projectKind === ProjectKind.Inferred) { - compilerOptions.allowJs = true; - } compilerOptions.allowNonTsExtensions = true; if (changesAffectModuleResolution(this.compilerOptions, compilerOptions)) { // reset cached unresolved imports if changes in compiler options affected module resolution @@ -715,6 +712,26 @@ namespace ts.server { } })(); + private _isJsInferredProject = false; + set isJsInferredProject(newValue: boolean) { + if (newValue && !this._isJsInferredProject) { + this.setCompilerOptions(this.getCompilerOptions()); + } + this._isJsInferredProject = newValue; + } + + setCompilerOptions(newOptions: CompilerOptions) { + if (!newOptions) { + return; + } + + if (this._isJsInferredProject && typeof newOptions.maxNodeModuleJsDepth !== "number") { + newOptions.maxNodeModuleJsDepth = 2; + } + newOptions.allowJs = true; + super.setCompilerOptions(newOptions); + } + // Used to keep track of what directories are watched for this project directoriesWatchedForTsconfig: string[] = []; From 09fc3b3a181e6babb9ad4dee2fd5166385793839 Mon Sep 17 00:00:00 2001 From: zhengbli Date: Thu, 29 Dec 2016 10:26:34 -0800 Subject: [PATCH 4/9] address cr feedback --- src/harness/unittests/tsserverProjectSystem.ts | 13 ++++++++----- src/server/editorServices.ts | 2 +- src/server/project.ts | 12 ++++++------ 3 files changed, 15 insertions(+), 12 deletions(-) diff --git a/src/harness/unittests/tsserverProjectSystem.ts b/src/harness/unittests/tsserverProjectSystem.ts index dbf9bf670e6..a766a9c4230 100644 --- a/src/harness/unittests/tsserverProjectSystem.ts +++ b/src/harness/unittests/tsserverProjectSystem.ts @@ -3067,12 +3067,15 @@ namespace ts.projectSystem { const projectService = createProjectService(host); projectService.openClientFile(file1.path); - const project = projectService.inferredProjects[0]; - const sourceFileForFile1 = project.getSourceFile(file1.path); - const sourceFileForModuleFile = project.getSourceFile(moduleFile.path); + let project = projectService.inferredProjects[0]; + let options = project.getCompilerOptions(); + assert.isTrue(options.maxNodeModuleJsDepth === 2); - assert.isNotNull(sourceFileForFile1); - assert.isNotNull(sourceFileForModuleFile); + // Assert the option sticks + projectService.setCompilerOptionsForInferredProjects({ target: ScriptTarget.ES2016 }); + project = projectService.inferredProjects[0]; + options = project.getCompilerOptions(); + assert.isTrue(options.maxNodeModuleJsDepth === 2); }); }); diff --git a/src/server/editorServices.ts b/src/server/editorServices.ts index eba0dbb119c..2b87fdf1cc7 100644 --- a/src/server/editorServices.ts +++ b/src/server/editorServices.ts @@ -1073,7 +1073,7 @@ namespace ts.server { : new InferredProject(this, this.documentRegistry, this.compilerOptionsForInferredProjects); if (root.scriptKind === ScriptKind.JS || root.scriptKind === ScriptKind.JSX) { - project.isJsInferredProject = true; + project.setAsJsInferredProject(); } project.addRoot(root); diff --git a/src/server/project.ts b/src/server/project.ts index ca3950a48a8..5178820b3c4 100644 --- a/src/server/project.ts +++ b/src/server/project.ts @@ -713,14 +713,14 @@ namespace ts.server { })(); private _isJsInferredProject = false; - set isJsInferredProject(newValue: boolean) { - if (newValue && !this._isJsInferredProject) { - this.setCompilerOptions(this.getCompilerOptions()); - } - this._isJsInferredProject = newValue; + + setAsJsInferredProject() { + this._isJsInferredProject = true; + this.setCompilerOptions(); } - setCompilerOptions(newOptions: CompilerOptions) { + setCompilerOptions(newOptions?: CompilerOptions) { + newOptions = newOptions ? newOptions : this.getCompilerOptions(); if (!newOptions) { return; } From 8ac22ecbb04df7fc6bccec93a10fa38a4eea94da Mon Sep 17 00:00:00 2001 From: zhengbli Date: Thu, 29 Dec 2016 17:00:04 -0800 Subject: [PATCH 5/9] Change the design to track addRoot and removeRoot --- .../unittests/tsserverProjectSystem.ts | 31 ++++++++++++- src/server/editorServices.ts | 4 -- src/server/project.ts | 44 ++++++++++++++----- src/server/scriptInfo.ts | 4 ++ 4 files changed, 66 insertions(+), 17 deletions(-) diff --git a/src/harness/unittests/tsserverProjectSystem.ts b/src/harness/unittests/tsserverProjectSystem.ts index a766a9c4230..1844b0743ca 100644 --- a/src/harness/unittests/tsserverProjectSystem.ts +++ b/src/harness/unittests/tsserverProjectSystem.ts @@ -1620,7 +1620,7 @@ namespace ts.projectSystem { const configureHostRequest = makeSessionRequest(CommandNames.Configure, { extraFileExtensions }); session.executeCommand(configureHostRequest).response; - // HTML file still not included in the project as it is closed + // HTML file still not included in the project as it is closed checkNumberOfProjects(projectService, { configuredProjects: 1 }); checkProjectActualFiles(projectService.configuredProjects[0], [file1.path]); @@ -3053,7 +3053,7 @@ namespace ts.projectSystem { }); describe("maxNodeModuleJsDepth for inferred projects", () => { - it("should be set by default", () => { + it("should be set to 2 if the project has js root files", () => { const file1: FileOrFolder = { path: "/a/b/file1.js", content: `var t = require("test"); t.` @@ -3077,6 +3077,33 @@ namespace ts.projectSystem { options = project.getCompilerOptions(); assert.isTrue(options.maxNodeModuleJsDepth === 2); }); + + it("should return to normal state when all js root files are removed from project", () => { + const file1 = { + path: "/a/file1.ts", + content: "let x =1;" + }; + const file2 = { + path: "/a/file2.js", + content: "let x =1;" + }; + + const host = createServerHost([file1, file2, libFile]); + const projectService = createProjectService(host, { useSingleInferredProject: true }); + + projectService.openClientFile(file1.path); + checkNumberOfInferredProjects(projectService, 1); + let project = projectService.inferredProjects[0]; + assert.isUndefined(project.getCompilerOptions().maxNodeModuleJsDepth); + + projectService.openClientFile(file2.path); + project = projectService.inferredProjects[0]; + assert.isTrue(project.getCompilerOptions().maxNodeModuleJsDepth === 2); + + projectService.closeClientFile(file2.path); + project = projectService.inferredProjects[0]; + assert.isUndefined(project.getCompilerOptions().maxNodeModuleJsDepth); + }); }); } \ No newline at end of file diff --git a/src/server/editorServices.ts b/src/server/editorServices.ts index 2b87fdf1cc7..00df53e1e35 100644 --- a/src/server/editorServices.ts +++ b/src/server/editorServices.ts @@ -1072,10 +1072,6 @@ namespace ts.server { ? this.inferredProjects[0] : new InferredProject(this, this.documentRegistry, this.compilerOptionsForInferredProjects); - if (root.scriptKind === ScriptKind.JS || root.scriptKind === ScriptKind.JSX) { - project.setAsJsInferredProject(); - } - project.addRoot(root); this.directoryWatchers.startWatchingContainingDirectoriesForFile( diff --git a/src/server/project.ts b/src/server/project.ts index 5178820b3c4..89312610a54 100644 --- a/src/server/project.ts +++ b/src/server/project.ts @@ -395,7 +395,9 @@ namespace ts.server { } removeFile(info: ScriptInfo, detachFromProject = true) { - this.removeRootFileIfNecessary(info); + if (this.isRoot(info)) { + this.removeRoot(info); + } this.lsHost.notifyFileRemoved(info); this.cachedUnresolvedImportsPerFile.remove(info.path); @@ -693,11 +695,9 @@ namespace ts.server { } // remove a root file from project - private removeRootFileIfNecessary(info: ScriptInfo): void { - if (this.isRoot(info)) { - remove(this.rootFiles, info); - this.rootFilesMap.remove(info.path); - } + protected removeRoot(info: ScriptInfo): void { + remove(this.rootFiles, info); + this.rootFilesMap.remove(info.path); } } @@ -714,13 +714,16 @@ namespace ts.server { private _isJsInferredProject = false; - setAsJsInferredProject() { - this._isJsInferredProject = true; - this.setCompilerOptions(); + toggleJsInferredProject(isJsInferredProject: boolean) { + if (isJsInferredProject !== this._isJsInferredProject) { + this._isJsInferredProject = isJsInferredProject; + this.setCompilerOptions(); + } } - setCompilerOptions(newOptions?: CompilerOptions) { - newOptions = newOptions ? newOptions : this.getCompilerOptions(); + setCompilerOptions(options?: CompilerOptions) { + // Avoid manipulating the given options directly + const newOptions = options ? clone(options) : this.getCompilerOptions(); if (!newOptions) { return; } @@ -728,6 +731,9 @@ namespace ts.server { if (this._isJsInferredProject && typeof newOptions.maxNodeModuleJsDepth !== "number") { newOptions.maxNodeModuleJsDepth = 2; } + else if (!this._isJsInferredProject) { + newOptions.maxNodeModuleJsDepth = undefined; + } newOptions.allowJs = true; super.setCompilerOptions(newOptions); } @@ -746,6 +752,22 @@ namespace ts.server { /*compileOnSaveEnabled*/ false); } + addRoot(info: ScriptInfo) { + if (!this._isJsInferredProject && info.isJavaScript()) { + this.toggleJsInferredProject(/*isJsInferredProject*/ true); + } + super.addRoot(info); + } + + removeRoot(info: ScriptInfo) { + if (this._isJsInferredProject && info.isJavaScript()) { + if (filter(this.getRootScriptInfos(), info => info.isJavaScript()).length === 0) { + this.toggleJsInferredProject(/*isJsInferredProject*/ false); + } + } + super.removeRoot(info); + } + getProjectRootPath() { // Single inferred project does not have a project root. if (this.projectService.useSingleInferredProject) { diff --git a/src/server/scriptInfo.ts b/src/server/scriptInfo.ts index 0acd45d0287..a93600de1a8 100644 --- a/src/server/scriptInfo.ts +++ b/src/server/scriptInfo.ts @@ -355,5 +355,9 @@ namespace ts.server { positionToLineOffset(position: number): ILineInfo { return this.textStorage.positionToLineOffset(position); } + + public isJavaScript() { + return this.scriptKind === ScriptKind.JS || this.scriptKind === ScriptKind.JSX; + } } } \ No newline at end of file From c9e301f236f7fad0f6dfb51f7e622f8b189d7207 Mon Sep 17 00:00:00 2001 From: Nathan Shively-Sanders Date: Tue, 10 Jan 2017 08:55:15 -0800 Subject: [PATCH 6/9] Test:object rest skips only class methods Previously, it skipped all methods. --- tests/baselines/reference/objectRest.js | 9 ++ tests/baselines/reference/objectRest.symbols | 82 ++++++++++++------- tests/baselines/reference/objectRest.types | 22 +++++ .../conformance/types/rest/objectRest.ts | 7 ++ 4 files changed, 90 insertions(+), 30 deletions(-) diff --git a/tests/baselines/reference/objectRest.js b/tests/baselines/reference/objectRest.js index 48a1bf8daf8..59eb11542c0 100644 --- a/tests/baselines/reference/objectRest.js +++ b/tests/baselines/reference/objectRest.js @@ -29,8 +29,15 @@ class Removable { removed: string; remainder: string; } +interface I { + m(): void; + removed: string; + remainder: string; +} var removable = new Removable(); var { removed, ...removableRest } = removable; +var i: I = removable; +var { removed, ...removableRest2 } = i; let computed = 'b'; let computed2 = 'a'; @@ -74,6 +81,8 @@ class Removable { } var removable = new Removable(); var { removed } = removable, removableRest = __rest(removable, ["removed"]); +var i = removable; +var { removed } = i, removableRest2 = __rest(i, ["removed"]); let computed = 'b'; let computed2 = 'a'; var _g = computed, stillNotGreat = o[_g], _h = computed2, soSo = o[_h], o = __rest(o, [typeof _g === "symbol" ? _g : _g + "", typeof _h === "symbol" ? _h : _h + ""]); diff --git a/tests/baselines/reference/objectRest.symbols b/tests/baselines/reference/objectRest.symbols index 46309392135..2992220d8b2 100644 --- a/tests/baselines/reference/objectRest.symbols +++ b/tests/baselines/reference/objectRest.symbols @@ -1,42 +1,42 @@ === tests/cases/conformance/types/rest/objectRest.ts === var o = { a: 1, b: 'no' } ->o : Symbol(o, Decl(objectRest.ts, 0, 3), Decl(objectRest.ts, 35, 51)) +>o : Symbol(o, Decl(objectRest.ts, 0, 3), Decl(objectRest.ts, 42, 51)) >a : Symbol(a, Decl(objectRest.ts, 0, 9)) >b : Symbol(b, Decl(objectRest.ts, 0, 15)) var { ...clone } = o; >clone : Symbol(clone, Decl(objectRest.ts, 1, 5)) ->o : Symbol(o, Decl(objectRest.ts, 0, 3), Decl(objectRest.ts, 35, 51)) +>o : Symbol(o, Decl(objectRest.ts, 0, 3), Decl(objectRest.ts, 42, 51)) var { a, ...justB } = o; >a : Symbol(a, Decl(objectRest.ts, 2, 5), Decl(objectRest.ts, 3, 5)) >justB : Symbol(justB, Decl(objectRest.ts, 2, 8)) ->o : Symbol(o, Decl(objectRest.ts, 0, 3), Decl(objectRest.ts, 35, 51)) +>o : Symbol(o, Decl(objectRest.ts, 0, 3), Decl(objectRest.ts, 42, 51)) var { a, b: renamed, ...empty } = o; >a : Symbol(a, Decl(objectRest.ts, 2, 5), Decl(objectRest.ts, 3, 5)) >b : Symbol(b, Decl(objectRest.ts, 0, 15)) >renamed : Symbol(renamed, Decl(objectRest.ts, 3, 8), Decl(objectRest.ts, 4, 5), Decl(objectRest.ts, 5, 5), Decl(objectRest.ts, 9, 5)) >empty : Symbol(empty, Decl(objectRest.ts, 3, 20)) ->o : Symbol(o, Decl(objectRest.ts, 0, 3), Decl(objectRest.ts, 35, 51)) +>o : Symbol(o, Decl(objectRest.ts, 0, 3), Decl(objectRest.ts, 42, 51)) var { ['b']: renamed, ...justA } = o; >'b' : Symbol(renamed, Decl(objectRest.ts, 3, 8), Decl(objectRest.ts, 4, 5), Decl(objectRest.ts, 5, 5), Decl(objectRest.ts, 9, 5)) >renamed : Symbol(renamed, Decl(objectRest.ts, 3, 8), Decl(objectRest.ts, 4, 5), Decl(objectRest.ts, 5, 5), Decl(objectRest.ts, 9, 5)) >justA : Symbol(justA, Decl(objectRest.ts, 4, 21), Decl(objectRest.ts, 5, 19), Decl(objectRest.ts, 6, 31)) ->o : Symbol(o, Decl(objectRest.ts, 0, 3), Decl(objectRest.ts, 35, 51)) +>o : Symbol(o, Decl(objectRest.ts, 0, 3), Decl(objectRest.ts, 42, 51)) var { 'b': renamed, ...justA } = o; >renamed : Symbol(renamed, Decl(objectRest.ts, 3, 8), Decl(objectRest.ts, 4, 5), Decl(objectRest.ts, 5, 5), Decl(objectRest.ts, 9, 5)) >justA : Symbol(justA, Decl(objectRest.ts, 4, 21), Decl(objectRest.ts, 5, 19), Decl(objectRest.ts, 6, 31)) ->o : Symbol(o, Decl(objectRest.ts, 0, 3), Decl(objectRest.ts, 35, 51)) +>o : Symbol(o, Decl(objectRest.ts, 0, 3), Decl(objectRest.ts, 42, 51)) var { b: { '0': n, '1': oooo }, ...justA } = o; >b : Symbol(b, Decl(objectRest.ts, 0, 15)) >n : Symbol(n, Decl(objectRest.ts, 6, 10)) >oooo : Symbol(oooo, Decl(objectRest.ts, 6, 18)) >justA : Symbol(justA, Decl(objectRest.ts, 4, 21), Decl(objectRest.ts, 5, 19), Decl(objectRest.ts, 6, 31)) ->o : Symbol(o, Decl(objectRest.ts, 0, 3), Decl(objectRest.ts, 35, 51)) +>o : Symbol(o, Decl(objectRest.ts, 0, 3), Decl(objectRest.ts, 42, 51)) let o2 = { c: 'terrible idea?', d: 'yes' }; >o2 : Symbol(o2, Decl(objectRest.ts, 8, 3)) @@ -138,41 +138,63 @@ class Removable { remainder: string; >remainder : Symbol(Removable.remainder, Decl(objectRest.ts, 27, 20)) } +interface I { +>I : Symbol(I, Decl(objectRest.ts, 29, 1)) + + m(): void; +>m : Symbol(I.m, Decl(objectRest.ts, 30, 13)) + + removed: string; +>removed : Symbol(I.removed, Decl(objectRest.ts, 31, 14)) + + remainder: string; +>remainder : Symbol(I.remainder, Decl(objectRest.ts, 32, 20)) +} var removable = new Removable(); ->removable : Symbol(removable, Decl(objectRest.ts, 30, 3)) +>removable : Symbol(removable, Decl(objectRest.ts, 35, 3)) >Removable : Symbol(Removable, Decl(objectRest.ts, 18, 35)) var { removed, ...removableRest } = removable; ->removed : Symbol(removed, Decl(objectRest.ts, 31, 5)) ->removableRest : Symbol(removableRest, Decl(objectRest.ts, 31, 14)) ->removable : Symbol(removable, Decl(objectRest.ts, 30, 3)) +>removed : Symbol(removed, Decl(objectRest.ts, 36, 5), Decl(objectRest.ts, 38, 5)) +>removableRest : Symbol(removableRest, Decl(objectRest.ts, 36, 14)) +>removable : Symbol(removable, Decl(objectRest.ts, 35, 3)) + +var i: I = removable; +>i : Symbol(i, Decl(objectRest.ts, 37, 3)) +>I : Symbol(I, Decl(objectRest.ts, 29, 1)) +>removable : Symbol(removable, Decl(objectRest.ts, 35, 3)) + +var { removed, ...removableRest2 } = i; +>removed : Symbol(removed, Decl(objectRest.ts, 36, 5), Decl(objectRest.ts, 38, 5)) +>removableRest2 : Symbol(removableRest2, Decl(objectRest.ts, 38, 14)) +>i : Symbol(i, Decl(objectRest.ts, 37, 3)) let computed = 'b'; ->computed : Symbol(computed, Decl(objectRest.ts, 33, 3)) +>computed : Symbol(computed, Decl(objectRest.ts, 40, 3)) let computed2 = 'a'; ->computed2 : Symbol(computed2, Decl(objectRest.ts, 34, 3)) +>computed2 : Symbol(computed2, Decl(objectRest.ts, 41, 3)) var { [computed]: stillNotGreat, [computed2]: soSo, ...o } = o; ->computed : Symbol(computed, Decl(objectRest.ts, 33, 3)) ->stillNotGreat : Symbol(stillNotGreat, Decl(objectRest.ts, 35, 5)) ->computed2 : Symbol(computed2, Decl(objectRest.ts, 34, 3)) ->soSo : Symbol(soSo, Decl(objectRest.ts, 35, 32)) ->o : Symbol(o, Decl(objectRest.ts, 0, 3), Decl(objectRest.ts, 35, 51)) ->o : Symbol(o, Decl(objectRest.ts, 0, 3), Decl(objectRest.ts, 35, 51)) +>computed : Symbol(computed, Decl(objectRest.ts, 40, 3)) +>stillNotGreat : Symbol(stillNotGreat, Decl(objectRest.ts, 42, 5)) +>computed2 : Symbol(computed2, Decl(objectRest.ts, 41, 3)) +>soSo : Symbol(soSo, Decl(objectRest.ts, 42, 32)) +>o : Symbol(o, Decl(objectRest.ts, 0, 3), Decl(objectRest.ts, 42, 51)) +>o : Symbol(o, Decl(objectRest.ts, 0, 3), Decl(objectRest.ts, 42, 51)) ({ [computed]: stillNotGreat, [computed2]: soSo, ...o } = o); ->computed : Symbol(computed, Decl(objectRest.ts, 33, 3)) ->stillNotGreat : Symbol(stillNotGreat, Decl(objectRest.ts, 35, 5)) ->computed2 : Symbol(computed2, Decl(objectRest.ts, 34, 3)) ->soSo : Symbol(soSo, Decl(objectRest.ts, 35, 32)) ->o : Symbol(o, Decl(objectRest.ts, 0, 3), Decl(objectRest.ts, 35, 51)) ->o : Symbol(o, Decl(objectRest.ts, 0, 3), Decl(objectRest.ts, 35, 51)) +>computed : Symbol(computed, Decl(objectRest.ts, 40, 3)) +>stillNotGreat : Symbol(stillNotGreat, Decl(objectRest.ts, 42, 5)) +>computed2 : Symbol(computed2, Decl(objectRest.ts, 41, 3)) +>soSo : Symbol(soSo, Decl(objectRest.ts, 42, 32)) +>o : Symbol(o, Decl(objectRest.ts, 0, 3), Decl(objectRest.ts, 42, 51)) +>o : Symbol(o, Decl(objectRest.ts, 0, 3), Decl(objectRest.ts, 42, 51)) var noContextualType = ({ aNumber = 12, ...notEmptyObject }) => aNumber + notEmptyObject['anythingGoes']; ->noContextualType : Symbol(noContextualType, Decl(objectRest.ts, 38, 3)) ->aNumber : Symbol(aNumber, Decl(objectRest.ts, 38, 25)) ->notEmptyObject : Symbol(notEmptyObject, Decl(objectRest.ts, 38, 39)) ->aNumber : Symbol(aNumber, Decl(objectRest.ts, 38, 25)) ->notEmptyObject : Symbol(notEmptyObject, Decl(objectRest.ts, 38, 39)) +>noContextualType : Symbol(noContextualType, Decl(objectRest.ts, 45, 3)) +>aNumber : Symbol(aNumber, Decl(objectRest.ts, 45, 25)) +>notEmptyObject : Symbol(notEmptyObject, Decl(objectRest.ts, 45, 39)) +>aNumber : Symbol(aNumber, Decl(objectRest.ts, 45, 25)) +>notEmptyObject : Symbol(notEmptyObject, Decl(objectRest.ts, 45, 39)) diff --git a/tests/baselines/reference/objectRest.types b/tests/baselines/reference/objectRest.types index 1dc05741713..5347f09f5a3 100644 --- a/tests/baselines/reference/objectRest.types +++ b/tests/baselines/reference/objectRest.types @@ -158,6 +158,18 @@ class Removable { remainder: string; >remainder : string } +interface I { +>I : I + + m(): void; +>m : () => void + + removed: string; +>removed : string + + remainder: string; +>remainder : string +} var removable = new Removable(); >removable : Removable >new Removable() : Removable @@ -168,6 +180,16 @@ var { removed, ...removableRest } = removable; >removableRest : { both: number; remainder: string; } >removable : Removable +var i: I = removable; +>i : I +>I : I +>removable : Removable + +var { removed, ...removableRest2 } = i; +>removed : string +>removableRest2 : { m(): void; remainder: string; } +>i : I + let computed = 'b'; >computed : string >'b' : "b" diff --git a/tests/cases/conformance/types/rest/objectRest.ts b/tests/cases/conformance/types/rest/objectRest.ts index 2fba5d0b6dc..77f0fca1ed7 100644 --- a/tests/cases/conformance/types/rest/objectRest.ts +++ b/tests/cases/conformance/types/rest/objectRest.ts @@ -29,8 +29,15 @@ class Removable { removed: string; remainder: string; } +interface I { + m(): void; + removed: string; + remainder: string; +} var removable = new Removable(); var { removed, ...removableRest } = removable; +var i: I = removable; +var { removed, ...removableRest2 } = i; let computed = 'b'; let computed2 = 'a'; From 945e65f4d8d79dc7bd25a9e818a1999a48664ad7 Mon Sep 17 00:00:00 2001 From: Nathan Shively-Sanders Date: Tue, 10 Jan 2017 08:55:46 -0800 Subject: [PATCH 7/9] Object rest skips only class methods Previously, it skipped all methods --- src/compiler/checker.ts | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/src/compiler/checker.ts b/src/compiler/checker.ts index 54f0758b3a9..f828fb02c0c 100644 --- a/src/compiler/checker.ts +++ b/src/compiler/checker.ts @@ -3125,9 +3125,8 @@ namespace ts { for (const prop of getPropertiesOfType(source)) { const inNamesToRemove = prop.name in names; const isPrivate = getDeclarationModifierFlagsFromSymbol(prop) & (ModifierFlags.Private | ModifierFlags.Protected); - const isMethod = prop.flags & SymbolFlags.Method; const isSetOnlyAccessor = prop.flags & SymbolFlags.SetAccessor && !(prop.flags & SymbolFlags.GetAccessor); - if (!inNamesToRemove && !isPrivate && !isMethod && !isSetOnlyAccessor) { + if (!inNamesToRemove && !isPrivate && !isClassMethod(prop) && !isSetOnlyAccessor) { members[prop.name] = prop; } } From 54f12307601c2dfb364575210c131da7f7a71ba6 Mon Sep 17 00:00:00 2001 From: Zhengbo Li Date: Tue, 10 Jan 2017 16:58:43 -0800 Subject: [PATCH 8/9] Change the remove unused local code fix message --- src/compiler/diagnosticMessages.json | 2 +- src/services/codefixes/unusedIdentifierFixes.ts | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/src/compiler/diagnosticMessages.json b/src/compiler/diagnosticMessages.json index 6bdf9932fca..bce99cbaf39 100644 --- a/src/compiler/diagnosticMessages.json +++ b/src/compiler/diagnosticMessages.json @@ -3247,7 +3247,7 @@ "category": "Message", "code": 90003 }, - "Remove unused identifiers.": { + "Remove the unused identifier: {0}": { "category": "Message", "code": 90004 }, diff --git a/src/services/codefixes/unusedIdentifierFixes.ts b/src/services/codefixes/unusedIdentifierFixes.ts index 8e14bdcb73e..5c42fc8e6e9 100644 --- a/src/services/codefixes/unusedIdentifierFixes.ts +++ b/src/services/codefixes/unusedIdentifierFixes.ts @@ -146,7 +146,7 @@ namespace ts.codefix { function createCodeFix(newText: string, start: number, length: number): CodeAction[] { return [{ - description: getLocaleSpecificMessage(Diagnostics.Remove_unused_identifiers), + description: formatStringFromArgs(getLocaleSpecificMessage(Diagnostics.Remove_the_unused_identifier_Colon_0), { 0: token.getText() }), changes: [{ fileName: sourceFile.fileName, textChanges: [{ newText, span: { start, length } }] From 0c7e4bbb455b99725d49fe3e89a353656048e9b6 Mon Sep 17 00:00:00 2001 From: Zhengbo Li Date: Tue, 10 Jan 2017 17:55:52 -0800 Subject: [PATCH 9/9] Update the message --- src/compiler/diagnosticMessages.json | 2 +- src/services/codefixes/unusedIdentifierFixes.ts | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/src/compiler/diagnosticMessages.json b/src/compiler/diagnosticMessages.json index bce99cbaf39..52fc401d1f1 100644 --- a/src/compiler/diagnosticMessages.json +++ b/src/compiler/diagnosticMessages.json @@ -3247,7 +3247,7 @@ "category": "Message", "code": 90003 }, - "Remove the unused identifier: {0}": { + "Remove declaration for: {0}": { "category": "Message", "code": 90004 }, diff --git a/src/services/codefixes/unusedIdentifierFixes.ts b/src/services/codefixes/unusedIdentifierFixes.ts index 5c42fc8e6e9..2784a09a504 100644 --- a/src/services/codefixes/unusedIdentifierFixes.ts +++ b/src/services/codefixes/unusedIdentifierFixes.ts @@ -146,7 +146,7 @@ namespace ts.codefix { function createCodeFix(newText: string, start: number, length: number): CodeAction[] { return [{ - description: formatStringFromArgs(getLocaleSpecificMessage(Diagnostics.Remove_the_unused_identifier_Colon_0), { 0: token.getText() }), + description: formatStringFromArgs(getLocaleSpecificMessage(Diagnostics.Remove_declaration_for_Colon_0), { 0: token.getText() }), changes: [{ fileName: sourceFile.fileName, textChanges: [{ newText, span: { start, length } }]