Injectable defs are not considered public API, so the property that contains them should be prefixed with Angular's marker for "private" ('ɵ') to discourage apps from relying on def APIs directly. This commit adds the prefix and shortens the name from ngInjectableDef to "prov" (for "provider", since injector defs are known as "inj"). This is because property names cannot be minified by Uglify without turning on property mangling (which most apps have turned off) and are thus size-sensitive. PR Close #33151
137 lines
4.9 KiB
TypeScript
137 lines
4.9 KiB
TypeScript
/**
|
|
* @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 {StaticSymbol} from './aot/static_symbol';
|
|
import {CompileInjectableMetadata, CompileNgModuleMetadata, CompileProviderMetadata, identifierName} from './compile_metadata';
|
|
import {CompileReflector} from './compile_reflector';
|
|
import {InjectFlags, NodeFlags} from './core';
|
|
import {Identifiers} from './identifiers';
|
|
import * as o from './output/output_ast';
|
|
import {convertValueToOutputAst} from './output/value_util';
|
|
import {typeSourceSpan} from './parse_util';
|
|
import {NgModuleProviderAnalyzer} from './provider_analyzer';
|
|
import {OutputContext} from './util';
|
|
import {componentFactoryResolverProviderDef, depDef, providerDef} from './view_compiler/provider_compiler';
|
|
|
|
type MapEntry = {
|
|
key: string,
|
|
quoted: boolean,
|
|
value: o.Expression
|
|
};
|
|
type MapLiteral = MapEntry[];
|
|
|
|
function mapEntry(key: string, value: o.Expression): MapEntry {
|
|
return {key, value, quoted: false};
|
|
}
|
|
|
|
export class InjectableCompiler {
|
|
private tokenInjector: StaticSymbol;
|
|
constructor(private reflector: CompileReflector, private alwaysGenerateDef: boolean) {
|
|
this.tokenInjector = reflector.resolveExternalReference(Identifiers.Injector);
|
|
}
|
|
|
|
private depsArray(deps: any[], ctx: OutputContext): o.Expression[] {
|
|
return deps.map(dep => {
|
|
let token = dep;
|
|
let args = [token];
|
|
let flags: InjectFlags = InjectFlags.Default;
|
|
if (Array.isArray(dep)) {
|
|
for (let i = 0; i < dep.length; i++) {
|
|
const v = dep[i];
|
|
if (v) {
|
|
if (v.ngMetadataName === 'Optional') {
|
|
flags |= InjectFlags.Optional;
|
|
} else if (v.ngMetadataName === 'SkipSelf') {
|
|
flags |= InjectFlags.SkipSelf;
|
|
} else if (v.ngMetadataName === 'Self') {
|
|
flags |= InjectFlags.Self;
|
|
} else if (v.ngMetadataName === 'Inject') {
|
|
token = v.token;
|
|
} else {
|
|
token = v;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
let tokenExpr: o.Expression;
|
|
if (typeof token === 'string') {
|
|
tokenExpr = o.literal(token);
|
|
} else if (token === this.tokenInjector) {
|
|
tokenExpr = o.importExpr(Identifiers.INJECTOR);
|
|
} else {
|
|
tokenExpr = ctx.importExpr(token);
|
|
}
|
|
|
|
if (flags !== InjectFlags.Default) {
|
|
args = [tokenExpr, o.literal(flags)];
|
|
} else {
|
|
args = [tokenExpr];
|
|
}
|
|
return o.importExpr(Identifiers.inject).callFn(args);
|
|
});
|
|
}
|
|
|
|
factoryFor(injectable: CompileInjectableMetadata, ctx: OutputContext): o.Expression {
|
|
let retValue: o.Expression;
|
|
if (injectable.useExisting) {
|
|
retValue = o.importExpr(Identifiers.inject).callFn([ctx.importExpr(injectable.useExisting)]);
|
|
} else if (injectable.useFactory) {
|
|
const deps = injectable.deps || [];
|
|
if (deps.length > 0) {
|
|
retValue = ctx.importExpr(injectable.useFactory).callFn(this.depsArray(deps, ctx));
|
|
} else {
|
|
return ctx.importExpr(injectable.useFactory);
|
|
}
|
|
} else if (injectable.useValue) {
|
|
retValue = convertValueToOutputAst(ctx, injectable.useValue);
|
|
} else {
|
|
const clazz = injectable.useClass || injectable.symbol;
|
|
const depArgs = this.depsArray(this.reflector.parameters(clazz), ctx);
|
|
retValue = new o.InstantiateExpr(ctx.importExpr(clazz), depArgs);
|
|
}
|
|
return o.fn(
|
|
[], [new o.ReturnStatement(retValue)], undefined, undefined,
|
|
injectable.symbol.name + '_Factory');
|
|
}
|
|
|
|
injectableDef(injectable: CompileInjectableMetadata, ctx: OutputContext): o.Expression {
|
|
let providedIn: o.Expression = o.NULL_EXPR;
|
|
if (injectable.providedIn !== undefined) {
|
|
if (injectable.providedIn === null) {
|
|
providedIn = o.NULL_EXPR;
|
|
} else if (typeof injectable.providedIn === 'string') {
|
|
providedIn = o.literal(injectable.providedIn);
|
|
} else {
|
|
providedIn = ctx.importExpr(injectable.providedIn);
|
|
}
|
|
}
|
|
const def: MapLiteral = [
|
|
mapEntry('factory', this.factoryFor(injectable, ctx)),
|
|
mapEntry('token', ctx.importExpr(injectable.type.reference)),
|
|
mapEntry('providedIn', providedIn),
|
|
];
|
|
return o.importExpr(Identifiers.ɵɵdefineInjectable).callFn([o.literalMap(def)]);
|
|
}
|
|
|
|
compile(injectable: CompileInjectableMetadata, ctx: OutputContext): void {
|
|
if (this.alwaysGenerateDef || injectable.providedIn !== undefined) {
|
|
const className = identifierName(injectable.type) !;
|
|
const clazz = new o.ClassStmt(
|
|
className, null,
|
|
[
|
|
new o.ClassField(
|
|
'ɵprov', o.INFERRED_TYPE, [o.StmtModifier.Static],
|
|
this.injectableDef(injectable, ctx)),
|
|
],
|
|
[], new o.ClassMethod(null, [], []), []);
|
|
ctx.statements.push(clazz);
|
|
}
|
|
}
|
|
}
|