Skip to content

Commit ab62c7a

Browse files
alan-agius4clydin
authored andcommitted
refactor(@angular-devkit/build-optimizer): refactor tests and logic to use non legacy tslib imports syntax
Tslib is no longer imported using namespace imports, with this change we update the logic to use named imports.
1 parent e49c926 commit ab62c7a

File tree

3 files changed

+55
-63
lines changed

3 files changed

+55
-63
lines changed

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

+4-1
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,10 @@ import { buildOptimizer } from './build-optimizer';
1414

1515

1616
describe('build-optimizer', () => {
17-
const imports = 'import { Injectable, Input, Component } from \'@angular/core\';';
17+
const imports = `
18+
import { __decorate, __metadata } from "tslib";
19+
import { Injectable, Input, Component } from '@angular/core';
20+
`;
1821
const clazz = 'var Clazz = (function () { function Clazz() { } return Clazz; }());';
1922
const decorators = 'Clazz.decorators = [ { type: Injectable } ];';
2023

packages/angular_devkit/build_optimizer/src/transforms/scrub-file.ts

+21-42
Original file line numberDiff line numberDiff line change
@@ -166,7 +166,7 @@ function isDecoratorAssignmentExpression(exprStmt: ts.ExpressionStatement): bool
166166
// Check if assignment is `Clazz = __decorate([...], Clazz)`.
167167
function isDecorateAssignmentExpression(
168168
exprStmt: ts.ExpressionStatement,
169-
tslibImports: ts.NamespaceImport[],
169+
tslibImports: ts.NamedImports[],
170170
checker: ts.TypeChecker,
171171
): boolean {
172172
if (!ts.isBinaryExpression(exprStmt.expression)) {
@@ -220,7 +220,7 @@ function isDecorateAssignmentExpression(
220220
function isAngularDecoratorExpression(
221221
exprStmt: ts.ExpressionStatement,
222222
ngMetadata: ts.Node[],
223-
tslibImports: ts.NamespaceImport[],
223+
tslibImports: ts.NamedImports[],
224224
checker: ts.TypeChecker,
225225
): boolean {
226226

@@ -373,7 +373,7 @@ function pickDecorationNodesToRemove(
373373
// are removed.
374374
function pickDecorateNodesToRemove(
375375
exprStmt: ts.ExpressionStatement,
376-
tslibImports: ts.NamespaceImport[],
376+
tslibImports: ts.NamedImports[],
377377
ngMetadata: ts.Node[],
378378
checker: ts.TypeChecker,
379379
): ts.Node[] {
@@ -538,9 +538,9 @@ function identifierIsMetadata(
538538
.some((spec) => metadata.includes(spec));
539539
}
540540

541-
// Find all namespace imports for `tslib`.
542-
function findTslibImports(node: ts.Node): ts.NamespaceImport[] {
543-
const imports: ts.NamespaceImport[] = [];
541+
// Find all named imports for `tslib`.
542+
function findTslibImports(node: ts.Node): ts.NamedImports[] {
543+
const imports: ts.NamedImports[] = [];
544544

545545
ts.forEachChild(node, child => {
546546
if (
@@ -549,7 +549,7 @@ function findTslibImports(node: ts.Node): ts.NamespaceImport[] {
549549
ts.isStringLiteral(child.moduleSpecifier) &&
550550
child.moduleSpecifier.text === 'tslib' &&
551551
child.importClause?.namedBindings &&
552-
ts.isNamespaceImport(child.importClause.namedBindings)
552+
ts.isNamedImports(child.importClause?.namedBindings)
553553
) {
554554
imports.push(child.importClause.namedBindings);
555555
}
@@ -558,50 +558,29 @@ function findTslibImports(node: ts.Node): ts.NamespaceImport[] {
558558
return imports;
559559
}
560560

561-
// Check if an identifier is part of the known tslib identifiers.
562-
function identifierIsTslib(
563-
id: ts.Identifier,
564-
tslibImports: ts.NamespaceImport[],
565-
checker: ts.TypeChecker,
566-
): boolean {
567-
const symbol = checker.getSymbolAtLocation(id);
568-
if (!symbol || !symbol.declarations || !symbol.declarations.length) {
569-
return false;
570-
}
571-
572-
return symbol
573-
.declarations
574-
.some((spec) => tslibImports.includes(spec as ts.NamespaceImport));
575-
}
576-
577561
// Check if a function call is a tslib helper.
578562
function isTslibHelper(
579563
callExpr: ts.CallExpression,
580564
helper: string,
581-
tslibImports: ts.NamespaceImport[],
565+
tslibImports: ts.NamedImports[],
582566
checker: ts.TypeChecker,
583567
) {
584-
let name: string | undefined;
585-
586-
if (ts.isIdentifier(callExpr.expression)) {
587-
name = callExpr.expression.text;
588-
} else if (ts.isPropertyAccessExpression(callExpr.expression)) {
589-
const left = callExpr.expression.expression;
568+
if (!ts.isIdentifier(callExpr.expression) || callExpr.expression.text !== helper) {
569+
return false;
570+
}
590571

591-
if (!ts.isIdentifier(left)) {
592-
return false;
593-
}
572+
const symbol = checker.getSymbolAtLocation(callExpr.expression);
573+
if (!symbol?.declarations?.length) {
574+
return false;
575+
}
594576

595-
if (!identifierIsTslib(left, tslibImports, checker)) {
596-
return false;
577+
for (const name of tslibImports) {
578+
for (const dec of symbol.declarations) {
579+
if (ts.isImportSpecifier(dec) && name.elements.includes(dec)) {
580+
return true;
581+
}
597582
}
598-
599-
name = callExpr.expression.name.text;
600-
} else {
601-
return false;
602583
}
603584

604-
// node.text on a name that starts with two underscores will return three instead.
605-
// Unless it's an expression like tslib.__decorate, in which case it's only 2.
606-
return name === `_${helper}` || name === helper;
585+
return false;
607586
}

packages/angular_devkit/build_optimizer/src/transforms/scrub-file_spec.ts

+30-20
Original file line numberDiff line numberDiff line change
@@ -90,13 +90,15 @@ describe('scrub-file', () => {
9090
describe('__decorate', () => {
9191
it('removes Angular decorators calls in __decorate', () => {
9292
const output = tags.stripIndent`
93-
import { Component, Injectable } from '@angular/core';
93+
import { __decorate } from "tslib";
94+
import { Component, Injectable } from '@angular/core';
9495
var Clazz = (function () {
9596
function Clazz() { }
9697
return Clazz;
9798
}());
9899
`;
99100
const input = tags.stripIndent`
101+
import { __decorate } from "tslib";
100102
import { Component, Injectable } from '@angular/core';
101103
var Clazz = (function () {
102104
function Clazz() { }
@@ -118,6 +120,7 @@ describe('scrub-file', () => {
118120

119121
it('removes constructor parameter metadata in __decorate', () => {
120122
const output = tags.stripIndent`
123+
import { __decorate, __metadata } from "tslib";
121124
import { Component, ElementRef } from '@angular/core';
122125
import { LibService } from 'another-lib';
123126
var Clazz = (function () {
@@ -126,6 +129,7 @@ describe('scrub-file', () => {
126129
}());
127130
`;
128131
const input = tags.stripIndent`
132+
import { __decorate, __metadata } from "tslib";
129133
import { Component, ElementRef } from '@angular/core';
130134
import { LibService } from 'another-lib';
131135
var Clazz = (function () {
@@ -148,6 +152,7 @@ describe('scrub-file', () => {
148152

149153
it('removes constructor parameter metadata when static properties are present', () => {
150154
const output = tags.stripIndent`
155+
import { __decorate, __metadata } from "tslib";
151156
import { Injectable } from '@angular/core';
152157
import { Logger } from 'another-lib';
153158
var GaService = (function () {
@@ -164,6 +169,7 @@ describe('scrub-file', () => {
164169
}());
165170
`;
166171
const input = tags.stripIndent`
172+
import { __decorate, __metadata } from "tslib";
167173
import { Injectable } from '@angular/core';
168174
import { Logger } from 'another-lib';
169175
var GaService = (function () {
@@ -190,6 +196,7 @@ describe('scrub-file', () => {
190196

191197
it('removes only Angular decorators calls in __decorate', () => {
192198
const output = tags.stripIndent`
199+
import { __decorate } from "tslib";
193200
import { Component } from '@angular/core';
194201
import { NotComponent } from 'another-lib';
195202
var Clazz = (function () {
@@ -201,6 +208,7 @@ describe('scrub-file', () => {
201208
}());
202209
`;
203210
const input = tags.stripIndent`
211+
import { __decorate } from "tslib";
204212
import { Component } from '@angular/core';
205213
import { NotComponent } from 'another-lib';
206214
var Clazz = (function () {
@@ -223,13 +231,12 @@ describe('scrub-file', () => {
223231

224232
it('recognizes tslib as well', () => {
225233
const input = tags.stripIndent`
226-
import * as tslib from "tslib";
227-
import * as tslib_2 from "tslib";
234+
import { __decorate } from "tslib";
228235
import { Component } from '@angular/core';
229236
import { NotComponent } from 'another-lib';
230237
var Clazz = (function () {
231238
function Clazz() { }
232-
Clazz = tslib.__decorate([
239+
Clazz = __decorate([
233240
NotComponent(),
234241
Component({
235242
selector: 'app-root',
@@ -242,7 +249,7 @@ describe('scrub-file', () => {
242249
243250
var Clazz2 = (function () {
244251
function Clazz2() { }
245-
Clazz2 = tslib_2.__decorate([
252+
Clazz2 = __decorate([
246253
NotComponent(),
247254
Component({
248255
selector: 'app-root',
@@ -254,21 +261,20 @@ describe('scrub-file', () => {
254261
}());
255262
`;
256263
const output = tags.stripIndent`
257-
import * as tslib from "tslib";
258-
import * as tslib_2 from "tslib";
264+
import { __decorate } from "tslib";
259265
import { Component } from '@angular/core';
260266
import { NotComponent } from 'another-lib';
261267
var Clazz = (function () {
262268
function Clazz() { }
263-
Clazz = tslib.__decorate([
269+
Clazz = __decorate([
264270
NotComponent()
265271
], Clazz);
266272
return Clazz;
267273
}());
268274
269275
var Clazz2 = (function () {
270276
function Clazz2() { }
271-
Clazz2 = tslib_2.__decorate([
277+
Clazz2 = __decorate([
272278
NotComponent()
273279
], Clazz2);
274280
return Clazz2;
@@ -281,7 +287,7 @@ describe('scrub-file', () => {
281287

282288
it('recognizes decorator imports in Angular core', () => {
283289
const input = tags.stripIndent`
284-
import * as tslib_1 from "tslib";
290+
import { __decorate } from "tslib";
285291
import { Injectable } from './di';
286292
var Console = /** @class */ (function () {
287293
function Console() {
@@ -292,15 +298,15 @@ describe('scrub-file', () => {
292298
Console.prototype.warn = function (message) {
293299
console.warn(message);
294300
};
295-
Console = tslib_1.__decorate([
301+
Console = __decorate([
296302
Injectable()
297303
], Console);
298304
return Console;
299305
}());
300306
export { Console };
301307
`;
302308
const output = tags.stripIndent`
303-
import * as tslib_1 from "tslib";
309+
import { __decorate } from "tslib";
304310
import { Injectable } from './di';
305311
var Console = /** @class */ (function () {
306312
function Console() {
@@ -425,6 +431,7 @@ describe('scrub-file', () => {
425431
describe('__metadata', () => {
426432
it('removes Angular decorators metadata', () => {
427433
const output = tags.stripIndent`
434+
import { __decorate, __metadata } from "tslib";
428435
import { Input, Output, EventEmitter, HostListener } from '@angular/core';
429436
var Clazz = (function () {
430437
function Clazz() {
@@ -434,6 +441,7 @@ describe('scrub-file', () => {
434441
}());
435442
`;
436443
const input = tags.stripIndent`
444+
import { __decorate, __metadata } from "tslib";
437445
import { Input, Output, EventEmitter, HostListener } from '@angular/core';
438446
import { NotInput } from 'another-lib';
439447
var Clazz = (function () {
@@ -464,6 +472,7 @@ describe('scrub-file', () => {
464472

465473
it('removes only Angular decorator metadata', () => {
466474
const output = tags.stripIndent`
475+
import { __decorate, __metadata } from "tslib";
467476
import { Input } from '@angular/core';
468477
import { NotInput } from 'another-lib';
469478
var Clazz = (function () {
@@ -483,6 +492,7 @@ describe('scrub-file', () => {
483492
}());
484493
`;
485494
const input = tags.stripIndent`
495+
import { __decorate, __metadata } from "tslib";
486496
import { Input } from '@angular/core';
487497
import { NotInput } from 'another-lib';
488498
var Clazz = (function () {
@@ -512,30 +522,28 @@ describe('scrub-file', () => {
512522

513523
it('recognizes tslib as well', () => {
514524
const input = tags.stripIndent`
515-
import * as tslib from "tslib";
516-
import * as tslib_2 from "tslib";
525+
import { __decorate, __metadata } from "tslib";
517526
import { Input } from '@angular/core';
518527
var Clazz = (function () {
519528
function Clazz() { }
520-
tslib.__decorate([
529+
__decorate([
521530
Input(),
522-
tslib.__metadata("design:type", Object)
531+
__metadata("design:type", Object)
523532
], Clazz.prototype, "selected", void 0);
524533
return Clazz;
525534
}());
526535
527536
var Clazz2 = (function () {
528537
function Clazz2() { }
529-
tslib_2.__decorate([
538+
__decorate([
530539
Input(),
531-
tslib_2.__metadata("design:type", Object)
540+
__metadata("design:type", Object)
532541
], Clazz.prototype, "selected", void 0);
533542
return Clazz2;
534543
}());
535544
`;
536545
const output = tags.stripIndent`
537-
import * as tslib from "tslib";
538-
import * as tslib_2 from "tslib";
546+
import { __decorate, __metadata } from "tslib";
539547
import { Input } from '@angular/core';
540548
var Clazz = (function () {
541549
function Clazz() { }
@@ -556,6 +564,7 @@ describe('scrub-file', () => {
556564
describe('__param', () => {
557565
it('removes all constructor parameters and their type metadata', () => {
558566
const output = tags.stripIndent`
567+
import { __decorate, __param, __metadata } from "tslib";
559568
var MyClass = /** @class */ (function () {
560569
function MyClass(myParam) {
561570
this.myProp = 'foo';
@@ -567,6 +576,7 @@ describe('scrub-file', () => {
567576
}());
568577
`;
569578
const input = tags.stripIndent`
579+
import { __decorate, __param, __metadata } from "tslib";
570580
var MyClass = /** @class */ (function () {
571581
function MyClass(myParam) {
572582
this.myProp = 'foo';

0 commit comments

Comments
 (0)