fix(ivy): properly inject all special token types (#24862)
Previously ngtsc had a few bugs handling special token types: * Injector was not properly translated to INJECTOR * ChangeDetectorRef was not injected via injectChangeDetectorRef() This commit fixes these two bugs, and also adds a test to ensure they continue to work correctly. PR Close #24862
This commit is contained in:
parent
53a16006d6
commit
f9a6a175bf
|
@ -53,6 +53,9 @@ export function getConstructorDependencies(
|
||||||
const importedSymbol = reflector.getImportOfIdentifier(tokenExpr);
|
const importedSymbol = reflector.getImportOfIdentifier(tokenExpr);
|
||||||
if (importedSymbol !== null && importedSymbol.from === '@angular/core') {
|
if (importedSymbol !== null && importedSymbol.from === '@angular/core') {
|
||||||
switch (importedSymbol.name) {
|
switch (importedSymbol.name) {
|
||||||
|
case 'ChangeDetectorRef':
|
||||||
|
resolved = R3ResolvedDependencyType.ChangeDetectorRef;
|
||||||
|
break;
|
||||||
case 'ElementRef':
|
case 'ElementRef':
|
||||||
resolved = R3ResolvedDependencyType.ElementRef;
|
resolved = R3ResolvedDependencyType.ElementRef;
|
||||||
break;
|
break;
|
||||||
|
|
|
@ -22,8 +22,15 @@ export const Injectable = callableClassDecorator();
|
||||||
export const NgModule = callableClassDecorator();
|
export const NgModule = callableClassDecorator();
|
||||||
export const Pipe = callableClassDecorator();
|
export const Pipe = callableClassDecorator();
|
||||||
|
|
||||||
|
export const Attribute = callableParamDecorator();
|
||||||
export const Inject = callableParamDecorator();
|
export const Inject = callableParamDecorator();
|
||||||
export const Self = callableParamDecorator();
|
export const Self = callableParamDecorator();
|
||||||
export const SkipSelf = callableParamDecorator();
|
export const SkipSelf = callableParamDecorator();
|
||||||
export const Optional = callableParamDecorator();
|
export const Optional = callableParamDecorator();
|
||||||
export type ModuleWithProviders<T> = any;
|
export type ModuleWithProviders<T> = any;
|
||||||
|
|
||||||
|
export class ChangeDetectorRef {}
|
||||||
|
export class ElementRef {}
|
||||||
|
export class Injector {}
|
||||||
|
export class TemplateRef {}
|
||||||
|
export class ViewContainerRef {}
|
|
@ -370,4 +370,42 @@ describe('ngtsc behavioral tests', () => {
|
||||||
expect(dtsContents).toContain(`import * as i1 from 'router';`);
|
expect(dtsContents).toContain(`import * as i1 from 'router';`);
|
||||||
expect(dtsContents).toContain('i0.ɵNgModuleDef<TestModule, [], [i1.RouterModule], []>');
|
expect(dtsContents).toContain('i0.ɵNgModuleDef<TestModule, [], [i1.RouterModule], []>');
|
||||||
});
|
});
|
||||||
|
|
||||||
|
it('should inject special types according to the metadata', () => {
|
||||||
|
writeConfig();
|
||||||
|
write(`test.ts`, `
|
||||||
|
import {
|
||||||
|
Attribute,
|
||||||
|
ChangeDetectorRef,
|
||||||
|
Component,
|
||||||
|
ElementRef,
|
||||||
|
Injector,
|
||||||
|
TemplateRef,
|
||||||
|
ViewContainerRef,
|
||||||
|
} from '@angular/core';
|
||||||
|
|
||||||
|
@Component({
|
||||||
|
selector: 'test',
|
||||||
|
template: 'Test',
|
||||||
|
})
|
||||||
|
class FooCmp {
|
||||||
|
constructor(
|
||||||
|
@Attribute("test") attr: string,
|
||||||
|
cdr: ChangeDetectorRef,
|
||||||
|
er: ElementRef,
|
||||||
|
i: Injector,
|
||||||
|
tr: TemplateRef,
|
||||||
|
vcr: ViewContainerRef,
|
||||||
|
) {}
|
||||||
|
}
|
||||||
|
`);
|
||||||
|
|
||||||
|
const exitCode = main(['-p', basePath], errorSpy);
|
||||||
|
expect(errorSpy).not.toHaveBeenCalled();
|
||||||
|
expect(exitCode).toBe(0);
|
||||||
|
const jsContents = getContents('test.js');
|
||||||
|
expect(jsContents)
|
||||||
|
.toContain(
|
||||||
|
`factory: function FooCmp_Factory() { return new FooCmp(i0.ɵinjectAttribute("test"), i0.ɵinjectChangeDetectorRef(), i0.ɵinjectElementRef(), i0.ɵdirectiveInject(i0.INJECTOR), i0.ɵinjectTemplateRef(), i0.ɵinjectViewContainerRef()); }`);
|
||||||
|
});
|
||||||
});
|
});
|
||||||
|
|
|
@ -106,6 +106,11 @@ export enum R3ResolvedDependencyType {
|
||||||
* The dependency is for `ViewContainerRef`.
|
* The dependency is for `ViewContainerRef`.
|
||||||
*/
|
*/
|
||||||
ViewContainerRef = 5,
|
ViewContainerRef = 5,
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The dependency is for `ChangeDetectorRef`.
|
||||||
|
*/
|
||||||
|
ChangeDetectorRef = 6,
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -182,7 +187,7 @@ function compileInjectDependency(
|
||||||
}
|
}
|
||||||
|
|
||||||
// Build up the arguments to the injectFn call.
|
// Build up the arguments to the injectFn call.
|
||||||
const injectArgs = [dep.token];
|
const injectArgs = [token];
|
||||||
// If this dependency is optional or otherwise has non-default flags, then additional
|
// If this dependency is optional or otherwise has non-default flags, then additional
|
||||||
// parameters describing how to inject the dependency must be passed to the inject function
|
// parameters describing how to inject the dependency must be passed to the inject function
|
||||||
// that's being used.
|
// that's being used.
|
||||||
|
@ -200,6 +205,8 @@ function compileInjectDependency(
|
||||||
return o.importExpr(R3.injectTemplateRef).callFn([]);
|
return o.importExpr(R3.injectTemplateRef).callFn([]);
|
||||||
case R3ResolvedDependencyType.ViewContainerRef:
|
case R3ResolvedDependencyType.ViewContainerRef:
|
||||||
return o.importExpr(R3.injectViewContainerRef).callFn([]);
|
return o.importExpr(R3.injectViewContainerRef).callFn([]);
|
||||||
|
case R3ResolvedDependencyType.ChangeDetectorRef:
|
||||||
|
return o.importExpr(R3.injectChangeDetectorRef).callFn([]);
|
||||||
default:
|
default:
|
||||||
return unsupported(
|
return unsupported(
|
||||||
`Unknown R3ResolvedDependencyType: ${R3ResolvedDependencyType[dep.resolved]}`);
|
`Unknown R3ResolvedDependencyType: ${R3ResolvedDependencyType[dep.resolved]}`);
|
||||||
|
|
|
@ -97,6 +97,9 @@ export class Identifiers {
|
||||||
static injectViewContainerRef:
|
static injectViewContainerRef:
|
||||||
o.ExternalReference = {name: 'ɵinjectViewContainerRef', moduleName: CORE};
|
o.ExternalReference = {name: 'ɵinjectViewContainerRef', moduleName: CORE};
|
||||||
|
|
||||||
|
static injectChangeDetectorRef:
|
||||||
|
o.ExternalReference = {name: 'ɵinjectChangeDetectorRef', moduleName: CORE};
|
||||||
|
|
||||||
static directiveInject: o.ExternalReference = {name: 'ɵdirectiveInject', moduleName: CORE};
|
static directiveInject: o.ExternalReference = {name: 'ɵdirectiveInject', moduleName: CORE};
|
||||||
|
|
||||||
static defineComponent: o.ExternalReference = {name: 'ɵdefineComponent', moduleName: CORE};
|
static defineComponent: o.ExternalReference = {name: 'ɵdefineComponent', moduleName: CORE};
|
||||||
|
|
Loading…
Reference in New Issue