Skip to content

Commit 7aec16f

Browse files
hanslfilipesilva
authored andcommitted
fix(@angular-devkit/build-optimizer): fix hoisted class declarations
The problem is that hoisted classes dont have the same name, so we need to change the regex, and to check the end of it for the class name. Also added a test to verify this works (based on RxJS issue). Also refactored the complex regex to make a bit more sense. Fixes #214.
1 parent f742045 commit 7aec16f

File tree

2 files changed

+84
-8
lines changed

2 files changed

+84
-8
lines changed

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

+23-8
Original file line numberDiff line numberDiff line change
@@ -5,22 +5,37 @@
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 { satisfies } from 'semver';
98
import * as ts from 'typescript';
109

1110

1211
export function testPrefixClasses(content: string) {
12+
const exportVarSetter = /(?:export )?(?:var|const)\s+(\S+)\s*=\s*/;
13+
const multiLineComment = /\s*(?:\/\*[\s\S]*?\*\/)?\s*/;
14+
const newLine = /\s*\r?\n\s*/;
15+
1316
const regexes = [
14-
// tslint:disable-next-line:max-line-length
15-
/^(?:export )?(var (\S+) = )(?:\/\*\* @class \*\/ )?(\(function \(\) \{\r?\n(?:\s+(?:\/\*\*| \*|\*\/|\/\/)[^\r?\n]*\r?\n)*\s+function \2\([^\)]*\) \{\r?\n)/,
16-
/^(?:export )?(var (\S+) = )(?:\/\*\* @class \*\/ )?(\(function \(_super\) \{\r?\n\s+\w*__extends\(\w+, _super\);\r?\n)/,
17-
];
17+
[
18+
/^/,
19+
exportVarSetter, multiLineComment,
20+
/\(/, multiLineComment,
21+
/\s*function \(\) {/, newLine,
22+
multiLineComment,
23+
/function \1\([^\)]*\) \{/, newLine,
24+
],
25+
[
26+
/^/,
27+
exportVarSetter, multiLineComment,
28+
/\(/, multiLineComment,
29+
/\s*function \(_super\) {/, newLine,
30+
/\w*__extends\(\w+, _super\);/,
31+
],
32+
].map(arr => new RegExp(arr.map(x => x.source).join(''), 'm'));
1833

1934
return regexes.some((regex) => regex.test(content));
2035
}
2136

2237
const superParameterName = '_super';
23-
const extendsHelperName = (satisfies(ts.version, '< 2.5') ? '_' : '') + '__extends';
38+
const extendsHelperName = '__extends';
2439

2540
export function getPrefixClassesTransformer(): ts.TransformerFactory<ts.SourceFile> {
2641
return (context: ts.TransformationContext): ts.Transformer<ts.SourceFile> => {
@@ -218,7 +233,7 @@ function isDownleveledClass(node: ts.Node): boolean {
218233
const extendCallExpression = firstStatement.expression;
219234

220235
if (!isIdentifier(extendCallExpression.expression)
221-
|| extendCallExpression.expression.text !== extendsHelperName) {
236+
|| !extendCallExpression.expression.text.endsWith(extendsHelperName)) {
222237
return false;
223238
}
224239

@@ -236,6 +251,6 @@ function isDownleveledClass(node: ts.Node): boolean {
236251

237252
return isFunctionDeclaration(secondStatement)
238253
&& secondStatement.name !== undefined
239-
&& secondStatement.name.text === className
254+
&& className.endsWith(secondStatement.name.text)
240255
&& returnStatement.expression.text === secondStatement.name.text;
241256
}

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

+61
Original file line numberDiff line numberDiff line change
@@ -217,4 +217,65 @@ describe('prefix-classes', () => {
217217
expect(tags.oneLine`${transform(input)}`).toEqual(tags.oneLine`${output}`);
218218
});
219219

220+
it('fixes the RxJS use case (issue #214)', () => {
221+
const input = `
222+
var ExtendedClass = /*@__PURE__*/ (/*@__PURE__*/ function (_super) {
223+
__extends(ExtendedClass, _super);
224+
function ExtendedClass() {
225+
return _super !== null && _super.apply(this, arguments) || this;
226+
}
227+
return ExtendedClass;
228+
}(StaticTestCase));
229+
230+
/**
231+
* We need this JSDoc comment for affecting ESDoc.
232+
* @ignore
233+
* @extends {Ignored}
234+
*/
235+
var zip_ZipSubscriber = /*@__PURE__*/ (/*@__PURE__*/ function (_super) {
236+
zip___extends(ZipSubscriber, _super);
237+
function ZipSubscriber(destination, project, values) {
238+
if (values === void 0) {
239+
values = Object.create(null);
240+
}
241+
_super.call(this, destination);
242+
this.iterators = [];
243+
this.active = 0;
244+
this.project = (typeof project === 'function') ? project : null;
245+
this.values = values;
246+
}
247+
return ZipSubscriber;
248+
}(Subscriber));
249+
`;
250+
const output = `
251+
var ExtendedClass = /*@__PURE__*/ (function (_super) {
252+
__extends(ExtendedClass, _super);
253+
function ExtendedClass() {
254+
return _super !== null && _super.apply(this, arguments) || this;
255+
}
256+
return ExtendedClass;
257+
}(StaticTestCase));
258+
259+
/**
260+
* We need this JSDoc comment for affecting ESDoc.
261+
* @ignore
262+
* @extends {Ignored}
263+
*/
264+
var zip_ZipSubscriber = /*@__PURE__*/ (function (_super) {
265+
zip___extends(ZipSubscriber, _super);
266+
function ZipSubscriber(destination, project, values) {
267+
if (values === void 0) {
268+
values = Object.create(null);
269+
}
270+
_super.call(this, destination);
271+
this.iterators = [];
272+
this.active = 0;
273+
this.project = (typeof project === 'function') ? project : null;
274+
this.values = values;
275+
}
276+
return ZipSubscriber;
277+
}(Subscriber));
278+
`;
279+
expect(tags.oneLine`${transform(input)}`).toEqual(tags.oneLine`${output}`);
280+
});
220281
});

0 commit comments

Comments
 (0)