From ffbb445148caafbeb9fdfaee7c6a6bce96067c67 Mon Sep 17 00:00:00 2001 From: Yui T Date: Tue, 14 Mar 2017 10:31:30 -0700 Subject: [PATCH] wip-Emit import call expression for commonjs --- src/compiler/factory.ts | 1 + src/compiler/parser.ts | 4 +- src/compiler/transformers/module/module.ts | 39 +++++++++++++++---- src/compiler/types.ts | 1 + .../importCallExpressionInCJS1.ts | 11 ++++++ .../importCallExpressionInCJS2.ts | 19 +++++++++ 6 files changed, 66 insertions(+), 9 deletions(-) create mode 100644 tests/cases/conformance/es2018/dynamicImport/importCallExpressionInCJS1.ts create mode 100644 tests/cases/conformance/es2018/dynamicImport/importCallExpressionInCJS2.ts diff --git a/src/compiler/factory.ts b/src/compiler/factory.ts index 0bf545f4fe1..0bd7989327b 100644 --- a/src/compiler/factory.ts +++ b/src/compiler/factory.ts @@ -1644,6 +1644,7 @@ namespace ts { if (node.resolvedTypeReferenceDirectiveNames !== undefined) updated.resolvedTypeReferenceDirectiveNames = node.resolvedTypeReferenceDirectiveNames; if (node.imports !== undefined) updated.imports = node.imports; if (node.moduleAugmentations !== undefined) updated.moduleAugmentations = node.moduleAugmentations; + if (node.containsDynamicImport !== undefined) updated.containsDynamicImport = node.containsDynamicImport; return updateNode(updated, node); } diff --git a/src/compiler/parser.ts b/src/compiler/parser.ts index fbcbfae0bdf..f9abe8be995 100644 --- a/src/compiler/parser.ts +++ b/src/compiler/parser.ts @@ -461,7 +461,7 @@ namespace ts { } export function isExternalModule(file: SourceFile): boolean { - return file.externalModuleIndicator !== undefined; + return file.externalModuleIndicator !== undefined || file.containsDynamicImport; } // Produces a new SourceFile for the 'newText' provided. The 'textChangeRange' parameter @@ -2778,6 +2778,7 @@ namespace ts { case SyntaxKind.SlashToken: case SyntaxKind.SlashEqualsToken: case SyntaxKind.Identifier: + case SyntaxKind.ImportKeyword: return true; default: return isIdentifier(); @@ -3698,6 +3699,7 @@ namespace ts { if (importCall.specifier.kind === SyntaxKind.StringLiteral) { (sourceFile.imports || (sourceFile.imports = [])).push(importCall.specifier as StringLiteral); } + sourceFile.containsDynamicImport = true; return importCall; } const expression = token() === SyntaxKind.SuperKeyword ? parseSuperExpression() : parseMemberExpressionOrHigher(); diff --git a/src/compiler/transformers/module/module.ts b/src/compiler/transformers/module/module.ts index 80a8c985c56..2aad24af76e 100644 --- a/src/compiler/transformers/module/module.ts +++ b/src/compiler/transformers/module/module.ts @@ -482,12 +482,35 @@ namespace ts { return visitEndOfDeclarationMarker(node); default: - // This visitor does not descend into the tree, as export/import statements - // are only transformed at the top level of a file. - return node; + return visitEachChild(node, visitor, context); } } + function visitor(node: Node): 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 (!currentSourceFile.containsDynamicImport) { + return node; + } + + switch (node.kind) { + case SyntaxKind.ImportCallExpression: + return visitImportCallExpression(node); + default: + return visitEachChild(node, visitor, context); + } + } + + function visitImportCallExpression(node: ImportCallExpression): Expression{ + return createCall( + createPropertyAccess( + createCall(/*expression*/ createPropertyAccess(createIdentifier("Promise"), "resolve"), /*typeArguments*/ undefined, /*argumentsArray*/ []), + "then"), + /*typeArguments*/ undefined, + [ createArrowFunction(/*modifiers*/ undefined, /*typeParameters*/ undefined, /*parameters*/ undefined, /*type*/ undefined, createToken(SyntaxKind.EqualsGreaterThanToken), createCall(createIdentifier("require"), /*typeArguments*/ undefined, [node.specifier]))] + ); + } + /** * Visits an ImportDeclaration node. * @@ -780,7 +803,7 @@ namespace ts { node.asteriskToken, getDeclarationName(node, /*allowComments*/ true, /*allowSourceMaps*/ true), /*typeParameters*/ undefined, - node.parameters, + visitNodes(node.parameters, visitor), /*type*/ undefined, node.body ), @@ -822,7 +845,7 @@ namespace ts { visitNodes(node.modifiers, modifierVisitor, isModifier), getDeclarationName(node, /*allowComments*/ true, /*allowSourceMaps*/ true), /*typeParameters*/ undefined, - node.heritageClauses, + visitNodes(node.heritageClauses, visitor), node.members ), node @@ -884,7 +907,7 @@ namespace ts { } } else { - statements = append(statements, node); + statements = append(statements, visitEachChild(node, visitor, context)); } if (hasAssociatedEndOfDeclarationMarker(node)) { @@ -907,7 +930,7 @@ namespace ts { function transformInitializedVariable(node: VariableDeclaration): Expression { if (isBindingPattern(node.name)) { return flattenDestructuringAssignment( - node, + visitNode(node, visitor), /*visitor*/ undefined, context, FlattenLevel.All, @@ -924,7 +947,7 @@ namespace ts { ), /*location*/ node.name ), - node.initializer + visitNode(node.initializer, visitor) ); } } diff --git a/src/compiler/types.ts b/src/compiler/types.ts index c8b16130f29..07a6610f8fd 100644 --- a/src/compiler/types.ts +++ b/src/compiler/types.ts @@ -2282,6 +2282,7 @@ namespace ts { /* @internal */ moduleAugmentations: LiteralExpression[]; /* @internal */ patternAmbientModules?: PatternAmbientModule[]; /* @internal */ ambientModuleNames: string[]; + /* @internal */ containsDynamicImport?: boolean; } export interface Bundle extends Node { diff --git a/tests/cases/conformance/es2018/dynamicImport/importCallExpressionInCJS1.ts b/tests/cases/conformance/es2018/dynamicImport/importCallExpressionInCJS1.ts new file mode 100644 index 00000000000..9287e8462e9 --- /dev/null +++ b/tests/cases/conformance/es2018/dynamicImport/importCallExpressionInCJS1.ts @@ -0,0 +1,11 @@ +// @module: commonjs +// @target: esnext +// @filename: 0.ts +export function foo() { return "foo"; } + +// @filename: 1.ts +import("./0"); +var p1 = import("./0"); +p1.then(zero => { + return zero.foo(); +}); \ No newline at end of file diff --git a/tests/cases/conformance/es2018/dynamicImport/importCallExpressionInCJS2.ts b/tests/cases/conformance/es2018/dynamicImport/importCallExpressionInCJS2.ts new file mode 100644 index 00000000000..e42a58a290c --- /dev/null +++ b/tests/cases/conformance/es2018/dynamicImport/importCallExpressionInCJS2.ts @@ -0,0 +1,19 @@ +// @module: commonjs +// @target: esnext +// @filename: 0.ts +export function foo() { return "foo"; } + +// @filename: 1.ts +export function backup() { return "backup"; } + +// @filename: 2.ts +async function compute(promise: Promise) { + let j = await promise; + if (!j) { + j = await import("./1"); + return j.backup(); + } + return j.foo(); +} + +compute(import("./0")); \ No newline at end of file