From 6a6e51336e214c47a709e9aded6b961d836ae715 Mon Sep 17 00:00:00 2001 From: Wesley Wigham Date: Thu, 24 Aug 2017 17:08:57 -0700 Subject: [PATCH] Call dynamic import transform on expression used by export equal statement (#18028) * Call dynamic import transform on expression used by export equal statement * Use Debug.fail --- src/compiler/transformers/module/module.ts | 46 +++++++++++-------- .../importCallExpressionInExportEqualsAMD.js | 22 +++++++++ ...ortCallExpressionInExportEqualsAMD.symbols | 10 ++++ ...mportCallExpressionInExportEqualsAMD.types | 14 ++++++ .../importCallExpressionInExportEqualsCJS.js | 18 ++++++++ ...ortCallExpressionInExportEqualsCJS.symbols | 10 ++++ ...mportCallExpressionInExportEqualsCJS.types | 14 ++++++ .../importCallExpressionInExportEqualsUMD.js | 39 ++++++++++++++++ ...ortCallExpressionInExportEqualsUMD.symbols | 10 ++++ ...mportCallExpressionInExportEqualsUMD.types | 14 ++++++ .../importCallExpressionInExportEqualsAMD.ts | 9 ++++ .../importCallExpressionInExportEqualsCJS.ts | 9 ++++ .../importCallExpressionInExportEqualsUMD.ts | 9 ++++ 13 files changed, 204 insertions(+), 20 deletions(-) create mode 100644 tests/baselines/reference/importCallExpressionInExportEqualsAMD.js create mode 100644 tests/baselines/reference/importCallExpressionInExportEqualsAMD.symbols create mode 100644 tests/baselines/reference/importCallExpressionInExportEqualsAMD.types create mode 100644 tests/baselines/reference/importCallExpressionInExportEqualsCJS.js create mode 100644 tests/baselines/reference/importCallExpressionInExportEqualsCJS.symbols create mode 100644 tests/baselines/reference/importCallExpressionInExportEqualsCJS.types create mode 100644 tests/baselines/reference/importCallExpressionInExportEqualsUMD.js create mode 100644 tests/baselines/reference/importCallExpressionInExportEqualsUMD.symbols create mode 100644 tests/baselines/reference/importCallExpressionInExportEqualsUMD.types create mode 100644 tests/cases/conformance/dynamicImport/importCallExpressionInExportEqualsAMD.ts create mode 100644 tests/cases/conformance/dynamicImport/importCallExpressionInExportEqualsCJS.ts create mode 100644 tests/cases/conformance/dynamicImport/importCallExpressionInExportEqualsUMD.ts diff --git a/src/compiler/transformers/module/module.ts b/src/compiler/transformers/module/module.ts index a0f593e511138..23bae8714c854 100644 --- a/src/compiler/transformers/module/module.ts +++ b/src/compiler/transformers/module/module.ts @@ -430,26 +430,32 @@ namespace ts { */ function addExportEqualsIfNeeded(statements: Statement[], emitAsReturn: boolean) { if (currentModuleInfo.exportEquals) { - if (emitAsReturn) { - const statement = createReturn(currentModuleInfo.exportEquals.expression); - setTextRange(statement, currentModuleInfo.exportEquals); - setEmitFlags(statement, EmitFlags.NoTokenSourceMaps | EmitFlags.NoComments); - statements.push(statement); - } - else { - const statement = createStatement( - createAssignment( - createPropertyAccess( - createIdentifier("module"), - "exports" - ), - currentModuleInfo.exportEquals.expression - ) - ); + const expressionResult = importCallExpressionVisitor(currentModuleInfo.exportEquals.expression); + if (expressionResult) { + if (expressionResult instanceof Array) { + return Debug.fail("export= expression should never be replaced with multiple expressions!"); + } + if (emitAsReturn) { + const statement = createReturn(expressionResult); + setTextRange(statement, currentModuleInfo.exportEquals); + setEmitFlags(statement, EmitFlags.NoTokenSourceMaps | EmitFlags.NoComments); + statements.push(statement); + } + else { + const statement = createStatement( + createAssignment( + createPropertyAccess( + createIdentifier("module"), + "exports" + ), + expressionResult + ) + ); - setTextRange(statement, currentModuleInfo.exportEquals); - setEmitFlags(statement, EmitFlags.NoComments); - statements.push(statement); + setTextRange(statement, currentModuleInfo.exportEquals); + setEmitFlags(statement, EmitFlags.NoComments); + statements.push(statement); + } } } } @@ -497,7 +503,7 @@ namespace ts { } } - function importCallExpressionVisitor(node: Node): VisitResult { + function importCallExpressionVisitor(node: Expression): VisitResult { // This visitor does not need to descend into the tree if there is no dynamic import, // as export/import statements are only transformed at the top level of a file. if (!(node.transformFlags & TransformFlags.ContainsDynamicImport)) { diff --git a/tests/baselines/reference/importCallExpressionInExportEqualsAMD.js b/tests/baselines/reference/importCallExpressionInExportEqualsAMD.js new file mode 100644 index 0000000000000..f2fda1fadd79f --- /dev/null +++ b/tests/baselines/reference/importCallExpressionInExportEqualsAMD.js @@ -0,0 +1,22 @@ +//// [tests/cases/conformance/dynamicImport/importCallExpressionInExportEqualsAMD.ts] //// + +//// [something.ts] +export = 42; + +//// [index.ts] +export = async function() { + const something = await import("./something"); +}; + +//// [something.js] +define(["require", "exports"], function (require, exports) { + "use strict"; + return 42; +}); +//// [index.js] +define(["require", "exports"], function (require, exports) { + "use strict"; + return async function () { + const something = await new Promise(function (resolve_1, reject_1) { require(["./something"], resolve_1, reject_1); }); + }; +}); diff --git a/tests/baselines/reference/importCallExpressionInExportEqualsAMD.symbols b/tests/baselines/reference/importCallExpressionInExportEqualsAMD.symbols new file mode 100644 index 0000000000000..cd8d7d3804190 --- /dev/null +++ b/tests/baselines/reference/importCallExpressionInExportEqualsAMD.symbols @@ -0,0 +1,10 @@ +=== tests/cases/conformance/dynamicImport/something.ts === +export = 42; +No type information for this code. +No type information for this code.=== tests/cases/conformance/dynamicImport/index.ts === +export = async function() { + const something = await import("./something"); +>something : Symbol(something, Decl(index.ts, 1, 9)) +>"./something" : Symbol("tests/cases/conformance/dynamicImport/something", Decl(something.ts, 0, 0)) + +}; diff --git a/tests/baselines/reference/importCallExpressionInExportEqualsAMD.types b/tests/baselines/reference/importCallExpressionInExportEqualsAMD.types new file mode 100644 index 0000000000000..b590130d1cff5 --- /dev/null +++ b/tests/baselines/reference/importCallExpressionInExportEqualsAMD.types @@ -0,0 +1,14 @@ +=== tests/cases/conformance/dynamicImport/something.ts === +export = 42; +No type information for this code. +No type information for this code.=== tests/cases/conformance/dynamicImport/index.ts === +export = async function() { +>async function() { const something = await import("./something");} : () => Promise + + const something = await import("./something"); +>something : 42 +>await import("./something") : 42 +>import("./something") : Promise<42> +>"./something" : "./something" + +}; diff --git a/tests/baselines/reference/importCallExpressionInExportEqualsCJS.js b/tests/baselines/reference/importCallExpressionInExportEqualsCJS.js new file mode 100644 index 0000000000000..5d7e28161164d --- /dev/null +++ b/tests/baselines/reference/importCallExpressionInExportEqualsCJS.js @@ -0,0 +1,18 @@ +//// [tests/cases/conformance/dynamicImport/importCallExpressionInExportEqualsCJS.ts] //// + +//// [something.ts] +export = 42; + +//// [index.ts] +export = async function() { + const something = await import("./something"); +}; + +//// [something.js] +"use strict"; +module.exports = 42; +//// [index.js] +"use strict"; +module.exports = async function () { + const something = await Promise.resolve().then(function () { return require("./something"); }); +}; diff --git a/tests/baselines/reference/importCallExpressionInExportEqualsCJS.symbols b/tests/baselines/reference/importCallExpressionInExportEqualsCJS.symbols new file mode 100644 index 0000000000000..cd8d7d3804190 --- /dev/null +++ b/tests/baselines/reference/importCallExpressionInExportEqualsCJS.symbols @@ -0,0 +1,10 @@ +=== tests/cases/conformance/dynamicImport/something.ts === +export = 42; +No type information for this code. +No type information for this code.=== tests/cases/conformance/dynamicImport/index.ts === +export = async function() { + const something = await import("./something"); +>something : Symbol(something, Decl(index.ts, 1, 9)) +>"./something" : Symbol("tests/cases/conformance/dynamicImport/something", Decl(something.ts, 0, 0)) + +}; diff --git a/tests/baselines/reference/importCallExpressionInExportEqualsCJS.types b/tests/baselines/reference/importCallExpressionInExportEqualsCJS.types new file mode 100644 index 0000000000000..b590130d1cff5 --- /dev/null +++ b/tests/baselines/reference/importCallExpressionInExportEqualsCJS.types @@ -0,0 +1,14 @@ +=== tests/cases/conformance/dynamicImport/something.ts === +export = 42; +No type information for this code. +No type information for this code.=== tests/cases/conformance/dynamicImport/index.ts === +export = async function() { +>async function() { const something = await import("./something");} : () => Promise + + const something = await import("./something"); +>something : 42 +>await import("./something") : 42 +>import("./something") : Promise<42> +>"./something" : "./something" + +}; diff --git a/tests/baselines/reference/importCallExpressionInExportEqualsUMD.js b/tests/baselines/reference/importCallExpressionInExportEqualsUMD.js new file mode 100644 index 0000000000000..e0c6e2a925fd7 --- /dev/null +++ b/tests/baselines/reference/importCallExpressionInExportEqualsUMD.js @@ -0,0 +1,39 @@ +//// [tests/cases/conformance/dynamicImport/importCallExpressionInExportEqualsUMD.ts] //// + +//// [something.ts] +export = 42; + +//// [index.ts] +export = async function() { + const something = await import("./something"); +}; + +//// [something.js] +(function (factory) { + if (typeof module === "object" && typeof module.exports === "object") { + var v = factory(require, exports); + if (v !== undefined) module.exports = v; + } + else if (typeof define === "function" && define.amd) { + define(["require", "exports"], factory); + } +})(function (require, exports) { + "use strict"; + return 42; +}); +//// [index.js] +(function (factory) { + if (typeof module === "object" && typeof module.exports === "object") { + var v = factory(require, exports); + if (v !== undefined) module.exports = v; + } + else if (typeof define === "function" && define.amd) { + define(["require", "exports"], factory); + } +})(function (require, exports) { + "use strict"; + var __syncRequire = typeof module === "object" && typeof module.exports === "object"; + return async function () { + const something = await (__syncRequire ? Promise.resolve().then(function () { return require("./something"); }) : new Promise(function (resolve_1, reject_1) { require(["./something"], resolve_1, reject_1); })); + }; +}); diff --git a/tests/baselines/reference/importCallExpressionInExportEqualsUMD.symbols b/tests/baselines/reference/importCallExpressionInExportEqualsUMD.symbols new file mode 100644 index 0000000000000..cd8d7d3804190 --- /dev/null +++ b/tests/baselines/reference/importCallExpressionInExportEqualsUMD.symbols @@ -0,0 +1,10 @@ +=== tests/cases/conformance/dynamicImport/something.ts === +export = 42; +No type information for this code. +No type information for this code.=== tests/cases/conformance/dynamicImport/index.ts === +export = async function() { + const something = await import("./something"); +>something : Symbol(something, Decl(index.ts, 1, 9)) +>"./something" : Symbol("tests/cases/conformance/dynamicImport/something", Decl(something.ts, 0, 0)) + +}; diff --git a/tests/baselines/reference/importCallExpressionInExportEqualsUMD.types b/tests/baselines/reference/importCallExpressionInExportEqualsUMD.types new file mode 100644 index 0000000000000..b590130d1cff5 --- /dev/null +++ b/tests/baselines/reference/importCallExpressionInExportEqualsUMD.types @@ -0,0 +1,14 @@ +=== tests/cases/conformance/dynamicImport/something.ts === +export = 42; +No type information for this code. +No type information for this code.=== tests/cases/conformance/dynamicImport/index.ts === +export = async function() { +>async function() { const something = await import("./something");} : () => Promise + + const something = await import("./something"); +>something : 42 +>await import("./something") : 42 +>import("./something") : Promise<42> +>"./something" : "./something" + +}; diff --git a/tests/cases/conformance/dynamicImport/importCallExpressionInExportEqualsAMD.ts b/tests/cases/conformance/dynamicImport/importCallExpressionInExportEqualsAMD.ts new file mode 100644 index 0000000000000..77f348bd3fa11 --- /dev/null +++ b/tests/cases/conformance/dynamicImport/importCallExpressionInExportEqualsAMD.ts @@ -0,0 +1,9 @@ +// @module: amd +// @target: esnext +// @filename: something.ts +export = 42; + +// @filename: index.ts +export = async function() { + const something = await import("./something"); +}; \ No newline at end of file diff --git a/tests/cases/conformance/dynamicImport/importCallExpressionInExportEqualsCJS.ts b/tests/cases/conformance/dynamicImport/importCallExpressionInExportEqualsCJS.ts new file mode 100644 index 0000000000000..efda80d4995db --- /dev/null +++ b/tests/cases/conformance/dynamicImport/importCallExpressionInExportEqualsCJS.ts @@ -0,0 +1,9 @@ +// @module: commonjs +// @target: esnext +// @filename: something.ts +export = 42; + +// @filename: index.ts +export = async function() { + const something = await import("./something"); +}; \ No newline at end of file diff --git a/tests/cases/conformance/dynamicImport/importCallExpressionInExportEqualsUMD.ts b/tests/cases/conformance/dynamicImport/importCallExpressionInExportEqualsUMD.ts new file mode 100644 index 0000000000000..fc0865914fbd0 --- /dev/null +++ b/tests/cases/conformance/dynamicImport/importCallExpressionInExportEqualsUMD.ts @@ -0,0 +1,9 @@ +// @module: umd +// @target: esnext +// @filename: something.ts +export = 42; + +// @filename: index.ts +export = async function() { + const something = await import("./something"); +}; \ No newline at end of file