Skip to content

Commit ec114b8

Browse files
Kingwlrbuckton
andauthoredSep 20, 2021
Import assertion (#40698)
* Add parsing * fix all api * check gramma of import call * Add more part of assertion * Add some case * Add baseline * use module insted of target * strip assertion in d.ts * Update new baseline * accept baseline * Revert error number changes * Update diagnostic message * Accept baseline * rename path * Fix cr issues * Accept baseline * Accept baseline * Error if assertion and typeonly import * Accept baseline * Make lint happy * Add some comment * Fix cr issues * Fix more issue * Incorporate PR feedback, fix module resolution for import() * Add contextual type and completions for ImportCall options argument Co-authored-by: Ron Buckton <[email protected]>
1 parent 5ef0439 commit ec114b8

File tree

86 files changed

+2954
-605
lines changed

Some content is hidden

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

86 files changed

+2954
-605
lines changed
 

‎src/compiler/checker.ts

+62-17
Original file line numberDiff line numberDiff line change
@@ -933,6 +933,7 @@ namespace ts {
933933
let deferredGlobalTemplateStringsArrayType: ObjectType | undefined;
934934
let deferredGlobalImportMetaType: ObjectType;
935935
let deferredGlobalImportMetaExpressionType: ObjectType;
936+
let deferredGlobalImportCallOptionsType: ObjectType | undefined;
936937
let deferredGlobalExtractSymbol: Symbol | undefined;
937938
let deferredGlobalOmitSymbol: Symbol | undefined;
938939
let deferredGlobalAwaitedSymbol: Symbol | undefined;
@@ -6568,7 +6569,7 @@ namespace ts {
65686569

65696570
function inlineExportModifiers(statements: Statement[]) {
65706571
// Pass 3: Move all `export {}`'s to `export` modifiers where possible
6571-
const index = findIndex(statements, d => isExportDeclaration(d) && !d.moduleSpecifier && !!d.exportClause && isNamedExports(d.exportClause));
6572+
const index = findIndex(statements, d => isExportDeclaration(d) && !d.moduleSpecifier && !d.assertClause && !!d.exportClause && isNamedExports(d.exportClause));
65726573
if (index >= 0) {
65736574
const exportDecl = statements[index] as ExportDeclaration & { readonly exportClause: NamedExports };
65746575
const replacements = mapDefined(exportDecl.exportClause.elements, e => {
@@ -6600,7 +6601,8 @@ namespace ts {
66006601
exportDecl.exportClause,
66016602
replacements
66026603
),
6603-
exportDecl.moduleSpecifier
6604+
exportDecl.moduleSpecifier,
6605+
exportDecl.assertClause
66046606
);
66056607
}
66066608
}
@@ -7260,7 +7262,8 @@ namespace ts {
72607262
propertyName && isIdentifier(propertyName) ? factory.createIdentifier(idText(propertyName)) : undefined,
72617263
factory.createIdentifier(localName)
72627264
)])),
7263-
factory.createStringLiteral(specifier)
7265+
factory.createStringLiteral(specifier),
7266+
/*importClause*/ undefined
72647267
), ModifierFlags.None);
72657268
break;
72667269
}
@@ -7336,15 +7339,17 @@ namespace ts {
73367339
// We use `target.parent || target` below as `target.parent` is unset when the target is a module which has been export assigned
73377340
// And then made into a default by the `esModuleInterop` or `allowSyntheticDefaultImports` flag
73387341
// In such cases, the `target` refers to the module itself already
7339-
factory.createStringLiteral(getSpecifierForModuleSymbol(target.parent || target, context))
7342+
factory.createStringLiteral(getSpecifierForModuleSymbol(target.parent || target, context)),
7343+
/*assertClause*/ undefined
73407344
), ModifierFlags.None);
73417345
break;
73427346
case SyntaxKind.NamespaceImport:
73437347
addResult(factory.createImportDeclaration(
73447348
/*decorators*/ undefined,
73457349
/*modifiers*/ undefined,
73467350
factory.createImportClause(/*isTypeOnly*/ false, /*importClause*/ undefined, factory.createNamespaceImport(factory.createIdentifier(localName))),
7347-
factory.createStringLiteral(getSpecifierForModuleSymbol(target, context))
7351+
factory.createStringLiteral(getSpecifierForModuleSymbol(target, context)),
7352+
/*assertClause*/ undefined
73487353
), ModifierFlags.None);
73497354
break;
73507355
case SyntaxKind.NamespaceExport:
@@ -7369,7 +7374,8 @@ namespace ts {
73697374
factory.createIdentifier(localName)
73707375
)
73717376
])),
7372-
factory.createStringLiteral(getSpecifierForModuleSymbol(target.parent || target, context))
7377+
factory.createStringLiteral(getSpecifierForModuleSymbol(target.parent || target, context)),
7378+
/*assertClause*/ undefined
73737379
), ModifierFlags.None);
73747380
break;
73757381
case SyntaxKind.ExportSpecifier:
@@ -13455,6 +13461,10 @@ namespace ts {
1345513461
return deferredGlobalImportMetaExpressionType;
1345613462
}
1345713463

