From 6cd3acc70de471e5a3beacd555ea2130f38faab5 Mon Sep 17 00:00:00 2001 From: Ron Buckton Date: Thu, 17 Nov 2022 18:34:21 -0500 Subject: [PATCH] Use IIFE to capture variable for transformed dynamic import --- src/compiler/factory/nodeFactory.ts | 8 ++++---- src/compiler/transformers/module/module.ts | 10 ++++++++-- src/compiler/types.ts | 4 ++-- .../reference/api/tsserverlibrary.d.ts | 4 ++-- tests/baselines/reference/api/typescript.d.ts | 4 ++-- .../reference/asyncImportNestedYield.js | 9 ++++++--- .../dynamicImportEvaluateSpecifier.js | 8 +++----- .../reference/dynamicImportTrailingComma.js | 5 +++-- .../importCallExpressionDeclarationEmit1.js | 12 +++++------- .../importCallExpressionGrammarError.js | 5 ++--- .../reference/importCallExpressionNestedCJS.js | 3 +-- .../importCallExpressionNestedCJS2.js | 5 +++-- .../importCallExpressionReturnPromiseOfAny.js | 18 ++++++++---------- ...allExpressionSpecifierNotStringTypeError.js | 11 +++++------ tests/baselines/reference/jsdocInTypeScript.js | 5 +++-- 15 files changed, 57 insertions(+), 54 deletions(-) diff --git a/src/compiler/factory/nodeFactory.ts b/src/compiler/factory/nodeFactory.ts index afa240bd0b392..0dff4d923f3df 100644 --- a/src/compiler/factory/nodeFactory.ts +++ b/src/compiler/factory/nodeFactory.ts @@ -5763,9 +5763,9 @@ export function createNodeFactory(flags: NodeFactoryFlags, baseFactory: BaseNode ); } - function createImmediatelyInvokedArrowFunction(statements: readonly Statement[]): CallExpression; - function createImmediatelyInvokedArrowFunction(statements: readonly Statement[], param: ParameterDeclaration, paramValue: Expression): CallExpression; - function createImmediatelyInvokedArrowFunction(statements: readonly Statement[], param?: ParameterDeclaration, paramValue?: Expression) { + function createImmediatelyInvokedArrowFunction(statements: readonly Statement[] | ConciseBody): CallExpression; + function createImmediatelyInvokedArrowFunction(statements: readonly Statement[] | ConciseBody, param: ParameterDeclaration, paramValue: Expression): CallExpression; + function createImmediatelyInvokedArrowFunction(statements: readonly Statement[] | ConciseBody, param?: ParameterDeclaration, paramValue?: Expression) { return createCallExpression( createArrowFunction( /*modifiers*/ undefined, @@ -5773,7 +5773,7 @@ export function createNodeFactory(flags: NodeFactoryFlags, baseFactory: BaseNode /*parameters*/ param ? [param] : [], /*type*/ undefined, /*equalsGreaterThanToken*/ undefined, - createBlock(statements, /*multiLine*/ true) + isArray(statements) ? createBlock(statements, /*multiLine*/ true) : statements ), /*typeArguments*/ undefined, /*argumentsArray*/ paramValue ? [paramValue] : [] diff --git a/src/compiler/transformers/module/module.ts b/src/compiler/transformers/module/module.ts index e5ade93e74fe9..78563863f0c92 100644 --- a/src/compiler/transformers/module/module.ts +++ b/src/compiler/transformers/module/module.ts @@ -855,7 +855,7 @@ export function transformModule(context: TransformationContext): (x: SourceFile // We have to wrap require in then callback so that require is done in asynchronously // if we simply do require in resolve callback in Promise constructor. We will execute the loading immediately // If the arg is not inlineable, we have to evaluate it in the current scope with a temp var - const temp = arg && !isSimpleInlineableExpression(arg) && !isInlineable ? factory.createTempVariable(hoistVariableDeclaration) : undefined; + const temp = arg && !isSimpleInlineableExpression(arg) && !isInlineable ? factory.createTempVariable(/*hoistVariableDeclaration*/ undefined) : undefined; const promiseResolveCall = factory.createCallExpression( factory.createPropertyAccessExpression(factory.createIdentifier("Promise"), "resolve"), /*typeArguments*/ undefined, @@ -892,8 +892,14 @@ export function transformModule(context: TransformationContext): (x: SourceFile } const downleveledImport = factory.createCallExpression(factory.createPropertyAccessExpression(promiseResolveCall, "then"), /*typeArguments*/ undefined, [func]); + if (temp && arg) { + const iife = languageVersion >= ScriptTarget.ES2015 ? + factory.createImmediatelyInvokedArrowFunction(downleveledImport, factory.createParameterDeclaration(/*modifiers*/ undefined, /*dotDotDotToken*/ undefined, temp), arg) : + factory.createImmediatelyInvokedFunctionExpression([factory.createReturnStatement(downleveledImport)], factory.createParameterDeclaration(/*modifiers*/ undefined, /*dotDotDotToken*/ undefined, temp), arg); + return iife; + } - return temp === undefined ? downleveledImport : factory.createCommaListExpression([factory.createAssignment(temp, arg!), downleveledImport]); + return downleveledImport; } function getHelperExpressionForExport(node: ExportDeclaration, innerExpr: Expression) { diff --git a/src/compiler/types.ts b/src/compiler/types.ts index ac70209e8a675..d2ed6fb31a1a1 100644 --- a/src/compiler/types.ts +++ b/src/compiler/types.ts @@ -8366,8 +8366,8 @@ export interface NodeFactory { createImmediatelyInvokedFunctionExpression(statements: readonly Statement[]): CallExpression; createImmediatelyInvokedFunctionExpression(statements: readonly Statement[], param: ParameterDeclaration, paramValue: Expression): CallExpression; - createImmediatelyInvokedArrowFunction(statements: readonly Statement[]): CallExpression; - createImmediatelyInvokedArrowFunction(statements: readonly Statement[], param: ParameterDeclaration, paramValue: Expression): CallExpression; + createImmediatelyInvokedArrowFunction(statements: readonly Statement[] | ConciseBody): CallExpression; + createImmediatelyInvokedArrowFunction(statements: readonly Statement[] | ConciseBody, param: ParameterDeclaration, paramValue: Expression): CallExpression; createVoidZero(): VoidExpression; diff --git a/tests/baselines/reference/api/tsserverlibrary.d.ts b/tests/baselines/reference/api/tsserverlibrary.d.ts index d91810e42cc4e..0969899938788 100644 --- a/tests/baselines/reference/api/tsserverlibrary.d.ts +++ b/tests/baselines/reference/api/tsserverlibrary.d.ts @@ -7888,8 +7888,8 @@ declare namespace ts { createPostfixDecrement(operand: Expression): PostfixUnaryExpression; createImmediatelyInvokedFunctionExpression(statements: readonly Statement[]): CallExpression; createImmediatelyInvokedFunctionExpression(statements: readonly Statement[], param: ParameterDeclaration, paramValue: Expression): CallExpression; - createImmediatelyInvokedArrowFunction(statements: readonly Statement[]): CallExpression; - createImmediatelyInvokedArrowFunction(statements: readonly Statement[], param: ParameterDeclaration, paramValue: Expression): CallExpression; + createImmediatelyInvokedArrowFunction(statements: readonly Statement[] | ConciseBody): CallExpression; + createImmediatelyInvokedArrowFunction(statements: readonly Statement[] | ConciseBody, param: ParameterDeclaration, paramValue: Expression): CallExpression; createVoidZero(): VoidExpression; createExportDefault(expression: Expression): ExportAssignment; createExternalModuleExport(exportName: Identifier): ExportDeclaration; diff --git a/tests/baselines/reference/api/typescript.d.ts b/tests/baselines/reference/api/typescript.d.ts index f7817050f13ed..be0de4e9a6f6a 100644 --- a/tests/baselines/reference/api/typescript.d.ts +++ b/tests/baselines/reference/api/typescript.d.ts @@ -3952,8 +3952,8 @@ declare namespace ts { createPostfixDecrement(operand: Expression): PostfixUnaryExpression; createImmediatelyInvokedFunctionExpression(statements: readonly Statement[]): CallExpression; createImmediatelyInvokedFunctionExpression(statements: readonly Statement[], param: ParameterDeclaration, paramValue: Expression): CallExpression; - createImmediatelyInvokedArrowFunction(statements: readonly Statement[]): CallExpression; - createImmediatelyInvokedArrowFunction(statements: readonly Statement[], param: ParameterDeclaration, paramValue: Expression): CallExpression; + createImmediatelyInvokedArrowFunction(statements: readonly Statement[] | ConciseBody): CallExpression; + createImmediatelyInvokedArrowFunction(statements: readonly Statement[] | ConciseBody, param: ParameterDeclaration, paramValue: Expression): CallExpression; createVoidZero(): VoidExpression; createExportDefault(expression: Expression): ExportAssignment; createExternalModuleExport(exportName: Identifier): ExportDeclaration; diff --git a/tests/baselines/reference/asyncImportNestedYield.js b/tests/baselines/reference/asyncImportNestedYield.js index 190d930a1adcc..1955a2bc9af2c 100644 --- a/tests/baselines/reference/asyncImportNestedYield.js +++ b/tests/baselines/reference/asyncImportNestedYield.js @@ -46,13 +46,16 @@ var __asyncGenerator = (this && this.__asyncGenerator) || function (thisArg, _ar function foo() { return __asyncGenerator(this, arguments, function foo_1() { return __generator(this, function (_a) { - var _b, _c; switch (_a.label) { case 0: return [4 /*yield*/, __await("foo")]; case 1: return [4 /*yield*/, _a.sent()]; - case 2: return [4 /*yield*/, __await.apply(void 0, [(_b = _a.sent(), Promise.resolve().then(function () { return require(_b); }))])]; + case 2: return [4 /*yield*/, __await.apply(void 0, [function (_a) { + return Promise.resolve().then(function () { return require(_a); }); + }(_a.sent())])]; case 3: - _c = (_a.sent())["default"], Promise.resolve().then(function () { return require(_c); }); + (function (_a) { + return Promise.resolve().then(function () { return require(_a); }); + })((_a.sent())["default"]); return [2 /*return*/]; } }); diff --git a/tests/baselines/reference/dynamicImportEvaluateSpecifier.js b/tests/baselines/reference/dynamicImportEvaluateSpecifier.js index 60c4a9f3d1f44..cc9e378058069 100644 --- a/tests/baselines/reference/dynamicImportEvaluateSpecifier.js +++ b/tests/baselines/reference/dynamicImportEvaluateSpecifier.js @@ -16,16 +16,14 @@ const someFunction = async () => { //// [dynamicImportEvaluateSpecifier.js] -var _a, _b; // https://github.com/microsoft/TypeScript/issues/48285 let i = 0; -_a = String(i++), Promise.resolve().then(() => require(_a)); -_b = String(i++), Promise.resolve().then(() => require(_b)); +(_a => Promise.resolve().then(() => require(_a)))(String(i++)); +(_b => Promise.resolve().then(() => require(_b)))(String(i++)); const getPath = async () => { /* in reality this would do some async FS operation, or a web request */ return "/root/my/cool/path"; }; const someFunction = async () => { - var _a; - const result = await (_a = await getPath(), Promise.resolve().then(() => require(_a))); + const result = await (_a => Promise.resolve().then(() => require(_a)))(await getPath()); }; diff --git a/tests/baselines/reference/dynamicImportTrailingComma.js b/tests/baselines/reference/dynamicImportTrailingComma.js index d28e9be57761d..38214e76f86e2 100644 --- a/tests/baselines/reference/dynamicImportTrailingComma.js +++ b/tests/baselines/reference/dynamicImportTrailingComma.js @@ -3,6 +3,7 @@ const path = './foo'; import(path,); //// [dynamicImportTrailingComma.js] -var _a; var path = './foo'; -_a = path, Promise.resolve().then(function () { return require(_a); }); +(function (_a) { + return Promise.resolve().then(function () { return require(_a); }); +})(path); diff --git a/tests/baselines/reference/importCallExpressionDeclarationEmit1.js b/tests/baselines/reference/importCallExpressionDeclarationEmit1.js index 89e42ee7f63de..3867c85c74cb4 100644 --- a/tests/baselines/reference/importCallExpressionDeclarationEmit1.js +++ b/tests/baselines/reference/importCallExpressionDeclarationEmit1.js @@ -15,14 +15,12 @@ function returnDynamicLoad(path: string) { } //// [importCallExpressionDeclarationEmit1.js] -var _a, _b, _c, _d; -_a = getSpecifier(), Promise.resolve().then(() => require(_a)); -var p0 = (_b = `${directory}\\${moduleFile}`, Promise.resolve().then(() => require(_b))); -var p1 = (_c = getSpecifier(), Promise.resolve().then(() => require(_c))); -const p2 = (_d = whatToLoad ? getSpecifier() : "defaulPath", Promise.resolve().then(() => require(_d))); +(_a => Promise.resolve().then(() => require(_a)))(getSpecifier()); +var p0 = (_b => Promise.resolve().then(() => require(_b)))(`${directory}\\${moduleFile}`); +var p1 = (_c => Promise.resolve().then(() => require(_c)))(getSpecifier()); +const p2 = (_d => Promise.resolve().then(() => require(_d)))(whatToLoad ? getSpecifier() : "defaulPath"); function returnDynamicLoad(path) { - var _a; - return _a = path, Promise.resolve().then(() => require(_a)); + return (_a => Promise.resolve().then(() => require(_a)))(path); } diff --git a/tests/baselines/reference/importCallExpressionGrammarError.js b/tests/baselines/reference/importCallExpressionGrammarError.js index 0a502e5e2891a..1b1d8b7d5705e 100644 --- a/tests/baselines/reference/importCallExpressionGrammarError.js +++ b/tests/baselines/reference/importCallExpressionGrammarError.js @@ -10,9 +10,8 @@ const p2 = import(); const p4 = import("pathToModule", "secondModule"); //// [importCallExpressionGrammarError.js] -var _a, _b; var a = ["./0"]; -_a = (...["PathModule"]), Promise.resolve().then(() => require(_a)); -var p1 = (_b = (...a), Promise.resolve().then(() => require(_b))); +(_a => Promise.resolve().then(() => require(_a)))(...["PathModule"]); +var p1 = (_b => Promise.resolve().then(() => require(_b)))(...a); const p2 = Promise.resolve().then(() => require()); const p4 = Promise.resolve().then(() => require("pathToModule")); diff --git a/tests/baselines/reference/importCallExpressionNestedCJS.js b/tests/baselines/reference/importCallExpressionNestedCJS.js index f099c9bc5fc53..d695689a1dd20 100644 --- a/tests/baselines/reference/importCallExpressionNestedCJS.js +++ b/tests/baselines/reference/importCallExpressionNestedCJS.js @@ -24,7 +24,6 @@ var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, ge }; function foo() { return __awaiter(this, void 0, void 0, function* () { - var _a; - return yield (_a = (yield Promise.resolve().then(() => require("./foo"))).default, Promise.resolve().then(() => require(_a))); + return yield (_a => Promise.resolve().then(() => require(_a)))((yield Promise.resolve().then(() => require("./foo"))).default); }); } diff --git a/tests/baselines/reference/importCallExpressionNestedCJS2.js b/tests/baselines/reference/importCallExpressionNestedCJS2.js index a29cbe396f1c8..021c804bc1988 100644 --- a/tests/baselines/reference/importCallExpressionNestedCJS2.js +++ b/tests/baselines/reference/importCallExpressionNestedCJS2.js @@ -52,10 +52,11 @@ var __generator = (this && this.__generator) || function (thisArg, body) { function foo() { return __awaiter(this, void 0, void 0, function () { return __generator(this, function (_a) { - var _b; switch (_a.label) { case 0: return [4 /*yield*/, Promise.resolve().then(function () { return require("./foo"); })]; - case 1: return [4 /*yield*/, (_b = (_a.sent()).default, Promise.resolve().then(function () { return require(_b); }))]; + case 1: return [4 /*yield*/, function (_a) { + return Promise.resolve().then(function () { return require(_a); }); + }((_a.sent()).default)]; case 2: return [2 /*return*/, _a.sent()]; } }); diff --git a/tests/baselines/reference/importCallExpressionReturnPromiseOfAny.js b/tests/baselines/reference/importCallExpressionReturnPromiseOfAny.js index b3d787c94a54e..2b888b165b41d 100644 --- a/tests/baselines/reference/importCallExpressionReturnPromiseOfAny.js +++ b/tests/baselines/reference/importCallExpressionReturnPromiseOfAny.js @@ -42,23 +42,21 @@ class C { exports.C = C; //// [1.js] "use strict"; -var _a, _b, _c, _d, _e, _f, _g; Object.defineProperty(exports, "__esModule", { value: true }); -_a = `${directory}\\${moduleFile}`, Promise.resolve().then(() => require(_a)); -_b = getSpecifier(), Promise.resolve().then(() => require(_b)); -var p1 = (_c = ValidSomeCondition() ? "./0" : "externalModule", Promise.resolve().then(() => require(_c))); -var p1 = (_d = getSpecifier(), Promise.resolve().then(() => require(_d))); -var p11 = (_e = getSpecifier(), Promise.resolve().then(() => require(_e))); -const p2 = (_f = whatToLoad ? getSpecifier() : "defaulPath", Promise.resolve().then(() => require(_f))); +(_a => Promise.resolve().then(() => require(_a)))(`${directory}\\${moduleFile}`); +(_b => Promise.resolve().then(() => require(_b)))(getSpecifier()); +var p1 = (_c => Promise.resolve().then(() => require(_c)))(ValidSomeCondition() ? "./0" : "externalModule"); +var p1 = (_d => Promise.resolve().then(() => require(_d)))(getSpecifier()); +var p11 = (_e => Promise.resolve().then(() => require(_e)))(getSpecifier()); +const p2 = (_f => Promise.resolve().then(() => require(_f)))(whatToLoad ? getSpecifier() : "defaulPath"); p1.then(zero => { return zero.foo(); // ok, zero is any }); let j; -var p3 = (_g = j = getSpecifier(), Promise.resolve().then(() => require(_g))); +var p3 = (_g => Promise.resolve().then(() => require(_g)))(j = getSpecifier()); function* loadModule(directories) { - var _a; for (const directory of directories) { const path = `${directory}\\moduleFile`; - _a = yield path, Promise.resolve().then(() => require(_a)); + (_a => Promise.resolve().then(() => require(_a)))(yield path); } } diff --git a/tests/baselines/reference/importCallExpressionSpecifierNotStringTypeError.js b/tests/baselines/reference/importCallExpressionSpecifierNotStringTypeError.js index ab2785a63d208..81e42562fe8af 100644 --- a/tests/baselines/reference/importCallExpressionSpecifierNotStringTypeError.js +++ b/tests/baselines/reference/importCallExpressionSpecifierNotStringTypeError.js @@ -14,13 +14,12 @@ var p3 = import(["path1", "path2"]); var p4 = import(()=>"PathToModule"); //// [importCallExpressionSpecifierNotStringTypeError.js] -var _a, _b, _c, _d, _e; // Error specifier is not assignable to string -_a = getSpecifier(), Promise.resolve().then(() => require(_a)); -var p1 = (_b = getSpecifier(), Promise.resolve().then(() => require(_b))); -const p2 = (_c = whatToLoad ? getSpecifier() : "defaulPath", Promise.resolve().then(() => require(_c))); +(_a => Promise.resolve().then(() => require(_a)))(getSpecifier()); +var p1 = (_b => Promise.resolve().then(() => require(_b)))(getSpecifier()); +const p2 = (_c => Promise.resolve().then(() => require(_c)))(whatToLoad ? getSpecifier() : "defaulPath"); p1.then(zero => { return zero.foo(); // ok, zero is any }); -var p3 = (_d = ["path1", "path2"], Promise.resolve().then(() => require(_d))); -var p4 = (_e = () => "PathToModule", Promise.resolve().then(() => require(_e))); +var p3 = (_d => Promise.resolve().then(() => require(_d)))(["path1", "path2"]); +var p4 = (_e => Promise.resolve().then(() => require(_e)))(() => "PathToModule"); diff --git a/tests/baselines/reference/jsdocInTypeScript.js b/tests/baselines/reference/jsdocInTypeScript.js index 39b8f917e0585..a1bb0169668eb 100644 --- a/tests/baselines/reference/jsdocInTypeScript.js +++ b/tests/baselines/reference/jsdocInTypeScript.js @@ -58,7 +58,6 @@ var v = import(String()); //// [jsdocInTypeScript.js] -var _a; var T = /** @class */ (function () { function T() { } @@ -93,4 +92,6 @@ var E = {}; E[""]; // make sure import types in JSDoc are not resolved /** @type {import("should-not-be-resolved").Type} */ -var v = (_a = String(), Promise.resolve().then(function () { return require(_a); })); +var v = function (_a) { + return Promise.resolve().then(function () { return require(_a); }); +}(String());