diff --git a/packages/compiler-cli/src/ngtsc/transform/jit/src/initializer_api_transforms/input_function.ts b/packages/compiler-cli/src/ngtsc/transform/jit/src/initializer_api_transforms/input_function.ts index 574037f4f7157..53614cd16b907 100644 --- a/packages/compiler-cli/src/ngtsc/transform/jit/src/initializer_api_transforms/input_function.ts +++ b/packages/compiler-cli/src/ngtsc/transform/jit/src/initializer_api_transforms/input_function.ts @@ -30,6 +30,7 @@ import { */ export const signalInputsTransform: PropertyTransform = ( member, + sourceFile, host, factory, importTracker, @@ -61,7 +62,6 @@ export const signalInputsTransform: PropertyTransform = ( 'transform': factory.createIdentifier('undefined'), }; - const sourceFile = member.node.getSourceFile(); const newDecorator = factory.createDecorator( factory.createCallExpression( createSyntheticAngularCoreDecoratorAccess( diff --git a/packages/compiler-cli/src/ngtsc/transform/jit/src/initializer_api_transforms/model_function.ts b/packages/compiler-cli/src/ngtsc/transform/jit/src/initializer_api_transforms/model_function.ts index fa6ce9f5c4442..1f2fc5891b0b5 100644 --- a/packages/compiler-cli/src/ngtsc/transform/jit/src/initializer_api_transforms/model_function.ts +++ b/packages/compiler-cli/src/ngtsc/transform/jit/src/initializer_api_transforms/model_function.ts @@ -20,6 +20,7 @@ import {createSyntheticAngularCoreDecoratorAccess, PropertyTransform} from './tr */ export const signalModelTransform: PropertyTransform = ( member, + sourceFile, host, factory, importTracker, @@ -56,7 +57,6 @@ export const signalModelTransform: PropertyTransform = ( ), ]); - const sourceFile = member.node.getSourceFile(); const inputDecorator = createDecorator( 'Input', // Config is cast to `any` because `isSignal` will be private, and in case this diff --git a/packages/compiler-cli/src/ngtsc/transform/jit/src/initializer_api_transforms/output_function.ts b/packages/compiler-cli/src/ngtsc/transform/jit/src/initializer_api_transforms/output_function.ts index f6f500ec35b73..233cb600080c4 100644 --- a/packages/compiler-cli/src/ngtsc/transform/jit/src/initializer_api_transforms/output_function.ts +++ b/packages/compiler-cli/src/ngtsc/transform/jit/src/initializer_api_transforms/output_function.ts @@ -22,6 +22,7 @@ import {createSyntheticAngularCoreDecoratorAccess, PropertyTransform} from './tr */ export const initializerApiOutputTransform: PropertyTransform = ( member, + sourceFile, host, factory, importTracker, @@ -43,7 +44,6 @@ export const initializerApiOutputTransform: PropertyTransform = ( return member.node; } - const sourceFile = member.node.getSourceFile(); const newDecorator = factory.createDecorator( factory.createCallExpression( createSyntheticAngularCoreDecoratorAccess( diff --git a/packages/compiler-cli/src/ngtsc/transform/jit/src/initializer_api_transforms/query_functions.ts b/packages/compiler-cli/src/ngtsc/transform/jit/src/initializer_api_transforms/query_functions.ts index b08c4b3363620..0855e2203ca5a 100644 --- a/packages/compiler-cli/src/ngtsc/transform/jit/src/initializer_api_transforms/query_functions.ts +++ b/packages/compiler-cli/src/ngtsc/transform/jit/src/initializer_api_transforms/query_functions.ts @@ -40,6 +40,7 @@ const queryFunctionToDecorator: Record = { */ export const queryFunctionsTransforms: PropertyTransform = ( member, + sourceFile, host, factory, importTracker, @@ -61,7 +62,6 @@ export const queryFunctionsTransforms: PropertyTransform = ( return member.node; } - const sourceFile = member.node.getSourceFile(); const callArgs = queryDefinition.call.arguments; const newDecorator = factory.createDecorator( factory.createCallExpression( diff --git a/packages/compiler-cli/src/ngtsc/transform/jit/src/initializer_api_transforms/transform.ts b/packages/compiler-cli/src/ngtsc/transform/jit/src/initializer_api_transforms/transform.ts index 032bb1177e0bb..7b18cc4b314bc 100644 --- a/packages/compiler-cli/src/ngtsc/transform/jit/src/initializer_api_transforms/transform.ts +++ b/packages/compiler-cli/src/ngtsc/transform/jit/src/initializer_api_transforms/transform.ts @@ -98,6 +98,7 @@ function createTransformVisitor( ) { let hasChanged = false; + const sourceFile = originalNode.getSourceFile(); const members = node.members.map((memberNode) => { if (!ts.isPropertyDeclaration(memberNode)) { return memberNode; @@ -111,6 +112,7 @@ function createTransformVisitor( for (const transform of propertyTransforms) { const newNode = transform( {...member, node: memberNode}, + sourceFile, host, ctx.factory, importTracker, diff --git a/packages/compiler-cli/src/ngtsc/transform/jit/src/initializer_api_transforms/transform_api.ts b/packages/compiler-cli/src/ngtsc/transform/jit/src/initializer_api_transforms/transform_api.ts index 83b7564a85c65..3c9b4365efab6 100644 --- a/packages/compiler-cli/src/ngtsc/transform/jit/src/initializer_api_transforms/transform_api.ts +++ b/packages/compiler-cli/src/ngtsc/transform/jit/src/initializer_api_transforms/transform_api.ts @@ -15,6 +15,7 @@ import {ImportManager} from '../../../../translator'; /** Function that can be used to transform class properties. */ export type PropertyTransform = ( member: Pick & {node: ts.PropertyDeclaration}, + sourceFile: ts.SourceFile, host: ReflectionHost, factory: ts.NodeFactory, importTracker: ImportedSymbolsTracker, diff --git a/packages/compiler-cli/src/ngtsc/transform/jit/test/initializer_api_transforms_spec.ts b/packages/compiler-cli/src/ngtsc/transform/jit/test/initializer_api_transforms_spec.ts index 661da20ee8283..44a9892a1b4f9 100644 --- a/packages/compiler-cli/src/ngtsc/transform/jit/test/initializer_api_transforms_spec.ts +++ b/packages/compiler-cli/src/ngtsc/transform/jit/test/initializer_api_transforms_spec.ts @@ -315,6 +315,52 @@ describe('initializer API metadata transform', () => { `), ); }); + + // Tsickle may transform the class via the downlevel decorator transform in advance in G3. + // In addition, the property declaration may be transformed too, to add `@type` JSDocs in G3. + it('should migrate if the class member and class is transformed in advance', () => { + const fakeDownlevelPreTransform = (ctx: ts.TransformationContext) => { + return (sf: ts.SourceFile) => { + const visitor = (node: ts.Node) => { + // Updating the `{transform: () => {}} arrow function triggers both transforms. + if (ts.isArrowFunction(node)) { + return ctx.factory.updateArrowFunction( + node, + node.modifiers, + node.typeParameters, + node.parameters, + node.type, + node.equalsGreaterThanToken, + ctx.factory.createBlock([]), + ); + } + return ts.visitEachChild(node, visitor, ctx); + }; + return ts.visitEachChild(sf, visitor, ctx); + }; + }; + + const result = transform( + ` + import {input, Directive} from '@angular/core'; + + @Directive({}) + class MyDir { + someInput = input({transform: () => {}}); + } + `, + false, + fakeDownlevelPreTransform, + ); + + expect(result).toContain( + omitLeadingWhitespace(` + __decorate([ + i0.Input({ isSignal: true, alias: "someInput", required: false, transform: undefined }) + ], MyDir.prototype, "someInput", void 0); + `), + ); + }); }); describe('model()', () => {