Skip to content

Commit 372e1ff

Browse files
crisbetothePunderWoman
authored andcommitted
refactor(compiler-cli): account for model inputs in language service (angular#54252)
Updates the code that resolves a node from the TCB to an input in order to fix the language service. PR Close angular#54252
1 parent 702ab28 commit 372e1ff

1 file changed

Lines changed: 22 additions & 5 deletions

File tree

packages/compiler-cli/src/ngtsc/typecheck/src/template_symbol_builder.ts

Lines changed: 22 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@
66
* found in the LICENSE file at https://angular.io/license
77
*/
88

9-
import {AST, ASTWithSource, BindingPipe, ParseSourceSpan, PropertyRead, PropertyWrite, R3Identifiers, SafePropertyRead, TmplAstBoundAttribute, TmplAstBoundEvent, TmplAstElement, TmplAstNode, TmplAstReference, TmplAstTemplate, TmplAstTextAttribute, TmplAstVariable} from '@angular/compiler';
9+
import {AST, ASTWithSource, BindingPipe, BindingType, ParseSourceSpan, PropertyRead, PropertyWrite, R3Identifiers, SafePropertyRead, TmplAstBoundAttribute, TmplAstBoundEvent, TmplAstElement, TmplAstNode, TmplAstReference, TmplAstTemplate, TmplAstTextAttribute, TmplAstVariable} from '@angular/compiler';
1010
import ts from 'typescript';
1111

1212
import {AbsoluteFsPath} from '../../file_system';
@@ -350,15 +350,32 @@ export class SymbolBuilder {
350350
return host !== null ? {kind: SymbolKind.DomBinding, host} : null;
351351
}
352352

353+
const isTwoWayBinding =
354+
binding instanceof TmplAstBoundAttribute && binding.type === BindingType.TwoWay;
353355
const nodes = findAllMatchingNodes(
354356
this.typeCheckBlock, {withSpan: binding.sourceSpan, filter: isAssignment});
355357
const bindings: BindingSymbol[] = [];
356358
for (const node of nodes) {
357-
if (!isAccessExpression(node.left)) {
359+
let assignment: ts.PropertyAccessExpression|ts.ElementAccessExpression|null = null;
360+
361+
// One-way bindings usually are in the form of `dir.input = expression`.
362+
if (isAccessExpression(node.left)) {
363+
assignment = node.left;
364+
} else if (
365+
// The property side of two-way bindings is in the
366+
// form of `(dir.input as unknown as someType) = expression`.
367+
isTwoWayBinding && ts.isParenthesizedExpression(node.left) &&
368+
ts.isAsExpression(node.left.expression) &&
369+
ts.isAsExpression(node.left.expression.expression) &&
370+
isAccessExpression(node.left.expression.expression.expression)) {
371+
assignment = node.left.expression.expression.expression;
372+
}
373+
374+
if (assignment === null) {
358375
continue;
359376
}
360377

361-
const signalInputAssignment = unwrapSignalInputWriteTAccessor(node.left);
378+
const signalInputAssignment = unwrapSignalInputWriteTAccessor(assignment);
362379
let symbolInfo: TsNodeSymbolInfo|null = null;
363380

364381
// Signal inputs need special treatment because they are generated with an extra keyed
@@ -376,15 +393,15 @@ export class SymbolBuilder {
376393
tsType: typeSymbol.tsType,
377394
};
378395
} else {
379-
symbolInfo = this.getSymbolOfTsNode(node.left);
396+
symbolInfo = this.getSymbolOfTsNode(assignment);
380397
}
381398

382399
if (symbolInfo === null || symbolInfo.tsSymbol === null) {
383400
continue;
384401
}
385402

386403
const target = this.getDirectiveSymbolForAccessExpression(
387-
signalInputAssignment?.fieldExpr ?? node.left, consumer);
404+
signalInputAssignment?.fieldExpr ?? assignment, consumer);
388405
if (target === null) {
389406
continue;
390407
}

0 commit comments

Comments
 (0)