feat(language-service): provide completion for $event variable (#34566)
This commit adds a completion for the `$event` variable in bound event expressions. This is the first in a series of PRs to support completions for properties on `$event` variables (https://github.com/angular/vscode-ng-language-service/issues/531). PR Close #34566
This commit is contained in:
parent
cb142b6df9
commit
d7ea389c84
|
@ -308,7 +308,7 @@ function attributeValueCompletions(info: AstResult, htmlPath: HtmlAstPath): ng.C
|
|||
const templatePath = findTemplateAstAt(info.templateAst, htmlPath.position);
|
||||
const visitor = new ExpressionVisitor(info, htmlPath.position, () => {
|
||||
const dinfo = diagnosticInfoFromTemplateInfo(info);
|
||||
return getExpressionScope(dinfo, templatePath, false);
|
||||
return getExpressionScope(dinfo, templatePath);
|
||||
});
|
||||
if (templatePath.tail instanceof AttrAst ||
|
||||
templatePath.tail instanceof BoundElementPropertyAst ||
|
||||
|
@ -398,8 +398,7 @@ function interpolationCompletions(info: AstResult, position: number): ng.Complet
|
|||
return [];
|
||||
}
|
||||
const visitor = new ExpressionVisitor(
|
||||
info, position,
|
||||
() => getExpressionScope(diagnosticInfoFromTemplateInfo(info), templatePath, false));
|
||||
info, position, () => getExpressionScope(diagnosticInfoFromTemplateInfo(info), templatePath));
|
||||
templatePath.tail.visit(visitor, null);
|
||||
return visitor.results;
|
||||
}
|
||||
|
|
|
@ -25,8 +25,7 @@ export interface DiagnosticTemplateInfo {
|
|||
|
||||
export function getTemplateExpressionDiagnostics(info: DiagnosticTemplateInfo): Diagnostic[] {
|
||||
const visitor = new ExpressionDiagnosticsVisitor(
|
||||
info, (path: TemplateAstPath, includeEvent: boolean) =>
|
||||
getExpressionScope(info, path, includeEvent));
|
||||
info, (path: TemplateAstPath) => getExpressionScope(info, path));
|
||||
templateVisitAll(visitor, info.templateAst);
|
||||
return visitor.diagnostics;
|
||||
}
|
||||
|
@ -194,9 +193,9 @@ function refinedVariableType(
|
|||
return query.getBuiltinType(BuiltinType.Any);
|
||||
}
|
||||
|
||||
function getEventDeclaration(info: DiagnosticTemplateInfo, includeEvent?: boolean) {
|
||||
function getEventDeclaration(info: DiagnosticTemplateInfo, path: TemplateAstPath) {
|
||||
let result: SymbolDeclaration[] = [];
|
||||
if (includeEvent) {
|
||||
if (path.tail instanceof BoundEventAst) {
|
||||
// TODO: Determine the type of the event parameter based on the Observable<T> or EventEmitter<T>
|
||||
// of the event.
|
||||
result = [{name: '$event', kind: 'variable', type: info.query.getBuiltinType(BuiltinType.Any)}];
|
||||
|
@ -205,11 +204,11 @@ function getEventDeclaration(info: DiagnosticTemplateInfo, includeEvent?: boolea
|
|||
}
|
||||
|
||||
export function getExpressionScope(
|
||||
info: DiagnosticTemplateInfo, path: TemplateAstPath, includeEvent: boolean): SymbolTable {
|
||||
info: DiagnosticTemplateInfo, path: TemplateAstPath): SymbolTable {
|
||||
let result = info.members;
|
||||
const references = getReferences(info);
|
||||
const variables = getVarDeclarations(info, path);
|
||||
const events = getEventDeclaration(info, includeEvent);
|
||||
const events = getEventDeclaration(info, path);
|
||||
if (references.length || variables.length || events.length) {
|
||||
const referenceTable = info.query.createSymbolTable(references);
|
||||
const variableTable = info.query.createSymbolTable(variables);
|
||||
|
@ -334,11 +333,6 @@ class ExpressionDiagnosticsVisitor extends RecursiveTemplateAstVisitor {
|
|||
{span: offsetSpan(span, this.info.offset), kind: ts.DiagnosticCategory.Error, message});
|
||||
}
|
||||
}
|
||||
|
||||
private reportWarning(message: string, span: Span) {
|
||||
this.diagnostics.push(
|
||||
{span: offsetSpan(span, this.info.offset), kind: ts.DiagnosticCategory.Warning, message});
|
||||
}
|
||||
}
|
||||
|
||||
function hasTemplateReference(type: CompileTypeMetadata): boolean {
|
||||
|
|
|
@ -37,7 +37,7 @@ export function locateSymbol(info: AstResult, position: number): SymbolInfo|unde
|
|||
if (attribute) {
|
||||
if (inSpan(templatePosition, spanOf(attribute.valueSpan))) {
|
||||
const dinfo = diagnosticInfoFromTemplateInfo(info);
|
||||
const scope = getExpressionScope(dinfo, path, inEvent);
|
||||
const scope = getExpressionScope(dinfo, path);
|
||||
if (attribute.valueSpan) {
|
||||
const result = getExpressionSymbol(scope, ast, templatePosition, info.template.query);
|
||||
if (result) {
|
||||
|
@ -113,7 +113,7 @@ export function locateSymbol(info: AstResult, position: number): SymbolInfo|unde
|
|||
const expressionPosition = templatePosition - ast.sourceSpan.start.offset;
|
||||
if (inSpan(expressionPosition, ast.value.span)) {
|
||||
const dinfo = diagnosticInfoFromTemplateInfo(info);
|
||||
const scope = getExpressionScope(dinfo, path, /* includeEvent */ false);
|
||||
const scope = getExpressionScope(dinfo, path);
|
||||
const result =
|
||||
getExpressionSymbol(scope, ast.value, templatePosition, info.template.query);
|
||||
if (result) {
|
||||
|
|
|
@ -744,6 +744,15 @@ describe('completions', () => {
|
|||
const completions = ngLS.getCompletionsAt(TEST_TEMPLATE, marker.start);
|
||||
expectContain(completions, CompletionKind.PROPERTY, ['title']);
|
||||
});
|
||||
|
||||
describe('$event completions', () => {
|
||||
it('should suggest $event in event bindings', () => {
|
||||
mockHost.override(TEST_TEMPLATE, `<div (click)="myClick(~{cursor});"></div>`);
|
||||
const marker = mockHost.getLocationMarkerFor(TEST_TEMPLATE, 'cursor');
|
||||
const completions = ngLS.getCompletionsAt(TEST_TEMPLATE, marker.start);
|
||||
expectContain(completions, CompletionKind.VARIABLE, ['$event']);
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
function expectContain(
|
||||
|
|
Loading…
Reference in New Issue