@angular-devkit/build-optimizer 0.800.0 → 0.800.4

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@angular-devkit/build-optimizer",
3
- "version": "0.800.0",
3
+ "version": "0.800.4",
4
4
  "description": "Angular Build Optimizer",
5
5
  "experimental": true,
6
6
  "main": "src/index.js",
@@ -9,7 +9,6 @@ Object.defineProperty(exports, "__esModule", { value: true });
9
9
  */
10
10
  const fs_1 = require("fs");
11
11
  const transform_javascript_1 = require("../helpers/transform-javascript");
12
- const class_fold_1 = require("../transforms/class-fold");
13
12
  const import_tslib_1 = require("../transforms/import-tslib");
14
13
  const prefix_classes_1 = require("../transforms/prefix-classes");
15
14
  const prefix_functions_1 = require("../transforms/prefix-functions");
@@ -86,12 +85,12 @@ function buildOptimizer(options) {
86
85
  // It will mark both `require()` calls and `console.log(stuff)` as pure.
87
86
  // We only apply it to whitelisted modules, since we know they are safe.
88
87
  // getPrefixFunctionsTransformer needs to be before getFoldFileTransformer.
89
- prefix_functions_1.getPrefixFunctionsTransformer, selectedGetScrubFileTransformer, class_fold_1.getFoldFileTransformer);
88
+ prefix_functions_1.getPrefixFunctionsTransformer, selectedGetScrubFileTransformer);
90
89
  typeCheck = true;
91
90
  }
92
91
  else if (scrub_file_1.testScrubFile(content)) {
93
92
  // Always test as these require the type checker
94
- getTransforms.push(selectedGetScrubFileTransformer, class_fold_1.getFoldFileTransformer);
93
+ getTransforms.push(selectedGetScrubFileTransformer);
95
94
  typeCheck = true;
96
95
  }
97
96
  // tests are not needed for fast path
@@ -6,4 +6,5 @@
6
6
  * found in the LICENSE file at https://angular.io/license
7
7
  */
8
8
  import * as ts from 'typescript';
9
+ /** @deprecated Since version 8 */
9
10
  export declare function getFoldFileTransformer(program: ts.Program): ts.TransformerFactory<ts.SourceFile>;
@@ -9,6 +9,7 @@ Object.defineProperty(exports, "__esModule", { value: true });
9
9
  */
10
10
  const ts = require("typescript");
11
11
  const ast_utils_1 = require("../helpers/ast-utils");
