Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
43 changes: 34 additions & 9 deletions src/compiler/transformers/module/module.ts
Original file line number Diff line number Diff line change
Expand Up @@ -850,32 +850,57 @@ export function transformModule(context: TransformationContext): (x: SourceFile
function createImportCallExpressionCommonJS(arg: Expression | undefined, isInlineable?: boolean): Expression {
// import(x)
// emit as
// var _a;
// (_a = x, Promise.resolve().then(() => require(_a)) /*CommonJs Require*/
// Promise.resolve(`${x}`).then((s) => require(s)) /*CommonJs Require*/
// 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;
// If the arg is not inlineable, we have to evaluate and ToString() it in the current scope
// Otherwise, we inline it in require() so that it's statically analyzable
const needSyncEval = arg && !isSimpleInlineableExpression(arg) && !isInlineable;

const promiseResolveCall = factory.createCallExpression(
factory.createPropertyAccessExpression(factory.createIdentifier("Promise"), "resolve"),
/*typeArguments*/ undefined,
/*argumentsArray*/ [],
/*argumentsArray*/ needSyncEval
? languageVersion >= ScriptTarget.ES2015
? [
factory.createTemplateExpression(factory.createTemplateHead(""), [
factory.createTemplateSpan(arg, factory.createTemplateTail("")),
]),
]
: [
factory.createCallExpression(
factory.createPropertyAccessExpression(factory.createStringLiteral(""), "concat"),
/*typeArguments*/ undefined,
[arg]
),
]
: []
);

let requireCall: Expression = factory.createCallExpression(
factory.createIdentifier("require"),
/*typeArguments*/ undefined,
temp ? [temp] : arg ? [arg] : [],
needSyncEval ? [factory.createIdentifier("s")] : arg ? [arg] : [],
);
if (getESModuleInterop(compilerOptions)) {
requireCall = emitHelpers().createImportStarHelper(requireCall);
}

const parameters = needSyncEval
? [
factory.createParameterDeclaration(
/*modifiers*/ undefined,
/*dotDotDotToken*/ undefined,
/*name*/ "s"),
]
: [];

let func: FunctionExpression | ArrowFunction;
if (languageVersion >= ScriptTarget.ES2015) {
func = factory.createArrowFunction(
/*modifiers*/ undefined,
/*typeParameters*/ undefined,
/*parameters*/ [],
/*parameters*/ parameters,
/*type*/ undefined,
/*equalsGreaterThanToken*/ undefined,
requireCall);
Expand All @@ -886,14 +911,14 @@ export function transformModule(context: TransformationContext): (x: SourceFile
/*asteriskToken*/ undefined,
/*name*/ undefined,
/*typeParameters*/ undefined,
/*parameters*/ [],
/*parameters*/ parameters,
/*type*/ undefined,
factory.createBlock([factory.createReturnStatement(requireCall)]));
}

const downleveledImport = factory.createCallExpression(factory.createPropertyAccessExpression(promiseResolveCall, "then"), /*typeArguments*/ undefined, [func]);

return temp === undefined ? downleveledImport : factory.createCommaListExpression([factory.createAssignment(temp, arg!), downleveledImport]);
return downleveledImport;
}

function getHelperExpressionForExport(node: ExportDeclaration, innerExpr: Expression) {
Expand Down
5 changes: 2 additions & 3 deletions tests/baselines/reference/asyncImportNestedYield.js
Original file line number Diff line number Diff line change
Expand Up @@ -46,13 +46,12 @@ 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, [Promise.resolve("".concat(_a.sent())).then(function (s) { return require(s); })])];
case 3:
_c = (_a.sent())["default"], Promise.resolve().then(function () { return require(_c); });
Promise.resolve("".concat((_a.sent())["default"])).then(function (s) { return require(s); });
return [2 /*return*/];
}
});
Expand Down
8 changes: 3 additions & 5 deletions tests/baselines/reference/dynamicImportEvaluateSpecifier.js
Original file line number Diff line number Diff line change
Expand Up @@ -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));
Promise.resolve(`${String(i++)}`).then(s => require(s));
Promise.resolve(`${String(i++)}`).then(s => require(s));
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 Promise.resolve(`${await getPath()}`).then(s => require(s));
};
3 changes: 1 addition & 2 deletions tests/baselines/reference/dynamicImportTrailingComma.js
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,5 @@ const path = './foo';
import(path,);

