Skip to content

Commit 62cf44c

Browse files
Allow per-file setting for rename default behavior preferences (#29593)
<!-- Thank you for submitting a pull request! Here's a checklist you might find useful. * [ ] There is an associated issue that is labeled 'Bug' or 'help wanted' or is in the Community milestone * [ ] Code is up-to-date with the `master` branch * [ ] You've successfully run `jake runtests` locally * [ ] You've signed the CLA * [ ] There are new or updated unit tests validating the change Refer to CONTRIBUTING.MD for more details. https://github.com/Microsoft/TypeScript/blob/master/CONTRIBUTING.md --> Fixes #29585. #29314 and #29385 made it so their respective settings are only recognized when provided to the host as a whole. This PR makes it so that the relevant settings for the preferences on the file override those of the preferences on the host.
1 parent 96706a7 commit 62cf44c

File tree

4 files changed

+112
-6
lines changed

4 files changed

+112
-6
lines changed

src/server/editorServices.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -904,7 +904,7 @@ namespace ts.server {
904904

905905
getPreferences(file: NormalizedPath): protocol.UserPreferences {
906906
const info = this.getScriptInfoForNormalizedPath(file);
907-
return info && info.getPreferences() || this.hostConfiguration.preferences;
907+
return { ...this.hostConfiguration.preferences, ...info && info.getPreferences() };
908908
}
909909

910910
getHostFormatCodeOptions(): FormatCodeSettings {

src/server/session.ts

Lines changed: 3 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1178,8 +1178,7 @@ namespace ts.server {
11781178
private getRenameInfo(args: protocol.FileLocationRequestArgs): RenameInfo {
11791179
const { file, project } = this.getFileAndProject(args);
11801180
const position = this.getPositionInFile(args, file);
1181-
const preferences = this.getHostPreferences();
1182-
return project.getLanguageService().getRenameInfo(file, position, { allowRenameOfImportPath: preferences.allowRenameOfImportPath });
1181+
return project.getLanguageService().getRenameInfo(file, position, { allowRenameOfImportPath: this.getPreferences(file).allowRenameOfImportPath });
11831182
}
11841183

11851184
private getProjects(args: protocol.FileRequestArgs, getScriptInfoEnsuringProjectsUptoDate?: boolean, ignoreNoProjectError?: boolean): Projects {
@@ -1234,12 +1233,12 @@ namespace ts.server {
12341233
{ fileName: args.file, pos: position },
12351234
!!args.findInStrings,
12361235
!!args.findInComments,
1237-
this.getHostPreferences()
1236+
this.getPreferences(file)
12381237
);
12391238
if (!simplifiedResult) return locations;
12401239

12411240
const defaultProject = this.getDefaultProject(args);
1242-
const renameInfo: protocol.RenameInfo = this.mapRenameInfo(defaultProject.getLanguageService().getRenameInfo(file, position, { allowRenameOfImportPath: this.getHostPreferences().allowRenameOfImportPath }), Debug.assertDefined(this.projectService.getScriptInfo(file)));
1241+
const renameInfo: protocol.RenameInfo = this.mapRenameInfo(defaultProject.getLanguageService().getRenameInfo(file, position, { allowRenameOfImportPath: this.getPreferences(file).allowRenameOfImportPath }), Debug.assertDefined(this.projectService.getScriptInfo(file)));
12431242
return { info: renameInfo, locs: this.toSpanGroups(locations) };
12441243
}
12451244

src/services/findAllReferences.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -41,6 +41,7 @@ namespace ts.FindAllReferences {
4141
readonly implementations?: boolean;
4242
/**
4343
* True to opt in for enhanced renaming of shorthand properties and import/export specifiers.
44+
* The options controls the behavior for the whole rename operation; it cannot be changed on a per-file basis.
4445
* Default is false for backwards compatibility.
4546
*/
4647
readonly providePrefixAndSuffixTextForRename?: boolean;

src/testRunner/unittests/tsserver/rename.ts

Lines changed: 107 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@ namespace ts.projectSystem {
77
const session = createSession(createServerHost([aTs, bTs]));
88
openFilesForSession([bTs], session);
99

10+
// rename fails with allowRenameOfImportPath disabled
1011
const response1 = executeSessionRequest<protocol.RenameRequest, protocol.RenameResponse>(session, protocol.CommandTypes.Rename, protocolFileLocationFromSubstring(bTs, 'a";'));
1112
assert.deepEqual<protocol.RenameResponseBody | undefined>(response1, {
1213
info: {
@@ -16,6 +17,7 @@ namespace ts.projectSystem {
1617
locs: [{ file: bTs.path, locs: [protocolRenameSpanFromSubstring(bTs.content, "./a")] }],
1718
});
1819

20+
// rename succeeds with allowRenameOfImportPath enabled in host
1921
session.getProjectService().setHostConfiguration({ preferences: { allowRenameOfImportPath: true } });
2022
const response2 = executeSessionRequest<protocol.RenameRequest, protocol.RenameResponse>(session, protocol.CommandTypes.Rename, protocolFileLocationFromSubstring(bTs, 'a";'));
2123
assert.deepEqual<protocol.RenameResponseBody | undefined>(response2, {
@@ -30,6 +32,23 @@ namespace ts.projectSystem {
3032
},
3133
locs: [{ file: bTs.path, locs: [protocolRenameSpanFromSubstring(bTs.content, "./a")] }],
3234
});
35+
36+
// rename succeeds with allowRenameOfImportPath enabled in file
37+
session.getProjectService().setHostConfiguration({ preferences: { allowRenameOfImportPath: false } });
38+
session.getProjectService().setHostConfiguration({ file: "/b.ts", formatOptions: {}, preferences: { allowRenameOfImportPath: true } });
39+
const response3 = executeSessionRequest<protocol.RenameRequest, protocol.RenameResponse>(session, protocol.CommandTypes.Rename, protocolFileLocationFromSubstring(bTs, 'a";'));
40+
assert.deepEqual<protocol.RenameResponseBody | undefined>(response3, {
41+
info: {
42+
canRename: true,
43+
fileToRename: aTs.path,
44+
displayName: aTs.path,
45+
fullDisplayName: aTs.path,
46+
kind: ScriptElementKind.moduleElement,
47+
kindModifiers: "",
48+
triggerSpan: protocolTextSpanFromSubstring(bTs.content, "a", { index: 1 }),
49+
},
50+
locs: [{ file: bTs.path, locs: [protocolRenameSpanFromSubstring(bTs.content, "./a")] }],
51+
});
3352
});
3453

3554
it("works with prefixText and suffixText when enabled", () => {
@@ -61,7 +80,7 @@ namespace ts.projectSystem {
6180
],
6281
});
6382

64-
// rename with prefixText and suffixText enabled
83+
// rename with prefixText and suffixText enabled in host
6584
session.getProjectService().setHostConfiguration({ preferences: { providePrefixAndSuffixTextForRename: true } });
6685
const response2 = executeSessionRequest<protocol.RenameRequest, protocol.RenameResponse>(session, protocol.CommandTypes.Rename, protocolFileLocationFromSubstring(aTs, "x"));
6786
assert.deepEqual<protocol.RenameResponseBody | undefined>(response2, {
@@ -84,6 +103,93 @@ namespace ts.projectSystem {
84103
},
85104
],
86105
});
106+
107+
// rename with prefixText and suffixText enabled for file
108+
session.getProjectService().setHostConfiguration({ preferences: { providePrefixAndSuffixTextForRename: false } });
109+
session.getProjectService().setHostConfiguration({ file: "/a.ts", formatOptions: {}, preferences: { providePrefixAndSuffixTextForRename: true } });
110+
const response3 = executeSessionRequest<protocol.RenameRequest, protocol.RenameResponse>(session, protocol.CommandTypes.Rename, protocolFileLocationFromSubstring(aTs, "x"));
111+
assert.deepEqual<protocol.RenameResponseBody | undefined>(response3, {
112+
info: {
113+
canRename: true,
114+
fileToRename: undefined,
115+
displayName: "x",
116+
fullDisplayName: "x",
117+
kind: ScriptElementKind.constElement,
118+
kindModifiers: ScriptElementKindModifier.none,
119+
triggerSpan: protocolTextSpanFromSubstring(aTs.content, "x"),
120+
},
121+
locs: [
122+
{
123+
file: aTs.path,
124+
locs: [
125+
protocolRenameSpanFromSubstring(aTs.content, "x"),
126+
protocolRenameSpanFromSubstring(aTs.content, "x", { index: 1 }, { prefixText: "x: " }),
127+
],
128+
},
129+
],
130+
});
131+
});
132+
133+
it("rename behavior is based on file of rename initiation", () => {
134+
const aTs: File = { path: "/a.ts", content: "const x = 1; export { x };" };
135+
const bTs: File = { path: "/b.ts", content: `import { x } from "./a"; const y = x + 1;` };
136+
const host = createServerHost([aTs, bTs]);
137+
const session = createSession(host);
138+
openFilesForSession([aTs, bTs], session);
139+
140+
// rename from file with prefixText and suffixText enabled
141+
session.getProjectService().setHostConfiguration({ file: "/a.ts", formatOptions: {}, preferences: { providePrefixAndSuffixTextForRename: true } });
142+
const response1 = executeSessionRequest<protocol.RenameRequest, protocol.RenameResponse>(session, protocol.CommandTypes.Rename, protocolFileLocationFromSubstring(aTs, "x"));
143+
assert.deepEqual<protocol.RenameResponseBody | undefined>(response1, {
144+
info: {
145+
canRename: true,
146+
fileToRename: undefined,
147+
displayName: "x",
148+
fullDisplayName: "x",
149+
kind: ScriptElementKind.constElement,
150+
kindModifiers: ScriptElementKindModifier.none,
151+
triggerSpan: protocolTextSpanFromSubstring(aTs.content, "x"),
152+
},
153+
locs: [
154+
{
155+
file: aTs.path,
156+
locs: [
157+
protocolRenameSpanFromSubstring(aTs.content, "x"),
158+
protocolRenameSpanFromSubstring(aTs.content, "x", { index: 2 }, { suffixText: " as x" }),
159+
],
160+
},
161+
],
162+
});
163+
164+
// rename from file with prefixText and suffixText disabled
165+
const response2 = executeSessionRequest<protocol.RenameRequest, protocol.RenameResponse>(session, protocol.CommandTypes.Rename, protocolFileLocationFromSubstring(bTs, "x"));
166+
assert.deepEqual<protocol.RenameResponseBody | undefined>(response2, {
167+
info: {
168+
canRename: true,
169+
fileToRename: undefined,
170+
displayName: "x",
171+
fullDisplayName: "x",
172+
kind: ScriptElementKind.alias,
173+
kindModifiers: ScriptElementKindModifier.none,
174+
triggerSpan: protocolTextSpanFromSubstring(bTs.content, "x"),
175+
},
176+
locs: [
177+
{
178+
file: bTs.path,
179+
locs: [
180+
protocolRenameSpanFromSubstring(bTs.content, "x"),
181+
protocolRenameSpanFromSubstring(bTs.content, "x", { index: 1 })
182+
]
183+
},
184+
{
185+
file: aTs.path,
186+
locs: [
187+
protocolRenameSpanFromSubstring(aTs.content, "x"),
188+
protocolRenameSpanFromSubstring(aTs.content, "x", { index: 2 }),
189+
],
190+
},
191+
],
192+
});
87193
});
88194
});
89195
}

0 commit comments

Comments
 (0)