Skip to content

Commit 5cc26b7

Browse files
filipesilvahansl
authored andcommitted
fix(@angular-devkit/build-optimizer): wrap tsickle enums
Fix #229
1 parent e4d40ac commit 5cc26b7

File tree

2 files changed

+96
-2
lines changed

2 files changed

+96
-2
lines changed

packages/angular_devkit/build_optimizer/src/transforms/wrap-enums.ts

+62-2
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,7 @@ export function testWrapEnums(content: string) {
1414
// tslint:disable:max-line-length
1515
/var (\S+) = \{\};\r?\n(\1\.(\S+) = \d+;\r?\n)+\1\[\1\.(\S+)\] = "\4";\r?\n(\1\[\1\.(\S+)\] = "\S+";\r?\n*)+/,
1616
/var (\S+);(\/\*@__PURE__\*\/)*\r?\n\(function \(\1\) \{\s+(\1\[\1\["(\S+)"\] = 0\] = "\4";(\s+\1\[\1\["\S+"\] = \d\] = "\S+";)*\r?\n)\}\)\(\1 \|\| \(\1 = \{\}\)\);/,
17+
/\/\*\* @enum \{\w+\} \*\//,
1718
// tslint:enable:max-line-length
1819
];
1920

@@ -122,6 +123,7 @@ function visitBlockStatements(
122123
name,
123124
currentStatement,
124125
enumStatements,
126+
undefined,
125127
));
126128
// skip IIFE statement
127129
oIndex++;
@@ -141,13 +143,34 @@ function visitBlockStatements(
141143
name,
142144
currentStatement,
143145
enumStatements,
146+
variableDeclaration.initializer,
147+
));
148+
// skip enum member declarations
149+
oIndex += enumStatements.length;
150+
continue;
151+
}
152+
} else if (isObjectLiteralExpression(variableDeclaration.initializer)
153+
&& variableDeclaration.initializer.properties.length !== 0) {
154+
const literalPropertyCount = variableDeclaration.initializer.properties.length;
155+
const nextStatements = statements.slice(oIndex + 1);
156+
const enumStatements = findTsickleEnumStatements(name, nextStatements);
157+
if (enumStatements.length === literalPropertyCount) {
158+
// found an enum
159+
if (!updatedStatements) {
160+
updatedStatements = statements.slice();
161+
}
162+
// create wrapper and replace variable statement and enum member statements
163+
updatedStatements.splice(uIndex, enumStatements.length + 1, createWrappedEnum(
164+
name,
165+
currentStatement,
166+
enumStatements,
167+
variableDeclaration.initializer,
144168
));
145169
// skip enum member declarations
146170
oIndex += enumStatements.length;
147171
continue;
148172
}
149173
}
150-
151174
}
152175
}
153176

@@ -285,17 +308,54 @@ function findTs2_2EnumStatements(
285308
return enumStatements;
286309
}
287310

311+
// Tsickle enums have a variable statement with indexes, followed by value statements.
312+
// See https://github.com/angular/devkit/issues/229#issuecomment-338512056 fore more information.
313+
function findTsickleEnumStatements(
314+
name: string,
315+
statements: ts.Statement[],
316+
): ts.ExpressionStatement[] {
317+
const enumStatements: ts.ExpressionStatement[] = [];
318+
// let beforeValueStatements = true;
319+
320+
for (const stmt of statements) {
321+
// Ensure all statements are of the expected format and using the right identifer.
322+
// When we find a statement that isn't part of the enum, return what we collected so far.
323+
const binExpr = drilldownNodes<ts.BinaryExpression>(stmt,
324+
[
325+
{ prop: null, kind: ts.SyntaxKind.ExpressionStatement },
326+
{ prop: 'expression', kind: ts.SyntaxKind.BinaryExpression },
327+
]);
328+
329+
if (binExpr === null || binExpr.left.kind !== ts.SyntaxKind.ElementAccessExpression) {
330+
return enumStatements;
331+
}
332+
333+
const exprStmt = stmt as ts.ExpressionStatement;
334+
const leftExpr = binExpr.left as ts.ElementAccessExpression;
335+
336+
if (!(leftExpr.expression.kind === ts.SyntaxKind.Identifier
337+
&& (leftExpr.expression as ts.Identifier).text === name)) {
338+
return enumStatements;
339+
}
340+
enumStatements.push(exprStmt);
341+
}
342+
343+
return enumStatements;
344+
}
345+
288346
function createWrappedEnum(
289347
name: string,
290348
hostNode: ts.VariableStatement,
291349
statements: Array<ts.Statement>,
350+
literalInitializer: ts.ObjectLiteralExpression | undefined,
292351
): ts.Statement {
293352
const pureFunctionComment = '@__PURE__';
294353

354+
literalInitializer = literalInitializer || ts.createObjectLiteral();
295355
const innerVarStmt = ts.createVariableStatement(
296356
undefined,
297357
ts.createVariableDeclarationList([
298-
ts.createVariableDeclaration(name, undefined, ts.createObjectLiteral()),
358+
ts.createVariableDeclaration(name, undefined, literalInitializer),
299359
]),
300360
);
301361

packages/angular_devkit/build_optimizer/src/transforms/wrap-enums_spec.ts

+34
Original file line numberDiff line numberDiff line change
@@ -57,4 +57,38 @@ describe('wrap-enums', () => {
5757
expect(testWrapEnums(input)).toBeTruthy();
5858
expect(tags.oneLine`${transform(input)}`).toEqual(tags.oneLine`${output}`);
5959
});
60+
61+
it('wraps tsickle enums in IIFE', () => {
62+
const input = tags.stripIndent`
63+
/** @enum {number} */
64+
var FormatWidth = {
65+
Short: 0,
66+
Medium: 1,
67+
Long: 2,
68+
Full: 3,
69+
};
70+
FormatWidth[FormatWidth.Short] = "Short";
71+
FormatWidth[FormatWidth.Medium] = "Medium";
72+
FormatWidth[FormatWidth.Long] = "Long";
73+
FormatWidth[FormatWidth.Full] = "Full";
74+
`;
75+
const output = tags.stripIndent`
76+
/** @enum {number} */ var FormatWidth = /*@__PURE__*/ (function () {
77+
var FormatWidth = {
78+
Short: 0,
79+
Medium: 1,
80+
Long: 2,
81+
Full: 3,
82+
};
83+
FormatWidth[FormatWidth.Short] = "Short";
84+
FormatWidth[FormatWidth.Medium] = "Medium";
85+
FormatWidth[FormatWidth.Long] = "Long";
86+
FormatWidth[FormatWidth.Full] = "Full";
87+
return FormatWidth;
88+
})();
89+
`;
90+
91+
expect(testWrapEnums(input)).toBeTruthy();
92+
expect(tags.oneLine`${transform(input)}`).toEqual(tags.oneLine`${output}`);
93+
});
6094
});

0 commit comments

Comments
 (0)