mirror of
https://github.com/microsoft/TypeScript.git
synced 2025-11-18 17:21:48 +00:00
Basic parsing/emitting support for 'import.meta'.
This commit is contained in:
+66
-20
@@ -542,7 +542,7 @@ namespace ts {
|
||||
const newSourceFile = IncrementalParser.updateSourceFile(sourceFile, newText, textChangeRange, aggressiveChecks);
|
||||
// Because new source file node is created, it may not have the flag PossiblyContainDynamicImport. This is the case if there is no new edit to add dynamic import.
|
||||
// We will manually port the flag to the new source file.
|
||||
newSourceFile.flags |= (sourceFile.flags & NodeFlags.PossiblyContainsDynamicImport);
|
||||
newSourceFile.flags |= (sourceFile.flags & NodeFlags.PermanentlySetIncrementalFlags);
|
||||
return newSourceFile;
|
||||
}
|
||||
|
||||
@@ -2627,6 +2627,20 @@ namespace ts {
|
||||
return token() === SyntaxKind.OpenParenToken || token() === SyntaxKind.LessThanToken;
|
||||
}
|
||||
|
||||
function nextTokenIsDot() {
|
||||
return nextToken() === SyntaxKind.DotToken;
|
||||
}
|
||||
|
||||
function nextTokenIsOpenParenOrLessThanOrDot() {
|
||||
switch (nextToken()) {
|
||||
case SyntaxKind.OpenParenToken:
|
||||
case SyntaxKind.LessThanToken:
|
||||
case SyntaxKind.DotToken:
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
function parseTypeLiteral(): TypeLiteralNode {
|
||||
const node = <TypeLiteralNode>createNode(SyntaxKind.TypeLiteral);
|
||||
node.members = parseObjectTypeMembers();
|
||||
@@ -3095,7 +3109,7 @@ namespace ts {
|
||||
case SyntaxKind.Identifier:
|
||||
return true;
|
||||
case SyntaxKind.ImportKeyword:
|
||||
return lookAhead(nextTokenIsOpenParenOrLessThan);
|
||||
return lookAhead(nextTokenIsOpenParenOrLessThanOrDot);
|
||||
default:
|
||||
return isIdentifier();
|
||||
}
|
||||
@@ -3957,14 +3971,31 @@ namespace ts {
|
||||
// 3)we have a MemberExpression which either completes the LeftHandSideExpression,
|
||||
// or starts the beginning of the first four CallExpression productions.
|
||||
let expression: MemberExpression;
|
||||
if (token() === SyntaxKind.ImportKeyword && lookAhead(nextTokenIsOpenParenOrLessThan)) {
|
||||
// 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
|
||||
// import * as foo1 from "module-from-node
|
||||
// We want this import to be a statement rather than import call expression
|
||||
sourceFile.flags |= NodeFlags.PossiblyContainsDynamicImport;
|
||||
expression = parseTokenNode<PrimaryExpression>();
|
||||
if (token() === SyntaxKind.ImportKeyword) {
|
||||
if (lookAhead(nextTokenIsOpenParenOrLessThan)) {
|
||||
// We don't want to eagerly consume all import keyword as import call expression so we look ahead to find "("
|
||||
// For example:
|
||||
// var foo3 = require("subfolder
|
||||
// import * as foo1 from "module-from-node
|
||||
// We want this import to be a statement rather than import call expression
|
||||
sourceFile.flags |= NodeFlags.PossiblyContainsDynamicImport;
|
||||
expression = parseTokenNode<PrimaryExpression>();
|
||||
}
|
||||
else if (lookAhead(nextTokenIsDot)) {
|
||||
// This is an 'import.*' metaproperty (i.e. 'import.meta')
|
||||
const fullStart = scanner.getStartPos();
|
||||
nextToken(); // advance past the 'import'
|
||||
nextToken(); // advance past the dot
|
||||
const node = createNode(SyntaxKind.MetaProperty, fullStart) as MetaProperty;
|
||||
node.keywordToken = SyntaxKind.ImportKeyword;
|
||||
node.name = parseIdentifierName();
|
||||
expression = finishNode(node);
|
||||
|
||||
sourceFile.flags |= NodeFlags.PossiblyContainsImportMeta;
|
||||
}
|
||||
else {
|
||||
expression = parseMemberExpressionOrHigher();
|
||||
}
|
||||
}
|
||||
else {
|
||||
expression = token() === SyntaxKind.SuperKeyword ? parseSuperExpression() : parseMemberExpressionOrHigher();
|
||||
@@ -4508,7 +4539,7 @@ namespace ts {
|
||||
case SyntaxKind.FunctionKeyword:
|
||||
return parseFunctionExpression();
|
||||
case SyntaxKind.NewKeyword:
|
||||
return parseNewExpression();
|
||||
return parseNewExpressionOrNewDotTarget();
|
||||
case SyntaxKind.SlashToken:
|
||||
case SyntaxKind.SlashEqualsToken:
|
||||
if (reScanSlashToken() === SyntaxKind.RegularExpressionLiteral) {
|
||||
@@ -4659,7 +4690,7 @@ namespace ts {
|
||||
return isIdentifier() ? parseIdentifier() : undefined;
|
||||
}
|
||||
|
||||
function parseNewExpression(): NewExpression | MetaProperty {
|
||||
function parseNewExpressionOrNewDotTarget(): NewExpression | MetaProperty {
|
||||
const fullStart = scanner.getStartPos();
|
||||
parseExpected(SyntaxKind.NewKeyword);
|
||||
if (parseOptional(SyntaxKind.DotToken)) {
|
||||
@@ -5093,7 +5124,7 @@ namespace ts {
|
||||
return true;
|
||||
|
||||
case SyntaxKind.ImportKeyword:
|
||||
return isStartOfDeclaration() || lookAhead(nextTokenIsOpenParenOrLessThan);
|
||||
return isStartOfDeclaration() || lookAhead(nextTokenIsOpenParenOrLessThanOrDot);
|
||||
|
||||
case SyntaxKind.ConstKeyword:
|
||||
case SyntaxKind.ExportKeyword:
|
||||
@@ -6079,14 +6110,29 @@ namespace ts {
|
||||
}
|
||||
|
||||
function setExternalModuleIndicator(sourceFile: SourceFile) {
|
||||
sourceFile.externalModuleIndicator = forEach(sourceFile.statements, node =>
|
||||
hasModifier(node, ModifierFlags.Export)
|
||||
|| node.kind === SyntaxKind.ImportEqualsDeclaration && (<ImportEqualsDeclaration>node).moduleReference.kind === SyntaxKind.ExternalModuleReference
|
||||
|| node.kind === SyntaxKind.ImportDeclaration
|
||||
|| node.kind === SyntaxKind.ExportAssignment
|
||||
|| node.kind === SyntaxKind.ExportDeclaration
|
||||
// Usually we'd like to avoid a full tree walk, but it's possible
|
||||
// that we have a deeper external module indicator (e.g. `import.meta`,
|
||||
// and possibly nested import statements in the future).
|
||||
// Ideally the first few statements will be an import/export anyway.
|
||||
sourceFile.externalModuleIndicator =
|
||||
!(sourceFile.flags & NodeFlags.PossiblyContainsImportMeta) ?
|
||||
forEach(sourceFile.statements, isAnExternalModuleIndicatorNode) :
|
||||
walkTreeForExternalModuleIndicators(sourceFile);
|
||||
}
|
||||
|
||||
function isAnExternalModuleIndicatorNode(node: Node) {
|
||||
return hasModifier(node, ModifierFlags.Export)
|
||||
|| node.kind === SyntaxKind.ImportEqualsDeclaration && (<ImportEqualsDeclaration>node).moduleReference.kind === SyntaxKind.ExternalModuleReference
|
||||
|| node.kind === SyntaxKind.ImportDeclaration
|
||||
|| node.kind === SyntaxKind.ExportAssignment
|
||||
|| node.kind === SyntaxKind.ExportDeclaration
|
||||
|| isMetaProperty(node) && node.keywordToken === SyntaxKind.ImportKeyword && node.name.escapedText === "meta"
|
||||
? node
|
||||
: undefined);
|
||||
: undefined
|
||||
}
|
||||
|
||||
function walkTreeForExternalModuleIndicators(node: Node): Node {
|
||||
return isAnExternalModuleIndicatorNode(node) ? node : forEachChild(node, walkTreeForExternalModuleIndicators);
|
||||
}
|
||||
|
||||
const enum ParsingContext {
|
||||
|
||||
Reference in New Issue
Block a user