feat(ivy): JIT support for compilation of @Pipes (#24703)
Adds support for compiling @Pipe in JIT mode, along with tests to verify that certain aspects of compilation are correct. PR Close #24703
This commit is contained in:
parent
dbdcfed2bd
commit
3d52174bf1
|
@ -11,3 +11,4 @@ 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_DIRECTIVE: ((type: any, meta: any) => void)|null = null;
|
||||||
export const R3_COMPILE_INJECTABLE: ((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;
|
export const R3_COMPILE_NGMODULE: ((type: any, meta: any) => void)|null = null;
|
||||||
|
export const R3_COMPILE_PIPE: ((type: any, meta: any) => void)|null = null;
|
||||||
|
|
|
@ -9,9 +9,11 @@
|
||||||
import {compileComponent, compileDirective} from './render3/jit/directive';
|
import {compileComponent, compileDirective} from './render3/jit/directive';
|
||||||
import {compileInjectable} from './render3/jit/injectable';
|
import {compileInjectable} from './render3/jit/injectable';
|
||||||
import {compileNgModule} from './render3/jit/module';
|
import {compileNgModule} from './render3/jit/module';
|
||||||
|
import {compilePipe} from './render3/jit/pipe';
|
||||||
|
|
||||||
export const ivyEnabled = true;
|
export const ivyEnabled = true;
|
||||||
export const R3_COMPILE_COMPONENT = compileComponent;
|
export const R3_COMPILE_COMPONENT = compileComponent;
|
||||||
export const R3_COMPILE_DIRECTIVE = compileDirective;
|
export const R3_COMPILE_DIRECTIVE = compileDirective;
|
||||||
export const R3_COMPILE_INJECTABLE = compileInjectable;
|
export const R3_COMPILE_INJECTABLE = compileInjectable;
|
||||||
export const R3_COMPILE_NGMODULE = compileNgModule;
|
export const R3_COMPILE_NGMODULE = compileNgModule;
|
||||||
|
export const R3_COMPILE_PIPE = compilePipe;
|
||||||
|
|
|
@ -8,7 +8,7 @@
|
||||||
|
|
||||||
import {ChangeDetectionStrategy} from '../change_detection/constants';
|
import {ChangeDetectionStrategy} from '../change_detection/constants';
|
||||||
import {Provider} from '../di';
|
import {Provider} from '../di';
|
||||||
import {R3_COMPILE_COMPONENT, R3_COMPILE_DIRECTIVE} from '../ivy_switch';
|
import {R3_COMPILE_COMPONENT, R3_COMPILE_DIRECTIVE, R3_COMPILE_PIPE} from '../ivy_switch';
|
||||||
import {Type} from '../type';
|
import {Type} from '../type';
|
||||||
import {TypeDecorator, makeDecorator, makePropDecorator} from '../util/decorators';
|
import {TypeDecorator, makeDecorator, makePropDecorator} from '../util/decorators';
|
||||||
import {ViewEncapsulation} from './view';
|
import {ViewEncapsulation} from './view';
|
||||||
|
@ -810,7 +810,9 @@ export interface Pipe {
|
||||||
*
|
*
|
||||||
* @Annotation
|
* @Annotation
|
||||||
*/
|
*/
|
||||||
export const Pipe: PipeDecorator = makeDecorator('Pipe', (p: Pipe) => ({pure: true, ...p}));
|
export const Pipe: PipeDecorator = makeDecorator(
|
||||||
|
'Pipe', (p: Pipe) => ({pure: true, ...p}), undefined, undefined,
|
||||||
|
(type: Type<any>, meta: Pipe) => (R3_COMPILE_PIPE || (() => {}))(type, meta));
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
|
@ -0,0 +1,40 @@
|
||||||
|
/**
|
||||||
|
* @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 {Expression, WrappedNodeExpr, compilePipeFromMetadata, jitExpression} from '@angular/compiler';
|
||||||
|
|
||||||
|
import {Pipe} from '../../metadata/directives';
|
||||||
|
import {Type} from '../../type';
|
||||||
|
import {stringify} from '../util';
|
||||||
|
|
||||||
|
import {angularCoreEnv} from './environment';
|
||||||
|
import {NG_PIPE_DEF} from './fields';
|
||||||
|
import {reflectDependencies} from './util';
|
||||||
|
|
||||||
|
export function compilePipe(type: Type<any>, meta: Pipe): void {
|
||||||
|
let def: any = null;
|
||||||
|
Object.defineProperty(type, NG_PIPE_DEF, {
|
||||||
|
get: () => {
|
||||||
|
if (def === 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,
|
||||||
|
});
|
||||||
|
|
||||||
|
def = jitExpression(res.expression, angularCoreEnv, sourceMapUrl);
|
||||||
|
}
|
||||||
|
return def;
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
|
@ -12,9 +12,9 @@ import {InjectorDef, defineInjectable} from '@angular/core/src/di/defs';
|
||||||
import {Injectable} from '@angular/core/src/di/injectable';
|
import {Injectable} from '@angular/core/src/di/injectable';
|
||||||
import {inject, setCurrentInjector} from '@angular/core/src/di/injector';
|
import {inject, setCurrentInjector} from '@angular/core/src/di/injector';
|
||||||
import {ivyEnabled} from '@angular/core/src/ivy_switch';
|
import {ivyEnabled} from '@angular/core/src/ivy_switch';
|
||||||
import {Component, HostBinding, HostListener} from '@angular/core/src/metadata/directives';
|
import {Component, HostBinding, HostListener, Pipe} from '@angular/core/src/metadata/directives';
|
||||||
import {NgModule, NgModuleDefInternal} from '@angular/core/src/metadata/ng_module';
|
import {NgModule, NgModuleDefInternal} from '@angular/core/src/metadata/ng_module';
|
||||||
import {ComponentDefInternal} from '@angular/core/src/render3/interfaces/definition';
|
import {ComponentDefInternal, PipeDefInternal} from '@angular/core/src/render3/interfaces/definition';
|
||||||
|
|
||||||
ivyEnabled && describe('render3 jit', () => {
|
ivyEnabled && describe('render3 jit', () => {
|
||||||
let injector: any;
|
let injector: any;
|
||||||
|
@ -212,6 +212,27 @@ ivyEnabled && describe('render3 jit', () => {
|
||||||
expect(cmpDef.hostBindings).toBeDefined();
|
expect(cmpDef.hostBindings).toBeDefined();
|
||||||
expect(cmpDef.hostBindings !.length).toBe(2);
|
expect(cmpDef.hostBindings !.length).toBe(2);
|
||||||
});
|
});
|
||||||
|
|
||||||
|
it('should compile @Pipes without errors', () => {
|
||||||
|
@Pipe({name: 'test-pipe', pure: false})
|
||||||
|
class P {
|
||||||
|
}
|
||||||
|
|
||||||
|
const pipeDef = (P as any).ngPipeDef as PipeDefInternal<P>;
|
||||||
|
expect(pipeDef.name).toBe('test-pipe');
|
||||||
|
expect(pipeDef.pure).toBe(false, 'pipe should not be pure');
|
||||||
|
expect(pipeDef.factory() instanceof P)
|
||||||
|
.toBe(true, 'factory() should create an instance of the pipe');
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should default @Pipe to pure: true', () => {
|
||||||
|
@Pipe({name: 'test-pipe'})
|
||||||
|
class P {
|
||||||
|
}
|
||||||
|
|
||||||
|
const pipeDef = (P as any).ngPipeDef as PipeDefInternal<P>;
|
||||||
|
expect(pipeDef.pure).toBe(true, 'pipe should be pure');
|
||||||
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
it('ensure at least one spec exists', () => {});
|
it('ensure at least one spec exists', () => {});
|
||||||
|
|
|
@ -16,6 +16,7 @@ const INTERFACE_EXCEPTIONS = new Set<string>([
|
||||||
'DirectiveDef',
|
'DirectiveDef',
|
||||||
'InjectorDef',
|
'InjectorDef',
|
||||||
'NgModuleDef',
|
'NgModuleDef',
|
||||||
|
'ɵPipeDef',
|
||||||
]);
|
]);
|
||||||
|
|
||||||
describe('r3 jit environment', () => {
|
describe('r3 jit environment', () => {
|
||||||
|
|
Loading…
Reference in New Issue