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:
parent
17b3f11e07
commit
9eb8274991
|
@ -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,
|
||||||
|
|
|
@ -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', `
|
||||||
|
|
|
@ -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;
|
||||||
|
|
|
@ -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,
|
||||||
|
|
|
@ -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,
|
||||||
};
|
};
|
||||||
|
|
|
@ -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;
|
||||||
|
|
|
@ -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,
|
||||||
|
|
Loading…
Reference in New Issue