fix(compiler): correct the `KeySpan` for animation events and properties (#40347)

We should provide the completion when the cursor is in the attribute
name after the `@` and `animate-`, but now the `KeySpan` starts from the
`@` or `animate-`. For example, the animation event `(@name.done)="v"`,
we can know where the cursor is by the `KeySpan` of `name.done` exactly,
it's in the event name or in the phase name.

PR Close #40347
This commit is contained in:
ivanwonder 2021-01-07 17:48:55 +08:00 committed by Andrew Kushnir
parent 61792cc6f5
commit 40e0bfdc0d
2 changed files with 49 additions and 0 deletions

View File

@ -244,6 +244,10 @@ export class BindingParser {
targetProps: ParsedProperty[], keySpan?: ParseSourceSpan) { targetProps: ParsedProperty[], keySpan?: ParseSourceSpan) {
if (isAnimationLabel(name)) { if (isAnimationLabel(name)) {
name = name.substring(1); name = name.substring(1);
if (keySpan !== undefined) {
keySpan = moveParseSourceSpan(
keySpan, new AbsoluteSourceSpan(keySpan.start.offset + 1, keySpan.end.offset));
}
if (value) { if (value) {
this._reportError( this._reportError(
`Assigning animation triggers via @prop="exp" attributes with an expression is invalid.` + `Assigning animation triggers via @prop="exp" attributes with an expression is invalid.` +
@ -274,9 +278,19 @@ export class BindingParser {
if (name.startsWith(ANIMATE_PROP_PREFIX)) { if (name.startsWith(ANIMATE_PROP_PREFIX)) {
isAnimationProp = true; isAnimationProp = true;
name = name.substring(ANIMATE_PROP_PREFIX.length); name = name.substring(ANIMATE_PROP_PREFIX.length);
if (keySpan !== undefined) {
keySpan = moveParseSourceSpan(
keySpan,
new AbsoluteSourceSpan(
keySpan.start.offset + ANIMATE_PROP_PREFIX.length, keySpan.end.offset));
}
} else if (isAnimationLabel(name)) { } else if (isAnimationLabel(name)) {
isAnimationProp = true; isAnimationProp = true;
name = name.substring(1); name = name.substring(1);
if (keySpan !== undefined) {
keySpan = moveParseSourceSpan(
keySpan, new AbsoluteSourceSpan(keySpan.start.offset + 1, keySpan.end.offset));
}
} }
if (isAnimationProp) { if (isAnimationProp) {
@ -424,6 +438,10 @@ export class BindingParser {
if (isAnimationLabel(name)) { if (isAnimationLabel(name)) {
name = name.substr(1); name = name.substr(1);
if (keySpan !== undefined) {
keySpan = moveParseSourceSpan(
keySpan, new AbsoluteSourceSpan(keySpan.start.offset + 1, keySpan.end.offset));
}
this._parseAnimationEvent(name, expression, sourceSpan, handlerSpan, targetEvents, keySpan); this._parseAnimationEvent(name, expression, sourceSpan, handlerSpan, targetEvents, keySpan);
} else { } else {
this._parseRegularEvent( this._parseRegularEvent(

View File

@ -193,6 +193,30 @@ describe('R3 AST source spans', () => {
['BoundAttribute', 'data-prop="{{v}}"', 'prop', '{{v}}'], ['BoundAttribute', 'data-prop="{{v}}"', 'prop', '{{v}}'],
]); ]);
}); });
it('is correct for bound properties via @', () => {
expectFromHtml('<div bind-@animation="v"></div>').toEqual([
['Element', '<div bind-@animation="v"></div>', '<div bind-@animation="v">', '</div>'],
['BoundAttribute', 'bind-@animation="v"', 'animation', 'v'],
]);
});
it('is correct for bound properties via animation-', () => {
expectFromHtml('<div bind-animate-animationName="v"></div>').toEqual([
[
'Element', '<div bind-animate-animationName="v"></div>',
'<div bind-animate-animationName="v">', '</div>'
],
['BoundAttribute', 'bind-animate-animationName="v"', 'animationName', 'v'],
]);
});
it('is correct for bound properties via @ without value', () => {
expectFromHtml('<div @animation></div>').toEqual([
['Element', '<div @animation></div>', '<div @animation>', '</div>'],
['BoundAttribute', '@animation', 'animation', '<empty>'],
]);
});
}); });
describe('templates', () => { describe('templates', () => {
@ -401,6 +425,13 @@ describe('R3 AST source spans', () => {
['BoundEvent', 'data-bindon-prop="v"', 'prop', 'v'], ['BoundEvent', 'data-bindon-prop="v"', 'prop', 'v'],
]); ]);
}); });
it('is correct for bound events via @', () => {
expectFromHtml('<div (@name.done)="v"></div>').toEqual([
['Element', '<div (@name.done)="v"></div>', '<div (@name.done)="v">', '</div>'],
['BoundEvent', '(@name.done)="v"', 'name.done', 'v'],
]);
});
}); });
describe('references', () => { describe('references', () => {