fix(ngcc): recognize re-exports with imported TS helpers in CommonJS and UMD (#34527)

Previously, the `CommonJsReflectionHost` and `UmdReflectionHost` would
only recognize re-exports of the form `__export(...)`. This is what
re-exports look like, when the TypeScript helpers are emitted inline
(i.e. when compiling with the default [TypeScript compiler options][1]
that include `noEmitHelpers: false` and `importHelpers: false`).

However, when compiling with `importHelpers: true` and [tslib][2] (which
is the recommended way for optimized bundles), the re-exports will look
like: `tslib_1.__exportStar(..., exports)`
These types of re-exports were previously not recognized by the
CommonJS/UMD `ReflectionHost`s and thus ignored.

This commit fixes this by ensuring both re-export formats are
recognized.

[1]: https://www.typescriptlang.org/docs/handbook/compiler-options.html
[2]: https://www.npmjs.com/package/tslib

PR Close #34527
This commit is contained in:
George Kalpakas
2019-12-05 21:02:57 +02:00
committed by atscott
parent 56a19f833e
commit a88dc17e5b
3 changed files with 152 additions and 21 deletions

View File

@ -118,7 +118,7 @@ exports.SomeDirective = SomeDirective;
contents: `
var core = require('@angular/core');
var CtorDecoratedAsArray = (function() {
function CtorDecoratedAsArray(arg1) {
function CtorDecoratedAsArray(arg1) {
}
CtorDecoratedAsArray.ctorParameters = [{ type: ParamType, decorators: [{ type: Inject },] }];
return CtorDecoratedAsArray;
@ -510,7 +510,8 @@ var c = file_a.a;
var a_module = require('./a_module');
var b_module = require('./b_module');
var xtra_module = require('./xtra_module');
var wildcard_reexports = require('./wildcard_reexports');
var wildcard_reexports_emitted_helpers = require('./wildcard_reexports_emitted_helpers');
var wildcard_reexports_imported_helpers = require('./wildcard_reexports_imported_helpers');
`
},
{
@ -552,15 +553,24 @@ exports.xtra2 = xtra2;
`,
},
{
name: _('/wildcard_reexports.js'),
name: _('/wildcard_reexports_emitted_helpers.js'),
contents: `
function __export(m) {
for (var p in m) if (!exports.hasOwnProperty(p)) exports[p] = m[p];
}
var b_module = require("./b_module");
__export(b_module);
__export(require("./xtra_module"));
`
function __export(m) {
for (var p in m) if (!exports.hasOwnProperty(p)) exports[p] = m[p];
}
var b_module = require("./b_module");
__export(b_module);
__export(require("./xtra_module"));
`,
},
{
name: _('/wildcard_reexports_imported_helpers.js'),
contents: `
var tslib_1 = require("tslib");
var b_module = require("./b_module");
tslib_1.__exportStar(b_module, exports);
tslib_1.__exportStar(require("./xtra_module"), exports);
`,
},
];
@ -1763,12 +1773,42 @@ exports.ExternalModule = ExternalModule;
]);
});
it('should handle wildcard re-exports of other modules', () => {
it('should handle wildcard re-exports of other modules (with emitted helpers)', () => {
loadFakeCore(getFileSystem());
loadTestFiles(EXPORTS_FILES);
const bundle = makeTestBundleProgram(_('/index.js'));
const host = new CommonJsReflectionHost(new MockLogger(), false, bundle);
const file = getSourceFileOrError(bundle.program, _('/wildcard_reexports.js'));
const file =
getSourceFileOrError(bundle.program, _('/wildcard_reexports_emitted_helpers.js'));
const exportDeclarations = host.getExportsOfModule(file);
expect(exportDeclarations).not.toBe(null);
expect(Array.from(exportDeclarations !.entries())
.map(entry => [entry[0], entry[1].node !.getText(), entry[1].viaModule]))
.toEqual([
['Directive', `Directive: FnWithArg<(clazz: any) => any>`, _('/b_module')],
['a', `a = 'a'`, _('/b_module')],
['b', `b = a_module.a`, _('/b_module')],
['c', `a = 'a'`, _('/b_module')],
['d', `b = a_module.a`, _('/b_module')],
['e', `e = 'e'`, _('/b_module')],
['DirectiveX', `Directive: FnWithArg<(clazz: any) => any>`, _('/b_module')],
[
'SomeClass',
`SomeClass = (function() {\n function SomeClass() {}\n return SomeClass;\n}())`,
_('/b_module')
],
['xtra1', `xtra1 = 'xtra1'`, _('/xtra_module')],
['xtra2', `xtra2 = 'xtra2'`, _('/xtra_module')],
]);
});
it('should handle wildcard re-exports of other modules (with imported helpers)', () => {
loadFakeCore(getFileSystem());
loadTestFiles(EXPORTS_FILES);
const bundle = makeTestBundleProgram(_('/index.js'));
const host = new CommonJsReflectionHost(new MockLogger(), false, bundle);
const file =
getSourceFileOrError(bundle.program, _('/wildcard_reexports_imported_helpers.js'));
const exportDeclarations = host.getExportsOfModule(file);
expect(exportDeclarations).not.toBe(null);
expect(Array.from(exportDeclarations !.entries())

View File

@ -564,10 +564,10 @@ runInEachFileSystem(() => {
name: _('/index.js'),
contents: `
(function (global, factory) {
typeof exports === 'object' && typeof module !== 'undefined' ? factory(exports, require('./a_module'), require('./b_module'), require('./wildcard_reexports'), require('./wildcard_reexports_with_require')) :
typeof define === 'function' && define.amd ? define('index', ['exports', './a_module', './b_module', './wildcard_reexports', './wildcard_reexports_with_require'], factory) :
(factory(global.index, global.a_module, global.b_module, global.wildcard_reexports, global.wildcard_reexports_with_require));
}(this, (function (exports, a_module, b_module, wildcard_reexports, wildcard_reexports_with_require) { 'use strict';
typeof exports === 'object' && typeof module !== 'undefined' ? factory(exports, require('./a_module'), require('./b_module'), require('./wildcard_reexports'), require('./wildcard_reexports_imported_helpers'), require('./wildcard_reexports_with_require')) :
typeof define === 'function' && define.amd ? define('index', ['exports', './a_module', './b_module', './wildcard_reexports', './wildcard_reexports_imported_helpers', './wildcard_reexports_with_require'], factory) :
(factory(global.index, global.a_module, global.b_module, global.wildcard_reexports, global.wildcard_reexports_imported_helpers, global.wildcard_reexports_with_require));
}(this, (function (exports, a_module, b_module, wildcard_reexports, wildcard_reexports_imported_helpers, wildcard_reexports_with_require) { 'use strict';
})));
`
},
@ -635,6 +635,18 @@ runInEachFileSystem(() => {
}
__export(b_module);
__export(xtra_module);
})));`,
},
{
name: _('/wildcard_reexports_imported_helpers.js'),
contents: `
(function (global, factory) {
typeof exports === 'object' && typeof module !== 'undefined' ? factory(exports, require('tslib'), require('./b_module'), require('./xtra_module')) :
typeof define === 'function' && define.amd ? define('wildcard_reexports', ['exports', 'tslib', './b_module', './xtra_module'], factory) :
(factory(global.wildcard_reexports_imported_helpers, tslib, b_module, xtra_module));
}(this, (function (exports, tslib, b_module, xtra_module) { 'use strict';
tslib.__exportStar(b_module, exports);
tslib.__exportStar(xtra_module, exports);
})));`,
},
{
@ -1947,7 +1959,7 @@ runInEachFileSystem(() => {
expect(classSymbol !.implementation.valueDeclaration).toBe(node);
});
it('should handle wildcard re-exports of other modules', () => {
it('should handle wildcard re-exports of other modules (with emitted helpers)', () => {
loadFakeCore(getFileSystem());
loadTestFiles(EXPORTS_FILES);
const bundle = makeTestBundleProgram(_('/index.js'));
@ -1975,6 +1987,35 @@ runInEachFileSystem(() => {
]);
});
it('should handle wildcard re-exports of other modules (with imported helpers)', () => {
loadFakeCore(getFileSystem());
loadTestFiles(EXPORTS_FILES);
const bundle = makeTestBundleProgram(_('/index.js'));
const host = new UmdReflectionHost(new MockLogger(), false, bundle);
const file =
getSourceFileOrError(bundle.program, _('/wildcard_reexports_imported_helpers.js'));
const exportDeclarations = host.getExportsOfModule(file);
expect(exportDeclarations).not.toBe(null);
expect(Array.from(exportDeclarations !.entries())
.map(entry => [entry[0], entry[1].node !.getText(), entry[1].viaModule]))
.toEqual([
['Directive', `Directive: FnWithArg<(clazz: any) => any>`, _('/b_module')],
['a', `a = 'a'`, _('/b_module')],
['b', `b = a_module.a`, _('/b_module')],
['c', `a = 'a'`, _('/b_module')],
['d', `b = a_module.a`, _('/b_module')],
['e', `e = 'e'`, _('/b_module')],
['DirectiveX', `Directive: FnWithArg<(clazz: any) => any>`, _('/b_module')],
[
'SomeClass',
`SomeClass = (function() {\n function SomeClass() {}\n return SomeClass;\n }())`,
_('/b_module')
],
['xtra1', `xtra1 = 'xtra1'`, _('/xtra_module')],
['xtra2', `xtra2 = 'xtra2'`, _('/xtra_module')],
]);
});
it('should handle wildcard re-exports of other modules using `require()` calls', () => {
loadFakeCore(getFileSystem());
loadTestFiles(EXPORTS_FILES);