Skip to content

Commit e3ccd7d

Browse files
authored
(fix) don't rename props name when triggered in shorthand (#1877)
1 parent fb9414a commit e3ccd7d

File tree

2 files changed

+80
-11
lines changed

2 files changed

+80
-11
lines changed

packages/language-server/src/plugins/typescript/features/RenameProvider.ts

Lines changed: 30 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,13 @@ import {
77
isInHTMLTagRange,
88
getNodeIfIsInHTMLStartTag
99
} from '../../../lib/documents';
10-
import { filterAsync, isNotNullOrUndefined, pathToUrl, unique } from '../../../utils';
10+
import {
11+
createGetCanonicalFileName,
12+
filterAsync,
13+
isNotNullOrUndefined,
14+
pathToUrl,
15+
unique
16+
} from '../../../utils';
1117
import { RenameProvider } from '../../interfaces';
1218
import { DocumentSnapshot, SvelteDocumentSnapshot } from '../DocumentSnapshot';
1319
import { convertRange } from '../utils';
@@ -18,7 +24,6 @@ import {
1824
isAfterSvelte2TsxPropsReturn,
1925
isTextSpanInGeneratedCode,
2026
SnapshotMap,
21-
findContainingNode,
2227
isStoreVariableIn$storeDeclaration,
2328
get$storeOffsetOf$storeDeclaration,
2429
getStoreOffsetOf$storeDeclaration,
@@ -113,7 +118,8 @@ export class RenameProviderImpl implements RenameProvider {
113118
: await this.getAdditionalLocationsForRenameOfPropInsideOtherComponent(
114119
convertedRenameLocations,
115120
docs,
116-
lang
121+
lang,
122+
tsDoc.filePath
117123
);
118124
convertedRenameLocations = [
119125
...convertedRenameLocations,
@@ -211,7 +217,7 @@ export class RenameProviderImpl implements RenameProvider {
211217
if (
212218
isStoreVariableIn$storeDeclaration(snapshot.getFullText(), loc.textSpan.start)
213219
) {
214-
// User renamed store, also rename correspondig $store locations
220+
// User renamed store, also rename corresponding $store locations
215221
const storeRenameLocations = lang.findRenameLocations(
216222
snapshot.filePath,
217223
get$storeOffsetOf$storeDeclaration(
@@ -268,8 +274,14 @@ export class RenameProviderImpl implements RenameProvider {
268274
) {
269275
// First find out if it's really the "rename prop inside component with that prop" case
270276
// Use original document for that because only there the `export` is present.
277+
// ':' for typescript's type operator (`export let bla: boolean`)
278+
// '//' and '/*' for comments (`export let bla// comment` or `export let bla/* comment */`)
271279
const regex = new RegExp(
272-
`export\\s+let\\s+${this.getVariableAtPosition(tsDoc, lang, position)}($|\\s|;|:)` // ':' for typescript's type operator (`export let bla: boolean`)
280+
`export\\s+let\\s+${this.getVariableAtPosition(
281+
tsDoc,
282+
lang,
283+
position
284+
)}($|\\s|;|:|\/\*|\/\/)`
273285
);
274286
const isRenameInsideComponentWithProp = regex.test(
275287
getLineAtPosition(position, document.getText())
@@ -395,7 +407,8 @@ export class RenameProviderImpl implements RenameProvider {
395407
private async getAdditionalLocationsForRenameOfPropInsideOtherComponent(
396408
convertedRenameLocations: TsRenameLocation[],
397409
snapshots: SnapshotMap,
398-
lang: ts.LanguageService
410+
lang: ts.LanguageService,
411+
requestedFileName: string
399412
) {
400413
// Check if it's a prop rename
401414
const updatePropLocation = this.findLocationWhichWantsToUpdatePropName(
@@ -405,6 +418,13 @@ export class RenameProviderImpl implements RenameProvider {
405418
if (!updatePropLocation) {
406419
return [];
407420
}
421+
const getCanonicalFileName = createGetCanonicalFileName(ts.sys.useCaseSensitiveFileNames);
422+
if (
423+
getCanonicalFileName(updatePropLocation.fileName) ===
424+
getCanonicalFileName(requestedFileName)
425+
) {
426+
return [];
427+
}
408428
// Find generated `export let`
409429
const doc = <SvelteDocumentSnapshot>snapshots.get(updatePropLocation.fileName);
410430
const match = this.matchGeneratedExportLet(doc, updatePropLocation);
@@ -430,12 +450,13 @@ export class RenameProviderImpl implements RenameProvider {
430450
) {
431451
const regex = new RegExp(
432452
// no 'export let', only 'let', because that's what it's translated to in svelte2tsx
453+
// '//' and '/*' for comments (`let bla/*Ωignore_startΩ*/`)
433454
`\\s+let\\s+(${snapshot
434455
.getFullText()
435456
.substring(
436457
updatePropLocation.textSpan.start,
437458
updatePropLocation.textSpan.start + updatePropLocation.textSpan.length
438-
)})($|\\s|;|:)`
459+
)})($|\\s|;|:|\/\*|\/\/)`
439460
);
440461
const match = snapshot.getFullText().match(regex);
441462
return match;
@@ -585,7 +606,7 @@ export class RenameProviderImpl implements RenameProvider {
585606
let rangeStart = parent.offsetAt(location.range.start);
586607
let prefixText = location.prefixText?.trimRight();
587608

588-
// rename needs to be prefixed in case of a bind shortand on a HTML element
609+
// rename needs to be prefixed in case of a bind shorthand on a HTML element
589610
if (!prefixText) {
590611
const original = parent.getText({
591612
start: Position.create(
@@ -634,7 +655,7 @@ export class RenameProviderImpl implements RenameProvider {
634655
suffixText: '}'
635656
};
636657

637-
// rename range needs to be adjusted in case of an attribute shortand
658+
// rename range needs to be adjusted in case of an attribute shorthand
638659
if (snapshot.getOriginalText().charAt(rangeStart - 1) === '{') {
639660
rangeStart--;
640661
const rangeEnd = parent.offsetAt(location.range.end) + 1;

packages/language-server/test/plugins/typescript/features/RenameProvider.test.ts

Lines changed: 50 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -353,6 +353,46 @@ describe('RenameProvider', () => {
353353
});
354354
});
355355

356+
it('should do rename of prop without type of component A in component B', async () => {
357+
const { provider, renameDoc2 } = await setup();
358+
const result = await provider.rename(renameDoc2, Position.create(6, 11), 'newName');
359+
360+
assert.deepStrictEqual(result, {
361+
changes: {
362+
[getUri('rename2.svelte')]: [
363+
{
364+
newText: 'newName',
365+
range: {
366+
start: {
367+
character: 9,
368+
line: 6
369+
},
370+
end: {
371+
character: 27,
372+
line: 6
373+
}
374+
}
375+
}
376+
],
377+
[getUri('rename3.svelte')]: [
378+
{
379+
newText: 'newName',
380+
range: {
381+
start: {
382+
character: 15,
383+
line: 1
384+
},
385+
end: {
386+
character: 33,
387+
line: 1
388+
}
389+
}
390+
}
391+
]
392+
}
393+
});
394+
});
395+
356396
it('should do rename of svelte component', async () => {
357397
const { provider, renameDoc4 } = await setup();
358398
const result = await provider.rename(renameDoc4, Position.create(1, 12), 'ChildNew');
@@ -701,9 +741,17 @@ describe('RenameProvider', () => {
701741
});
702742

703743
it('can rename shorthand props without breaking value-passing', async () => {
744+
await testShorthand(Position.create(3, 16));
745+
});
746+
747+
it('can rename shorthand props without breaking value-passing (triggers from shorthand)', async () => {
748+
await testShorthand(Position.create(7, 9));
749+
});
750+
751+
async function testShorthand(position: Position) {
704752
const { provider, renameDocShorthand } = await setup();
705753

706-
const result = await provider.rename(renameDocShorthand, Position.create(3, 16), 'newName');
754+
const result = await provider.rename(renameDocShorthand, position, 'newName');
707755

708756
assert.deepStrictEqual(result, {
709757
changes: {
@@ -776,7 +824,7 @@ describe('RenameProvider', () => {
776824
]
777825
}
778826
});
779-
});
827+
}
780828

781829
it('can rename slot let to an alias', async () => {
782830
const { provider, renameSlotLet } = await setup();

0 commit comments

Comments
 (0)