diff --git a/goldens/public-api/core/errors.md b/goldens/public-api/core/errors.md index 72a4f0ee91a..25acf3a8037 100644 --- a/goldens/public-api/core/errors.md +++ b/goldens/public-api/core/errors.md @@ -61,6 +61,8 @@ export const enum RuntimeErrorCode { // (undocumented) PLATFORM_NOT_FOUND = 401, // (undocumented) + PROVIDER_IN_WRONG_CONTEXT = 207, + // (undocumented) PROVIDER_NOT_FOUND = -201, // (undocumented) RECURSIVE_APPLICATION_REF_TICK = 101, diff --git a/goldens/public-api/core/index.md b/goldens/public-api/core/index.md index 28a12ac688d..a26561a7b88 100644 --- a/goldens/public-api/core/index.md +++ b/goldens/public-api/core/index.md @@ -289,7 +289,7 @@ export interface ContentChildrenDecorator { } // @public -export function createEnvironmentInjector(providers: Provider[], parent?: EnvironmentInjector | null, debugName?: string | null): EnvironmentInjector; +export function createEnvironmentInjector(providers: Array, parent?: EnvironmentInjector | null, debugName?: string | null): EnvironmentInjector; // @public export function createNgModuleRef(ngModule: Type, parentInjector?: Injector): NgModuleRef; @@ -578,7 +578,13 @@ export interface HostListenerDecorator { } // @public -export function importProvidersFrom(...sources: ImportProvidersSource[]): Provider[]; +export interface ImportedNgModuleProviders { + // (undocumented) + ɵproviders: Provider[]; +} + +// @public +export function importProvidersFrom(...sources: ImportProvidersSource[]): ImportedNgModuleProviders; // @public export type ImportProvidersSource = Type | ModuleWithProviders | Array; diff --git a/goldens/public-api/platform-browser/index.md b/goldens/public-api/platform-browser/index.md index f377e715add..19976664592 100644 --- a/goldens/public-api/platform-browser/index.md +++ b/goldens/public-api/platform-browser/index.md @@ -10,6 +10,7 @@ import { DebugElement } from '@angular/core'; import { DebugNode } from '@angular/core'; import * as i0 from '@angular/core'; import * as i1 from '@angular/common'; +import { ImportedNgModuleProviders } from '@angular/core'; import { InjectionToken } from '@angular/core'; import { ModuleWithProviders } from '@angular/core'; import { NgZone } from '@angular/core'; @@ -24,7 +25,7 @@ import { Version } from '@angular/core'; // @public export interface ApplicationConfig { - providers: Provider[]; + providers: Array; } // @public diff --git a/goldens/public-api/platform-server/index.md b/goldens/public-api/platform-server/index.md index 04eb04af626..83965839557 100644 --- a/goldens/public-api/platform-server/index.md +++ b/goldens/public-api/platform-server/index.md @@ -8,6 +8,7 @@ import * as i0 from '@angular/core'; import * as i1 from '@angular/common/http'; import * as i2 from '@angular/platform-browser/animations'; import * as i3 from '@angular/platform-browser'; +import { ImportedNgModuleProviders } from '@angular/core'; import { InjectionToken } from '@angular/core'; import { NgModuleFactory } from '@angular/core'; import { PlatformRef } from '@angular/core'; @@ -52,7 +53,7 @@ export function renderApplication(rootComponent: Type, options: { appId: string; document?: string; url?: string; - providers?: Provider[]; + providers?: Array; platformProviders?: Provider[]; }): Promise; diff --git a/goldens/public-api/router/index.md b/goldens/public-api/router/index.md index 7bc5910d9a4..dcd37d85803 100644 --- a/goldens/public-api/router/index.md +++ b/goldens/public-api/router/index.md @@ -13,6 +13,7 @@ import { ElementRef } from '@angular/core'; import { EnvironmentInjector } from '@angular/core'; import { EventEmitter } from '@angular/core'; import * as i0 from '@angular/core'; +import { ImportedNgModuleProviders } from '@angular/core'; import { InjectionToken } from '@angular/core'; import { Injector } from '@angular/core'; import { Location as Location_2 } from '@angular/common'; @@ -456,7 +457,7 @@ export interface Route { outlet?: string; path?: string; pathMatch?: 'prefix' | 'full'; - providers?: Provider[]; + providers?: Array; redirectTo?: string; resolve?: ResolveData; runGuardsAndResolvers?: RunGuardsAndResolvers; diff --git a/packages/core/src/application_ref.ts b/packages/core/src/application_ref.ts index 8a50e34f106..a5cba8a357a 100644 --- a/packages/core/src/application_ref.ts +++ b/packages/core/src/application_ref.ts @@ -18,7 +18,7 @@ import {Console} from './console'; import {Injectable} from './di/injectable'; import {InjectionToken} from './di/injection_token'; import {Injector} from './di/injector'; -import {Provider, StaticProvider} from './di/interface/provider'; +import {ImportedNgModuleProviders, Provider, StaticProvider} from './di/interface/provider'; import {EnvironmentInjector} from './di/r3_injector'; import {INJECTOR_SCOPE} from './di/scope'; import {ErrorHandler} from './error_handler'; @@ -187,7 +187,7 @@ export function runPlatformInitializers(injector: Injector): void { */ export function bootstrapApplication(config: { rootComponent: Type, - appProviders?: Provider[], + appProviders?: Array, platformProviders?: Provider[], }): Promise { const {rootComponent, appProviders, platformProviders} = config; diff --git a/packages/core/src/di/create_injector.ts b/packages/core/src/di/create_injector.ts index 295acf7f227..68f96d214a4 100644 --- a/packages/core/src/di/create_injector.ts +++ b/packages/core/src/di/create_injector.ts @@ -40,8 +40,8 @@ export function createInjectorWithoutInjectorInstances( additionalProviders: StaticProvider[]|null = null, name?: string, scopes = new Set()): R3Injector { const providers = [ - ...flatten(additionalProviders || EMPTY_ARRAY), - ...importProvidersFrom(defType), + additionalProviders || EMPTY_ARRAY, + importProvidersFrom(defType), ]; name = name || (typeof defType === 'object' ? undefined : stringify(defType)); diff --git a/packages/core/src/di/index.ts b/packages/core/src/di/index.ts index b9bcfa02cf8..34a5d50df8d 100644 --- a/packages/core/src/di/index.ts +++ b/packages/core/src/di/index.ts @@ -25,7 +25,7 @@ export {ProviderToken} from './provider_token'; export {ɵɵinject, inject, ɵɵinvalidFactoryDep} from './injector_compatibility'; export {INJECTOR} from './injector_token'; export {ReflectiveInjector} from './reflective_injector'; -export {ClassProvider, ModuleWithProviders, ClassSansProvider, ConstructorProvider, ConstructorSansProvider, ExistingProvider, ExistingSansProvider, FactoryProvider, FactorySansProvider, Provider, StaticClassProvider, StaticClassSansProvider, StaticProvider, TypeProvider, ValueProvider, ValueSansProvider} from './interface/provider'; +export {ClassProvider, ModuleWithProviders, ClassSansProvider, ImportedNgModuleProviders, ConstructorProvider, ConstructorSansProvider, ExistingProvider, ExistingSansProvider, FactoryProvider, FactorySansProvider, Provider, StaticClassProvider, StaticClassSansProvider, StaticProvider, TypeProvider, ValueProvider, ValueSansProvider} from './interface/provider'; export {ResolvedReflectiveFactory, ResolvedReflectiveProvider} from './reflective_provider'; export {ReflectiveKey} from './reflective_key'; export {InjectionToken} from './injection_token'; diff --git a/packages/core/src/di/interface/provider.ts b/packages/core/src/di/interface/provider.ts index ccb362cda43..c58311e2953 100644 --- a/packages/core/src/di/interface/provider.ts +++ b/packages/core/src/di/interface/provider.ts @@ -351,3 +351,20 @@ export interface ModuleWithProviders { ngModule: Type; providers?: Provider[]; } + +/** + * Providers that were imported from NgModules via the `importProvidersFrom` function. + * + * These providers are meant for use in an application injector (or other environment injectors) and + * should not be used in component injectors. + * + * This type cannot be directly implemented. It's returned from the `importProvidersFrom` function + * and serves to prevent the extracted NgModule providers from being used in the wrong contexts. + * + * @see `importProvidersFrom` + * + * @publicApi + */ +export interface ImportedNgModuleProviders { + ɵproviders: Provider[]; +} diff --git a/packages/core/src/di/provider_collection.ts b/packages/core/src/di/provider_collection.ts index c99c3564dd4..21039d8a03b 100644 --- a/packages/core/src/di/provider_collection.ts +++ b/packages/core/src/di/provider_collection.ts @@ -19,7 +19,7 @@ import {resolveForwardRef} from './forward_ref'; import {ENVIRONMENT_INITIALIZER} from './initializer_token'; import {ɵɵinject as inject} from './injector_compatibility'; import {getInjectorDef, InjectorType, InjectorTypeWithProviders} from './interface/defs'; -import {ClassProvider, ConstructorProvider, ExistingProvider, FactoryProvider, ModuleWithProviders, Provider, StaticClassProvider, TypeProvider, ValueProvider} from './interface/provider'; +import {ClassProvider, ConstructorProvider, ExistingProvider, FactoryProvider, ImportedNgModuleProviders, ModuleWithProviders, Provider, StaticClassProvider, TypeProvider, ValueProvider} from './interface/provider'; import {INJECTOR_DEF_TYPES} from './internal_tokens'; /** @@ -34,10 +34,15 @@ export type ImportProvidersSource = * Collects providers from all NgModules and standalone components, including transitively imported * ones. * - * @returns The list of collected providers from the specified list of types. + * Providers extracted via `importProvidersFrom` are only usable in an application injector or + * another environment injector (such as a route injector). They should not be used in component + * providers. + * + * @returns The collected providers from the specified list of types. * @publicApi */ -export function importProvidersFrom(...sources: ImportProvidersSource[]): Provider[] { +export function importProvidersFrom(...sources: ImportProvidersSource[]): + ImportedNgModuleProviders { const providersOut: SingleProvider[] = []; const dedup = new Set>(); // already seen types let injectorTypesWithProviders: InjectorTypeWithProviders[]|undefined; @@ -53,7 +58,7 @@ export function importProvidersFrom(...sources: ImportProvidersSource[]): Provid if (injectorTypesWithProviders !== undefined) { processInjectorTypesWithProviders(injectorTypesWithProviders, providersOut); } - return providersOut; + return {ɵproviders: providersOut}; } /** diff --git a/packages/core/src/di/r3_injector.ts b/packages/core/src/di/r3_injector.ts index e5c0b818a0e..f8f7ec22861 100644 --- a/packages/core/src/di/r3_injector.ts +++ b/packages/core/src/di/r3_injector.ts @@ -14,7 +14,7 @@ import {Type} from '../interface/type'; import {getComponentDef} from '../render3/definition'; import {FactoryFn, getFactoryDef} from '../render3/definition_factory'; import {throwCyclicDependencyError, throwInvalidProviderError, throwMixedMultiProviderError} from '../render3/errors_di'; -import {deepForEach, flatten, newArray} from '../util/array_utils'; +import {newArray} from '../util/array_utils'; import {EMPTY_ARRAY} from '../util/empty'; import {stringify} from '../util/stringify'; @@ -27,7 +27,7 @@ import {catchInjectorError, injectArgs, NG_TEMP_TOKEN_PATH, setCurrentInjector, import {INJECTOR} from './injector_token'; import {getInheritedInjectableDef, getInjectableDef, InjectorType, ɵɵInjectableDeclaration} from './interface/defs'; import {InjectFlags} from './interface/injector'; -import {ClassProvider, ConstructorProvider, Provider, StaticClassProvider} from './interface/provider'; +import {ClassProvider, ConstructorProvider, ImportedNgModuleProviders, Provider, StaticClassProvider} from './interface/provider'; import {INJECTOR_DEF_TYPES} from './internal_tokens'; import {NullInjector} from './null_injector'; import {importProvidersFrom, isExistingProvider, isFactoryProvider, isTypeProvider, isValueProvider, SingleProvider} from './provider_collection'; @@ -121,13 +121,11 @@ export class R3Injector extends EnvironmentInjector { private injectorDefTypes: Set>; constructor( - providers: Provider[], readonly parent: Injector, readonly source: string|null, - readonly scopes: Set) { + providers: Array, readonly parent: Injector, + readonly source: string|null, readonly scopes: Set) { super(); // Start off by creating Records for every provider. - deepForEach(providers, provider => { - this.processProvider(provider as SingleProvider); - }); + forEachSingleProvider(providers, provider => this.processProvider(provider)); // Make sure the INJECTOR token provides this injector. this.records.set(INJECTOR, makeRecord(undefined, this)); @@ -403,6 +401,10 @@ function providerToRecord(provider: SingleProvider): Record { export function providerToFactory( provider: SingleProvider, ngModuleType?: InjectorType, providers?: any[]): () => any { let factory: (() => any)|undefined = undefined; + if (ngDevMode && isImportedNgModuleProviders(provider)) { + throwInvalidProviderError(undefined, providers, provider); + } + if (isTypeProvider(provider)) { const unwrappedProvider = resolveForwardRef(provider); return getFactoryDef(unwrappedProvider) || injectableDefOrInjectorDefFactory(unwrappedProvider); @@ -453,3 +455,22 @@ function couldBeInjectableType(value: any): value is ProviderToken { return (typeof value === 'function') || (typeof value === 'object' && value instanceof InjectionToken); } + +function isImportedNgModuleProviders(provider: Provider|ImportedNgModuleProviders): + provider is ImportedNgModuleProviders { + return !!(provider as ImportedNgModuleProviders).ɵproviders; +} + +function forEachSingleProvider( + providers: Array, + fn: (provider: SingleProvider) => void): void { + for (const provider of providers) { + if (Array.isArray(provider)) { + forEachSingleProvider(provider, fn); + } else if (isImportedNgModuleProviders(provider)) { + forEachSingleProvider(provider.ɵproviders, fn); + } else { + fn(provider); + } + } +} diff --git a/packages/core/src/errors.ts b/packages/core/src/errors.ts index 064fdf0ebe5..1f131be9baa 100644 --- a/packages/core/src/errors.ts +++ b/packages/core/src/errors.ts @@ -30,6 +30,7 @@ export const enum RuntimeErrorCode { MISSING_INJECTION_CONTEXT = 203, INVALID_INJECTION_TOKEN = 204, INJECTOR_ALREADY_DESTROYED = 205, + PROVIDER_IN_WRONG_CONTEXT = 207, // Template Errors MULTIPLE_COMPONENTS_MATCH = -300, diff --git a/packages/core/src/render3/errors_di.ts b/packages/core/src/render3/errors_di.ts index 590d4b275b7..71416fc42f6 100644 --- a/packages/core/src/render3/errors_di.ts +++ b/packages/core/src/render3/errors_di.ts @@ -6,6 +6,7 @@ * found in the LICENSE file at https://angular.io/license */ +import {ImportedNgModuleProviders} from '../di/interface/provider'; import {RuntimeError, RuntimeErrorCode} from '../errors'; import {Type} from '../interface/type'; import {stringify} from '../util/stringify'; @@ -26,16 +27,19 @@ export function throwMixedMultiProviderError() { } export function throwInvalidProviderError( - ngModuleType?: Type, providers?: any[], provider?: any) { - let ngModuleDetail = ''; + ngModuleType?: Type, providers?: any[], provider?: any): never { if (ngModuleType && providers) { const providerDetail = providers.map(v => v == provider ? '?' + provider + '?' : '...'); - ngModuleDetail = - ` - only instances of Provider and Type are allowed, got: [${providerDetail.join(', ')}]`; + throw new Error(`Invalid provider for the NgModule '${ + stringify(ngModuleType)}' - only instances of Provider and Type are allowed, got: [${ + providerDetail.join(', ')}]`); + } else if ((provider as ImportedNgModuleProviders).ɵproviders) { + throw new RuntimeError( + RuntimeErrorCode.PROVIDER_IN_WRONG_CONTEXT, + `Invalid providers from 'importProvidersFrom' present in a non-environment injector. 'importProvidersFrom' can't be used for component providers.`); + } else { + throw new Error('Invalid provider'); } - - throw new Error( - `Invalid provider for the NgModule '${stringify(ngModuleType)}'` + ngModuleDetail); } diff --git a/packages/core/src/render3/features/standalone_feature.ts b/packages/core/src/render3/features/standalone_feature.ts index 2f4527d27ae..6fed11b3ddc 100644 --- a/packages/core/src/render3/features/standalone_feature.ts +++ b/packages/core/src/render3/features/standalone_feature.ts @@ -30,9 +30,9 @@ class StandaloneService implements OnDestroy { if (!this.cachedInjectors.has(componentDef)) { const providers = importProvidersFrom(componentDef.type); - const standaloneInjector = providers.length > 0 ? + const standaloneInjector = providers.ɵproviders.length > 0 ? createEnvironmentInjector( - providers, this._injector, `Standalone[${componentDef.type.name}]`) : + [providers], this._injector, `Standalone[${componentDef.type.name}]`) : null; this.cachedInjectors.set(componentDef, standaloneInjector); } diff --git a/packages/core/src/render3/ng_module_ref.ts b/packages/core/src/render3/ng_module_ref.ts index 9deab7f9f5e..1a9986fc6c2 100644 --- a/packages/core/src/render3/ng_module_ref.ts +++ b/packages/core/src/render3/ng_module_ref.ts @@ -10,7 +10,7 @@ import {createInjectorWithoutInjectorInstances} from '../di/create_injector'; import {Injector} from '../di/injector'; import {INJECTOR} from '../di/injector_token'; import {InjectFlags} from '../di/interface/injector'; -import {Provider} from '../di/interface/provider'; +import {ImportedNgModuleProviders, Provider} from '../di/interface/provider'; import {EnvironmentInjector, getNullInjector, R3Injector} from '../di/r3_injector'; import {Type} from '../interface/type'; import {ComponentFactoryResolver as viewEngine_ComponentFactoryResolver} from '../linker/component_factory_resolver'; @@ -115,7 +115,9 @@ class EnvironmentNgModuleRefAdapter extends viewEngine_NgModuleRef { new ComponentFactoryResolver(this); override readonly instance = null; - constructor(providers: Provider[], parent: EnvironmentInjector|null, source: string|null) { + constructor( + providers: Array, parent: EnvironmentInjector|null, + source: string|null) { super(); const injector = new R3Injector( [ @@ -143,7 +145,7 @@ class EnvironmentNgModuleRefAdapter extends viewEngine_NgModuleRef { * @publicApi */ export function createEnvironmentInjector( - providers: Provider[], parent: EnvironmentInjector|null = null, + providers: Array, parent: EnvironmentInjector|null = null, debugName: string|null = null): EnvironmentInjector { const adapter = new EnvironmentNgModuleRefAdapter(providers, parent, debugName); return adapter.injector; diff --git a/packages/core/test/acceptance/di_spec.ts b/packages/core/test/acceptance/di_spec.ts index d8470093680..b2bd937f278 100644 --- a/packages/core/test/acceptance/di_spec.ts +++ b/packages/core/test/acceptance/di_spec.ts @@ -7,7 +7,7 @@ */ import {CommonModule} from '@angular/common'; -import {Attribute, ChangeDetectorRef, Component, ComponentFactoryResolver, ComponentRef, createEnvironmentInjector, Directive, ElementRef, ENVIRONMENT_INITIALIZER, EventEmitter, forwardRef, Host, HostBinding, importProvidersFrom, Inject, Injectable, InjectFlags, InjectionToken, INJECTOR, Injector, Input, LOCALE_ID, ModuleWithProviders, NgModule, NgZone, Optional, Output, Pipe, PipeTransform, Provider, Self, SkipSelf, TemplateRef, Type, ViewChild, ViewContainerRef, ViewRef, ɵcreateInjector as createInjector, ɵDEFAULT_LOCALE_ID as DEFAULT_LOCALE_ID, ɵINJECTOR_SCOPE} from '@angular/core'; +import {Attribute, ChangeDetectorRef, Component, ComponentFactoryResolver, ComponentRef, createEnvironmentInjector, Directive, ElementRef, ENVIRONMENT_INITIALIZER, EventEmitter, forwardRef, Host, HostBinding, ImportedNgModuleProviders, importProvidersFrom, ImportProvidersSource, Inject, Injectable, InjectFlags, InjectionToken, INJECTOR, Injector, Input, LOCALE_ID, ModuleWithProviders, NgModule, NgZone, Optional, Output, Pipe, PipeTransform, Provider, Self, SkipSelf, TemplateRef, Type, ViewChild, ViewContainerRef, ViewRef, ɵcreateInjector as createInjector, ɵDEFAULT_LOCALE_ID as DEFAULT_LOCALE_ID, ɵINJECTOR_SCOPE} from '@angular/core'; import {ViewRef as ViewRefInternal} from '@angular/core/src/render3/view_ref'; import {TestBed} from '@angular/core/testing'; import {By} from '@angular/platform-browser'; @@ -23,6 +23,10 @@ const hasProviderWithToken = (providers: Provider[], token: InjectionToken getProvidersByToken(providers, ENVIRONMENT_INITIALIZER); +function unwrappedImportProvidersFrom(...sources: ImportProvidersSource[]): Provider[] { + return importProvidersFrom(...sources).ɵproviders; +} + describe('importProvidersFrom', () => { // Set of tokens used in various tests. const A = new InjectionToken('A'); @@ -48,7 +52,7 @@ describe('importProvidersFrom', () => { }) class MyModule { } - const providers = importProvidersFrom(MyModule); + const providers = unwrappedImportProvidersFrom(MyModule); // 4 tokens (A, B, C, D) + 2 providers for each NgModule: // - the definition type itself @@ -70,7 +74,7 @@ describe('importProvidersFrom', () => { class Module { } - const providers = importProvidersFrom({ + const providers = unwrappedImportProvidersFrom({ ngModule: Module, providers: [{provide: A, useValue: 'A'}], }); @@ -97,7 +101,7 @@ describe('importProvidersFrom', () => { } } - const providers = importProvidersFrom(ModuleB.forRoot(), ModuleB.forChild()); + const providers = unwrappedImportProvidersFrom(ModuleB.forRoot(), ModuleB.forChild()); // Expect 2 `ENVIRONMENT_INITIALIZER` providers: one for `ModuleA`, another one for `ModuleB` expect(collectEnvironmentInitializerProviders(providers).length).toBe(2); @@ -127,7 +131,7 @@ describe('importProvidersFrom', () => { } } - const providers = importProvidersFrom(ModuleA.forRoot()); + const providers = unwrappedImportProvidersFrom(ModuleA.forRoot()); // Expect 1 `ENVIRONMENT_INITIALIZER` provider (for `ModuleA`) expect(collectEnvironmentInitializerProviders(providers).length).toBe(1); @@ -161,7 +165,7 @@ describe('importProvidersFrom', () => { class ModuleB { } - const providers = importProvidersFrom(ModuleB); + const providers = unwrappedImportProvidersFrom(ModuleB); // Expect 2 `ENVIRONMENT_INITIALIZER` providers: one for `ModuleA`, another one for `ModuleB` expect(collectEnvironmentInitializerProviders(providers).length).toBe(2); @@ -198,7 +202,7 @@ describe('importProvidersFrom', () => { } } - const providers = importProvidersFrom(ModuleA.forRoot()); + const providers = unwrappedImportProvidersFrom(ModuleA.forRoot()); // Expect all tokens to be collected. expect(hasProviderWithToken(providers, A)).toBe(true); @@ -214,6 +218,26 @@ describe('importProvidersFrom', () => { // Verify that a multi-provider has both values. expect(injector.get(D)).toEqual(['Original D', 'Extra D']); }); + + it('should not be allowed in component providers', () => { + @NgModule({}) + class Module { + } + + expect(() => { + @Component({ + selector: 'test-cmp', + template: '', + // The double array here is necessary to escape the compile-time error, via Provider's + // `any[]` option. + providers: [[importProvidersFrom(Module)]], + }) + class Cmp { + } + + TestBed.createComponent(Cmp); + }).toThrowError(/NG0207/); + }); }); describe('di', () => { diff --git a/packages/core/test/acceptance/env_injector_standalone_spec.ts b/packages/core/test/acceptance/env_injector_standalone_spec.ts index 937ba941ef6..dfa4248023d 100644 --- a/packages/core/test/acceptance/env_injector_standalone_spec.ts +++ b/packages/core/test/acceptance/env_injector_standalone_spec.ts @@ -20,7 +20,7 @@ describe('environement injector and standalone components', () => { class StandaloneComponent { } - const envInjector = createEnvironmentInjector(importProvidersFrom(StandaloneComponent)); + const envInjector = createEnvironmentInjector([importProvidersFrom(StandaloneComponent)]); expect(envInjector.get(ModuleService)).toBeInstanceOf(ModuleService); }); @@ -39,7 +39,7 @@ describe('environement injector and standalone components', () => { class AppModule { } - const envInjector = createEnvironmentInjector(importProvidersFrom(AppModule)); + const envInjector = createEnvironmentInjector([importProvidersFrom(AppModule)]); expect(envInjector.get(ModuleService)).toBeInstanceOf(ModuleService); }); @@ -65,7 +65,7 @@ describe('environement injector and standalone components', () => { class AppModule { } - const envInjector = createEnvironmentInjector(importProvidersFrom(AppModule)); + const envInjector = createEnvironmentInjector([importProvidersFrom(AppModule)]); const services = envInjector.get(ModuleService) as ModuleService[]; expect(services.length).toBe(1); diff --git a/packages/core/test/bundling/animations/bundle.golden_symbols.json b/packages/core/test/bundling/animations/bundle.golden_symbols.json index ca1e0f0b050..631b50b3050 100644 --- a/packages/core/test/bundling/animations/bundle.golden_symbols.json +++ b/packages/core/test/bundling/animations/bundle.golden_symbols.json @@ -767,15 +767,15 @@ { "name": "findAttrIndexInNode" }, - { - "name": "flatten" - }, { "name": "flattenStyles" }, { "name": "flattenUnsubscriptionErrors" }, + { + "name": "forEachSingleProvider" + }, { "name": "forwardRef" }, @@ -1007,6 +1007,9 @@ { "name": "isFunction" }, + { + "name": "isImportedNgModuleProviders" + }, { "name": "isInCheckNoChangesMode" }, diff --git a/packages/core/test/bundling/forms_reactive/bundle.golden_symbols.json b/packages/core/test/bundling/forms_reactive/bundle.golden_symbols.json index d52696c6f98..e191b4ff257 100644 --- a/packages/core/test/bundling/forms_reactive/bundle.golden_symbols.json +++ b/packages/core/test/bundling/forms_reactive/bundle.golden_symbols.json @@ -791,15 +791,15 @@ { "name": "findStylingValue" }, - { - "name": "flatten" - }, { "name": "flattenStyles" }, { "name": "flattenUnsubscriptionErrors" }, + { + "name": "forEachSingleProvider" + }, { "name": "forkJoinInternal" }, @@ -1109,6 +1109,9 @@ { "name": "isFunction" }, + { + "name": "isImportedNgModuleProviders" + }, { "name": "isInCheckNoChangesMode" }, diff --git a/packages/core/test/bundling/forms_template_driven/bundle.golden_symbols.json b/packages/core/test/bundling/forms_template_driven/bundle.golden_symbols.json index 5a2d70d927e..938fad62f62 100644 --- a/packages/core/test/bundling/forms_template_driven/bundle.golden_symbols.json +++ b/packages/core/test/bundling/forms_template_driven/bundle.golden_symbols.json @@ -764,15 +764,15 @@ { "name": "findStylingValue" }, - { - "name": "flatten" - }, { "name": "flattenStyles" }, { "name": "flattenUnsubscriptionErrors" }, + { + "name": "forEachSingleProvider" + }, { "name": "forkJoinInternal" }, @@ -1073,6 +1073,9 @@ { "name": "isFunction" }, + { + "name": "isImportedNgModuleProviders" + }, { "name": "isInCheckNoChangesMode" }, diff --git a/packages/core/test/bundling/injection/bundle.golden_symbols.json b/packages/core/test/bundling/injection/bundle.golden_symbols.json index aa0ad446e31..3dc42c82503 100644 --- a/packages/core/test/bundling/injection/bundle.golden_symbols.json +++ b/packages/core/test/bundling/injection/bundle.golden_symbols.json @@ -84,7 +84,7 @@ "name": "deepForEach" }, { - "name": "flatten" + "name": "forEachSingleProvider" }, { "name": "forwardRef" @@ -122,6 +122,9 @@ { "name": "injectableDefOrInjectorDefFactory" }, + { + "name": "isImportedNgModuleProviders" + }, { "name": "isTypeProvider" }, diff --git a/packages/core/test/bundling/router/bundle.golden_symbols.json b/packages/core/test/bundling/router/bundle.golden_symbols.json index 431966b1aff..620486094b7 100644 --- a/packages/core/test/bundling/router/bundle.golden_symbols.json +++ b/packages/core/test/bundling/router/bundle.golden_symbols.json @@ -1118,6 +1118,9 @@ { "name": "forEach" }, + { + "name": "forEachSingleProvider" + }, { "name": "forwardRef" }, @@ -1448,6 +1451,9 @@ { "name": "isImmediateMatch" }, + { + "name": "isImportedNgModuleProviders" + }, { "name": "isInCheckNoChangesMode" }, diff --git a/packages/core/test/bundling/standalone_bootstrap/bundle.golden_symbols.json b/packages/core/test/bundling/standalone_bootstrap/bundle.golden_symbols.json index 0d1fe2792fa..6df6ee3cebf 100644 --- a/packages/core/test/bundling/standalone_bootstrap/bundle.golden_symbols.json +++ b/packages/core/test/bundling/standalone_bootstrap/bundle.golden_symbols.json @@ -485,15 +485,15 @@ { "name": "extractDirectiveDef" }, - { - "name": "flatten" - }, { "name": "flattenStyles" }, { "name": "flattenUnsubscriptionErrors" }, + { + "name": "forEachSingleProvider" + }, { "name": "forwardRef" }, @@ -650,6 +650,9 @@ { "name": "isFunction" }, + { + "name": "isImportedNgModuleProviders" + }, { "name": "isInCheckNoChangesMode" }, diff --git a/packages/platform-browser/src/browser.ts b/packages/platform-browser/src/browser.ts index 59639a7b851..795121062d5 100644 --- a/packages/platform-browser/src/browser.ts +++ b/packages/platform-browser/src/browser.ts @@ -7,7 +7,7 @@ */ import {CommonModule, DOCUMENT, XhrFactory, ɵPLATFORM_BROWSER_ID as PLATFORM_BROWSER_ID} from '@angular/common'; -import {APP_ID, ApplicationModule, ApplicationRef, createPlatformFactory, ErrorHandler, Inject, ModuleWithProviders, NgModule, NgZone, Optional, PLATFORM_ID, PLATFORM_INITIALIZER, platformCore, PlatformRef, Provider, RendererFactory2, SkipSelf, StaticProvider, Testability, Type, ɵbootstrapApplication as _bootstrapApplication, ɵINJECTOR_SCOPE as INJECTOR_SCOPE, ɵsetDocument} from '@angular/core'; +import {APP_ID, ApplicationModule, ApplicationRef, createPlatformFactory, ErrorHandler, ImportedNgModuleProviders, Inject, ModuleWithProviders, NgModule, NgZone, Optional, PLATFORM_ID, PLATFORM_INITIALIZER, platformCore, PlatformRef, Provider, RendererFactory2, SkipSelf, StaticProvider, Testability, Type, ɵbootstrapApplication as _bootstrapApplication, ɵINJECTOR_SCOPE as INJECTOR_SCOPE, ɵsetDocument} from '@angular/core'; import {BrowserDomAdapter} from './browser/browser_adapter'; import {SERVER_TRANSITION_PROVIDERS, TRANSITION_ID} from './browser/server-transition'; @@ -28,7 +28,7 @@ export interface ApplicationConfig { /** * List of providers that should be available to the root component and all its children. */ - providers: Provider[]; + providers: Array; } /** diff --git a/packages/platform-server/src/utils.ts b/packages/platform-server/src/utils.ts index 49101d3f4d4..e7d01020a2c 100644 --- a/packages/platform-server/src/utils.ts +++ b/packages/platform-server/src/utils.ts @@ -6,7 +6,7 @@ * found in the LICENSE file at https://angular.io/license */ -import {ApplicationRef, importProvidersFrom, Injector, NgModuleFactory, NgModuleRef, PlatformRef, Provider, StaticProvider, Type, ɵbootstrapApplication as bootstrapApplication, ɵisPromise} from '@angular/core'; +import {ApplicationRef, ImportedNgModuleProviders, importProvidersFrom, Injector, NgModuleFactory, NgModuleRef, PlatformRef, Provider, StaticProvider, Type, ɵbootstrapApplication as bootstrapApplication, ɵisPromise} from '@angular/core'; import {BrowserModule, ɵTRANSITION_ID} from '@angular/platform-browser'; import {first} from 'rxjs/operators'; @@ -141,14 +141,14 @@ export function renderApplication(rootComponent: Type, options: { appId: string, document?: string, url?: string, - providers?: Provider[], + providers?: Array, platformProviders?: Provider[], }): Promise { const {document, url, platformProviders, appId} = options; const platform = _getPlatform(platformDynamicServer, {document, url, platformProviders}); const appProviders = [ - ...importProvidersFrom(BrowserModule.withServerTransition({appId})), - ...importProvidersFrom(ServerModule), + importProvidersFrom(BrowserModule.withServerTransition({appId})), + importProvidersFrom(ServerModule), ...(options.providers ?? []), ]; return _render(platform, bootstrapApplication({rootComponent, appProviders})); diff --git a/packages/router/src/models.ts b/packages/router/src/models.ts index 12530b9af08..3415da7f6eb 100644 --- a/packages/router/src/models.ts +++ b/packages/router/src/models.ts @@ -6,7 +6,7 @@ * found in the LICENSE file at https://angular.io/license */ -import {EnvironmentInjector, NgModuleFactory, Provider, Type} from '@angular/core'; +import {EnvironmentInjector, ImportedNgModuleProviders, NgModuleFactory, Provider, Type} from '@angular/core'; import {Observable} from 'rxjs'; import {ActivatedRouteSnapshot, RouterStateSnapshot} from './router_state'; @@ -508,7 +508,7 @@ export interface Route { * route also has a `loadChildren` function which returns an `NgModuleRef`, this injector will be * used as the parent of the lazy loaded module. */ - providers?: Provider[]; + providers?: Array; /** * Injector created from the static route providers