refactor(language-service): do not mutate the original template node span (#40484)

Rather than mutating the span on the template when renaming literal strings,
this commit updates the logic to mutate the `TextSpan` equivalent that
is used by the Language Service.

PR Close #40484
This commit is contained in:
Andrew Scott 2021-01-19 08:40:00 -08:00 committed by Jessica Janiuk
parent 3cf4e3c7c5
commit 5bbb5ea955
2 changed files with 18 additions and 10 deletions

View File

@ -87,7 +87,7 @@ export class ReferencesAndRenameBuilder {
canRename: true,
displayName: text,
fullDisplayName: text,
triggerSpan: toTextSpan(span),
triggerSpan: span,
};
}
@ -396,19 +396,19 @@ export class ReferencesAndRenameBuilder {
}
}
function getRenameTextAndSpanAtPosition(node: TmplAstNode|AST, position: number):
{text: string, span: ParseSourceSpan|AbsoluteSourceSpan}|null {
function getRenameTextAndSpanAtPosition(
node: TmplAstNode|AST, position: number): {text: string, span: ts.TextSpan}|null {
if (node instanceof TmplAstBoundAttribute || node instanceof TmplAstTextAttribute ||
node instanceof TmplAstBoundEvent) {
if (node.keySpan === undefined) {
return null;
}
return {text: node.name, span: node.keySpan};
return {text: node.name, span: toTextSpan(node.keySpan)};
} else if (node instanceof TmplAstVariable || node instanceof TmplAstReference) {
if (isWithin(position, node.keySpan)) {
return {text: node.keySpan.toString(), span: node.keySpan};
return {text: node.keySpan.toString(), span: toTextSpan(node.keySpan)};
} else if (node.valueSpan && isWithin(position, node.valueSpan)) {
return {text: node.valueSpan.toString(), span: node.valueSpan};
return {text: node.valueSpan.toString(), span: toTextSpan(node.valueSpan)};
}
}
@ -418,14 +418,14 @@ function getRenameTextAndSpanAtPosition(node: TmplAstNode|AST, position: number)
}
if (node instanceof PropertyRead || node instanceof MethodCall || node instanceof PropertyWrite ||
node instanceof SafePropertyRead || node instanceof SafeMethodCall) {
return {text: node.name, span: node.nameSpan};
return {text: node.name, span: toTextSpan(node.nameSpan)};
} else if (node instanceof LiteralPrimitive) {
const span = node.span;
const span = toTextSpan(node.sourceSpan);
const text = node.value;
if (typeof text === 'string') {
// The span of a string literal includes the quotes but they should be removed for renaming.
span.start += 1;
span.end -= 1;
span.length -= 2;
}
return {text, span};
}

View File

@ -1425,7 +1425,15 @@ describe('find references and rename locations', () => {
expect(result.canRename).toEqual(true);
expect(result.displayName).toEqual('myProp');
expect(result.kind).toEqual('property');
expect(result.triggerSpan.length).toEqual('myProp'.length);
expect(text.substring(
result.triggerSpan.start, result.triggerSpan.start + result.triggerSpan.length))
.toBe('myProp');
// re-queries also work
const {triggerSpan, displayName} =
env.ngLS.getRenameInfo(_('/my-comp.ts'), cursor) as ts.RenameInfoSuccess;
expect(displayName).toEqual('myProp');
expect(text.substring(triggerSpan.start, triggerSpan.start + triggerSpan.length))
.toBe('myProp');
});
it('gets rename info when cursor is on a directive input in a template', () => {