-
Notifications
You must be signed in to change notification settings - Fork 12.5k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
[Master] wip-dynamic import #14774
[Master] wip-dynamic import #14774
Changes from 31 commits
787ed37
ca08167
330f7bf
e7b3a15
827abb3
6933b58
126fb64
bd50ccf
7340d84
18c826b
ddf5ed9
26f9a52
20293b0
369af08
ffbb445
be375cb
a84645c
9864b4e
86c7129
6db02e7
a77f0d2
dbac66c
804ab2c
1af1005
e019216
015f71b
8fd660b
f04f7b5
871d609
15ca0af
2332ea3
91d9ecf
c798489
c62f4f5
e1ba855
265d0c0
640f2c7
61f199e
486dc91
6080c3e
32e5cf7
249f446
f3306db
11f6eae
d4754db
9715052
ca65996
faaa38d
55430c4
78b8275
d1d5cac
2b96374
2f61d47
a10e668
e50667e
feb41f7
742d515
35e2289
a2d9fd4
1b0d020
1b7d3bf
faab927
a02edb1
72ba23c
e6d7327
d9e2033
769f6ad
2f476bf
9203f95
4733f0d
c2056c0
e386d65
3118afe
75aa4bd
7d64ec9
1729ea8
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -867,6 +867,10 @@ | |
"category": "Error", | ||
"code": 1319 | ||
}, | ||
"Dynamic import cannot be used when targeting ECMAScript 2015 modules.": { | ||
"category": "Error", | ||
"code": 1320 | ||
}, | ||
"Duplicate identifier '{0}'.": { | ||
"category": "Error", | ||
"code": 2300 | ||
|
@@ -1863,10 +1867,6 @@ | |
"category": "Error", | ||
"code": 2649 | ||
}, | ||
"Cannot emit namespaced JSX elements in React.": { | ||
"category": "Error", | ||
"code": 2650 | ||
}, | ||
"A member initializer in a enum declaration cannot reference members declared after it, including members defined in other enums.": { | ||
"category": "Error", | ||
"code": 2651 | ||
|
@@ -2091,6 +2091,14 @@ | |
"category": "Error", | ||
"code": 2707 | ||
}, | ||
"A dynamic import call must return a 'Promise'. Make sure you have a declaration for 'Promise' or include 'ES2015' in your `--lib` option.": { | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Since you cannot set the return type for |
||
"category": "Error", | ||
"code": 2708 | ||
}, | ||
"A dynamic import call in ES5/ES3 requires the 'Promise' constructor. Make sure you have a declaration for the 'Promise' constructor or include 'ES2015' in your `--lib` option.": { | ||
"category": "Error", | ||
"code": 2709 | ||
}, | ||
|
||
"Import declaration '{0}' is using private name '{1}'.": { | ||
"category": "Error", | ||
|
@@ -2561,7 +2569,7 @@ | |
"category": "Message", | ||
"code": 6015 | ||
}, | ||
"Specify module code generation: 'commonjs', 'amd', 'system', 'umd' or 'es2015'.": { | ||
"Specify module code generation: 'commonjs', 'amd', 'system', 'umd', 'es2015', or 'es2018'.": { | ||
"category": "Message", | ||
"code": 6016 | ||
}, | ||
|
@@ -3153,6 +3161,14 @@ | |
"category": "Error", | ||
"code": 7034 | ||
}, | ||
"Cannot resolve dynamic import, implicitly has a 'Promise<any>' type.": { | ||
"category": "Error", | ||
"code": 7035 | ||
}, | ||
"Dynamic import's specifier must be of type 'string', but here has type '{0}'.": { | ||
"category": "Error", | ||
"code": 7036 | ||
}, | ||
"You cannot rename this element.": { | ||
"category": "Error", | ||
"code": 8000 | ||
|
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -167,6 +167,8 @@ namespace ts { | |
return visitNode(cbNode, (<CallExpression>node).expression) || | ||
visitNodes(cbNodes, (<CallExpression>node).typeArguments) || | ||
visitNodes(cbNodes, (<CallExpression>node).arguments); | ||
case SyntaxKind.ImportCallExpression: | ||
return visitNode(cbNode, (<ImportCallExpression>node).specifier); | ||
case SyntaxKind.TaggedTemplateExpression: | ||
return visitNode(cbNode, (<TaggedTemplateExpression>node).tag) || | ||
visitNode(cbNode, (<TaggedTemplateExpression>node).template); | ||
|
@@ -2776,6 +2778,7 @@ namespace ts { | |
case SyntaxKind.SlashToken: | ||
case SyntaxKind.SlashEqualsToken: | ||
case SyntaxKind.Identifier: | ||
case SyntaxKind.ImportKeyword: | ||
return true; | ||
default: | ||
return isIdentifier(); | ||
|
@@ -3509,10 +3512,10 @@ namespace ts { | |
* 5) --UnaryExpression[?Yield] | ||
*/ | ||
if (isUpdateExpression()) { | ||
const incrementExpression = parseIncrementExpression(); | ||
const UpdateExpression = parseUpdateExpression(); | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. nit: Capitalization. Variable name should be |
||
return token() === SyntaxKind.AsteriskAsteriskToken ? | ||
<BinaryExpression>parseBinaryExpressionRest(getBinaryOperatorPrecedence(), incrementExpression) : | ||
incrementExpression; | ||
<BinaryExpression>parseBinaryExpressionRest(getBinaryOperatorPrecedence(), UpdateExpression) : | ||
UpdateExpression; | ||
} | ||
|
||
/** | ||
|
@@ -3577,7 +3580,7 @@ namespace ts { | |
return parseAwaitExpression(); | ||
} | ||
default: | ||
return parseIncrementExpression(); | ||
return parseUpdateExpression(); | ||
} | ||
} | ||
|
||
|
@@ -3593,7 +3596,7 @@ namespace ts { | |
*/ | ||
function isUpdateExpression(): boolean { | ||
// This function is called inside parseUnaryExpression to decide | ||
// whether to call parseSimpleUnaryExpression or call parseIncrementExpression directly | ||
// whether to call parseSimpleUnaryExpression or call parseUpdateExpression directly | ||
switch (token()) { | ||
case SyntaxKind.PlusToken: | ||
case SyntaxKind.MinusToken: | ||
|
@@ -3617,17 +3620,17 @@ namespace ts { | |
} | ||
|
||
/** | ||
* Parse ES7 IncrementExpression. IncrementExpression is used instead of ES6's PostFixExpression. | ||
* Parse ES7 UpdateExpression. UpdateExpression is used instead of ES6's PostFixExpression. | ||
* | ||
* ES7 IncrementExpression[yield]: | ||
* ES7 UpdateExpression[yield]: | ||
* 1) LeftHandSideExpression[?yield] | ||
* 2) LeftHandSideExpression[?yield] [[no LineTerminator here]]++ | ||
* 3) LeftHandSideExpression[?yield] [[no LineTerminator here]]-- | ||
* 4) ++LeftHandSideExpression[?yield] | ||
* 5) --LeftHandSideExpression[?yield] | ||
* In TypeScript (2), (3) are parsed as PostfixUnaryExpression. (4), (5) are parsed as PrefixUnaryExpression | ||
*/ | ||
function parseIncrementExpression(): IncrementExpression { | ||
function parseUpdateExpression(): UpdateExpression { | ||
if (token() === SyntaxKind.PlusPlusToken || token() === SyntaxKind.MinusMinusToken) { | ||
const node = <PrefixUnaryExpression>createNode(SyntaxKind.PrefixUnaryExpression); | ||
node.operator = <PrefixUnaryOperator>token(); | ||
|
@@ -3677,25 +3680,33 @@ namespace ts { | |
// CallExpression Arguments | ||
// CallExpression[Expression] | ||
// CallExpression.IdentifierName | ||
// super ( ArgumentListopt ) | ||
// import (AssignmentExpression) | ||
// super Arguments | ||
// super.IdentifierName | ||
// | ||
// Because of the recursion in these calls, we need to bottom out first. There are two | ||
// bottom out states we can run into. Either we see 'super' which must start either of | ||
// the last two CallExpression productions. Or we have a MemberExpression which either | ||
// completes the LeftHandSideExpression, or starts the beginning of the first four | ||
// CallExpression productions. | ||
const expression = token() === SyntaxKind.SuperKeyword | ||
? parseSuperExpression() | ||
: parseMemberExpressionOrHigher(); | ||
// Because of the recursion in these calls, we need to bottom out first. There are three | ||
// bottom out states we can run into: 1) We see 'super' which must start either of | ||
// 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. | ||
|
||
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 | ||
// import * as foo1 from "module-from-node -> we want this import to be a statement rather than import call expression | ||
const importCall = parseImportCallExpression(); | ||
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. | ||
return parseCallExpressionRest(expression); | ||
} | ||
|
||
function parseMemberExpressionOrHigher(): MemberExpression { | ||
// Note: to make our lives simpler, we decompose the the NewExpression productions and | ||
// Note: to make our lives simpler, we decompose the NewExpression productions and | ||
// place ObjectCreationExpression and FunctionExpression into PrimaryExpression. | ||
// like so: | ||
// | ||
|
@@ -3761,6 +3772,15 @@ namespace ts { | |
return finishNode(node); | ||
} | ||
|
||
function parseImportCallExpression(): ImportCallExpression { | ||
const importCallExpr = <ImportCallExpression>createNode(SyntaxKind.ImportCallExpression); | ||
parseExpected(SyntaxKind.ImportKeyword); | ||
parseExpected(SyntaxKind.OpenParenToken); | ||
importCallExpr.specifier = parseAssignmentExpressionOrHigher(); | ||
parseExpected(SyntaxKind.CloseParenToken); | ||
return finishNode(importCallExpr); | ||
} | ||
|
||
function tagNamesAreEquivalent(lhs: JsxTagNameExpression, rhs: JsxTagNameExpression): boolean { | ||
if (lhs.kind !== rhs.kind) { | ||
return false; | ||
|
@@ -4776,11 +4796,11 @@ namespace ts { | |
// however, we say they are here so that we may gracefully parse them and error later. | ||
case SyntaxKind.CatchKeyword: | ||
case SyntaxKind.FinallyKeyword: | ||
case SyntaxKind.ImportKeyword: | ||
return true; | ||
|
||
case SyntaxKind.ConstKeyword: | ||
case SyntaxKind.ExportKeyword: | ||
case SyntaxKind.ImportKeyword: | ||
return isStartOfDeclaration(); | ||
|
||
case SyntaxKind.AsyncKeyword: | ||
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Just a note: there were talks in the past about attaching meta-properties to the
import
keyword (similar tonew.target
), though there hasn't been a concrete proposal for it yet. It'll probably become needed as node iterates on their implementation.Also, estree and babylon went with
Import
for this AST node.There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Sound like a good idea to prepare for that....
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Now that I'm back on a computer, I found the discussion in estree's repository about the AST node: estree/estree#137
And this is how it got merged in their spec: https://github.com/estree/estree/blob/8ab627557/experimental/import-expression.md
Thinking about it, (when it gets meta-properties) it'll behave pretty similarly to
super
, being both callable and "indexable".There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@Kovensky That is what I was thinking about doing. treat it similar to super -> which we either parse as callExpression or propertyAccessexpression
Update: extra benefit is that now for future, it is also possible to use type argument of callexpression to express the shape of return module object