Skip to content

Commit c0778b4

Browse files
ivanwonderatscott
authored andcommitted
fix(compiler-cli): Support resolve animation name from the DTS (#45107)
Before this, the compiler resolves the value in the DTS as dynamic. If the `trigger` is imported from `@angular/animations`, this PR will use FFR to simulate the actual implementation in JS and extracts the animation name. PR Close #45107
1 parent f80c59e commit c0778b4

3 files changed

Lines changed: 46 additions & 13 deletions

File tree

packages/compiler-cli/src/ngtsc/annotations/component/src/handler.ts

Lines changed: 5 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -35,7 +35,7 @@ import {ComponentAnalysisData, ComponentResolutionData} from './metadata';
3535
import {_extractTemplateStyleUrls, extractComponentStyleUrls, extractStyleResources, extractTemplate, makeResourceNotFoundError, ParsedTemplateWithSource, parseTemplateDeclaration, preloadAndParseTemplate, ResourceTypeForDiagnostics, StyleUrlMeta, transformDecoratorToInlineResources} from './resources';
3636
import {scopeTemplate} from './scope';
3737
import {ComponentSymbol} from './symbol';
38-
import {collectAnimationNames, validateAndFlattenComponentImports} from './util';
38+
import {animationTriggerResolver, collectAnimationNames, validateAndFlattenComponentImports} from './util';
3939

4040
const EMPTY_MAP = new Map<string, Expression>();
4141
const EMPTY_ARRAY: any[] = [];
@@ -210,8 +210,10 @@ export class ComponentDecoratorHandler implements
210210
let animations: Expression|null = null;
211211
let animationTriggerNames: AnimationTriggerNames|null = null;
212212
if (component.has('animations')) {
213-
animations = new WrappedNodeExpr(component.get('animations')!);
214-
const animationsValue = this.evaluator.evaluate(component.get('animations')!);
213+
const animationExpression = component.get('animations')!;
214+
animations = new WrappedNodeExpr(animationExpression);
215+
const animationsValue =
216+
this.evaluator.evaluate(animationExpression, animationTriggerResolver);
215217
animationTriggerNames = {includesDynamicAnimations: false, staticTriggerNames: []};
216218
collectAnimationNames(animationsValue, animationTriggerNames);
217219
}

packages/compiler-cli/src/ngtsc/annotations/component/src/util.ts

Lines changed: 23 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,7 @@ import {AnimationTriggerNames} from '@angular/compiler';
1010
import ts from 'typescript';
1111

1212
import {Reference} from '../../../imports';
13-
import {ResolvedValue} from '../../../partial_evaluator';
13+
import {ForeignFunctionResolver, ResolvedValue} from '../../../partial_evaluator';
1414
import {ClassDeclaration, isNamedClassDeclaration} from '../../../reflection';
1515
import {createValueHasWrongTypeError} from '../../common';
1616

@@ -38,6 +38,28 @@ export function collectAnimationNames(
3838
}
3939
}
4040

41+
export function isAngularAnimationsReference(reference: Reference, symbolName: string): boolean {
42+
return reference.ownedByModuleGuess === '@angular/animations' &&
43+
reference.debugName === symbolName;
44+
}
45+
46+
export const animationTriggerResolver: ForeignFunctionResolver = (ref, args) => {
47+
const animationTriggerMethodName = 'trigger';
48+
if (!isAngularAnimationsReference(ref, animationTriggerMethodName)) {
49+
return null;
50+
}
51+
const triggerNameExpression = args[0];
52+
if (!triggerNameExpression) {
53+
return null;
54+
}
55+
const factory = ts.factory;
56+
return factory.createObjectLiteralExpression(
57+
[
58+
factory.createPropertyAssignment(factory.createIdentifier('name'), triggerNameExpression),
59+
],
60+
true);
61+
};
62+
4163
export function validateAndFlattenComponentImports(imports: ResolvedValue, expr: ts.Expression): {
4264
imports: Reference<ClassDeclaration>[],
4365
diagnostics: ts.Diagnostic[],

packages/compiler-cli/src/ngtsc/annotations/component/test/component_spec.ts

Lines changed: 18 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -408,13 +408,16 @@ runInEachFileSystem(() => {
408408
name: _('/node_modules/@angular/core/index.d.ts'),
409409
contents: 'export const Component: any;',
410410
},
411+
{
412+
name: _('/node_modules/@angular/animations/index.d.ts'),
413+
contents: 'export declare function trigger(name: any): any',
414+
},
411415
{
412416
name: _('/entry.ts'),
413417
contents: `
414418
import {Component} from '@angular/core';
415-
function trigger(name) {
416-
return {name};
417-
}
419+
import {trigger} from '@angular/animations';
420+
418421
@Component({
419422
template: '',
420423
animations: [
@@ -447,13 +450,16 @@ runInEachFileSystem(() => {
447450
name: _('/node_modules/@angular/core/index.d.ts'),
448451
contents: 'export const Component: any;',
449452
},
453+
{
454+
name: _('/node_modules/@angular/animations/index.d.ts'),
455+
contents: 'export declare function trigger(name: any): any',
456+
},
450457
{
451458
name: _('/entry.ts'),
452459
contents: `
453460
import {Component} from '@angular/core';
454-
function trigger(name) {
455-
return {name};
456-
}
461+
import {trigger} from '@angular/animations';
462+
457463
function buildComplexAnimations() {
458464
const name = 'complex';
459465
return [trigger(name)];
@@ -488,13 +494,16 @@ runInEachFileSystem(() => {
488494
name: _('/node_modules/@angular/core/index.d.ts'),
489495
contents: 'export const Component: any;',
490496
},
497+
{
498+
name: _('/node_modules/@angular/animations/index.d.ts'),
499+
contents: 'export declare function trigger(name: any): any',
500+
},
491501
{
492502
name: _('/entry.ts'),
493503
contents: `
494504
import {Component} from '@angular/core';
495-
function trigger(name) {
496-
return {name};
497-
}
505+
import {trigger} from '@angular/animations';
506+
498507
function buildComplexAnimations() {
499508
const name = 'complex';
500509
return [trigger(name)];

0 commit comments

Comments
 (0)