2018-04-06 09:53:10 -07:00
|
|
|
/**
|
|
|
|
* @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 {InjectFlags} from './core';
|
|
|
|
import * as o from './output/output_ast';
|
|
|
|
import {Identifiers} from './render3/r3_identifiers';
|
|
|
|
|
|
|
|
|
|
|
|
type MapEntry = {
|
|
|
|
key: string; quoted: boolean; value: o.Expression;
|
|
|
|
};
|
|
|
|
|
|
|
|
function mapToMapExpression(map: {[key: string]: o.Expression}): o.LiteralMapExpr {
|
|
|
|
const result = Object.keys(map).map(key => ({key, value: map[key], quoted: false}));
|
|
|
|
return o.literalMap(result);
|
|
|
|
}
|
|
|
|
|
|
|
|
export interface InjectableDef {
|
|
|
|
expression: o.Expression;
|
|
|
|
type: o.Type;
|
|
|
|
}
|
|
|
|
|
|
|
|
export interface IvyInjectableDep {
|
|
|
|
token: o.Expression;
|
|
|
|
optional: boolean;
|
|
|
|
self: boolean;
|
|
|
|
skipSelf: boolean;
|
2018-04-24 11:34:11 -07:00
|
|
|
attribute: boolean;
|
2018-04-06 09:53:10 -07:00
|
|
|
}
|
|
|
|
|
|
|
|
export interface IvyInjectableMetadata {
|
|
|
|
name: string;
|
|
|
|
type: o.Expression;
|
|
|
|
providedIn: o.Expression;
|
|
|
|
useType?: IvyInjectableDep[];
|
|
|
|
useClass?: o.Expression;
|
|
|
|
useFactory?: {factory: o.Expression; deps: IvyInjectableDep[];};
|
|
|
|
useExisting?: o.Expression;
|
|
|
|
useValue?: o.Expression;
|
|
|
|
}
|
|
|
|
|
|
|
|
export function compileIvyInjectable(meta: IvyInjectableMetadata): InjectableDef {
|
|
|
|
let ret: o.Expression = o.NULL_EXPR;
|
|
|
|
if (meta.useType !== undefined) {
|
|
|
|
const args = meta.useType.map(dep => injectDep(dep));
|
|
|
|
ret = new o.InstantiateExpr(meta.type, args);
|
|
|
|
} else if (meta.useClass !== undefined) {
|
|
|
|
const factory =
|
|
|
|
new o.ReadPropExpr(new o.ReadPropExpr(meta.useClass, 'ngInjectableDef'), 'factory');
|
|
|
|
ret = new o.InvokeFunctionExpr(factory, []);
|
|
|
|
} else if (meta.useValue !== undefined) {
|
|
|
|
ret = meta.useValue;
|
|
|
|
} else if (meta.useExisting !== undefined) {
|
|
|
|
ret = o.importExpr(Identifiers.inject).callFn([meta.useExisting]);
|
|
|
|
} else if (meta.useFactory !== undefined) {
|
|
|
|
const args = meta.useFactory.deps.map(dep => injectDep(dep));
|
|
|
|
ret = new o.InvokeFunctionExpr(meta.useFactory.factory, args);
|
|
|
|
} else {
|
|
|
|
throw new Error('No instructions for injectable compiler!');
|
|
|
|
}
|
|
|
|
|
|
|
|
const token = meta.type;
|
|
|
|
const providedIn = meta.providedIn;
|
|
|
|
const factory =
|
|
|
|
o.fn([], [new o.ReturnStatement(ret)], undefined, undefined, `${meta.name}_Factory`);
|
|
|
|
|
|
|
|
const expression = o.importExpr({
|
|
|
|
moduleName: '@angular/core',
|
|
|
|
name: 'defineInjectable',
|
|
|
|
}).callFn([mapToMapExpression({token, factory, providedIn})]);
|
|
|
|
const type = new o.ExpressionType(o.importExpr(
|
|
|
|
{
|
|
|
|
moduleName: '@angular/core',
|
|
|
|
name: 'InjectableDef',
|
|
|
|
},
|
|
|
|
[new o.ExpressionType(meta.type)]));
|
|
|
|
|
|
|
|
return {
|
|
|
|
expression, type,
|
|
|
|
};
|
|
|
|
}
|
|
|
|
|
|
|
|
function injectDep(dep: IvyInjectableDep): o.Expression {
|
|
|
|
const defaultValue = dep.optional ? o.NULL_EXPR : o.literal(undefined);
|
|
|
|
const flags = o.literal(
|
|
|
|
InjectFlags.Default | (dep.self && InjectFlags.Self || 0) |
|
|
|
|
(dep.skipSelf && InjectFlags.SkipSelf || 0));
|
|
|
|
if (!dep.optional && !dep.skipSelf && !dep.self) {
|
|
|
|
return o.importExpr(Identifiers.inject).callFn([dep.token]);
|
|
|
|
} else {
|
|
|
|
return o.importExpr(Identifiers.inject).callFn([
|
|
|
|
dep.token,
|
|
|
|
defaultValue,
|
|
|
|
flags,
|
|
|
|
]);
|
|
|
|
}
|
|
|
|
}
|