//// [dynamicImportTrailingComma.js]
var _a;
var path = './foo';
_a = path, Promise.resolve().then(function () { return require(_a); });
Promise.resolve("".concat(path)).then(function (s) { return require(s); });
Original file line number Diff line number Diff line change
Expand Up @@ -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)));
Promise.resolve(`${getSpecifier()}`).then(s => require(s));
var p0 = Promise.resolve(`${`${directory}\\${moduleFile}`}`).then(s => require(s));
var p1 = Promise.resolve(`${getSpecifier()}`).then(s => require(s));
const p2 = Promise.resolve(`${whatToLoad ? getSpecifier() : "defaulPath"}`).then(s => require(s));
function returnDynamicLoad(path) {
var _a;
return _a = path, Promise.resolve().then(() => require(_a));
return Promise.resolve(`${path}`).then(s => require(s));
}


Expand Down
5 changes: 2 additions & 3 deletions tests/baselines/reference/importCallExpressionGrammarError.js
Original file line number Diff line number Diff line change
Expand Up @@ -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)));
Promise.resolve(`${...["PathModule"]}`).then(s => require(s));
var p1 = Promise.resolve(`${...a}`).then(s => require(s));
const p2 = Promise.resolve().then(() => require());
const p4 = Promise.resolve().then(() => require("pathToModule"));
3 changes: 1 addition & 2 deletions tests/baselines/reference/importCallExpressionNestedCJS.js
Original file line number Diff line number Diff line change
Expand Up @@ -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 Promise.resolve(`${(yield Promise.resolve().then(() => require("./foo"))).default}`).then(s => require(s));
});
}
3 changes: 1 addition & 2 deletions tests/baselines/reference/importCallExpressionNestedCJS2.js
Original file line number Diff line number Diff line change
Expand Up @@ -52,10 +52,9 @@ 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*/, Promise.resolve("".concat((_a.sent()).default)).then(function (s) { return require(s); })];
case 2: return [2 /*return*/, _a.sent()];
}
});
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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)));
Promise.resolve(`${`${directory}\\${moduleFile}`}`).then(s => require(s));
Promise.resolve(`${getSpecifier()}`).then(s => require(s));
var p1 = Promise.resolve(`${ValidSomeCondition() ? "./0" : "externalModule"}`).then(s => require(s));
var p1 = Promise.resolve(`${getSpecifier()}`).then(s => require(s));
var p11 = Promise.resolve(`${getSpecifier()}`).then(s => require(s));
const p2 = Promise.resolve(`${whatToLoad ? getSpecifier() : "defaulPath"}`).then(s => require(s));
p1.then(zero => {
return zero.foo(); // ok, zero is any
});
let j;
var p3 = (_g = j = getSpecifier(), Promise.resolve().then(() => require(_g)));
var p3 = Promise.resolve(`${j = getSpecifier()}`).then(s => require(s));
function* loadModule(directories) {
var _a;
for (const directory of directories) {
const path = `${directory}\\moduleFile`;
_a = yield path, Promise.resolve().then(() => require(_a));
Promise.resolve(`${yield path}`).then(s => require(s));
}
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The previous behavior here looked exactly like the bug because they would all import the same thing...

}
Original file line number Diff line number Diff line change
Expand Up @@ -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)));
Promise.resolve(`${getSpecifier()}`).then(s => require(s));
var p1 = Promise.resolve(`${getSpecifier()}`).then(s => require(s));
const p2 = Promise.resolve(`${whatToLoad ? getSpecifier() : "defaulPath"}`).then(s => require(s));
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 = Promise.resolve(`${["path1", "path2"]}`).then(s => require(s));
var p4 = Promise.resolve(`${() => "PathToModule"}`).then(s => require(s));
3 changes: 1 addition & 2 deletions tests/baselines/reference/jsdocInTypeScript.js
Original file line number Diff line number Diff line change
Expand Up @@ -58,7 +58,6 @@ var v = import(String());


//// [jsdocInTypeScript.js]
var _a;
var T = /** @class */ (function () {
function T() {
}
Expand Down Expand Up @@ -93,4 +92,4 @@ 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 = Promise.resolve("".concat(String())).then(function (s) { return require(s); });