1namespace ts.projectSystem { 2 describe("unittests:: tsserver:: rename", () => { 3 it("works with fileToRename", () => { 4 const aTs: File = { path: "/a.ts", content: "export const a = 0;" }; 5 const bTs: File = { path: "/b.ts", content: 'import { a } from "./a";' }; 6 7 const session = createSession(createServerHost([aTs, bTs])); 8 openFilesForSession([bTs], session); 9 10 // rename fails with allowRenameOfImportPath disabled 11 const response1 = executeSessionRequest<protocol.RenameRequest, protocol.RenameResponse>(session, protocol.CommandTypes.Rename, protocolFileLocationFromSubstring(bTs, 'a";')); 12 assert.deepEqual<protocol.RenameResponseBody | undefined>(response1, { 13 info: { 14 canRename: false, 15 localizedErrorMessage: "You cannot rename this element." 16 }, 17 locs: [{ 18 file: bTs.path, 19 locs: [ 20 protocolRenameSpanFromSubstring({ 21 fileText: bTs.content, 22 text: "./a", 23 contextText: bTs.content 24 }) 25 ] 26 }], 27 }); 28 29 // rename succeeds with allowRenameOfImportPath enabled in host 30 session.getProjectService().setHostConfiguration({ preferences: { allowRenameOfImportPath: true } }); 31 const response2 = executeSessionRequest<protocol.RenameRequest, protocol.RenameResponse>(session, protocol.CommandTypes.Rename, protocolFileLocationFromSubstring(bTs, 'a";')); 32 assert.deepEqual<protocol.RenameResponseBody | undefined>(response2, { 33 info: { 34 canRename: true, 35 fileToRename: aTs.path, 36 displayName: aTs.path, 37 fullDisplayName: aTs.path, 38 kind: ScriptElementKind.moduleElement, 39 kindModifiers: "", 40 triggerSpan: protocolTextSpanFromSubstring(bTs.content, "a", { index: 1 }), 41 }, 42 locs: [{ 43 file: bTs.path, 44 locs: [ 45 protocolRenameSpanFromSubstring({ 46 fileText: bTs.content, 47 text: "./a", 48 contextText: bTs.content 49 }) 50 ] 51 }], 52 }); 53 54 // rename succeeds with allowRenameOfImportPath enabled in file 55 session.getProjectService().setHostConfiguration({ preferences: { allowRenameOfImportPath: false } }); 56 session.getProjectService().setHostConfiguration({ file: "/b.ts", formatOptions: {}, preferences: { allowRenameOfImportPath: true } }); 57 const response3 = executeSessionRequest<protocol.RenameRequest, protocol.RenameResponse>(session, protocol.CommandTypes.Rename, protocolFileLocationFromSubstring(bTs, 'a";')); 58 assert.deepEqual<protocol.RenameResponseBody | undefined>(response3, { 59 info: { 60 canRename: true, 61 fileToRename: aTs.path, 62 displayName: aTs.path, 63 fullDisplayName: aTs.path, 64 kind: ScriptElementKind.moduleElement, 65 kindModifiers: "", 66 triggerSpan: protocolTextSpanFromSubstring(bTs.content, "a", { index: 1 }), 67 }, 68 locs: [{ 69 file: bTs.path, 70 locs: [ 71 protocolRenameSpanFromSubstring({ 72 fileText: bTs.content, 73 text: "./a", 74 contextText: bTs.content 75 }) 76 ] 77 }], 78 }); 79 }); 80 81 it("works with prefixText and suffixText when enabled", () => { 82 const aTs: File = { path: "/a.ts", content: "const x = 0; const o = { x };" }; 83 const host = createServerHost([aTs]); 84 const session = createSession(host); 85 openFilesForSession([aTs], session); 86 87 // rename with prefixText and suffixText disabled 88 const response1 = executeSessionRequest<protocol.RenameRequest, protocol.RenameResponse>(session, protocol.CommandTypes.Rename, protocolFileLocationFromSubstring(aTs, "x")); 89 assert.deepEqual<protocol.RenameResponseBody | undefined>(response1, { 90 info: { 91 canRename: true, 92 fileToRename: undefined, 93 displayName: "x", 94 fullDisplayName: "x", 95 kind: ScriptElementKind.constElement, 96 kindModifiers: ScriptElementKindModifier.none, 97 triggerSpan: protocolTextSpanFromSubstring(aTs.content, "x"), 98 }, 99 locs: [ 100 { 101 file: aTs.path, 102 locs: [ 103 protocolRenameSpanFromSubstring({ 104 fileText: aTs.content, 105 text: "x", 106 contextText: "const x = 0;" 107 }), 108 protocolRenameSpanFromSubstring({ 109 fileText: aTs.content, 110 text: "x", 111 options: { index: 1 } 112 }), 113 ], 114 }, 115 ], 116 }); 117 118 // rename with prefixText and suffixText enabled in host 119 session.getProjectService().setHostConfiguration({ preferences: { providePrefixAndSuffixTextForRename: true } }); 120 const response2 = executeSessionRequest<protocol.RenameRequest, protocol.RenameResponse>(session, protocol.CommandTypes.Rename, protocolFileLocationFromSubstring(aTs, "x")); 121 assert.deepEqual<protocol.RenameResponseBody | undefined>(response2, { 122 info: { 123 canRename: true, 124 fileToRename: undefined, 125 displayName: "x", 126 fullDisplayName: "x", 127 kind: ScriptElementKind.constElement, 128 kindModifiers: ScriptElementKindModifier.none, 129 triggerSpan: protocolTextSpanFromSubstring(aTs.content, "x"), 130 }, 131 locs: [ 132 { 133 file: aTs.path, 134 locs: [ 135 protocolRenameSpanFromSubstring({ 136 fileText: aTs.content, 137 text: "x", 138 contextText: "const x = 0;" 139 }), 140 protocolRenameSpanFromSubstring({ 141 fileText: aTs.content, 142 text: "x", 143 options: { index: 1 }, 144 prefixSuffixText: { prefixText: "x: " } 145 }), 146 ], 147 }, 148 ], 149 }); 150 151 // rename with prefixText and suffixText enabled for file 152 session.getProjectService().setHostConfiguration({ preferences: { providePrefixAndSuffixTextForRename: false } }); 153 session.getProjectService().setHostConfiguration({ file: "/a.ts", formatOptions: {}, preferences: { providePrefixAndSuffixTextForRename: true } }); 154 const response3 = executeSessionRequest<protocol.RenameRequest, protocol.RenameResponse>(session, protocol.CommandTypes.Rename, protocolFileLocationFromSubstring(aTs, "x")); 155 assert.deepEqual<protocol.RenameResponseBody | undefined>(response3, { 156 info: { 157 canRename: true, 158 fileToRename: undefined, 159 displayName: "x", 160 fullDisplayName: "x", 161 kind: ScriptElementKind.constElement, 162 kindModifiers: ScriptElementKindModifier.none, 163 triggerSpan: protocolTextSpanFromSubstring(aTs.content, "x"), 164 }, 165 locs: [ 166 { 167 file: aTs.path, 168 locs: [ 169 protocolRenameSpanFromSubstring({ 170 fileText: aTs.content, 171 text: "x", 172 contextText: "const x = 0;" 173 }), 174 protocolRenameSpanFromSubstring({ 175 fileText: aTs.content, 176 text: "x", 177 options: { index: 1 }, 178 prefixSuffixText: { prefixText: "x: " } 179 }), 180 ], 181 }, 182 ], 183 }); 184 }); 185 186 it("rename behavior is based on file of rename initiation", () => { 187 const aTs: File = { path: "/a.ts", content: "const x = 1; export { x };" }; 188 const bTs: File = { path: "/b.ts", content: `import { x } from "./a"; const y = x + 1;` }; 189 const host = createServerHost([aTs, bTs]); 190 const session = createSession(host); 191 openFilesForSession([aTs, bTs], session); 192 193 // rename from file with prefixText and suffixText enabled 194 session.getProjectService().setHostConfiguration({ file: "/a.ts", formatOptions: {}, preferences: { providePrefixAndSuffixTextForRename: true } }); 195 const response1 = executeSessionRequest<protocol.RenameRequest, protocol.RenameResponse>(session, protocol.CommandTypes.Rename, protocolFileLocationFromSubstring(aTs, "x")); 196 assert.deepEqual<protocol.RenameResponseBody | undefined>(response1, { 197 info: { 198 canRename: true, 199 fileToRename: undefined, 200 displayName: "x", 201 fullDisplayName: "x", 202 kind: ScriptElementKind.constElement, 203 kindModifiers: ScriptElementKindModifier.none, 204 triggerSpan: protocolTextSpanFromSubstring(aTs.content, "x"), 205 }, 206 locs: [ 207 { 208 file: aTs.path, 209 locs: [ 210 protocolRenameSpanFromSubstring({ 211 fileText: aTs.content, 212 text: "x", 213 contextText: "const x = 1;" 214 }), 215 protocolRenameSpanFromSubstring({ 216 fileText: aTs.content, 217 text: "x", 218 options: { index: 2 }, 219 contextText: "export { x };", 220 prefixSuffixText: { suffixText: " as x" } 221 }), 222 ], 223 }, 224 ], 225 }); 226 227 // rename from file with prefixText and suffixText disabled 228 const response2 = executeSessionRequest<protocol.RenameRequest, protocol.RenameResponse>(session, protocol.CommandTypes.Rename, protocolFileLocationFromSubstring(bTs, "x")); 229 assert.deepEqual<protocol.RenameResponseBody | undefined>(response2, { 230 info: { 231 canRename: true, 232 fileToRename: undefined, 233 displayName: "x", 234 fullDisplayName: "x", 235 kind: ScriptElementKind.alias, 236 kindModifiers: ScriptElementKindModifier.none, 237 triggerSpan: protocolTextSpanFromSubstring(bTs.content, "x"), 238 }, 239 locs: [ 240 { 241 file: bTs.path, 242 locs: [ 243 protocolRenameSpanFromSubstring({ 244 fileText: bTs.content, 245 text: "x", 246 contextText: `import { x } from "./a";` 247 }), 248 protocolRenameSpanFromSubstring({ 249 fileText: bTs.content, 250 text: "x", 251 options: { index: 1 }, 252 }) 253 ] 254 }, 255 { 256 file: aTs.path, 257 locs: [ 258 protocolRenameSpanFromSubstring({ 259 fileText: aTs.content, 260 text: "x", 261 contextText: "const x = 1;" 262 }), 263 protocolRenameSpanFromSubstring({ 264 fileText: aTs.content, 265 text: "x", 266 options: { index: 2 }, 267 contextText: "export { x };", 268 }), 269 ], 270 }, 271 ], 272 }); 273 }); 274 }); 275} 276