Skip to content

Commit 594343c

Browse files
alan-agius4mgechev
authored andcommitted
fix(@angular-devkit/build-optimizer): don't add pure comments to tslib helpers (#15314)
Closes #15301
1 parent ed6c5f9 commit 594343c

File tree

8 files changed

+84
-18
lines changed

8 files changed

+84
-18
lines changed

packages/angular_devkit/build_optimizer/BUILD

+1
Original file line numberDiff line numberDiff line change
@@ -28,6 +28,7 @@ ts_library(
2828
"@npm//@types/node",
2929
"@npm//@types/source-map",
3030
"@npm//@types/webpack",
31+
"@npm//tslib",
3132
"@npm//typescript",
3233
],
3334
)

packages/angular_devkit/build_optimizer/package.json

+1
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,7 @@
1111
"dependencies": {
1212
"loader-utils": "1.2.3",
1313
"source-map": "0.5.6",
14+
"tslib": "1.10.0",
1415
"typescript": "3.5.3",
1516
"webpack-sources": "1.3.0"
1617
}

packages/angular_devkit/build_optimizer/src/build-optimizer/build-optimizer_spec.ts

+38
Original file line numberDiff line numberDiff line change
@@ -100,6 +100,44 @@ describe('build-optimizer', () => {
100100
expect(boOutput.emitSkipped).toEqual(false);
101101
});
102102

