fix(core): Remove static dependency from @angular/core to @angular/compiler (#26734)
PR Close #26734
This commit is contained in:

committed by
Matias Niemelä

parent
5d740785a9
commit
d042c4afe0
22
packages/core/src/render3/jit/compiler_facade.ts
Normal file
22
packages/core/src/render3/jit/compiler_facade.ts
Normal file
@ -0,0 +1,22 @@
|
||||
/**
|
||||
* @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 {global} from '../../util';
|
||||
import {CompilerFacade, ExportedCompilerFacade} from './compiler_facade_interface';
|
||||
export * from './compiler_facade_interface';
|
||||
|
||||
export function getCompilerFacade(): CompilerFacade {
|
||||
const globalNg: ExportedCompilerFacade = global.ng;
|
||||
if (!globalNg || !globalNg.ɵcompilerFacade) {
|
||||
throw new Error(
|
||||
`Angular JIT compilation failed: '@angular/compiler' not loaded!\n` +
|
||||
` - JIT compilation is discouraged for production use-cases! Consider AOT mode instead.\n` +
|
||||
` - Did you bootstrap using '@angular/platform-browser-dynamic' or '@angular/platform-server'?\n` +
|
||||
` - Alternatively provide the compiler with 'import "@angular/compiler";' before bootstrapping.`);
|
||||
}
|
||||
return globalNg.ɵcompilerFacade;
|
||||
}
|
145
packages/core/src/render3/jit/compiler_facade_interface.ts
Normal file
145
packages/core/src/render3/jit/compiler_facade_interface.ts
Normal file
@ -0,0 +1,145 @@
|
||||
/**
|
||||
* @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
|
||||
*/
|
||||
|
||||
|
||||
/**
|
||||
* A set of interfaces which are shared between `@angular/core` and `@angular/compiler` to allow
|
||||
* for late binding of `@angular/compiler` for JIT purposes.
|
||||
*
|
||||
* This file has two copies. Please ensure that they are in sync:
|
||||
* - packages/compiler/src/compiler_facade_interface.ts (master)
|
||||
* - packages/core/src/render3/jit/compiler_facade_interface.ts (copy)
|
||||
*
|
||||
* Please ensure that the two files are in sync using this command:
|
||||
* ```
|
||||
* cp packages/compiler/src/compiler_facade_interface.ts \
|
||||
* packages/core/src/render3/jit/compiler_facade_interface.ts
|
||||
* ```
|
||||
*/
|
||||
|
||||
export interface ExportedCompilerFacade { ɵcompilerFacade: CompilerFacade; }
|
||||
|
||||
export interface CompilerFacade {
|
||||
compilePipe(angularCoreEnv: CoreEnvironment, sourceMapUrl: string, meta: R3PipeMetadataFacade):
|
||||
any;
|
||||
compileInjectable(
|
||||
angularCoreEnv: CoreEnvironment, sourceMapUrl: string, meta: R3InjectableMetadataFacade): any;
|
||||
compileInjector(
|
||||
angularCoreEnv: CoreEnvironment, sourceMapUrl: string, meta: R3InjectorMetadataFacade): any;
|
||||
compileNgModule(
|
||||
angularCoreEnv: CoreEnvironment, sourceMapUrl: string, meta: R3NgModuleMetadataFacade): any;
|
||||
compileDirective(
|
||||
angularCoreEnv: CoreEnvironment, sourceMapUrl: string, meta: R3DirectiveMetadataFacade): any;
|
||||
compileComponent(
|
||||
angularCoreEnv: CoreEnvironment, sourceMapUrl: string, meta: R3ComponentMetadataFacade): any;
|
||||
|
||||
R3ResolvedDependencyType: typeof R3ResolvedDependencyType;
|
||||
}
|
||||
|
||||
export interface CoreEnvironment { [name: string]: Function; }
|
||||
|
||||
export type StringMap = {
|
||||
[key: string]: string;
|
||||
};
|
||||
|
||||
export type StringMapWithRename = {
|
||||
[key: string]: string | [string, string];
|
||||
};
|
||||
|
||||
export type Provider = any;
|
||||
|
||||
export enum R3ResolvedDependencyType {
|
||||
Token = 0,
|
||||
Attribute = 1,
|
||||
}
|
||||
|
||||
export interface R3DependencyMetadataFacade {
|
||||
token: any;
|
||||
resolved: R3ResolvedDependencyType;
|
||||
host: boolean;
|
||||
optional: boolean;
|
||||
self: boolean;
|
||||
skipSelf: boolean;
|
||||
}
|
||||
|
||||
export interface R3PipeMetadataFacade {
|
||||
name: string;
|
||||
type: any;
|
||||
pipeName: string;
|
||||
deps: R3DependencyMetadataFacade[]|null;
|
||||
pure: boolean;
|
||||
}
|
||||
|
||||
export interface R3InjectableMetadataFacade {
|
||||
name: string;
|
||||
type: any;
|
||||
ctorDeps: R3DependencyMetadataFacade[]|null;
|
||||
providedIn: any;
|
||||
useClass?: any;
|
||||
useFactory?: any;
|
||||
useExisting?: any;
|
||||
useValue?: any;
|
||||
userDeps?: R3DependencyMetadataFacade[];
|
||||
}
|
||||
|
||||
export interface R3NgModuleMetadataFacade {
|
||||
type: any;
|
||||
bootstrap: Function[];
|
||||
declarations: Function[];
|
||||
imports: Function[];
|
||||
exports: Function[];
|
||||
emitInline: boolean;
|
||||
}
|
||||
|
||||
export interface R3InjectorMetadataFacade {
|
||||
name: string;
|
||||
type: any;
|
||||
deps: R3DependencyMetadataFacade[]|null;
|
||||
providers: any;
|
||||
imports: any;
|
||||
}
|
||||
|
||||
export interface R3DirectiveMetadataFacade {
|
||||
name: string;
|
||||
type: any;
|
||||
typeArgumentCount: number;
|
||||
typeSourceSpan: null;
|
||||
deps: R3DependencyMetadataFacade[]|null;
|
||||
selector: string|null;
|
||||
queries: R3QueryMetadataFacade[];
|
||||
host: {[key: string]: string};
|
||||
propMetadata: {[key: string]: any[]};
|
||||
lifecycle: {usesOnChanges: boolean;};
|
||||
inputs: string[];
|
||||
outputs: string[];
|
||||
usesInheritance: boolean;
|
||||
exportAs: string|null;
|
||||
providers: Provider[]|null;
|
||||
}
|
||||
|
||||
export interface R3ComponentMetadataFacade extends R3DirectiveMetadataFacade {
|
||||
template: string;
|
||||
preserveWhitespaces: boolean;
|
||||
animations: any[]|undefined;
|
||||
viewQueries: R3QueryMetadataFacade[];
|
||||
pipes: Map<string, any>;
|
||||
directives: Map<string, any>;
|
||||
styles: string[];
|
||||
encapsulation: ViewEncapsulation;
|
||||
viewProviders: Provider[]|null;
|
||||
}
|
||||
|
||||
export type ViewEncapsulation = number;
|
||||
|
||||
export interface R3QueryMetadataFacade {
|
||||
propertyName: string;
|
||||
first: boolean;
|
||||
predicate: any|string[];
|
||||
descendants: boolean;
|
||||
read: any|null;
|
||||
}
|
@ -6,23 +6,22 @@
|
||||
* found in the LICENSE file at https://angular.io/license
|
||||
*/
|
||||
|
||||
import {ConstantPool, Expression, R3DirectiveMetadata, R3QueryMetadata, WrappedNodeExpr, compileComponentFromMetadata as compileR3Component, compileDirectiveFromMetadata as compileR3Directive, jitExpression, makeBindingParser, parseHostBindings, parseTemplate} from '@angular/compiler';
|
||||
|
||||
import {Query} from '../../metadata/di';
|
||||
import {Component, Directive, HostBinding, HostListener, Input, Output} from '../../metadata/directives';
|
||||
import {Component, Directive} from '../../metadata/directives';
|
||||
import {componentNeedsResolution, maybeQueueResolutionOfComponentResources} from '../../metadata/resource_loading';
|
||||
import {ViewEncapsulation} from '../../metadata/view';
|
||||
import {Type} from '../../type';
|
||||
import {stringify} from '../../util';
|
||||
import {EMPTY_ARRAY} from '../definition';
|
||||
import {NG_COMPONENT_DEF, NG_DIRECTIVE_DEF} from '../fields';
|
||||
|
||||
import {R3DirectiveMetadataFacade, getCompilerFacade} from './compiler_facade';
|
||||
import {R3ComponentMetadataFacade, R3QueryMetadataFacade} from './compiler_facade_interface';
|
||||
import {angularCoreEnv} from './environment';
|
||||
import {patchComponentDefWithScope, transitiveScopesFor} from './module';
|
||||
import {getReflect, reflectDependencies} from './util';
|
||||
|
||||
type StringMap = {
|
||||
[key: string]: string
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* Compile an Angular component according to its decorator metadata, and patch the resulting
|
||||
@ -39,6 +38,7 @@ export function compileComponent(type: Type<any>, metadata: Component): void {
|
||||
maybeQueueResolutionOfComponentResources(metadata);
|
||||
Object.defineProperty(type, NG_COMPONENT_DEF, {
|
||||
get: () => {
|
||||
const compiler = getCompilerFacade();
|
||||
if (ngComponentDef === null) {
|
||||
if (componentNeedsResolution(metadata)) {
|
||||
const error = [`Component '${stringify(type)}' is not resolved:`];
|
||||
@ -51,43 +51,20 @@ export function compileComponent(type: Type<any>, metadata: Component): void {
|
||||
error.push(`Did you run and wait for 'resolveComponentResources()'?`);
|
||||
throw new Error(error.join('\n'));
|
||||
}
|
||||
// The ConstantPool is a requirement of the JIT'er.
|
||||
const constantPool = new ConstantPool();
|
||||
|
||||
// Parse the template and check for errors.
|
||||
const template = parseTemplate(
|
||||
metadata.template !, `ng://${stringify(type)}/template.html`, {
|
||||
preserveWhitespaces: metadata.preserveWhitespaces || false,
|
||||
},
|
||||
'');
|
||||
if (template.errors !== undefined) {
|
||||
const errors = template.errors.map(err => err.toString()).join(', ');
|
||||
throw new Error(
|
||||
`Errors during JIT compilation of template for ${stringify(type)}: ${errors}`);
|
||||
}
|
||||
|
||||
const animations =
|
||||
metadata.animations !== null ? new WrappedNodeExpr(metadata.animations) : null;
|
||||
|
||||
// Compile the component metadata, including template, into an expression.
|
||||
const res = compileR3Component(
|
||||
{
|
||||
...directiveMetadata(type, metadata),
|
||||
template,
|
||||
directives: new Map(),
|
||||
pipes: new Map(),
|
||||
viewQueries: extractQueriesMetadata(getReflect().propMetadata(type), isViewQuery),
|
||||
wrapDirectivesAndPipesInClosure: false,
|
||||
styles: metadata.styles || [],
|
||||
encapsulation: metadata.encapsulation || ViewEncapsulation.Emulated, animations,
|
||||
viewProviders: metadata.viewProviders ? new WrappedNodeExpr(metadata.viewProviders) :
|
||||
null
|
||||
},
|
||||
constantPool, makeBindingParser());
|
||||
const preStatements = [...constantPool.statements, ...res.statements];
|
||||
|
||||
ngComponentDef = jitExpression(
|
||||
res.expression, angularCoreEnv, `ng://${type.name}/ngComponentDef.js`, preStatements);
|
||||
const meta: R3ComponentMetadataFacade = {
|
||||
...directiveMetadata(type, metadata),
|
||||
template: metadata.template || '',
|
||||
preserveWhitespaces: metadata.preserveWhitespaces || false,
|
||||
styles: metadata.styles || EMPTY_ARRAY,
|
||||
animations: metadata.animations,
|
||||
viewQueries: extractQueriesMetadata(getReflect().propMetadata(type), isViewQuery),
|
||||
directives: new Map(),
|
||||
pipes: new Map(),
|
||||
encapsulation: metadata.encapsulation || ViewEncapsulation.Emulated,
|
||||
viewProviders: metadata.viewProviders || null,
|
||||
};
|
||||
ngComponentDef = compiler.compileComponent(
|
||||
angularCoreEnv, `ng://${stringify(type)}/template.html`, meta);
|
||||
|
||||
// If component compilation is async, then the @NgModule annotation which declares the
|
||||
// component may execute and set an ngSelectorScope property on the component type. This
|
||||
@ -122,12 +99,9 @@ export function compileDirective(type: Type<any>, directive: Directive): void {
|
||||
Object.defineProperty(type, NG_DIRECTIVE_DEF, {
|
||||
get: () => {
|
||||
if (ngDirectiveDef === null) {
|
||||
const constantPool = new ConstantPool();
|
||||
const sourceMapUrl = `ng://${type && type.name}/ngDirectiveDef.js`;
|
||||
const res = compileR3Directive(
|
||||
directiveMetadata(type, directive), constantPool, makeBindingParser());
|
||||
const preStatements = [...constantPool.statements, ...res.statements];
|
||||
ngDirectiveDef = jitExpression(res.expression, angularCoreEnv, sourceMapUrl, preStatements);
|
||||
const facade = directiveMetadata(type, directive);
|
||||
ngDirectiveDef = getCompilerFacade().compileDirective(
|
||||
angularCoreEnv, `ng://${type && type.name}/ngDirectiveDef.js`, facade);
|
||||
}
|
||||
return ngDirectiveDef;
|
||||
},
|
||||
@ -144,38 +118,20 @@ export function extendsDirectlyFromObject(type: Type<any>): boolean {
|
||||
* Extract the `R3DirectiveMetadata` for a particular directive (either a `Directive` or a
|
||||
* `Component`).
|
||||
*/
|
||||
function directiveMetadata(type: Type<any>, metadata: Directive): R3DirectiveMetadata {
|
||||
function directiveMetadata(type: Type<any>, metadata: Directive): R3DirectiveMetadataFacade {
|
||||
// Reflect inputs and outputs.
|
||||
const propMetadata = getReflect().propMetadata(type);
|
||||
|
||||
const host = extractHostBindings(metadata, propMetadata);
|
||||
|
||||
const inputsFromMetadata = parseInputOutputs(metadata.inputs || []);
|
||||
const outputsFromMetadata = parseInputOutputs(metadata.outputs || []);
|
||||
|
||||
const inputsFromType: {[key: string]: string | string[]} = {};
|
||||
const outputsFromType: StringMap = {};
|
||||
for (const field in propMetadata) {
|
||||
if (propMetadata.hasOwnProperty(field)) {
|
||||
propMetadata[field].forEach(ann => {
|
||||
if (isInput(ann)) {
|
||||
inputsFromType[field] =
|
||||
ann.bindingPropertyName ? [ann.bindingPropertyName, field] : field;
|
||||
} else if (isOutput(ann)) {
|
||||
outputsFromType[field] = ann.bindingPropertyName || field;
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
return {
|
||||
name: type.name,
|
||||
type: new WrappedNodeExpr(type),
|
||||
type: type,
|
||||
typeArgumentCount: 0,
|
||||
selector: metadata.selector !,
|
||||
deps: reflectDependencies(type), host,
|
||||
inputs: {...inputsFromMetadata, ...inputsFromType},
|
||||
outputs: {...outputsFromMetadata, ...outputsFromType},
|
||||
deps: reflectDependencies(type),
|
||||
host: metadata.host || EMPTY_OBJ,
|
||||
propMetadata: propMetadata,
|
||||
inputs: metadata.inputs || EMPTY_ARRAY,
|
||||
outputs: metadata.outputs || EMPTY_ARRAY,
|
||||
queries: extractQueriesMetadata(propMetadata, isContentQuery),
|
||||
lifecycle: {
|
||||
usesOnChanges: type.prototype.ngOnChanges !== undefined,
|
||||
@ -183,57 +139,29 @@ function directiveMetadata(type: Type<any>, metadata: Directive): R3DirectiveMet
|
||||
typeSourceSpan: null !,
|
||||
usesInheritance: !extendsDirectlyFromObject(type),
|
||||
exportAs: metadata.exportAs || null,
|
||||
providers: metadata.providers ? new WrappedNodeExpr(metadata.providers) : null
|
||||
providers: metadata.providers || null,
|
||||
};
|
||||
}
|
||||
|
||||
function extractHostBindings(metadata: Directive, propMetadata: {[key: string]: any[]}): {
|
||||
attributes: StringMap,
|
||||
listeners: StringMap,
|
||||
properties: StringMap,
|
||||
} {
|
||||
// First parse the declarations from the metadata.
|
||||
const {attributes, listeners, properties, animations} = parseHostBindings(metadata.host || {});
|
||||
const EMPTY_OBJ = {};
|
||||
|
||||
if (Object.keys(animations).length > 0) {
|
||||
throw new Error(`Animation bindings are as-of-yet unsupported in Ivy`);
|
||||
}
|
||||
|
||||
// Next, loop over the properties of the object, looking for @HostBinding and @HostListener.
|
||||
for (const field in propMetadata) {
|
||||
if (propMetadata.hasOwnProperty(field)) {
|
||||
propMetadata[field].forEach(ann => {
|
||||
if (isHostBinding(ann)) {
|
||||
properties[ann.hostPropertyName || field] = field;
|
||||
} else if (isHostListener(ann)) {
|
||||
listeners[ann.eventName || field] = `${field}(${(ann.args || []).join(',')})`;
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
return {attributes, listeners, properties};
|
||||
function convertToR3QueryPredicate(selector: any): any|string[] {
|
||||
return typeof selector === 'string' ? splitByComma(selector) : selector;
|
||||
}
|
||||
|
||||
function convertToR3QueryPredicate(selector: any): Expression|string[] {
|
||||
return typeof selector === 'string' ? splitByComma(selector) : new WrappedNodeExpr(selector);
|
||||
}
|
||||
|
||||
export function convertToR3QueryMetadata(propertyName: string, ann: Query): R3QueryMetadata {
|
||||
export function convertToR3QueryMetadata(propertyName: string, ann: Query): R3QueryMetadataFacade {
|
||||
return {
|
||||
propertyName: propertyName,
|
||||
predicate: convertToR3QueryPredicate(ann.selector),
|
||||
descendants: ann.descendants,
|
||||
first: ann.first,
|
||||
read: ann.read ? new WrappedNodeExpr(ann.read) : null
|
||||
read: ann.read ? ann.read : null
|
||||
};
|
||||
}
|
||||
|
||||
function extractQueriesMetadata(
|
||||
propMetadata: {[key: string]: any[]},
|
||||
isQueryAnn: (ann: any) => ann is Query): R3QueryMetadata[] {
|
||||
const queriesMeta: R3QueryMetadata[] = [];
|
||||
|
||||
isQueryAnn: (ann: any) => ann is Query): R3QueryMetadataFacade[] {
|
||||
const queriesMeta: R3QueryMetadataFacade[] = [];
|
||||
for (const field in propMetadata) {
|
||||
if (propMetadata.hasOwnProperty(field)) {
|
||||
propMetadata[field].forEach(ann => {
|
||||
@ -243,26 +171,9 @@ function extractQueriesMetadata(
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
return queriesMeta;
|
||||
}
|
||||
|
||||
function isInput(value: any): value is Input {
|
||||
return value.ngMetadataName === 'Input';
|
||||
}
|
||||
|
||||
function isOutput(value: any): value is Output {
|
||||
return value.ngMetadataName === 'Output';
|
||||
}
|
||||
|
||||
function isHostBinding(value: any): value is HostBinding {
|
||||
return value.ngMetadataName === 'HostBinding';
|
||||
}
|
||||
|
||||
function isHostListener(value: any): value is HostListener {
|
||||
return value.ngMetadataName === 'HostListener';
|
||||
}
|
||||
|
||||
function isContentQuery(value: any): value is Query {
|
||||
const name = value.ngMetadataName;
|
||||
return name === 'ContentChild' || name === 'ContentChildren';
|
||||
@ -276,13 +187,3 @@ function isViewQuery(value: any): value is Query {
|
||||
function splitByComma(value: string): string[] {
|
||||
return value.split(',').map(piece => piece.trim());
|
||||
}
|
||||
|
||||
function parseInputOutputs(values: string[]): StringMap {
|
||||
return values.reduce(
|
||||
(map, value) => {
|
||||
const [field, property] = splitByComma(value);
|
||||
map[field] = property || field;
|
||||
return map;
|
||||
},
|
||||
{} as StringMap);
|
||||
}
|
||||
|
@ -6,14 +6,13 @@
|
||||
* found in the LICENSE file at https://angular.io/license
|
||||
*/
|
||||
|
||||
import {Expression, LiteralExpr, R3DependencyMetadata, R3InjectableMetadata, WrappedNodeExpr, compileInjectable as compileR3Injectable, jitExpression} from '@angular/compiler';
|
||||
|
||||
import {Injectable} from '../../di/injectable';
|
||||
import {ClassSansProvider, ExistingSansProvider, FactorySansProvider, StaticClassSansProvider, ValueProvider, ValueSansProvider} from '../../di/provider';
|
||||
import {ClassSansProvider, ExistingSansProvider, FactorySansProvider, ValueProvider, ValueSansProvider} from '../../di/provider';
|
||||
import {Type} from '../../type';
|
||||
import {getClosureSafeProperty} from '../../util/property';
|
||||
import {NG_INJECTABLE_DEF} from '../fields';
|
||||
|
||||
import {R3InjectableMetadataFacade, getCompilerFacade} from './compiler_facade';
|
||||
import {angularCoreEnv} from './environment';
|
||||
import {convertDependencies, reflectDependencies} from './util';
|
||||
|
||||
@ -31,84 +30,60 @@ export function compileInjectable(type: Type<any>, srcMeta?: Injectable): void {
|
||||
Object.defineProperty(type, NG_INJECTABLE_DEF, {
|
||||
get: () => {
|
||||
if (def === null) {
|
||||
// Check whether the injectable metadata includes a provider specification.
|
||||
const meta: Injectable = srcMeta || {providedIn: null};
|
||||
const hasAProvider = isUseClassProvider(meta) || isUseFactoryProvider(meta) ||
|
||||
isUseValueProvider(meta) || isUseExistingProvider(meta);
|
||||
|
||||
const ctorDeps = reflectDependencies(type);
|
||||
|
||||
let userDeps: R3DependencyMetadata[]|undefined = undefined;
|
||||
const compilerMeta: R3InjectableMetadataFacade = {
|
||||
name: type.name,
|
||||
type: type,
|
||||
providedIn: meta.providedIn,
|
||||
ctorDeps: reflectDependencies(type),
|
||||
userDeps: undefined
|
||||
};
|
||||
if ((isUseClassProvider(meta) || isUseFactoryProvider(meta)) && meta.deps !== undefined) {
|
||||
userDeps = convertDependencies(meta.deps);
|
||||
compilerMeta.userDeps = convertDependencies(meta.deps);
|
||||
}
|
||||
|
||||
// Decide which flavor of factory to generate, based on the provider specified.
|
||||
// Only one of the use* fields should be set.
|
||||
let useClass: Expression|undefined = undefined;
|
||||
let useFactory: Expression|undefined = undefined;
|
||||
let useValue: Expression|undefined = undefined;
|
||||
let useExisting: Expression|undefined = undefined;
|
||||
|
||||
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.
|
||||
useClass = new WrappedNodeExpr(type);
|
||||
compilerMeta.useClass = type;
|
||||
} else if (isUseClassProvider(meta)) {
|
||||
// The user explicitly specified useClass, and may or may not have provided deps.
|
||||
useClass = new WrappedNodeExpr(meta.useClass);
|
||||
compilerMeta.useClass = meta.useClass;
|
||||
} else if (isUseValueProvider(meta)) {
|
||||
// The user explicitly specified useValue.
|
||||
useValue = new WrappedNodeExpr(meta.useValue);
|
||||
compilerMeta.useValue = meta.useValue;
|
||||
} else if (isUseFactoryProvider(meta)) {
|
||||
// The user explicitly specified useFactory.
|
||||
useFactory = new WrappedNodeExpr(meta.useFactory);
|
||||
compilerMeta.useFactory = meta.useFactory;
|
||||
} else if (isUseExistingProvider(meta)) {
|
||||
// The user explicitly specified useExisting.
|
||||
useExisting = new WrappedNodeExpr(meta.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.`);
|
||||
}
|
||||
|
||||
const {expression, statements} = compileR3Injectable({
|
||||
name: type.name,
|
||||
type: new WrappedNodeExpr(type),
|
||||
providedIn: computeProvidedIn(meta.providedIn),
|
||||
useClass,
|
||||
useFactory,
|
||||
useValue,
|
||||
useExisting,
|
||||
ctorDeps,
|
||||
userDeps,
|
||||
});
|
||||
|
||||
def = jitExpression(
|
||||
expression, angularCoreEnv, `ng://${type.name}/ngInjectableDef.js`, statements);
|
||||
def = getCompilerFacade().compileInjectable(
|
||||
angularCoreEnv, `ng://${type.name}/ngInjectableDef.js`, compilerMeta);
|
||||
}
|
||||
return def;
|
||||
},
|
||||
});
|
||||
}
|
||||
|
||||
function computeProvidedIn(providedIn: Type<any>| string | null | undefined): Expression {
|
||||
if (providedIn == null || typeof providedIn === 'string') {
|
||||
return new LiteralExpr(providedIn);
|
||||
} else {
|
||||
return new WrappedNodeExpr(providedIn);
|
||||
}
|
||||
}
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
const USE_VALUE =
|
||||
getClosureSafeProperty<ValueProvider>({provide: String, useValue: getClosureSafeProperty});
|
||||
|
||||
function isUseValueProvider(meta: Injectable): meta is Injectable&ValueSansProvider {
|
||||
return USE_VALUE in meta;
|
||||
}
|
||||
|
@ -6,14 +6,13 @@
|
||||
* found in the LICENSE file at https://angular.io/license
|
||||
*/
|
||||
|
||||
import {Expression, R3InjectorMetadata, R3NgModuleMetadata, R3Reference, WrappedNodeExpr, compileInjector, compileNgModule as compileR3NgModule, jitExpression} from '@angular/compiler';
|
||||
|
||||
import {ModuleWithProviders, NgModule, NgModuleDef, NgModuleTransitiveScopes} from '../../metadata/ng_module';
|
||||
import {Type} from '../../type';
|
||||
import {getComponentDef, getDirectiveDef, getNgModuleDef, getPipeDef} from '../definition';
|
||||
import {NG_COMPONENT_DEF, NG_DIRECTIVE_DEF, NG_INJECTOR_DEF, NG_MODULE_DEF, NG_PIPE_DEF} from '../fields';
|
||||
import {ComponentDef} from '../interfaces/definition';
|
||||
|
||||
import {R3InjectorMetadataFacade, getCompilerFacade} from './compiler_facade';
|
||||
import {angularCoreEnv} from './environment';
|
||||
import {reflectDependencies} from './util';
|
||||
|
||||
@ -37,48 +36,39 @@ export function compileNgModuleDefs(moduleType: Type<any>, ngModule: NgModule):
|
||||
|
||||
let ngModuleDef: any = null;
|
||||
Object.defineProperty(moduleType, NG_MODULE_DEF, {
|
||||
configurable: true,
|
||||
get: () => {
|
||||
if (ngModuleDef === null) {
|
||||
const meta: R3NgModuleMetadata = {
|
||||
type: wrap(moduleType),
|
||||
bootstrap: flatten(ngModule.bootstrap || EMPTY_ARRAY).map(wrapReference),
|
||||
declarations: declarations.map(wrapReference),
|
||||
imports: flatten(ngModule.imports || EMPTY_ARRAY)
|
||||
.map(expandModuleWithProviders)
|
||||
.map(wrapReference),
|
||||
exports: flatten(ngModule.exports || EMPTY_ARRAY)
|
||||
.map(expandModuleWithProviders)
|
||||
.map(wrapReference),
|
||||
emitInline: true,
|
||||
};
|
||||
const res = compileR3NgModule(meta);
|
||||
ngModuleDef = jitExpression(
|
||||
res.expression, angularCoreEnv, `ng://${moduleType.name}/ngModuleDef.js`, []);
|
||||
ngModuleDef = getCompilerFacade().compileNgModule(
|
||||
angularCoreEnv, `ng://${moduleType.name}/ngModuleDef.js`, {
|
||||
type: moduleType,
|
||||
bootstrap: flatten(ngModule.bootstrap || EMPTY_ARRAY),
|
||||
declarations: declarations,
|
||||
imports: flatten(ngModule.imports || EMPTY_ARRAY).map(expandModuleWithProviders),
|
||||
exports: flatten(ngModule.exports || EMPTY_ARRAY).map(expandModuleWithProviders),
|
||||
emitInline: true,
|
||||
});
|
||||
}
|
||||
return ngModuleDef;
|
||||
},
|
||||
// Make the property configurable in dev mode to allow overriding in tests
|
||||
configurable: !!ngDevMode,
|
||||
}
|
||||
});
|
||||
|
||||
let ngInjectorDef: any = null;
|
||||
Object.defineProperty(moduleType, NG_INJECTOR_DEF, {
|
||||
get: () => {
|
||||
if (ngInjectorDef === null) {
|
||||
const meta: R3InjectorMetadata = {
|
||||
const meta: R3InjectorMetadataFacade = {
|
||||
name: moduleType.name,
|
||||
type: wrap(moduleType),
|
||||
type: moduleType,
|
||||
deps: reflectDependencies(moduleType),
|
||||
providers: new WrappedNodeExpr(ngModule.providers || EMPTY_ARRAY),
|
||||
imports: new WrappedNodeExpr([
|
||||
providers: ngModule.providers || EMPTY_ARRAY,
|
||||
imports: [
|
||||
ngModule.imports || EMPTY_ARRAY,
|
||||
ngModule.exports || EMPTY_ARRAY,
|
||||
]),
|
||||
],
|
||||
};
|
||||
const res = compileInjector(meta);
|
||||
ngInjectorDef = jitExpression(
|
||||
res.expression, angularCoreEnv, `ng://${moduleType.name}/ngInjectorDef.js`,
|
||||
res.statements);
|
||||
ngInjectorDef = getCompilerFacade().compileInjector(
|
||||
angularCoreEnv, `ng://${moduleType.name}/ngInjectorDef.js`, meta);
|
||||
}
|
||||
return ngInjectorDef;
|
||||
},
|
||||
@ -235,15 +225,6 @@ function expandModuleWithProviders(value: Type<any>| ModuleWithProviders<{}>): T
|
||||
return value;
|
||||
}
|
||||
|
||||
function wrap(value: Type<any>): Expression {
|
||||
return new WrappedNodeExpr(value);
|
||||
}
|
||||
|
||||
function wrapReference(value: Type<any>): R3Reference {
|
||||
const wrapped = wrap(value);
|
||||
return {value: wrapped, type: wrapped};
|
||||
}
|
||||
|
||||
function isModuleWithProviders(value: any): value is ModuleWithProviders<{}> {
|
||||
return (value as{ngModule?: any}).ngModule !== undefined;
|
||||
}
|
||||
|
@ -6,13 +6,12 @@
|
||||
* found in the LICENSE file at https://angular.io/license
|
||||
*/
|
||||
|
||||
import {WrappedNodeExpr, compilePipeFromMetadata, jitExpression} from '@angular/compiler';
|
||||
|
||||
import {Pipe} from '../../metadata/directives';
|
||||
import {Type} from '../../type';
|
||||
import {NG_PIPE_DEF} from '../fields';
|
||||
import {stringify} from '../util';
|
||||
|
||||
import {getCompilerFacade} from './compiler_facade';
|
||||
import {angularCoreEnv} from './environment';
|
||||
import {reflectDependencies} from './util';
|
||||
|
||||
@ -21,18 +20,14 @@ export function compilePipe(type: Type<any>, meta: Pipe): void {
|
||||
Object.defineProperty(type, NG_PIPE_DEF, {
|
||||
get: () => {
|
||||
if (ngPipeDef === null) {
|
||||
const sourceMapUrl = `ng://${stringify(type)}/ngPipeDef.js`;
|
||||
|
||||
const name = type.name;
|
||||
const res = compilePipeFromMetadata({
|
||||
name,
|
||||
type: new WrappedNodeExpr(type),
|
||||
deps: reflectDependencies(type),
|
||||
pipeName: meta.name,
|
||||
pure: meta.pure !== undefined ? meta.pure : true,
|
||||
});
|
||||
|
||||
ngPipeDef = jitExpression(res.expression, angularCoreEnv, sourceMapUrl, res.statements);
|
||||
ngPipeDef = getCompilerFacade().compilePipe(
|
||||
angularCoreEnv, `ng://${stringify(type)}/ngPipeDef.js`, {
|
||||
type: type,
|
||||
name: type.name,
|
||||
deps: reflectDependencies(type),
|
||||
pipeName: meta.name,
|
||||
pure: meta.pure !== undefined ? meta.pure : true
|
||||
});
|
||||
}
|
||||
return ngPipeDef;
|
||||
},
|
||||
|
@ -6,44 +6,41 @@
|
||||
* found in the LICENSE file at https://angular.io/license
|
||||
*/
|
||||
|
||||
import {LiteralExpr, R3DependencyMetadata, R3ResolvedDependencyType, WrappedNodeExpr} from '@angular/compiler';
|
||||
|
||||
import {Injector} from '../../di/injector';
|
||||
import {Host, Inject, Optional, Self, SkipSelf} from '../../di/metadata';
|
||||
import {ElementRef} from '../../linker/element_ref';
|
||||
import {TemplateRef} from '../../linker/template_ref';
|
||||
import {ViewContainerRef} from '../../linker/view_container_ref';
|
||||
import {Attribute} from '../../metadata/di';
|
||||
import {ReflectionCapabilities} from '../../reflection/reflection_capabilities';
|
||||
import {Type} from '../../type';
|
||||
|
||||
import {CompilerFacade, R3DependencyMetadataFacade, getCompilerFacade} from './compiler_facade';
|
||||
|
||||
let _reflect: ReflectionCapabilities|null = null;
|
||||
|
||||
export function getReflect(): ReflectionCapabilities {
|
||||
return (_reflect = _reflect || new ReflectionCapabilities());
|
||||
}
|
||||
|
||||
export function reflectDependencies(type: Type<any>): R3DependencyMetadata[] {
|
||||
export function reflectDependencies(type: Type<any>): R3DependencyMetadataFacade[] {
|
||||
return convertDependencies(getReflect().parameters(type));
|
||||
}
|
||||
|
||||
export function convertDependencies(deps: any[]): R3DependencyMetadata[] {
|
||||
return deps.map(dep => reflectDependency(dep));
|
||||
export function convertDependencies(deps: any[]): R3DependencyMetadataFacade[] {
|
||||
const compiler = getCompilerFacade();
|
||||
return deps.map(dep => reflectDependency(compiler, dep));
|
||||
}
|
||||
|
||||
function reflectDependency(dep: any | any[]): R3DependencyMetadata {
|
||||
const meta: R3DependencyMetadata = {
|
||||
token: new LiteralExpr(null),
|
||||
function reflectDependency(compiler: CompilerFacade, dep: any | any[]): R3DependencyMetadataFacade {
|
||||
const meta: R3DependencyMetadataFacade = {
|
||||
token: null,
|
||||
host: false,
|
||||
optional: false,
|
||||
resolved: R3ResolvedDependencyType.Token,
|
||||
resolved: compiler.R3ResolvedDependencyType.Token,
|
||||
self: false,
|
||||
skipSelf: false,
|
||||
};
|
||||
|
||||
function setTokenAndResolvedType(token: any): void {
|
||||
meta.resolved = R3ResolvedDependencyType.Token;
|
||||
meta.token = new WrappedNodeExpr(token);
|
||||
meta.resolved = compiler.R3ResolvedDependencyType.Token;
|
||||
meta.token = token;
|
||||
}
|
||||
|
||||
if (Array.isArray(dep)) {
|
||||
@ -61,13 +58,13 @@ function reflectDependency(dep: any | any[]): R3DependencyMetadata {
|
||||
} else if (param instanceof Host || param.__proto__.ngMetadataName === 'Host') {
|
||||
meta.host = true;
|
||||
} else if (param instanceof Inject) {
|
||||
meta.token = new WrappedNodeExpr(param.token);
|
||||
meta.token = param.token;
|
||||
} else if (param instanceof Attribute) {
|
||||
if (param.attributeName === undefined) {
|
||||
throw new Error(`Attribute name must be defined.`);
|
||||
}
|
||||
meta.token = new LiteralExpr(param.attributeName);
|
||||
meta.resolved = R3ResolvedDependencyType.Attribute;
|
||||
meta.token = param.attributeName;
|
||||
meta.resolved = compiler.R3ResolvedDependencyType.Attribute;
|
||||
} else {
|
||||
setTokenAndResolvedType(param);
|
||||
}
|
||||
|
Reference in New Issue
Block a user