@@ -163,7 +163,6 @@ import {
163163 EmitResolver,
164164 EmitTextWriter,
165165 emptyArray,
166- endsWith,
167166 EntityName,
168167 EntityNameExpression,
169168 EntityNameOrEntityNameExpression,
@@ -265,6 +264,7 @@ import {
265264 getContainingClassStaticBlock,
266265 getContainingFunction,
267266 getContainingFunctionOrClassStaticBlock,
267+ getDeclarationFileExtension,
268268 getDeclarationModifierFlagsFromSymbol,
269269 getDeclarationOfKind,
270270 getDeclarationsOfKind,
@@ -3702,11 +3702,15 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker {
37023702 return usageMode === ModuleKind.ESNext && targetMode === ModuleKind.CommonJS;
37033703 }
37043704
3705- function isOnlyImportableAsDefault(usage: Expression) {
3705+ function isOnlyImportableAsDefault(usage: Expression, resolvedModule?: Symbol ) {
37063706 // In Node.js, JSON modules don't get named exports
37073707 if (ModuleKind.Node16 <= moduleKind && moduleKind <= ModuleKind.NodeNext) {
37083708 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+ }
37103714 }
37113715 return false;
37123716 }
@@ -3776,7 +3780,7 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker {
37763780 if (!specifier) {
37773781 return exportDefaultSymbol;
37783782 }
3779- const hasDefaultOnly = isOnlyImportableAsDefault(specifier);
3783+ const hasDefaultOnly = isOnlyImportableAsDefault(specifier, moduleSymbol );
37803784 const hasSyntheticDefault = canHaveSyntheticDefault(file, moduleSymbol, dontResolveAlias, specifier);
37813785 if (!exportDefaultSymbol && !hasSyntheticDefault && !hasDefaultOnly) {
37823786 if (hasExportAssignmentSymbol(moduleSymbol) && !allowSyntheticDefaultImports) {
@@ -3961,15 +3965,19 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker {
39613965 let symbolFromModule = getExportOfModule(targetSymbol, nameText, specifier, dontResolveAlias);
39623966 if (symbolFromModule === undefined && nameText === InternalSymbolName.Default) {
39633967 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)) {
39653969 symbolFromModule = resolveExternalModuleSymbol(moduleSymbol, dontResolveAlias) || resolveSymbol(moduleSymbol, dontResolveAlias);
39663970 }
39673971 }
39683972
39693973 const symbol = symbolFromModule && symbolFromVariable && symbolFromModule !== symbolFromVariable ?
39703974 combineValueAndTypeSymbols(symbolFromVariable, symbolFromModule) :
39713975 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) {
39733981 errorNoModuleMemberSymbol(moduleSymbol, targetSymbol, node, name);
39743982 }
39753983 return symbol;
@@ -47779,6 +47787,7 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker {
4777947787 grammarErrorOnFirstToken(node, Diagnostics.An_import_declaration_cannot_have_modifiers);
4778047788 }
4778147789 if (checkExternalImportOrExportDeclaration(node)) {
47790+ let resolvedModule;
4778247791 const importClause = node.importClause;
4778347792 if (importClause && !checkGrammarImportClause(importClause)) {
4778447793 if (importClause.name) {
@@ -47793,12 +47802,16 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker {
4779347802 }
4779447803 }
4779547804 else {
47796- const moduleExisted = resolveExternalModuleName(node, node.moduleSpecifier);
47797- if (moduleExisted ) {
47805+ resolvedModule = resolveExternalModuleName(node, node.moduleSpecifier);
47806+ if (resolvedModule ) {
4779847807 forEach(importClause.namedBindings.elements, checkImportBinding);
4779947808 }
4780047809 }
4780147810 }
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+ }
4780247815 }
4780347816 else if (noUncheckedSideEffectImports && !importClause) {
4780447817 void resolveExternalModuleName(node, node.moduleSpecifier);
@@ -47807,6 +47820,10 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker {
4780747820 checkImportAttributes(node);
4780847821 }
4780947822
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+
4781047827 function checkImportEqualsDeclaration(node: ImportEqualsDeclaration) {
4781147828 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)) {
4781247829 // If we hit an import declaration in an illegal context, just bail out to avoid cascading errors.
0 commit comments