|
6 | 6 | * found in the LICENSE file at https://angular.io/license
|
7 | 7 | */
|
8 | 8 |
|
9 |
| -import {AST, BindingPipe, BindingType, BoundTarget, Call, createCssSelectorFromNode, CssSelector, DYNAMIC_TYPE, ImplicitReceiver, ParsedEventType, ParseSourceSpan, PropertyRead, PropertyWrite, SafeCall, SafePropertyRead, SchemaMetadata, SelectorMatcher, ThisReceiver, TmplAstBoundAttribute, TmplAstBoundEvent, TmplAstBoundText, TmplAstDeferredBlock, TmplAstDeferredBlockTriggers, TmplAstElement, TmplAstForLoopBlock, TmplAstHoverDeferredTrigger, TmplAstIcu, TmplAstIfBlock, TmplAstIfBlockBranch, TmplAstInteractionDeferredTrigger, TmplAstNode, TmplAstReference, TmplAstSwitchBlock, TmplAstSwitchBlockCase, TmplAstTemplate, TmplAstText, TmplAstTextAttribute, TmplAstVariable, TmplAstViewportDeferredTrigger, TransplantedType} from '@angular/compiler'; |
| 9 | +import {AST, BindingPipe, BindingType, BoundTarget, Call, createCssSelectorFromNode, CssSelector, DYNAMIC_TYPE, ImplicitReceiver, ParsedEventType, ParseSourceSpan, PropertyRead, PropertyWrite, R3Identifiers, SafeCall, SafePropertyRead, SchemaMetadata, SelectorMatcher, ThisReceiver, TmplAstBoundAttribute, TmplAstBoundEvent, TmplAstBoundText, TmplAstDeferredBlock, TmplAstDeferredBlockTriggers, TmplAstElement, TmplAstForLoopBlock, TmplAstHoverDeferredTrigger, TmplAstIcu, TmplAstIfBlock, TmplAstIfBlockBranch, TmplAstInteractionDeferredTrigger, TmplAstNode, TmplAstReference, TmplAstSwitchBlock, TmplAstSwitchBlockCase, TmplAstTemplate, TmplAstText, TmplAstTextAttribute, TmplAstVariable, TmplAstViewportDeferredTrigger, TransplantedType} from '@angular/compiler'; |
10 | 10 | import ts from 'typescript';
|
11 | 11 |
|
12 | 12 | import {Reference} from '../../imports';
|
@@ -707,13 +707,19 @@ class TcbDirectiveInputsOp extends TcbOp {
|
707 | 707 |
|
708 | 708 | let assignment: ts.Expression = wrapForDiagnostics(expr);
|
709 | 709 |
|
710 |
| - for (const {fieldName, required, transformType} of attr.inputs) { |
| 710 | + for (const {fieldName, required, transformType, isSignal} of attr.inputs) { |
711 | 711 | let target: ts.LeftHandSideExpression;
|
712 | 712 |
|
713 | 713 | if (required) {
|
714 | 714 | seenRequiredInputs.add(fieldName);
|
715 | 715 | }
|
716 | 716 |
|
| 717 | + // Note: There is no special logic for transforms/coercion with signal inputs. |
| 718 | + // For signal inputs, a `transformType` will never be set as we do not capture |
| 719 | + // the transform in the compiler metadata. Signal inputs incorporate their |
| 720 | + // transform write type into their member type, and we extract it below when |
| 721 | + // unwrapping the `InputSignal<ReadT, WriteT>`. |
| 722 | + |
717 | 723 | if (this.dir.coercedInputFields.has(fieldName)) {
|
718 | 724 | let type: ts.TypeNode;
|
719 | 725 |
|
@@ -781,6 +787,24 @@ class TcbDirectiveInputsOp extends TcbOp {
|
781 | 787 | dirId, ts.factory.createIdentifier(fieldName));
|
782 | 788 | }
|
783 | 789 |
|
| 790 | + // For signal inputs, we unwrap the target `InputSignal`. Note that |
| 791 | + // we intentionally do the following things: |
| 792 | + // 1. keep the direct access to `dir.[field]` so that modifiers are honored. |
| 793 | + // 2. follow the existing pattern where multiple targets assign a single expression. |
| 794 | + // This is a significant requirement for language service auto-completion. |
| 795 | + if (isSignal) { |
| 796 | + const inputSignalBrandWriteSymbol = this.tcb.env.referenceExternalSymbol( |
| 797 | + R3Identifiers.InputSignalBrandWriteType.moduleName, |
| 798 | + R3Identifiers.InputSignalBrandWriteType.name); |
| 799 | + if (!ts.isIdentifier(inputSignalBrandWriteSymbol) && |
| 800 | + !ts.isPropertyAccessExpression(inputSignalBrandWriteSymbol)) { |
| 801 | + throw new Error(`Expected identifier or property access for reference to ${ |
| 802 | + R3Identifiers.InputSignalBrandWriteType.name}`); |
| 803 | + } |
| 804 | + |
| 805 | + target = ts.factory.createElementAccessExpression(target, inputSignalBrandWriteSymbol); |
| 806 | + } |
| 807 | + |
784 | 808 | if (attr.attribute.keySpan !== undefined) {
|
785 | 809 | addParseSpanInfo(target, attr.attribute.keySpan);
|
786 | 810 | }
|
|
0 commit comments