From 5803b44de81eb6df0f3aa5494b143afeb0f8025b Mon Sep 17 00:00:00 2001 From: Nathan Shively-Sanders <293473+sandersn@users.noreply.github.com> Date: Fri, 19 Oct 2018 10:45:06 -0700 Subject: [PATCH] Fix alias of module.exports->exports->IIFE 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 })() ``` --- src/compiler/checker.ts | 9 ++++-- .../moduleExportAliasExports.symbols | 21 +++++++++++++ .../reference/moduleExportAliasExports.types | 30 +++++++++++++++++++ .../salsa/moduleExportAliasExports.ts | 10 +++++++ 4 files changed, 68 insertions(+), 2 deletions(-) create mode 100644 tests/baselines/reference/moduleExportAliasExports.symbols create mode 100644 tests/baselines/reference/moduleExportAliasExports.types create mode 100644 tests/cases/conformance/salsa/moduleExportAliasExports.ts diff --git a/src/compiler/checker.ts b/src/compiler/checker.ts index df817c3a79536..3d649d078207e 100644 --- a/src/compiler/checker.ts +++ b/src/compiler/checker.ts @@ -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); diff --git a/tests/baselines/reference/moduleExportAliasExports.symbols b/tests/baselines/reference/moduleExportAliasExports.symbols new file mode 100644 index 0000000000000..7253e7ed5f344 --- /dev/null +++ b/tests/baselines/reference/moduleExportAliasExports.symbols @@ -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)) + +})() + diff --git a/tests/baselines/reference/moduleExportAliasExports.types b/tests/baselines/reference/moduleExportAliasExports.types new file mode 100644 index 0000000000000..06640be0b6e70 --- /dev/null +++ b/tests/baselines/reference/moduleExportAliasExports.types @@ -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") + +})() + diff --git a/tests/cases/conformance/salsa/moduleExportAliasExports.ts b/tests/cases/conformance/salsa/moduleExportAliasExports.ts new file mode 100644 index 0000000000000..d716060e1bfb9 --- /dev/null +++ b/tests/cases/conformance/salsa/moduleExportAliasExports.ts @@ -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 +})()