@@ -120,7 +120,6 @@ import {
120
120
ImportClause,
121
121
ImportDeclaration,
122
122
ImportEqualsDeclaration,
123
- ImportOrExportSpecifier,
124
123
ImportSpecifier,
125
124
ImportTypeAssertionContainer,
126
125
ImportTypeNode,
@@ -253,6 +252,7 @@ import {
253
252
modifiersToFlags,
254
253
ModuleBlock,
255
254
ModuleDeclaration,
255
+ ModuleExportName,
256
256
ModuleKind,
257
257
Mutable,
258
258
NamedExportBindings,
@@ -2869,7 +2869,13 @@ namespace Parser {
2869
2869
case ParsingContext.HeritageClauses:
2870
2870
return isHeritageClause();
2871
2871
case ParsingContext.ImportOrExportSpecifiers:
2872
- return tokenIsIdentifierOrKeyword(token());
2872
+ // bail out if the next token is Identifier(from) StringLiteral.
2873
+ // That means we're in something like `import { from "mod"`
2874
+ // In this case we don't want parse it as import { from <missing SyntaxKind.AsKeyword> "mod", ...
2875
+ if (token() === SyntaxKind.FromKeyword && lookAhead(nextTokenIsStringLiteral)) {
2876
+ return false;
2877
+ }
2878
+ return token() === SyntaxKind.StringLiteral || tokenIsIdentifierOrKeyword(token());
2873
2879
case ParsingContext.JsxAttributes:
2874
2880
return tokenIsIdentifierOrKeyword(token()) || token() === SyntaxKind.OpenBraceToken;
2875
2881
case ParsingContext.JsxChildren:
@@ -3390,7 +3396,11 @@ namespace Parser {
3390
3396
case ParsingContext.TypeArguments: return parseErrorAtCurrentToken(Diagnostics.Type_argument_expected);
3391
3397
case ParsingContext.TupleElementTypes: return parseErrorAtCurrentToken(Diagnostics.Type_expected);
3392
3398
case ParsingContext.HeritageClauses: return parseErrorAtCurrentToken(Diagnostics.Unexpected_token_expected);
3393
- case ParsingContext.ImportOrExportSpecifiers: return parseErrorAtCurrentToken(Diagnostics.Identifier_expected);
3399
+ case ParsingContext.ImportOrExportSpecifiers:
3400
+ if (token() === SyntaxKind.FromKeyword) {
3401
+ return parseErrorAtCurrentToken(Diagnostics._0_expected, "}");
3402
+ }
3403
+ return parseErrorAtCurrentToken(Diagnostics.Identifier_expected);
3394
3404
case ParsingContext.JsxAttributes: return parseErrorAtCurrentToken(Diagnostics.Identifier_expected);
3395
3405
case ParsingContext.JsxChildren: return parseErrorAtCurrentToken(Diagnostics.Identifier_expected);
3396
3406
case ParsingContext.AssertEntries: return parseErrorAtCurrentToken(Diagnostics.Identifier_or_string_literal_expected); // AssertionKey.
@@ -7358,6 +7368,9 @@ namespace Parser {
7358
7368
}
7359
7369
}
7360
7370
7371
+ function nextTokenIsStringLiteral() {
7372
+ return nextToken() === SyntaxKind.StringLiteral;
7373
+ }
7361
7374
function nextTokenIsIdentifierOrStringLiteralOnSameLine() {
7362
7375
nextToken();
7363
7376
return !scanner.hasPrecedingLineBreak() && (isIdentifier() || token() === SyntaxKind.StringLiteral);
@@ -8345,29 +8358,34 @@ namespace Parser {
8345
8358
return parseImportOrExportSpecifier(SyntaxKind.ImportSpecifier) as ImportSpecifier;
8346
8359
}
8347
8360
8348
- function parseImportOrExportSpecifier(kind: SyntaxKind): ImportOrExportSpecifier {
8361
+ function parseImportOrExportSpecifier(kind: SyntaxKind) {
8349
8362
const pos = getNodePos();
8363
+ // ModuleExportName:
8364
+ // Identifier
8365
+ // StringLiteral
8350
8366
// ImportSpecifier:
8351
8367
// BindingIdentifier
8352
- // IdentifierName as BindingIdentifier
8368
+ // ModuleExportName as BindingIdentifier
8353
8369
// ExportSpecifier:
8354
- // IdentifierName
8355
- // IdentifierName as IdentifierName
8370
+ // ModuleExportName
8371
+ // ModuleExportName as ModuleExportName
8356
8372
let checkIdentifierIsKeyword = isKeyword(token()) && !isIdentifier();
8357
8373
let checkIdentifierStart = scanner.getTokenStart();
8358
8374
let checkIdentifierEnd = scanner.getTokenEnd();
8359
8375
let isTypeOnly = false;
8360
- let propertyName: Identifier | undefined;
8376
+ let propertyName: ModuleExportName | undefined;
8361
8377
let canParseAsKeyword = true;
8362
- let name = parseIdentifierName();
8363
- if (name.escapedText === "type") {
8378
+ let mustParseAsKeyword = false;
8379
+ let name = parseModuleExportName(parseIdentifierName);
8380
+ if (name.kind === SyntaxKind.Identifier && name.escapedText === "type") {
8364
8381
// If the first token of an import specifier is 'type', there are a lot of possibilities,
8365
8382
// especially if we see 'as' afterwards:
8366
8383
//
8367
8384
// import { type } from "mod"; - isTypeOnly: false, name: type
8368
8385
// import { type as } from "mod"; - isTypeOnly: true, name: as
8369
8386
// import { type as as } from "mod"; - isTypeOnly: false, name: as, propertyName: type
8370
8387
// import { type as as as } from "mod"; - isTypeOnly: true, name: as, propertyName: as
8388
+ // export { type as as "s" } from "mod";- isTypeOnly: true, name: "s", propertyName: as
8371
8389
if (token() === SyntaxKind.AsKeyword) {
8372
8390
// { type as ...? }
8373
8391
const firstAs = parseIdentifierName();
@@ -8376,9 +8394,10 @@ namespace Parser {
8376
8394
const secondAs = parseIdentifierName();
8377
8395
if (tokenIsIdentifierOrKeyword(token())) {
8378
8396
// { type as as something }
8397
+ // { type as as "something" } (only in exports)
8379
8398
isTypeOnly = true;
8380
8399
propertyName = firstAs;
8381
- name = parseNameWithKeywordCheck ();
8400
+ name = parseModuleExportNameOnlyForExports ();
8382
8401
canParseAsKeyword = false;
8383
8402
}
8384
8403
else {
@@ -8392,31 +8411,43 @@ namespace Parser {
8392
8411
// { type as something }
8393
8412
propertyName = name;
8394
8413
canParseAsKeyword = false;
8395
- name = parseNameWithKeywordCheck ();
8414
+ name = parseModuleExportNameOnlyForExports ();
8396
8415
}
8397
8416
else {
8398
8417
// { type as }
8399
8418
isTypeOnly = true;
8400
8419
name = firstAs;
8401
8420
}
8402
8421
}
8422
+ // export { type "x" }
8423
+ // import { type "x" as ... }
8424
+ else if (token() === SyntaxKind.StringLiteral) {
8425
+ isTypeOnly = true;
8426
+ if (kind === SyntaxKind.ImportSpecifier) mustParseAsKeyword = true;
8427
+ name = parseModuleExportName(parseNameWithKeywordCheck);
8428
+ }
8403
8429
else if (tokenIsIdentifierOrKeyword(token())) {
8404
8430
// { type something ...? }
8405
8431
isTypeOnly = true;
8406
8432
name = parseNameWithKeywordCheck();
8407
8433
}
8408
8434
}
8435
+ // import { "x" as ... }
8436
+ else if (kind === SyntaxKind.ImportSpecifier && name.kind === SyntaxKind.StringLiteral) {
8437
+ mustParseAsKeyword = true;
8438
+ }
8409
8439
8410
- if (canParseAsKeyword && token() === SyntaxKind.AsKeyword) {
8440
+ if (mustParseAsKeyword || ( canParseAsKeyword && token() === SyntaxKind.AsKeyword) ) {
8411
8441
propertyName = name;
8412
8442
parseExpected(SyntaxKind.AsKeyword);
8413
- name = parseNameWithKeywordCheck ();
8443
+ name = parseModuleExportNameOnlyForExports ();
8414
8444
}
8415
8445
if (kind === SyntaxKind.ImportSpecifier && checkIdentifierIsKeyword) {
8416
8446
parseErrorAt(checkIdentifierStart, checkIdentifierEnd, Diagnostics.Identifier_expected);
8417
8447
}
8448
+ if (kind === SyntaxKind.ImportSpecifier) Debug.assert(name.kind === SyntaxKind.Identifier);
8418
8449
const node = kind === SyntaxKind.ImportSpecifier
8419
- ? factory.createImportSpecifier(isTypeOnly, propertyName, name)
8450
+ ? factory.createImportSpecifier(isTypeOnly, propertyName, name as Identifier )
8420
8451
: factory.createExportSpecifier(isTypeOnly, propertyName, name);
8421
8452
return finishNode(node, pos);
8422
8453
@@ -8426,10 +8457,22 @@ namespace Parser {
8426
8457
checkIdentifierEnd = scanner.getTokenEnd();
8427
8458
return parseIdentifierName();
8428
8459
}
8460
+ function parseModuleExportNameOnlyForExports() {
8461
+ if (kind === SyntaxKind.ImportSpecifier) return parseNameWithKeywordCheck();
8462
+ return parseModuleExportName(parseNameWithKeywordCheck);
8463
+ }
8464
+ function parseModuleExportName(parser: () => Identifier): ModuleExportName {
8465
+ if (token() === SyntaxKind.StringLiteral) return parseStringLiteral();
8466
+ return parser();
8467
+ }
8468
+ function parseStringLiteral(): StringLiteral {
8469
+ // TODO: the spec requires it pass IsStringWellFormedUnicode
8470
+ return parseLiteralLikeNode(SyntaxKind.StringLiteral) as StringLiteral;
8471
+ }
8429
8472
}
8430
8473
8431
8474
function parseNamespaceExport(pos: number): NamespaceExport {
8432
- return finishNode(factory.createNamespaceExport(parseIdentifierName()), pos);
8475
+ return finishNode(factory.createNamespaceExport(token() === SyntaxKind.StringLiteral ? parseLiteralLikeNode(SyntaxKind.StringLiteral) as StringLiteral : parseIdentifierName()), pos);
8433
8476
}
8434
8477
8435
8478
function parseExportDeclaration(pos: number, hasJSDoc: boolean, modifiers: NodeArray<ModifierLike> | undefined): ExportDeclaration {
0 commit comments