Skip to content

Navigation Menu

Sign in
Appearance settings

Search code, repositories, users, issues, pull requests...

Provide feedback

We read every piece of feedback, and take your input very seriously.

Saved searches

Use saved searches to filter your results more quickly

Appearance settings

Commit 9e2bbb6

Browse filesBrowse files
Basic parsing/emitting support for 'import.meta'.
1 parent 9b8670c commit 9e2bbb6
Copy full SHA for 9e2bbb6

3 files changed

+85-32Lines changed: 85 additions & 32 deletions

File tree

Expand file treeCollapse file tree
Open diff view settings
Filter options
Expand file treeCollapse file tree
Open diff view settings
Collapse file

‎src/compiler/parser.ts‎

Copy file name to clipboardExpand all lines: src/compiler/parser.ts
+66-20Lines changed: 66 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -542,7 +542,7 @@ namespace ts {
542542
const newSourceFile = IncrementalParser.updateSourceFile(sourceFile, newText, textChangeRange, aggressiveChecks);
543543
// 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.
544544
// We will manually port the flag to the new source file.
545-
newSourceFile.flags |= (sourceFile.flags & NodeFlags.PossiblyContainsDynamicImport);
545+
newSourceFile.flags |= (sourceFile.flags & NodeFlags.PermanentlySetIncrementalFlags);
546546
return newSourceFile;
547547
}
548548

@@ -2627,6 +2627,20 @@ namespace ts {
26272627
return token() === SyntaxKind.OpenParenToken || token() === SyntaxKind.LessThanToken;
26282628
}
26292629

