angular-cn/packages/compiler/src/injectable_compiler.ts
Kara Erickson 86104b82b8 refactor(core): rename ngInjectableDef to ɵprov (#33151)
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
2019-10-16 16:36:19 -04:00

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);
}
}
}