12
+ /** @deprecated Since version 8 */
12
13
  function getFoldFileTransformer(program) {
13
14
  const checker = program.getTypeChecker();
14
15
  return (context) => {
@@ -54,8 +54,10 @@ function visitBlockStatements(statements, context) {
54
54
  }
55
55
  };
56
56
  // 'oIndex' is the original statement index; 'uIndex' is the updated statement index
57
- for (let oIndex = 0, uIndex = 0; oIndex < statements.length; oIndex++, uIndex++) {
57
+ for (let oIndex = 0, uIndex = 0; oIndex < statements.length - 1; oIndex++, uIndex++) {
58
58
  const currentStatement = statements[oIndex];
59
+ let newStatement;
60
+ let oldStatementsLength = 0;
59
61
  // these can't contain an enum declaration
60
62
  if (currentStatement.kind === ts.SyntaxKind.ImportDeclaration) {
61
63
  continue;
@@ -65,44 +67,42 @@ function visitBlockStatements(statements, context) {
65
67
  // * be a variable statement
66
68
  // * have only one declaration
67
69
  // * have an identifer as a declaration name
68
- if (oIndex < statements.length - 1
69
- && ts.isVariableStatement(currentStatement)
70
+ // ClassExpression declarations must:
71
+ // * not be last statement
72
+ // * be a variable statement
73
+ // * have only one declaration
74
+ // * have an ClassExpression or BinaryExpression and a right
75
+ // of kind ClassExpression as a initializer
76
+ if (ts.isVariableStatement(currentStatement)
70
77
  && currentStatement.declarationList.declarations.length === 1) {
71
78
  const variableDeclaration = currentStatement.declarationList.declarations[0];
79
+ const initializer = variableDeclaration.initializer;
72
80
  if (ts.isIdentifier(variableDeclaration.name)) {
73
81
  const name = variableDeclaration.name.text;
74
- if (!variableDeclaration.initializer) {
82
+ if (!initializer) {
75
83
  const iife = findTs2_3EnumIife(name, statements[oIndex + 1]);
76
84
  if (iife) {
77
- // found an enum
78
- if (!updatedStatements) {
79
- updatedStatements = statements.slice();
80
- }
81
85
  // update IIFE and replace variable statement and old IIFE
82
- updatedStatements.splice(uIndex, 2, updateEnumIife(currentStatement, iife[0], iife[1]));
86
+ oldStatementsLength = 2;
87
+ newStatement = updateEnumIife(currentStatement, iife[0], iife[1]);
83
88
  // skip IIFE statement
84
89
  oIndex++;
85
- continue;
86
90
  }
87
91
  }
88
- else if (ts.isObjectLiteralExpression(variableDeclaration.initializer)
89
- && variableDeclaration.initializer.properties.length === 0) {
92
+ else if (ts.isObjectLiteralExpression(initializer)
93
+ && initializer.properties.length === 0) {
90
94
  const enumStatements = findTs2_2EnumStatements(name, statements, oIndex + 1);
91
95
  if (enumStatements.length > 0) {
92
- // found an enum
93
- if (!updatedStatements) {
94
- updatedStatements = statements.slice();
95
- }
96
96
  // create wrapper and replace variable statement and enum member statements
97
- updatedStatements.splice(uIndex, enumStatements.length + 1, createWrappedEnum(name, currentStatement, enumStatements, variableDeclaration.initializer));
97
+ oldStatementsLength = enumStatements.length + 1;
98
+ newStatement = createWrappedEnum(name, currentStatement, enumStatements, initializer);
98
99
  // skip enum member declarations
99
100
  oIndex += enumStatements.length;
100
- continue;
101
101
  }
102
102
  }
103
- else if (ts.isObjectLiteralExpression(variableDeclaration.initializer)
104
- && variableDeclaration.initializer.properties.length !== 0) {
105
- const literalPropertyCount = variableDeclaration.initializer.properties.length;
103
+ else if (ts.isObjectLiteralExpression(initializer)
104
+ && initializer.properties.length !== 0) {
105
+ const literalPropertyCount = initializer.properties.length;
106
106
  // tsickle es2015 enums first statement is an export declaration
107
107
  const isPotentialEnumExport = ts.isExportDeclaration(statements[oIndex + 1]);
108
108
  if (isPotentialEnumExport) {
@@ -111,20 +111,45 @@ function visitBlockStatements(statements, context) {
111
111
  }
112
112
  const enumStatements = findEnumNameStatements(name, statements, oIndex + 1);
113
113
  if (enumStatements.length === literalPropertyCount) {
114
- // found an enum
115
- if (!updatedStatements) {
116
- updatedStatements = statements.slice();
117
- }
118
114
  // create wrapper and replace variable statement and enum member statements
119
- const deleteCount = enumStatements.length + (isPotentialEnumExport ? 2 : 1);
120
- updatedStatements.splice(uIndex, deleteCount, createWrappedEnum(name, currentStatement, enumStatements, variableDeclaration.initializer, isPotentialEnumExport));
115
+ oldStatementsLength = enumStatements.length + (isPotentialEnumExport ? 2 : 1);
116
+ newStatement = createWrappedEnum(name, currentStatement, enumStatements, initializer, isPotentialEnumExport);
121
117
  // skip enum member declarations
122
118
  oIndex += enumStatements.length;
119
+ }
120
+ }
121
+ else if (ts.isClassExpression(initializer)
122
+ || (ts.isBinaryExpression(initializer)
123
+ && ts.isClassExpression(initializer.right))) {
124
+ const classStatements = findClassStatements(name, statements, oIndex);
125
+ if (!classStatements) {
123
126
  continue;
124
127
  }
128
+ oldStatementsLength = classStatements.length;
129
+ newStatement = createWrappedClass(variableDeclaration, classStatements);
130
+ oIndex += classStatements.length - 1;
125
131
  }
126
132
  }
127
133
  }
134
+ else if (ts.isClassDeclaration(currentStatement)) {
135
+ const name = currentStatement.name.text;
136
+ const classStatements = findClassStatements(name, statements, oIndex);
137
+ if (!classStatements) {
138
+ continue;
139
+ }
140
+ oldStatementsLength = classStatements.length;
141
+ newStatement = createWrappedClass(currentStatement, classStatements);
142
+ oIndex += classStatements.length - 1;
143
+ }
144
+ if (newStatement && newStatement.length > 0) {
145
+ if (!updatedStatements) {
146
+ updatedStatements = [...statements];
147
+ }
148
+ updatedStatements.splice(uIndex, oldStatementsLength, ...newStatement);
149
+ // When having more than a single new statement
150
+ // we need to update the update Index
151
+ uIndex += (newStatement ? newStatement.length - 1 : 0);
152
+ }
128
153
  const result = ts.visitNode(currentStatement, visitor);
129
154
  if (result !== currentStatement) {
130
155
  if (!updatedStatements) {
@@ -210,7 +235,12 @@ function findTs2_3EnumIife(name, statement) {
210
235
  return null;
211
236
  }
212
237
  const memberArgument = assignment.argumentExpression;
213
- if (!memberArgument || !ts.isBinaryExpression(memberArgument)
238
+ // String enum
239
+ if (ts.isStringLiteral(memberArgument)) {
240
+ return [callExpression, exportExpression];
241
+ }
242
+ // Non string enums
243
+ if (!ts.isBinaryExpression(memberArgument)
214
244
  || memberArgument.operatorToken.kind !== ts.SyntaxKind.FirstAssignment) {
215
245
  return null;
216
246
  }
@@ -307,6 +337,66 @@ function updateHostNode(hostNode, expression) {
307
337
  ]));
308
338
  return outerVarStmt;
309
339
  }
340
+ /**
341
+ * Find class expression or declaration statements.
342
+ *
343
+ * The classExpressions block to wrap in an iife must
344
+ * - end with an ExpressionStatement
345
+ * - it's expression must be a BinaryExpression
346
+ * - have the same name
347
+ *
348
+ * ```
349
+ let Foo = class Foo {};
350
+ Foo = __decorate([]);
351
+ ```
352
+ */
353
+ function findClassStatements(name, statements, statementIndex) {
354
+ let count = 1;
355
+ for (let index = statementIndex + 1; index < statements.length; ++index) {
356
+ const statement = statements[index];
357
+ if (!ts.isExpressionStatement(statement)) {
358
+ break;
359
+ }
360
+ const expression = statement.expression;
361
+ if (ts.isCallExpression(expression)) {
362
+ // Ex:
363
+ // setClassMetadata(FooClass, [{}], void 0);
364
+ // __decorate([propDecorator()], FooClass.prototype, "propertyName", void 0);
365
+ // __decorate([propDecorator()], FooClass, "propertyName", void 0);
366
+ // __decorate$1([propDecorator()], FooClass, "propertyName", void 0);
367
+ const args = expression.arguments;
368
+ if (args.length > 2) {
369
+ const isReferenced = args.some(arg => {
370
+ const potentialIdentifier = ts.isPropertyAccessExpression(arg) ? arg.expression : arg;
371
+ return ts.isIdentifier(potentialIdentifier) && potentialIdentifier.text === name;
372
+ });
373
+ if (isReferenced) {
374
+ count++;
375
+ continue;
376
+ }
377
+ }
378
+ }
379
+ else if (ts.isBinaryExpression(expression)) {
380
+ const node = ts.isBinaryExpression(expression.left)
381
+ ? expression.left.left
382
+ : expression.left;
383
+ const leftExpression = ts.isPropertyAccessExpression(node)
384
+ // Static Properties // Ex: Foo.bar = 'value';
385
+ ? node.expression
386
+ // Ex: FooClass = __decorate([Component()], FooClass);
387
+ : node;
388
+ if (ts.isIdentifier(leftExpression) && leftExpression.text === name) {
389
+ count++;
390
+ continue;
391
+ }
392
+ }
393
+ break;
394
+ }
395
+ if (count > 1) {
396
+ return statements.slice(statementIndex, statementIndex + count);
397
+ }
398
+ return undefined;
399
+ }
310
400
  function updateEnumIife(hostNode, iife, exportAssignment) {
311
401
  if (!ts.isParenthesizedExpression(iife.expression)
312
402
  || !ts.isFunctionExpression(iife.expression.expression)) {
@@ -331,10 +421,9 @@ function updateEnumIife(hostNode, iife, exportAssignment) {
331
421
  if (exportAssignment) {
332
422
  value = ts.createBinary(exportAssignment, ts.SyntaxKind.FirstAssignment, updatedIife);
333
423
  }
334
- return updateHostNode(hostNode, value);
424
+ return [updateHostNode(hostNode, value)];
335
425
  }
336
- function createWrappedEnum(name, hostNode, statements, literalInitializer, addExportModifier = false) {
337
- literalInitializer = literalInitializer || ts.createObjectLiteral();
426
+ function createWrappedEnum(name, hostNode, statements, literalInitializer = ts.createObjectLiteral(), addExportModifier = false) {
338
427
  const node = addExportModifier
339
428
  ? ts.updateVariableStatement(hostNode, [ts.createToken(ts.SyntaxKind.ExportKeyword)], hostNode.declarationList)
340
429
  : hostNode;
@@ -347,5 +436,27 @@ function createWrappedEnum(name, hostNode, statements, literalInitializer, addEx
347
436
  ...statements,
348
437
  innerReturn,
349
438
  ]);
350
- return updateHostNode(node, ast_utils_1.addPureComment(ts.createParen(iife)));
439
+ return [updateHostNode(node, ast_utils_1.addPureComment(ts.createParen(iife)))];
440
+ }
441
+ function createWrappedClass(hostNode, statements) {
442
+ const name = hostNode.name.text;
443
+ const updatedStatements = [...statements];
444
+ if (ts.isClassDeclaration(hostNode)) {
445
+ updatedStatements[0] = ts.createClassDeclaration(hostNode.decorators, undefined, hostNode.name, hostNode.typeParameters, hostNode.heritageClauses, hostNode.members);
446
+ }
447
+ const pureIife = ast_utils_1.addPureComment(ts.createImmediatelyInvokedArrowFunction([
448
+ ...updatedStatements,
449
+ ts.createReturn(ts.createIdentifier(name)),
450
+ ]));
451
+ const modifiers = hostNode.modifiers;
452
+ const isDefault = !!modifiers
453
+ && modifiers.some(x => x.kind === ts.SyntaxKind.DefaultKeyword);
454
+ const newStatement = [];
455
+ newStatement.push(ts.createVariableStatement(isDefault ? undefined : modifiers, ts.createVariableDeclarationList([
456
+ ts.createVariableDeclaration(name, undefined, pureIife),
457
+ ], ts.NodeFlags.Const)));
458
+ if (isDefault) {
459
+ newStatement.push(ts.createExportAssignment(undefined, undefined, false, ts.createIdentifier(name)));
460
+ }
461
+ return newStatement;
351
462
  }