diff --git a/src/compiler/checker.ts b/src/compiler/checker.ts index 397a424ee7b27..cd1409b13f37a 100644 --- a/src/compiler/checker.ts +++ b/src/compiler/checker.ts @@ -48100,7 +48100,8 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { } } - if (isOnlyImportableAsDefault(node.moduleSpecifier, resolvedModule) && !hasTypeJsonImportAttribute(node)) { + if (moduleKind === ModuleKind.NodeNext && isOnlyImportableAsDefault(node.moduleSpecifier, resolvedModule) && !hasTypeJsonImportAttribute(node)) { + // Import attributes/assertions are not allowed in --module node16, so don't suggest adding one 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]); } } diff --git a/tests/baselines/reference/nodeModulesJson(module=node16).errors.txt b/tests/baselines/reference/nodeModulesJson(module=node16).errors.txt new file mode 100644 index 0000000000000..989bb7dcf9a58 --- /dev/null +++ b/tests/baselines/reference/nodeModulesJson(module=node16).errors.txt @@ -0,0 +1,81 @@ +/loosey.cts(1,36): error TS2823: Import attributes are only supported when the '--module' option is set to 'esnext', 'nodenext', or 'preserve'. +/loosey.cts(6,9): error TS2339: Property 'default' does not exist on type '{ version: number; }'. +/main.mts(5,36): error TS2823: Import attributes are only supported when the '--module' option is set to 'esnext', 'nodenext', or 'preserve'. +/main.mts(6,52): error TS2823: Import attributes are only supported when the '--module' option is set to 'esnext', 'nodenext', or 'preserve'. +/main.mts(8,10): error TS1544: Named imports from a JSON file into an ECMAScript module are not allowed when 'module' is set to 'Node16'. +/main.mts(8,41): error TS2823: Import attributes are only supported when the '--module' option is set to 'esnext', 'nodenext', or 'preserve'. +/main.mts(9,42): error TS2823: Import attributes are only supported when the '--module' option is set to 'esnext', 'nodenext', or 'preserve'. +/main.mts(10,9): error TS2339: Property 'version' does not exist on type '{ default: { version: number; }; }'. + + +==== /node_modules/not.json/package.json (0 errors) ==== + { + "name": "not.json", + "version": "1.0.0", + "type": "module", + "exports": "./index.js" + } + +==== /node_modules/not.json/index.d.ts (0 errors) ==== + export function oops(json: string): any; + +==== /node_modules/actually-json/package.json (0 errors) ==== + { + "name": "actually-json", + "version": "1.0.0", + "type": "module", + "exports": { + ".": "./index.json", + "./typed": "./typed.d.json.ts" + } + } + +==== /node_modules/actually-json/index.json (0 errors) ==== + {} + +==== /node_modules/actually-json/typed.d.json.ts (0 errors) ==== + declare const _default: {}; + export default _default; + +==== /config.json (0 errors) ==== + { + "version": 1 + } + +==== /main.mts (6 errors) ==== + import { oops } from "not.json"; // Ok + import moreOops from "actually-json"; // Error in nodenext + import typed from "actually-json/typed"; // Error in nodenext + + import config from "./config.json" with { type: "json" }; // Ok + ~~~~~~~~~~~~~~~~~~~~~ +!!! error TS2823: Import attributes are only supported when the '--module' option is set to 'esnext', 'nodenext', or 'preserve'. + import { default as config1 } from "./config.json" with { type: "json" }; // Ok + ~~~~~~~~~~~~~~~~~~~~~ +!!! error TS2823: Import attributes are only supported when the '--module' option is set to 'esnext', 'nodenext', or 'preserve'. + import config2 from "./config.json"; // Error in nodenext, no attribute + import { version } from "./config.json" with { type: "json" }; // Error, named import + ~~~~~~~ +!!! error TS1544: Named imports from a JSON file into an ECMAScript module are not allowed when 'module' is set to 'Node16'. + ~~~~~~~~~~~~~~~~~~~~~ +!!! error TS2823: Import attributes are only supported when the '--module' option is set to 'esnext', 'nodenext', or 'preserve'. + import * as config3 from "./config.json" with { type: "json" }; + ~~~~~~~~~~~~~~~~~~~~~ +!!! error TS2823: Import attributes are only supported when the '--module' option is set to 'esnext', 'nodenext', or 'preserve'. + config3.version; // Error + ~~~~~~~ +!!! error TS2339: Property 'version' does not exist on type '{ default: { version: number; }; }'. + config3.default; // Ok + +==== /loosey.cts (2 errors) ==== + import config from "./config.json" with { type: "json" }; // Error + ~~~~~~~~~~~~~~~~~~~~~ +!!! error TS2823: Import attributes are only supported when the '--module' option is set to 'esnext', 'nodenext', or 'preserve'. + import config2 from "./config.json"; // Ok + import { version } from "./config.json"; // Ok + import * as config3 from "./config.json"; + config3.version; // Ok + config3.default; // Error + ~~~~~~~ +!!! error TS2339: Property 'default' does not exist on type '{ version: number; }'. + \ No newline at end of file diff --git a/tests/baselines/reference/nodeModulesJson.symbols b/tests/baselines/reference/nodeModulesJson(module=node16).symbols similarity index 89% rename from tests/baselines/reference/nodeModulesJson.symbols rename to tests/baselines/reference/nodeModulesJson(module=node16).symbols index 5f26b469ae9f3..42c68c640a2e7 100644 --- a/tests/baselines/reference/nodeModulesJson.symbols +++ b/tests/baselines/reference/nodeModulesJson(module=node16).symbols @@ -26,10 +26,10 @@ export default _default; import { oops } from "not.json"; // Ok >oops : Symbol(oops, Decl(main.mts, 0, 8)) -import moreOops from "actually-json"; // Error +import moreOops from "actually-json"; // Error in nodenext >moreOops : Symbol(moreOops, Decl(main.mts, 1, 6)) -import typed from "actually-json/typed"; // Error +import typed from "actually-json/typed"; // Error in nodenext >typed : Symbol(typed, Decl(main.mts, 2, 6)) import config from "./config.json" with { type: "json" }; // Ok @@ -39,7 +39,7 @@ import { default as config1 } from "./config.json" with { type: "json" }; // Ok >default : Symbol(config, Decl(config.json, 0, 0)) >config1 : Symbol(config1, Decl(main.mts, 5, 8)) -import config2 from "./config.json"; // Error, no attribute +import config2 from "./config.json"; // Error in nodenext, no attribute >config2 : Symbol(config2, Decl(main.mts, 6, 6)) import { version } from "./config.json" with { type: "json" }; // Error, named import diff --git a/tests/baselines/reference/nodeModulesJson.types b/tests/baselines/reference/nodeModulesJson(module=node16).types similarity index 89% rename from tests/baselines/reference/nodeModulesJson.types rename to tests/baselines/reference/nodeModulesJson(module=node16).types index 2c992f8548a03..2c41926af320a 100644 --- a/tests/baselines/reference/nodeModulesJson.types +++ b/tests/baselines/reference/nodeModulesJson(module=node16).types @@ -38,11 +38,11 @@ import { oops } from "not.json"; // Ok >oops : (json: string) => any > : ^ ^^ ^^^^^ -import moreOops from "actually-json"; // Error +import moreOops from "actually-json"; // Error in nodenext >moreOops : {} > : ^^ -import typed from "actually-json/typed"; // Error +import typed from "actually-json/typed"; // Error in nodenext >typed : typeof typed > : ^^^^^^^^^^^^ @@ -60,7 +60,7 @@ import { default as config1 } from "./config.json" with { type: "json" }; // Ok >type : any > : ^^^ -import config2 from "./config.json"; // Error, no attribute +import config2 from "./config.json"; // Error in nodenext, no attribute >config2 : { version: number; } > : ^^^^^^^^^^^^^^^^^^^^ diff --git a/tests/baselines/reference/nodeModulesJson.errors.txt b/tests/baselines/reference/nodeModulesJson(module=nodenext).errors.txt similarity index 92% rename from tests/baselines/reference/nodeModulesJson.errors.txt rename to tests/baselines/reference/nodeModulesJson(module=nodenext).errors.txt index 8e9a050cffbce..bf355357b0905 100644 --- a/tests/baselines/reference/nodeModulesJson.errors.txt +++ b/tests/baselines/reference/nodeModulesJson(module=nodenext).errors.txt @@ -43,16 +43,16 @@ ==== /main.mts (5 errors) ==== import { oops } from "not.json"; // Ok - import moreOops from "actually-json"; // Error + import moreOops from "actually-json"; // Error in nodenext ~~~~~~~~~~~~~~~ !!! error TS1543: Importing a JSON file into an ECMAScript module requires a 'type: "json"' import attribute when 'module' is set to 'NodeNext'. - import typed from "actually-json/typed"; // Error + import typed from "actually-json/typed"; // Error in nodenext ~~~~~~~~~~~~~~~~~~~~~ !!! error TS1543: Importing a JSON file into an ECMAScript module requires a 'type: "json"' import attribute when 'module' is set to 'NodeNext'. import config from "./config.json" with { type: "json" }; // Ok import { default as config1 } from "./config.json" with { type: "json" }; // Ok - import config2 from "./config.json"; // Error, no attribute + import config2 from "./config.json"; // Error in nodenext, no attribute ~~~~~~~~~~~~~~~ !!! error TS1543: Importing a JSON file into an ECMAScript module requires a 'type: "json"' import attribute when 'module' is set to 'NodeNext'. import { version } from "./config.json" with { type: "json" }; // Error, named import diff --git a/tests/baselines/reference/nodeModulesJson(module=nodenext).symbols b/tests/baselines/reference/nodeModulesJson(module=nodenext).symbols new file mode 100644 index 0000000000000..42c68c640a2e7 --- /dev/null +++ b/tests/baselines/reference/nodeModulesJson(module=nodenext).symbols @@ -0,0 +1,79 @@ +//// [tests/cases/conformance/node/nodeModulesJson.ts] //// + +=== /node_modules/not.json/index.d.ts === +export function oops(json: string): any; +>oops : Symbol(oops, Decl(index.d.ts, 0, 0)) +>json : Symbol(json, Decl(index.d.ts, 0, 21)) + +=== /node_modules/actually-json/index.json === + +{} + +=== /node_modules/actually-json/typed.d.json.ts === +declare const _default: {}; +>_default : Symbol(_default, Decl(typed.d.json.ts, 0, 13)) + +export default _default; +>_default : Symbol(_default, Decl(typed.d.json.ts, 0, 13)) + +=== /config.json === +{ + "version": 1 +>"version" : Symbol("version", Decl(config.json, 0, 1)) +} + +=== /main.mts === +import { oops } from "not.json"; // Ok +>oops : Symbol(oops, Decl(main.mts, 0, 8)) + +import moreOops from "actually-json"; // Error in nodenext +>moreOops : Symbol(moreOops, Decl(main.mts, 1, 6)) + +import typed from "actually-json/typed"; // Error in nodenext +>typed : Symbol(typed, Decl(main.mts, 2, 6)) + +import config from "./config.json" with { type: "json" }; // Ok +>config : Symbol(config, Decl(main.mts, 4, 6)) + +import { default as config1 } from "./config.json" with { type: "json" }; // Ok +>default : Symbol(config, Decl(config.json, 0, 0)) +>config1 : Symbol(config1, Decl(main.mts, 5, 8)) + +import config2 from "./config.json"; // Error in nodenext, no attribute +>config2 : Symbol(config2, Decl(main.mts, 6, 6)) + +import { version } from "./config.json" with { type: "json" }; // Error, named import +>version : Symbol(version, Decl(main.mts, 7, 8)) + +import * as config3 from "./config.json" with { type: "json" }; +>config3 : Symbol(config3, Decl(main.mts, 8, 6)) + +config3.version; // Error +>config3 : Symbol(config3, Decl(main.mts, 8, 6)) + +config3.default; // Ok +>config3.default : Symbol("/config") +>config3 : Symbol(config3, Decl(main.mts, 8, 6)) +>default : Symbol("/config") + +=== /loosey.cts === +import config from "./config.json" with { type: "json" }; // Error +>config : Symbol(config, Decl(loosey.cts, 0, 6)) + +import config2 from "./config.json"; // Ok +>config2 : Symbol(config2, Decl(loosey.cts, 1, 6)) + +import { version } from "./config.json"; // Ok +>version : Symbol(version, Decl(loosey.cts, 2, 8)) + +import * as config3 from "./config.json"; +>config3 : Symbol(config3, Decl(loosey.cts, 3, 6)) + +config3.version; // Ok +>config3.version : Symbol(version, Decl(config.json, 0, 1)) +>config3 : Symbol(config3, Decl(loosey.cts, 3, 6)) +>version : Symbol(version, Decl(config.json, 0, 1)) + +config3.default; // Error +>config3 : Symbol(config3, Decl(loosey.cts, 3, 6)) + diff --git a/tests/baselines/reference/nodeModulesJson(module=nodenext).types b/tests/baselines/reference/nodeModulesJson(module=nodenext).types new file mode 100644 index 0000000000000..2c41926af320a --- /dev/null +++ b/tests/baselines/reference/nodeModulesJson(module=nodenext).types @@ -0,0 +1,129 @@ +//// [tests/cases/conformance/node/nodeModulesJson.ts] //// + +=== /node_modules/not.json/index.d.ts === +export function oops(json: string): any; +>oops : (json: string) => any +> : ^ ^^ ^^^^^ +>json : string +> : ^^^^^^ + +=== /node_modules/actually-json/index.json === +{} +>{} : {} +> : ^^ + +=== /node_modules/actually-json/typed.d.json.ts === +declare const _default: {}; +>_default : {} +> : ^^ + +export default _default; +>_default : {} +> : ^^ + +=== /config.json === +{ +>{ "version": 1} : { version: number; } +> : ^^^^^^^^^^^^^^^^^^^^ + + "version": 1 +>"version" : number +> : ^^^^^^ +>1 : 1 +> : ^ +} + +=== /main.mts === +import { oops } from "not.json"; // Ok +>oops : (json: string) => any +> : ^ ^^ ^^^^^ + +import moreOops from "actually-json"; // Error in nodenext +>moreOops : {} +> : ^^ + +import typed from "actually-json/typed"; // Error in nodenext +>typed : typeof typed +> : ^^^^^^^^^^^^ + +import config from "./config.json" with { type: "json" }; // Ok +>config : { version: number; } +> : ^^^^^^^^^^^^^^^^^^^^ +>type : any +> : ^^^ + +import { default as config1 } from "./config.json" with { type: "json" }; // Ok +>default : { version: number; } +> : ^^^^^^^^^^^^^^^^^^^^ +>config1 : { version: number; } +> : ^^^^^^^^^^^^^^^^^^^^ +>type : any +> : ^^^ + +import config2 from "./config.json"; // Error in nodenext, no attribute +>config2 : { version: number; } +> : ^^^^^^^^^^^^^^^^^^^^ + +import { version } from "./config.json" with { type: "json" }; // Error, named import +>version : number +> : ^^^^^^ +>type : any +> : ^^^ + +import * as config3 from "./config.json" with { type: "json" }; +>config3 : { default: { version: number; }; } +> : ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +>type : any +> : ^^^ + +config3.version; // Error +>config3.version : any +> : ^^^ +>config3 : { default: { version: number; }; } +> : ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +>version : any +> : ^^^ + +config3.default; // Ok +>config3.default : { version: number; } +> : ^^^^^^^^^^^^^^^^^^^^ +>config3 : { default: { version: number; }; } +> : ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +>default : { version: number; } +> : ^^^^^^^^^^^^^^^^^^^^ + +=== /loosey.cts === +import config from "./config.json" with { type: "json" }; // Error +>config : { version: number; } +> : ^^^^^^^^^^^^^^^^^^^^ +>type : any +> : ^^^ + +import config2 from "./config.json"; // Ok +>config2 : { version: number; } +> : ^^^^^^^^^^^^^^^^^^^^ + +import { version } from "./config.json"; // Ok +>version : number +> : ^^^^^^ + +import * as config3 from "./config.json"; +>config3 : { version: number; } +> : ^^^^^^^^^^^^^^^^^^^^ + +config3.version; // Ok +>config3.version : number +> : ^^^^^^ +>config3 : { version: number; } +> : ^^^^^^^^^^^^^^^^^^^^ +>version : number +> : ^^^^^^ + +config3.default; // Error +>config3.default : any +> : ^^^ +>config3 : { version: number; } +> : ^^^^^^^^^^^^^^^^^^^^ +>default : any +> : ^^^ + diff --git a/tests/cases/conformance/node/nodeModulesJson.ts b/tests/cases/conformance/node/nodeModulesJson.ts index c983d561cdfd9..e231ec9b0aa1d 100644 --- a/tests/cases/conformance/node/nodeModulesJson.ts +++ b/tests/cases/conformance/node/nodeModulesJson.ts @@ -1,4 +1,4 @@ -// @module: nodenext +// @module: node16,nodenext // @resolveJsonModule: true // @noEmit: true @@ -38,12 +38,12 @@ export default _default; // @Filename: /main.mts import { oops } from "not.json"; // Ok -import moreOops from "actually-json"; // Error -import typed from "actually-json/typed"; // Error +import moreOops from "actually-json"; // Error in nodenext +import typed from "actually-json/typed"; // Error in nodenext import config from "./config.json" with { type: "json" }; // Ok import { default as config1 } from "./config.json" with { type: "json" }; // Ok -import config2 from "./config.json"; // Error, no attribute +import config2 from "./config.json"; // Error in nodenext, no attribute import { version } from "./config.json" with { type: "json" }; // Error, named import import * as config3 from "./config.json" with { type: "json" }; config3.version; // Error