Skip to content

Commit 9819350

Browse files
Merge remote-tracking branch 'origin/main' into release-4.5
2 parents d2a9da9 + cdfc796 commit 9819350

File tree

115 files changed

+4129
-3002
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

115 files changed

+4129
-3002
lines changed

package-lock.json

Lines changed: 3 additions & 3 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

src/compiler/checker.ts

Lines changed: 149 additions & 50 deletions
Large diffs are not rendered by default.

src/compiler/diagnosticMessages.json

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1434,6 +1434,14 @@
14341434
"code": 2205,
14351435
"elidedInCompatabilityPyramid": true
14361436
},
1437+
"The 'type' modifier cannot be used on a named import when 'import type' is used on its import statement.": {
1438+
"category": "Error",
1439+
"code": 2206
1440+
},
1441+
"The 'type' modifier cannot be used on a named export when 'export type' is used on its export statement.": {
1442+
"category": "Error",
1443+
"code": 2207
1444+
},
14371445

14381446
"Duplicate identifier '{0}'.": {
14391447
"category": "Error",

src/compiler/emitter.ts

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3441,6 +3441,10 @@ namespace ts {
34413441
}
34423442

34433443
function emitImportOrExportSpecifier(node: ImportOrExportSpecifier) {
3444+
if (node.isTypeOnly) {
3445+
writeKeyword("type");
3446+
writeSpace();
3447+
}
34443448
if (node.propertyName) {
34453449
emit(node.propertyName);
34463450
writeSpace();

src/compiler/factory/nodeFactory.ts

Lines changed: 13 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -4089,8 +4089,9 @@ namespace ts {
40894089
}
40904090

40914091
// @api
4092-
function createImportSpecifier(propertyName: Identifier | undefined, name: Identifier) {
4092+
function createImportSpecifier(isTypeOnly: boolean, propertyName: Identifier | undefined, name: Identifier) {
40934093
const node = createBaseNode<ImportSpecifier>(SyntaxKind.ImportSpecifier);
4094+
node.isTypeOnly = isTypeOnly;
40944095
node.propertyName = propertyName;
40954096
node.name = name;
40964097
node.transformFlags |=
@@ -4101,10 +4102,11 @@ namespace ts {
41014102
}
41024103

41034104
// @api
4104-
function updateImportSpecifier(node: ImportSpecifier, propertyName: Identifier | undefined, name: Identifier) {
4105-
return node.propertyName !== propertyName
4105+
function updateImportSpecifier(node: ImportSpecifier, isTypeOnly: boolean, propertyName: Identifier | undefined, name: Identifier) {
4106+
return node.isTypeOnly !== isTypeOnly
4107+
|| node.propertyName !== propertyName
41064108
|| node.name !== name
4107-
? update(createImportSpecifier(propertyName, name), node)
4109+
? update(createImportSpecifier(isTypeOnly, propertyName, name), node)
41084110
: node;
41094111
}
41104112

@@ -4205,8 +4207,9 @@ namespace ts {
42054207
}
42064208

42074209
// @api
4208-
function createExportSpecifier(propertyName: string | Identifier | undefined, name: string | Identifier) {
4210+
function createExportSpecifier(isTypeOnly: boolean, propertyName: string | Identifier | undefined, name: string | Identifier) {
42094211
const node = createBaseNode<ExportSpecifier>(SyntaxKind.ExportSpecifier);
4212+
node.isTypeOnly = isTypeOnly;
42104213
node.propertyName = asName(propertyName);
42114214
node.name = asName(name);
42124215
node.transformFlags |=
@@ -4217,10 +4220,11 @@ namespace ts {
42174220
}
42184221

42194222
// @api
4220-
function updateExportSpecifier(node: ExportSpecifier, propertyName: Identifier | undefined, name: Identifier) {
4221-
return node.propertyName !== propertyName
4223+
function updateExportSpecifier(node: ExportSpecifier, isTypeOnly: boolean, propertyName: Identifier | undefined, name: Identifier) {
4224+
return node.isTypeOnly !== isTypeOnly
4225+
|| node.propertyName !== propertyName
42224226
|| node.name !== name
4223-
? update(createExportSpecifier(propertyName, name), node)
4227+
? update(createExportSpecifier(isTypeOnly, propertyName, name), node)
42244228
: node;
42254229
}
42264230

@@ -5488,7 +5492,7 @@ namespace ts {
54885492
/*modifiers*/ undefined,
54895493
/*isTypeOnly*/ false,
54905494
createNamedExports([
5491-
createExportSpecifier(/*propertyName*/ undefined, exportName)
5495+
createExportSpecifier(/*isTypeOnly*/ false, /*propertyName*/ undefined, exportName)
54925496
])
54935497
);
54945498
}

src/compiler/factory/utilities.ts

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -500,8 +500,8 @@ namespace ts {
500500
// NOTE: We don't need to care about global import collisions as this is a module.
501501
namedBindings = nodeFactory.createNamedImports(
502502
map(helperNames, name => isFileLevelUniqueName(sourceFile, name)
503-
? nodeFactory.createImportSpecifier(/*propertyName*/ undefined, nodeFactory.createIdentifier(name))
504-
: nodeFactory.createImportSpecifier(nodeFactory.createIdentifier(name), helperFactory.getUnscopedHelperName(name))
503+
? nodeFactory.createImportSpecifier(/*isTypeOnly*/ false, /*propertyName*/ undefined, nodeFactory.createIdentifier(name))
504+
: nodeFactory.createImportSpecifier(/*isTypeOnly*/ false, nodeFactory.createIdentifier(name), helperFactory.getUnscopedHelperName(name))
505505
)
506506
);
507507
const parseNode = getOriginalNode(sourceFile, isSourceFile);

src/compiler/parser.ts

Lines changed: 62 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -7404,27 +7404,76 @@ namespace ts {
74047404
let checkIdentifierIsKeyword = isKeyword(token()) && !isIdentifier();
74057405
let checkIdentifierStart = scanner.getTokenPos();
74067406
let checkIdentifierEnd = scanner.getTextPos();
7407-
const identifierName = parseIdentifierName();
7407+
let isTypeOnly = false;
74087408
let propertyName: Identifier | undefined;
7409-
let name: Identifier;
7410-
if (token() === SyntaxKind.AsKeyword) {
7411-
propertyName = identifierName;
7412-
parseExpected(SyntaxKind.AsKeyword);
7413-
checkIdentifierIsKeyword = isKeyword(token()) && !isIdentifier();
7414-
checkIdentifierStart = scanner.getTokenPos();
7415-
checkIdentifierEnd = scanner.getTextPos();
7416-
name = parseIdentifierName();
7409+
let canParseAsKeyword = true;
7410+
let name = parseIdentifierName();
7411+
if (name.escapedText === "type") {
7412+
// If the first token of an import specifier is 'type', there are a lot of possibilities,
7413+
// especially if we see 'as' afterwards:
7414+
//
7415+
// import { type } from "mod"; - isTypeOnly: false, name: type
7416+
// import { type as } from "mod"; - isTypeOnly: true, name: as
7417+
// import { type as as } from "mod"; - isTypeOnly: false, name: as, propertyName: type
7418+
// import { type as as as } from "mod"; - isTypeOnly: true, name: as, propertyName: as
7419+
if (token() === SyntaxKind.AsKeyword) {
7420+
// { type as ...? }
7421+
const firstAs = parseIdentifierName();
7422+
if (token() === SyntaxKind.AsKeyword) {
7423+
// { type as as ...? }
7424+
const secondAs = parseIdentifierName();
7425+
if (tokenIsIdentifierOrKeyword(token())) {
7426+
// { type as as something }
7427+
isTypeOnly = true;
7428+
propertyName = firstAs;
7429+
name = parseNameWithKeywordCheck();
7430+
canParseAsKeyword = false;
7431+
}
7432+
else {
7433+
// { type as as }
7434+
propertyName = name;
7435+
name = secondAs;
7436+
canParseAsKeyword = false;
7437+
}
7438+
}
7439+
else if (tokenIsIdentifierOrKeyword(token())) {
7440+
// { type as something }
7441+
propertyName = name;
7442+
canParseAsKeyword = false;
7443+
name = parseNameWithKeywordCheck();
7444+
}
7445+
else {
7446+
// { type as }
7447+
isTypeOnly = true;
7448+
name = firstAs;
7449+
}
7450+
}
7451+
else if (tokenIsIdentifierOrKeyword(token())) {
7452+
// { type something ...? }
7453+
isTypeOnly = true;
7454+
name = parseNameWithKeywordCheck();
7455+
}
74177456
}
7418-
else {
7419-
name = identifierName;
7457+
7458+
if (canParseAsKeyword && token() === SyntaxKind.AsKeyword) {
7459+
propertyName = name;
7460+
parseExpected(SyntaxKind.AsKeyword);
7461+
name = parseNameWithKeywordCheck();
74207462
}
74217463
if (kind === SyntaxKind.ImportSpecifier && checkIdentifierIsKeyword) {
74227464
parseErrorAt(checkIdentifierStart, checkIdentifierEnd, Diagnostics.Identifier_expected);
74237465
}
74247466
const node = kind === SyntaxKind.ImportSpecifier
7425-
? factory.createImportSpecifier(propertyName, name)
7426-
: factory.createExportSpecifier(propertyName, name);
7467+
? factory.createImportSpecifier(isTypeOnly, propertyName, name)
7468+
: factory.createExportSpecifier(isTypeOnly, propertyName, name);
74277469
return finishNode(node, pos);
7470+
7471+
function parseNameWithKeywordCheck() {
7472+
checkIdentifierIsKeyword = isKeyword(token()) && !isIdentifier();
7473+
checkIdentifierStart = scanner.getTokenPos();
7474+
checkIdentifierEnd = scanner.getTextPos();
7475+
return parseIdentifierName();
7476+
}
74287477
}
74297478

74307479
function parseNamespaceExport(pos: number): NamespaceExport {

src/compiler/transformers/declarations.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1256,7 +1256,7 @@ namespace ts {
12561256
/*modifiers*/ undefined,
12571257
/*isTypeOnly*/ false,
12581258
factory.createNamedExports(map(exportMappings, ([gen, exp]) => {
1259-
return factory.createExportSpecifier(gen, exp);
1259+
return factory.createExportSpecifier(/*isTypeOnly*/ false, gen, exp);
12601260
}))
12611261
));
12621262
}

src/compiler/transformers/jsx.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -56,7 +56,7 @@ namespace ts {
5656
currentFileState.utilizedImplicitRuntimeImports.set(importSource, specifierSourceImports);
5757
}
5858
const generatedName = factory.createUniqueName(`_${name}`, GeneratedIdentifierFlags.Optimistic | GeneratedIdentifierFlags.FileLevel | GeneratedIdentifierFlags.AllowNameSubstitution);
59-
const specifier = factory.createImportSpecifier(factory.createIdentifier(name), generatedName);
59+
const specifier = factory.createImportSpecifier(/*isTypeOnly*/ false, factory.createIdentifier(name), generatedName);
6060
generatedName.generatedImportReference = specifier;
6161
specifierSourceImports.set(name, specifier);
6262
return generatedName;

src/compiler/transformers/module/esnextAnd2015.ts

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -104,7 +104,7 @@ namespace ts {
104104
/*isTypeOnly*/ false,
105105
/*name*/ undefined,
106106
factory.createNamedImports([
107-
factory.createImportSpecifier(factory.createIdentifier("createRequire"), createRequireName)
107+
factory.createImportSpecifier(/*isTypeOnly*/ false, factory.createIdentifier("createRequire"), createRequireName)
108108
])
109109
),
110110
factory.createStringLiteral("module")
@@ -177,7 +177,7 @@ namespace ts {
177177
/*decorators*/ undefined,
178178
/*modifiers*/ undefined,
179179
node.isTypeOnly,
180-
factory.createNamedExports([factory.createExportSpecifier(/*propertyName*/ undefined, idText(node.name))])
180+
factory.createNamedExports([factory.createExportSpecifier(/*isTypeOnly*/ false, /*propertyName*/ undefined, idText(node.name))])
181181
));
182182
}
183183
return statements;
@@ -220,7 +220,7 @@ namespace ts {
220220
/*decorators*/ undefined,
221221
/*modifiers*/ undefined,
222222
/*isTypeOnly*/ false,
223-
factory.createNamedExports([factory.createExportSpecifier(synthName, oldIdentifier)]),
223+
factory.createNamedExports([factory.createExportSpecifier(/*isTypeOnly*/ false, synthName, oldIdentifier)]),
224224
);
225225
setOriginalNode(exportDecl, node);
226226

0 commit comments

Comments
 (0)