Skip to content

Commit 9cb43fb

Browse files
petebacondarwinjosephperrott
authored andcommitted
refactor(compiler-cli): implement ɵɵngDeclarePipe() (angular#40803)
This commit implements creating of `ɵɵngDeclarePipe()` calls in partial compilation, and processing of those calls in the linker and JIT compiler. See angular#40677 PR Close angular#40803
1 parent 6425a6d commit 9cb43fb

File tree

26 files changed

+265
-46
lines changed

26 files changed

+265
-46
lines changed

packages/compiler-cli/linker/src/file_linker/partial_linkers/partial_linker_selector.ts

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -14,10 +14,12 @@ import {LinkerEnvironment} from '../linker_environment';
1414
import {PartialComponentLinkerVersion1} from './partial_component_linker_1';
1515
import {PartialDirectiveLinkerVersion1} from './partial_directive_linker_1';
1616
import {PartialLinker} from './partial_linker';
17+
import {PartialPipeLinkerVersion1} from './partial_pipe_linker_1';
1718

1819
export const ɵɵngDeclareDirective = 'ɵɵngDeclareDirective';
1920
export const ɵɵngDeclareComponent = 'ɵɵngDeclareComponent';
20-
export const declarationFunctions = [ɵɵngDeclareDirective, ɵɵngDeclareComponent];
21+
export const ɵɵngDeclarePipe = 'ɵɵngDeclarePipe';
22+
export const declarationFunctions = [ɵɵngDeclareDirective, ɵɵngDeclareComponent, ɵɵngDeclarePipe];
2123

2224
interface LinkerRange<TExpression> {
2325
range: string;
@@ -81,6 +83,7 @@ export class PartialLinkerSelector<TStatement, TExpression> {
8183
const partialComponentLinkerVersion1 = new PartialComponentLinkerVersion1(
8284
environment, createGetSourceFile(sourceUrl, code, environment.sourceFileLoader), sourceUrl,
8385
code);
86+
const partialPipeLinkerVersion1 = new PartialPipeLinkerVersion1();
8487

8588
const linkers = new Map<string, LinkerRange<TExpression>[]>();
8689
linkers.set(ɵɵngDeclareDirective, [
@@ -91,6 +94,10 @@ export class PartialLinkerSelector<TStatement, TExpression> {
9194
{range: '0.0.0-PLACEHOLDER', linker: partialComponentLinkerVersion1},
9295
{range: '>=11.1.0-next.1', linker: partialComponentLinkerVersion1},
9396
]);
97+
linkers.set(ɵɵngDeclarePipe, [
98+
{range: '0.0.0-PLACEHOLDER', linker: partialPipeLinkerVersion1},
99+
{range: '>=11.1.0-next.1', linker: partialPipeLinkerVersion1},
100+
]);
94101
return linkers;
95102
}
96103
}
Lines changed: 58 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,58 @@
1+
/**
2+
* @license
3+
* Copyright Google LLC All Rights Reserved.
4+
*
5+
* Use of this source code is governed by an MIT-style license that can be
6+
* found in the LICENSE file at https://angular.io/license
7+
*/
8+
import {compilePipeFromMetadata, ConstantPool, R3DeclarePipeMetadata, R3PartialDeclaration, R3PipeMetadata, R3Reference} from '@angular/compiler';
9+
import * as o from '@angular/compiler/src/output/output_ast';
10+
11+
import {AstObject} from '../../ast/ast_value';
12+
import {FatalLinkerError} from '../../fatal_linker_error';
13+
14+
import {PartialLinker} from './partial_linker';
15+
16+
/**
17+
* A `PartialLinker` that is designed to process `ɵɵngDeclarePipe()` call expressions.
18+
*/
19+
export class PartialPipeLinkerVersion1<TExpression> implements PartialLinker<TExpression> {
20+
constructor() {}
21+
22+
linkPartialDeclaration(
23+
constantPool: ConstantPool,
24+
metaObj: AstObject<R3PartialDeclaration, TExpression>): o.Expression {
25+
const meta = toR3PipeMeta(metaObj);
26+
const def = compilePipeFromMetadata(meta);
27+
return def.expression;
28+
}
29+
}
30+
31+
/**
32+
* Derives the `R3PipeMetadata` structure from the AST object.
33+
*/
34+
export function toR3PipeMeta<TExpression>(metaObj: AstObject<R3DeclarePipeMetadata, TExpression>):
35+
R3PipeMetadata {
36+
const typeExpr = metaObj.getValue('type');
37+
const typeName = typeExpr.getSymbolName();
38+
if (typeName === null) {
39+
throw new FatalLinkerError(
40+
typeExpr.expression, 'Unsupported type, its name could not be determined');
41+
}
42+
43+
const pure = metaObj.has('pure') ? metaObj.getBoolean('pure') : true;
44+
45+
return {
46+
name: typeName,
47+
type: wrapReference(typeExpr.getOpaque()),
48+
internalType: metaObj.getOpaque('type'),
49+
typeArgumentCount: 0,
50+
deps: null,
51+
pipeName: metaObj.getString('name'),
52+
pure,
53+
};
54+
}
55+
56+
function wrapReference<TExpression>(wrapped: o.WrappedNodeExpr<TExpression>): R3Reference {
57+
return {value: wrapped, type: wrapped};
58+
}

packages/compiler-cli/linker/test/file_linker/partial_linkers/partial_linker_selector_spec.ts

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,7 @@ import {LinkerEnvironment} from '../../../src/file_linker/linker_environment';
1717
import {PartialComponentLinkerVersion1} from '../../../src/file_linker/partial_linkers/partial_component_linker_1';
1818
import {PartialDirectiveLinkerVersion1} from '../../../src/file_linker/partial_linkers/partial_directive_linker_1';
1919
import {PartialLinkerSelector} from '../../../src/file_linker/partial_linkers/partial_linker_selector';
20+
import {PartialPipeLinkerVersion1} from '../../../src/file_linker/partial_linkers/partial_pipe_linker_1';
2021

2122
describe('PartialLinkerSelector', () => {
2223
const options: LinkerOptions = {
@@ -42,6 +43,7 @@ describe('PartialLinkerSelector', () => {
4243
environment, fs.resolve('/some/path/to/file.js'), 'some file contents');
4344
expect(selector.supportsDeclaration('ɵɵngDeclareDirective')).toBe(true);
4445
expect(selector.supportsDeclaration('ɵɵngDeclareComponent')).toBe(true);
46+
expect(selector.supportsDeclaration('ɵɵngDeclarePipe')).toBe(true);
4547
expect(selector.supportsDeclaration('$foo')).toBe(false);
4648
});
4749

@@ -60,6 +62,8 @@ describe('PartialLinkerSelector', () => {
6062
.toBeInstanceOf(PartialDirectiveLinkerVersion1);
6163
expect(selector.getLinker('ɵɵngDeclareComponent', '0.0.0-PLACEHOLDER'))
6264
.toBeInstanceOf(PartialComponentLinkerVersion1);
65+
expect(selector.getLinker('ɵɵngDeclarePipe', '0.0.0-PLACEHOLDER'))
66+
.toBeInstanceOf(PartialPipeLinkerVersion1);
6367
});
6468

6569
it('should return the linker that matches the name and valid full version', () => {

packages/compiler-cli/src/ngtsc/annotations/src/pipe.ts

Lines changed: 14 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@
66
* found in the LICENSE file at https://angular.io/license
77
*/
88

9-
import {compilePipeFromMetadata, Identifiers, R3FactoryTarget, R3PipeMetadata, Statement, WrappedNodeExpr} from '@angular/compiler';
9+
import {compileDeclarePipeFromMetadata, compilePipeFromMetadata, Identifiers, R3FactoryTarget, R3PipeDef, R3PipeMetadata, Statement, WrappedNodeExpr} from '@angular/compiler';
1010
import * as ts from 'typescript';
1111

1212
import {ErrorCode, FatalDiagnosticError} from '../../diagnostics';
@@ -134,10 +134,18 @@ export class PipeDecoratorHandler implements DecoratorHandler<Decorator, PipeHan
134134
}
135135

136136
compileFull(node: ClassDeclaration, analysis: Readonly<PipeHandlerData>): CompileResult[] {
137-
const meta = analysis.meta;
138-
const res = compilePipeFromMetadata(meta);
137+
const res = compilePipeFromMetadata(analysis.meta);
138+
return this.compilePipe(analysis, res);
139+
}
140+
141+
compilePartial(node: ClassDeclaration, analysis: Readonly<PipeHandlerData>): CompileResult[] {
142+
const res = compileDeclarePipeFromMetadata(analysis.meta);
143+
return this.compilePipe(analysis, res);
144+
}
145+
146+
private compilePipe(analysis: Readonly<PipeHandlerData>, def: R3PipeDef) {
139147
const factoryRes = compileNgFactoryDefField({
140-
...meta,
148+
...analysis.meta,
141149
injectFn: Identifiers.directiveInject,
142150
target: R3FactoryTarget.Pipe,
143151
});
@@ -147,9 +155,9 @@ export class PipeDecoratorHandler implements DecoratorHandler<Decorator, PipeHan
147155
return [
148156
factoryRes, {
149157
name: 'ɵpipe',
150-
initializer: res.expression,
158+
initializer: def.expression,
151159
statements: [],
152-
type: res.type,
160+
type: def.type,
153161
}
154162
];
155163
}

packages/compiler-cli/test/compliance/test_cases/r3_compiler_compliance/components_and_directives/GOLDEN_PARTIAL.js

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -72,7 +72,7 @@ HostBindingComp.ɵcmp = i0.ɵɵngDeclareComponent({ version: "0.0.0-PLACEHOLDER"
7272
class MyForwardPipe {
7373
}
7474
MyForwardPipe.ɵfac = function MyForwardPipe_Factory(t) { return new (t || MyForwardPipe)(); };
75-
MyForwardPipe.ɵpipe = i0.ɵɵdefinePipe({ name: "my_forward_pipe", type: MyForwardPipe, pure: true });
75+
MyForwardPipe.ɵpipe = i0.ɵɵngDeclarePipe({ version: "0.0.0-PLACEHOLDER", ngImport: i0, type: MyForwardPipe, name: "my_forward_pipe" });
7676
(function () { (typeof ngDevMode === "undefined" || ngDevMode) && i0.ɵsetClassMetadata(MyForwardPipe, [{
7777
type: Pipe,
7878
args: [{ name: 'my_forward_pipe' }]

packages/compiler-cli/test/compliance/test_cases/r3_compiler_compliance/components_and_directives/pipes/GOLDEN_PARTIAL.js

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,7 @@ export class MyPipe {
1010
ngOnDestroy() { }
1111
}
1212
MyPipe.ɵfac = function MyPipe_Factory(t) { return new (t || MyPipe)(); };
13-
MyPipe.ɵpipe = i0.ɵɵdefinePipe({ name: "myPipe", type: MyPipe, pure: false });
13+
MyPipe.ɵpipe = i0.ɵɵngDeclarePipe({ version: "0.0.0-PLACEHOLDER", ngImport: i0, type: MyPipe, name: "myPipe", pure: false });
1414
(function () { (typeof ngDevMode === "undefined" || ngDevMode) && i0.ɵsetClassMetadata(MyPipe, [{
1515
type: Pipe,
1616
args: [{ name: 'myPipe', pure: false }]
@@ -21,7 +21,7 @@ export class MyPurePipe {
2121
}
2222
}
2323
MyPurePipe.ɵfac = function MyPurePipe_Factory(t) { return new (t || MyPurePipe)(); };
24-
MyPurePipe.ɵpipe = i0.ɵɵdefinePipe({ name: "myPurePipe", type: MyPurePipe, pure: true });
24+
MyPurePipe.ɵpipe = i0.ɵɵngDeclarePipe({ version: "0.0.0-PLACEHOLDER", ngImport: i0, type: MyPurePipe, name: "myPurePipe" });
2525
(function () { (typeof ngDevMode === "undefined" || ngDevMode) && i0.ɵsetClassMetadata(MyPurePipe, [{
2626
type: Pipe,
2727
args: [{
@@ -93,7 +93,7 @@ export class MyPipe {
9393
ngOnDestroy() { }
9494
}
9595
MyPipe.ɵfac = function MyPipe_Factory(t) { return new (t || MyPipe)(); };
96-
MyPipe.ɵpipe = i0.ɵɵdefinePipe({ name: "myPipe", type: MyPipe, pure: false });
96+
MyPipe.ɵpipe = i0.ɵɵngDeclarePipe({ version: "0.0.0-PLACEHOLDER", ngImport: i0, type: MyPipe, name: "myPipe", pure: false });
9797
(function () { (typeof ngDevMode === "undefined" || ngDevMode) && i0.ɵsetClassMetadata(MyPipe, [{
9898
type: Pipe,
9999
args: [{ name: 'myPipe', pure: false }]
@@ -155,7 +155,7 @@ export class MyPipe {
155155
}
156156
}
157157
MyPipe.ɵfac = function MyPipe_Factory(t) { return new (t || MyPipe)(i0.ɵɵinjectPipeChangeDetectorRef()); };
158-
MyPipe.ɵpipe = i0.ɵɵdefinePipe({ name: "myPipe", type: MyPipe, pure: true });
158+
MyPipe.ɵpipe = i0.ɵɵngDeclarePipe({ version: "0.0.0-PLACEHOLDER", ngImport: i0, type: MyPipe, name: "myPipe" });
159159
(function () { (typeof ngDevMode === "undefined" || ngDevMode) && i0.ɵsetClassMetadata(MyPipe, [{
160160
type: Pipe,
161161
args: [{ name: 'myPipe' }]
@@ -167,7 +167,7 @@ export class MyOtherPipe {
167167
}
168168
}
169169
MyOtherPipe.ɵfac = function MyOtherPipe_Factory(t) { return new (t || MyOtherPipe)(i0.ɵɵinjectPipeChangeDetectorRef(8)); };
170-
MyOtherPipe.ɵpipe = i0.ɵɵdefinePipe({ name: "myOtherPipe", type: MyOtherPipe, pure: true });
170+
MyOtherPipe.ɵpipe = i0.ɵɵngDeclarePipe({ version: "0.0.0-PLACEHOLDER", ngImport: i0, type: MyOtherPipe, name: "myOtherPipe" });
171171
(function () { (typeof ngDevMode === "undefined" || ngDevMode) && i0.ɵsetClassMetadata(MyOtherPipe, [{
172172
type: Pipe,
173173
args: [{ name: 'myOtherPipe' }]

packages/compiler-cli/test/compliance/test_cases/r3_compiler_compliance/elements/GOLDEN_PARTIAL.js

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -318,7 +318,7 @@ export class PipePipe {
318318
transform(v, a, a2) { }
319319
}
320320
PipePipe.ɵfac = function PipePipe_Factory(t) { return new (t || PipePipe)(); };
321-
PipePipe.ɵpipe = i0.ɵɵdefinePipe({ name: "pipe", type: PipePipe, pure: true });
321+
PipePipe.ɵpipe = i0.ɵɵngDeclarePipe({ version: "0.0.0-PLACEHOLDER", ngImport: i0, type: PipePipe, name: "pipe" });
322322
(function () { (typeof ngDevMode === "undefined" || ngDevMode) && i0.ɵsetClassMetadata(PipePipe, [{
323323
type: Pipe,
324324
args: [{ name: 'pipe' }]

packages/compiler-cli/test/compliance/test_cases/r3_view_compiler_bindings/property_bindings/GOLDEN_PARTIAL.js

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -211,7 +211,7 @@ export class AsyncPipe {
211211
transform(v) { }
212212
}
213213
AsyncPipe.ɵfac = function AsyncPipe_Factory(t) { return new (t || AsyncPipe)(); };
214-
AsyncPipe.ɵpipe = i0.ɵɵdefinePipe({ name: "async", type: AsyncPipe, pure: true });
214+
AsyncPipe.ɵpipe = i0.ɵɵngDeclarePipe({ version: "0.0.0-PLACEHOLDER", ngImport: i0, type: AsyncPipe, name: "async" });
215215
(function () { (typeof ngDevMode === "undefined" || ngDevMode) && i0.ɵsetClassMetadata(AsyncPipe, [{
216216
type: Pipe,
217217
args: [{ name: 'async' }]

packages/compiler-cli/test/compliance/test_cases/r3_view_compiler_di/di/GOLDEN_PARTIAL.js

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -297,7 +297,7 @@ export class MyPipe {
297297
}
298298
}
299299
MyPipe.ɵfac = function MyPipe_Factory(t) { return new (t || MyPipe)(i0.ɵɵdirectiveInject(Service)); };
300-
MyPipe.ɵpipe = i0.ɵɵdefinePipe({ name: "myPipe", type: MyPipe, pure: true });
300+
MyPipe.ɵpipe = i0.ɵɵngDeclarePipe({ version: "0.0.0-PLACEHOLDER", ngImport: i0, type: MyPipe, name: "myPipe" });
301301
MyPipe.ɵprov = i0.ɵɵdefineInjectable({ token: MyPipe, factory: MyPipe.ɵfac });
302302
(function () { (typeof ngDevMode === "undefined" || ngDevMode) && i0.ɵsetClassMetadata(MyPipe, [{
303303
type: Injectable
@@ -312,7 +312,7 @@ export class MyOtherPipe {
312312
}
313313
}
314314
MyOtherPipe.ɵfac = function MyOtherPipe_Factory(t) { return new (t || MyOtherPipe)(i0.ɵɵdirectiveInject(Service)); };
315-
MyOtherPipe.ɵpipe = i0.ɵɵdefinePipe({ name: "myOtherPipe", type: MyOtherPipe, pure: true });
315+
MyOtherPipe.ɵpipe = i0.ɵɵngDeclarePipe({ version: "0.0.0-PLACEHOLDER", ngImport: i0, type: MyOtherPipe, name: "myOtherPipe" });
316316
MyOtherPipe.ɵprov = i0.ɵɵdefineInjectable({ token: MyOtherPipe, factory: MyOtherPipe.ɵfac });
317317
(function () { (typeof ngDevMode === "undefined" || ngDevMode) && i0.ɵsetClassMetadata(MyOtherPipe, [{
318318
type: Pipe,

packages/compiler-cli/test/compliance/test_cases/r3_view_compiler_i18n/element_attributes/GOLDEN_PARTIAL.js

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -201,7 +201,7 @@ export class UppercasePipe {
201201
transform(v) { }
202202
}
203203
UppercasePipe.ɵfac = function UppercasePipe_Factory(t) { return new (t || UppercasePipe)(); };
204-
UppercasePipe.ɵpipe = i0.ɵɵdefinePipe({ name: "uppercase", type: UppercasePipe, pure: true });
204+
UppercasePipe.ɵpipe = i0.ɵɵngDeclarePipe({ version: "0.0.0-PLACEHOLDER", ngImport: i0, type: UppercasePipe, name: "uppercase" });
205205
(function () { (typeof ngDevMode === "undefined" || ngDevMode) && i0.ɵsetClassMetadata(UppercasePipe, [{
206206
type: Pipe,
207207
args: [{ name: 'uppercase' }]
@@ -450,7 +450,7 @@ export class UppercasePipe {
450450
transform(v) { }
451451
}
452452
UppercasePipe.ɵfac = function UppercasePipe_Factory(t) { return new (t || UppercasePipe)(); };
453-
UppercasePipe.ɵpipe = i0.ɵɵdefinePipe({ name: "uppercase", type: UppercasePipe, pure: true });
453+
UppercasePipe.ɵpipe = i0.ɵɵngDeclarePipe({ version: "0.0.0-PLACEHOLDER", ngImport: i0, type: UppercasePipe, name: "uppercase" });
454454
(function () { (typeof ngDevMode === "undefined" || ngDevMode) && i0.ɵsetClassMetadata(UppercasePipe, [{
455455
type: Pipe,
456456
args: [{ name: 'uppercase' }]
@@ -546,7 +546,7 @@ export class UppercasePipe {
546546
transform(v) { }
547547
}
548548
UppercasePipe.ɵfac = function UppercasePipe_Factory(t) { return new (t || UppercasePipe)(); };
549-
UppercasePipe.ɵpipe = i0.ɵɵdefinePipe({ name: "uppercase", type: UppercasePipe, pure: true });
549+
UppercasePipe.ɵpipe = i0.ɵɵngDeclarePipe({ version: "0.0.0-PLACEHOLDER", ngImport: i0, type: UppercasePipe, name: "uppercase" });
550550
(function () { (typeof ngDevMode === "undefined" || ngDevMode) && i0.ɵsetClassMetadata(UppercasePipe, [{
551551
type: Pipe,
552552
args: [{ name: 'uppercase' }]
@@ -608,7 +608,7 @@ export class UppercasePipe {
608608
transform(v) { }
609609
}
610610
UppercasePipe.ɵfac = function UppercasePipe_Factory(t) { return new (t || UppercasePipe)(); };
611-
UppercasePipe.ɵpipe = i0.ɵɵdefinePipe({ name: "uppercase", type: UppercasePipe, pure: true });
611+
UppercasePipe.ɵpipe = i0.ɵɵngDeclarePipe({ version: "0.0.0-PLACEHOLDER", ngImport: i0, type: UppercasePipe, name: "uppercase" });
612612
(function () { (typeof ngDevMode === "undefined" || ngDevMode) && i0.ɵsetClassMetadata(UppercasePipe, [{
613613
type: Pipe,
614614
args: [{ name: 'uppercase' }]

0 commit comments

Comments
 (0)