diff --git a/src/compiler/parser.ts b/src/compiler/parser.ts index 5a3560d45e6..c1a8f293418 100644 --- a/src/compiler/parser.ts +++ b/src/compiler/parser.ts @@ -167,6 +167,8 @@ namespace ts { return visitNode(cbNode, (node).expression) || visitNodes(cbNodes, (node).typeArguments) || visitNodes(cbNodes, (node).arguments); + case SyntaxKind.ImportCallExpression: + return visitNode(cbNode, (node).expression); case SyntaxKind.TaggedTemplateExpression: return visitNode(cbNode, (node).tag) || visitNode(cbNode, (node).template); @@ -3686,20 +3688,19 @@ namespace ts { // the last two CallExpression productions. 2) We see 'import' which must start import call. // 3)we have a MemberExpression which either completes the LeftHandSideExpression, // or starts the beginning of the first four CallExpression productions. - let expression: LeftHandSideExpression; - if (token() === SyntaxKind.SuperKeyword) { - expression = parseSuperExpression(); - } - else if (token() === SyntaxKind.ImportKeyword && lookAhead(nextTokenIsOpenParen)) { - // We don't want to eagerly consume all import keyword as import call expression. + + if (token() === SyntaxKind.ImportKeyword && lookAhead(nextTokenIsOpenParen)) { + // We don't want to eagerly consume all import keyword as import call expression so we look a head to find "(" // For example: - // var foo3 = require("subfolder//*require0*/ - // import * as foo1 from "module-from-node//*import_as1*/ -> we want this import to be a statement rather than import call expression - expression = parseImportExpression(); - } - else { - expression = parseMemberExpressionOrHigher(); + // var foo3 = require("subfolder + // import * as foo1 from "module-from-node -> we want this import to be a statement rather than import call expression + const importCall = parseImportCall(); + if (importCall.expression.kind === SyntaxKind.StringLiteral) { + (sourceFile.imports || (sourceFile.imports = [])).push(importCall.expression as StringLiteral); + } + return importCall; } + const expression = token() === SyntaxKind.SuperKeyword ? parseSuperExpression() : parseMemberExpressionOrHigher(); // Now, we *may* be complete. However, we might have consumed the start of a // CallExpression. As such, we need to consume the rest of it here to be complete. @@ -3773,12 +3774,13 @@ namespace ts { return finishNode(node); } - function parseImportExpression(): LeftHandSideExpression { - const expression = parseTokenNode(); - if (token() === SyntaxKind.OpenParenToken) { - return expression; - } - Debug.assert(token() === SyntaxKind.OpenParenToken, "Parsing import expression expects open parenthesis after import keyword"); + function parseImportCall(): ImportCall { + const importCallExpr = createNode(SyntaxKind.ImportCallExpression); + parseExpected(SyntaxKind.ImportKeyword); + parseExpected(SyntaxKind.OpenParenToken); + importCallExpr.expression = parseAssignmentExpressionOrHigher(); + parseExpected(SyntaxKind.CloseParenToken); + return finishNode(importCallExpr); } function tagNamesAreEquivalent(lhs: JsxTagNameExpression, rhs: JsxTagNameExpression): boolean { diff --git a/src/compiler/program.ts b/src/compiler/program.ts index abb8b0b2f09..ec263831cd4 100644 --- a/src/compiler/program.ts +++ b/src/compiler/program.ts @@ -1178,15 +1178,12 @@ namespace ts { } function collectExternalModuleReferences(file: SourceFile): void { - if (file.imports) { - return; - } - const isJavaScriptFile = isSourceFileJavaScript(file); const isExternalModuleFile = isExternalModule(file); const isDtsFile = isDeclarationFile(file); - let imports: LiteralExpression[]; + // file.imports may not be undefined if there exists dynamic import + let imports = file.imports; let moduleAugmentations: LiteralExpression[]; let ambientModules: string[]; diff --git a/src/compiler/types.ts b/src/compiler/types.ts index 28ec1cba955..d3ecdef2799 100644 --- a/src/compiler/types.ts +++ b/src/compiler/types.ts @@ -391,8 +391,12 @@ namespace ts { MergeDeclarationMarker, EndOfDeclarationMarker, + // Dynamic import + ImportCallExpression, + // Enum value count Count, + // Markers FirstAssignment = EqualsToken, LastAssignment = CaretEqualsToken, @@ -1443,8 +1447,9 @@ namespace ts { expression: SuperExpression; } - export interface ImportCall extends CallExpression { - expression: ImportExpression; + export interface ImportCall extends LeftHandSideExpression, Declaration { + kind: SyntaxKind.ImportCallExpression; + expression: Expression; } export interface ExpressionWithTypeArguments extends TypeNode { diff --git a/src/compiler/utilities.ts b/src/compiler/utilities.ts index a5229b614be..98a95e9e861 100644 --- a/src/compiler/utilities.ts +++ b/src/compiler/utilities.ts @@ -662,6 +662,10 @@ namespace ts { return n.kind === SyntaxKind.CallExpression && (n).expression.kind === SyntaxKind.SuperKeyword; } + export function isImportCall(n: Node): n is ImportCall { + return n.kind === SyntaxKind.ImportCallExpression; + } + export function isPrologueDirective(node: Node): node is PrologueDirective { return node.kind === SyntaxKind.ExpressionStatement && (node).expression.kind === SyntaxKind.StringLiteral; @@ -3886,7 +3890,8 @@ namespace ts { || kind === SyntaxKind.TrueKeyword || kind === SyntaxKind.SuperKeyword || kind === SyntaxKind.NonNullExpression - || kind === SyntaxKind.MetaProperty; + || kind === SyntaxKind.MetaProperty + || kind === SyntaxKind.ImportCallExpression; } export function isLeftHandSideExpression(node: Node): node is LeftHandSideExpression {