@angular/core
Version:
Angular - the core framework
1,153 lines • 109 kB
JavaScript
/**
* @fileoverview added by tsickle
* @suppress {checkTypes,extraRequire,missingOverride,missingReturn,unusedPrivateMembers,uselessCode} checked by tsc
*/
import * as tslib_1 from "tslib";
/**
* @license
* Copyright Google Inc. All Rights Reserved.
*
* Use of this source code is governed by an MIT-style license that can be
* found in the LICENSE file at https://angular.io/license
*/
import { ResourceLoader } from '@angular/compiler';
import { ApplicationInitStatus, COMPILER_OPTIONS, Compiler, LOCALE_ID, ModuleWithComponentFactories, NgZone, ɵDEFAULT_LOCALE_ID as DEFAULT_LOCALE_ID, ɵNG_COMPONENT_DEF as NG_COMPONENT_DEF, ɵNG_DIRECTIVE_DEF as NG_DIRECTIVE_DEF, ɵNG_INJECTOR_DEF as NG_INJECTOR_DEF, ɵNG_MODULE_DEF as NG_MODULE_DEF, ɵNG_PIPE_DEF as NG_PIPE_DEF, ɵNgModuleFactory as R3NgModuleFactory, ɵRender3ComponentFactory as ComponentFactory, ɵRender3NgModuleRef as NgModuleRef, ɵcompileComponent as compileComponent, ɵcompileDirective as compileDirective, ɵcompileNgModuleDefs as compileNgModuleDefs, ɵcompilePipe as compilePipe, ɵgetInjectableDef as getInjectableDef, ɵpatchComponentDefWithScope as patchComponentDefWithScope, ɵsetLocaleId as setLocaleId, ɵtransitiveScopesFor as transitiveScopesFor } from '@angular/core';
import { clearResolutionOfComponentResourcesQueue, isComponentDefPendingResolution, resolveComponentResources, restoreComponentResolutionQueue } from '../../src/metadata/resource_loading';
import { ComponentResolver, DirectiveResolver, NgModuleResolver, PipeResolver } from './resolvers';
/** @enum {number} */
const TestingModuleOverride = {
DECLARATION: 0,
OVERRIDE_TEMPLATE: 1,
};
TestingModuleOverride[TestingModuleOverride.DECLARATION] = 'DECLARATION';
TestingModuleOverride[TestingModuleOverride.OVERRIDE_TEMPLATE] = 'OVERRIDE_TEMPLATE';
/**
* @param {?} value
* @return {?}
*/
function isTestingModuleOverride(value) {
return value === TestingModuleOverride.DECLARATION ||
value === TestingModuleOverride.OVERRIDE_TEMPLATE;
}
/**
* @record
*/
function CleanupOperation() { }
if (false) {
/** @type {?} */
CleanupOperation.prototype.field;
/** @type {?} */
CleanupOperation.prototype.def;
/** @type {?} */
CleanupOperation.prototype.original;
}
export class R3TestBedCompiler {
/**
* @param {?} platform
* @param {?} additionalModuleTypes
*/
constructor(platform, additionalModuleTypes) {
this.platform = platform;
this.additionalModuleTypes = additionalModuleTypes;
this.originalComponentResolutionQueue = null;
// Testing module configuration
this.declarations = [];
this.imports = [];
this.providers = [];
this.schemas = [];
// Queues of components/directives/pipes that should be recompiled.
this.pendingComponents = new Set();
this.pendingDirectives = new Set();
this.pendingPipes = new Set();
// Keep track of all components and directives, so we can patch Providers onto defs later.
this.seenComponents = new Set();
this.seenDirectives = new Set();
// Store resolved styles for Components that have template overrides present and `styleUrls`
// defined at the same time.
this.existingComponentStyles = new Map();
this.resolvers = initResolvers();
this.componentToModuleScope = new Map();
// Map that keeps initial version of component/directive/pipe defs in case
// we compile a Type again, thus overriding respective static fields. This is
// required to make sure we restore defs to their initial states between test runs
// TODO: we should support the case with multiple defs on a type
this.initialNgDefs = new Map();
// Array that keeps cleanup operations for initial versions of component/directive/pipe/module
// defs in case TestBed makes changes to the originals.
this.defCleanupOps = [];
this._injector = null;
this.compilerProviders = null;
this.providerOverrides = [];
this.rootProviderOverrides = [];
this.providerOverridesByToken = new Map();
this.moduleProvidersOverridden = new Set();
this.testModuleRef = null;
class DynamicTestModule {
}
this.testModuleType = (/** @type {?} */ (DynamicTestModule));
}
/**
* @param {?} providers
* @return {?}
*/
setCompilerProviders(providers) {
this.compilerProviders = providers;
this._injector = null;
}
/**
* @param {?} moduleDef
* @return {?}
*/
configureTestingModule(moduleDef) {
// Enqueue any compilation tasks for the directly declared component.
if (moduleDef.declarations !== undefined) {
this.queueTypeArray(moduleDef.declarations, TestingModuleOverride.DECLARATION);
this.declarations.push(...moduleDef.declarations);
}
// Enqueue any compilation tasks for imported modules.
if (moduleDef.imports !== undefined) {
this.queueTypesFromModulesArray(moduleDef.imports);
this.imports.push(...moduleDef.imports);
}
if (moduleDef.providers !== undefined) {
this.providers.push(...moduleDef.providers);
}
if (moduleDef.schemas !== undefined) {
this.schemas.push(...moduleDef.schemas);
}
}
/**
* @param {?} ngModule
* @param {?} override
* @return {?}
*/
overrideModule(ngModule, override) {
// Compile the module right away.
this.resolvers.module.addOverride(ngModule, override);
/** @type {?} */
const metadata = this.resolvers.module.resolve(ngModule);
if (metadata === null) {
throw new Error(`${ngModule.name} is not an @NgModule or is missing metadata`);
}
this.recompileNgModule(ngModule);
// At this point, the module has a valid .ngModuleDef, but the override may have introduced
// new declarations or imported modules. Ingest any possible new types and add them to the
// current queue.
this.queueTypesFromModulesArray([ngModule]);
}
/**
* @param {?} component
* @param {?} override
* @return {?}
*/
overrideComponent(component, override) {
this.resolvers.component.addOverride(component, override);
this.pendingComponents.add(component);
}
/**
* @param {?} directive
* @param {?} override
* @return {?}
*/
overrideDirective(directive, override) {
this.resolvers.directive.addOverride(directive, override);
this.pendingDirectives.add(directive);
}
/**
* @param {?} pipe
* @param {?} override
* @return {?}
*/
overridePipe(pipe, override) {
this.resolvers.pipe.addOverride(pipe, override);
this.pendingPipes.add(pipe);
}
/**
* @param {?} token
* @param {?} provider
* @return {?}
*/
overrideProvider(token, provider) {
/** @type {?} */
const providerDef = provider.useFactory ?
{
provide: token,
useFactory: provider.useFactory,
deps: provider.deps || [],
multi: provider.multi,
} :
{ provide: token, useValue: provider.useValue, multi: provider.multi };
/** @type {?} */
let injectableDef;
/** @type {?} */
const isRoot = (typeof token !== 'string' && (injectableDef = getInjectableDef(token)) &&
injectableDef.providedIn === 'root');
/** @type {?} */
const overridesBucket = isRoot ? this.rootProviderOverrides : this.providerOverrides;
overridesBucket.push(providerDef);
// Keep overrides grouped by token as well for fast lookups using token
this.providerOverridesByToken.set(token, providerDef);
}
/**
* @param {?} type
* @param {?} template
* @return {?}
*/
overrideTemplateUsingTestingModule(type, template) {
/** @type {?} */
const def = ((/** @type {?} */ (type)))[NG_COMPONENT_DEF];
/** @type {?} */
const hasStyleUrls = (/**
* @return {?}
*/
() => {
/** @type {?} */
const metadata = (/** @type {?} */ ((/** @type {?} */ (this.resolvers.component.resolve(type)))));
return !!metadata.styleUrls && metadata.styleUrls.length > 0;
});
/** @type {?} */
const overrideStyleUrls = !!def && !isComponentDefPendingResolution(type) && hasStyleUrls();
// In Ivy, compiling a component does not require knowing the module providing the
// component's scope, so overrideTemplateUsingTestingModule can be implemented purely via
// overrideComponent. Important: overriding template requires full Component re-compilation,
// which may fail in case styleUrls are also present (thus Component is considered as required
// resolution). In order to avoid this, we preemptively set styleUrls to an empty array,
// preserve current styles available on Component def and restore styles back once compilation
// is complete.
/** @type {?} */
const override = overrideStyleUrls ? { template, styles: [], styleUrls: [] } : { template };
this.overrideComponent(type, { set: override });
if (overrideStyleUrls && def.styles && def.styles.length > 0) {
this.existingComponentStyles.set(type, def.styles);
}
// Set the component's scope to be the testing module.
this.componentToModuleScope.set(type, TestingModuleOverride.OVERRIDE_TEMPLATE);
}
/**
* @return {?}
*/
compileComponents() {
return tslib_1.__awaiter(this, void 0, void 0, function* () {
this.clearComponentResolutionQueue();
// Run compilers for all queued types.
/** @type {?} */
let needsAsyncResources = this.compileTypesSync();
// compileComponents() should not be async unless it needs to be.
if (needsAsyncResources) {
/** @type {?} */
let resourceLoader;
/** @type {?} */
let resolver = (/**
* @param {?} url
* @return {?}
*/
(url) => {
if (!resourceLoader) {
resourceLoader = this.injector.get(ResourceLoader);
}
return Promise.resolve(resourceLoader.get(url));
});
yield resolveComponentResources(resolver);
}
});
}
/**
* @return {?}
*/
finalize() {
// One last compile
this.compileTypesSync();
// Create the testing module itself.
this.compileTestModule();
this.applyTransitiveScopes();
this.applyProviderOverrides();
// Patch previously stored `styles` Component values (taken from ngComponentDef), in case these
// Components have `styleUrls` fields defined and template override was requested.
this.patchComponentsWithExistingStyles();
// Clear the componentToModuleScope map, so that future compilations don't reset the scope of
// every component.
this.componentToModuleScope.clear();
/** @type {?} */
const parentInjector = this.platform.injector;
this.testModuleRef = new NgModuleRef(this.testModuleType, parentInjector);
// Set the locale ID, it can be overridden for the tests
/** @type {?} */
const localeId = this.testModuleRef.injector.get(LOCALE_ID, DEFAULT_LOCALE_ID);
setLocaleId(localeId);
// ApplicationInitStatus.runInitializers() is marked @internal to core.
// Cast it to any before accessing it.
((/** @type {?} */ (this.testModuleRef.injector.get(ApplicationInitStatus)))).runInitializers();
return this.testModuleRef;
}
/**
* \@internal
* @param {?} moduleType
* @return {?}
*/
_compileNgModuleSync(moduleType) {
this.queueTypesFromModulesArray([moduleType]);
this.compileTypesSync();
this.applyProviderOverrides();
this.applyProviderOverridesToModule(moduleType);
this.applyTransitiveScopes();
}
/**
* \@internal
* @param {?} moduleType
* @return {?}
*/
_compileNgModuleAsync(moduleType) {
return tslib_1.__awaiter(this, void 0, void 0, function* () {
this.queueTypesFromModulesArray([moduleType]);
yield this.compileComponents();
this.applyProviderOverrides();
this.applyProviderOverridesToModule(moduleType);
this.applyTransitiveScopes();
});
}
/**
* \@internal
* @return {?}
*/
_getModuleResolver() { return this.resolvers.module; }
/**
* \@internal
* @param {?} moduleType
* @return {?}
*/
_getComponentFactories(moduleType) {
return maybeUnwrapFn(moduleType.ngModuleDef.declarations).reduce((/**
* @param {?} factories
* @param {?} declaration
* @return {?}
*/
(factories, declaration) => {
/** @nocollapse @type {?} */
const componentDef = ((/** @type {?} */ (declaration))).ngComponentDef;
componentDef && factories.push(new ComponentFactory(componentDef, (/** @type {?} */ (this.testModuleRef))));
return factories;
}), (/** @type {?} */ ([])));
}
/**
* @private
* @return {?}
*/
compileTypesSync() {
// Compile all queued components, directives, pipes.
/** @type {?} */
let needsAsyncResources = false;
this.pendingComponents.forEach((/**
* @param {?} declaration
* @return {?}
*/
declaration => {
needsAsyncResources = needsAsyncResources || isComponentDefPendingResolution(declaration);
/** @type {?} */
const metadata = (/** @type {?} */ (this.resolvers.component.resolve(declaration)));
this.maybeStoreNgDef(NG_COMPONENT_DEF, declaration);
compileComponent(declaration, metadata);
}));
this.pendingComponents.clear();
this.pendingDirectives.forEach((/**
* @param {?} declaration
* @return {?}
*/
declaration => {
/** @type {?} */
const metadata = (/** @type {?} */ (this.resolvers.directive.resolve(declaration)));
this.maybeStoreNgDef(NG_DIRECTIVE_DEF, declaration);
compileDirective(declaration, metadata);
}));
this.pendingDirectives.clear();
this.pendingPipes.forEach((/**
* @param {?} declaration
* @return {?}
*/
declaration => {
/** @type {?} */
const metadata = (/** @type {?} */ (this.resolvers.pipe.resolve(declaration)));
this.maybeStoreNgDef(NG_PIPE_DEF, declaration);
compilePipe(declaration, metadata);
}));
this.pendingPipes.clear();
return needsAsyncResources;
}
/**
* @private
* @return {?}
*/
applyTransitiveScopes() {
/** @type {?} */
const moduleToScope = new Map();
/** @type {?} */
const getScopeOfModule = (/**
* @param {?} moduleType
* @return {?}
*/
(moduleType) => {
if (!moduleToScope.has(moduleType)) {
/** @type {?} */
const realType = isTestingModuleOverride(moduleType) ? this.testModuleType : moduleType;
moduleToScope.set(moduleType, transitiveScopesFor(realType));
}
return (/** @type {?} */ (moduleToScope.get(moduleType)));
});
this.componentToModuleScope.forEach((/**
* @param {?} moduleType
* @param {?} componentType
* @return {?}
*/
(moduleType, componentType) => {
/** @type {?} */
const moduleScope = getScopeOfModule(moduleType);
this.storeFieldOfDefOnType(componentType, NG_COMPONENT_DEF, 'directiveDefs');
this.storeFieldOfDefOnType(componentType, NG_COMPONENT_DEF, 'pipeDefs');
patchComponentDefWithScope(((/** @type {?} */ (componentType))).ngComponentDef, moduleScope);
}));
this.componentToModuleScope.clear();
}
/**
* @private
* @return {?}
*/
applyProviderOverrides() {
/** @type {?} */
const maybeApplyOverrides = (/**
* @param {?} field
* @return {?}
*/
(field) => (/**
* @param {?} type
* @return {?}
*/
(type) => {
/** @type {?} */
const resolver = field === NG_COMPONENT_DEF ? this.resolvers.component : this.resolvers.directive;
/** @type {?} */
const metadata = (/** @type {?} */ (resolver.resolve(type)));
if (this.hasProviderOverrides(metadata.providers)) {
this.patchDefWithProviderOverrides(type, field);
}
}));
this.seenComponents.forEach(maybeApplyOverrides(NG_COMPONENT_DEF));
this.seenDirectives.forEach(maybeApplyOverrides(NG_DIRECTIVE_DEF));
this.seenComponents.clear();
this.seenDirectives.clear();
}
/**
* @private
* @param {?} moduleType
* @return {?}
*/
applyProviderOverridesToModule(moduleType) {
if (this.moduleProvidersOverridden.has(moduleType)) {
return;
}
this.moduleProvidersOverridden.add(moduleType);
/** @type {?} */
const injectorDef = ((/** @type {?} */ (moduleType)))[NG_INJECTOR_DEF];
if (this.providerOverridesByToken.size > 0) {
if (this.hasProviderOverrides(injectorDef.providers)) {
this.maybeStoreNgDef(NG_INJECTOR_DEF, moduleType);
this.storeFieldOfDefOnType(moduleType, NG_INJECTOR_DEF, 'providers');
injectorDef.providers = this.getOverriddenProviders(injectorDef.providers);
}
// Apply provider overrides to imported modules recursively
/** @type {?} */
const moduleDef = ((/** @type {?} */ (moduleType)))[NG_MODULE_DEF];
for (const importType of moduleDef.imports) {
this.applyProviderOverridesToModule(importType);
}
}
}
/**
* @private
* @return {?}
*/
patchComponentsWithExistingStyles() {
this.existingComponentStyles.forEach((/**
* @param {?} styles
* @param {?} type
* @return {?}
*/
(styles, type) => ((/** @type {?} */ (type)))[NG_COMPONENT_DEF].styles = styles));
this.existingComponentStyles.clear();
}
/**
* @private
* @param {?} arr
* @param {?} moduleType
* @return {?}
*/
queueTypeArray(arr, moduleType) {
for (const value of arr) {
if (Array.isArray(value)) {
this.queueTypeArray(value, moduleType);
}
else {
this.queueType(value, moduleType);
}
}
}
/**
* @private
* @param {?} ngModule
* @return {?}
*/
recompileNgModule(ngModule) {
/** @type {?} */
const metadata = this.resolvers.module.resolve(ngModule);
if (metadata === null) {
throw new Error(`Unable to resolve metadata for NgModule: ${ngModule.name}`);
}
// Cache the initial ngModuleDef as it will be overwritten.
this.maybeStoreNgDef(NG_MODULE_DEF, ngModule);
this.maybeStoreNgDef(NG_INJECTOR_DEF, ngModule);
compileNgModuleDefs((/** @type {?} */ (ngModule)), metadata);
}
/**
* @private
* @param {?} type
* @param {?} moduleType
* @return {?}
*/
queueType(type, moduleType) {
/** @type {?} */
const component = this.resolvers.component.resolve(type);
if (component) {
// Check whether a give Type has respective NG def (ngComponentDef) and compile if def is
// missing. That might happen in case a class without any Angular decorators extends another
// class where Component/Directive/Pipe decorator is defined.
if (isComponentDefPendingResolution(type) || !type.hasOwnProperty(NG_COMPONENT_DEF)) {
this.pendingComponents.add(type);
}
this.seenComponents.add(type);
// Keep track of the module which declares this component, so later the component's scope
// can be set correctly. If the component has already been recorded here, then one of several
// cases is true:
// * the module containing the component was imported multiple times (common).
// * the component is declared in multiple modules (which is an error).
// * the component was in 'declarations' of the testing module, and also in an imported module
// in which case the module scope will be TestingModuleOverride.DECLARATION.
// * overrideTemplateUsingTestingModule was called for the component in which case the module
// scope will be TestingModuleOverride.OVERRIDE_TEMPLATE.
//
// If the component was previously in the testing module's 'declarations' (meaning the
// current value is TestingModuleOverride.DECLARATION), then `moduleType` is the component's
// real module, which was imported. This pattern is understood to mean that the component
// should use its original scope, but that the testing module should also contain the
// component in its scope.
if (!this.componentToModuleScope.has(type) ||
this.componentToModuleScope.get(type) === TestingModuleOverride.DECLARATION) {
this.componentToModuleScope.set(type, moduleType);
}
return;
}
/** @type {?} */
const directive = this.resolvers.directive.resolve(type);
if (directive) {
if (!type.hasOwnProperty(NG_DIRECTIVE_DEF)) {
this.pendingDirectives.add(type);
}
this.seenDirectives.add(type);
return;
}
/** @type {?} */
const pipe = this.resolvers.pipe.resolve(type);
if (pipe && !type.hasOwnProperty(NG_PIPE_DEF)) {
this.pendingPipes.add(type);
return;
}
}
/**
* @private
* @param {?} arr
* @return {?}
*/
queueTypesFromModulesArray(arr) {
for (const value of arr) {
if (Array.isArray(value)) {
this.queueTypesFromModulesArray(value);
}
else if (hasNgModuleDef(value)) {
/** @nocollapse @type {?} */
const def = value.ngModuleDef;
// Look through declarations, imports, and exports, and queue everything found there.
this.queueTypeArray(maybeUnwrapFn(def.declarations), value);
this.queueTypesFromModulesArray(maybeUnwrapFn(def.imports));
this.queueTypesFromModulesArray(maybeUnwrapFn(def.exports));
}
}
}
/**
* @private
* @param {?} prop
* @param {?} type
* @return {?}
*/
maybeStoreNgDef(prop, type) {
if (!this.initialNgDefs.has(type)) {
/** @type {?} */
const currentDef = Object.getOwnPropertyDescriptor(type, prop);
this.initialNgDefs.set(type, [prop, currentDef]);
}
}
/**
* @private
* @param {?} type
* @param {?} defField
* @param {?} field
* @return {?}
*/
storeFieldOfDefOnType(type, defField, field) {
/** @type {?} */
const def = ((/** @type {?} */ (type)))[defField];
/** @type {?} */
const original = def[field];
this.defCleanupOps.push({ field, def, original });
}
/**
* Clears current components resolution queue, but stores the state of the queue, so we can
* restore it later. Clearing the queue is required before we try to compile components (via
* `TestBed.compileComponents`), so that component defs are in sync with the resolution queue.
* @private
* @return {?}
*/
clearComponentResolutionQueue() {
if (this.originalComponentResolutionQueue === null) {
this.originalComponentResolutionQueue = new Map();
}
clearResolutionOfComponentResourcesQueue().forEach((/**
* @param {?} value
* @param {?} key
* @return {?}
*/
(value, key) => (/** @type {?} */ (this.originalComponentResolutionQueue)).set(key, value)));
}
/*
* Restores component resolution queue to the previously saved state. This operation is performed
* as a part of restoring the state after completion of the current set of tests (that might
* potentially mutate the state).
*/
/**
* @private
* @return {?}
*/
restoreComponentResolutionQueue() {
if (this.originalComponentResolutionQueue !== null) {
restoreComponentResolutionQueue(this.originalComponentResolutionQueue);
this.originalComponentResolutionQueue = null;
}
}
/**
* @return {?}
*/
restoreOriginalState() {
for (const op of this.defCleanupOps) {
op.def[op.field] = op.original;
}
// Restore initial component/directive/pipe defs
this.initialNgDefs.forEach((/**
* @param {?} value
* @param {?} type
* @return {?}
*/
(value, type) => {
const [prop, descriptor] = value;
if (!descriptor) {
// Delete operations are generally undesirable since they have performance implications
// on objects they were applied to. In this particular case, situations where this code is
// invoked should be quite rare to cause any noticable impact, since it's applied only to
// some test cases (for example when class with no annotations extends some @Component)
// when we need to clear 'ngComponentDef' field on a given class to restore its original
// state (before applying overrides and running tests).
delete ((/** @type {?} */ (type)))[prop];
}
else {
Object.defineProperty(type, prop, descriptor);
}
}));
this.initialNgDefs.clear();
this.moduleProvidersOverridden.clear();
this.restoreComponentResolutionQueue();
// Restore the locale ID to the default value, this shouldn't be necessary but we never know
setLocaleId(DEFAULT_LOCALE_ID);
}
/**
* @private
* @return {?}
*/
compileTestModule() {
class RootScopeModule {
}
compileNgModuleDefs((/** @type {?} */ (RootScopeModule)), {
providers: [...this.rootProviderOverrides],
});
/** @type {?} */
const ngZone = new NgZone({ enableLongStackTrace: true });
/** @type {?} */
const providers = [
{ provide: NgZone, useValue: ngZone },
{ provide: Compiler, useFactory: (/**
* @return {?}
*/
() => new R3TestCompiler(this)) },
...this.providers,
...this.providerOverrides,
];
/** @type {?} */
const imports = [RootScopeModule, this.additionalModuleTypes, this.imports || []];
// clang-format off
compileNgModuleDefs(this.testModuleType, {
declarations: this.declarations,
imports,
schemas: this.schemas,
providers,
}, /* allowDuplicateDeclarationsInRoot */ true);
// clang-format on
this.applyProviderOverridesToModule(this.testModuleType);
}
/**
* @return {?}
*/
get injector() {
if (this._injector !== null) {
return this._injector;
}
/** @type {?} */
const providers = [];
/** @type {?} */
const compilerOptions = this.platform.injector.get(COMPILER_OPTIONS);
compilerOptions.forEach((/**
* @param {?} opts
* @return {?}
*/
opts => {
if (opts.providers) {
providers.push(opts.providers);
}
}));
if (this.compilerProviders !== null) {
providers.push(...this.compilerProviders);
}
// TODO(ocombe): make this work with an Injector directly instead of creating a module for it
class CompilerModule {
}
compileNgModuleDefs((/** @type {?} */ (CompilerModule)), { providers });
/** @type {?} */
const CompilerModuleFactory = new R3NgModuleFactory(CompilerModule);
this._injector = CompilerModuleFactory.create(this.platform.injector).injector;
return this._injector;
}
// get overrides for a specific provider (if any)
/**
* @private
* @param {?} provider
* @return {?}
*/
getSingleProviderOverrides(provider) {
/** @type {?} */
const token = getProviderToken(provider);
return this.providerOverridesByToken.get(token) || null;
}
/**
* @private
* @param {?=} providers
* @return {?}
*/
getProviderOverrides(providers) {
if (!providers || !providers.length || this.providerOverridesByToken.size === 0)
return [];
// There are two flattening operations here. The inner flatten() operates on the metadata's
// providers and applies a mapping function which retrieves overrides for each incoming
// provider. The outer flatten() then flattens the produced overrides array. If this is not
// done, the array can contain other empty arrays (e.g. `[[], []]`) which leak into the
// providers array and contaminate any error messages that might be generated.
return flatten(flatten(providers, (/**
* @param {?} provider
* @return {?}
*/
(provider) => this.getSingleProviderOverrides(provider) || [])));
}
/**
* @private
* @param {?=} providers
* @return {?}
*/
getOverriddenProviders(providers) {
if (!providers || !providers.length || this.providerOverridesByToken.size === 0)
return [];
/** @type {?} */
const overrides = this.getProviderOverrides(providers);
/** @type {?} */
const hasMultiProviderOverrides = overrides.some(isMultiProvider);
/** @type {?} */
const overriddenProviders = [...providers, ...overrides];
// No additional processing is required in case we have no multi providers to override
if (!hasMultiProviderOverrides) {
return overriddenProviders;
}
/** @type {?} */
const final = [];
/** @type {?} */
const seenMultiProviders = new Set();
// We iterate through the list of providers in reverse order to make sure multi provider
// overrides take precedence over the values defined in provider list. We also fiter out all
// multi providers that have overrides, keeping overridden values only.
forEachRight(overriddenProviders, (/**
* @param {?} provider
* @return {?}
*/
(provider) => {
/** @type {?} */
const token = getProviderToken(provider);
if (isMultiProvider(provider) && this.providerOverridesByToken.has(token)) {
if (!seenMultiProviders.has(token)) {
seenMultiProviders.add(token);
if (provider && provider.useValue && Array.isArray(provider.useValue)) {
forEachRight(provider.useValue, (/**
* @param {?} value
* @return {?}
*/
(value) => {
// Unwrap provider override array into individual providers in final set.
final.unshift({ provide: token, useValue: value, multi: true });
}));
}
else {
final.unshift(provider);
}
}
}
else {
final.unshift(provider);
}
}));
return final;
}
/**
* @private
* @param {?=} providers
* @return {?}
*/
hasProviderOverrides(providers) {
return this.getProviderOverrides(providers).length > 0;
}
/**
* @private
* @param {?} declaration
* @param {?} field
* @return {?}
*/
patchDefWithProviderOverrides(declaration, field) {
/** @type {?} */
const def = ((/** @type {?} */ (declaration)))[field];
if (def && def.providersResolver) {
this.maybeStoreNgDef(field, declaration);
/** @type {?} */
const resolver = def.providersResolver;
/** @type {?} */
const processProvidersFn = (/**
* @param {?} providers
* @return {?}
*/
(providers) => this.getOverriddenProviders(providers));
this.storeFieldOfDefOnType(declaration, field, 'providersResolver');
def.providersResolver = (/**
* @param {?} ngDef
* @return {?}
*/
(ngDef) => resolver(ngDef, processProvidersFn));
}
}
}
if (false) {
/**
* @type {?}
* @private
*/
R3TestBedCompiler.prototype.originalComponentResolutionQueue;
/**
* @type {?}
* @private
*/
R3TestBedCompiler.prototype.declarations;
/**
* @type {?}
* @private
*/
R3TestBedCompiler.prototype.imports;
/**
* @type {?}
* @private
*/
R3TestBedCompiler.prototype.providers;
/**
* @type {?}
* @private
*/
R3TestBedCompiler.prototype.schemas;
/**
* @type {?}
* @private
*/
R3TestBedCompiler.prototype.pendingComponents;
/**
* @type {?}
* @private
*/
R3TestBedCompiler.prototype.pendingDirectives;
/**
* @type {?}
* @private
*/
R3TestBedCompiler.prototype.pendingPipes;
/**
* @type {?}
* @private
*/
R3TestBedCompiler.prototype.seenComponents;
/**
* @type {?}
* @private
*/
R3TestBedCompiler.prototype.seenDirectives;
/**
* @type {?}
* @private
*/
R3TestBedCompiler.prototype.existingComponentStyles;
/**
* @type {?}
* @private
*/
R3TestBedCompiler.prototype.resolvers;
/**
* @type {?}
* @private
*/
R3TestBedCompiler.prototype.componentToModuleScope;
/**
* @type {?}
* @private
*/
R3TestBedCompiler.prototype.initialNgDefs;
/**
* @type {?}
* @private
*/
R3TestBedCompiler.prototype.defCleanupOps;
/**
* @type {?}
* @private
*/
R3TestBedCompiler.prototype._injector;
/**
* @type {?}
* @private
*/
R3TestBedCompiler.prototype.compilerProviders;
/**
* @type {?}
* @private
*/
R3TestBedCompiler.prototype.providerOverrides;
/**
* @type {?}
* @private
*/
R3TestBedCompiler.prototype.rootProviderOverrides;
/**
* @type {?}
* @private
*/
R3TestBedCompiler.prototype.providerOverridesByToken;
/**
* @type {?}
* @private
*/
R3TestBedCompiler.prototype.moduleProvidersOverridden;
/**
* @type {?}
* @private
*/
R3TestBedCompiler.prototype.testModuleType;
/**
* @type {?}
* @private
*/
R3TestBedCompiler.prototype.testModuleRef;
/**
* @type {?}
* @private
*/
R3TestBedCompiler.prototype.platform;
/**
* @type {?}
* @private
*/
R3TestBedCompiler.prototype.additionalModuleTypes;
}
/**
* @return {?}
*/
function initResolvers() {
return {
module: new NgModuleResolver(),
component: new ComponentResolver(),
directive: new DirectiveResolver(),
pipe: new PipeResolver()
};
}
/**
* @template T
* @param {?} value
* @return {?}
*/
function hasNgModuleDef(value) {
return value.hasOwnProperty('ngModuleDef');
}
/**
* @template T
* @param {?} maybeFn
* @return {?}
*/
function maybeUnwrapFn(maybeFn) {
return maybeFn instanceof Function ? maybeFn() : maybeFn;
}
/**
* @template T
* @param {?} values
* @param {?=} mapFn
* @return {?}
*/
function flatten(values, mapFn) {
/** @type {?} */
const out = [];
values.forEach((/**
* @param {?} value
* @return {?}
*/
value => {
if (Array.isArray(value)) {
out.push(...flatten(value, mapFn));
}
else {
out.push(mapFn ? mapFn(value) : value);
}
}));
return out;
}
/**
* @param {?} provider
* @param {?} field
* @return {?}
*/
function getProviderField(provider, field) {
return provider && typeof provider === 'object' && ((/** @type {?} */ (provider)))[field];
}
/**
* @param {?} provider
* @return {?}
*/
function getProviderToken(provider) {
return getProviderField(provider, 'provide') || provider;
}
/**
* @param {?} provider
* @return {?}
*/
function isMultiProvider(provider) {
return !!getProviderField(provider, 'multi');
}
/**
* @template T
* @param {?} values
* @param {?} fn
* @return {?}
*/
function forEachRight(values, fn) {
for (let idx = values.length - 1; idx >= 0; idx--) {
fn(values[idx], idx);
}
}
class R3TestCompiler {
/**
* @param {?} testBed
*/
constructor(testBed) {
this.testBed = testBed;
}
/**
* @template T
* @param {?} moduleType
* @return {?}
*/
compileModuleSync(moduleType) {
this.testBed._compileNgModuleSync(moduleType);
return new R3NgModuleFactory(moduleType);
}
/**
* @template T
* @param {?} moduleType
* @return {?}
*/
compileModuleAsync(moduleType) {
return tslib_1.__awaiter(this, void 0, void 0, function* () {
yield this.testBed._compileNgModuleAsync(moduleType);
return new R3NgModuleFactory(moduleType);
});
}
/**
* @template T
* @param {?} moduleType
* @return {?}
*/
compileModuleAndAllComponentsSync(moduleType) {
/** @type {?} */
const ngModuleFactory = this.compileModuleSync(moduleType);
/** @type {?} */
const componentFactories = this.testBed._getComponentFactories((/** @type {?} */ (moduleType)));
return new ModuleWithComponentFactories(ngModuleFactory, componentFactories);
}
/**
* @template T
* @param {?} moduleType
* @return {?}
*/
compileModuleAndAllComponentsAsync(moduleType) {
return tslib_1.__awaiter(this, void 0, void 0, function* () {
/** @type {?} */
const ngModuleFactory = yield this.compileModuleAsync(moduleType);
/** @type {?} */
const componentFactories = this.testBed._getComponentFactories((/** @type {?} */ (moduleType)));
return new ModuleWithComponentFactories(ngModuleFactory, componentFactories);
});
}
/**
* @return {?}
*/
clearCache() { }
/**
* @param {?} type
* @return {?}
*/
clearCacheFor(type) { }
/**
* @param {?} moduleType
* @return {?}
*/
getModuleId(moduleType) {
/** @type {?} */
const meta = this.testBed._getModuleResolver().resolve(moduleType);
return meta && meta.id || undefined;
}
}
if (false) {
/**
* @type {?}
* @private
*/
R3TestCompiler.prototype.testBed;
}
//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoicjNfdGVzdF9iZWRfY29tcGlsZXIuanMiLCJzb3VyY2VSb290IjoiIiwic291cmNlcyI6WyIuLi8uLi8uLi8uLi8uLi8uLi8uLi9wYWNrYWdlcy9jb3JlL3Rlc3Rpbmcvc3JjL3IzX3Rlc3RfYmVkX2NvbXBpbGVyLnRzIl0sIm5hbWVzIjpbXSwibWFwcGluZ3MiOiI7Ozs7Ozs7Ozs7OztBQVFBLE9BQU8sRUFBQyxjQUFjLEVBQUMsTUFBTSxtQkFBbUIsQ0FBQztBQUNqRCxPQUFPLEVBQUMscUJBQXFCLEVBQUUsZ0JBQWdCLEVBQUUsUUFBUSxFQUFrQyxTQUFTLEVBQUUsNEJBQTRCLEVBQTZCLE1BQU0sRUFBcUMsa0JBQWtCLElBQUksaUJBQWlCLEVBQWlDLGlCQUFpQixJQUFJLGdCQUFnQixFQUFFLGlCQUFpQixJQUFJLGdCQUFnQixFQUFFLGdCQUFnQixJQUFJLGVBQWUsRUFBRSxjQUFjLElBQUksYUFBYSxFQUFFLFlBQVksSUFBSSxXQUFXLEVBQUUsZ0JBQWdCLElBQUksaUJBQWlCLEVBQXdGLHdCQUF3QixJQUFJLGdCQUFnQixFQUFFLG1CQUFtQixJQUFJLFdBQVcsRUFBRSxpQkFBaUIsSUFBSSxnQkFBZ0IsRUFBRSxpQkFBaUIsSUFBSSxnQkFBZ0IsRUFBRSxvQkFBb0IsSUFBSSxtQkFBbUIsRUFBRSxZQUFZLElBQUksV0FBVyxFQUFFLGlCQUFpQixJQUFJLGdCQUFnQixFQUFFLDJCQUEyQixJQUFJLDBCQUEwQixFQUFFLFlBQVksSUFBSSxXQUFXLEVBQUUsb0JBQW9CLElBQUksbUJBQW1CLEVBQW1DLE1BQU0sZUFBZSxDQUFDO0FBRTdnQyxPQUFPLEVBQUMsd0NBQXdDLEVBQUUsK0JBQStCLEVBQUUseUJBQXlCLEVBQUUsK0JBQStCLEVBQUMsTUFBTSxxQ0FBcUMsQ0FBQztBQUUxTCxPQUFPLEVBQUMsaUJBQWlCLEVBQUUsaUJBQWlCLEVBQUUsZ0JBQWdCLEVBQUUsWUFBWSxFQUFXLE1BQU0sYUFBYSxDQUFDOzs7SUFJekcsY0FBVztJQUNYLG9CQUFpQjs7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