Skip to content

Commit

Permalink
Fix alias of module.exports->exports->IIFE (#27992)
Browse files Browse the repository at this point in the history
In JS, when you assign `module.exports = exports` and the entire module is
wrapped in an IIFE, the resulting `export=` symbol, after following
aliases, is the module itself. This results in trying to merge the
file's exports with itself inside `getCommonJsExportEquals`, since it
thinks that it has found new exports, possibly in an object literal,
that need to be merged with the file's exports.

For example:

```js
(function() {
exports.a = 1
module.exports = exports
})()
```
  • Loading branch information
sandersn authored Oct 19, 2018
1 parent b64d08a commit e379aeb
Show file tree
Hide file tree
Showing 4 changed files with 68 additions and 2 deletions.
9 changes: 7 additions & 2 deletions src/compiler/checker.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2353,11 +2353,16 @@ namespace ts {
function resolveExternalModuleSymbol(moduleSymbol: Symbol, dontResolveAlias?: boolean): Symbol;
function resolveExternalModuleSymbol(moduleSymbol: Symbol | undefined, dontResolveAlias?: boolean): Symbol | undefined;
function resolveExternalModuleSymbol(moduleSymbol: Symbol, dontResolveAlias?: boolean): Symbol {
return moduleSymbol && getMergedSymbol(getCommonJsExportEquals(resolveSymbol(moduleSymbol.exports!.get(InternalSymbolName.ExportEquals), dontResolveAlias), moduleSymbol)) || moduleSymbol;
if (moduleSymbol) {
const exportEquals = resolveSymbol(moduleSymbol.exports!.get(InternalSymbolName.ExportEquals), dontResolveAlias);
const exported = getCommonJsExportEquals(exportEquals, moduleSymbol);
return getMergedSymbol(exported) || moduleSymbol;
}
return undefined!;
}

function getCommonJsExportEquals(exported: Symbol | undefined, moduleSymbol: Symbol): Symbol | undefined {
if (!exported || exported === unknownSymbol || moduleSymbol.exports!.size === 1) {
if (!exported || exported === unknownSymbol || exported === moduleSymbol || moduleSymbol.exports!.size === 1) {
return exported;
}
const merged = cloneSymbol(exported);
Expand Down
21 changes: 21 additions & 0 deletions tests/baselines/reference/moduleExportAliasExports.symbols
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
=== tests/cases/conformance/salsa/Eloquent.js ===
// bug #27365, crashes from github.com/marijnh/Eloquent-JavaScript
(function() {
exports.bigOak = 1
>exports.bigOak : Symbol(bigOak, Decl(Eloquent.js, 1, 13))
>exports : Symbol(bigOak, Decl(Eloquent.js, 1, 13))
>bigOak : Symbol(bigOak, Decl(Eloquent.js, 1, 13))

exports.everywhere = 2
>exports.everywhere : Symbol(everywhere, Decl(Eloquent.js, 2, 18))
>exports : Symbol(everywhere, Decl(Eloquent.js, 2, 18))
>everywhere : Symbol(everywhere, Decl(Eloquent.js, 2, 18))

module.exports = exports
>module.exports : Symbol("tests/cases/conformance/salsa/Eloquent", Decl(Eloquent.js, 0, 0))
>module : Symbol(export=, Decl(Eloquent.js, 3, 22))
>exports : Symbol(export=, Decl(Eloquent.js, 3, 22))
>exports : Symbol("tests/cases/conformance/salsa/Eloquent", Decl(Eloquent.js, 0, 0))

})()

30 changes: 30 additions & 0 deletions tests/baselines/reference/moduleExportAliasExports.types
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
=== tests/cases/conformance/salsa/Eloquent.js ===
// bug #27365, crashes from github.com/marijnh/Eloquent-JavaScript
(function() {
>(function() {exports.bigOak = 1exports.everywhere = 2module.exports = exports})() : void
>(function() {exports.bigOak = 1exports.everywhere = 2module.exports = exports}) : () => void
>function() {exports.bigOak = 1exports.everywhere = 2module.exports = exports} : () => void

exports.bigOak = 1
>exports.bigOak = 1 : 1
>exports.bigOak : number
>exports : typeof import("tests/cases/conformance/salsa/Eloquent")
>bigOak : number
>1 : 1

exports.everywhere = 2
>exports.everywhere = 2 : 2
>exports.everywhere : number
>exports : typeof import("tests/cases/conformance/salsa/Eloquent")
>everywhere : number
>2 : 2

module.exports = exports
>module.exports = exports : typeof import("tests/cases/conformance/salsa/Eloquent")
>module.exports : typeof import("tests/cases/conformance/salsa/Eloquent")
>module : { "tests/cases/conformance/salsa/Eloquent": typeof import("tests/cases/conformance/salsa/Eloquent"); }
>exports : typeof import("tests/cases/conformance/salsa/Eloquent")
>exports : typeof import("tests/cases/conformance/salsa/Eloquent")

})()

10 changes: 10 additions & 0 deletions tests/cases/conformance/salsa/moduleExportAliasExports.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
// @noEmit: true
// @allowJs: true
// @checkJs: true
// @Filename: Eloquent.js
// bug #27365, crashes from github.com/marijnh/Eloquent-JavaScript
(function() {
exports.bigOak = 1
exports.everywhere = 2
module.exports = exports
})()

0 comments on commit e379aeb

Please sign in to comment.