103+
it(`doesn't add pure comments to tslib helpers`, () => {
104+
const input = tags.stripIndent`
105+
class LanguageState {
106+
}
107+
108+
LanguageState.ctorParameters = () => [
109+
{ type: TranslateService },
110+
{ type: undefined, decorators: [{ type: Inject, args: [LANGUAGE_CONFIG,] }] }
111+
];
112+
113+
__decorate([
114+
Action(CheckLanguage),
115+
__metadata("design:type", Function),
116+
__metadata("design:paramtypes", [Object]),
117+
__metadata("design:returntype", void 0)
118+
], LanguageState.prototype, "checkLanguage", null);
119+
`;
120+
121+
const output = tags.oneLine`
122+
let LanguageState = /*@__PURE__*/ (() => {
123+
class LanguageState {
124+
}
125+
126+
__decorate([
127+
Action(CheckLanguage),
128+
__metadata("design:type", Function),
129+
__metadata("design:paramtypes", [Object]),
130+
__metadata("design:returntype", void 0)
131+
], LanguageState.prototype, "checkLanguage", null);
132+
return LanguageState;
133+
})();
134+
`;
135+
136+
const boOutput = buildOptimizer({ content: input, isSideEffectFree: true });
137+
expect(tags.oneLine`${boOutput.content}`).toEqual(output);
138+
expect(boOutput.emitSkipped).toEqual(false);
139+
});
140+
103141
it('should not wrap classes which had all static properties dropped in IIFE', () => {
104142
const classDeclaration = tags.oneLine`
105143
import { Injectable } from '@angular/core';

packages/angular_devkit/build_optimizer/src/helpers/ast-utils.ts

+9
Original file line numberDiff line numberDiff line change
@@ -5,10 +5,15 @@
55
* Use of this source code is governed by an MIT-style license that can be
66
* found in the LICENSE file at https://angular.io/license
77
*/
8+
import * as tslib from 'tslib';
89
import * as ts from 'typescript';
910

1011
const pureFunctionComment = '@__PURE__';
1112

13+
// We include only exports that start with '__' because tslib helpers
14+
// all start with a suffix of two underscores.
15+
const tslibHelpers = new Set<string>(Object.keys(tslib).filter(h => h.startsWith('__')));
16+
1217
// Find all nodes from the AST in the subtree of node of SyntaxKind kind.
1318
export function collectDeepNodes<T extends ts.Node>(node: ts.Node, kind: ts.SyntaxKind): T[] {
1419
const nodes: T[] = [];
@@ -41,3 +46,7 @@ export function hasPureComment(node: ts.Node): boolean {
4146

4247
return !!leadingComment && leadingComment.some(comment => comment.text === pureFunctionComment);
4348
}
49+
50+
export function isHelperName(name: string): boolean {
51+
return tslibHelpers.has(name);
52+
}

packages/angular_devkit/build_optimizer/src/transforms/import-tslib.ts

+1-12
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@
66
* found in the LICENSE file at https://angular.io/license
77
*/
88
import * as ts from 'typescript';
9+
import { isHelperName } from '../helpers/ast-utils';
910

1011
/**
1112
* @deprecated From 0.9.0
@@ -89,15 +90,3 @@ function createTslibImport(
8990
return newNode;
9091
}
9192
}
92-
93-
function isHelperName(name: string): boolean {
94-
// TODO: there are more helpers than these, should we replace them all?
95-
const tsHelpers = [
96-
'__extends',
97-
'__decorate',
98-
'__metadata',
99-
'__param',
100-
];
101-
102-
return tsHelpers.indexOf(name) !== -1;
103-
}

packages/angular_devkit/build_optimizer/src/transforms/prefix-functions.ts

+9-5
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
import * as ts from 'typescript';
9-
import { addPureComment, hasPureComment } from '../helpers/ast-utils';
9+
import { addPureComment, hasPureComment, isHelperName } from '../helpers/ast-utils';
1010

1111
export function getPrefixFunctionsTransformer(): ts.TransformerFactory<ts.SourceFile> {
1212
return (context: ts.TransformationContext): ts.Transformer<ts.SourceFile> => {
@@ -44,10 +44,8 @@ export function findTopLevelFunctions(parentNode: ts.Node): Set<ts.Node> {
4444
// need to mark function calls inside them as pure.
4545
// Class static initializers in ES2015 are an exception we don't cover. They would need similar
4646
// processing as enums to prevent property setting from causing the class to be retained.
47-
if (ts.isFunctionDeclaration(node)
48-
|| ts.isFunctionExpression(node)
49-
|| ts.isClassDeclaration(node)
50-
|| ts.isClassExpression(node)
47+
if (ts.isFunctionLike(node)
48+
|| ts.isClassLike(node)
5149
|| ts.isArrowFunction(node)
5250
|| ts.isMethodDeclaration(node)
5351
) {
@@ -78,9 +76,15 @@ export function findTopLevelFunctions(parentNode: ts.Node): Set<ts.Node> {
7876
topLevelFunctions.add(node);
7977
} else if (ts.isCallExpression(innerNode)) {
8078
let expression: ts.Expression = innerNode.expression;
79+
80+
if (ts.isIdentifier(expression) && isHelperName(expression.text)) {
81+
return;
82+
}
83+
8184
while (expression && ts.isParenthesizedExpression(expression)) {
8285
expression = expression.expression;
8386
}
87+
8488
if (expression) {
8589
if (ts.isFunctionExpression(expression)) {
8690
// Skip IIFE's with arguments

packages/angular_devkit/build_optimizer/src/transforms/prefix-functions_spec.ts

+24
Original file line numberDiff line numberDiff line change
@@ -186,4 +186,28 @@ describe('prefix-functions', () => {
186186

187187
expect(tags.oneLine`${transform(input)}`).toEqual(tags.oneLine`${output}`);
188188
});
189+
190+
it(`doesn't add pure comments to tslib helpers`, () => {
191+
const input = tags.stripIndent`
192+
class LanguageState {
193+
194+
}
195+
196+
LanguageState.ctorParameters = () => [
197+
{ type: TranslateService },
198+
{ type: undefined, decorators: [{ type: Inject, args: [LANGUAGE_CONFIG,] }] }
199+
];
200+
201+
__decorate([
202+
Action(CheckLanguage),
203+
__metadata("design:type", Function),
204+
__metadata("design:paramtypes", [Object]),
205+
__metadata("design:returntype", void 0)
206+
], LanguageState.prototype, "checkLanguage", null);
207+
`;
208+
209+
const output = input;
210+
211+
expect(tags.oneLine`${transform(input)}`).toEqual(tags.oneLine`${output}`);
212+
});
189213
});

yarn.lock

+1-1
Original file line numberDiff line numberDiff line change
@@ -10549,7 +10549,7 @@ ts-node@^5.0.0:
1054910549
source-map-support "^0.5.3"
1055010550
yn "^2.0.0"
1055110551

10552-
tslib@^1.10.0:
10552+
tslib@1.10.0, tslib@^1.10.0:
1055310553
version "1.10.0"
1055410554
resolved "https://registry.yarnpkg.com/tslib/-/tslib-1.10.0.tgz#c3c19f95973fb0a62973fb09d90d961ee43e5c8a"
1055510555
integrity sha512-qOebF53frne81cf0S9B41ByenJ3/IuH8yJKngAX35CmiZySA0khhkovshKK+jGCaMnVomla7gVlIcc3EvKPbTQ==

0 commit comments

Comments
 (0)