@@ -163,7 +163,6 @@ import {
163
163
EmitResolver,
164
164
EmitTextWriter,
165
165
emptyArray,
166
- endsWith,
167
166
EntityName,
168
167
EntityNameExpression,
169
168
EntityNameOrEntityNameExpression,
@@ -265,6 +264,7 @@ import {
265
264
getContainingClassStaticBlock,
266
265
getContainingFunction,
267
266
getContainingFunctionOrClassStaticBlock,
267
+ getDeclarationFileExtension,
268
268
getDeclarationModifierFlagsFromSymbol,
269
269
getDeclarationOfKind,
270
270
getDeclarationsOfKind,
@@ -3702,11 +3702,15 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker {
3702
3702
return usageMode === ModuleKind.ESNext && targetMode === ModuleKind.CommonJS;
3703
3703
}
3704
3704
3705
- function isOnlyImportableAsDefault(usage: Expression) {
3705
+ function isOnlyImportableAsDefault(usage: Expression, resolvedModule?: Symbol ) {
3706
3706
// In Node.js, JSON modules don't get named exports
3707
3707
if (ModuleKind.Node16 <= moduleKind && moduleKind <= ModuleKind.NodeNext) {
3708
3708
const usageMode = getEmitSyntaxForModuleSpecifierExpression(usage);
3709
- return usageMode === ModuleKind.ESNext && endsWith((usage as StringLiteralLike).text, Extension.Json);
3709
+ if (usageMode === ModuleKind.ESNext) {
3710
+ resolvedModule ??= resolveExternalModuleName(usage, usage, /*ignoreErrors*/ true);
3711
+ const targetFile = resolvedModule && getSourceFileOfModule(resolvedModule);
3712
+ return targetFile && (isJsonSourceFile(targetFile) || getDeclarationFileExtension(targetFile.fileName) === ".d.json.ts");
3713
+ }
3710
3714
}
3711
3715
return false;
3712
3716
}
@@ -3776,7 +3780,7 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker {
3776
3780
if (!specifier) {
3777
3781
return exportDefaultSymbol;
3778
3782
}
3779
- const hasDefaultOnly = isOnlyImportableAsDefault(specifier);
3783
+ const hasDefaultOnly = isOnlyImportableAsDefault(specifier, moduleSymbol );
3780
3784
const hasSyntheticDefault = canHaveSyntheticDefault(file, moduleSymbol, dontResolveAlias, specifier);
3781
3785
if (!exportDefaultSymbol && !hasSyntheticDefault && !hasDefaultOnly) {
3782
3786
if (hasExportAssignmentSymbol(moduleSymbol) && !allowSyntheticDefaultImports) {
@@ -3961,15 +3965,19 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker {
3961
3965
let symbolFromModule = getExportOfModule(targetSymbol, nameText, specifier, dontResolveAlias);
3962
3966
if (symbolFromModule === undefined && nameText === InternalSymbolName.Default) {
3963
3967
const file = moduleSymbol.declarations?.find(isSourceFile);
3964
- if (isOnlyImportableAsDefault(moduleSpecifier) || canHaveSyntheticDefault(file, moduleSymbol, dontResolveAlias, moduleSpecifier)) {
3968
+ if (isOnlyImportableAsDefault(moduleSpecifier, moduleSymbol ) || canHaveSyntheticDefault(file, moduleSymbol, dontResolveAlias, moduleSpecifier)) {
3965
3969
symbolFromModule = resolveExternalModuleSymbol(moduleSymbol, dontResolveAlias) || resolveSymbol(moduleSymbol, dontResolveAlias);
3966
3970
}
3967
3971
}
3968
3972
3969
3973
const symbol = symbolFromModule && symbolFromVariable && symbolFromModule !== symbolFromVariable ?
3970
3974
combineValueAndTypeSymbols(symbolFromVariable, symbolFromModule) :
3971
3975
symbolFromModule || symbolFromVariable;
3972
- if (!symbol) {
3976
+
3977
+ if (isImportOrExportSpecifier(specifier) && isOnlyImportableAsDefault(moduleSpecifier, moduleSymbol) && nameText !== InternalSymbolName.Default) {
3978
+ error(name, Diagnostics.Named_imports_from_a_JSON_file_into_an_ECMAScript_module_are_not_allowed_when_module_is_set_to_0, ModuleKind[moduleKind]);
3979
+ }
3980
+ else if (!symbol) {
3973
3981
errorNoModuleMemberSymbol(moduleSymbol, targetSymbol, node, name);
3974
3982
}
3975
3983
return symbol;
@@ -47779,6 +47787,7 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker {
47779
47787
grammarErrorOnFirstToken(node, Diagnostics.An_import_declaration_cannot_have_modifiers);
47780
47788
}
47781
47789
if (checkExternalImportOrExportDeclaration(node)) {
47790
+ let resolvedModule;
47782
47791
const importClause = node.importClause;
47783
47792
if (importClause && !checkGrammarImportClause(importClause)) {
47784
47793
if (importClause.name) {
@@ -47793,12 +47802,16 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker {
47793
47802
}
47794
47803
}
47795
47804
else {
47796
- const moduleExisted = resolveExternalModuleName(node, node.moduleSpecifier);
47797
- if (moduleExisted ) {
47805
+ resolvedModule = resolveExternalModuleName(node, node.moduleSpecifier);
47806
+ if (resolvedModule ) {
47798
47807
forEach(importClause.namedBindings.elements, checkImportBinding);
47799
47808
}
47800
47809
}
47801
47810
}
47811
+
47812
+ if (isOnlyImportableAsDefault(node.moduleSpecifier, resolvedModule) && !hasTypeJsonImportAttribute(node)) {
47813
+ error(node.moduleSpecifier, Diagnostics.Importing_a_JSON_file_into_an_ECMAScript_module_requires_a_type_Colon_json_import_attribute_when_module_is_set_to_0, ModuleKind[moduleKind]);
47814
+ }
47802
47815
}
47803
47816
else if (noUncheckedSideEffectImports && !importClause) {
47804
47817
void resolveExternalModuleName(node, node.moduleSpecifier);
@@ -47807,6 +47820,10 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker {
47807
47820
checkImportAttributes(node);
47808
47821
}
47809
47822
47823
+ function hasTypeJsonImportAttribute(node: ImportDeclaration) {
47824
+ return !!node.attributes && node.attributes.elements.some(attr => getTextOfIdentifierOrLiteral(attr.name) === "type" && tryCast(attr.value, isStringLiteralLike)?.text === "json");
47825
+ }
47826
+
47810
47827
function checkImportEqualsDeclaration(node: ImportEqualsDeclaration) {
47811
47828
if (checkGrammarModuleElementContext(node, isInJSFile(node) ? Diagnostics.An_import_declaration_can_only_be_used_at_the_top_level_of_a_module : Diagnostics.An_import_declaration_can_only_be_used_at_the_top_level_of_a_namespace_or_module)) {
47812
47829
// If we hit an import declaration in an illegal context, just bail out to avoid cascading errors.
0 commit comments