fix(ivy): allow abstract directives to have an invalid constructor (#32987)
For abstract directives, i.e. directives without a selector, it may happen that their constructor is called explicitly from a subclass, hence its parameters are not required to be valid for Angular's DI purposes. Prior to this commit however, having an abstract directive with a constructor that has parameters that are not eligible for Angular's DI would produce a compilation error. A similar scenario may occur for `@Injectable`s, where an explicit `use*` definition allows for the constructor to be irrelevant. For example, the situation where `useFactory` is specified allows for the constructor to be called explicitly with any value, so its constructor parameters are not required to be valid. For `@Injectable`s this is handled by generating a DI factory function that throws. This commit implements the same solution for abstract directives, such that a compilation error is avoided while still producing an error at runtime if the type is instantiated implicitly by Angular's DI mechanism. Fixes #32981 PR Close #32987
This commit is contained in:
@ -56,6 +56,7 @@ export {
|
||||
ɵɵcontainerRefreshStart,
|
||||
|
||||
ɵɵdirectiveInject,
|
||||
ɵɵinvalidFactory,
|
||||
|
||||
ɵɵelement,
|
||||
ɵɵelementContainer,
|
||||
|
@ -59,3 +59,21 @@ export function ɵɵdirectiveInject<T>(
|
||||
export function ɵɵinjectAttribute(attrNameToInject: string): string|null {
|
||||
return injectAttributeImpl(getPreviousOrParentTNode(), attrNameToInject);
|
||||
}
|
||||
|
||||
/**
|
||||
* Throws an error indicating that a factory function could not be generated by the compiler for a
|
||||
* particular class.
|
||||
*
|
||||
* This instruction allows the actual error message to be optimized away when ngDevMode is turned
|
||||
* off, saving bytes of generated code while still providing a good experience in dev mode.
|
||||
*
|
||||
* The name of the class is not mentioned here, but will be in the generated factory function name
|
||||
* and thus in the stack trace.
|
||||
*
|
||||
* @codeGenApi
|
||||
*/
|
||||
export function ɵɵinvalidFactory(): never {
|
||||
const msg =
|
||||
ngDevMode ? `This constructor was not compatible with Dependency Injection.` : 'invalid';
|
||||
throw new Error(msg);
|
||||
}
|
||||
|
@ -165,9 +165,12 @@ function addDirectiveFactoryDef(type: Type<any>, metadata: Directive | Component
|
||||
get: () => {
|
||||
if (ngFactoryDef === null) {
|
||||
const meta = getDirectiveMetadata(type, metadata);
|
||||
ngFactoryDef = getCompilerFacade().compileFactory(
|
||||
angularCoreEnv, `ng:///${type.name}/ɵfac.js`,
|
||||
{...meta.metadata, injectFn: 'directiveInject', isPipe: false});
|
||||
const compiler = getCompilerFacade();
|
||||
ngFactoryDef = compiler.compileFactory(angularCoreEnv, `ng:///${type.name}/ɵfac.js`, {
|
||||
...meta.metadata,
|
||||
injectFn: 'directiveInject',
|
||||
target: compiler.R3FactoryTarget.Directive
|
||||
});
|
||||
}
|
||||
return ngFactoryDef;
|
||||
},
|
||||
|
@ -42,6 +42,7 @@ export const angularCoreEnv: {[name: string]: Function} =
|
||||
'ɵɵgetInheritedFactory': r3.ɵɵgetInheritedFactory,
|
||||
'ɵɵinject': ɵɵinject,
|
||||
'ɵɵinjectAttribute': r3.ɵɵinjectAttribute,
|
||||
'ɵɵinvalidFactory': r3.ɵɵinvalidFactory,
|
||||
'ɵɵinjectPipeChangeDetectorRef': r3.ɵɵinjectPipeChangeDetectorRef,
|
||||
'ɵɵtemplateRefExtractor': r3.ɵɵtemplateRefExtractor,
|
||||
'ɵɵNgOnChangesFeature': r3.ɵɵNgOnChangesFeature,
|
||||
|
@ -22,9 +22,10 @@ export function compilePipe(type: Type<any>, meta: Pipe): void {
|
||||
get: () => {
|
||||
if (ngFactoryDef === null) {
|
||||
const metadata = getPipeMetadata(type, meta);
|
||||
ngFactoryDef = getCompilerFacade().compileFactory(
|
||||
const compiler = getCompilerFacade();
|
||||
ngFactoryDef = compiler.compileFactory(
|
||||
angularCoreEnv, `ng:///${metadata.name}/ɵfac.js`,
|
||||
{...metadata, injectFn: 'directiveInject', isPipe: true});
|
||||
{...metadata, injectFn: 'directiveInject', target: compiler.R3FactoryTarget.Pipe});
|
||||
}
|
||||
return ngFactoryDef;
|
||||
},
|
||||
|
Reference in New Issue
Block a user