fix(ivy): emit generic type arguments in Pipe metadata (#29403)

Previously, only directives and services with generic type parameters
would emit `any` as generic type when emitting Ivy metadata into .d.ts
files. Pipes can also have generic type parameters but did not emit
`any` for all type parameters, resulting in the omission of those
parameters which causes compilation errors.

This commit adds support for pipes with generic type arguments and emits
`any` as generic type in the Ivy metadata.

Fixes #29400

PR Close #29403
This commit is contained in:
JoostK 2019-03-19 21:22:03 +01:00 committed by Matias Niemelä
parent 17b3f11e07
commit 9eb8274991
7 changed files with 55 additions and 11 deletions

View File

@ -98,7 +98,7 @@ export class PipeDecoratorHandler implements DecoratorHandler<PipeHandlerData, D
meta: { meta: {
name, name,
type, type,
pipeName, typeArgumentCount: this.reflector.getGenericArityOfClass(clazz) || 0, pipeName,
deps: getValidConstructorDependencies( deps: getValidConstructorDependencies(
clazz, this.reflector, this.defaultImportRecorder, this.isCore), clazz, this.reflector, this.defaultImportRecorder, this.isCore),
pure, pure,

View File

@ -792,6 +792,26 @@ describe('ngtsc behavioral tests', () => {
expect(jsContents).toContain('return new (t || TestPipe)(i0.ɵdirectiveInject(Dep));'); expect(jsContents).toContain('return new (t || TestPipe)(i0.ɵdirectiveInject(Dep));');
}); });
it('should compile Pipes with generic types', () => {
env.tsconfig();
env.write('test.ts', `
import {Pipe} from '@angular/core';
@Pipe({
name: 'test-pipe',
})
export class TestPipe<T> {}
`);
env.driveMain();
const jsContents = env.getContents('test.js');
expect(jsContents).toContain('TestPipe.ngPipeDef =');
const dtsContents = env.getContents('test.d.ts');
expect(dtsContents)
.toContain('static ngPipeDef: i0.ɵPipeDefWithMeta<TestPipe<any>, "test-pipe">;');
});
it('should include @Pipes in @NgModule scopes', () => { it('should include @Pipes in @NgModule scopes', () => {
env.tsconfig(); env.tsconfig();
env.write('test.ts', ` env.write('test.ts', `

View File

@ -77,6 +77,7 @@ export interface R3DependencyMetadataFacade {
export interface R3PipeMetadataFacade { export interface R3PipeMetadataFacade {
name: string; name: string;
type: any; type: any;
typeArgumentCount: number;
pipeName: string; pipeName: string;
deps: R3DependencyMetadataFacade[]|null; deps: R3DependencyMetadataFacade[]|null;
pure: boolean; pure: boolean;

View File

@ -38,6 +38,7 @@ export class CompilerFacadeImpl implements CompilerFacade {
const res = compilePipeFromMetadata({ const res = compilePipeFromMetadata({
name: facade.name, name: facade.name,
type: new WrappedNodeExpr(facade.type), type: new WrappedNodeExpr(facade.type),
typeArgumentCount: facade.typeArgumentCount,
deps: convertR3DependencyMetadataArray(facade.deps), deps: convertR3DependencyMetadataArray(facade.deps),
pipeName: facade.pipeName, pipeName: facade.pipeName,
pure: facade.pure, pure: facade.pure,

View File

@ -14,19 +14,38 @@ import {OutputContext, error} from '../util';
import {R3DependencyMetadata, compileFactoryFunction, dependenciesFromGlobalMetadata} from './r3_factory'; import {R3DependencyMetadata, compileFactoryFunction, dependenciesFromGlobalMetadata} from './r3_factory';
import {Identifiers as R3} from './r3_identifiers'; import {Identifiers as R3} from './r3_identifiers';
import {typeWithParameters} from './util';
export interface R3PipeMetadata { export interface R3PipeMetadata {
/**
* Name of the pipe type.
*/
name: string; name: string;
type: o.Expression;
pipeName: string;
deps: R3DependencyMetadata[]|null;
pure: boolean;
}
export interface R3PipeDef { /**
expression: o.Expression; * An expression representing a reference to the pipe itself.
type: o.Type; */
statements: o.Statement[]; type: o.Expression;
/**
* Number of generic type parameters of the type itself.
*/
typeArgumentCount: number;
/**
* Name of the pipe.
*/
pipeName: string;
/**
* Dependencies of the pipe's constructor.
*/
deps: R3DependencyMetadata[]|null;
/**
* Whether the pipe is marked as pure.
*/
pure: boolean;
} }
export function compilePipeFromMetadata(metadata: R3PipeMetadata) { export function compilePipeFromMetadata(metadata: R3PipeMetadata) {
@ -51,7 +70,7 @@ export function compilePipeFromMetadata(metadata: R3PipeMetadata) {
const expression = o.importExpr(R3.definePipe).callFn([o.literalMap(definitionMapValues)]); const expression = o.importExpr(R3.definePipe).callFn([o.literalMap(definitionMapValues)]);
const type = new o.ExpressionType(o.importExpr(R3.PipeDefWithMeta, [ const type = new o.ExpressionType(o.importExpr(R3.PipeDefWithMeta, [
new o.ExpressionType(metadata.type), typeWithParameters(metadata.type, metadata.typeArgumentCount),
new o.ExpressionType(new o.LiteralExpr(metadata.pipeName)), new o.ExpressionType(new o.LiteralExpr(metadata.pipeName)),
])); ]));
return {expression, type, statements: templateFactory.statements}; return {expression, type, statements: templateFactory.statements};
@ -73,6 +92,7 @@ export function compilePipeFromRender2(
name, name,
pipeName: pipe.name, pipeName: pipe.name,
type: outputCtx.importExpr(pipe.type.reference), type: outputCtx.importExpr(pipe.type.reference),
typeArgumentCount: 0,
deps: dependenciesFromGlobalMetadata(pipe.type, outputCtx, reflector), deps: dependenciesFromGlobalMetadata(pipe.type, outputCtx, reflector),
pure: pipe.pure, pure: pipe.pure,
}; };

View File

@ -77,6 +77,7 @@ export interface R3DependencyMetadataFacade {
export interface R3PipeMetadataFacade { export interface R3PipeMetadataFacade {
name: string; name: string;
type: any; type: any;
typeArgumentCount: number;
pipeName: string; pipeName: string;
deps: R3DependencyMetadataFacade[]|null; deps: R3DependencyMetadataFacade[]|null;
pure: boolean; pure: boolean;

View File

@ -23,6 +23,7 @@ export function compilePipe(type: Type<any>, meta: Pipe): void {
ngPipeDef = getCompilerFacade().compilePipe( ngPipeDef = getCompilerFacade().compilePipe(
angularCoreEnv, `ng://${renderStringify(type)}/ngPipeDef.js`, { angularCoreEnv, `ng://${renderStringify(type)}/ngPipeDef.js`, {
type: type, type: type,
typeArgumentCount: 0,
name: type.name, name: type.name,
deps: reflectDependencies(type), deps: reflectDependencies(type),
pipeName: meta.name, pipeName: meta.name,