diff --git a/src/compiler/commandLineParser.ts b/src/compiler/commandLineParser.ts index 4a699c8bc34e6..85043a9fdf359 100644 --- a/src/compiler/commandLineParser.ts +++ b/src/compiler/commandLineParser.ts @@ -1089,7 +1089,7 @@ const commandOptionsWithoutBuild: CommandLineOption[] = [ { name: "allowImportingTsExtensions", type: "boolean", - affectsModuleResolution: true, + affectsSemanticDiagnostics: true, category: Diagnostics.Modules, description: Diagnostics.Allow_imports_to_include_TypeScript_file_extensions_Requires_moduleResolution_bundler_and_either_noEmit_or_emitDeclarationOnly_to_be_set, defaultValueDescription: false, diff --git a/src/compiler/diagnosticMessages.json b/src/compiler/diagnosticMessages.json index 377bc39a74d82..96ea8324d8e34 100644 --- a/src/compiler/diagnosticMessages.json +++ b/src/compiler/diagnosticMessages.json @@ -4233,7 +4233,7 @@ "category": "Error", "code": 5095 }, - "Option 'allowImportingTsExtensions' can only be used when 'moduleResolution' is set to 'bundler' and either 'noEmit' or 'emitDeclarationOnly' is set.": { + "Option 'allowImportingTsExtensions' can only be used when either 'noEmit' or 'emitDeclarationOnly' is set.": { "category": "Error", "code": 5096 }, diff --git a/src/compiler/moduleNameResolver.ts b/src/compiler/moduleNameResolver.ts index 0d66245a58f41..45ba44eac4b00 100644 --- a/src/compiler/moduleNameResolver.ts +++ b/src/compiler/moduleNameResolver.ts @@ -3033,9 +3033,7 @@ export function classicNameResolver(moduleName: string, containingFile: string, // Program errors validate that `noEmit` or `emitDeclarationOnly` is also set, // so this function doesn't check them to avoid propagating errors. export function shouldAllowImportingTsExtension(compilerOptions: CompilerOptions, fromFileName?: string) { - return getEmitModuleResolutionKind(compilerOptions) === ModuleResolutionKind.Bundler && ( - !!compilerOptions.allowImportingTsExtensions || - fromFileName && isDeclarationFileName(fromFileName)); + return !!compilerOptions.allowImportingTsExtensions || fromFileName && isDeclarationFileName(fromFileName); } /** diff --git a/src/compiler/program.ts b/src/compiler/program.ts index 67e7e20928d58..dc7cd4784245b 100644 --- a/src/compiler/program.ts +++ b/src/compiler/program.ts @@ -4213,7 +4213,7 @@ export function createProgram(rootNamesOrOptions: readonly string[] | CreateProg } if (options.allowImportingTsExtensions && !(options.noEmit || options.emitDeclarationOnly)) { - createOptionValueDiagnostic("allowImportingTsExtensions", Diagnostics.Option_allowImportingTsExtensions_can_only_be_used_when_moduleResolution_is_set_to_bundler_and_either_noEmit_or_emitDeclarationOnly_is_set); + createOptionValueDiagnostic("allowImportingTsExtensions", Diagnostics.Option_allowImportingTsExtensions_can_only_be_used_when_either_noEmit_or_emitDeclarationOnly_is_set); } const moduleResolution = getEmitModuleResolutionKind(options); diff --git a/src/testRunner/unittests/tscWatch/programUpdates.ts b/src/testRunner/unittests/tscWatch/programUpdates.ts index 3437470bcd461..2e62b3e41d112 100644 --- a/src/testRunner/unittests/tscWatch/programUpdates.ts +++ b/src/testRunner/unittests/tscWatch/programUpdates.ts @@ -1957,4 +1957,42 @@ import { x } from "../b";`), }, ] }); + + verifyTscWatch({ + scenario, + subScenario: "when changing `allowImportingTsExtensions` of config file", + commandLineArgs: ["-w", "-p", ".", "--extendedDiagnostics"], + sys: () => { + const module1: File = { + path: `/user/username/projects/myproject/a.ts`, + content: `` + }; + const module2: File = { + path: `/user/username/projects/myproject/b.ts`, + content: `import "./a.ts";` + }; + const config: File = { + path: `/user/username/projects/myproject/tsconfig.json`, + content: JSON.stringify({ + compilerOptions: { + noEmit: true, + allowImportingTsExtensions: false + } + }), + }; + return createWatchedSystem([module1, module2, config, libFile], { currentDirectory: "/user/username/projects/myproject" }); + }, + edits: [ + { + caption: "Change allowImportingTsExtensions to true", + edit: sys => sys.writeFile(`/user/username/projects/myproject/tsconfig.json`, JSON.stringify({ + compilerOptions: { + noEmit: true, + allowImportingTsExtensions: true + } + })), + timeouts: sys => sys.checkTimeoutQueueLengthAndRun(1), + }, + ] + }); }); diff --git a/tests/baselines/reference/bundlerImportTsExtensions(allowimportingtsextensions=true,noemit=false).errors.txt b/tests/baselines/reference/bundlerImportTsExtensions(allowimportingtsextensions=true,noemit=false).errors.txt index 928c92f5f33bc..c6a2bf4156b5e 100644 --- a/tests/baselines/reference/bundlerImportTsExtensions(allowimportingtsextensions=true,noemit=false).errors.txt +++ b/tests/baselines/reference/bundlerImportTsExtensions(allowimportingtsextensions=true,noemit=false).errors.txt @@ -1,6 +1,6 @@ error TS5056: Cannot write file 'out/b.js' because it would be overwritten by multiple input files. error TS5056: Cannot write file 'out/c.js' because it would be overwritten by multiple input files. -error TS5096: Option 'allowImportingTsExtensions' can only be used when 'moduleResolution' is set to 'bundler' and either 'noEmit' or 'emitDeclarationOnly' is set. +error TS5096: Option 'allowImportingTsExtensions' can only be used when either 'noEmit' or 'emitDeclarationOnly' is set. error TS6054: File '/project/e.txt' has an unsupported extension. The only supported extensions are '.ts', '.tsx', '.d.ts', '.js', '.jsx', '.cts', '.d.cts', '.cjs', '.mts', '.d.mts', '.mjs'. The file is in the program because: Root file specified for compilation @@ -11,7 +11,7 @@ error TS6054: File '/project/e.txt' has an unsupported extension. The only suppo !!! error TS5056: Cannot write file 'out/b.js' because it would be overwritten by multiple input files. !!! error TS5056: Cannot write file 'out/c.js' because it would be overwritten by multiple input files. -!!! error TS5096: Option 'allowImportingTsExtensions' can only be used when 'moduleResolution' is set to 'bundler' and either 'noEmit' or 'emitDeclarationOnly' is set. +!!! error TS5096: Option 'allowImportingTsExtensions' can only be used when either 'noEmit' or 'emitDeclarationOnly' is set. !!! error TS6054: File '/project/e.txt' has an unsupported extension. The only supported extensions are '.ts', '.tsx', '.d.ts', '.js', '.jsx', '.cts', '.d.cts', '.cjs', '.mts', '.d.mts', '.mjs'. !!! error TS6054: The file is in the program because: !!! error TS6054: Root file specified for compilation diff --git a/tests/baselines/reference/tscWatch/programUpdates/when-changing-`allowImportingTsExtensions`-of-config-file.js b/tests/baselines/reference/tscWatch/programUpdates/when-changing-`allowImportingTsExtensions`-of-config-file.js new file mode 100644 index 0000000000000..b66e13c4bf181 --- /dev/null +++ b/tests/baselines/reference/tscWatch/programUpdates/when-changing-`allowImportingTsExtensions`-of-config-file.js @@ -0,0 +1,146 @@ +Input:: +//// [/user/username/projects/myproject/a.ts] + + +//// [/user/username/projects/myproject/b.ts] +import "./a.ts"; + +//// [/user/username/projects/myproject/tsconfig.json] +{"compilerOptions":{"noEmit":true,"allowImportingTsExtensions":false}} + +//// [/a/lib/lib.d.ts] +/// +interface Boolean {} +interface Function {} +interface CallableFunction {} +interface NewableFunction {} +interface IArguments {} +interface Number { toExponential: any; } +interface Object {} +interface RegExp {} +interface String { charAt: any; } +interface Array { length: number; [n: number]: T; } + + +/a/lib/tsc.js -w -p . --extendedDiagnostics +Output:: +[12:00:23 AM] Starting compilation in watch mode... + +Current directory: /user/username/projects/myproject CaseSensitiveFileNames: false +FileWatcher:: Added:: WatchInfo: /user/username/projects/myproject/tsconfig.json 2000 undefined Config file +Synchronizing program +CreatingProgramWith:: + roots: ["/user/username/projects/myproject/a.ts","/user/username/projects/myproject/b.ts"] + options: {"noEmit":true,"allowImportingTsExtensions":false,"watch":true,"project":"/user/username/projects/myproject","extendedDiagnostics":true,"configFilePath":"/user/username/projects/myproject/tsconfig.json"} +FileWatcher:: Added:: WatchInfo: /user/username/projects/myproject/a.ts 250 undefined Source file +FileWatcher:: Added:: WatchInfo: /user/username/projects/myproject/b.ts 250 undefined Source file +FileWatcher:: Added:: WatchInfo: /a/lib/lib.d.ts 250 undefined Source file +DirectoryWatcher:: Added:: WatchInfo: /user/username/projects/myproject/node_modules/@types 1 undefined Type roots +Elapsed:: *ms DirectoryWatcher:: Added:: WatchInfo: /user/username/projects/myproject/node_modules/@types 1 undefined Type roots +b.ts:1:8 - error TS5097: An import path can only end with a '.ts' extension when 'allowImportingTsExtensions' is enabled. + +1 import "./a.ts"; +   ~~~~~~~~ + +[12:00:24 AM] Found 1 error. Watching for file changes. + +DirectoryWatcher:: Added:: WatchInfo: /user/username/projects/myproject 1 undefined Wild card directory +Elapsed:: *ms DirectoryWatcher:: Added:: WatchInfo: /user/username/projects/myproject 1 undefined Wild card directory + + +Program root files: ["/user/username/projects/myproject/a.ts","/user/username/projects/myproject/b.ts"] +Program options: {"noEmit":true,"allowImportingTsExtensions":false,"watch":true,"project":"/user/username/projects/myproject","extendedDiagnostics":true,"configFilePath":"/user/username/projects/myproject/tsconfig.json"} +Program structureReused: Not +Program files:: +/a/lib/lib.d.ts +/user/username/projects/myproject/a.ts +/user/username/projects/myproject/b.ts + +Semantic diagnostics in builder refreshed for:: +/a/lib/lib.d.ts +/user/username/projects/myproject/a.ts +/user/username/projects/myproject/b.ts + +Shape signatures in builder refreshed for:: +/a/lib/lib.d.ts (used version) +/user/username/projects/myproject/a.ts (used version) +/user/username/projects/myproject/b.ts (used version) + +PolledWatches:: +/user/username/projects/myproject/node_modules/@types: + {"pollingInterval":500} + +FsWatches:: +/user/username/projects/myproject/tsconfig.json: + {} +/user/username/projects/myproject/a.ts: + {} +/user/username/projects/myproject/b.ts: + {} +/a/lib/lib.d.ts: + {} + +FsWatchesRecursive:: +/user/username/projects/myproject: + {} + +exitCode:: ExitStatus.undefined + + +Change:: Change allowImportingTsExtensions to true + +Input:: +//// [/user/username/projects/myproject/tsconfig.json] +{"compilerOptions":{"noEmit":true,"allowImportingTsExtensions":true}} + + +Output:: +FileWatcher:: Triggered with /user/username/projects/myproject/tsconfig.json 1:: WatchInfo: /user/username/projects/myproject/tsconfig.json 2000 undefined Config file +Scheduling update +Elapsed:: *ms FileWatcher:: Triggered with /user/username/projects/myproject/tsconfig.json 1:: WatchInfo: /user/username/projects/myproject/tsconfig.json 2000 undefined Config file +Reloading config file: /user/username/projects/myproject/tsconfig.json +Synchronizing program +[12:00:28 AM] File change detected. Starting incremental compilation... + +CreatingProgramWith:: + roots: ["/user/username/projects/myproject/a.ts","/user/username/projects/myproject/b.ts"] + options: {"noEmit":true,"allowImportingTsExtensions":true,"watch":true,"project":"/user/username/projects/myproject","extendedDiagnostics":true,"configFilePath":"/user/username/projects/myproject/tsconfig.json"} +[12:00:29 AM] Found 0 errors. Watching for file changes. + + + +Program root files: ["/user/username/projects/myproject/a.ts","/user/username/projects/myproject/b.ts"] +Program options: {"noEmit":true,"allowImportingTsExtensions":true,"watch":true,"project":"/user/username/projects/myproject","extendedDiagnostics":true,"configFilePath":"/user/username/projects/myproject/tsconfig.json"} +Program structureReused: Completely +Program files:: +/a/lib/lib.d.ts +/user/username/projects/myproject/a.ts +/user/username/projects/myproject/b.ts + +Semantic diagnostics in builder refreshed for:: +/a/lib/lib.d.ts +/user/username/projects/myproject/a.ts +/user/username/projects/myproject/b.ts + +No shapes updated in the builder:: + +PolledWatches:: +/user/username/projects/myproject/node_modules/@types: + {"pollingInterval":500} + +FsWatches:: +/user/username/projects/myproject/tsconfig.json: + {} +/user/username/projects/myproject/a.ts: + {} +/user/username/projects/myproject/b.ts: + {} +/a/lib/lib.d.ts: + {} + +FsWatchesRecursive:: +/user/username/projects/myproject: + {} + +exitCode:: ExitStatus.undefined + diff --git a/tests/cases/conformance/moduleResolution/allowImportingTsExtensions.ts b/tests/cases/conformance/moduleResolution/allowImportingTsExtensions.ts new file mode 100644 index 0000000000000..24004050d2de0 --- /dev/null +++ b/tests/cases/conformance/moduleResolution/allowImportingTsExtensions.ts @@ -0,0 +1,29 @@ +// @allowImportingTsExtensions: true +// @noEmit: true +// @moduleResolution: classic,node10,node16,nodenext,bundler +// @jsx: preserve +// @noTypesAndSymbols: true + +// @Filename: /ts.ts +export {}; + +// @Filename: /tsx.tsx +export {}; + +// @Filename: /dts.d.ts +export {}; + +// @Filename: /b.ts +import {} from "./ts.js"; +import {} from "./ts.ts"; +import type {} from "./ts.d.ts"; + +import {} from "./tsx.js"; +import {} from "./tsx.jsx"; +import {} from "./tsx.ts"; +import {} from "./tsx.tsx"; +import type {} from "./tsx.d.ts"; + +import {} from "./dts.js"; +import {} from "./dts.ts"; +import type {} from "./dts.d.ts";