@angular-devkit/build-optimizer 0.800.0-rc.4 → 0.800.3

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-rc.4",
3
+ "version": "0.800.3",
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,42 @@ 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) {
145
+ if (!updatedStatements) {
146
+ updatedStatements = [...statements];
147
+ }
148
+ updatedStatements.splice(uIndex, oldStatementsLength, newStatement);
149
+ }
128
150
  const result = ts.visitNode(currentStatement, visitor);
129
151
  if (result !== currentStatement) {
130
152
  if (!updatedStatements) {
@@ -307,6 +329,66 @@ function updateHostNode(hostNode, expression) {
307
329
  ]));
308
330
  return outerVarStmt;
309
331
  }
332
+ /**
333
+ * Find class expression or declaration statements.
334
+ *
335
+ * The classExpressions block to wrap in an iife must
336
+ * - end with an ExpressionStatement
337
+ * - it's expression must be a BinaryExpression
338
+ * - have the same name
339
+ *
340
+ * ```
341
+ let Foo = class Foo {};
342
+ Foo = __decorate([]);
343
+ ```
344
+ */
345
+ function findClassStatements(name, statements, statementIndex) {
346
+ let count = 1;
347
+ for (let index = statementIndex + 1; index < statements.length; ++index) {
348
+ const statement = statements[index];
349
+ if (!ts.isExpressionStatement(statement)) {
350
+ break;
351
+ }
352
+ const expression = statement.expression;
353
+ if (ts.isCallExpression(expression)) {
354
+ // Ex:
355
+ // setClassMetadata(FooClass, [{}], void 0);
356
+ // __decorate([propDecorator()], FooClass.prototype, "propertyName", void 0);
357
+ // __decorate([propDecorator()], FooClass, "propertyName", void 0);
358
+ // __decorate$1([propDecorator()], FooClass, "propertyName", void 0);
359
+ const args = expression.arguments;
360
+ if (args.length > 2) {
361
+ const isReferenced = args.some(arg => {
362
+ const potentialIdentifier = ts.isPropertyAccessExpression(arg) ? arg.expression : arg;
363
+ return ts.isIdentifier(potentialIdentifier) && potentialIdentifier.text === name;
364
+ });
365
+ if (isReferenced) {
366
+ count++;
367
+ continue;
368
+ }
369
+ }
370
+ }
371
+ else if (ts.isBinaryExpression(expression)) {
372
+ const node = ts.isBinaryExpression(expression.left)
373
+ ? expression.left.left
374
+ : expression.left;
375
+ const leftExpression = ts.isPropertyAccessExpression(node)
376
+ // Static Properties // Ex: Foo.bar = 'value';
377
+ ? node.expression
378
+ // Ex: FooClass = __decorate([Component()], FooClass);
379
+ : node;
380
+ if (ts.isIdentifier(leftExpression) && leftExpression.text === name) {
381
+ count++;
382
+ continue;
383
+ }
384
+ }
385
+ break;
386
+ }
387
+ if (count > 1) {
388
+ return statements.slice(statementIndex, statementIndex + count);
389
+ }
390
+ return undefined;
391
+ }
310
392
  function updateEnumIife(hostNode, iife, exportAssignment) {
311
393
  if (!ts.isParenthesizedExpression(iife.expression)
312
394
  || !ts.isFunctionExpression(iife.expression.expression)) {
@@ -333,8 +415,7 @@ function updateEnumIife(hostNode, iife, exportAssignment) {
333
415
  }
334
416
  return updateHostNode(hostNode, value);
335
417
  }
336
- function createWrappedEnum(name, hostNode, statements, literalInitializer, addExportModifier = false) {
337
- literalInitializer = literalInitializer || ts.createObjectLiteral();
418
+ function createWrappedEnum(name, hostNode, statements, literalInitializer = ts.createObjectLiteral(), addExportModifier = false) {
338
419
  const node = addExportModifier
339
420
  ? ts.updateVariableStatement(hostNode, [ts.createToken(ts.SyntaxKind.ExportKeyword)], hostNode.declarationList)
340
421
  : hostNode;
@@ -349,3 +430,17 @@ function createWrappedEnum(name, hostNode, statements, literalInitializer, addEx
349
430
  ]);
350
431
  return updateHostNode(node, ast_utils_1.addPureComment(ts.createParen(iife)));
351
432
  }
433
+ function createWrappedClass(hostNode, statements) {
434
+ const name = hostNode.name.text;
435
+ const updatedStatements = [...statements];
436
+ if (ts.isClassDeclaration(hostNode)) {
437
+ updatedStatements[0] = ts.createClassDeclaration(hostNode.decorators, undefined, hostNode.name, hostNode.typeParameters, hostNode.heritageClauses, hostNode.members);
438
+ }
439
+ const pureIife = ast_utils_1.addPureComment(ts.createImmediatelyInvokedArrowFunction([
440
+ ...updatedStatements,
441
+ ts.createReturn(ts.createIdentifier(name)),
442
+ ]));
443
+ return ts.createVariableStatement(hostNode.modifiers, ts.createVariableDeclarationList([
444
+ ts.createVariableDeclaration(name, undefined, pureIife),
445
+ ], ts.NodeFlags.Const));
446
+ }