refactor(ivy): refactor more files in DI to prepare it for bazel packages (#28098)
PR Close #28098
This commit is contained in:

committed by
Andrew Kushnir

parent
6a9a48b0ac
commit
978ffa9d32
33
packages/core/src/di/jit/environment.ts
Normal file
33
packages/core/src/di/jit/environment.ts
Normal file
@ -0,0 +1,33 @@
|
||||
/**
|
||||
* @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 {Type} from '../../interface/type';
|
||||
import {inject} from '../injector_compatibility';
|
||||
import {defineInjectable, defineInjector, getInjectableDef, getInjectorDef} from '../interface/defs';
|
||||
|
||||
|
||||
/**
|
||||
* A mapping of the @angular/core API surface used in generated expressions to the actual symbols.
|
||||
*
|
||||
* This should be kept up to date with the public exports of @angular/core.
|
||||
*/
|
||||
export const angularCoreDiEnv: {[name: string]: Function} = {
|
||||
'defineInjectable': defineInjectable,
|
||||
'defineInjector': defineInjector,
|
||||
'inject': inject,
|
||||
'ɵgetFactoryOf': getFactoryOf,
|
||||
};
|
||||
|
||||
function getFactoryOf<T>(type: Type<any>): ((type: Type<T>| null) => T)|null {
|
||||
const typeAny = type as any;
|
||||
const def = getInjectableDef<T>(typeAny) || getInjectorDef<T>(typeAny);
|
||||
if (!def || def.factory === undefined) {
|
||||
return null;
|
||||
}
|
||||
return def.factory;
|
||||
}
|
100
packages/core/src/di/jit/injectable.ts
Normal file
100
packages/core/src/di/jit/injectable.ts
Normal file
@ -0,0 +1,100 @@
|
||||
/**
|
||||
* @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 {R3InjectableMetadataFacade, getCompilerFacade} from '../../compiler/compiler_facade';
|
||||
import {Type} from '../../interface/type';
|
||||
import {getClosureSafeProperty} from '../../util/property';
|
||||
import {Injectable} from '../injectable';
|
||||
import {NG_INJECTABLE_DEF} from '../interface/defs';
|
||||
import {ClassSansProvider, ExistingSansProvider, FactorySansProvider, ValueProvider, ValueSansProvider} from '../interface/provider';
|
||||
|
||||
import {angularCoreDiEnv} from './environment';
|
||||
import {convertDependencies, reflectDependencies} from './util';
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* Compile an Angular injectable according to its `Injectable` metadata, and patch the resulting
|
||||
* `ngInjectableDef` onto the injectable type.
|
||||
*/
|
||||
export function compileInjectable(type: Type<any>, srcMeta?: Injectable): void {
|
||||
let def: any = null;
|
||||
|
||||
// if NG_INJECTABLE_DEF is already defined on this class then don't overwrite it
|
||||
if (type.hasOwnProperty(NG_INJECTABLE_DEF)) return;
|
||||
|
||||
Object.defineProperty(type, NG_INJECTABLE_DEF, {
|
||||
get: () => {
|
||||
if (def === null) {
|
||||
// Allow the compilation of a class with a `@Injectable()` decorator without parameters
|
||||
const meta: Injectable = srcMeta || {providedIn: null};
|
||||
const hasAProvider = isUseClassProvider(meta) || isUseFactoryProvider(meta) ||
|
||||
isUseValueProvider(meta) || isUseExistingProvider(meta);
|
||||
|
||||
|
||||
const compilerMeta: R3InjectableMetadataFacade = {
|
||||
name: type.name,
|
||||
type: type,
|
||||
typeArgumentCount: 0,
|
||||
providedIn: meta.providedIn,
|
||||
ctorDeps: reflectDependencies(type),
|
||||
userDeps: undefined
|
||||
};
|
||||
if ((isUseClassProvider(meta) || isUseFactoryProvider(meta)) && meta.deps !== undefined) {
|
||||
compilerMeta.userDeps = convertDependencies(meta.deps);
|
||||
}
|
||||
if (!hasAProvider) {
|
||||
// In the case the user specifies a type provider, treat it as {provide: X, useClass: X}.
|
||||
// The deps will have been reflected above, causing the factory to create the class by
|
||||
// calling
|
||||
// its constructor with injected deps.
|
||||
compilerMeta.useClass = type;
|
||||
} else if (isUseClassProvider(meta)) {
|
||||
// The user explicitly specified useClass, and may or may not have provided deps.
|
||||
compilerMeta.useClass = meta.useClass;
|
||||
} else if (isUseValueProvider(meta)) {
|
||||
// The user explicitly specified useValue.
|
||||
compilerMeta.useValue = meta.useValue;
|
||||
} else if (isUseFactoryProvider(meta)) {
|
||||
// The user explicitly specified useFactory.
|
||||
compilerMeta.useFactory = meta.useFactory;
|
||||
} else if (isUseExistingProvider(meta)) {
|
||||
// The user explicitly specified useExisting.
|
||||
compilerMeta.useExisting = meta.useExisting;
|
||||
} else {
|
||||
// Can't happen - either hasAProvider will be false, or one of the providers will be set.
|
||||
throw new Error(`Unreachable state.`);
|
||||
}
|
||||
def = getCompilerFacade().compileInjectable(
|
||||
angularCoreDiEnv, `ng://${type.name}/ngInjectableDef.js`, compilerMeta);
|
||||
}
|
||||
return def;
|
||||
},
|
||||
});
|
||||
}
|
||||
|
||||
type UseClassProvider = Injectable & ClassSansProvider & {deps?: any[]};
|
||||
|
||||
const USE_VALUE =
|
||||
getClosureSafeProperty<ValueProvider>({provide: String, useValue: getClosureSafeProperty});
|
||||
|
||||
function isUseClassProvider(meta: Injectable): meta is UseClassProvider {
|
||||
return (meta as UseClassProvider).useClass !== undefined;
|
||||
}
|
||||
|
||||
function isUseValueProvider(meta: Injectable): meta is Injectable&ValueSansProvider {
|
||||
return USE_VALUE in meta;
|
||||
}
|
||||
|
||||
function isUseFactoryProvider(meta: Injectable): meta is Injectable&FactorySansProvider {
|
||||
return (meta as FactorySansProvider).useFactory !== undefined;
|
||||
}
|
||||
|
||||
function isUseExistingProvider(meta: Injectable): meta is Injectable&ExistingSansProvider {
|
||||
return (meta as ExistingSansProvider).useExisting !== undefined;
|
||||
}
|
77
packages/core/src/di/jit/util.ts
Normal file
77
packages/core/src/di/jit/util.ts
Normal file
@ -0,0 +1,77 @@
|
||||
/**
|
||||
* @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 {CompilerFacade, R3DependencyMetadataFacade, getCompilerFacade} from '../../compiler/compiler_facade';
|
||||
import {Type} from '../../interface/type';
|
||||
import {ReflectionCapabilities} from '../../reflection/reflection_capabilities';
|
||||
import {Attribute, Host, Inject, Optional, Self, SkipSelf} from '../metadata';
|
||||
|
||||
let _reflect: ReflectionCapabilities|null = null;
|
||||
|
||||
export function getReflect(): ReflectionCapabilities {
|
||||
return (_reflect = _reflect || new ReflectionCapabilities());
|
||||
}
|
||||
|
||||
export function reflectDependencies(type: Type<any>): R3DependencyMetadataFacade[] {
|
||||
return convertDependencies(getReflect().parameters(type));
|
||||
}
|
||||
|
||||
export function convertDependencies(deps: any[]): R3DependencyMetadataFacade[] {
|
||||
const compiler = getCompilerFacade();
|
||||
return deps.map(dep => reflectDependency(compiler, dep));
|
||||
}
|
||||
|
||||
function reflectDependency(compiler: CompilerFacade, dep: any | any[]): R3DependencyMetadataFacade {
|
||||
const meta: R3DependencyMetadataFacade = {
|
||||
token: null,
|
||||
host: false,
|
||||
optional: false,
|
||||
resolved: compiler.R3ResolvedDependencyType.Token,
|
||||
self: false,
|
||||
skipSelf: false,
|
||||
};
|
||||
|
||||
function setTokenAndResolvedType(token: any): void {
|
||||
meta.resolved = compiler.R3ResolvedDependencyType.Token;
|
||||
meta.token = token;
|
||||
}
|
||||
|
||||
if (Array.isArray(dep)) {
|
||||
if (dep.length === 0) {
|
||||
throw new Error('Dependency array must have arguments.');
|
||||
}
|
||||
for (let j = 0; j < dep.length; j++) {
|
||||
const param = dep[j];
|
||||
if (param === undefined) {
|
||||
// param may be undefined if type of dep is not set by ngtsc
|
||||
continue;
|
||||
} else if (param instanceof Optional || param.__proto__.ngMetadataName === 'Optional') {
|
||||
meta.optional = true;
|
||||
} else if (param instanceof SkipSelf || param.__proto__.ngMetadataName === 'SkipSelf') {
|
||||
meta.skipSelf = true;
|
||||
} else if (param instanceof Self || param.__proto__.ngMetadataName === 'Self') {
|
||||
meta.self = true;
|
||||
} else if (param instanceof Host || param.__proto__.ngMetadataName === 'Host') {
|
||||
meta.host = true;
|
||||
} else if (param instanceof Inject) {
|
||||
meta.token = param.token;
|
||||
} else if (param instanceof Attribute) {
|
||||
if (param.attributeName === undefined) {
|
||||
throw new Error(`Attribute name must be defined.`);
|
||||
}
|
||||
meta.token = param.attributeName;
|
||||
meta.resolved = compiler.R3ResolvedDependencyType.Attribute;
|
||||
} else {
|
||||
setTokenAndResolvedType(param);
|
||||
}
|
||||
}
|
||||
} else {
|
||||
setTokenAndResolvedType(dep);
|
||||
}
|
||||
return meta;
|
||||
}
|
Reference in New Issue
Block a user