feat(ivy): JIT renders the TODO app (#24138)
This commit builds out enough of the JIT compiler to render //packages/core/test/bundling/todo, and allows the tests to run in JIT mode. To play with the app, run: bazel run --define=compile=jit //packages/core/test/bundling/todo:prodserver PR Close #24138
This commit is contained in:

committed by
Victor Berchet

parent
24e5c5b425
commit
646b42a113
@ -8,5 +8,6 @@
|
||||
|
||||
export const ivyEnabled = false;
|
||||
export const R3_COMPILE_COMPONENT: ((type: any, meta: any) => void)|null = null;
|
||||
export const R3_COMPILE_DIRECTIVE: ((type: any, meta: any) => void)|null = null;
|
||||
export const R3_COMPILE_INJECTABLE: ((type: any, meta: any) => void)|null = null;
|
||||
export const R3_COMPILE_NGMODULE: ((type: any, meta: any) => void)|null = null;
|
||||
|
@ -6,11 +6,12 @@
|
||||
* found in the LICENSE file at https://angular.io/license
|
||||
*/
|
||||
|
||||
import {compileComponentDecorator} from './render3/jit/directive';
|
||||
import {compileComponentDecorator, compileDirective} from './render3/jit/directive';
|
||||
import {compileInjectable} from './render3/jit/injectable';
|
||||
import {compileNgModule} from './render3/jit/module';
|
||||
|
||||
export const ivyEnabled = true;
|
||||
export const R3_COMPILE_COMPONENT = compileComponentDecorator;
|
||||
export const R3_COMPILE_DIRECTIVE = compileDirective;
|
||||
export const R3_COMPILE_INJECTABLE = compileInjectable;
|
||||
export const R3_COMPILE_NGMODULE = compileNgModule;
|
||||
|
@ -8,7 +8,7 @@
|
||||
|
||||
import {ChangeDetectionStrategy} from '../change_detection/constants';
|
||||
import {Provider} from '../di';
|
||||
import {R3_COMPILE_COMPONENT} from '../ivy_switch';
|
||||
import {R3_COMPILE_COMPONENT, R3_COMPILE_DIRECTIVE} from '../ivy_switch';
|
||||
import {Type} from '../type';
|
||||
import {TypeDecorator, makeDecorator, makePropDecorator} from '../util/decorators';
|
||||
import {ViewEncapsulation} from './view';
|
||||
@ -400,8 +400,9 @@ export interface Directive {
|
||||
*
|
||||
* @Annotation
|
||||
*/
|
||||
export const Directive: DirectiveDecorator =
|
||||
makeDecorator('Directive', (dir: Directive = {}) => dir);
|
||||
export const Directive: DirectiveDecorator = makeDecorator(
|
||||
'Directive', (dir: Directive = {}) => dir, undefined, undefined,
|
||||
(type: Type<any>, meta: Directive) => (R3_COMPILE_DIRECTIVE || (() => {}))(type, meta));
|
||||
|
||||
/**
|
||||
* Type of the Component decorator / constructor function.
|
||||
|
@ -6,14 +6,14 @@
|
||||
* found in the LICENSE file at https://angular.io/license
|
||||
*/
|
||||
|
||||
import {compileComponent as compileIvyComponent, parseTemplate, ConstantPool, makeBindingParser, WrappedNodeExpr, jitPatchDefinition,} from '@angular/compiler';
|
||||
import {ConstantPool, R3DirectiveMetadata, WrappedNodeExpr, compileComponentFromMetadata as compileIvyComponent, compileDirectiveFromMetadata as compileIvyDirective, jitExpression, makeBindingParser, parseTemplate} from '@angular/compiler';
|
||||
|
||||
import {Component} from '../../metadata/directives';
|
||||
import {Component, Directive, HostBinding, Input, Output} from '../../metadata/directives';
|
||||
import {ReflectionCapabilities} from '../../reflection/reflection_capabilities';
|
||||
import {Type} from '../../type';
|
||||
|
||||
import {angularCoreEnv} from './environment';
|
||||
import {reflectDependencies} from './util';
|
||||
import {getReflect, reflectDependencies} from './util';
|
||||
|
||||
let _pendingPromises: Promise<void>[] = [];
|
||||
|
||||
@ -31,45 +31,65 @@ export function compileComponent(type: Type<any>, metadata: Component): Promise<
|
||||
if (!metadata.template) {
|
||||
throw new Error('templateUrl not yet supported');
|
||||
}
|
||||
const templateStr = metadata.template;
|
||||
|
||||
// Parse the template and check for errors.
|
||||
const template = parseTemplate(metadata.template !, `ng://${type.name}/template.html`);
|
||||
if (template.errors !== undefined) {
|
||||
const errors = template.errors.map(err => err.toString()).join(', ');
|
||||
throw new Error(`Errors during JIT compilation of template for ${type.name}: ${errors}`);
|
||||
}
|
||||
let def: any = null;
|
||||
Object.defineProperty(type, 'ngComponentDef', {
|
||||
get: () => {
|
||||
if (def === null) {
|
||||
// The ConstantPool is a requirement of the JIT'er.
|
||||
const constantPool = new ConstantPool();
|
||||
|
||||
// The ConstantPool is a requirement of the JIT'er.
|
||||
const constantPool = new ConstantPool();
|
||||
// Parse the template and check for errors.
|
||||
const template = parseTemplate(templateStr, `ng://${type.name}/template.html`);
|
||||
if (template.errors !== undefined) {
|
||||
const errors = template.errors.map(err => err.toString()).join(', ');
|
||||
throw new Error(`Errors during JIT compilation of template for ${type.name}: ${errors}`);
|
||||
}
|
||||
|
||||
// Compile the component metadata, including template, into an expression.
|
||||
// TODO(alxhub): implement inputs, outputs, queries, etc.
|
||||
const res = compileIvyComponent(
|
||||
{
|
||||
name: type.name,
|
||||
type: new WrappedNodeExpr(type),
|
||||
selector: metadata.selector !, template,
|
||||
deps: reflectDependencies(type),
|
||||
directives: new Map(),
|
||||
pipes: new Map(),
|
||||
host: {
|
||||
attributes: {},
|
||||
listeners: {},
|
||||
properties: {},
|
||||
},
|
||||
inputs: {},
|
||||
outputs: {},
|
||||
lifecycle: {
|
||||
usesOnChanges: false,
|
||||
},
|
||||
queries: [],
|
||||
typeSourceSpan: null !,
|
||||
viewQueries: [],
|
||||
},
|
||||
constantPool, makeBindingParser());
|
||||
// Compile the component metadata, including template, into an expression.
|
||||
// TODO(alxhub): implement inputs, outputs, queries, etc.
|
||||
const res = compileIvyComponent(
|
||||
{
|
||||
...directiveMetadata(type, metadata),
|
||||
template,
|
||||
directives: new Map(),
|
||||
pipes: new Map(),
|
||||
viewQueries: [],
|
||||
},
|
||||
constantPool, makeBindingParser());
|
||||
|
||||
// Patch the generated expression as ngComponentDef on the type.
|
||||
jitPatchDefinition(type, 'ngComponentDef', res.expression, angularCoreEnv, constantPool);
|
||||
def = jitExpression(
|
||||
res.expression, angularCoreEnv, `ng://${type.name}/ngComponentDef.js`, constantPool);
|
||||
}
|
||||
return def;
|
||||
},
|
||||
});
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Compile an Angular directive according to its decorator metadata, and patch the resulting
|
||||
* ngDirectiveDef onto the component type.
|
||||
*
|
||||
* In the event that compilation is not immediate, `compileDirective` will return a `Promise` which
|
||||
* will resolve when compilation completes and the directive becomes usable.
|
||||
*/
|
||||
export function compileDirective(type: Type<any>, directive: Directive): Promise<void>|null {
|
||||
let def: any = null;
|
||||
Object.defineProperty(type, 'ngDirectiveDef', {
|
||||
get: () => {
|
||||
if (def === null) {
|
||||
const constantPool = new ConstantPool();
|
||||
const sourceMapUrl = `ng://${type && type.name}/ngDirectiveDef.js`;
|
||||
const res = compileIvyDirective(
|
||||
directiveMetadata(type, directive), constantPool, makeBindingParser());
|
||||
def = jitExpression(res.expression, angularCoreEnv, sourceMapUrl, constantPool);
|
||||
}
|
||||
return def;
|
||||
},
|
||||
});
|
||||
return null;
|
||||
}
|
||||
|
||||
@ -95,3 +115,51 @@ export function awaitCurrentlyCompilingComponents(): Promise<void> {
|
||||
_pendingPromises = [];
|
||||
return res;
|
||||
}
|
||||
|
||||
/**
|
||||
* Extract the `R3DirectiveMetadata` for a particular directive (either a `Directive` or a
|
||||
* `Component`).
|
||||
*/
|
||||
function directiveMetadata(type: Type<any>, metadata: Directive): R3DirectiveMetadata {
|
||||
// Reflect inputs and outputs.
|
||||
const props = getReflect().propMetadata(type);
|
||||
const inputs: {[key: string]: string} = {};
|
||||
const outputs: {[key: string]: string} = {};
|
||||
|
||||
for (let field in props) {
|
||||
props[field].forEach(ann => {
|
||||
if (isInput(ann)) {
|
||||
inputs[field] = ann.bindingPropertyName || field;
|
||||
} else if (isOutput(ann)) {
|
||||
outputs[field] = ann.bindingPropertyName || field;
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
return {
|
||||
name: type.name,
|
||||
type: new WrappedNodeExpr(type),
|
||||
selector: metadata.selector !,
|
||||
deps: reflectDependencies(type),
|
||||
host: {
|
||||
attributes: {},
|
||||
listeners: {},
|
||||
properties: {},
|
||||
},
|
||||
inputs,
|
||||
outputs,
|
||||
queries: [],
|
||||
lifecycle: {
|
||||
usesOnChanges: type.prototype.ngOnChanges !== undefined,
|
||||
},
|
||||
typeSourceSpan: null !,
|
||||
};
|
||||
}
|
||||
|
||||
function isInput(value: any): value is Input {
|
||||
return value.ngMetadataName === 'Input';
|
||||
}
|
||||
|
||||
function isOutput(value: any): value is Output {
|
||||
return value.ngMetadataName === 'Output';
|
||||
}
|
||||
|
@ -17,15 +17,37 @@ import * as r3 from '../index';
|
||||
*
|
||||
* This should be kept up to date with the public exports of @angular/core.
|
||||
*/
|
||||
export const angularCoreEnv = {
|
||||
export const angularCoreEnv: {[name: string]: Function} = {
|
||||
'ɵdefineComponent': r3.defineComponent,
|
||||
'ɵdefineDirective': r3.defineDirective,
|
||||
'defineInjectable': defineInjectable,
|
||||
'ɵdefineNgModule': defineNgModule,
|
||||
'ɵdirectiveInject': r3.directiveInject,
|
||||
'inject': inject,
|
||||
'ɵinjectAttribute': r3.injectAttribute,
|
||||
'ɵinjectChangeDetectorRef': r3.injectChangeDetectorRef,
|
||||
'ɵinjectElementRef': r3.injectElementRef,
|
||||
'ɵinjectTemplateRef': r3.injectTemplateRef,
|
||||
'ɵinjectViewContainerRef': r3.injectViewContainerRef,
|
||||
'ɵNgOnChangesFeature': r3.NgOnChangesFeature,
|
||||
'ɵa': r3.a,
|
||||
'ɵb': r3.b,
|
||||
'ɵC': r3.C,
|
||||
'ɵcR': r3.cR,
|
||||
'ɵcr': r3.cr,
|
||||
'ɵd': r3.d,
|
||||
'ɵE': r3.E,
|
||||
'ɵe': r3.e,
|
||||
'ɵf0': r3.f0,
|
||||
'ɵf1': r3.f1,
|
||||
'ɵf2': r3.f2,
|
||||
'ɵf3': r3.f3,
|
||||
'ɵf4': r3.f4,
|
||||
'ɵf5': r3.f5,
|
||||
'ɵf6': r3.f6,
|
||||
'ɵf7': r3.f7,
|
||||
'ɵf8': r3.f8,
|
||||
'ɵfV': r3.fV,
|
||||
'ɵi1': r3.i1,
|
||||
'ɵi2': r3.i2,
|
||||
'ɵi3': r3.i3,
|
||||
@ -34,6 +56,23 @@ export const angularCoreEnv = {
|
||||
'ɵi6': r3.i6,
|
||||
'ɵi7': r3.i7,
|
||||
'ɵi8': r3.i8,
|
||||
'ɵk': r3.k,
|
||||
'ɵkn': r3.kn,
|
||||
'ɵL': r3.L,
|
||||
'ɵld': r3.ld,
|
||||
'ɵp': r3.p,
|
||||
'ɵpb1': r3.pb1,
|
||||
'ɵpb2': r3.pb2,
|
||||
'ɵpb3': r3.pb3,
|
||||
'ɵpb4': r3.pb4,
|
||||
'ɵpbV': r3.pbV,
|
||||
'ɵQ': r3.Q,
|
||||
'ɵqR': r3.qR,
|
||||
'ɵs': r3.s,
|
||||
'ɵsn': r3.sn,
|
||||
'ɵst': r3.st,
|
||||
'ɵT': r3.T,
|
||||
'ɵt': r3.t,
|
||||
'ɵV': r3.V,
|
||||
'ɵv': r3.v,
|
||||
};
|
||||
|
@ -6,7 +6,7 @@
|
||||
* found in the LICENSE file at https://angular.io/license
|
||||
*/
|
||||
|
||||
import {Expression, LiteralExpr, R3DependencyMetadata, WrappedNodeExpr, compileInjectable as compileIvyInjectable, jitPatchDefinition} from '@angular/compiler';
|
||||
import {Expression, LiteralExpr, R3DependencyMetadata, WrappedNodeExpr, compileInjectable as compileIvyInjectable, jitExpression} from '@angular/compiler';
|
||||
|
||||
import {Injectable} from '../../di/injectable';
|
||||
import {ClassSansProvider, ExistingSansProvider, FactorySansProvider, StaticClassSansProvider, ValueProvider, ValueSansProvider} from '../../di/provider';
|
||||
@ -27,60 +27,69 @@ export function compileInjectable(type: Type<any>, meta?: Injectable): void {
|
||||
return;
|
||||
}
|
||||
|
||||
// Check whether the injectable metadata includes a provider specification.
|
||||
const hasAProvider = isUseClassProvider(meta) || isUseFactoryProvider(meta) ||
|
||||
isUseValueProvider(meta) || isUseExistingProvider(meta);
|
||||
let def: any = null;
|
||||
Object.defineProperty(type, 'ngInjectableDef', {
|
||||
get: () => {
|
||||
if (def === null) {
|
||||
// Check whether the injectable metadata includes a provider specification.
|
||||
const hasAProvider = isUseClassProvider(meta) || isUseFactoryProvider(meta) ||
|
||||
isUseValueProvider(meta) || isUseExistingProvider(meta);
|
||||
|
||||
let deps: R3DependencyMetadata[]|undefined = undefined;
|
||||
if (!hasAProvider || (isUseClassProvider(meta) && type === meta.useClass)) {
|
||||
deps = reflectDependencies(type);
|
||||
} else if (isUseClassProvider(meta)) {
|
||||
deps = meta.deps && convertDependencies(meta.deps);
|
||||
} else if (isUseFactoryProvider(meta)) {
|
||||
deps = meta.deps && convertDependencies(meta.deps) || [];
|
||||
}
|
||||
let deps: R3DependencyMetadata[]|undefined = undefined;
|
||||
if (!hasAProvider || (isUseClassProvider(meta) && type === meta.useClass)) {
|
||||
deps = reflectDependencies(type);
|
||||
} else if (isUseClassProvider(meta)) {
|
||||
deps = meta.deps && convertDependencies(meta.deps);
|
||||
} else if (isUseFactoryProvider(meta)) {
|
||||
deps = meta.deps && 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;
|
||||
// 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);
|
||||
} else if (isUseClassProvider(meta)) {
|
||||
// The user explicitly specified useClass, and may or may not have provided deps.
|
||||
useClass = new WrappedNodeExpr(meta.useClass);
|
||||
} else if (isUseValueProvider(meta)) {
|
||||
// The user explicitly specified useValue.
|
||||
useValue = new WrappedNodeExpr(meta.useValue);
|
||||
} else if (isUseFactoryProvider(meta)) {
|
||||
// The user explicitly specified useFactory.
|
||||
useFactory = new WrappedNodeExpr(meta.useFactory);
|
||||
} else if (isUseExistingProvider(meta)) {
|
||||
// The user explicitly specified useExisting.
|
||||
useExisting = new WrappedNodeExpr(meta.useExisting);
|
||||
} else {
|
||||
// Can't happen - either hasAProvider will be false, or one of the providers will be set.
|
||||
throw new Error(`Unreachable state.`);
|
||||
}
|
||||
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);
|
||||
} else if (isUseClassProvider(meta)) {
|
||||
// The user explicitly specified useClass, and may or may not have provided deps.
|
||||
useClass = new WrappedNodeExpr(meta.useClass);
|
||||
} else if (isUseValueProvider(meta)) {
|
||||
// The user explicitly specified useValue.
|
||||
useValue = new WrappedNodeExpr(meta.useValue);
|
||||
} else if (isUseFactoryProvider(meta)) {
|
||||
// The user explicitly specified useFactory.
|
||||
useFactory = new WrappedNodeExpr(meta.useFactory);
|
||||
} else if (isUseExistingProvider(meta)) {
|
||||
// The user explicitly specified useExisting.
|
||||
useExisting = new WrappedNodeExpr(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} = compileIvyInjectable({
|
||||
name: type.name,
|
||||
type: new WrappedNodeExpr(type),
|
||||
providedIn: computeProvidedIn(meta.providedIn),
|
||||
useClass,
|
||||
useFactory,
|
||||
useValue,
|
||||
useExisting,
|
||||
deps,
|
||||
const {expression} = compileIvyInjectable({
|
||||
name: type.name,
|
||||
type: new WrappedNodeExpr(type),
|
||||
providedIn: computeProvidedIn(meta.providedIn),
|
||||
useClass,
|
||||
useFactory,
|
||||
useValue,
|
||||
useExisting,
|
||||
deps,
|
||||
});
|
||||
|
||||
def = jitExpression(expression, angularCoreEnv, `ng://${type.name}/ngInjectableDef.js`);
|
||||
}
|
||||
return def;
|
||||
},
|
||||
});
|
||||
|
||||
jitPatchDefinition(type, 'ngInjectableDef', expression, angularCoreEnv);
|
||||
}
|
||||
|
||||
function computeProvidedIn(providedIn: Type<any>| string | null | undefined): Expression {
|
||||
|
@ -6,7 +6,7 @@
|
||||
* found in the LICENSE file at https://angular.io/license
|
||||
*/
|
||||
|
||||
import {Expression, R3NgModuleMetadata, WrappedNodeExpr, compileNgModule as compileIvyNgModule, jitPatchDefinition} from '@angular/compiler';
|
||||
import {Expression, R3NgModuleMetadata, WrappedNodeExpr, compileNgModule as compileIvyNgModule, jitExpression} from '@angular/compiler';
|
||||
|
||||
import {ModuleWithProviders, NgModule, NgModuleDef} from '../../metadata/ng_module';
|
||||
import {Type} from '../../type';
|
||||
@ -33,17 +33,6 @@ export function compileNgModule(type: Type<any>, ngModule: NgModule): void {
|
||||
directives: [] as any[],
|
||||
pipes: [] as any[],
|
||||
};
|
||||
flatten(ngModule.declarations || EMPTY_ARRAY).forEach(decl => {
|
||||
if (decl.ngPipeDef) {
|
||||
transitiveCompileScope.pipes.push(decl);
|
||||
} else if (decl.ngComponentDef) {
|
||||
transitiveCompileScope.directives.push(decl);
|
||||
patchComponentWithScope(decl, type as any);
|
||||
} else {
|
||||
transitiveCompileScope.directives.push(decl);
|
||||
decl.ngSelectorScope = type;
|
||||
}
|
||||
});
|
||||
|
||||
function addExportsFrom(module: Type<any>& {ngModuleDef: NgModuleDef<any>}): void {
|
||||
module.ngModuleDef.exports.forEach((exp: any) => {
|
||||
@ -60,16 +49,49 @@ export function compileNgModule(type: Type<any>, ngModule: NgModule): void {
|
||||
flatten([(ngModule.imports || EMPTY_ARRAY), (ngModule.exports || EMPTY_ARRAY)])
|
||||
.filter(importExport => isNgModule(importExport))
|
||||
.forEach(mod => addExportsFrom(mod));
|
||||
jitPatchDefinition(type, 'ngModuleDef', res.expression, angularCoreEnv);
|
||||
((type as any).ngModuleDef as NgModuleDef<any>).transitiveCompileScope = transitiveCompileScope;
|
||||
|
||||
flatten(ngModule.declarations || EMPTY_ARRAY).forEach(decl => {
|
||||
if (decl.ngPipeDef) {
|
||||
transitiveCompileScope.pipes.push(decl);
|
||||
} else if (decl.ngComponentDef) {
|
||||
transitiveCompileScope.directives.push(decl);
|
||||
patchComponentWithScope(decl, type as any);
|
||||
} else {
|
||||
transitiveCompileScope.directives.push(decl);
|
||||
decl.ngSelectorScope = type;
|
||||
}
|
||||
});
|
||||
|
||||
let def: any = null;
|
||||
Object.defineProperty(type, 'ngModuleDef', {
|
||||
get: () => {
|
||||
if (def === null) {
|
||||
const meta: R3NgModuleMetadata = {
|
||||
type: wrap(type),
|
||||
bootstrap: flatten(ngModule.bootstrap || EMPTY_ARRAY).map(wrap),
|
||||
declarations: flatten(ngModule.declarations || EMPTY_ARRAY).map(wrap),
|
||||
imports:
|
||||
flatten(ngModule.imports || EMPTY_ARRAY).map(expandModuleWithProviders).map(wrap),
|
||||
exports:
|
||||
flatten(ngModule.exports || EMPTY_ARRAY).map(expandModuleWithProviders).map(wrap),
|
||||
emitInline: true,
|
||||
};
|
||||
const res = compileIvyNgModule(meta);
|
||||
def = jitExpression(res.expression, angularCoreEnv, `ng://${type.name}/ngModuleDef.js`);
|
||||
def.transitiveCompileScope = transitiveCompileScope;
|
||||
}
|
||||
return def;
|
||||
},
|
||||
});
|
||||
}
|
||||
|
||||
export function patchComponentWithScope<C, M>(
|
||||
component: Type<C>& {ngComponentDef: ComponentDef<C>},
|
||||
module: Type<M>& {ngModuleDef: NgModuleDef<M>}) {
|
||||
component.ngComponentDef.directiveDefs = () =>
|
||||
module.ngModuleDef.transitiveCompileScope !.directives.map(
|
||||
dir => dir.ngDirectiveDef || dir.ngComponentDef);
|
||||
module.ngModuleDef.transitiveCompileScope !.directives
|
||||
.map(dir => dir.ngDirectiveDef || dir.ngComponentDef)
|
||||
.filter(def => !!def);
|
||||
component.ngComponentDef.pipeDefs = () =>
|
||||
module.ngModuleDef.transitiveCompileScope !.pipes.map(pipe => pipe.ngPipeDef);
|
||||
}
|
||||
|
@ -19,9 +19,12 @@ import {Type} from '../../type';
|
||||
|
||||
let _reflect: ReflectionCapabilities|null = null;
|
||||
|
||||
export function getReflect(): ReflectionCapabilities {
|
||||
return (_reflect = _reflect || new ReflectionCapabilities());
|
||||
}
|
||||
|
||||
export function reflectDependencies(type: Type<any>): R3DependencyMetadata[] {
|
||||
_reflect = _reflect || new ReflectionCapabilities();
|
||||
return convertDependencies(_reflect.parameters(type));
|
||||
return convertDependencies(getReflect().parameters(type));
|
||||
}
|
||||
|
||||
export function convertDependencies(deps: any[]): R3DependencyMetadata[] {
|
||||
|
@ -20,7 +20,10 @@ const __window = typeof window !== 'undefined' && window;
|
||||
const __self = typeof self !== 'undefined' && typeof WorkerGlobalScope !== 'undefined' &&
|
||||
self instanceof WorkerGlobalScope && self;
|
||||
const __global = typeof global !== 'undefined' && global;
|
||||
const _global: {[name: string]: any} = __window || __global || __self;
|
||||
|
||||
// Check __global first, because in Node tests both __global and __window may be defined and _global
|
||||
// should be __global in that case.
|
||||
const _global: {[name: string]: any} = __global || __window || __self;
|
||||
|
||||
const promise: Promise<any> = Promise.resolve(0);
|
||||
/**
|
||||
|
Reference in New Issue
Block a user