2630+
function nextTokenIsDot() {
2631+
return nextToken() === SyntaxKind.DotToken;
2632+
}
2633+
2634+
function nextTokenIsOpenParenOrLessThanOrDot() {
2635+
switch (nextToken()) {
2636+
case SyntaxKind.OpenParenToken:
2637+
case SyntaxKind.LessThanToken:
2638+
case SyntaxKind.DotToken:
2639+
return true;
2640+
}
2641+
return false;
2642+
}
2643+
26302644
function parseTypeLiteral(): TypeLiteralNode {
26312645
const node = <TypeLiteralNode>createNode(SyntaxKind.TypeLiteral);
26322646
node.members = parseObjectTypeMembers();
@@ -3095,7 +3109,7 @@ namespace ts {
30953109
case SyntaxKind.Identifier:
30963110
return true;
30973111
case SyntaxKind.ImportKeyword:
3098-
return lookAhead(nextTokenIsOpenParenOrLessThan);
3112+
return lookAhead(nextTokenIsOpenParenOrLessThanOrDot);
30993113
default:
31003114
return isIdentifier();
31013115
}
@@ -3957,14 +3971,31 @@ namespace ts {
39573971
// 3)we have a MemberExpression which either completes the LeftHandSideExpression,
39583972
// or starts the beginning of the first four CallExpression productions.
39593973
let expression: MemberExpression;
3960-
if (token() === SyntaxKind.ImportKeyword && lookAhead(nextTokenIsOpenParenOrLessThan)) {
3961-
// We don't want to eagerly consume all import keyword as import call expression so we look a head to find "("
3962-
// For example:
3963-
// var foo3 = require("subfolder
3964-
// import * as foo1 from "module-from-node
3965-
// We want this import to be a statement rather than import call expression
3966-
sourceFile.flags |= NodeFlags.PossiblyContainsDynamicImport;
3967-
expression = parseTokenNode<PrimaryExpression>();
3974+
if (token() === SyntaxKind.ImportKeyword) {
3975+
if (lookAhead(nextTokenIsOpenParenOrLessThan)) {
3976+
// We don't want to eagerly consume all import keyword as import call expression so we look ahead to find "("
3977+
// For example:
3978+
// var foo3 = require("subfolder
3979+
// import * as foo1 from "module-from-node
3980+
// We want this import to be a statement rather than import call expression
3981+
sourceFile.flags |= NodeFlags.PossiblyContainsDynamicImport;
3982+
expression = parseTokenNode<PrimaryExpression>();
3983+
}
3984+
else if (lookAhead(nextTokenIsDot)) {
3985+
// This is an 'import.*' metaproperty (i.e. 'import.meta')
3986+
const fullStart = scanner.getStartPos();
3987+
nextToken(); // advance past the 'import'
3988+
nextToken(); // advance past the dot
3989+
const node = createNode(SyntaxKind.MetaProperty, fullStart) as MetaProperty;
3990+
node.keywordToken = SyntaxKind.ImportKeyword;
3991+
node.name = parseIdentifierName();
3992+
expression = finishNode(node);
3993+
3994+
sourceFile.flags |= NodeFlags.PossiblyContainsImportMeta;
3995+
}
3996+
else {
3997+
expression = parseMemberExpressionOrHigher();
3998+
}
39683999
}
39694000
else {
39704001
expression = token() === SyntaxKind.SuperKeyword ? parseSuperExpression() : parseMemberExpressionOrHigher();
@@ -4508,7 +4539,7 @@ namespace ts {
45084539
case SyntaxKind.FunctionKeyword:
45094540
return parseFunctionExpression();
45104541
case SyntaxKind.NewKeyword:
4511-
return parseNewExpression();
4542+
return parseNewExpressionOrNewDotTarget();
45124543
case SyntaxKind.SlashToken:
45134544
case SyntaxKind.SlashEqualsToken:
45144545
if (reScanSlashToken() === SyntaxKind.RegularExpressionLiteral) {
@@ -4659,7 +4690,7 @@ namespace ts {
46594690
return isIdentifier() ? parseIdentifier() : undefined;
46604691
}
46614692

4662-
function parseNewExpression(): NewExpression | MetaProperty {
4693+
function parseNewExpressionOrNewDotTarget(): NewExpression | MetaProperty {
46634694
const fullStart = scanner.getStartPos();
46644695
parseExpected(SyntaxKind.NewKeyword);
46654696
if (parseOptional(SyntaxKind.DotToken)) {
@@ -5093,7 +5124,7 @@ namespace ts {
50935124
return true;
50945125

50955126
case SyntaxKind.ImportKeyword:
5096-
return isStartOfDeclaration() || lookAhead(nextTokenIsOpenParenOrLessThan);
5127+
return isStartOfDeclaration() || lookAhead(nextTokenIsOpenParenOrLessThanOrDot);
50975128

50985129
case SyntaxKind.ConstKeyword:
50995130
case SyntaxKind.ExportKeyword:
@@ -6079,14 +6110,29 @@ namespace ts {
60796110
}
60806111

60816112
function setExternalModuleIndicator(sourceFile: SourceFile) {
6082-
sourceFile.externalModuleIndicator = forEach(sourceFile.statements, node =>
6083-
hasModifier(node, ModifierFlags.Export)
6084-
|| node.kind === SyntaxKind.ImportEqualsDeclaration && (<ImportEqualsDeclaration>node).moduleReference.kind === SyntaxKind.ExternalModuleReference
6085-
|| node.kind === SyntaxKind.ImportDeclaration
6086-
|| node.kind === SyntaxKind.ExportAssignment
6087-
|| node.kind === SyntaxKind.ExportDeclaration
6113+
// Usually we'd like to avoid a full tree walk, but it's possible
6114+
// that we have a deeper external module indicator (e.g. `import.meta`,
6115+
// and possibly nested import statements in the future).
6116+
// Ideally the first few statements will be an import/export anyway.
6117+
sourceFile.externalModuleIndicator =
6118+
!(sourceFile.flags & NodeFlags.PossiblyContainsImportMeta) ?
6119+
forEach(sourceFile.statements, isAnExternalModuleIndicatorNode) :
6120+
walkTreeForExternalModuleIndicators(sourceFile);
6121+
}
6122+
6123+
function isAnExternalModuleIndicatorNode(node: Node) {
6124+
return hasModifier(node, ModifierFlags.Export)
6125+
|| node.kind === SyntaxKind.ImportEqualsDeclaration && (<ImportEqualsDeclaration>node).moduleReference.kind === SyntaxKind.ExternalModuleReference
6126+
|| node.kind === SyntaxKind.ImportDeclaration
6127+
|| node.kind === SyntaxKind.ExportAssignment
6128+
|| node.kind === SyntaxKind.ExportDeclaration
6129+
|| isMetaProperty(node) && node.keywordToken === SyntaxKind.ImportKeyword && node.name.escapedText === "meta"
60886130
? node
6089-
: undefined);
6131+
: undefined
6132+
}
6133+
6134+
function walkTreeForExternalModuleIndicators(node: Node): Node {
6135+
return isAnExternalModuleIndicatorNode(node) ? node : forEachChild(node, walkTreeForExternalModuleIndicators);
60906136
}
60916137

60926138
const enum ParsingContext {
Collapse file

‎src/compiler/program.ts‎

Copy file name to clipboardExpand all lines: src/compiler/program.ts
+1-1Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -989,7 +989,7 @@ namespace ts {
989989
// moduleAugmentations has changed
990990
oldProgram.structureIsReused = StructureIsReused.SafeModules;
991991
}
992-
if ((oldSourceFile.flags & NodeFlags.PossiblyContainsDynamicImport) !== (newSourceFile.flags & NodeFlags.PossiblyContainsDynamicImport)) {
992+
if ((oldSourceFile.flags & NodeFlags.PermanentlySetIncrementalFlags) !== (newSourceFile.flags & NodeFlags.PermanentlySetIncrementalFlags)) {
993993
// dynamicImport has changed
994994
oldProgram.structureIsReused = StructureIsReused.SafeModules;
995995
}
Collapse file

‎src/compiler/types.ts‎

Copy file name to clipboardExpand all lines: src/compiler/types.ts
+18-11Lines changed: 18 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -490,19 +490,21 @@ namespace ts {
490490
ThisNodeOrAnySubNodesHasError = 1 << 17, // If this node or any of its children had an error
491491
HasAggregatedChildData = 1 << 18, // If we've computed data from children and cached it in this node
492492

493-
// This flag will be set when the parser encounters a dynamic import expression so that module resolution
494-
// will not have to walk the tree if the flag is not set. However, this flag is just a approximation because
495-
// once it is set, the flag never gets cleared (hence why it's named "PossiblyContainsDynamicImport").
496-
// During editing, if dynamic import is removed, incremental parsing will *NOT* update this flag. This means that the tree will always be traversed
497-
// during module resolution. However, the removal operation should not occur often and in the case of the
493+
// These flags will be set when the parser encounters a dynamic import expression or 'import.meta' to avoid
494+
// walking the tree if the flags are not set. However, these flags are just a approximation
495+
// (hence why it's named "PossiblyContainsDynamicImport") because once set, the flags never get cleared.
496+
// During editing, if a dynamic import is removed, incremental parsing will *NOT* clear this flag.
497+
// This means that the tree will always be traversed during module resolution, or when looking for external module indicators.
498+
// However, the removal operation should not occur often and in the case of the
498499
// removal, it is likely that users will add the import anyway.
499500
// The advantage of this approach is its simplicity. For the case of batch compilation,
500501
// we guarantee that users won't have to pay the price of walking the tree if a dynamic import isn't used.
501-
/* @internal */
502-
PossiblyContainsDynamicImport = 1 << 19,
503-
JSDoc = 1 << 20, // If node was parsed inside jsdoc
504-
/* @internal */ Ambient = 1 << 21, // If node was inside an ambient context -- a declaration file, or inside something with the `declare` modifier.
505-
/* @internal */ InWithStatement = 1 << 22, // If any ancestor of node was the `statement` of a WithStatement (not the `expression`)
502+
/* @internal */ PossiblyContainsDynamicImport = 1 << 19,
503+
/* @internal */ PossiblyContainsImportMeta = 1 << 20,
504+
505+
JSDoc = 1 << 21, // If node was parsed inside jsdoc
506+
/* @internal */ Ambient = 1 << 22, // If node was inside an ambient context -- a declaration file, or inside something with the `declare` modifier.
507+
/* @internal */ InWithStatement = 1 << 23, // If any ancestor of node was the `statement` of a WithStatement (not the `expression`)
506508

507509
BlockScoped = Let | Const,
508510

@@ -514,6 +516,11 @@ namespace ts {
514516

515517
// Exclude these flags when parsing a Type
516518
TypeExcludesFlags = YieldContext | AwaitContext,
519+
520+
// Represents all flags that are potentially set once and
521+
// never cleared on SourceFiles which get re-used in between incremental parses.
522+
// See the comment above on `PossiblyContainsDynamicImport` and `PossiblyContainsImportMeta`.
523+
/* @internal */ PermanentlySetIncrementalFlags = PossiblyContainsDynamicImport | PossiblyContainsImportMeta,
517524
}
518525

519526
export const enum ModifierFlags {
@@ -1754,7 +1761,7 @@ namespace ts {
17541761
// for the same reasons we treat NewExpression as a PrimaryExpression.
17551762
export interface MetaProperty extends PrimaryExpression {
17561763
kind: SyntaxKind.MetaProperty;
1757-
keywordToken: SyntaxKind.NewKeyword;
1764+
keywordToken: SyntaxKind.NewKeyword | SyntaxKind.ImportKeyword;
17581765
name: Identifier;
17591766
}
17601767

0 commit comments

Comments
0 (0)
Morty Proxy This is a proxified and sanitized view of the page, visit original site.