13464+
function getGlobalImportCallOptionsType(reportErrors: boolean) {
13465+
return (deferredGlobalImportCallOptionsType ||= getGlobalType("ImportCallOptions" as __String, /*arity*/ 0, reportErrors)) || emptyObjectType;
13466+
}
13467+
1345813468
function getGlobalESSymbolConstructorSymbol(reportErrors: boolean): Symbol | undefined {
1345913469
return deferredGlobalESSymbolConstructorSymbol ||= getGlobalValueSymbol("Symbol" as __String, reportErrors);
1346013470
}
@@ -25547,6 +25557,12 @@ namespace ts {
2554725557
}
2554825558

2554925559
function getContextualTypeForArgumentAtIndex(callTarget: CallLikeExpression, argIndex: number): Type {
25560+
if (isImportCall(callTarget)) {
25561+
return argIndex === 0 ? stringType :
25562+
argIndex === 1 ? getGlobalImportCallOptionsType(/*reportErrors*/ false) :
25563+
anyType;
25564+
}
25565+
2555025566
// If we're already in the process of resolving the given signature, don't resolve again as
2555125567
// that could cause infinite recursion. Instead, return anySignature.
2555225568
const signature = getNodeLinks(callTarget).resolvedSignature === resolvingSignature ? resolvingSignature : getResolvedSignature(callTarget);
@@ -26007,10 +26023,6 @@ namespace ts {
2600726023
case SyntaxKind.AwaitExpression:
2600826024
return getContextualTypeForAwaitOperand(parent as AwaitExpression, contextFlags);
2600926025
case SyntaxKind.CallExpression:
26010-
if ((parent as CallExpression).expression.kind === SyntaxKind.ImportKeyword) {
26011-
return stringType;
26012-
}
26013-
/* falls through */
2601426026
case SyntaxKind.NewExpression:
2601526027
return getContextualTypeForArgument(parent as CallExpression | NewExpression, node);
2601626028
case SyntaxKind.TypeAssertionExpression:
@@ -30606,17 +30618,26 @@ namespace ts {
3060630618
if (node.arguments.length === 0) {
3060730619
return createPromiseReturnType(node, anyType);
3060830620
}
30621+
3060930622
const specifier = node.arguments[0];
3061030623
const specifierType = checkExpressionCached(specifier);
30624+
const optionsType = node.arguments.length > 1 ? checkExpressionCached(node.arguments[1]) : undefined;
3061130625
// Even though multiple arguments is grammatically incorrect, type-check extra arguments for completion
30612-
for (let i = 1; i < node.arguments.length; ++i) {
30626+
for (let i = 2; i < node.arguments.length; ++i) {
3061330627
checkExpressionCached(node.arguments[i]);
3061430628
}
3061530629

3061630630
if (specifierType.flags & TypeFlags.Undefined || specifierType.flags & TypeFlags.Null || !isTypeAssignableTo(specifierType, stringType)) {
3061730631
error(specifier, Diagnostics.Dynamic_import_s_specifier_must_be_of_type_string_but_here_has_type_0, typeToString(specifierType));
3061830632
}
3061930633

30634+
if (optionsType) {
30635+
const importCallOptionsType = getGlobalImportCallOptionsType(/*reportErrors*/ true);
30636+
if (importCallOptionsType !== emptyObjectType) {
30637+
checkTypeAssignableTo(optionsType, getNullableType(importCallOptionsType, TypeFlags.Undefined), node.arguments[1]);
30638+
}
30639+
}
30640+
3062030641
// resolveExternalModuleName will return undefined if the moduleReferenceExpression is not a string literal
3062130642
const moduleSymbol = resolveExternalModuleName(node, specifier);
3062230643
if (moduleSymbol) {
@@ -39039,6 +39060,18 @@ namespace ts {
3903939060
}
3904039061
}
3904139062

39063+
function checkAssertClause(declaration: ImportDeclaration | ExportDeclaration) {
39064+
if (declaration.assertClause) {
39065+
if (moduleKind !== ModuleKind.ESNext) {
39066+
return grammarErrorOnNode(declaration.assertClause, Diagnostics.Import_assertions_are_only_supported_when_the_module_option_is_set_to_esnext);
39067+
}
39068+
39069+
if (isImportDeclaration(declaration) ? declaration.importClause?.isTypeOnly : declaration.isTypeOnly) {
39070+
return grammarErrorOnNode(declaration.assertClause, Diagnostics.Import_assertions_cannot_be_used_with_type_only_imports_or_exports);
39071+
}
39072+
}
39073+
}
39074+
3904239075
function checkImportDeclaration(node: ImportDeclaration) {
3904339076
if (checkGrammarModuleElementContext(node, Diagnostics.An_import_declaration_can_only_be_used_in_a_namespace_or_module)) {
3904439077
// If we hit an import declaration in an illegal context, just bail out to avoid cascading errors.
@@ -39070,7 +39103,7 @@ namespace ts {
3907039103
}
3907139104
}
3907239105
}
39073-
39106+
checkAssertClause(node);
3907439107
}
3907539108

3907639109
function checkImportEqualsDeclaration(node: ImportEqualsDeclaration) {
@@ -39165,6 +39198,7 @@ namespace ts {
3916539198
}
3916639199
}
3916739200
}
39201+
checkAssertClause(node);
3916839202
}
3916939203

3917039204
function checkGrammarExportDeclaration(node: ExportDeclaration): boolean {
@@ -43201,14 +43235,25 @@ namespace ts {
4320143235
}
4320243236

4320343237
const nodeArguments = node.arguments;
43204-
if (nodeArguments.length !== 1) {
43205-
return grammarErrorOnNode(node, Diagnostics.Dynamic_import_must_have_one_specifier_as_an_argument);
43238+
if (moduleKind !== ModuleKind.ESNext) {
43239+
// We are allowed trailing comma after proposal-import-assertions.
43240+
checkGrammarForDisallowedTrailingComma(nodeArguments);
43241+
43242+
if (nodeArguments.length > 1) {
43243+
const assertionArgument = nodeArguments[1];
43244+
return grammarErrorOnNode(assertionArgument, Diagnostics.Dynamic_imports_only_support_a_second_argument_when_the_module_option_is_set_to_esnext);
43245+
}
4320643246
}
43207-
checkGrammarForDisallowedTrailingComma(nodeArguments);
43247+
43248+
if (nodeArguments.length === 0 || nodeArguments.length > 2) {
43249+
return grammarErrorOnNode(node, Diagnostics.Dynamic_imports_can_only_accept_a_module_specifier_and_an_optional_assertion_as_arguments);
43250+
}
43251+
4320843252
// see: parseArgumentOrArrayLiteralElement...we use this function which parse arguments of callExpression to parse specifier for dynamic import.
4320943253
// parseArgumentOrArrayLiteralElement allows spread element to be in an argument list which is not allowed as specifier in dynamic import.
43210-
if (isSpreadElement(nodeArguments[0])) {
43211-
return grammarErrorOnNode(nodeArguments[0], Diagnostics.Specifier_of_dynamic_import_cannot_be_spread_element);
43254+
const spreadElement = find(nodeArguments, isSpreadElement);
43255+
if (spreadElement) {
43256+
return grammarErrorOnNode(spreadElement, Diagnostics.Argument_of_dynamic_import_cannot_be_spread_element);
4321243257
}
4321343258
return false;
4321443259
}

‎src/compiler/diagnosticMessages.json

+14-2
Original file line numberDiff line numberDiff line change
@@ -924,11 +924,11 @@
924924
"category": "Error",
925925
"code": 1323
926926
},
927-
"Dynamic import must have one specifier as an argument.": {
927+
"Dynamic imports only support a second argument when the '--module' option is set to 'esnext'.": {
928928
"category": "Error",
929929
"code": 1324
930930
},
931-
"Specifier of dynamic import cannot be spread element.": {
931+
"Argument of dynamic import cannot be spread element.": {
932932
"category": "Error",
933933
"code": 1325
934934
},
@@ -1388,6 +1388,10 @@
13881388
"category": "Message",
13891389
"code": 1449
13901390
},
1391+
"Dynamic imports can only accept a module specifier and an optional assertion as arguments": {
1392+
"category": "Message",
1393+
"code": 1450
1394+
},
13911395

13921396
"The types of '{0}' are incompatible between these types.": {
13931397
"category": "Error",
@@ -3304,6 +3308,14 @@
33043308
"category": "Error",
33053309
"code": 2820
33063310
},
3311+
"Import assertions are only supported when the '--module' option is set to 'esnext'.": {
3312+
"category": "Error",
3313+
"code": 2821
3314+
},
3315+
"Import assertions cannot be used with type-only imports or exports.": {
3316+
"category": "Error",
3317+
"code": 2822
3318+
},
33073319

33083320
"Import declaration '{0}' is using private name '{1}'.": {
33093321
"category": "Error",

0 commit comments

Comments
 (0)
Please sign in to comment.