refactor(compiler-cli): implement `ɵɵngDeclarePipe()` (#40803)

This commit implements creating of `ɵɵngDeclarePipe()` calls in partial
compilation, and processing of those calls in the linker and JIT compiler.

See #40677

PR Close #40803
This commit is contained in:
Pete Bacon Darwin 2021-02-11 14:42:10 +00:00 committed by Joey Perrott
parent 6425a6d543
commit 9cb43fb507
26 changed files with 265 additions and 46 deletions

View File

@ -14,10 +14,12 @@ import {LinkerEnvironment} from '../linker_environment';
import {PartialComponentLinkerVersion1} from './partial_component_linker_1';
import {PartialDirectiveLinkerVersion1} from './partial_directive_linker_1';
import {PartialLinker} from './partial_linker';
import {PartialPipeLinkerVersion1} from './partial_pipe_linker_1';
export const ɵɵngDeclareDirective = 'ɵɵngDeclareDirective';
export const ɵɵngDeclareComponent = 'ɵɵngDeclareComponent';
export const declarationFunctions = [ɵɵngDeclareDirective, ɵɵngDeclareComponent];
export const ɵɵngDeclarePipe = 'ɵɵngDeclarePipe';
export const declarationFunctions = [ɵɵngDeclareDirective, ɵɵngDeclareComponent, ɵɵngDeclarePipe];
interface LinkerRange<TExpression> {
range: string;
@ -81,6 +83,7 @@ export class PartialLinkerSelector<TStatement, TExpression> {
const partialComponentLinkerVersion1 = new PartialComponentLinkerVersion1(
environment, createGetSourceFile(sourceUrl, code, environment.sourceFileLoader), sourceUrl,
code);
const partialPipeLinkerVersion1 = new PartialPipeLinkerVersion1();
const linkers = new Map<string, LinkerRange<TExpression>[]>();
linkers.set(ɵɵngDeclareDirective, [
@ -91,6 +94,10 @@ export class PartialLinkerSelector<TStatement, TExpression> {
{range: '0.0.0-PLACEHOLDER', linker: partialComponentLinkerVersion1},
{range: '>=11.1.0-next.1', linker: partialComponentLinkerVersion1},
]);
linkers.set(ɵɵngDeclarePipe, [
{range: '0.0.0-PLACEHOLDER', linker: partialPipeLinkerVersion1},
{range: '>=11.1.0-next.1', linker: partialPipeLinkerVersion1},
]);
return linkers;
}
}

View File

@ -0,0 +1,58 @@
/**
* @license
* Copyright Google LLC 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 {compilePipeFromMetadata, ConstantPool, R3DeclarePipeMetadata, R3PartialDeclaration, R3PipeMetadata, R3Reference} from '@angular/compiler';
import * as o from '@angular/compiler/src/output/output_ast';
import {AstObject} from '../../ast/ast_value';
import {FatalLinkerError} from '../../fatal_linker_error';
import {PartialLinker} from './partial_linker';
/**
* A `PartialLinker` that is designed to process `ɵɵngDeclarePipe()` call expressions.
*/
export class PartialPipeLinkerVersion1<TExpression> implements PartialLinker<TExpression> {
constructor() {}
linkPartialDeclaration(
constantPool: ConstantPool,
metaObj: AstObject<R3PartialDeclaration, TExpression>): o.Expression {
const meta = toR3PipeMeta(metaObj);
const def = compilePipeFromMetadata(meta);
return def.expression;
}
}
/**
* Derives the `R3PipeMetadata` structure from the AST object.
*/
export function toR3PipeMeta<TExpression>(metaObj: AstObject<R3DeclarePipeMetadata, TExpression>):
R3PipeMetadata {
const typeExpr = metaObj.getValue('type');
const typeName = typeExpr.getSymbolName();
if (typeName === null) {
throw new FatalLinkerError(
typeExpr.expression, 'Unsupported type, its name could not be determined');
}
const pure = metaObj.has('pure') ? metaObj.getBoolean('pure') : true;
return {
name: typeName,
type: wrapReference(typeExpr.getOpaque()),
internalType: metaObj.getOpaque('type'),
typeArgumentCount: 0,
deps: null,
pipeName: metaObj.getString('name'),
pure,
};
}
function wrapReference<TExpression>(wrapped: o.WrappedNodeExpr<TExpression>): R3Reference {
return {value: wrapped, type: wrapped};
}

View File

@ -17,6 +17,7 @@ import {LinkerEnvironment} from '../../../src/file_linker/linker_environment';
import {PartialComponentLinkerVersion1} from '../../../src/file_linker/partial_linkers/partial_component_linker_1';
import {PartialDirectiveLinkerVersion1} from '../../../src/file_linker/partial_linkers/partial_directive_linker_1';
import {PartialLinkerSelector} from '../../../src/file_linker/partial_linkers/partial_linker_selector';
import {PartialPipeLinkerVersion1} from '../../../src/file_linker/partial_linkers/partial_pipe_linker_1';
describe('PartialLinkerSelector', () => {
const options: LinkerOptions = {
@ -42,6 +43,7 @@ describe('PartialLinkerSelector', () => {
environment, fs.resolve('/some/path/to/file.js'), 'some file contents');
expect(selector.supportsDeclaration('ɵɵngDeclareDirective')).toBe(true);
expect(selector.supportsDeclaration('ɵɵngDeclareComponent')).toBe(true);
expect(selector.supportsDeclaration('ɵɵngDeclarePipe')).toBe(true);
expect(selector.supportsDeclaration('$foo')).toBe(false);
});
@ -60,6 +62,8 @@ describe('PartialLinkerSelector', () => {
.toBeInstanceOf(PartialDirectiveLinkerVersion1);
expect(selector.getLinker('ɵɵngDeclareComponent', '0.0.0-PLACEHOLDER'))
.toBeInstanceOf(PartialComponentLinkerVersion1);
expect(selector.getLinker('ɵɵngDeclarePipe', '0.0.0-PLACEHOLDER'))
.toBeInstanceOf(PartialPipeLinkerVersion1);
});
it('should return the linker that matches the name and valid full version', () => {

View File

@ -6,7 +6,7 @@
* found in the LICENSE file at https://angular.io/license
*/
import {compilePipeFromMetadata, Identifiers, R3FactoryTarget, R3PipeMetadata, Statement, WrappedNodeExpr} from '@angular/compiler';
import {compileDeclarePipeFromMetadata, compilePipeFromMetadata, Identifiers, R3FactoryTarget, R3PipeDef, R3PipeMetadata, Statement, WrappedNodeExpr} from '@angular/compiler';
import * as ts from 'typescript';
import {ErrorCode, FatalDiagnosticError} from '../../diagnostics';
@ -134,10 +134,18 @@ export class PipeDecoratorHandler implements DecoratorHandler<Decorator, PipeHan
}
compileFull(node: ClassDeclaration, analysis: Readonly<PipeHandlerData>): CompileResult[] {
const meta = analysis.meta;
const res = compilePipeFromMetadata(meta);
const res = compilePipeFromMetadata(analysis.meta);
return this.compilePipe(analysis, res);
}
compilePartial(node: ClassDeclaration, analysis: Readonly<PipeHandlerData>): CompileResult[] {
const res = compileDeclarePipeFromMetadata(analysis.meta);
return this.compilePipe(analysis, res);
}
private compilePipe(analysis: Readonly<PipeHandlerData>, def: R3PipeDef) {
const factoryRes = compileNgFactoryDefField({
...meta,
...analysis.meta,
injectFn: Identifiers.directiveInject,
target: R3FactoryTarget.Pipe,
});
@ -147,9 +155,9 @@ export class PipeDecoratorHandler implements DecoratorHandler<Decorator, PipeHan
return [
factoryRes, {
name: 'ɵpipe',
initializer: res.expression,
initializer: def.expression,
statements: [],
type: res.type,
type: def.type,
}
];
}

View File

@ -72,7 +72,7 @@ HostBindingComp.ɵcmp = i0.ɵɵngDeclareComponent({ version: "0.0.0-PLACEHOLDER"
class MyForwardPipe {
}
MyForwardPipe.ɵfac = function MyForwardPipe_Factory(t) { return new (t || MyForwardPipe)(); };
MyForwardPipe.ɵpipe = i0.ɵɵdefinePipe({ name: "my_forward_pipe", type: MyForwardPipe, pure: true });
MyForwardPipe.ɵpipe = i0.ɵɵngDeclarePipe({ version: "0.0.0-PLACEHOLDER", ngImport: i0, type: MyForwardPipe, name: "my_forward_pipe" });
(function () { (typeof ngDevMode === "undefined" || ngDevMode) && i0.ɵsetClassMetadata(MyForwardPipe, [{
type: Pipe,
args: [{ name: 'my_forward_pipe' }]

View File

@ -10,7 +10,7 @@ export class MyPipe {
ngOnDestroy() { }
}
MyPipe.ɵfac = function MyPipe_Factory(t) { return new (t || MyPipe)(); };
MyPipe.ɵpipe = i0.ɵɵdefinePipe({ name: "myPipe", type: MyPipe, pure: false });
MyPipe.ɵpipe = i0.ɵɵngDeclarePipe({ version: "0.0.0-PLACEHOLDER", ngImport: i0, type: MyPipe, name: "myPipe", pure: false });
(function () { (typeof ngDevMode === "undefined" || ngDevMode) && i0.ɵsetClassMetadata(MyPipe, [{
type: Pipe,
args: [{ name: 'myPipe', pure: false }]
@ -21,7 +21,7 @@ export class MyPurePipe {
}
}
MyPurePipe.ɵfac = function MyPurePipe_Factory(t) { return new (t || MyPurePipe)(); };
MyPurePipe.ɵpipe = i0.ɵɵdefinePipe({ name: "myPurePipe", type: MyPurePipe, pure: true });
MyPurePipe.ɵpipe = i0.ɵɵngDeclarePipe({ version: "0.0.0-PLACEHOLDER", ngImport: i0, type: MyPurePipe, name: "myPurePipe" });
(function () { (typeof ngDevMode === "undefined" || ngDevMode) && i0.ɵsetClassMetadata(MyPurePipe, [{
type: Pipe,
args: [{
@ -93,7 +93,7 @@ export class MyPipe {
ngOnDestroy() { }
}
MyPipe.ɵfac = function MyPipe_Factory(t) { return new (t || MyPipe)(); };
MyPipe.ɵpipe = i0.ɵɵdefinePipe({ name: "myPipe", type: MyPipe, pure: false });
MyPipe.ɵpipe = i0.ɵɵngDeclarePipe({ version: "0.0.0-PLACEHOLDER", ngImport: i0, type: MyPipe, name: "myPipe", pure: false });
(function () { (typeof ngDevMode === "undefined" || ngDevMode) && i0.ɵsetClassMetadata(MyPipe, [{
type: Pipe,
args: [{ name: 'myPipe', pure: false }]
@ -155,7 +155,7 @@ export class MyPipe {
}
}
MyPipe.ɵfac = function MyPipe_Factory(t) { return new (t || MyPipe)(i0.ɵɵinjectPipeChangeDetectorRef()); };
MyPipe.ɵpipe = i0.ɵɵdefinePipe({ name: "myPipe", type: MyPipe, pure: true });
MyPipe.ɵpipe = i0.ɵɵngDeclarePipe({ version: "0.0.0-PLACEHOLDER", ngImport: i0, type: MyPipe, name: "myPipe" });
(function () { (typeof ngDevMode === "undefined" || ngDevMode) && i0.ɵsetClassMetadata(MyPipe, [{
type: Pipe,
args: [{ name: 'myPipe' }]
@ -167,7 +167,7 @@ export class MyOtherPipe {
}
}
MyOtherPipe.ɵfac = function MyOtherPipe_Factory(t) { return new (t || MyOtherPipe)(i0.ɵɵinjectPipeChangeDetectorRef(8)); };
MyOtherPipe.ɵpipe = i0.ɵɵdefinePipe({ name: "myOtherPipe", type: MyOtherPipe, pure: true });
MyOtherPipe.ɵpipe = i0.ɵɵngDeclarePipe({ version: "0.0.0-PLACEHOLDER", ngImport: i0, type: MyOtherPipe, name: "myOtherPipe" });
(function () { (typeof ngDevMode === "undefined" || ngDevMode) && i0.ɵsetClassMetadata(MyOtherPipe, [{
type: Pipe,
args: [{ name: 'myOtherPipe' }]

View File

@ -318,7 +318,7 @@ export class PipePipe {
transform(v, a, a2) { }
}
PipePipe.ɵfac = function PipePipe_Factory(t) { return new (t || PipePipe)(); };
PipePipe.ɵpipe = i0.ɵɵdefinePipe({ name: "pipe", type: PipePipe, pure: true });
PipePipe.ɵpipe = i0.ɵɵngDeclarePipe({ version: "0.0.0-PLACEHOLDER", ngImport: i0, type: PipePipe, name: "pipe" });
(function () { (typeof ngDevMode === "undefined" || ngDevMode) && i0.ɵsetClassMetadata(PipePipe, [{
type: Pipe,
args: [{ name: 'pipe' }]

View File

@ -211,7 +211,7 @@ export class AsyncPipe {
transform(v) { }
}
AsyncPipe.ɵfac = function AsyncPipe_Factory(t) { return new (t || AsyncPipe)(); };
AsyncPipe.ɵpipe = i0.ɵɵdefinePipe({ name: "async", type: AsyncPipe, pure: true });
AsyncPipe.ɵpipe = i0.ɵɵngDeclarePipe({ version: "0.0.0-PLACEHOLDER", ngImport: i0, type: AsyncPipe, name: "async" });
(function () { (typeof ngDevMode === "undefined" || ngDevMode) && i0.ɵsetClassMetadata(AsyncPipe, [{
type: Pipe,
args: [{ name: 'async' }]

View File

@ -297,7 +297,7 @@ export class MyPipe {
}
}
MyPipe.ɵfac = function MyPipe_Factory(t) { return new (t || MyPipe)(i0.ɵɵdirectiveInject(Service)); };
MyPipe.ɵpipe = i0.ɵɵdefinePipe({ name: "myPipe", type: MyPipe, pure: true });
MyPipe.ɵpipe = i0.ɵɵngDeclarePipe({ version: "0.0.0-PLACEHOLDER", ngImport: i0, type: MyPipe, name: "myPipe" });
MyPipe.ɵprov = i0.ɵɵdefineInjectable({ token: MyPipe, factory: MyPipe.ɵfac });
(function () { (typeof ngDevMode === "undefined" || ngDevMode) && i0.ɵsetClassMetadata(MyPipe, [{
type: Injectable
@ -312,7 +312,7 @@ export class MyOtherPipe {
}
}
MyOtherPipe.ɵfac = function MyOtherPipe_Factory(t) { return new (t || MyOtherPipe)(i0.ɵɵdirectiveInject(Service)); };
MyOtherPipe.ɵpipe = i0.ɵɵdefinePipe({ name: "myOtherPipe", type: MyOtherPipe, pure: true });
MyOtherPipe.ɵpipe = i0.ɵɵngDeclarePipe({ version: "0.0.0-PLACEHOLDER", ngImport: i0, type: MyOtherPipe, name: "myOtherPipe" });
MyOtherPipe.ɵprov = i0.ɵɵdefineInjectable({ token: MyOtherPipe, factory: MyOtherPipe.ɵfac });
(function () { (typeof ngDevMode === "undefined" || ngDevMode) && i0.ɵsetClassMetadata(MyOtherPipe, [{
type: Pipe,

View File

@ -201,7 +201,7 @@ export class UppercasePipe {
transform(v) { }
}
UppercasePipe.ɵfac = function UppercasePipe_Factory(t) { return new (t || UppercasePipe)(); };
UppercasePipe.ɵpipe = i0.ɵɵdefinePipe({ name: "uppercase", type: UppercasePipe, pure: true });
UppercasePipe.ɵpipe = i0.ɵɵngDeclarePipe({ version: "0.0.0-PLACEHOLDER", ngImport: i0, type: UppercasePipe, name: "uppercase" });
(function () { (typeof ngDevMode === "undefined" || ngDevMode) && i0.ɵsetClassMetadata(UppercasePipe, [{
type: Pipe,
args: [{ name: 'uppercase' }]
@ -450,7 +450,7 @@ export class UppercasePipe {
transform(v) { }
}
UppercasePipe.ɵfac = function UppercasePipe_Factory(t) { return new (t || UppercasePipe)(); };
UppercasePipe.ɵpipe = i0.ɵɵdefinePipe({ name: "uppercase", type: UppercasePipe, pure: true });
UppercasePipe.ɵpipe = i0.ɵɵngDeclarePipe({ version: "0.0.0-PLACEHOLDER", ngImport: i0, type: UppercasePipe, name: "uppercase" });
(function () { (typeof ngDevMode === "undefined" || ngDevMode) && i0.ɵsetClassMetadata(UppercasePipe, [{
type: Pipe,
args: [{ name: 'uppercase' }]
@ -546,7 +546,7 @@ export class UppercasePipe {
transform(v) { }
}
UppercasePipe.ɵfac = function UppercasePipe_Factory(t) { return new (t || UppercasePipe)(); };
UppercasePipe.ɵpipe = i0.ɵɵdefinePipe({ name: "uppercase", type: UppercasePipe, pure: true });
UppercasePipe.ɵpipe = i0.ɵɵngDeclarePipe({ version: "0.0.0-PLACEHOLDER", ngImport: i0, type: UppercasePipe, name: "uppercase" });
(function () { (typeof ngDevMode === "undefined" || ngDevMode) && i0.ɵsetClassMetadata(UppercasePipe, [{
type: Pipe,
args: [{ name: 'uppercase' }]
@ -608,7 +608,7 @@ export class UppercasePipe {
transform(v) { }
}
UppercasePipe.ɵfac = function UppercasePipe_Factory(t) { return new (t || UppercasePipe)(); };
UppercasePipe.ɵpipe = i0.ɵɵdefinePipe({ name: "uppercase", type: UppercasePipe, pure: true });
UppercasePipe.ɵpipe = i0.ɵɵngDeclarePipe({ version: "0.0.0-PLACEHOLDER", ngImport: i0, type: UppercasePipe, name: "uppercase" });
(function () { (typeof ngDevMode === "undefined" || ngDevMode) && i0.ɵsetClassMetadata(UppercasePipe, [{
type: Pipe,
args: [{ name: 'uppercase' }]

View File

@ -341,7 +341,7 @@ export class AsyncPipe {
transform(v) { }
}
AsyncPipe.ɵfac = function AsyncPipe_Factory(t) { return new (t || AsyncPipe)(); };
AsyncPipe.ɵpipe = i0.ɵɵdefinePipe({ name: "async", type: AsyncPipe, pure: true });
AsyncPipe.ɵpipe = i0.ɵɵngDeclarePipe({ version: "0.0.0-PLACEHOLDER", ngImport: i0, type: AsyncPipe, name: "async" });
(function () { (typeof ngDevMode === "undefined" || ngDevMode) && i0.ɵsetClassMetadata(AsyncPipe, [{
type: Pipe,
args: [{ name: 'async' }]
@ -407,7 +407,7 @@ export class UppercasePipe {
transform(v) { }
}
UppercasePipe.ɵfac = function UppercasePipe_Factory(t) { return new (t || UppercasePipe)(); };
UppercasePipe.ɵpipe = i0.ɵɵdefinePipe({ name: "uppercase", type: UppercasePipe, pure: true });
UppercasePipe.ɵpipe = i0.ɵɵngDeclarePipe({ version: "0.0.0-PLACEHOLDER", ngImport: i0, type: UppercasePipe, name: "uppercase" });
(function () { (typeof ngDevMode === "undefined" || ngDevMode) && i0.ɵsetClassMetadata(UppercasePipe, [{
type: Pipe,
args: [{ name: 'uppercase' }]
@ -480,7 +480,7 @@ export class UppercasePipe {
transform(v) { }
}
UppercasePipe.ɵfac = function UppercasePipe_Factory(t) { return new (t || UppercasePipe)(); };
UppercasePipe.ɵpipe = i0.ɵɵdefinePipe({ name: "uppercase", type: UppercasePipe, pure: true });
UppercasePipe.ɵpipe = i0.ɵɵngDeclarePipe({ version: "0.0.0-PLACEHOLDER", ngImport: i0, type: UppercasePipe, name: "uppercase" });
(function () { (typeof ngDevMode === "undefined" || ngDevMode) && i0.ɵsetClassMetadata(UppercasePipe, [{
type: Pipe,
args: [{ name: 'uppercase' }]
@ -571,7 +571,7 @@ export class UppercasePipe {
transform(v) { }
}
UppercasePipe.ɵfac = function UppercasePipe_Factory(t) { return new (t || UppercasePipe)(); };
UppercasePipe.ɵpipe = i0.ɵɵdefinePipe({ name: "uppercase", type: UppercasePipe, pure: true });
UppercasePipe.ɵpipe = i0.ɵɵngDeclarePipe({ version: "0.0.0-PLACEHOLDER", ngImport: i0, type: UppercasePipe, name: "uppercase" });
(function () { (typeof ngDevMode === "undefined" || ngDevMode) && i0.ɵsetClassMetadata(UppercasePipe, [{
type: Pipe,
args: [{ name: 'uppercase' }]

View File

@ -7,7 +7,7 @@ export class UppercasePipe {
transform(v) { }
}
UppercasePipe.ɵfac = function UppercasePipe_Factory(t) { return new (t || UppercasePipe)(); };
UppercasePipe.ɵpipe = i0.ɵɵdefinePipe({ name: "uppercase", type: UppercasePipe, pure: true });
UppercasePipe.ɵpipe = i0.ɵɵngDeclarePipe({ version: "0.0.0-PLACEHOLDER", ngImport: i0, type: UppercasePipe, name: "uppercase" });
(function () { (typeof ngDevMode === "undefined" || ngDevMode) && i0.ɵsetClassMetadata(UppercasePipe, [{
type: Pipe,
args: [{ name: 'uppercase' }]
@ -111,7 +111,7 @@ export class UppercasePipe {
transform(v) { }
}
UppercasePipe.ɵfac = function UppercasePipe_Factory(t) { return new (t || UppercasePipe)(); };
UppercasePipe.ɵpipe = i0.ɵɵdefinePipe({ name: "uppercase", type: UppercasePipe, pure: true });
UppercasePipe.ɵpipe = i0.ɵɵngDeclarePipe({ version: "0.0.0-PLACEHOLDER", ngImport: i0, type: UppercasePipe, name: "uppercase" });
(function () { (typeof ngDevMode === "undefined" || ngDevMode) && i0.ɵsetClassMetadata(UppercasePipe, [{
type: Pipe,
args: [{ name: 'uppercase' }]

View File

@ -55,7 +55,7 @@ export class StylePipe {
transform(v) { }
}
StylePipe.ɵfac = function StylePipe_Factory(t) { return new (t || StylePipe)(); };
StylePipe.ɵpipe = i0.ɵɵdefinePipe({ name: "stylePipe", type: StylePipe, pure: true });
StylePipe.ɵpipe = i0.ɵɵngDeclarePipe({ version: "0.0.0-PLACEHOLDER", ngImport: i0, type: StylePipe, name: "stylePipe" });
(function () { (typeof ngDevMode === "undefined" || ngDevMode) && i0.ɵsetClassMetadata(StylePipe, [{
type: Pipe,
args: [{ name: 'stylePipe' }]
@ -64,7 +64,7 @@ export class ClassPipe {
transform(v) { }
}
ClassPipe.ɵfac = function ClassPipe_Factory(t) { return new (t || ClassPipe)(); };
ClassPipe.ɵpipe = i0.ɵɵdefinePipe({ name: "classPipe", type: ClassPipe, pure: true });
ClassPipe.ɵpipe = i0.ɵɵngDeclarePipe({ version: "0.0.0-PLACEHOLDER", ngImport: i0, type: ClassPipe, name: "classPipe" });
(function () { (typeof ngDevMode === "undefined" || ngDevMode) && i0.ɵsetClassMetadata(ClassPipe, [{
type: Pipe,
args: [{ name: 'classPipe' }]
@ -134,7 +134,7 @@ export class PipePipe {
transform(v) { }
}
PipePipe.ɵfac = function PipePipe_Factory(t) { return new (t || PipePipe)(); };
PipePipe.ɵpipe = i0.ɵɵdefinePipe({ name: "pipe", type: PipePipe, pure: true });
PipePipe.ɵpipe = i0.ɵɵngDeclarePipe({ version: "0.0.0-PLACEHOLDER", ngImport: i0, type: PipePipe, name: "pipe" });
(function () { (typeof ngDevMode === "undefined" || ngDevMode) && i0.ɵsetClassMetadata(PipePipe, [{
type: Pipe,
args: [{ name: 'pipe' }]

View File

@ -346,7 +346,7 @@ export class PercentPipe {
transform() { }
}
PercentPipe.ɵfac = function PercentPipe_Factory(t) { return new (t || PercentPipe)(); };
PercentPipe.ɵpipe = i0.ɵɵdefinePipe({ name: "percent", type: PercentPipe, pure: true });
PercentPipe.ɵpipe = i0.ɵɵngDeclarePipe({ version: "0.0.0-PLACEHOLDER", ngImport: i0, type: PercentPipe, name: "percent" });
(function () { (typeof ngDevMode === "undefined" || ngDevMode) && i0.ɵsetClassMetadata(PercentPipe, [{
type: Pipe,
args: [{ name: 'percent' }]
@ -364,7 +364,7 @@ AppModule.ɵinj = i0.ɵɵdefineInjector({ factory: function AppModule_Factory(t)
/****************************************************************************************************
* PARTIAL FILE: interpolation_with_pipe.js.map
****************************************************************************************************/
{"version":3,"file":"interpolation_with_pipe.js","sourceRoot":"","sources":["../interpolation_with_pipe.ts"],"names":[],"mappings":"AAAA,OAAO,EAAC,SAAS,EAAE,QAAQ,EAAE,IAAI,EAAgB,MAAM,eAAe,CAAC;;AAMvE,MAAM,OAAO,OAAO;;8DAAP,OAAO;6EAAP,OAAO,gDAFR,qCAAqC,yEAMpC,WAAW;uFAJX,OAAO;cAJnB,SAAS;eAAC;gBACT,QAAQ,EAAE,UAAU;gBACpB,QAAQ,EAAE,qCAAqC;aAChD;;AAKD,MAAM,OAAO,WAAW;IACtB,SAAS,KAAI,CAAC;;sEADH,WAAW;6DAAX,WAAW;uFAAX,WAAW;cADvB,IAAI;eAAC,EAAC,IAAI,EAAE,SAAS,EAAC;;AAMvB,MAAM,OAAO,SAAS;;6CAAT,SAAS;iGAAT,SAAS;wFAAT,SAAS,mBATT,OAAO,EAIP,WAAW;uFAKX,SAAS;cADrB,QAAQ;eAAC,EAAC,YAAY,EAAE,CAAC,OAAO,EAAE,WAAW,CAAC,EAAC"}
{"version":3,"file":"interpolation_with_pipe.js","sourceRoot":"","sources":["../interpolation_with_pipe.ts"],"names":[],"mappings":"AAAA,OAAO,EAAC,SAAS,EAAE,QAAQ,EAAE,IAAI,EAAgB,MAAM,eAAe,CAAC;;AAMvE,MAAM,OAAO,OAAO;;8DAAP,OAAO;6EAAP,OAAO,gDAFR,qCAAqC,yEAMpC,WAAW;uFAJX,OAAO;cAJnB,SAAS;eAAC;gBACT,QAAQ,EAAE,UAAU;gBACpB,QAAQ,EAAE,qCAAqC;aAChD;;AAKD,MAAM,OAAO,WAAW;IACtB,SAAS,KAAI,CAAC;;sEADH,WAAW;2FAAX,WAAW;uFAAX,WAAW;cADvB,IAAI;eAAC,EAAC,IAAI,EAAE,SAAS,EAAC;;AAMvB,MAAM,OAAO,SAAS;;6CAAT,SAAS;iGAAT,SAAS;wFAAT,SAAS,mBATT,OAAO,EAIP,WAAW;uFAKX,SAAS;cADrB,QAAQ;eAAC,EAAC,YAAY,EAAE,CAAC,OAAO,EAAE,WAAW,CAAC,EAAC"}
/****************************************************************************************************
* PARTIAL FILE: interpolation_with_pipe.d.ts
****************************************************************************************************/
@ -404,7 +404,7 @@ export class PercentPipe {
transform() { }
}
PercentPipe.ɵfac = function PercentPipe_Factory(t) { return new (t || PercentPipe)(); };
PercentPipe.ɵpipe = i0.ɵɵdefinePipe({ name: "percent", type: PercentPipe, pure: true });
PercentPipe.ɵpipe = i0.ɵɵngDeclarePipe({ version: "0.0.0-PLACEHOLDER", ngImport: i0, type: PercentPipe, name: "percent" });
(function () { (typeof ngDevMode === "undefined" || ngDevMode) && i0.ɵsetClassMetadata(PercentPipe, [{
type: Pipe,
args: [{ name: 'percent' }]
@ -422,7 +422,7 @@ AppModule.ɵinj = i0.ɵɵdefineInjector({ factory: function AppModule_Factory(t)
/****************************************************************************************************
* PARTIAL FILE: interpolation_with_pipe.js.map
****************************************************************************************************/
{"version":3,"file":"interpolation_with_pipe.js","sourceRoot":"","sources":["../interpolation_with_pipe.ts"],"names":[],"mappings":"AAAA,OAAO,EAAC,SAAS,EAAE,QAAQ,EAAE,IAAI,EAAgB,MAAM,eAAe,CAAC;;AAMvE,MAAM,OAAO,OAAO;;8DAAP,OAAO;6EAAP,OAAO,gDAFR,qCAAqC,yEAMpC,WAAW;uFAJX,OAAO;cAJnB,SAAS;eAAC;gBACT,QAAQ,EAAE,UAAU;gBACpB,QAAQ,EAAE,qCAAqC;aAChD;;AAKD,MAAM,OAAO,WAAW;IACtB,SAAS,KAAI,CAAC;;sEADH,WAAW;6DAAX,WAAW;uFAAX,WAAW;cADvB,IAAI;eAAC,EAAC,IAAI,EAAE,SAAS,EAAC;;AAMvB,MAAM,OAAO,SAAS;;6CAAT,SAAS;iGAAT,SAAS;wFAAT,SAAS,mBATT,OAAO,EAIP,WAAW;uFAKX,SAAS;cADrB,QAAQ;eAAC,EAAC,YAAY,EAAE,CAAC,OAAO,EAAE,WAAW,CAAC,EAAC"}
{"version":3,"file":"interpolation_with_pipe.js","sourceRoot":"","sources":["../interpolation_with_pipe.ts"],"names":[],"mappings":"AAAA,OAAO,EAAC,SAAS,EAAE,QAAQ,EAAE,IAAI,EAAgB,MAAM,eAAe,CAAC;;AAMvE,MAAM,OAAO,OAAO;;8DAAP,OAAO;6EAAP,OAAO,gDAFR,qCAAqC,yEAMpC,WAAW;uFAJX,OAAO;cAJnB,SAAS;eAAC;gBACT,QAAQ,EAAE,UAAU;gBACpB,QAAQ,EAAE,qCAAqC;aAChD;;AAKD,MAAM,OAAO,WAAW;IACtB,SAAS,KAAI,CAAC;;sEADH,WAAW;2FAAX,WAAW;uFAAX,WAAW;cADvB,IAAI;eAAC,EAAC,IAAI,EAAE,SAAS,EAAC;;AAMvB,MAAM,OAAO,SAAS;;6CAAT,SAAS;iGAAT,SAAS;wFAAT,SAAS,mBATT,OAAO,EAIP,WAAW;uFAKX,SAAS;cADrB,QAAQ;eAAC,EAAC,YAAY,EAAE,CAAC,OAAO,EAAE,WAAW,CAAC,EAAC"}
/****************************************************************************************************
* PARTIAL FILE: interpolation_with_pipe.d.ts
****************************************************************************************************/

View File

@ -105,6 +105,7 @@ export {R3Reference, devOnlyGuardedExpression, getSafePropertyAccessString} from
export {compileComponentFromMetadata, compileDirectiveFromMetadata, parseHostBindings, ParsedHostBindings, verifyHostBindings} from './render3/view/compiler';
export {compileDeclareComponentFromMetadata} from './render3/partial/component';
export {compileDeclareDirectiveFromMetadata} from './render3/partial/directive';
export {compileDeclarePipeFromMetadata} from './render3/partial/pipe';
export {publishFacade} from './jit_compiler_facade';
// This file only reexports content of the `src` folder. Keep it that way.

View File

@ -29,6 +29,8 @@ export interface ExportedCompilerFacade {
export interface CompilerFacade {
compilePipe(angularCoreEnv: CoreEnvironment, sourceMapUrl: string, meta: R3PipeMetadataFacade):
any;
compilePipeDeclaration(
angularCoreEnv: CoreEnvironment, sourceMapUrl: string, declaration: R3DeclarePipeFacade): any;
compileInjectable(
angularCoreEnv: CoreEnvironment, sourceMapUrl: string, meta: R3InjectableMetadataFacade): any;
compileInjector(
@ -255,6 +257,12 @@ export interface R3DeclareQueryMetadataFacade {
emitDistinctChangesOnly?: boolean;
}
export interface R3DeclarePipeFacade {
type: Function;
name: string;
pure?: boolean;
}
export interface ParseSourceSpan {
start: any;
end: any;

View File

@ -7,7 +7,7 @@
*/
import {CompilerFacade, CoreEnvironment, ExportedCompilerFacade, OpaqueValue, R3ComponentMetadataFacade, R3DeclareComponentFacade, R3DeclareDirectiveFacade, R3DeclareQueryMetadataFacade, R3DependencyMetadataFacade, R3DirectiveMetadataFacade, R3FactoryDefMetadataFacade, R3InjectableMetadataFacade, R3InjectorMetadataFacade, R3NgModuleMetadataFacade, R3PipeMetadataFacade, R3QueryMetadataFacade, StringMap, StringMapWithRename} from './compiler_facade_interface';
import {CompilerFacade, CoreEnvironment, ExportedCompilerFacade, OpaqueValue, R3ComponentMetadataFacade, R3DeclareComponentFacade, R3DeclareDirectiveFacade, R3DeclarePipeFacade, R3DeclareQueryMetadataFacade, R3DependencyMetadataFacade, R3DirectiveMetadataFacade, R3FactoryDefMetadataFacade, R3InjectableMetadataFacade, R3InjectorMetadataFacade, R3NgModuleMetadataFacade, R3PipeMetadataFacade, R3QueryMetadataFacade, StringMap, StringMapWithRename} from './compiler_facade_interface';
import {ConstantPool} from './constant_pool';
import {ChangeDetectionStrategy, HostBinding, HostListener, Input, Output, Type, ViewEncapsulation} from './core';
import {Identifiers} from './identifiers';
@ -50,6 +50,13 @@ export class CompilerFacadeImpl implements CompilerFacade {
return this.jitExpression(res.expression, angularCoreEnv, sourceMapUrl, []);
}
compilePipeDeclaration(
angularCoreEnv: CoreEnvironment, sourceMapUrl: string,
declaration: R3DeclarePipeFacade): any {
const meta = convertDeclarePipeFacadeToMetadata(declaration);
return compilePipeFromMetadata(meta);
}
compileInjectable(
angularCoreEnv: CoreEnvironment, sourceMapUrl: string,
facade: R3InjectableMetadataFacade): any {
@ -513,6 +520,19 @@ function parseInputOutputs(values: string[]): StringMap {
}, {} as StringMap);
}
function convertDeclarePipeFacadeToMetadata(declaration: R3DeclarePipeFacade): R3PipeMetadata {
return {
name: declaration.type.name,
type: wrapReference(declaration.type),
internalType: new WrappedNodeExpr(declaration.type),
typeArgumentCount: 0,
pipeName: declaration.name,
deps: null,
pure: declaration.pure ?? true,
};
}
export function publishFacade(global: any) {
const ng: ExportedCompilerFacade = global.ng || (global.ng = {});
ng.ɵcompilerFacade = new CompilerFacadeImpl();

View File

@ -23,10 +23,10 @@ export interface R3PartialDeclaration {
}
/**
* This interface describes the shape of the object that partial directive declarations are compiled
* into. This serves only as documentation, as conformance of this interface is not enforced during
* the generation of the partial declaration, nor when the linker applies full compilation from the
* partial declaration.
* Describes the shape of the object that the `ɵɵngDeclareDirective() function accepts.
*
* This interface serves primarily as documentation, as conformance to this interface is not
* enforced during linking.
*/
export interface R3DeclareDirectiveMetadata extends R3PartialDeclaration {
/**
@ -114,8 +114,10 @@ export interface R3DeclareDirectiveMetadata extends R3PartialDeclaration {
}
/**
* An extension of `R3DeclareDirectiveMetadata` that declares the shape of a partial declaration of
* a component.
* Describes the shape of the object that the `ɵɵngDeclareComponent()` function accepts.
*
* This interface serves primarily as documentation, as conformance to this interface is not
* enforced during linking.
*/
export interface R3DeclareComponentMetadata extends R3DeclareDirectiveMetadata {
/**
@ -261,3 +263,30 @@ export interface R3DeclareQueryMetadata {
*/
static?: boolean;
}
/**
* Describes the shape of the object that the `ɵɵngDeclarePipe()` function accepts.
*
* This interface serves primarily as documentation, as conformance to this interface is not
* enforced during linking.
*/
export interface R3DeclarePipeMetadata extends R3PartialDeclaration {
/**
* Reference to the pipe class itself.
*/
type: o.Expression;
/**
* The name to use in templates to refer to this pipe.
*/
name: string;
/**
* Whether this pipe is "pure".
*
* A pure pipe's `transform()` method is only invoked when its input arguments change.
*
* Default: true.
*/
pure?: boolean;
}

View File

@ -0,0 +1,50 @@
/**
* @license
* Copyright Google LLC 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 * as o from '../../output/output_ast';
import {Identifiers as R3} from '../r3_identifiers';
import {createPipeType, R3PipeMetadata} from '../r3_pipe_compiler';
import {R3PipeDef} from '../view/api';
import {DefinitionMap} from '../view/util';
import {R3DeclarePipeMetadata} from './api';
/**
* Compile a Pipe declaration defined by the `R3PipeMetadata`.
*/
export function compileDeclarePipeFromMetadata(meta: R3PipeMetadata): R3PipeDef {
const definitionMap = createPipeDefinitionMap(meta);
const expression = o.importExpr(R3.declarePipe).callFn([definitionMap.toLiteralMap()]);
const type = createPipeType(meta);
return {expression, type};
}
/**
* Gathers the declaration fields for a Pipe into a `DefinitionMap`. This allows for reusing
* this logic for components, as they extend the Pipe metadata.
*/
export function createPipeDefinitionMap(meta: R3PipeMetadata):
DefinitionMap<R3DeclarePipeMetadata> {
const definitionMap = new DefinitionMap<R3DeclarePipeMetadata>();
definitionMap.set('version', o.literal('0.0.0-PLACEHOLDER'));
definitionMap.set('ngImport', o.importExpr(R3.core));
// e.g. `type: MyPipe`
definitionMap.set('type', meta.internalType);
// e.g. `name: "myPipe"`
definitionMap.set('name', o.literal(meta.pipeName));
if (meta.pure === false) {
// e.g. `pure: false`
definitionMap.set('pure', o.literal(meta.pure));
}
return definitionMap;
}

View File

@ -294,6 +294,7 @@ export class Identifiers {
static PipeDefWithMeta: o.ExternalReference = {name: 'ɵɵPipeDefWithMeta', moduleName: CORE};
static definePipe: o.ExternalReference = {name: 'ɵɵdefinePipe', moduleName: CORE};
static declarePipe: o.ExternalReference = {name: 'ɵɵngDeclarePipe', moduleName: CORE};
static queryRefresh: o.ExternalReference = {name: 'ɵɵqueryRefresh', moduleName: CORE};
static viewQuery: o.ExternalReference = {name: 'ɵɵviewQuery', moduleName: CORE};

View File

@ -15,6 +15,7 @@ import {error, OutputContext} from '../util';
import {compileFactoryFunction, dependenciesFromGlobalMetadata, R3DependencyMetadata, R3FactoryTarget} from './r3_factory';
import {Identifiers as R3} from './r3_identifiers';
import {R3Reference, typeWithParameters, wrapReference} from './util';
import {R3PipeDef} from './view/api';
export interface R3PipeMetadata {
/**
@ -57,7 +58,7 @@ export interface R3PipeMetadata {
pure: boolean;
}
export function compilePipeFromMetadata(metadata: R3PipeMetadata) {
export function compilePipeFromMetadata(metadata: R3PipeMetadata): R3PipeDef {
const definitionMapValues: {key: string, quoted: boolean, value: o.Expression}[] = [];
// e.g. `name: 'myPipe'`
@ -70,12 +71,16 @@ export function compilePipeFromMetadata(metadata: R3PipeMetadata) {
definitionMapValues.push({key: 'pure', value: o.literal(metadata.pure), quoted: false});
const expression = o.importExpr(R3.definePipe).callFn([o.literalMap(definitionMapValues)]);
const type = new o.ExpressionType(o.importExpr(R3.PipeDefWithMeta, [
const type = createPipeType(metadata);
return {expression, type};
}
export function createPipeType(metadata: R3PipeMetadata): o.Type {
return new o.ExpressionType(o.importExpr(R3.PipeDefWithMeta, [
typeWithParameters(metadata.type.type, metadata.typeArgumentCount),
new o.ExpressionType(new o.LiteralExpr(metadata.pipeName)),
]));
return {expression, type};
}
/**

View File

@ -349,6 +349,14 @@ export interface R3ComponentDef {
type: o.Type;
}
/**
* Output of render3 pipe compilation.
*/
export interface R3PipeDef {
expression: o.Expression;
type: o.Type;
}
/**
* Mappings indicating how the class interacts with its
* host element (host bindings, listeners, etc).

View File

@ -29,6 +29,8 @@ export interface ExportedCompilerFacade {
export interface CompilerFacade {
compilePipe(angularCoreEnv: CoreEnvironment, sourceMapUrl: string, meta: R3PipeMetadataFacade):
any;
compilePipeDeclaration(
angularCoreEnv: CoreEnvironment, sourceMapUrl: string, declaration: R3DeclarePipeFacade): any;
compileInjectable(
angularCoreEnv: CoreEnvironment, sourceMapUrl: string, meta: R3InjectableMetadataFacade): any;
compileInjector(
@ -255,6 +257,12 @@ export interface R3DeclareQueryMetadataFacade {
emitDistinctChangesOnly?: boolean;
}
export interface R3DeclarePipeFacade {
type: Function;
name: string;
pure?: boolean;
}
export interface ParseSourceSpan {
start: any;
end: any;

View File

@ -273,6 +273,7 @@ export {
export {
ɵɵngDeclareComponent,
ɵɵngDeclareDirective,
ɵɵngDeclarePipe,
} from './render3/jit/partial';
export {
compilePipe as ɵcompilePipe,

View File

@ -6,7 +6,7 @@
* found in the LICENSE file at https://angular.io/license
*/
import {getCompilerFacade, R3DeclareComponentFacade, R3DeclareDirectiveFacade} from '../../compiler/compiler_facade';
import {getCompilerFacade, R3DeclareComponentFacade, R3DeclareDirectiveFacade, R3DeclarePipeFacade} from '../../compiler/compiler_facade';
import {angularCoreEnv} from './environment';
/**
@ -30,3 +30,13 @@ export function ɵɵngDeclareComponent(decl: R3DeclareComponentFacade): unknown
return compiler.compileComponentDeclaration(
angularCoreEnv, `ng:///${decl.type.name}/ɵcmp.js`, decl);
}
/**
* Compiles a partial pipe declaration object into a full pipe definition object.
*
* @codeGenApi
*/
export function ɵɵngDeclarePipe(decl: R3DeclarePipeFacade): unknown {
const compiler = getCompilerFacade();
return compiler.compilePipeDeclaration(angularCoreEnv, `ng:///${decl.type.name}/ɵpipe.js`, decl);
}

View File

@ -28,6 +28,7 @@ const INTERFACE_EXCEPTIONS = new Set<string>([
const PARTIAL_ONLY = new Set<string>([
'ɵɵngDeclareDirective',
'ɵɵngDeclareComponent',
'ɵɵngDeclarePipe',
'ChangeDetectionStrategy',
'ViewEncapsulation',
]);