Skip to content

Commit

Permalink
(fix) deal with shorthands during rename (#1876)
Browse files Browse the repository at this point in the history
...of component A props inside component A
#1863
  • Loading branch information
dummdidumm authored Feb 16, 2023
1 parent 7449ec0 commit fb9414a
Show file tree
Hide file tree
Showing 3 changed files with 167 additions and 5 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -103,7 +103,8 @@ export class RenameProviderImpl implements RenameProvider {
position,
convertedRenameLocations,
docs,
lang
lang,
newName
);
const additionalRenamesForPropRenameOutsideComponentWithProp =
// This is an either-or-situation, don't do both
Expand Down Expand Up @@ -262,7 +263,8 @@ export class RenameProviderImpl implements RenameProvider {
position: Position,
convertedRenameLocations: TsRenameLocation[],
snapshots: SnapshotMap,
lang: ts.LanguageService
lang: ts.LanguageService,
newName: string
) {
// First find out if it's really the "rename prop inside component with that prop" case
// Use original document for that because only there the `export` is present.
Expand Down Expand Up @@ -292,16 +294,94 @@ export class RenameProviderImpl implements RenameProvider {
// It would not work for `return props: {bla}` because then typescript would do a rename of `{bla: renamed}`,
// so other locations would not be affected.
const replacementsForProp = (
lang.findRenameLocations(updatePropLocation.fileName, idxOfOldPropName, false, false) ||
[]
lang.findRenameLocations(
updatePropLocation.fileName,
idxOfOldPropName,
false,
false,
true
) || []
).filter(
(rename) =>
// filter out all renames inside the component except the prop rename,
// because the others were done before and then would show up twice, making a wrong rename.
rename.fileName !== updatePropLocation.fileName ||
this.isInSvelte2TsxPropLine(tsDoc, rename)
);
return await this.mapAndFilterRenameLocations(replacementsForProp, snapshots);

const renameLocations = await this.mapAndFilterRenameLocations(
replacementsForProp,
snapshots
);
const bind = 'bind:';

// Adjust shorthands
return renameLocations.map((location) => {
if (updatePropLocation.fileName === location.fileName) {
return location;
}

const sourceFile = lang.getProgram()?.getSourceFile(location.fileName);

if (
!sourceFile ||
location.fileName !== sourceFile.fileName ||
location.range.start.line < 0 ||
location.range.end.line < 0
) {
return location;
}

const snapshot = snapshots.get(location.fileName);
if (!(snapshot instanceof SvelteDocumentSnapshot)) {
return location;
}

const { parent } = snapshot;

let rangeStart = parent.offsetAt(location.range.start);
let suffixText = location.suffixText?.trimStart();

// suffix is of the form `: oldVarName` -> hints at a shorthand
if (!suffixText?.startsWith(':') || !getNodeIfIsInStartTag(parent.html, rangeStart)) {
return location;
}

const original = parent.getText({
start: Position.create(
location.range.start.line,
location.range.start.character - bind.length
),
end: location.range.end
});

if (original.startsWith(bind)) {
// bind:|foo| -> bind:|newName|={foo}
return {
...location,
prefixText: '',
suffixText: `={${original.slice(bind.length)}}`
};
}

if (snapshot.getOriginalText().charAt(rangeStart - 1) === '{') {
// {|foo|} -> |{foo|}
rangeStart--;
return {
...location,
range: {
start: parent.positionAt(rangeStart),
end: location.range.end
},
// |{foo|} -> newName=|{foo|}
newName: parent.getText(location.range),
prefixText: `${newName}={`,
suffixText: ''
};
}

return location;
});
}

/**
Expand Down
1 change: 1 addition & 0 deletions packages/language-server/src/plugins/typescript/service.ts
Original file line number Diff line number Diff line change
Expand Up @@ -59,6 +59,7 @@ const pendingReloads = new FileSet();
export function __resetCache() {
services.clear();
serviceSizeMap.clear();
configFileForOpenFiles.clear();
}

export interface LanguageServiceDocumentContext {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -272,6 +272,87 @@ describe('RenameProvider', () => {
});
});

it('should do rename of prop without type of component A in component A that is used with shorthands in component B', async () => {
const { provider, renameDoc3 } = await setup();
const result = await provider.rename(renameDoc3, Position.create(2, 20), 'newName');

console.log(JSON.stringify(result, null, 3));

assert.deepStrictEqual(result, {
changes: {
[getUri('rename3.svelte')]: [
{
newText: 'newName',
range: {
start: {
line: 2,
character: 15
},
end: {
line: 2,
character: 21
}
}
}
],
[getUri('rename-shorthand.svelte')]: [
{
newText: 'newName={props2}',
range: {
start: {
line: 6,
character: 12
},
end: {
line: 6,
character: 18
}
}
},
{
newText: 'newName={props2',
range: {
start: {
line: 7,
character: 7
},
end: {
line: 7,
character: 14
}
}
},
{
newText: 'newName',
range: {
start: {
line: 8,
character: 7
},
end: {
line: 8,
character: 13
}
}
},
{
newText: 'newName',
range: {
start: {
line: 9,
character: 7
},
end: {
line: 9,
character: 13
}
}
}
]
}
});
});

it('should do rename of svelte component', async () => {
const { provider, renameDoc4 } = await setup();
const result = await provider.rename(renameDoc4, Position.create(1, 12), 'ChildNew');
Expand Down

0 comments on commit fb9414a

Please sign in to comment.