refactor(language-service): make findOutputBinding a utility function (#34997)
This commit makes `findOutputBinding` a utility function for the language service, which will be used by the `expression_diagnostics` module in #34570. Keeping the function in `locate_symbol` results in a circular dependency between `expression_diagnostics` and `locate_symbol`. PR Close #34997
This commit is contained in:
parent
304584c291
commit
90b303faa3
|
@ -6,13 +6,14 @@
|
|||
* found in the LICENSE file at https://angular.io/license
|
||||
*/
|
||||
|
||||
import {AST, Attribute, BoundDirectivePropertyAst, BoundEventAst, CssSelector, DirectiveAst, ElementAst, EmbeddedTemplateAst, RecursiveTemplateAstVisitor, SelectorMatcher, StaticSymbol, TemplateAst, TemplateAstPath, templateVisitAll, tokenReference} from '@angular/compiler';
|
||||
import {Attribute, BoundDirectivePropertyAst, CssSelector, DirectiveAst, ElementAst, EmbeddedTemplateAst, RecursiveTemplateAstVisitor, SelectorMatcher, StaticSymbol, TemplateAst, TemplateAstPath, templateVisitAll, tokenReference} from '@angular/compiler';
|
||||
import * as tss from 'typescript/lib/tsserverlibrary';
|
||||
|
||||
import {AstResult} from './common';
|
||||
import {getExpressionScope} from './expression_diagnostics';
|
||||
import {getExpressionSymbol} from './expressions';
|
||||
import {Definition, DirectiveKind, Span, Symbol} from './types';
|
||||
import {diagnosticInfoFromTemplateInfo, findTemplateAstAt, getPathToNodeAtPosition, inSpan, isNarrower, offsetSpan, spanOf} from './utils';
|
||||
import {diagnosticInfoFromTemplateInfo, findOutputBinding, findTemplateAstAt, getPathToNodeAtPosition, inSpan, invertMap, isNarrower, offsetSpan, spanOf} from './utils';
|
||||
|
||||
export interface SymbolInfo {
|
||||
symbol: Symbol;
|
||||
|
@ -286,32 +287,6 @@ function findInputBinding(info: AstResult, name: string, directiveAst: Directive
|
|||
}
|
||||
}
|
||||
|
||||
function findOutputBinding(info: AstResult, path: TemplateAstPath, binding: BoundEventAst): Symbol|
|
||||
undefined {
|
||||
const element = path.first(ElementAst);
|
||||
if (element) {
|
||||
for (const directive of element.directives) {
|
||||
const invertedOutputs = invertMap(directive.directive.outputs);
|
||||
const fieldName = invertedOutputs[binding.name];
|
||||
if (fieldName) {
|
||||
const classSymbol = info.template.query.getTypeSymbol(directive.directive.type.reference);
|
||||
if (classSymbol) {
|
||||
return classSymbol.members().get(fieldName);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
function invertMap(obj: {[name: string]: string}): {[name: string]: string} {
|
||||
const result: {[name: string]: string} = {};
|
||||
for (const name of Object.keys(obj)) {
|
||||
const v = obj[name];
|
||||
result[v] = name;
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
/**
|
||||
* Wrap a symbol and change its kind to component.
|
||||
*/
|
||||
|
|
|
@ -6,12 +6,12 @@
|
|||
* found in the LICENSE file at https://angular.io/license
|
||||
*/
|
||||
|
||||
import {AstPath, CompileDirectiveSummary, CompileTypeMetadata, CssSelector, DirectiveAst, ElementAst, EmbeddedTemplateAst, HtmlAstPath, Identifiers, Node, ParseSourceSpan, RecursiveTemplateAstVisitor, RecursiveVisitor, TemplateAst, TemplateAstPath, identifierName, templateVisitAll, visitAll} from '@angular/compiler';
|
||||
import {AstPath, BoundEventAst, CompileDirectiveSummary, CompileTypeMetadata, CssSelector, DirectiveAst, ElementAst, EmbeddedTemplateAst, HtmlAstPath, Identifiers, Node, ParseSourceSpan, RecursiveTemplateAstVisitor, RecursiveVisitor, TemplateAst, TemplateAstPath, identifierName, templateVisitAll, visitAll} from '@angular/compiler';
|
||||
import * as ts from 'typescript';
|
||||
|
||||
import {AstResult, SelectorInfo} from './common';
|
||||
import {DiagnosticTemplateInfo} from './expression_diagnostics';
|
||||
import {Span} from './types';
|
||||
import {Span, Symbol} from './types';
|
||||
|
||||
export interface SpanHolder {
|
||||
sourceSpan: ParseSourceSpan;
|
||||
|
@ -102,7 +102,7 @@ export function diagnosticInfoFromTemplateInfo(info: AstResult): DiagnosticTempl
|
|||
export function findTemplateAstAt(ast: TemplateAst[], position: number): TemplateAstPath {
|
||||
const path: TemplateAst[] = [];
|
||||
const visitor = new class extends RecursiveTemplateAstVisitor {
|
||||
visit(ast: TemplateAst, context: any): any {
|
||||
visit(ast: TemplateAst): any {
|
||||
let span = spanOf(ast);
|
||||
if (inSpan(position, span)) {
|
||||
const len = path.length;
|
||||
|
@ -247,3 +247,39 @@ export function getPathToNodeAtPosition(nodes: Node[], position: number): HtmlAs
|
|||
visitAll(visitor, nodes);
|
||||
return new AstPath<Node>(path, position);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Inverts an object's key-value pairs.
|
||||
*/
|
||||
export function invertMap(obj: {[name: string]: string}): {[name: string]: string} {
|
||||
const result: {[name: string]: string} = {};
|
||||
for (const name of Object.keys(obj)) {
|
||||
const v = obj[name];
|
||||
result[v] = name;
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Finds the directive member providing a template output binding, if one exists.
|
||||
* @param info aggregate template AST information
|
||||
* @param path narrowing
|
||||
*/
|
||||
export function findOutputBinding(
|
||||
info: AstResult, path: TemplateAstPath, binding: BoundEventAst): Symbol|undefined {
|
||||
const element = path.first(ElementAst);
|
||||
if (element) {
|
||||
for (const directive of element.directives) {
|
||||
const invertedOutputs = invertMap(directive.directive.outputs);
|
||||
const fieldName = invertedOutputs[binding.name];
|
||||
if (fieldName) {
|
||||
const classSymbol = info.template.query.getTypeSymbol(directive.directive.type.reference);
|
||||
if (classSymbol) {
|
||||
return classSymbol.members().get(fieldName);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue