fix(core): get root and platform injector providers in special cases (#52365)

Previously, because the platform injector does not have a provider container, this API would fail. Now, we account for this case specifically by returning the found providers immediately, without trying to calculate their importpaths.

Also previously, in the case where a boostrapped standalone component did not import any feature modules, the environment injector connected to that bootstrapped component would be the root injector configured by `bootstrapApplication`. This injector is configured through a `providers` array instead of an `imports` array, and also does not have a provider container. Similarly to the platform case, we account this for this by returning the found providers immediately if there is no provider container for our standalone component.

PR Close #52365
This commit is contained in:
AleksanderBodurri
2023-10-25 02:20:46 -04:00
committed by Dylan Hunn
parent 54ea3b65c3
commit 78533324dc
@@ -151,6 +151,12 @@ function getProviderImportsContainer(injector: Injector): Type<unknown>|null {
return null;
}
// In standalone applications, the root environment injector created by bootstrapApplication
// may have no associated "instance".
if (defTypeRef.instance === null) {
return null;
}
return defTypeRef.instance.constructor;
}
@@ -351,13 +357,29 @@ function walkProviderTreeToDiscoverImportPaths(
* @returns an array of objects representing the providers of the given injector
*/
function getEnvironmentInjectorProviders(injector: EnvironmentInjector): ProviderRecord[] {
const providerRecords = getFrameworkDIDebugData().resolverToProviders.get(injector) ?? [];
// platform injector has no provider imports container so can we skip trying to
// find import paths
if (isPlatformInjector(injector)) {
return providerRecords;
}
const providerImportsContainer = getProviderImportsContainer(injector);
if (providerImportsContainer === null) {
// There is a special case where the bootstrapped component does not
// import any NgModules. In this case the environment injector connected to
// that component is the root injector, which does not have a provider imports
// container (and thus no concept of module import paths). Therefore we simply
// return the provider records as is.
if (isRootInjector(injector)) {
return providerRecords;
}
throwError('Could not determine where injector providers were configured.');
}
const providerToPath = getProviderImportPaths(providerImportsContainer);
const providerRecords = getFrameworkDIDebugData().resolverToProviders.get(injector) ?? [];
return providerRecords.map(providerRecord => {
let importPath = providerToPath.get(providerRecord.provider) ?? [providerImportsContainer];
@@ -374,6 +396,14 @@ function getEnvironmentInjectorProviders(injector: EnvironmentInjector): Provide
});
}
function isPlatformInjector(injector: Injector) {
return injector instanceof R3Injector && injector.scopes.has('platform');
}
function isRootInjector(injector: Injector) {
return injector instanceof R3Injector && injector.scopes.has('root');
}
/**
* Gets the providers configured on an injector.
*