From e9f0a1af539edfb5dde48a257bc4e81520d80968 Mon Sep 17 00:00:00 2001 From: Andrew Branch Date: Thu, 28 Jul 2022 09:20:32 -0700 Subject: [PATCH 01/14] WIP --- src/compiler/commandLineParser.ts | 1 + src/compiler/moduleNameResolver.ts | 67 ++++++++++++++++++- src/compiler/types.ts | 2 + src/testRunner/compilerRunner.ts | 1 + .../moduleResolution/minimal_relative.ts | 47 +++++++++++++ 5 files changed, 117 insertions(+), 1 deletion(-) create mode 100644 tests/cases/conformance/moduleResolution/minimal_relative.ts diff --git a/src/compiler/commandLineParser.ts b/src/compiler/commandLineParser.ts index 370461abd8559..646807980fc8f 100644 --- a/src/compiler/commandLineParser.ts +++ b/src/compiler/commandLineParser.ts @@ -835,6 +835,7 @@ namespace ts { classic: ModuleResolutionKind.Classic, node16: ModuleResolutionKind.Node16, nodenext: ModuleResolutionKind.NodeNext, + minimal: ModuleResolutionKind.Minimal, })), affectsModuleResolution: true, paramType: Diagnostics.STRATEGY, diff --git a/src/compiler/moduleNameResolver.ts b/src/compiler/moduleNameResolver.ts index 68780ef26aab3..bf8fbb5ca37eb 100644 --- a/src/compiler/moduleNameResolver.ts +++ b/src/compiler/moduleNameResolver.ts @@ -25,6 +25,10 @@ namespace ts { return r && { path: r.path, extension: r.ext, packageId }; } + function createLoaderWithNoPackageId

(loader: (...args: P) => PathAndExtension | undefined): (...args: P) => Resolved | undefined { + return (...args) => noPackageId(loader(...args)); + } + function noPackageId(r: PathAndExtension | undefined): Resolved | undefined { return withPackageId(/*packageInfo*/ undefined, r); } @@ -1013,6 +1017,9 @@ namespace ts { case ModuleResolutionKind.Classic: result = classicNameResolver(moduleName, containingFile, compilerOptions, host, cache, redirectedReference); break; + case ModuleResolutionKind.Minimal: + result = minimalModuleNameResolver(moduleName, containingFile, compilerOptions, host); + break; default: return Debug.fail(`Unexpected moduleResolution: ${moduleResolution}`); } @@ -1550,7 +1557,10 @@ namespace ts { function loadModuleFromFileNoImplicitExtensions(extensions: Extensions, candidate: string, onlyRecordFailures: boolean, state: ModuleResolutionState): PathAndExtension | undefined { // If that didn't work, try stripping a ".js" or ".jsx" extension and replacing it with a TypeScript one; // e.g. "./foo.js" can be matched by "./foo.ts" or "./foo.d.ts" - if (hasJSFileExtension(candidate) || (fileExtensionIs(candidate, Extension.Json) && state.compilerOptions.resolveJsonModule)) { + if (hasJSFileExtension(candidate) || + (state.compilerOptions.resolveJsonModule && fileExtensionIs(candidate, Extension.Json)) || + (shouldResolveTsExtension(state.compilerOptions) && fileExtensionIsOneOf(candidate, supportedTSExtensionsFlat)) + ) { const extensionless = removeFileExtension(candidate); const extension = candidate.substring(extensionless.length); if (state.traceEnabled) { @@ -1610,6 +1620,13 @@ namespace ts { case Extension.Json: candidate += Extension.Json; return useDts ? tryExtension(Extension.Dts) : undefined; + case Extension.Ts: + case Extension.Tsx: + case Extension.Dts: + if (shouldResolveTsExtension(state.compilerOptions)) { + return tryExtension(originalExtension); + } + // falls through default: return tryExtension(Extension.Ts) || tryExtension(Extension.Tsx) || (useDts ? tryExtension(Extension.Dts) : undefined); } @@ -2636,6 +2653,54 @@ namespace ts { } } + export function minimalModuleNameResolver(moduleName: string, containingFile: string, compilerOptions: CompilerOptions, host: ModuleResolutionHost): ResolvedModuleWithFailedLookupLocations { + const traceEnabled = isTraceEnabled(compilerOptions, host); + const failedLookupLocations: string[] = []; + const affectingLocations: string[] = []; + const containingDirectory = getDirectoryPath(containingFile); + const diagnostics: Diagnostic[] = []; + const state: ModuleResolutionState = { + compilerOptions, + host, + traceEnabled, + failedLookupLocations, + affectingLocations, + packageJsonInfoCache: undefined, + features: NodeResolutionFeatures.None, + conditions: [], + requestContainingDirectory: containingDirectory, + reportDiagnostic: diag => void diagnostics.push(diag), + }; + + const candidate = normalizePath(combinePaths(containingDirectory, moduleName)); + return createResolvedModuleWithFailedLookupLocations( + tryResolve(Extensions.TypeScript) || tryResolve(Extensions.JavaScript), + /*isExternalLibraryImport*/ false, + failedLookupLocations, + affectingLocations, + diagnostics, + state.resultFromCache); + + function tryResolve(extensions: Extensions) { + const resolvedUsingSettings = tryLoadModuleUsingOptionalResolutionSettings(extensions, moduleName, containingDirectory, createLoaderWithNoPackageId(loadModuleFromFileNoImplicitExtensions), state); + if (resolvedUsingSettings) { + return resolvedUsingSettings; + } + const resolvedRelative = loadModuleFromFileNoImplicitExtensions(extensions, candidate, /*onlyRecordFailures*/ false, state); + if (resolvedRelative) { + return noPackageId(resolvedRelative); + } + } + } + + export function shouldResolveTsExtension(compilerOptions: CompilerOptions) { + return getEmitModuleResolutionKind(compilerOptions) === ModuleResolutionKind.Minimal; + } + + export function shouldAllowTsExtension(compilerOptions: CompilerOptions) { + return shouldResolveTsExtension(compilerOptions) && !!compilerOptions.noEmit; + } + /** * A host may load a module from a global cache of typings. * This is the minumum code needed to expose that functionality; the rest is in the host. diff --git a/src/compiler/types.ts b/src/compiler/types.ts index f93f36c369157..d5e5dbbb27ab2 100644 --- a/src/compiler/types.ts +++ b/src/compiler/types.ts @@ -6246,6 +6246,8 @@ namespace ts { // In turn, we offer both a `NodeNext` moving resolution target, and a `Node16` version-anchored resolution target Node16 = 3, NodeNext = 99, // Not simply `Node16` so that compiled code linked against TS can use the `Next` value reliably (same as with `ModuleKind`) + + Minimal = 100, } export enum ModuleDetectionKind { diff --git a/src/testRunner/compilerRunner.ts b/src/testRunner/compilerRunner.ts index a6c67a17ee186..2fcda0891a652 100644 --- a/src/testRunner/compilerRunner.ts +++ b/src/testRunner/compilerRunner.ts @@ -121,6 +121,7 @@ namespace Harness { "moduleDetection", "target", "jsx", + "noEmit", "removeComments", "importHelpers", "importHelpers", diff --git a/tests/cases/conformance/moduleResolution/minimal_relative.ts b/tests/cases/conformance/moduleResolution/minimal_relative.ts new file mode 100644 index 0000000000000..48fda19b7c3eb --- /dev/null +++ b/tests/cases/conformance/moduleResolution/minimal_relative.ts @@ -0,0 +1,47 @@ +// @moduleResolution: minimal +// @outDir: dist +// @noEmit: true,false +// @traceResolution: true + +// @Filename: /project/a.ts +export {}; + +// @Filename: /project/b.ts +export {}; + +// @Filename: /project/b.js +export {}; + +// @Filename: /project/b.d.ts +export {}; + +// @Filename: /project/c.ts +export {}; + +// @Filename: /project/c.tsx +export {}; + +// @Filename: /project/d/index.ts +export {}; + +// @Filename: /project/e +export {}; + +// @Filename: /project/main.ts +import {} from "./a"; +import {} from "./a.js"; +import {} from "./a.ts"; + +import {} from "./b"; +import {} from "./b.js"; +import {} from "./b.ts"; +import {} from "./b.d.ts"; + +import {} from "./c.ts"; +import {} from "./c.tsx"; + +import {} from "./d"; +import {} from "./d/index"; +import {} from "./d/index.ts"; + +import {} from "./e"; From 5f9cf9db8d71dcc98ffe41b49cde8f181b6beb31 Mon Sep 17 00:00:00 2001 From: Andrew Branch Date: Fri, 29 Jul 2022 13:07:11 -0700 Subject: [PATCH 02/14] Add extension error back unless noEmit is set --- src/compiler/checker.ts | 30 +++--- src/compiler/moduleNameResolver.ts | 47 ++++++--- src/compiler/types.ts | 5 + src/services/shims.ts | 2 +- src/testRunner/unittests/moduleResolution.ts | 9 +- src/testRunner/unittests/tscWatch/watchApi.ts | 1 + .../reference/api/tsserverlibrary.d.ts | 11 ++- tests/baselines/reference/api/typescript.d.ts | 11 ++- .../minimal_relative(noemit=false).errors.txt | 95 +++++++++++++++++++ .../minimal_relative(noemit=false).js | 58 +++++++++++ .../minimal_relative(noemit=false).symbols | 38 ++++++++ .../minimal_relative(noemit=false).trace.json | 57 +++++++++++ .../minimal_relative(noemit=false).types | 38 ++++++++ .../minimal_relative(noemit=true).errors.txt | 75 +++++++++++++++ .../minimal_relative(noemit=true).symbols | 38 ++++++++ .../minimal_relative(noemit=true).trace.json | 57 +++++++++++ .../minimal_relative(noemit=true).types | 38 ++++++++ 17 files changed, 582 insertions(+), 28 deletions(-) create mode 100644 tests/baselines/reference/minimal_relative(noemit=false).errors.txt create mode 100644 tests/baselines/reference/minimal_relative(noemit=false).js create mode 100644 tests/baselines/reference/minimal_relative(noemit=false).symbols create mode 100644 tests/baselines/reference/minimal_relative(noemit=false).trace.json create mode 100644 tests/baselines/reference/minimal_relative(noemit=false).types create mode 100644 tests/baselines/reference/minimal_relative(noemit=true).errors.txt create mode 100644 tests/baselines/reference/minimal_relative(noemit=true).symbols create mode 100644 tests/baselines/reference/minimal_relative(noemit=true).trace.json create mode 100644 tests/baselines/reference/minimal_relative(noemit=true).types diff --git a/src/compiler/checker.ts b/src/compiler/checker.ts index 7768b78ef3ecd..bbcb97e7c881f 100644 --- a/src/compiler/checker.ts +++ b/src/compiler/checker.ts @@ -3570,6 +3570,10 @@ namespace ts { if (resolutionDiagnostic) { error(errorNode, resolutionDiagnostic, moduleReference, resolvedModule.resolvedFileName); } + if (resolvedModule.resolvedUsingTsExtension && !shouldAllowTsExtension(compilerOptions)) { + const tsExtension = Debug.checkDefined(tryExtractTSExtension(moduleReference)); + errorOnTSExtensionImport(tsExtension); + } if (sourceFile.symbol) { if (resolvedModule.isExternalLibraryImport && !resolutionExtensionIsTSOrJson(resolvedModule.extension)) { errorOnImplicitAnyModule(/*isError*/ false, errorNode, resolvedModule, moduleReference); @@ -3642,17 +3646,7 @@ namespace ts { const resolutionIsNode16OrNext = moduleResolutionKind === ModuleResolutionKind.Node16 || moduleResolutionKind === ModuleResolutionKind.NodeNext; if (tsExtension) { - const diag = Diagnostics.An_import_path_cannot_end_with_a_0_extension_Consider_importing_1_instead; - const importSourceWithoutExtension = removeExtension(moduleReference, tsExtension); - let replacedImportSource = importSourceWithoutExtension; - /** - * Direct users to import source with .js extension if outputting an ES module. - * @see https://github.com/microsoft/TypeScript/issues/42151 - */ - if (moduleKind >= ModuleKind.ES2015) { - replacedImportSource += tsExtension === Extension.Mts ? ".mjs" : tsExtension === Extension.Cts ? ".cjs" : ".js"; - } - error(errorNode, diag, tsExtension, replacedImportSource); + errorOnTSExtensionImport(tsExtension); } else if (!compilerOptions.resolveJsonModule && fileExtensionIs(moduleReference, Extension.Json) && @@ -3678,6 +3672,20 @@ namespace ts { } } return undefined; + + function errorOnTSExtensionImport(tsExtension: string) { + const diag = Diagnostics.An_import_path_cannot_end_with_a_0_extension_Consider_importing_1_instead; + const importSourceWithoutExtension = removeExtension(moduleReference, tsExtension); + let replacedImportSource = importSourceWithoutExtension; + /** + * Direct users to import source with .js extension if outputting an ES module. + * @see https://github.com/microsoft/TypeScript/issues/42151 + */ + if (moduleKind >= ModuleKind.ES2015 || getEmitModuleResolutionKind(compilerOptions) === ModuleResolutionKind.Minimal) { + replacedImportSource += tsExtension === Extension.Mts ? ".mjs" : tsExtension === Extension.Cts ? ".cjs" : ".js"; + } + error(errorNode, diag, tsExtension, replacedImportSource); + } } function errorOnImplicitAnyModule(isError: boolean, errorNode: Node, { packageId, resolvedFileName }: ResolvedModuleFull, moduleReference: string): void { diff --git a/src/compiler/moduleNameResolver.ts b/src/compiler/moduleNameResolver.ts index bf8fbb5ca37eb..5bec091015037 100644 --- a/src/compiler/moduleNameResolver.ts +++ b/src/compiler/moduleNameResolver.ts @@ -22,7 +22,7 @@ namespace ts { }; } } - return r && { path: r.path, extension: r.ext, packageId }; + return r && { path: r.path, extension: r.ext, packageId, resolvedUsingTsExtension: r.resolvedUsingTsExtension }; } function createLoaderWithNoPackageId

(loader: (...args: P) => PathAndExtension | undefined): (...args: P) => Resolved | undefined { @@ -36,7 +36,7 @@ namespace ts { function removeIgnoredPackageId(r: Resolved | undefined): PathAndExtension | undefined { if (r) { Debug.assert(r.packageId === undefined); - return { path: r.path, ext: r.extension }; + return { path: r.path, ext: r.extension, resolvedUsingTsExtension: r.resolvedUsingTsExtension }; } } @@ -55,6 +55,7 @@ namespace ts { * Note: This is a file name with preserved original casing, not a normalized `Path`. */ originalPath?: string | true; + resolvedUsingTsExtension: boolean | undefined; } /** Result of trying to resolve a module at a file. Needs to have 'packageId' added later. */ @@ -62,6 +63,7 @@ namespace ts { path: string; // (Use a different name than `extension` to make sure Resolved isn't assignable to PathAndExtension.) ext: Extension; + resolvedUsingTsExtension: boolean | undefined; } /** @@ -104,7 +106,14 @@ namespace ts { return resultFromCache; } return { - resolvedModule: resolved && { resolvedFileName: resolved.path, originalPath: resolved.originalPath === true ? undefined : resolved.originalPath, extension: resolved.extension, isExternalLibraryImport, packageId: resolved.packageId }, + resolvedModule: resolved && { + resolvedFileName: resolved.path, + originalPath: resolved.originalPath === true ? undefined : resolved.originalPath, + extension: resolved.extension, + isExternalLibraryImport, + packageId: resolved.packageId, + resolvedUsingTsExtension: !!resolved.resolvedUsingTsExtension, + }, failedLookupLocations, affectingLocations, resolutionDiagnostics: diagnostics, @@ -1573,7 +1582,7 @@ namespace ts { function loadJSOrExactTSFileName(extensions: Extensions, candidate: string, onlyRecordFailures: boolean, state: ModuleResolutionState): PathAndExtension | undefined { if ((extensions === Extensions.TypeScript || extensions === Extensions.DtsOnly) && fileExtensionIsOneOf(candidate, supportedTSExtensionsFlat)) { const result = tryFile(candidate, onlyRecordFailures, state); - return result !== undefined ? { path: candidate, ext: tryExtractTSExtension(candidate) as Extension } : undefined; + return result !== undefined ? { path: candidate, ext: tryExtractTSExtension(candidate) as Extension, resolvedUsingTsExtension: undefined } : undefined; } return loadModuleFromFileNoImplicitExtensions(extensions, candidate, onlyRecordFailures, state); @@ -1624,7 +1633,7 @@ namespace ts { case Extension.Tsx: case Extension.Dts: if (shouldResolveTsExtension(state.compilerOptions)) { - return tryExtension(originalExtension); + return tryExtension(originalExtension, /*resolvedUsingTsExtension*/ true); } // falls through default: @@ -1650,9 +1659,9 @@ namespace ts { return tryExtension(Extension.Json); } - function tryExtension(ext: Extension): PathAndExtension | undefined { + function tryExtension(ext: Extension, resolvedUsingTsExtension?: boolean): PathAndExtension | undefined { const path = tryFile(candidate + ext, onlyRecordFailures, state); - return path === undefined ? undefined : { path, ext }; + return path === undefined ? undefined : { path, ext, resolvedUsingTsExtension }; } } @@ -1978,9 +1987,9 @@ namespace ts { } /** Resolve from an arbitrarily specified file. Return `undefined` if it has an unsupported extension. */ - function resolvedIfExtensionMatches(extensions: Extensions, path: string): PathAndExtension | undefined { + function resolvedIfExtensionMatches(extensions: Extensions, path: string, resolvedUsingTsExtension?: boolean): PathAndExtension | undefined { const ext = tryGetExtensionFromPath(path); - return ext !== undefined && extensionIsOk(extensions, ext) ? { path, ext } : undefined; + return ext !== undefined && extensionIsOk(extensions, ext) ? { path, ext, resolvedUsingTsExtension } : undefined; } /** True if `extension` is one of the supported `extensions`. */ @@ -2179,7 +2188,13 @@ namespace ts { if (isImports && !startsWith(target, "../") && !startsWith(target, "/") && !isRootedDiskPath(target)) { const combinedLookup = pattern ? target.replace(/\*/g, subpath) : target + subpath; const result = nodeModuleNameResolverWorker(state.features, combinedLookup, scope.packageDirectory + "/", state.compilerOptions, state.host, cache, [extensions], redirectedReference); - return toSearchResult(result.resolvedModule ? { path: result.resolvedModule.resolvedFileName, extension: result.resolvedModule.extension, packageId: result.resolvedModule.packageId, originalPath: result.resolvedModule.originalPath } : undefined); + return toSearchResult(result.resolvedModule ? { + path: result.resolvedModule.resolvedFileName, + extension: result.resolvedModule.extension, + packageId: result.resolvedModule.packageId, + originalPath: result.resolvedModule.originalPath, + resolvedUsingTsExtension: result.resolvedModule.resolvedUsingTsExtension + } : undefined); } if (state.traceEnabled) { trace(state.host, Diagnostics.package_json_scope_0_has_invalid_type_for_target_of_specifier_1, scope.packageDirectory, moduleName); @@ -2528,7 +2543,7 @@ namespace ts { if (extension !== undefined) { const path = tryFile(candidate, onlyRecordFailures, state); if (path !== undefined) { - return noPackageId({ path, ext: extension }); + return noPackageId({ path, ext: extension, resolvedUsingTsExtension: undefined }); } } return loader(extensions, candidate, onlyRecordFailures || !directoryProbablyExists(getDirectoryPath(candidate), state.host), state); @@ -2588,7 +2603,15 @@ namespace ts { trace(state.host, Diagnostics.Resolution_for_module_0_was_found_in_cache_from_location_1, moduleName, containingDirectory); } state.resultFromCache = result; - return { value: result.resolvedModule && { path: result.resolvedModule.resolvedFileName, originalPath: result.resolvedModule.originalPath || true, extension: result.resolvedModule.extension, packageId: result.resolvedModule.packageId } }; + return { + value: result.resolvedModule && { + path: result.resolvedModule.resolvedFileName, + originalPath: result.resolvedModule.originalPath || true, + extension: result.resolvedModule.extension, + packageId: result.resolvedModule.packageId, + resolvedUsingTsExtension: result.resolvedModule.resolvedUsingTsExtension + } + }; } } diff --git a/src/compiler/types.ts b/src/compiler/types.ts index d5e5dbbb27ab2..4f2c65d876578 100644 --- a/src/compiler/types.ts +++ b/src/compiler/types.ts @@ -6853,6 +6853,11 @@ namespace ts { resolvedFileName: string; /** True if `resolvedFileName` comes from `node_modules`. */ isExternalLibraryImport?: boolean; + /** + * True if the original module reference used a .ts extension to refer directly to a .ts file, + * which should produce an error during checking if emit is enabled. + */ + resolvedUsingTsExtension: boolean; } /** diff --git a/src/services/shims.ts b/src/services/shims.ts index 6d313b695ce67..72b7c936863ea 100644 --- a/src/services/shims.ts +++ b/src/services/shims.ts @@ -362,7 +362,7 @@ namespace ts { const resolutionsInFile = JSON.parse(this.shimHost.getModuleResolutionsForFile!(containingFile)) as MapLike; // TODO: GH#18217 return map(moduleNames, name => { const result = getProperty(resolutionsInFile, name); - return result ? { resolvedFileName: result, extension: extensionFromPath(result), isExternalLibraryImport: false } : undefined; + return result ? { resolvedFileName: result, extension: extensionFromPath(result), isExternalLibraryImport: false, resolvedUsingTsExtension: false } : undefined; }); }; } diff --git a/src/testRunner/unittests/moduleResolution.ts b/src/testRunner/unittests/moduleResolution.ts index 1f85f97827c16..abf0c48773385 100644 --- a/src/testRunner/unittests/moduleResolution.ts +++ b/src/testRunner/unittests/moduleResolution.ts @@ -24,8 +24,8 @@ namespace ts { assert.deepEqual(actual.failedLookupLocations, expectedFailedLookupLocations, `Failed lookup locations should match - expected has ${expectedFailedLookupLocations.length}, actual has ${actual.failedLookupLocations.length}`); } - export function createResolvedModule(resolvedFileName: string, isExternalLibraryImport = false): ResolvedModuleFull { - return { resolvedFileName, extension: extensionFromPath(resolvedFileName), isExternalLibraryImport }; + export function createResolvedModule(resolvedFileName: string, isExternalLibraryImport = false, resolvedUsingTsExtension = false): ResolvedModuleFull { + return { resolvedFileName, extension: extensionFromPath(resolvedFileName), isExternalLibraryImport, resolvedUsingTsExtension }; } interface File { @@ -214,6 +214,7 @@ namespace ts { resolvedFileName: "/sub/node_modules/a/index.ts", isExternalLibraryImport: true, extension: Extension.Ts, + resolvedUsingTsExtension: false, }, failedLookupLocations: [], affectingLocations: [], @@ -229,6 +230,7 @@ namespace ts { resolvedFileName: "/sub/directory/node_modules/b/index.ts", isExternalLibraryImport: true, extension: Extension.Ts, + resolvedUsingTsExtension: false, }, failedLookupLocations: [], affectingLocations: [], @@ -246,6 +248,7 @@ namespace ts { resolvedFileName: "/bar/node_modules/c/index.ts", isExternalLibraryImport: true, extension: Extension.Ts, + resolvedUsingTsExtension: false, }, failedLookupLocations: [], affectingLocations: [], @@ -262,6 +265,7 @@ namespace ts { resolvedFileName: "/foo/index.ts", isExternalLibraryImport: true, extension: Extension.Ts, + resolvedUsingTsExtension: false, }, failedLookupLocations: [], affectingLocations: [], @@ -277,6 +281,7 @@ namespace ts { resolvedFileName: "d:/bar/node_modules/e/index.ts", isExternalLibraryImport: true, extension: Extension.Ts, + resolvedUsingTsExtension: false, }, failedLookupLocations: [], affectingLocations: [], diff --git a/src/testRunner/unittests/tscWatch/watchApi.ts b/src/testRunner/unittests/tscWatch/watchApi.ts index 477a982eafde2..89b7359309903 100644 --- a/src/testRunner/unittests/tscWatch/watchApi.ts +++ b/src/testRunner/unittests/tscWatch/watchApi.ts @@ -35,6 +35,7 @@ namespace ts.tscWatch { resolvedFileName: resolvedModule.resolvedFileName, isExternalLibraryImport: resolvedModule.isExternalLibraryImport, originalFileName: resolvedModule.originalPath, + resolvedUsingTsExtension: false, }; }); const watch = createWatchProgram(host); diff --git a/tests/baselines/reference/api/tsserverlibrary.d.ts b/tests/baselines/reference/api/tsserverlibrary.d.ts index bbc5c38476cdd..1fe485492ffd2 100644 --- a/tests/baselines/reference/api/tsserverlibrary.d.ts +++ b/tests/baselines/reference/api/tsserverlibrary.d.ts @@ -2926,7 +2926,8 @@ declare namespace ts { Classic = 1, NodeJs = 2, Node16 = 3, - NodeNext = 99 + NodeNext = 99, + Minimal = 100 } export enum ModuleDetectionKind { /** @@ -3221,6 +3222,11 @@ declare namespace ts { resolvedFileName: string; /** True if `resolvedFileName` comes from `node_modules`. */ isExternalLibraryImport?: boolean; + /** + * True if the original module reference used a .ts extension to refer directly to a .ts file, + * which should produce an error during checking if emit is enabled. + */ + resolvedUsingTsExtension: boolean; } /** * ResolvedModule with an explicitly provided `extension` property. @@ -5028,6 +5034,9 @@ declare namespace ts { export function resolveModuleName(moduleName: string, containingFile: string, compilerOptions: CompilerOptions, host: ModuleResolutionHost, cache?: ModuleResolutionCache, redirectedReference?: ResolvedProjectReference, resolutionMode?: ModuleKind.CommonJS | ModuleKind.ESNext): ResolvedModuleWithFailedLookupLocations; export function nodeModuleNameResolver(moduleName: string, containingFile: string, compilerOptions: CompilerOptions, host: ModuleResolutionHost, cache?: ModuleResolutionCache, redirectedReference?: ResolvedProjectReference): ResolvedModuleWithFailedLookupLocations; export function classicNameResolver(moduleName: string, containingFile: string, compilerOptions: CompilerOptions, host: ModuleResolutionHost, cache?: NonRelativeModuleNameResolutionCache, redirectedReference?: ResolvedProjectReference): ResolvedModuleWithFailedLookupLocations; + export function minimalModuleNameResolver(moduleName: string, containingFile: string, compilerOptions: CompilerOptions, host: ModuleResolutionHost): ResolvedModuleWithFailedLookupLocations; + export function shouldResolveTsExtension(compilerOptions: CompilerOptions): boolean; + export function shouldAllowTsExtension(compilerOptions: CompilerOptions): boolean; export {}; } declare namespace ts { diff --git a/tests/baselines/reference/api/typescript.d.ts b/tests/baselines/reference/api/typescript.d.ts index f9e5f2d0bdebf..62ea676e7dd8d 100644 --- a/tests/baselines/reference/api/typescript.d.ts +++ b/tests/baselines/reference/api/typescript.d.ts @@ -2926,7 +2926,8 @@ declare namespace ts { Classic = 1, NodeJs = 2, Node16 = 3, - NodeNext = 99 + NodeNext = 99, + Minimal = 100 } export enum ModuleDetectionKind { /** @@ -3221,6 +3222,11 @@ declare namespace ts { resolvedFileName: string; /** True if `resolvedFileName` comes from `node_modules`. */ isExternalLibraryImport?: boolean; + /** + * True if the original module reference used a .ts extension to refer directly to a .ts file, + * which should produce an error during checking if emit is enabled. + */ + resolvedUsingTsExtension: boolean; } /** * ResolvedModule with an explicitly provided `extension` property. @@ -5028,6 +5034,9 @@ declare namespace ts { export function resolveModuleName(moduleName: string, containingFile: string, compilerOptions: CompilerOptions, host: ModuleResolutionHost, cache?: ModuleResolutionCache, redirectedReference?: ResolvedProjectReference, resolutionMode?: ModuleKind.CommonJS | ModuleKind.ESNext): ResolvedModuleWithFailedLookupLocations; export function nodeModuleNameResolver(moduleName: string, containingFile: string, compilerOptions: CompilerOptions, host: ModuleResolutionHost, cache?: ModuleResolutionCache, redirectedReference?: ResolvedProjectReference): ResolvedModuleWithFailedLookupLocations; export function classicNameResolver(moduleName: string, containingFile: string, compilerOptions: CompilerOptions, host: ModuleResolutionHost, cache?: NonRelativeModuleNameResolutionCache, redirectedReference?: ResolvedProjectReference): ResolvedModuleWithFailedLookupLocations; + export function minimalModuleNameResolver(moduleName: string, containingFile: string, compilerOptions: CompilerOptions, host: ModuleResolutionHost): ResolvedModuleWithFailedLookupLocations; + export function shouldResolveTsExtension(compilerOptions: CompilerOptions): boolean; + export function shouldAllowTsExtension(compilerOptions: CompilerOptions): boolean; export {}; } declare namespace ts { diff --git a/tests/baselines/reference/minimal_relative(noemit=false).errors.txt b/tests/baselines/reference/minimal_relative(noemit=false).errors.txt new file mode 100644 index 0000000000000..fde1ffef20104 --- /dev/null +++ b/tests/baselines/reference/minimal_relative(noemit=false).errors.txt @@ -0,0 +1,95 @@ +error TS5056: Cannot write file 'dist/c.js' because it would be overwritten by multiple input files. +error TS6231: Could not resolve the path '/project/e' with the extensions: '.ts', '.tsx', '.d.ts', '.cts', '.d.cts', '.mts', '.d.mts'. + The file is in the program because: + Root file specified for compilation +error TS6504: File '/project/b.js' is a JavaScript file. Did you mean to enable the 'allowJs' option? + The file is in the program because: + Root file specified for compilation +/project/main.ts(1,16): error TS2307: Cannot find module './a' or its corresponding type declarations. +/project/main.ts(3,16): error TS2691: An import path cannot end with a '.ts' extension. Consider importing './a.js' instead. +/project/main.ts(5,16): error TS2307: Cannot find module './b' or its corresponding type declarations. +/project/main.ts(7,16): error TS2691: An import path cannot end with a '.ts' extension. Consider importing './b.js' instead. +/project/main.ts(8,16): error TS2691: An import path cannot end with a '.d.ts' extension. Consider importing './b.js' instead. +/project/main.ts(10,16): error TS2691: An import path cannot end with a '.ts' extension. Consider importing './c.js' instead. +/project/main.ts(11,16): error TS2691: An import path cannot end with a '.tsx' extension. Consider importing './c.js' instead. +/project/main.ts(11,16): error TS6142: Module './c.tsx' was resolved to '/project/c.tsx', but '--jsx' is not set. +/project/main.ts(13,16): error TS2307: Cannot find module './d' or its corresponding type declarations. +/project/main.ts(14,16): error TS2307: Cannot find module './d/index' or its corresponding type declarations. +/project/main.ts(15,16): error TS2691: An import path cannot end with a '.ts' extension. Consider importing './d/index.js' instead. +/project/main.ts(17,16): error TS2307: Cannot find module './e' or its corresponding type declarations. + + +!!! error TS5056: Cannot write file 'dist/c.js' because it would be overwritten by multiple input files. +!!! error TS6231: Could not resolve the path '/project/e' with the extensions: '.ts', '.tsx', '.d.ts', '.cts', '.d.cts', '.mts', '.d.mts'. +!!! error TS6231: The file is in the program because: +!!! error TS6231: Root file specified for compilation +!!! error TS6504: File '/project/b.js' is a JavaScript file. Did you mean to enable the 'allowJs' option? +!!! error TS6504: The file is in the program because: +!!! error TS6504: Root file specified for compilation +==== /project/a.ts (0 errors) ==== + export {}; + +==== /project/b.ts (0 errors) ==== + export {}; + +==== /project/b.js (0 errors) ==== + export {}; + +==== /project/b.d.ts (0 errors) ==== + export {}; + +==== /project/c.ts (0 errors) ==== + export {}; + +==== /project/c.tsx (0 errors) ==== + export {}; + +==== /project/d/index.ts (0 errors) ==== + export {}; + +==== /project/e (0 errors) ==== + export {}; + +==== /project/main.ts (12 errors) ==== + import {} from "./a"; + ~~~~~ +!!! error TS2307: Cannot find module './a' or its corresponding type declarations. + import {} from "./a.js"; + import {} from "./a.ts"; + ~~~~~~~~ +!!! error TS2691: An import path cannot end with a '.ts' extension. Consider importing './a.js' instead. + + import {} from "./b"; + ~~~~~ +!!! error TS2307: Cannot find module './b' or its corresponding type declarations. + import {} from "./b.js"; + import {} from "./b.ts"; + ~~~~~~~~ +!!! error TS2691: An import path cannot end with a '.ts' extension. Consider importing './b.js' instead. + import {} from "./b.d.ts"; + ~~~~~~~~~~ +!!! error TS2691: An import path cannot end with a '.d.ts' extension. Consider importing './b.js' instead. + + import {} from "./c.ts"; + ~~~~~~~~ +!!! error TS2691: An import path cannot end with a '.ts' extension. Consider importing './c.js' instead. + import {} from "./c.tsx"; + ~~~~~~~~~ +!!! error TS2691: An import path cannot end with a '.tsx' extension. Consider importing './c.js' instead. + ~~~~~~~~~ +!!! error TS6142: Module './c.tsx' was resolved to '/project/c.tsx', but '--jsx' is not set. + + import {} from "./d"; + ~~~~~ +!!! error TS2307: Cannot find module './d' or its corresponding type declarations. + import {} from "./d/index"; + ~~~~~~~~~~~ +!!! error TS2307: Cannot find module './d/index' or its corresponding type declarations. + import {} from "./d/index.ts"; + ~~~~~~~~~~~~~~ +!!! error TS2691: An import path cannot end with a '.ts' extension. Consider importing './d/index.js' instead. + + import {} from "./e"; + ~~~~~ +!!! error TS2307: Cannot find module './e' or its corresponding type declarations. + \ No newline at end of file diff --git a/tests/baselines/reference/minimal_relative(noemit=false).js b/tests/baselines/reference/minimal_relative(noemit=false).js new file mode 100644 index 0000000000000..ca36c746501fb --- /dev/null +++ b/tests/baselines/reference/minimal_relative(noemit=false).js @@ -0,0 +1,58 @@ +//// [tests/cases/conformance/moduleResolution/minimal_relative.ts] //// + +//// [a.ts] +export {}; + +//// [b.ts] +export {}; + +//// [b.js] +export {}; + +//// [b.d.ts] +export {}; + +//// [c.ts] +export {}; + +//// [c.tsx] +export {}; + +//// [index.ts] +export {}; + +//// [e] +export {}; + +//// [main.ts] +import {} from "./a"; +import {} from "./a.js"; +import {} from "./a.ts"; + +import {} from "./b"; +import {} from "./b.js"; +import {} from "./b.ts"; +import {} from "./b.d.ts"; + +import {} from "./c.ts"; +import {} from "./c.tsx"; + +import {} from "./d"; +import {} from "./d/index"; +import {} from "./d/index.ts"; + +import {} from "./e"; + + +//// [a.js] +"use strict"; +exports.__esModule = true; +//// [b.js] +"use strict"; +exports.__esModule = true; +//// [index.js] +"use strict"; +exports.__esModule = true; +//// [main.js] +"use strict"; +exports.__esModule = true; diff --git a/tests/baselines/reference/minimal_relative(noemit=false).symbols b/tests/baselines/reference/minimal_relative(noemit=false).symbols new file mode 100644 index 0000000000000..42b5e186aa78d --- /dev/null +++ b/tests/baselines/reference/minimal_relative(noemit=false).symbols @@ -0,0 +1,38 @@ +=== /project/a.ts === +export {}; +No type information for this code. +No type information for this code.=== /project/b.ts === +export {}; +No type information for this code. +No type information for this code.=== /project/b.d.ts === +export {}; +No type information for this code. +No type information for this code.=== /project/c.ts === +export {}; +No type information for this code. +No type information for this code.=== /project/c.tsx === +export {}; +No type information for this code. +No type information for this code.=== /project/d/index.ts === +export {}; +No type information for this code. +No type information for this code.=== /project/main.ts === +import {} from "./a"; +No type information for this code.import {} from "./a.js"; +No type information for this code.import {} from "./a.ts"; +No type information for this code. +No type information for this code.import {} from "./b"; +No type information for this code.import {} from "./b.js"; +No type information for this code.import {} from "./b.ts"; +No type information for this code.import {} from "./b.d.ts"; +No type information for this code. +No type information for this code.import {} from "./c.ts"; +No type information for this code.import {} from "./c.tsx"; +No type information for this code. +No type information for this code.import {} from "./d"; +No type information for this code.import {} from "./d/index"; +No type information for this code.import {} from "./d/index.ts"; +No type information for this code. +No type information for this code.import {} from "./e"; +No type information for this code. +No type information for this code. \ No newline at end of file diff --git a/tests/baselines/reference/minimal_relative(noemit=false).trace.json b/tests/baselines/reference/minimal_relative(noemit=false).trace.json new file mode 100644 index 0000000000000..33784890cf65f --- /dev/null +++ b/tests/baselines/reference/minimal_relative(noemit=false).trace.json @@ -0,0 +1,57 @@ +[ + "======== Resolving module './a' from '/project/main.ts'. ========", + "Explicitly specified module resolution kind: 'Minimal'.", + "======== Module name './a' was not resolved. ========", + "======== Resolving module './a.js' from '/project/main.ts'. ========", + "Explicitly specified module resolution kind: 'Minimal'.", + "File name '/project/a.js' has a '.js' extension - stripping it.", + "File '/project/a.ts' exist - use it as a name resolution result.", + "======== Module name './a.js' was successfully resolved to '/project/a.ts'. ========", + "======== Resolving module './a.ts' from '/project/main.ts'. ========", + "Explicitly specified module resolution kind: 'Minimal'.", + "File name '/project/a.ts' has a '.ts' extension - stripping it.", + "File '/project/a.ts' exist - use it as a name resolution result.", + "======== Module name './a.ts' was successfully resolved to '/project/a.ts'. ========", + "======== Resolving module './b' from '/project/main.ts'. ========", + "Explicitly specified module resolution kind: 'Minimal'.", + "======== Module name './b' was not resolved. ========", + "======== Resolving module './b.js' from '/project/main.ts'. ========", + "Explicitly specified module resolution kind: 'Minimal'.", + "File name '/project/b.js' has a '.js' extension - stripping it.", + "File '/project/b.ts' exist - use it as a name resolution result.", + "======== Module name './b.js' was successfully resolved to '/project/b.ts'. ========", + "======== Resolving module './b.ts' from '/project/main.ts'. ========", + "Explicitly specified module resolution kind: 'Minimal'.", + "File name '/project/b.ts' has a '.ts' extension - stripping it.", + "File '/project/b.ts' exist - use it as a name resolution result.", + "======== Module name './b.ts' was successfully resolved to '/project/b.ts'. ========", + "======== Resolving module './b.d.ts' from '/project/main.ts'. ========", + "Explicitly specified module resolution kind: 'Minimal'.", + "File name '/project/b.d.ts' has a '.d.ts' extension - stripping it.", + "File '/project/b.d.ts' exist - use it as a name resolution result.", + "======== Module name './b.d.ts' was successfully resolved to '/project/b.d.ts'. ========", + "======== Resolving module './c.ts' from '/project/main.ts'. ========", + "Explicitly specified module resolution kind: 'Minimal'.", + "File name '/project/c.ts' has a '.ts' extension - stripping it.", + "File '/project/c.ts' exist - use it as a name resolution result.", + "======== Module name './c.ts' was successfully resolved to '/project/c.ts'. ========", + "======== Resolving module './c.tsx' from '/project/main.ts'. ========", + "Explicitly specified module resolution kind: 'Minimal'.", + "File name '/project/c.tsx' has a '.tsx' extension - stripping it.", + "File '/project/c.tsx' exist - use it as a name resolution result.", + "======== Module name './c.tsx' was successfully resolved to '/project/c.tsx'. ========", + "======== Resolving module './d' from '/project/main.ts'. ========", + "Explicitly specified module resolution kind: 'Minimal'.", + "======== Module name './d' was not resolved. ========", + "======== Resolving module './d/index' from '/project/main.ts'. ========", + "Explicitly specified module resolution kind: 'Minimal'.", + "======== Module name './d/index' was not resolved. ========", + "======== Resolving module './d/index.ts' from '/project/main.ts'. ========", + "Explicitly specified module resolution kind: 'Minimal'.", + "File name '/project/d/index.ts' has a '.ts' extension - stripping it.", + "File '/project/d/index.ts' exist - use it as a name resolution result.", + "======== Module name './d/index.ts' was successfully resolved to '/project/d/index.ts'. ========", + "======== Resolving module './e' from '/project/main.ts'. ========", + "Explicitly specified module resolution kind: 'Minimal'.", + "======== Module name './e' was not resolved. ========" +] \ No newline at end of file diff --git a/tests/baselines/reference/minimal_relative(noemit=false).types b/tests/baselines/reference/minimal_relative(noemit=false).types new file mode 100644 index 0000000000000..42b5e186aa78d --- /dev/null +++ b/tests/baselines/reference/minimal_relative(noemit=false).types @@ -0,0 +1,38 @@ +=== /project/a.ts === +export {}; +No type information for this code. +No type information for this code.=== /project/b.ts === +export {}; +No type information for this code. +No type information for this code.=== /project/b.d.ts === +export {}; +No type information for this code. +No type information for this code.=== /project/c.ts === +export {}; +No type information for this code. +No type information for this code.=== /project/c.tsx === +export {}; +No type information for this code. +No type information for this code.=== /project/d/index.ts === +export {}; +No type information for this code. +No type information for this code.=== /project/main.ts === +import {} from "./a"; +No type information for this code.import {} from "./a.js"; +No type information for this code.import {} from "./a.ts"; +No type information for this code. +No type information for this code.import {} from "./b"; +No type information for this code.import {} from "./b.js"; +No type information for this code.import {} from "./b.ts"; +No type information for this code.import {} from "./b.d.ts"; +No type information for this code. +No type information for this code.import {} from "./c.ts"; +No type information for this code.import {} from "./c.tsx"; +No type information for this code. +No type information for this code.import {} from "./d"; +No type information for this code.import {} from "./d/index"; +No type information for this code.import {} from "./d/index.ts"; +No type information for this code. +No type information for this code.import {} from "./e"; +No type information for this code. +No type information for this code. \ No newline at end of file diff --git a/tests/baselines/reference/minimal_relative(noemit=true).errors.txt b/tests/baselines/reference/minimal_relative(noemit=true).errors.txt new file mode 100644 index 0000000000000..7c405129a243d --- /dev/null +++ b/tests/baselines/reference/minimal_relative(noemit=true).errors.txt @@ -0,0 +1,75 @@ +error TS6231: Could not resolve the path '/project/e' with the extensions: '.ts', '.tsx', '.d.ts', '.cts', '.d.cts', '.mts', '.d.mts'. + The file is in the program because: + Root file specified for compilation +error TS6504: File '/project/b.js' is a JavaScript file. Did you mean to enable the 'allowJs' option? + The file is in the program because: + Root file specified for compilation +/project/main.ts(1,16): error TS2307: Cannot find module './a' or its corresponding type declarations. +/project/main.ts(5,16): error TS2307: Cannot find module './b' or its corresponding type declarations. +/project/main.ts(11,16): error TS6142: Module './c.tsx' was resolved to '/project/c.tsx', but '--jsx' is not set. +/project/main.ts(13,16): error TS2307: Cannot find module './d' or its corresponding type declarations. +/project/main.ts(14,16): error TS2307: Cannot find module './d/index' or its corresponding type declarations. +/project/main.ts(17,16): error TS2307: Cannot find module './e' or its corresponding type declarations. + + +!!! error TS6231: Could not resolve the path '/project/e' with the extensions: '.ts', '.tsx', '.d.ts', '.cts', '.d.cts', '.mts', '.d.mts'. +!!! error TS6231: The file is in the program because: +!!! error TS6231: Root file specified for compilation +!!! error TS6504: File '/project/b.js' is a JavaScript file. Did you mean to enable the 'allowJs' option? +!!! error TS6504: The file is in the program because: +!!! error TS6504: Root file specified for compilation +==== /project/a.ts (0 errors) ==== + export {}; + +==== /project/b.ts (0 errors) ==== + export {}; + +==== /project/b.js (0 errors) ==== + export {}; + +==== /project/b.d.ts (0 errors) ==== + export {}; + +==== /project/c.ts (0 errors) ==== + export {}; + +==== /project/c.tsx (0 errors) ==== + export {}; + +==== /project/d/index.ts (0 errors) ==== + export {}; + +==== /project/e (0 errors) ==== + export {}; + +==== /project/main.ts (6 errors) ==== + import {} from "./a"; + ~~~~~ +!!! error TS2307: Cannot find module './a' or its corresponding type declarations. + import {} from "./a.js"; + import {} from "./a.ts"; + + import {} from "./b"; + ~~~~~ +!!! error TS2307: Cannot find module './b' or its corresponding type declarations. + import {} from "./b.js"; + import {} from "./b.ts"; + import {} from "./b.d.ts"; + + import {} from "./c.ts"; + import {} from "./c.tsx"; + ~~~~~~~~~ +!!! error TS6142: Module './c.tsx' was resolved to '/project/c.tsx', but '--jsx' is not set. + + import {} from "./d"; + ~~~~~ +!!! error TS2307: Cannot find module './d' or its corresponding type declarations. + import {} from "./d/index"; + ~~~~~~~~~~~ +!!! error TS2307: Cannot find module './d/index' or its corresponding type declarations. + import {} from "./d/index.ts"; + + import {} from "./e"; + ~~~~~ +!!! error TS2307: Cannot find module './e' or its corresponding type declarations. + \ No newline at end of file diff --git a/tests/baselines/reference/minimal_relative(noemit=true).symbols b/tests/baselines/reference/minimal_relative(noemit=true).symbols new file mode 100644 index 0000000000000..42b5e186aa78d --- /dev/null +++ b/tests/baselines/reference/minimal_relative(noemit=true).symbols @@ -0,0 +1,38 @@ +=== /project/a.ts === +export {}; +No type information for this code. +No type information for this code.=== /project/b.ts === +export {}; +No type information for this code. +No type information for this code.=== /project/b.d.ts === +export {}; +No type information for this code. +No type information for this code.=== /project/c.ts === +export {}; +No type information for this code. +No type information for this code.=== /project/c.tsx === +export {}; +No type information for this code. +No type information for this code.=== /project/d/index.ts === +export {}; +No type information for this code. +No type information for this code.=== /project/main.ts === +import {} from "./a"; +No type information for this code.import {} from "./a.js"; +No type information for this code.import {} from "./a.ts"; +No type information for this code. +No type information for this code.import {} from "./b"; +No type information for this code.import {} from "./b.js"; +No type information for this code.import {} from "./b.ts"; +No type information for this code.import {} from "./b.d.ts"; +No type information for this code. +No type information for this code.import {} from "./c.ts"; +No type information for this code.import {} from "./c.tsx"; +No type information for this code. +No type information for this code.import {} from "./d"; +No type information for this code.import {} from "./d/index"; +No type information for this code.import {} from "./d/index.ts"; +No type information for this code. +No type information for this code.import {} from "./e"; +No type information for this code. +No type information for this code. \ No newline at end of file diff --git a/tests/baselines/reference/minimal_relative(noemit=true).trace.json b/tests/baselines/reference/minimal_relative(noemit=true).trace.json new file mode 100644 index 0000000000000..33784890cf65f --- /dev/null +++ b/tests/baselines/reference/minimal_relative(noemit=true).trace.json @@ -0,0 +1,57 @@ +[ + "======== Resolving module './a' from '/project/main.ts'. ========", + "Explicitly specified module resolution kind: 'Minimal'.", + "======== Module name './a' was not resolved. ========", + "======== Resolving module './a.js' from '/project/main.ts'. ========", + "Explicitly specified module resolution kind: 'Minimal'.", + "File name '/project/a.js' has a '.js' extension - stripping it.", + "File '/project/a.ts' exist - use it as a name resolution result.", + "======== Module name './a.js' was successfully resolved to '/project/a.ts'. ========", + "======== Resolving module './a.ts' from '/project/main.ts'. ========", + "Explicitly specified module resolution kind: 'Minimal'.", + "File name '/project/a.ts' has a '.ts' extension - stripping it.", + "File '/project/a.ts' exist - use it as a name resolution result.", + "======== Module name './a.ts' was successfully resolved to '/project/a.ts'. ========", + "======== Resolving module './b' from '/project/main.ts'. ========", + "Explicitly specified module resolution kind: 'Minimal'.", + "======== Module name './b' was not resolved. ========", + "======== Resolving module './b.js' from '/project/main.ts'. ========", + "Explicitly specified module resolution kind: 'Minimal'.", + "File name '/project/b.js' has a '.js' extension - stripping it.", + "File '/project/b.ts' exist - use it as a name resolution result.", + "======== Module name './b.js' was successfully resolved to '/project/b.ts'. ========", + "======== Resolving module './b.ts' from '/project/main.ts'. ========", + "Explicitly specified module resolution kind: 'Minimal'.", + "File name '/project/b.ts' has a '.ts' extension - stripping it.", + "File '/project/b.ts' exist - use it as a name resolution result.", + "======== Module name './b.ts' was successfully resolved to '/project/b.ts'. ========", + "======== Resolving module './b.d.ts' from '/project/main.ts'. ========", + "Explicitly specified module resolution kind: 'Minimal'.", + "File name '/project/b.d.ts' has a '.d.ts' extension - stripping it.", + "File '/project/b.d.ts' exist - use it as a name resolution result.", + "======== Module name './b.d.ts' was successfully resolved to '/project/b.d.ts'. ========", + "======== Resolving module './c.ts' from '/project/main.ts'. ========", + "Explicitly specified module resolution kind: 'Minimal'.", + "File name '/project/c.ts' has a '.ts' extension - stripping it.", + "File '/project/c.ts' exist - use it as a name resolution result.", + "======== Module name './c.ts' was successfully resolved to '/project/c.ts'. ========", + "======== Resolving module './c.tsx' from '/project/main.ts'. ========", + "Explicitly specified module resolution kind: 'Minimal'.", + "File name '/project/c.tsx' has a '.tsx' extension - stripping it.", + "File '/project/c.tsx' exist - use it as a name resolution result.", + "======== Module name './c.tsx' was successfully resolved to '/project/c.tsx'. ========", + "======== Resolving module './d' from '/project/main.ts'. ========", + "Explicitly specified module resolution kind: 'Minimal'.", + "======== Module name './d' was not resolved. ========", + "======== Resolving module './d/index' from '/project/main.ts'. ========", + "Explicitly specified module resolution kind: 'Minimal'.", + "======== Module name './d/index' was not resolved. ========", + "======== Resolving module './d/index.ts' from '/project/main.ts'. ========", + "Explicitly specified module resolution kind: 'Minimal'.", + "File name '/project/d/index.ts' has a '.ts' extension - stripping it.", + "File '/project/d/index.ts' exist - use it as a name resolution result.", + "======== Module name './d/index.ts' was successfully resolved to '/project/d/index.ts'. ========", + "======== Resolving module './e' from '/project/main.ts'. ========", + "Explicitly specified module resolution kind: 'Minimal'.", + "======== Module name './e' was not resolved. ========" +] \ No newline at end of file diff --git a/tests/baselines/reference/minimal_relative(noemit=true).types b/tests/baselines/reference/minimal_relative(noemit=true).types new file mode 100644 index 0000000000000..42b5e186aa78d --- /dev/null +++ b/tests/baselines/reference/minimal_relative(noemit=true).types @@ -0,0 +1,38 @@ +=== /project/a.ts === +export {}; +No type information for this code. +No type information for this code.=== /project/b.ts === +export {}; +No type information for this code. +No type information for this code.=== /project/b.d.ts === +export {}; +No type information for this code. +No type information for this code.=== /project/c.ts === +export {}; +No type information for this code. +No type information for this code.=== /project/c.tsx === +export {}; +No type information for this code. +No type information for this code.=== /project/d/index.ts === +export {}; +No type information for this code. +No type information for this code.=== /project/main.ts === +import {} from "./a"; +No type information for this code.import {} from "./a.js"; +No type information for this code.import {} from "./a.ts"; +No type information for this code. +No type information for this code.import {} from "./b"; +No type information for this code.import {} from "./b.js"; +No type information for this code.import {} from "./b.ts"; +No type information for this code.import {} from "./b.d.ts"; +No type information for this code. +No type information for this code.import {} from "./c.ts"; +No type information for this code.import {} from "./c.tsx"; +No type information for this code. +No type information for this code.import {} from "./d"; +No type information for this code.import {} from "./d/index"; +No type information for this code.import {} from "./d/index.ts"; +No type information for this code. +No type information for this code.import {} from "./e"; +No type information for this code. +No type information for this code. \ No newline at end of file From 2421cf58ab4527288c26668e0e1e39e19a598dfe Mon Sep 17 00:00:00 2001 From: Andrew Branch Date: Fri, 29 Jul 2022 13:46:17 -0700 Subject: [PATCH 03/14] Add non-relative tests --- .../reference/minimal_nonRelative.errors.txt | 18 +++++ .../reference/minimal_nonRelative.trace.json | 14 ++++ .../minimal_pathsAndBaseUrl.errors.txt | 38 ++++++++++ .../minimal_pathsAndBaseUrl.trace.json | 73 +++++++++++++++++++ .../moduleResolution/minimal_nonRelative.ts | 14 ++++ .../minimal_pathsAndBaseUrl.ts | 35 +++++++++ 6 files changed, 192 insertions(+) create mode 100644 tests/baselines/reference/minimal_nonRelative.errors.txt create mode 100644 tests/baselines/reference/minimal_nonRelative.trace.json create mode 100644 tests/baselines/reference/minimal_pathsAndBaseUrl.errors.txt create mode 100644 tests/baselines/reference/minimal_pathsAndBaseUrl.trace.json create mode 100644 tests/cases/conformance/moduleResolution/minimal_nonRelative.ts create mode 100644 tests/cases/conformance/moduleResolution/minimal_pathsAndBaseUrl.ts diff --git a/tests/baselines/reference/minimal_nonRelative.errors.txt b/tests/baselines/reference/minimal_nonRelative.errors.txt new file mode 100644 index 0000000000000..9229d86fe597c --- /dev/null +++ b/tests/baselines/reference/minimal_nonRelative.errors.txt @@ -0,0 +1,18 @@ +/main.ts(1,16): error TS2307: Cannot find module 'foo' or its corresponding type declarations. +/main.ts(2,16): error TS2307: Cannot find module 'bar' or its corresponding type declarations. + + +==== /node_modules/@types/foo/index.d.ts (0 errors) ==== + export {}; + +==== /node_modules/bar/index.d.ts (0 errors) ==== + export {}; + +==== /main.ts (2 errors) ==== + import {} from "foo"; + ~~~~~ +!!! error TS2307: Cannot find module 'foo' or its corresponding type declarations. + import {} from "bar"; + ~~~~~ +!!! error TS2307: Cannot find module 'bar' or its corresponding type declarations. + \ No newline at end of file diff --git a/tests/baselines/reference/minimal_nonRelative.trace.json b/tests/baselines/reference/minimal_nonRelative.trace.json new file mode 100644 index 0000000000000..769cebfe4261f --- /dev/null +++ b/tests/baselines/reference/minimal_nonRelative.trace.json @@ -0,0 +1,14 @@ +[ + "======== Resolving module 'foo' from '/main.ts'. ========", + "Explicitly specified module resolution kind: 'Minimal'.", + "======== Module name 'foo' was not resolved. ========", + "======== Resolving module 'bar' from '/main.ts'. ========", + "Explicitly specified module resolution kind: 'Minimal'.", + "======== Module name 'bar' was not resolved. ========", + "======== Resolving type reference directive 'foo', containing file '__inferred type names__.ts', root directory '/node_modules/@types'. ========", + "Resolving with primary search path '/node_modules/@types'.", + "File '/node_modules/@types/foo/package.json' does not exist.", + "File '/node_modules/@types/foo/index.d.ts' exist - use it as a name resolution result.", + "Resolving real path for '/node_modules/@types/foo/index.d.ts', result '/node_modules/@types/foo/index.d.ts'.", + "======== Type reference directive 'foo' was successfully resolved to '/node_modules/@types/foo/index.d.ts', primary: true. ========" +] \ No newline at end of file diff --git a/tests/baselines/reference/minimal_pathsAndBaseUrl.errors.txt b/tests/baselines/reference/minimal_pathsAndBaseUrl.errors.txt new file mode 100644 index 0000000000000..a1b7074087d13 --- /dev/null +++ b/tests/baselines/reference/minimal_pathsAndBaseUrl.errors.txt @@ -0,0 +1,38 @@ +/main.ts(4,16): error TS2307: Cannot find module 'hello' or its corresponding type declarations. + + +==== /tsconfig.json (0 errors) ==== + { + "compilerOptions": { + "moduleResolution": "minimal", + "noEmit": true, + "baseUrl": ".", + "paths": { + "*": [ + "*", + "./vendor/*", + "./vendor/*/index.d.ts", + "./apps/*" + ] + } + } + } + +==== /vendor/foo/index.d.ts (0 errors) ==== + export {}; + +==== /apps/hello.ts (0 errors) ==== + export {}; + +==== /foo.ts (0 errors) ==== + export {}; + +==== /main.ts (1 errors) ==== + import {} from "foo"; + import {} from "foo/index.js"; + import {} from "hello.ts"; + import {} from "hello"; + ~~~~~~~ +!!! error TS2307: Cannot find module 'hello' or its corresponding type declarations. + import {} from "foo.js"; + \ No newline at end of file diff --git a/tests/baselines/reference/minimal_pathsAndBaseUrl.trace.json b/tests/baselines/reference/minimal_pathsAndBaseUrl.trace.json new file mode 100644 index 0000000000000..9d8aa1165d31a --- /dev/null +++ b/tests/baselines/reference/minimal_pathsAndBaseUrl.trace.json @@ -0,0 +1,73 @@ +[ + "======== Resolving module 'foo' from '/main.ts'. ========", + "Explicitly specified module resolution kind: 'Minimal'.", + "'baseUrl' option is set to '/', using this value to resolve non-relative module name 'foo'.", + "'paths' option is specified, looking for a pattern to match module name 'foo'.", + "Module name 'foo', matched pattern '*'.", + "Trying substitution '*', candidate module location: 'foo'.", + "Trying substitution './vendor/*', candidate module location: './vendor/foo'.", + "Trying substitution './vendor/*/index.d.ts', candidate module location: './vendor/foo/index.d.ts'.", + "File '/vendor/foo/index.d.ts' exist - use it as a name resolution result.", + "======== Module name 'foo' was successfully resolved to '/vendor/foo/index.d.ts'. ========", + "======== Resolving module 'foo/index.js' from '/main.ts'. ========", + "Explicitly specified module resolution kind: 'Minimal'.", + "'baseUrl' option is set to '/', using this value to resolve non-relative module name 'foo/index.js'.", + "'paths' option is specified, looking for a pattern to match module name 'foo/index.js'.", + "Module name 'foo/index.js', matched pattern '*'.", + "Trying substitution '*', candidate module location: 'foo/index.js'.", + "File name '/foo/index.js' has a '.js' extension - stripping it.", + "Trying substitution './vendor/*', candidate module location: './vendor/foo/index.js'.", + "File name '/vendor/foo/index.js' has a '.js' extension - stripping it.", + "File '/vendor/foo/index.ts' does not exist.", + "File '/vendor/foo/index.tsx' does not exist.", + "File '/vendor/foo/index.d.ts' exist - use it as a name resolution result.", + "======== Module name 'foo/index.js' was successfully resolved to '/vendor/foo/index.d.ts'. ========", + "======== Resolving module 'hello.ts' from '/main.ts'. ========", + "Explicitly specified module resolution kind: 'Minimal'.", + "'baseUrl' option is set to '/', using this value to resolve non-relative module name 'hello.ts'.", + "'paths' option is specified, looking for a pattern to match module name 'hello.ts'.", + "Module name 'hello.ts', matched pattern '*'.", + "Trying substitution '*', candidate module location: 'hello.ts'.", + "File name '/hello.ts' has a '.ts' extension - stripping it.", + "File '/hello.ts' does not exist.", + "Trying substitution './vendor/*', candidate module location: './vendor/hello.ts'.", + "File name '/vendor/hello.ts' has a '.ts' extension - stripping it.", + "File '/vendor/hello.ts' does not exist.", + "Trying substitution './vendor/*/index.d.ts', candidate module location: './vendor/hello.ts/index.d.ts'.", + "File '/vendor/hello.ts/index.d.ts' does not exist.", + "File name '/vendor/hello.ts/index.d.ts' has a '.d.ts' extension - stripping it.", + "Trying substitution './apps/*', candidate module location: './apps/hello.ts'.", + "File name '/apps/hello.ts' has a '.ts' extension - stripping it.", + "File '/apps/hello.ts' exist - use it as a name resolution result.", + "======== Module name 'hello.ts' was successfully resolved to '/apps/hello.ts'. ========", + "======== Resolving module 'hello' from '/main.ts'. ========", + "Explicitly specified module resolution kind: 'Minimal'.", + "'baseUrl' option is set to '/', using this value to resolve non-relative module name 'hello'.", + "'paths' option is specified, looking for a pattern to match module name 'hello'.", + "Module name 'hello', matched pattern '*'.", + "Trying substitution '*', candidate module location: 'hello'.", + "Trying substitution './vendor/*', candidate module location: './vendor/hello'.", + "Trying substitution './vendor/*/index.d.ts', candidate module location: './vendor/hello/index.d.ts'.", + "File '/vendor/hello/index.d.ts' does not exist.", + "File name '/vendor/hello/index.d.ts' has a '.d.ts' extension - stripping it.", + "Trying substitution './apps/*', candidate module location: './apps/hello'.", + "'baseUrl' option is set to '/', using this value to resolve non-relative module name 'hello'.", + "'paths' option is specified, looking for a pattern to match module name 'hello'.", + "Module name 'hello', matched pattern '*'.", + "Trying substitution '*', candidate module location: 'hello'.", + "Trying substitution './vendor/*', candidate module location: './vendor/hello'.", + "Trying substitution './vendor/*/index.d.ts', candidate module location: './vendor/hello/index.d.ts'.", + "File '/vendor/hello/index.d.ts' does not exist.", + "File name '/vendor/hello/index.d.ts' has a '.d.ts' extension - stripping it.", + "Trying substitution './apps/*', candidate module location: './apps/hello'.", + "======== Module name 'hello' was not resolved. ========", + "======== Resolving module 'foo.js' from '/main.ts'. ========", + "Explicitly specified module resolution kind: 'Minimal'.", + "'baseUrl' option is set to '/', using this value to resolve non-relative module name 'foo.js'.", + "'paths' option is specified, looking for a pattern to match module name 'foo.js'.", + "Module name 'foo.js', matched pattern '*'.", + "Trying substitution '*', candidate module location: 'foo.js'.", + "File name '/foo.js' has a '.js' extension - stripping it.", + "File '/foo.ts' exist - use it as a name resolution result.", + "======== Module name 'foo.js' was successfully resolved to '/foo.ts'. ========" +] \ No newline at end of file diff --git a/tests/cases/conformance/moduleResolution/minimal_nonRelative.ts b/tests/cases/conformance/moduleResolution/minimal_nonRelative.ts new file mode 100644 index 0000000000000..e055574fc2739 --- /dev/null +++ b/tests/cases/conformance/moduleResolution/minimal_nonRelative.ts @@ -0,0 +1,14 @@ +// @moduleResolution: minimal +// @noEmit: true +// @traceResolution: true +// @noTypesAndSymbols: true + +// @Filename: /node_modules/@types/foo/index.d.ts +export {}; + +// @Filename: /node_modules/bar/index.d.ts +export {}; + +// @Filename: /main.ts +import {} from "foo"; +import {} from "bar"; diff --git a/tests/cases/conformance/moduleResolution/minimal_pathsAndBaseUrl.ts b/tests/cases/conformance/moduleResolution/minimal_pathsAndBaseUrl.ts new file mode 100644 index 0000000000000..a7fb1a2c4ebb6 --- /dev/null +++ b/tests/cases/conformance/moduleResolution/minimal_pathsAndBaseUrl.ts @@ -0,0 +1,35 @@ +// @traceResolution: true +// @noTypesAndSymbols: true + +// @Filename: /tsconfig.json +{ + "compilerOptions": { + "moduleResolution": "minimal", + "noEmit": true, + "baseUrl": ".", + "paths": { + "*": [ + "*", + "./vendor/*", + "./vendor/*/index.d.ts", + "./apps/*" + ] + } + } +} + +// @Filename: /vendor/foo/index.d.ts +export {}; + +// @Filename: /apps/hello.ts +export {}; + +// @Filename: /foo.ts +export {}; + +// @Filename: /main.ts +import {} from "foo"; +import {} from "foo/index.js"; +import {} from "hello.ts"; +import {} from "hello"; +import {} from "foo.js"; From 660026e966000df368516a156f53e3652f913ef2 Mon Sep 17 00:00:00 2001 From: Andrew Branch Date: Fri, 29 Jul 2022 15:02:41 -0700 Subject: [PATCH 04/14] Add error for importing from declaration file --- src/compiler/checker.ts | 24 +++++++++++++++---- src/compiler/diagnosticMessages.json | 4 ++++ .../minimal_relative(noemit=false).errors.txt | 19 ++++++++------- .../minimal_relative(noemit=false).js | 1 + .../minimal_relative(noemit=false).symbols | 1 + .../minimal_relative(noemit=false).types | 1 + .../minimal_relative(noemit=true).errors.txt | 14 +++++++---- .../minimal_relative(noemit=true).symbols | 1 + .../minimal_relative(noemit=true).types | 1 + .../moduleResolution/minimal_relative.ts | 1 + 10 files changed, 49 insertions(+), 18 deletions(-) diff --git a/src/compiler/checker.ts b/src/compiler/checker.ts index bbcb97e7c881f..eb5d398dc4c35 100644 --- a/src/compiler/checker.ts +++ b/src/compiler/checker.ts @@ -3570,10 +3570,23 @@ namespace ts { if (resolutionDiagnostic) { error(errorNode, resolutionDiagnostic, moduleReference, resolvedModule.resolvedFileName); } - if (resolvedModule.resolvedUsingTsExtension && !shouldAllowTsExtension(compilerOptions)) { + + if (resolvedModule.resolvedUsingTsExtension && isDeclarationFileName(moduleReference)) { + const importOrExport = + findAncestor(location, isImportDeclaration)?.importClause || + findAncestor(location, or(isImportEqualsDeclaration, isExportDeclaration)) as ImportEqualsDeclaration | ExportDeclaration | undefined; + if (importOrExport && !importOrExport.isTypeOnly || findAncestor(location, isImportCall)) { + error( + errorNode, + Diagnostics.A_declaration_file_cannot_be_imported_without_import_type_Did_you_mean_to_import_an_implementation_file_0_instead, + getSuggestedImportSource(Debug.checkDefined(tryExtractTSExtension(moduleReference)))); + } + } + else if (resolvedModule.resolvedUsingTsExtension && !shouldAllowTsExtension(compilerOptions)) { const tsExtension = Debug.checkDefined(tryExtractTSExtension(moduleReference)); errorOnTSExtensionImport(tsExtension); } + if (sourceFile.symbol) { if (resolvedModule.isExternalLibraryImport && !resolutionExtensionIsTSOrJson(resolvedModule.extension)) { errorOnImplicitAnyModule(/*isError*/ false, errorNode, resolvedModule, moduleReference); @@ -3675,16 +3688,19 @@ namespace ts { function errorOnTSExtensionImport(tsExtension: string) { const diag = Diagnostics.An_import_path_cannot_end_with_a_0_extension_Consider_importing_1_instead; + error(errorNode, diag, tsExtension, getSuggestedImportSource(tsExtension)); + } + + function getSuggestedImportSource(tsExtension: string) { const importSourceWithoutExtension = removeExtension(moduleReference, tsExtension); - let replacedImportSource = importSourceWithoutExtension; /** * Direct users to import source with .js extension if outputting an ES module. * @see https://github.com/microsoft/TypeScript/issues/42151 */ if (moduleKind >= ModuleKind.ES2015 || getEmitModuleResolutionKind(compilerOptions) === ModuleResolutionKind.Minimal) { - replacedImportSource += tsExtension === Extension.Mts ? ".mjs" : tsExtension === Extension.Cts ? ".cjs" : ".js"; + return importSourceWithoutExtension + (tsExtension === Extension.Mts ? ".mjs" : tsExtension === Extension.Cts ? ".cjs" : ".js"); } - error(errorNode, diag, tsExtension, replacedImportSource); + return importSourceWithoutExtension; } } diff --git a/src/compiler/diagnosticMessages.json b/src/compiler/diagnosticMessages.json index dc22ff2b4b7e3..718d8845e85bc 100644 --- a/src/compiler/diagnosticMessages.json +++ b/src/compiler/diagnosticMessages.json @@ -3515,6 +3515,10 @@ "category": "Error", "code": 2844 }, + "A declaration file cannot be imported without 'import type'. Did you mean to import an implementation file '{0}' instead?": { + "category": "Error", + "code": 2845 + }, "Import declaration '{0}' is using private name '{1}'.": { "category": "Error", diff --git a/tests/baselines/reference/minimal_relative(noemit=false).errors.txt b/tests/baselines/reference/minimal_relative(noemit=false).errors.txt index fde1ffef20104..04640dbdd2934 100644 --- a/tests/baselines/reference/minimal_relative(noemit=false).errors.txt +++ b/tests/baselines/reference/minimal_relative(noemit=false).errors.txt @@ -9,14 +9,14 @@ error TS6504: File '/project/b.js' is a JavaScript file. Did you mean to enable /project/main.ts(3,16): error TS2691: An import path cannot end with a '.ts' extension. Consider importing './a.js' instead. /project/main.ts(5,16): error TS2307: Cannot find module './b' or its corresponding type declarations. /project/main.ts(7,16): error TS2691: An import path cannot end with a '.ts' extension. Consider importing './b.js' instead. -/project/main.ts(8,16): error TS2691: An import path cannot end with a '.d.ts' extension. Consider importing './b.js' instead. -/project/main.ts(10,16): error TS2691: An import path cannot end with a '.ts' extension. Consider importing './c.js' instead. -/project/main.ts(11,16): error TS2691: An import path cannot end with a '.tsx' extension. Consider importing './c.js' instead. -/project/main.ts(11,16): error TS6142: Module './c.tsx' was resolved to '/project/c.tsx', but '--jsx' is not set. -/project/main.ts(13,16): error TS2307: Cannot find module './d' or its corresponding type declarations. -/project/main.ts(14,16): error TS2307: Cannot find module './d/index' or its corresponding type declarations. -/project/main.ts(15,16): error TS2691: An import path cannot end with a '.ts' extension. Consider importing './d/index.js' instead. -/project/main.ts(17,16): error TS2307: Cannot find module './e' or its corresponding type declarations. +/project/main.ts(8,16): error TS2845: A declaration file cannot be imported without 'import type'. Did you mean to import an implementation file './b.js' instead? +/project/main.ts(11,16): error TS2691: An import path cannot end with a '.ts' extension. Consider importing './c.js' instead. +/project/main.ts(12,16): error TS2691: An import path cannot end with a '.tsx' extension. Consider importing './c.js' instead. +/project/main.ts(12,16): error TS6142: Module './c.tsx' was resolved to '/project/c.tsx', but '--jsx' is not set. +/project/main.ts(14,16): error TS2307: Cannot find module './d' or its corresponding type declarations. +/project/main.ts(15,16): error TS2307: Cannot find module './d/index' or its corresponding type declarations. +/project/main.ts(16,16): error TS2691: An import path cannot end with a '.ts' extension. Consider importing './d/index.js' instead. +/project/main.ts(18,16): error TS2307: Cannot find module './e' or its corresponding type declarations. !!! error TS5056: Cannot write file 'dist/c.js' because it would be overwritten by multiple input files. @@ -68,7 +68,8 @@ error TS6504: File '/project/b.js' is a JavaScript file. Did you mean to enable !!! error TS2691: An import path cannot end with a '.ts' extension. Consider importing './b.js' instead. import {} from "./b.d.ts"; ~~~~~~~~~~ -!!! error TS2691: An import path cannot end with a '.d.ts' extension. Consider importing './b.js' instead. +!!! error TS2845: A declaration file cannot be imported without 'import type'. Did you mean to import an implementation file './b.js' instead? + import type {} from "./b.d.ts"; import {} from "./c.ts"; ~~~~~~~~ diff --git a/tests/baselines/reference/minimal_relative(noemit=false).js b/tests/baselines/reference/minimal_relative(noemit=false).js index ca36c746501fb..4044dbad4adb8 100644 --- a/tests/baselines/reference/minimal_relative(noemit=false).js +++ b/tests/baselines/reference/minimal_relative(noemit=false).js @@ -33,6 +33,7 @@ import {} from "./b"; import {} from "./b.js"; import {} from "./b.ts"; import {} from "./b.d.ts"; +import type {} from "./b.d.ts"; import {} from "./c.ts"; import {} from "./c.tsx"; diff --git a/tests/baselines/reference/minimal_relative(noemit=false).symbols b/tests/baselines/reference/minimal_relative(noemit=false).symbols index 42b5e186aa78d..13a097c71c1b7 100644 --- a/tests/baselines/reference/minimal_relative(noemit=false).symbols +++ b/tests/baselines/reference/minimal_relative(noemit=false).symbols @@ -25,6 +25,7 @@ No type information for this code.import {} from "./b"; No type information for this code.import {} from "./b.js"; No type information for this code.import {} from "./b.ts"; No type information for this code.import {} from "./b.d.ts"; +No type information for this code.import type {} from "./b.d.ts"; No type information for this code. No type information for this code.import {} from "./c.ts"; No type information for this code.import {} from "./c.tsx"; diff --git a/tests/baselines/reference/minimal_relative(noemit=false).types b/tests/baselines/reference/minimal_relative(noemit=false).types index 42b5e186aa78d..13a097c71c1b7 100644 --- a/tests/baselines/reference/minimal_relative(noemit=false).types +++ b/tests/baselines/reference/minimal_relative(noemit=false).types @@ -25,6 +25,7 @@ No type information for this code.import {} from "./b"; No type information for this code.import {} from "./b.js"; No type information for this code.import {} from "./b.ts"; No type information for this code.import {} from "./b.d.ts"; +No type information for this code.import type {} from "./b.d.ts"; No type information for this code. No type information for this code.import {} from "./c.ts"; No type information for this code.import {} from "./c.tsx"; diff --git a/tests/baselines/reference/minimal_relative(noemit=true).errors.txt b/tests/baselines/reference/minimal_relative(noemit=true).errors.txt index 7c405129a243d..b5584db1abe5f 100644 --- a/tests/baselines/reference/minimal_relative(noemit=true).errors.txt +++ b/tests/baselines/reference/minimal_relative(noemit=true).errors.txt @@ -6,10 +6,11 @@ error TS6504: File '/project/b.js' is a JavaScript file. Did you mean to enable Root file specified for compilation /project/main.ts(1,16): error TS2307: Cannot find module './a' or its corresponding type declarations. /project/main.ts(5,16): error TS2307: Cannot find module './b' or its corresponding type declarations. -/project/main.ts(11,16): error TS6142: Module './c.tsx' was resolved to '/project/c.tsx', but '--jsx' is not set. -/project/main.ts(13,16): error TS2307: Cannot find module './d' or its corresponding type declarations. -/project/main.ts(14,16): error TS2307: Cannot find module './d/index' or its corresponding type declarations. -/project/main.ts(17,16): error TS2307: Cannot find module './e' or its corresponding type declarations. +/project/main.ts(8,16): error TS2845: A declaration file cannot be imported without 'import type'. Did you mean to import an implementation file './b.js' instead? +/project/main.ts(12,16): error TS6142: Module './c.tsx' was resolved to '/project/c.tsx', but '--jsx' is not set. +/project/main.ts(14,16): error TS2307: Cannot find module './d' or its corresponding type declarations. +/project/main.ts(15,16): error TS2307: Cannot find module './d/index' or its corresponding type declarations. +/project/main.ts(18,16): error TS2307: Cannot find module './e' or its corresponding type declarations. !!! error TS6231: Could not resolve the path '/project/e' with the extensions: '.ts', '.tsx', '.d.ts', '.cts', '.d.cts', '.mts', '.d.mts'. @@ -42,7 +43,7 @@ error TS6504: File '/project/b.js' is a JavaScript file. Did you mean to enable ==== /project/e (0 errors) ==== export {}; -==== /project/main.ts (6 errors) ==== +==== /project/main.ts (7 errors) ==== import {} from "./a"; ~~~~~ !!! error TS2307: Cannot find module './a' or its corresponding type declarations. @@ -55,6 +56,9 @@ error TS6504: File '/project/b.js' is a JavaScript file. Did you mean to enable import {} from "./b.js"; import {} from "./b.ts"; import {} from "./b.d.ts"; + ~~~~~~~~~~ +!!! error TS2845: A declaration file cannot be imported without 'import type'. Did you mean to import an implementation file './b.js' instead? + import type {} from "./b.d.ts"; import {} from "./c.ts"; import {} from "./c.tsx"; diff --git a/tests/baselines/reference/minimal_relative(noemit=true).symbols b/tests/baselines/reference/minimal_relative(noemit=true).symbols index 42b5e186aa78d..13a097c71c1b7 100644 --- a/tests/baselines/reference/minimal_relative(noemit=true).symbols +++ b/tests/baselines/reference/minimal_relative(noemit=true).symbols @@ -25,6 +25,7 @@ No type information for this code.import {} from "./b"; No type information for this code.import {} from "./b.js"; No type information for this code.import {} from "./b.ts"; No type information for this code.import {} from "./b.d.ts"; +No type information for this code.import type {} from "./b.d.ts"; No type information for this code. No type information for this code.import {} from "./c.ts"; No type information for this code.import {} from "./c.tsx"; diff --git a/tests/baselines/reference/minimal_relative(noemit=true).types b/tests/baselines/reference/minimal_relative(noemit=true).types index 42b5e186aa78d..13a097c71c1b7 100644 --- a/tests/baselines/reference/minimal_relative(noemit=true).types +++ b/tests/baselines/reference/minimal_relative(noemit=true).types @@ -25,6 +25,7 @@ No type information for this code.import {} from "./b"; No type information for this code.import {} from "./b.js"; No type information for this code.import {} from "./b.ts"; No type information for this code.import {} from "./b.d.ts"; +No type information for this code.import type {} from "./b.d.ts"; No type information for this code. No type information for this code.import {} from "./c.ts"; No type information for this code.import {} from "./c.tsx"; diff --git a/tests/cases/conformance/moduleResolution/minimal_relative.ts b/tests/cases/conformance/moduleResolution/minimal_relative.ts index 48fda19b7c3eb..b3428c435e48a 100644 --- a/tests/cases/conformance/moduleResolution/minimal_relative.ts +++ b/tests/cases/conformance/moduleResolution/minimal_relative.ts @@ -36,6 +36,7 @@ import {} from "./b"; import {} from "./b.js"; import {} from "./b.ts"; import {} from "./b.d.ts"; +import type {} from "./b.d.ts"; import {} from "./c.ts"; import {} from "./c.tsx"; From f49a36851f8425d957a6b3259d4cd79479f6e605 Mon Sep 17 00:00:00 2001 From: Andrew Branch Date: Wed, 14 Sep 2022 14:05:41 -0700 Subject: [PATCH 05/14] Update unit test --- src/testRunner/unittests/config/commandLineParsing.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/testRunner/unittests/config/commandLineParsing.ts b/src/testRunner/unittests/config/commandLineParsing.ts index e2b48977106b6..07ecbb7393328 100644 --- a/src/testRunner/unittests/config/commandLineParsing.ts +++ b/src/testRunner/unittests/config/commandLineParsing.ts @@ -237,7 +237,7 @@ namespace ts { start: undefined, length: undefined, }, { - messageText: "Argument for '--moduleResolution' option must be: 'node', 'classic', 'node16', 'nodenext'.", + messageText: "Argument for '--moduleResolution' option must be: 'node', 'classic', 'node16', 'nodenext', 'minimal'.", category: Diagnostics.Argument_for_0_option_must_be_Colon_1.category, code: Diagnostics.Argument_for_0_option_must_be_Colon_1.code, From af03675a085d6b799b8b7ce7e8f6f4baf4008ea9 Mon Sep 17 00:00:00 2001 From: Andrew Branch Date: Wed, 14 Sep 2022 16:52:42 -0700 Subject: [PATCH 06/14] Add explicit flag for importing from .ts extensions --- src/compiler/checker.ts | 4 +- src/compiler/commandLineParser.ts | 8 ++ src/compiler/diagnosticMessages.json | 16 ++- src/compiler/moduleNameResolver.ts | 8 +- src/compiler/program.ts | 4 + src/compiler/types.ts | 1 + src/testRunner/compilerRunner.ts | 1 + .../minimal_pathsAndBaseUrl.errors.txt | 1 + ...sextensions=false,noemit=false).errors.txt | 107 ++++++++++++++++++ ...portingtsextensions=false,noemit=false).js | 64 +++++++++++ ...ngtsextensions=false,noemit=false).symbols | 44 +++++++ ...sextensions=false,noemit=false).trace.json | 68 +++++++++++ ...tingtsextensions=false,noemit=false).types | 44 +++++++ ...tsextensions=false,noemit=true).errors.txt | 105 +++++++++++++++++ ...ingtsextensions=false,noemit=true).symbols | 44 +++++++ ...tsextensions=false,noemit=true).trace.json | 68 +++++++++++ ...rtingtsextensions=false,noemit=true).types | 44 +++++++ ...tsextensions=true,noemit=false).errors.txt | 94 +++++++++++++++ ...mportingtsextensions=true,noemit=false).js | 64 +++++++++++ ...ingtsextensions=true,noemit=false).symbols | 44 +++++++ ...tsextensions=true,noemit=false).trace.json | 68 +++++++++++ ...rtingtsextensions=true,noemit=false).types | 44 +++++++ ...gtsextensions=true,noemit=true).errors.txt | 90 +++++++++++++++ ...tingtsextensions=true,noemit=true).symbols | 44 +++++++ ...gtsextensions=true,noemit=true).trace.json | 68 +++++++++++ ...ortingtsextensions=true,noemit=true).types | 44 +++++++ .../minimal_pathsAndBaseUrl.ts | 1 + .../moduleResolution/minimal_relative.ts | 6 + 28 files changed, 1190 insertions(+), 8 deletions(-) create mode 100644 tests/baselines/reference/minimal_relative(allowimportingtsextensions=false,noemit=false).errors.txt create mode 100644 tests/baselines/reference/minimal_relative(allowimportingtsextensions=false,noemit=false).js create mode 100644 tests/baselines/reference/minimal_relative(allowimportingtsextensions=false,noemit=false).symbols create mode 100644 tests/baselines/reference/minimal_relative(allowimportingtsextensions=false,noemit=false).trace.json create mode 100644 tests/baselines/reference/minimal_relative(allowimportingtsextensions=false,noemit=false).types create mode 100644 tests/baselines/reference/minimal_relative(allowimportingtsextensions=false,noemit=true).errors.txt create mode 100644 tests/baselines/reference/minimal_relative(allowimportingtsextensions=false,noemit=true).symbols create mode 100644 tests/baselines/reference/minimal_relative(allowimportingtsextensions=false,noemit=true).trace.json create mode 100644 tests/baselines/reference/minimal_relative(allowimportingtsextensions=false,noemit=true).types create mode 100644 tests/baselines/reference/minimal_relative(allowimportingtsextensions=true,noemit=false).errors.txt create mode 100644 tests/baselines/reference/minimal_relative(allowimportingtsextensions=true,noemit=false).js create mode 100644 tests/baselines/reference/minimal_relative(allowimportingtsextensions=true,noemit=false).symbols create mode 100644 tests/baselines/reference/minimal_relative(allowimportingtsextensions=true,noemit=false).trace.json create mode 100644 tests/baselines/reference/minimal_relative(allowimportingtsextensions=true,noemit=false).types create mode 100644 tests/baselines/reference/minimal_relative(allowimportingtsextensions=true,noemit=true).errors.txt create mode 100644 tests/baselines/reference/minimal_relative(allowimportingtsextensions=true,noemit=true).symbols create mode 100644 tests/baselines/reference/minimal_relative(allowimportingtsextensions=true,noemit=true).trace.json create mode 100644 tests/baselines/reference/minimal_relative(allowimportingtsextensions=true,noemit=true).types diff --git a/src/compiler/checker.ts b/src/compiler/checker.ts index d7d6c3148b9e4..36e21f63f35d5 100644 --- a/src/compiler/checker.ts +++ b/src/compiler/checker.ts @@ -3620,9 +3620,9 @@ namespace ts { getSuggestedImportSource(Debug.checkDefined(tryExtractTSExtension(moduleReference)))); } } - else if (resolvedModule.resolvedUsingTsExtension && !shouldAllowTsExtension(compilerOptions)) { + else if (resolvedModule.resolvedUsingTsExtension && !shouldAllowImportingTsExtension(compilerOptions, currentSourceFile.fileName)) { const tsExtension = Debug.checkDefined(tryExtractTSExtension(moduleReference)); - errorOnTSExtensionImport(tsExtension); + error(errorNode, Diagnostics.An_import_path_can_only_end_with_a_0_extension_when_allowImportingTsExtensions_is_enabled, tsExtension); } if (sourceFile.symbol) { diff --git a/src/compiler/commandLineParser.ts b/src/compiler/commandLineParser.ts index 541871714593f..f3ffc50336dc0 100644 --- a/src/compiler/commandLineParser.ts +++ b/src/compiler/commandLineParser.ts @@ -956,6 +956,14 @@ namespace ts { category: Diagnostics.Modules, description: Diagnostics.List_of_file_name_suffixes_to_search_when_resolving_a_module, }, + { + name: "allowImportingTsExtensions", + type: "boolean", + affectsModuleResolution: true, + category: Diagnostics.Modules, + description: Diagnostics.Allow_imports_to_include_TypeScript_file_extensions_Requires_moduleResolution_minimal_and_either_noEmit_or_emitDeclarationOnly_to_be_set, + defaultValueDescription: false, + }, // Source Maps { diff --git a/src/compiler/diagnosticMessages.json b/src/compiler/diagnosticMessages.json index 4d74c87d16799..c6614d6482b14 100644 --- a/src/compiler/diagnosticMessages.json +++ b/src/compiler/diagnosticMessages.json @@ -4229,6 +4229,14 @@ "category": "Error", "code": 5095 }, + "Option 'allowImportingTsExtensions' can only be used when 'moduleResolution' is set to 'minimal' and either 'noEmit' or 'emitDeclarationOnly' is set.": { + "category": "Error", + "code": 5096 + }, + "An import path can only end with a '{0}' extension when 'allowImportingTsExtensions' is enabled.": { + "category": "Error", + "code": 5097 + }, "Generates a sourcemap for each corresponding '.d.ts' file.": { "category": "Message", @@ -4451,10 +4459,6 @@ "category": "Message", "code": 6066 }, - "Specify module resolution strategy: 'node' (Node.js) or 'classic' (TypeScript pre-1.6).": { - "category": "Message", - "code": 6069 - }, "Initializes a TypeScript project and creates a tsconfig.json file.": { "category": "Message", "code": 6070 @@ -5418,6 +5422,10 @@ "category": "Message", "code": 6401 }, + "Allow imports to include TypeScript file extensions. Requires '--moduleResolution minimal' and either '--noEmit' or '--emitDeclarationOnly' to be set.": { + "category": "Message", + "code": 6402 + }, "The expected type comes from property '{0}' which is declared here on type '{1}'": { "category": "Message", diff --git a/src/compiler/moduleNameResolver.ts b/src/compiler/moduleNameResolver.ts index c61ba110532bb..6fc614ab5dc1a 100644 --- a/src/compiler/moduleNameResolver.ts +++ b/src/compiler/moduleNameResolver.ts @@ -2716,8 +2716,12 @@ namespace ts { return getEmitModuleResolutionKind(compilerOptions) === ModuleResolutionKind.Minimal; } - export function shouldAllowTsExtension(compilerOptions: CompilerOptions) { - return shouldResolveTsExtension(compilerOptions) && !!compilerOptions.noEmit; + // 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 shouldResolveTsExtension(compilerOptions) && ( + !!compilerOptions.allowImportingTsExtensions || + fromFileName && isDeclarationFileName(fromFileName)); } /** diff --git a/src/compiler/program.ts b/src/compiler/program.ts index 412f307eae4bf..676c5507ee143 100644 --- a/src/compiler/program.ts +++ b/src/compiler/program.ts @@ -3657,6 +3657,10 @@ namespace ts { createOptionValueDiagnostic("importsNotUsedAsValues", Diagnostics.Option_preserveValueImports_can_only_be_used_when_module_is_set_to_es2015_or_later); } + if (options.allowImportingTsExtensions && !(getEmitModuleResolutionKind(options) === ModuleResolutionKind.Minimal && (options.noEmit || options.emitDeclarationOnly))) { + createOptionValueDiagnostic("allowImportingTsExtensions", Diagnostics.Option_allowImportingTsExtensions_can_only_be_used_when_moduleResolution_is_set_to_minimal_and_either_noEmit_or_emitDeclarationOnly_is_set); + } + // If the emit is enabled make sure that every output file is unique and not overwriting any of the input files if (!options.noEmit && !options.suppressOutputPathCheck) { const emitHost = getEmitHost(); diff --git a/src/compiler/types.ts b/src/compiler/types.ts index fa3fdd92df5e0..2790fb700ffa3 100644 --- a/src/compiler/types.ts +++ b/src/compiler/types.ts @@ -6543,6 +6543,7 @@ namespace ts { export interface CompilerOptions { /*@internal*/ all?: boolean; + allowImportingTsExtensions?: boolean; allowJs?: boolean; /*@internal*/ allowNonTsExtensions?: boolean; allowSyntheticDefaultImports?: boolean; diff --git a/src/testRunner/compilerRunner.ts b/src/testRunner/compilerRunner.ts index 00daa90668848..22ae1b9c6e469 100644 --- a/src/testRunner/compilerRunner.ts +++ b/src/testRunner/compilerRunner.ts @@ -119,6 +119,7 @@ namespace Harness { "module", "moduleResolution", "moduleDetection", + "allowImportingTsExtensions", "target", "jsx", "noEmit", diff --git a/tests/baselines/reference/minimal_pathsAndBaseUrl.errors.txt b/tests/baselines/reference/minimal_pathsAndBaseUrl.errors.txt index a1b7074087d13..31490691952d2 100644 --- a/tests/baselines/reference/minimal_pathsAndBaseUrl.errors.txt +++ b/tests/baselines/reference/minimal_pathsAndBaseUrl.errors.txt @@ -6,6 +6,7 @@ "compilerOptions": { "moduleResolution": "minimal", "noEmit": true, + "allowImportingTsExtensions": true, "baseUrl": ".", "paths": { "*": [ diff --git a/tests/baselines/reference/minimal_relative(allowimportingtsextensions=false,noemit=false).errors.txt b/tests/baselines/reference/minimal_relative(allowimportingtsextensions=false,noemit=false).errors.txt new file mode 100644 index 0000000000000..1a1ce3a5447b2 --- /dev/null +++ b/tests/baselines/reference/minimal_relative(allowimportingtsextensions=false,noemit=false).errors.txt @@ -0,0 +1,107 @@ +error TS5056: Cannot write file 'dist/c.js' because it would be overwritten by multiple input files. +error TS6231: Could not resolve the path '/project/e' with the extensions: '.ts', '.tsx', '.d.ts', '.cts', '.d.cts', '.mts', '.d.mts'. + The file is in the program because: + Root file specified for compilation +error TS6504: File '/project/b.js' is a JavaScript file. Did you mean to enable the 'allowJs' option? + The file is in the program because: + Root file specified for compilation +/project/main.ts(1,16): error TS2307: Cannot find module './a' or its corresponding type declarations. +/project/main.ts(3,16): error TS5097: An import path can only end with a '.ts' extension when 'allowImportingTsExtensions' is enabled. +/project/main.ts(5,16): error TS2307: Cannot find module './b' or its corresponding type declarations. +/project/main.ts(7,16): error TS5097: An import path can only end with a '.ts' extension when 'allowImportingTsExtensions' is enabled. +/project/main.ts(8,16): error TS2845: A declaration file cannot be imported without 'import type'. Did you mean to import an implementation file './b.js' instead? +/project/main.ts(11,16): error TS5097: An import path can only end with a '.ts' extension when 'allowImportingTsExtensions' is enabled. +/project/main.ts(12,16): error TS5097: An import path can only end with a '.tsx' extension when 'allowImportingTsExtensions' is enabled. +/project/main.ts(12,16): error TS6142: Module './c.tsx' was resolved to '/project/c.tsx', but '--jsx' is not set. +/project/main.ts(14,16): error TS2307: Cannot find module './d' or its corresponding type declarations. +/project/main.ts(15,16): error TS2307: Cannot find module './d/index' or its corresponding type declarations. +/project/main.ts(16,16): error TS5097: An import path can only end with a '.ts' extension when 'allowImportingTsExtensions' is enabled. +/project/main.ts(18,16): error TS2307: Cannot find module './e' or its corresponding type declarations. +/project/types.d.ts(2,16): error TS2691: An import path cannot end with a '.d.ts' extension. Consider importing './a.js' instead. +/project/types.d.ts(3,21): error TS2691: An import path cannot end with a '.d.ts' extension. Consider importing './a.js' instead. + + +!!! error TS5056: Cannot write file 'dist/c.js' because it would be overwritten by multiple input files. +!!! error TS6231: Could not resolve the path '/project/e' with the extensions: '.ts', '.tsx', '.d.ts', '.cts', '.d.cts', '.mts', '.d.mts'. +!!! error TS6231: The file is in the program because: +!!! error TS6231: Root file specified for compilation +!!! error TS6504: File '/project/b.js' is a JavaScript file. Did you mean to enable the 'allowJs' option? +!!! error TS6504: The file is in the program because: +!!! error TS6504: Root file specified for compilation +==== /project/a.ts (0 errors) ==== + export {}; + +==== /project/b.ts (0 errors) ==== + export {}; + +==== /project/b.js (0 errors) ==== + export {}; + +==== /project/b.d.ts (0 errors) ==== + export {}; + +==== /project/c.ts (0 errors) ==== + export {}; + +==== /project/c.tsx (0 errors) ==== + export {}; + +==== /project/d/index.ts (0 errors) ==== + export {}; + +==== /project/e (0 errors) ==== + export {}; + +==== /project/main.ts (12 errors) ==== + import {} from "./a"; + ~~~~~ +!!! error TS2307: Cannot find module './a' or its corresponding type declarations. + import {} from "./a.js"; + import {} from "./a.ts"; + ~~~~~~~~ +!!! error TS5097: An import path can only end with a '.ts' extension when 'allowImportingTsExtensions' is enabled. + + import {} from "./b"; + ~~~~~ +!!! error TS2307: Cannot find module './b' or its corresponding type declarations. + import {} from "./b.js"; + import {} from "./b.ts"; + ~~~~~~~~ +!!! error TS5097: An import path can only end with a '.ts' extension when 'allowImportingTsExtensions' is enabled. + import {} from "./b.d.ts"; + ~~~~~~~~~~ +!!! error TS2845: A declaration file cannot be imported without 'import type'. Did you mean to import an implementation file './b.js' instead? + import type {} from "./b.d.ts"; + + import {} from "./c.ts"; + ~~~~~~~~ +!!! error TS5097: An import path can only end with a '.ts' extension when 'allowImportingTsExtensions' is enabled. + import {} from "./c.tsx"; + ~~~~~~~~~ +!!! error TS5097: An import path can only end with a '.tsx' extension when 'allowImportingTsExtensions' is enabled. + ~~~~~~~~~ +!!! error TS6142: Module './c.tsx' was resolved to '/project/c.tsx', but '--jsx' is not set. + + import {} from "./d"; + ~~~~~ +!!! error TS2307: Cannot find module './d' or its corresponding type declarations. + import {} from "./d/index"; + ~~~~~~~~~~~ +!!! error TS2307: Cannot find module './d/index' or its corresponding type declarations. + import {} from "./d/index.ts"; + ~~~~~~~~~~~~~~ +!!! error TS5097: An import path can only end with a '.ts' extension when 'allowImportingTsExtensions' is enabled. + + import {} from "./e"; + ~~~~~ +!!! error TS2307: Cannot find module './e' or its corresponding type declarations. + +==== /project/types.d.ts (2 errors) ==== + import {} from "./a.ts"; + import {} from "./a.d.ts"; + ~~~~~~~~~~ +!!! error TS2691: An import path cannot end with a '.d.ts' extension. Consider importing './a.js' instead. + import type {} from "./a.d.ts"; + ~~~~~~~~~~ +!!! error TS2691: An import path cannot end with a '.d.ts' extension. Consider importing './a.js' instead. + \ No newline at end of file diff --git a/tests/baselines/reference/minimal_relative(allowimportingtsextensions=false,noemit=false).js b/tests/baselines/reference/minimal_relative(allowimportingtsextensions=false,noemit=false).js new file mode 100644 index 0000000000000..2eeeabf051a24 --- /dev/null +++ b/tests/baselines/reference/minimal_relative(allowimportingtsextensions=false,noemit=false).js @@ -0,0 +1,64 @@ +//// [tests/cases/conformance/moduleResolution/minimal_relative.ts] //// + +//// [a.ts] +export {}; + +//// [b.ts] +export {}; + +//// [b.js] +export {}; + +//// [b.d.ts] +export {}; + +//// [c.ts] +export {}; + +//// [c.tsx] +export {}; + +//// [index.ts] +export {}; + +//// [e] +export {}; + +//// [main.ts] +import {} from "./a"; +import {} from "./a.js"; +import {} from "./a.ts"; + +import {} from "./b"; +import {} from "./b.js"; +import {} from "./b.ts"; +import {} from "./b.d.ts"; +import type {} from "./b.d.ts"; + +import {} from "./c.ts"; +import {} from "./c.tsx"; + +import {} from "./d"; +import {} from "./d/index"; +import {} from "./d/index.ts"; + +import {} from "./e"; + +//// [types.d.ts] +import {} from "./a.ts"; +import {} from "./a.d.ts"; +import type {} from "./a.d.ts"; + + +//// [a.js] +"use strict"; +exports.__esModule = true; +//// [b.js] +"use strict"; +exports.__esModule = true; +//// [index.js] +"use strict"; +exports.__esModule = true; +//// [main.js] +"use strict"; +exports.__esModule = true; diff --git a/tests/baselines/reference/minimal_relative(allowimportingtsextensions=false,noemit=false).symbols b/tests/baselines/reference/minimal_relative(allowimportingtsextensions=false,noemit=false).symbols new file mode 100644 index 0000000000000..8087e521944d1 --- /dev/null +++ b/tests/baselines/reference/minimal_relative(allowimportingtsextensions=false,noemit=false).symbols @@ -0,0 +1,44 @@ +=== /project/a.ts === +export {}; +No type information for this code. +No type information for this code.=== /project/b.ts === +export {}; +No type information for this code. +No type information for this code.=== /project/b.d.ts === +export {}; +No type information for this code. +No type information for this code.=== /project/c.ts === +export {}; +No type information for this code. +No type information for this code.=== /project/c.tsx === +export {}; +No type information for this code. +No type information for this code.=== /project/d/index.ts === +export {}; +No type information for this code. +No type information for this code.=== /project/main.ts === +import {} from "./a"; +No type information for this code.import {} from "./a.js"; +No type information for this code.import {} from "./a.ts"; +No type information for this code. +No type information for this code.import {} from "./b"; +No type information for this code.import {} from "./b.js"; +No type information for this code.import {} from "./b.ts"; +No type information for this code.import {} from "./b.d.ts"; +No type information for this code.import type {} from "./b.d.ts"; +No type information for this code. +No type information for this code.import {} from "./c.ts"; +No type information for this code.import {} from "./c.tsx"; +No type information for this code. +No type information for this code.import {} from "./d"; +No type information for this code.import {} from "./d/index"; +No type information for this code.import {} from "./d/index.ts"; +No type information for this code. +No type information for this code.import {} from "./e"; +No type information for this code. +No type information for this code.=== /project/types.d.ts === +import {} from "./a.ts"; +No type information for this code.import {} from "./a.d.ts"; +No type information for this code.import type {} from "./a.d.ts"; +No type information for this code. +No type information for this code. \ No newline at end of file diff --git a/tests/baselines/reference/minimal_relative(allowimportingtsextensions=false,noemit=false).trace.json b/tests/baselines/reference/minimal_relative(allowimportingtsextensions=false,noemit=false).trace.json new file mode 100644 index 0000000000000..40a02fe86a714 --- /dev/null +++ b/tests/baselines/reference/minimal_relative(allowimportingtsextensions=false,noemit=false).trace.json @@ -0,0 +1,68 @@ +[ + "======== Resolving module './a' from '/project/main.ts'. ========", + "Explicitly specified module resolution kind: 'Minimal'.", + "======== Module name './a' was not resolved. ========", + "======== Resolving module './a.js' from '/project/main.ts'. ========", + "Explicitly specified module resolution kind: 'Minimal'.", + "File name '/project/a.js' has a '.js' extension - stripping it.", + "File '/project/a.ts' exist - use it as a name resolution result.", + "======== Module name './a.js' was successfully resolved to '/project/a.ts'. ========", + "======== Resolving module './a.ts' from '/project/main.ts'. ========", + "Explicitly specified module resolution kind: 'Minimal'.", + "File name '/project/a.ts' has a '.ts' extension - stripping it.", + "File '/project/a.ts' exist - use it as a name resolution result.", + "======== Module name './a.ts' was successfully resolved to '/project/a.ts'. ========", + "======== Resolving module './b' from '/project/main.ts'. ========", + "Explicitly specified module resolution kind: 'Minimal'.", + "======== Module name './b' was not resolved. ========", + "======== Resolving module './b.js' from '/project/main.ts'. ========", + "Explicitly specified module resolution kind: 'Minimal'.", + "File name '/project/b.js' has a '.js' extension - stripping it.", + "File '/project/b.ts' exist - use it as a name resolution result.", + "======== Module name './b.js' was successfully resolved to '/project/b.ts'. ========", + "======== Resolving module './b.ts' from '/project/main.ts'. ========", + "Explicitly specified module resolution kind: 'Minimal'.", + "File name '/project/b.ts' has a '.ts' extension - stripping it.", + "File '/project/b.ts' exist - use it as a name resolution result.", + "======== Module name './b.ts' was successfully resolved to '/project/b.ts'. ========", + "======== Resolving module './b.d.ts' from '/project/main.ts'. ========", + "Explicitly specified module resolution kind: 'Minimal'.", + "File name '/project/b.d.ts' has a '.d.ts' extension - stripping it.", + "File '/project/b.d.ts' exist - use it as a name resolution result.", + "======== Module name './b.d.ts' was successfully resolved to '/project/b.d.ts'. ========", + "======== Resolving module './c.ts' from '/project/main.ts'. ========", + "Explicitly specified module resolution kind: 'Minimal'.", + "File name '/project/c.ts' has a '.ts' extension - stripping it.", + "File '/project/c.ts' exist - use it as a name resolution result.", + "======== Module name './c.ts' was successfully resolved to '/project/c.ts'. ========", + "======== Resolving module './c.tsx' from '/project/main.ts'. ========", + "Explicitly specified module resolution kind: 'Minimal'.", + "File name '/project/c.tsx' has a '.tsx' extension - stripping it.", + "File '/project/c.tsx' exist - use it as a name resolution result.", + "======== Module name './c.tsx' was successfully resolved to '/project/c.tsx'. ========", + "======== Resolving module './d' from '/project/main.ts'. ========", + "Explicitly specified module resolution kind: 'Minimal'.", + "======== Module name './d' was not resolved. ========", + "======== Resolving module './d/index' from '/project/main.ts'. ========", + "Explicitly specified module resolution kind: 'Minimal'.", + "======== Module name './d/index' was not resolved. ========", + "======== Resolving module './d/index.ts' from '/project/main.ts'. ========", + "Explicitly specified module resolution kind: 'Minimal'.", + "File name '/project/d/index.ts' has a '.ts' extension - stripping it.", + "File '/project/d/index.ts' exist - use it as a name resolution result.", + "======== Module name './d/index.ts' was successfully resolved to '/project/d/index.ts'. ========", + "======== Resolving module './e' from '/project/main.ts'. ========", + "Explicitly specified module resolution kind: 'Minimal'.", + "======== Module name './e' was not resolved. ========", + "======== Resolving module './a.ts' from '/project/types.d.ts'. ========", + "Resolution for module './a.ts' was found in cache from location '/project'.", + "======== Module name './a.ts' was successfully resolved to '/project/a.ts'. ========", + "======== Resolving module './a.d.ts' from '/project/types.d.ts'. ========", + "Explicitly specified module resolution kind: 'Minimal'.", + "File name '/project/a.d.ts' has a '.d.ts' extension - stripping it.", + "File '/project/a.d.ts' does not exist.", + "File name '/project/a.d.ts' has a '.d.ts' extension - stripping it.", + "File '/project/a.js' does not exist.", + "File '/project/a.jsx' does not exist.", + "======== Module name './a.d.ts' was not resolved. ========" +] \ No newline at end of file diff --git a/tests/baselines/reference/minimal_relative(allowimportingtsextensions=false,noemit=false).types b/tests/baselines/reference/minimal_relative(allowimportingtsextensions=false,noemit=false).types new file mode 100644 index 0000000000000..8087e521944d1 --- /dev/null +++ b/tests/baselines/reference/minimal_relative(allowimportingtsextensions=false,noemit=false).types @@ -0,0 +1,44 @@ +=== /project/a.ts === +export {}; +No type information for this code. +No type information for this code.=== /project/b.ts === +export {}; +No type information for this code. +No type information for this code.=== /project/b.d.ts === +export {}; +No type information for this code. +No type information for this code.=== /project/c.ts === +export {}; +No type information for this code. +No type information for this code.=== /project/c.tsx === +export {}; +No type information for this code. +No type information for this code.=== /project/d/index.ts === +export {}; +No type information for this code. +No type information for this code.=== /project/main.ts === +import {} from "./a"; +No type information for this code.import {} from "./a.js"; +No type information for this code.import {} from "./a.ts"; +No type information for this code. +No type information for this code.import {} from "./b"; +No type information for this code.import {} from "./b.js"; +No type information for this code.import {} from "./b.ts"; +No type information for this code.import {} from "./b.d.ts"; +No type information for this code.import type {} from "./b.d.ts"; +No type information for this code. +No type information for this code.import {} from "./c.ts"; +No type information for this code.import {} from "./c.tsx"; +No type information for this code. +No type information for this code.import {} from "./d"; +No type information for this code.import {} from "./d/index"; +No type information for this code.import {} from "./d/index.ts"; +No type information for this code. +No type information for this code.import {} from "./e"; +No type information for this code. +No type information for this code.=== /project/types.d.ts === +import {} from "./a.ts"; +No type information for this code.import {} from "./a.d.ts"; +No type information for this code.import type {} from "./a.d.ts"; +No type information for this code. +No type information for this code. \ No newline at end of file diff --git a/tests/baselines/reference/minimal_relative(allowimportingtsextensions=false,noemit=true).errors.txt b/tests/baselines/reference/minimal_relative(allowimportingtsextensions=false,noemit=true).errors.txt new file mode 100644 index 0000000000000..be1af8b2bad51 --- /dev/null +++ b/tests/baselines/reference/minimal_relative(allowimportingtsextensions=false,noemit=true).errors.txt @@ -0,0 +1,105 @@ +error TS6231: Could not resolve the path '/project/e' with the extensions: '.ts', '.tsx', '.d.ts', '.cts', '.d.cts', '.mts', '.d.mts'. + The file is in the program because: + Root file specified for compilation +error TS6504: File '/project/b.js' is a JavaScript file. Did you mean to enable the 'allowJs' option? + The file is in the program because: + Root file specified for compilation +/project/main.ts(1,16): error TS2307: Cannot find module './a' or its corresponding type declarations. +/project/main.ts(3,16): error TS5097: An import path can only end with a '.ts' extension when 'allowImportingTsExtensions' is enabled. +/project/main.ts(5,16): error TS2307: Cannot find module './b' or its corresponding type declarations. +/project/main.ts(7,16): error TS5097: An import path can only end with a '.ts' extension when 'allowImportingTsExtensions' is enabled. +/project/main.ts(8,16): error TS2845: A declaration file cannot be imported without 'import type'. Did you mean to import an implementation file './b.js' instead? +/project/main.ts(11,16): error TS5097: An import path can only end with a '.ts' extension when 'allowImportingTsExtensions' is enabled. +/project/main.ts(12,16): error TS5097: An import path can only end with a '.tsx' extension when 'allowImportingTsExtensions' is enabled. +/project/main.ts(12,16): error TS6142: Module './c.tsx' was resolved to '/project/c.tsx', but '--jsx' is not set. +/project/main.ts(14,16): error TS2307: Cannot find module './d' or its corresponding type declarations. +/project/main.ts(15,16): error TS2307: Cannot find module './d/index' or its corresponding type declarations. +/project/main.ts(16,16): error TS5097: An import path can only end with a '.ts' extension when 'allowImportingTsExtensions' is enabled. +/project/main.ts(18,16): error TS2307: Cannot find module './e' or its corresponding type declarations. +/project/types.d.ts(2,16): error TS2691: An import path cannot end with a '.d.ts' extension. Consider importing './a.js' instead. +/project/types.d.ts(3,21): error TS2691: An import path cannot end with a '.d.ts' extension. Consider importing './a.js' instead. + + +!!! error TS6231: Could not resolve the path '/project/e' with the extensions: '.ts', '.tsx', '.d.ts', '.cts', '.d.cts', '.mts', '.d.mts'. +!!! error TS6231: The file is in the program because: +!!! error TS6231: Root file specified for compilation +!!! error TS6504: File '/project/b.js' is a JavaScript file. Did you mean to enable the 'allowJs' option? +!!! error TS6504: The file is in the program because: +!!! error TS6504: Root file specified for compilation +==== /project/a.ts (0 errors) ==== + export {}; + +==== /project/b.ts (0 errors) ==== + export {}; + +==== /project/b.js (0 errors) ==== + export {}; + +==== /project/b.d.ts (0 errors) ==== + export {}; + +==== /project/c.ts (0 errors) ==== + export {}; + +==== /project/c.tsx (0 errors) ==== + export {}; + +==== /project/d/index.ts (0 errors) ==== + export {}; + +==== /project/e (0 errors) ==== + export {}; + +==== /project/main.ts (12 errors) ==== + import {} from "./a"; + ~~~~~ +!!! error TS2307: Cannot find module './a' or its corresponding type declarations. + import {} from "./a.js"; + import {} from "./a.ts"; + ~~~~~~~~ +!!! error TS5097: An import path can only end with a '.ts' extension when 'allowImportingTsExtensions' is enabled. + + import {} from "./b"; + ~~~~~ +!!! error TS2307: Cannot find module './b' or its corresponding type declarations. + import {} from "./b.js"; + import {} from "./b.ts"; + ~~~~~~~~ +!!! error TS5097: An import path can only end with a '.ts' extension when 'allowImportingTsExtensions' is enabled. + import {} from "./b.d.ts"; + ~~~~~~~~~~ +!!! error TS2845: A declaration file cannot be imported without 'import type'. Did you mean to import an implementation file './b.js' instead? + import type {} from "./b.d.ts"; + + import {} from "./c.ts"; + ~~~~~~~~ +!!! error TS5097: An import path can only end with a '.ts' extension when 'allowImportingTsExtensions' is enabled. + import {} from "./c.tsx"; + ~~~~~~~~~ +!!! error TS5097: An import path can only end with a '.tsx' extension when 'allowImportingTsExtensions' is enabled. + ~~~~~~~~~ +!!! error TS6142: Module './c.tsx' was resolved to '/project/c.tsx', but '--jsx' is not set. + + import {} from "./d"; + ~~~~~ +!!! error TS2307: Cannot find module './d' or its corresponding type declarations. + import {} from "./d/index"; + ~~~~~~~~~~~ +!!! error TS2307: Cannot find module './d/index' or its corresponding type declarations. + import {} from "./d/index.ts"; + ~~~~~~~~~~~~~~ +!!! error TS5097: An import path can only end with a '.ts' extension when 'allowImportingTsExtensions' is enabled. + + import {} from "./e"; + ~~~~~ +!!! error TS2307: Cannot find module './e' or its corresponding type declarations. + +==== /project/types.d.ts (2 errors) ==== + import {} from "./a.ts"; + import {} from "./a.d.ts"; + ~~~~~~~~~~ +!!! error TS2691: An import path cannot end with a '.d.ts' extension. Consider importing './a.js' instead. + import type {} from "./a.d.ts"; + ~~~~~~~~~~ +!!! error TS2691: An import path cannot end with a '.d.ts' extension. Consider importing './a.js' instead. + \ No newline at end of file diff --git a/tests/baselines/reference/minimal_relative(allowimportingtsextensions=false,noemit=true).symbols b/tests/baselines/reference/minimal_relative(allowimportingtsextensions=false,noemit=true).symbols new file mode 100644 index 0000000000000..8087e521944d1 --- /dev/null +++ b/tests/baselines/reference/minimal_relative(allowimportingtsextensions=false,noemit=true).symbols @@ -0,0 +1,44 @@ +=== /project/a.ts === +export {}; +No type information for this code. +No type information for this code.=== /project/b.ts === +export {}; +No type information for this code. +No type information for this code.=== /project/b.d.ts === +export {}; +No type information for this code. +No type information for this code.=== /project/c.ts === +export {}; +No type information for this code. +No type information for this code.=== /project/c.tsx === +export {}; +No type information for this code. +No type information for this code.=== /project/d/index.ts === +export {}; +No type information for this code. +No type information for this code.=== /project/main.ts === +import {} from "./a"; +No type information for this code.import {} from "./a.js"; +No type information for this code.import {} from "./a.ts"; +No type information for this code. +No type information for this code.import {} from "./b"; +No type information for this code.import {} from "./b.js"; +No type information for this code.import {} from "./b.ts"; +No type information for this code.import {} from "./b.d.ts"; +No type information for this code.import type {} from "./b.d.ts"; +No type information for this code. +No type information for this code.import {} from "./c.ts"; +No type information for this code.import {} from "./c.tsx"; +No type information for this code. +No type information for this code.import {} from "./d"; +No type information for this code.import {} from "./d/index"; +No type information for this code.import {} from "./d/index.ts"; +No type information for this code. +No type information for this code.import {} from "./e"; +No type information for this code. +No type information for this code.=== /project/types.d.ts === +import {} from "./a.ts"; +No type information for this code.import {} from "./a.d.ts"; +No type information for this code.import type {} from "./a.d.ts"; +No type information for this code. +No type information for this code. \ No newline at end of file diff --git a/tests/baselines/reference/minimal_relative(allowimportingtsextensions=false,noemit=true).trace.json b/tests/baselines/reference/minimal_relative(allowimportingtsextensions=false,noemit=true).trace.json new file mode 100644 index 0000000000000..40a02fe86a714 --- /dev/null +++ b/tests/baselines/reference/minimal_relative(allowimportingtsextensions=false,noemit=true).trace.json @@ -0,0 +1,68 @@ +[ + "======== Resolving module './a' from '/project/main.ts'. ========", + "Explicitly specified module resolution kind: 'Minimal'.", + "======== Module name './a' was not resolved. ========", + "======== Resolving module './a.js' from '/project/main.ts'. ========", + "Explicitly specified module resolution kind: 'Minimal'.", + "File name '/project/a.js' has a '.js' extension - stripping it.", + "File '/project/a.ts' exist - use it as a name resolution result.", + "======== Module name './a.js' was successfully resolved to '/project/a.ts'. ========", + "======== Resolving module './a.ts' from '/project/main.ts'. ========", + "Explicitly specified module resolution kind: 'Minimal'.", + "File name '/project/a.ts' has a '.ts' extension - stripping it.", + "File '/project/a.ts' exist - use it as a name resolution result.", + "======== Module name './a.ts' was successfully resolved to '/project/a.ts'. ========", + "======== Resolving module './b' from '/project/main.ts'. ========", + "Explicitly specified module resolution kind: 'Minimal'.", + "======== Module name './b' was not resolved. ========", + "======== Resolving module './b.js' from '/project/main.ts'. ========", + "Explicitly specified module resolution kind: 'Minimal'.", + "File name '/project/b.js' has a '.js' extension - stripping it.", + "File '/project/b.ts' exist - use it as a name resolution result.", + "======== Module name './b.js' was successfully resolved to '/project/b.ts'. ========", + "======== Resolving module './b.ts' from '/project/main.ts'. ========", + "Explicitly specified module resolution kind: 'Minimal'.", + "File name '/project/b.ts' has a '.ts' extension - stripping it.", + "File '/project/b.ts' exist - use it as a name resolution result.", + "======== Module name './b.ts' was successfully resolved to '/project/b.ts'. ========", + "======== Resolving module './b.d.ts' from '/project/main.ts'. ========", + "Explicitly specified module resolution kind: 'Minimal'.", + "File name '/project/b.d.ts' has a '.d.ts' extension - stripping it.", + "File '/project/b.d.ts' exist - use it as a name resolution result.", + "======== Module name './b.d.ts' was successfully resolved to '/project/b.d.ts'. ========", + "======== Resolving module './c.ts' from '/project/main.ts'. ========", + "Explicitly specified module resolution kind: 'Minimal'.", + "File name '/project/c.ts' has a '.ts' extension - stripping it.", + "File '/project/c.ts' exist - use it as a name resolution result.", + "======== Module name './c.ts' was successfully resolved to '/project/c.ts'. ========", + "======== Resolving module './c.tsx' from '/project/main.ts'. ========", + "Explicitly specified module resolution kind: 'Minimal'.", + "File name '/project/c.tsx' has a '.tsx' extension - stripping it.", + "File '/project/c.tsx' exist - use it as a name resolution result.", + "======== Module name './c.tsx' was successfully resolved to '/project/c.tsx'. ========", + "======== Resolving module './d' from '/project/main.ts'. ========", + "Explicitly specified module resolution kind: 'Minimal'.", + "======== Module name './d' was not resolved. ========", + "======== Resolving module './d/index' from '/project/main.ts'. ========", + "Explicitly specified module resolution kind: 'Minimal'.", + "======== Module name './d/index' was not resolved. ========", + "======== Resolving module './d/index.ts' from '/project/main.ts'. ========", + "Explicitly specified module resolution kind: 'Minimal'.", + "File name '/project/d/index.ts' has a '.ts' extension - stripping it.", + "File '/project/d/index.ts' exist - use it as a name resolution result.", + "======== Module name './d/index.ts' was successfully resolved to '/project/d/index.ts'. ========", + "======== Resolving module './e' from '/project/main.ts'. ========", + "Explicitly specified module resolution kind: 'Minimal'.", + "======== Module name './e' was not resolved. ========", + "======== Resolving module './a.ts' from '/project/types.d.ts'. ========", + "Resolution for module './a.ts' was found in cache from location '/project'.", + "======== Module name './a.ts' was successfully resolved to '/project/a.ts'. ========", + "======== Resolving module './a.d.ts' from '/project/types.d.ts'. ========", + "Explicitly specified module resolution kind: 'Minimal'.", + "File name '/project/a.d.ts' has a '.d.ts' extension - stripping it.", + "File '/project/a.d.ts' does not exist.", + "File name '/project/a.d.ts' has a '.d.ts' extension - stripping it.", + "File '/project/a.js' does not exist.", + "File '/project/a.jsx' does not exist.", + "======== Module name './a.d.ts' was not resolved. ========" +] \ No newline at end of file diff --git a/tests/baselines/reference/minimal_relative(allowimportingtsextensions=false,noemit=true).types b/tests/baselines/reference/minimal_relative(allowimportingtsextensions=false,noemit=true).types new file mode 100644 index 0000000000000..8087e521944d1 --- /dev/null +++ b/tests/baselines/reference/minimal_relative(allowimportingtsextensions=false,noemit=true).types @@ -0,0 +1,44 @@ +=== /project/a.ts === +export {}; +No type information for this code. +No type information for this code.=== /project/b.ts === +export {}; +No type information for this code. +No type information for this code.=== /project/b.d.ts === +export {}; +No type information for this code. +No type information for this code.=== /project/c.ts === +export {}; +No type information for this code. +No type information for this code.=== /project/c.tsx === +export {}; +No type information for this code. +No type information for this code.=== /project/d/index.ts === +export {}; +No type information for this code. +No type information for this code.=== /project/main.ts === +import {} from "./a"; +No type information for this code.import {} from "./a.js"; +No type information for this code.import {} from "./a.ts"; +No type information for this code. +No type information for this code.import {} from "./b"; +No type information for this code.import {} from "./b.js"; +No type information for this code.import {} from "./b.ts"; +No type information for this code.import {} from "./b.d.ts"; +No type information for this code.import type {} from "./b.d.ts"; +No type information for this code. +No type information for this code.import {} from "./c.ts"; +No type information for this code.import {} from "./c.tsx"; +No type information for this code. +No type information for this code.import {} from "./d"; +No type information for this code.import {} from "./d/index"; +No type information for this code.import {} from "./d/index.ts"; +No type information for this code. +No type information for this code.import {} from "./e"; +No type information for this code. +No type information for this code.=== /project/types.d.ts === +import {} from "./a.ts"; +No type information for this code.import {} from "./a.d.ts"; +No type information for this code.import type {} from "./a.d.ts"; +No type information for this code. +No type information for this code. \ No newline at end of file diff --git a/tests/baselines/reference/minimal_relative(allowimportingtsextensions=true,noemit=false).errors.txt b/tests/baselines/reference/minimal_relative(allowimportingtsextensions=true,noemit=false).errors.txt new file mode 100644 index 0000000000000..68fea4b6506d7 --- /dev/null +++ b/tests/baselines/reference/minimal_relative(allowimportingtsextensions=true,noemit=false).errors.txt @@ -0,0 +1,94 @@ +error TS5056: Cannot write file 'dist/c.js' because it would be overwritten by multiple input files. +error TS5096: Option 'allowImportingTsExtensions' can only be used when 'moduleResolution' is set to 'minimal' and either 'noEmit' or 'emitDeclarationOnly' is set. +error TS6231: Could not resolve the path '/project/e' with the extensions: '.ts', '.tsx', '.d.ts', '.cts', '.d.cts', '.mts', '.d.mts'. + The file is in the program because: + Root file specified for compilation +error TS6504: File '/project/b.js' is a JavaScript file. Did you mean to enable the 'allowJs' option? + The file is in the program because: + Root file specified for compilation +/project/main.ts(1,16): error TS2307: Cannot find module './a' or its corresponding type declarations. +/project/main.ts(5,16): error TS2307: Cannot find module './b' or its corresponding type declarations. +/project/main.ts(8,16): error TS2845: A declaration file cannot be imported without 'import type'. Did you mean to import an implementation file './b.js' instead? +/project/main.ts(12,16): error TS6142: Module './c.tsx' was resolved to '/project/c.tsx', but '--jsx' is not set. +/project/main.ts(14,16): error TS2307: Cannot find module './d' or its corresponding type declarations. +/project/main.ts(15,16): error TS2307: Cannot find module './d/index' or its corresponding type declarations. +/project/main.ts(18,16): error TS2307: Cannot find module './e' or its corresponding type declarations. +/project/types.d.ts(2,16): error TS2691: An import path cannot end with a '.d.ts' extension. Consider importing './a.js' instead. +/project/types.d.ts(3,21): error TS2691: An import path cannot end with a '.d.ts' extension. Consider importing './a.js' instead. + + +!!! error TS5056: Cannot write file 'dist/c.js' because it would be overwritten by multiple input files. +!!! error TS5096: Option 'allowImportingTsExtensions' can only be used when 'moduleResolution' is set to 'minimal' and either 'noEmit' or 'emitDeclarationOnly' is set. +!!! error TS6231: Could not resolve the path '/project/e' with the extensions: '.ts', '.tsx', '.d.ts', '.cts', '.d.cts', '.mts', '.d.mts'. +!!! error TS6231: The file is in the program because: +!!! error TS6231: Root file specified for compilation +!!! error TS6504: File '/project/b.js' is a JavaScript file. Did you mean to enable the 'allowJs' option? +!!! error TS6504: The file is in the program because: +!!! error TS6504: Root file specified for compilation +==== /project/a.ts (0 errors) ==== + export {}; + +==== /project/b.ts (0 errors) ==== + export {}; + +==== /project/b.js (0 errors) ==== + export {}; + +==== /project/b.d.ts (0 errors) ==== + export {}; + +==== /project/c.ts (0 errors) ==== + export {}; + +==== /project/c.tsx (0 errors) ==== + export {}; + +==== /project/d/index.ts (0 errors) ==== + export {}; + +==== /project/e (0 errors) ==== + export {}; + +==== /project/main.ts (7 errors) ==== + import {} from "./a"; + ~~~~~ +!!! error TS2307: Cannot find module './a' or its corresponding type declarations. + import {} from "./a.js"; + import {} from "./a.ts"; + + import {} from "./b"; + ~~~~~ +!!! error TS2307: Cannot find module './b' or its corresponding type declarations. + import {} from "./b.js"; + import {} from "./b.ts"; + import {} from "./b.d.ts"; + ~~~~~~~~~~ +!!! error TS2845: A declaration file cannot be imported without 'import type'. Did you mean to import an implementation file './b.js' instead? + import type {} from "./b.d.ts"; + + import {} from "./c.ts"; + import {} from "./c.tsx"; + ~~~~~~~~~ +!!! error TS6142: Module './c.tsx' was resolved to '/project/c.tsx', but '--jsx' is not set. + + import {} from "./d"; + ~~~~~ +!!! error TS2307: Cannot find module './d' or its corresponding type declarations. + import {} from "./d/index"; + ~~~~~~~~~~~ +!!! error TS2307: Cannot find module './d/index' or its corresponding type declarations. + import {} from "./d/index.ts"; + + import {} from "./e"; + ~~~~~ +!!! error TS2307: Cannot find module './e' or its corresponding type declarations. + +==== /project/types.d.ts (2 errors) ==== + import {} from "./a.ts"; + import {} from "./a.d.ts"; + ~~~~~~~~~~ +!!! error TS2691: An import path cannot end with a '.d.ts' extension. Consider importing './a.js' instead. + import type {} from "./a.d.ts"; + ~~~~~~~~~~ +!!! error TS2691: An import path cannot end with a '.d.ts' extension. Consider importing './a.js' instead. + \ No newline at end of file diff --git a/tests/baselines/reference/minimal_relative(allowimportingtsextensions=true,noemit=false).js b/tests/baselines/reference/minimal_relative(allowimportingtsextensions=true,noemit=false).js new file mode 100644 index 0000000000000..2eeeabf051a24 --- /dev/null +++ b/tests/baselines/reference/minimal_relative(allowimportingtsextensions=true,noemit=false).js @@ -0,0 +1,64 @@ +//// [tests/cases/conformance/moduleResolution/minimal_relative.ts] //// + +//// [a.ts] +export {}; + +//// [b.ts] +export {}; + +//// [b.js] +export {}; + +//// [b.d.ts] +export {}; + +//// [c.ts] +export {}; + +//// [c.tsx] +export {}; + +//// [index.ts] +export {}; + +//// [e] +export {}; + +//// [main.ts] +import {} from "./a"; +import {} from "./a.js"; +import {} from "./a.ts"; + +import {} from "./b"; +import {} from "./b.js"; +import {} from "./b.ts"; +import {} from "./b.d.ts"; +import type {} from "./b.d.ts"; + +import {} from "./c.ts"; +import {} from "./c.tsx"; + +import {} from "./d"; +import {} from "./d/index"; +import {} from "./d/index.ts"; + +import {} from "./e"; + +//// [types.d.ts] +import {} from "./a.ts"; +import {} from "./a.d.ts"; +import type {} from "./a.d.ts"; + + +//// [a.js] +"use strict"; +exports.__esModule = true; +//// [b.js] +"use strict"; +exports.__esModule = true; +//// [index.js] +"use strict"; +exports.__esModule = true; +//// [main.js] +"use strict"; +exports.__esModule = true; diff --git a/tests/baselines/reference/minimal_relative(allowimportingtsextensions=true,noemit=false).symbols b/tests/baselines/reference/minimal_relative(allowimportingtsextensions=true,noemit=false).symbols new file mode 100644 index 0000000000000..8087e521944d1 --- /dev/null +++ b/tests/baselines/reference/minimal_relative(allowimportingtsextensions=true,noemit=false).symbols @@ -0,0 +1,44 @@ +=== /project/a.ts === +export {}; +No type information for this code. +No type information for this code.=== /project/b.ts === +export {}; +No type information for this code. +No type information for this code.=== /project/b.d.ts === +export {}; +No type information for this code. +No type information for this code.=== /project/c.ts === +export {}; +No type information for this code. +No type information for this code.=== /project/c.tsx === +export {}; +No type information for this code. +No type information for this code.=== /project/d/index.ts === +export {}; +No type information for this code. +No type information for this code.=== /project/main.ts === +import {} from "./a"; +No type information for this code.import {} from "./a.js"; +No type information for this code.import {} from "./a.ts"; +No type information for this code. +No type information for this code.import {} from "./b"; +No type information for this code.import {} from "./b.js"; +No type information for this code.import {} from "./b.ts"; +No type information for this code.import {} from "./b.d.ts"; +No type information for this code.import type {} from "./b.d.ts"; +No type information for this code. +No type information for this code.import {} from "./c.ts"; +No type information for this code.import {} from "./c.tsx"; +No type information for this code. +No type information for this code.import {} from "./d"; +No type information for this code.import {} from "./d/index"; +No type information for this code.import {} from "./d/index.ts"; +No type information for this code. +No type information for this code.import {} from "./e"; +No type information for this code. +No type information for this code.=== /project/types.d.ts === +import {} from "./a.ts"; +No type information for this code.import {} from "./a.d.ts"; +No type information for this code.import type {} from "./a.d.ts"; +No type information for this code. +No type information for this code. \ No newline at end of file diff --git a/tests/baselines/reference/minimal_relative(allowimportingtsextensions=true,noemit=false).trace.json b/tests/baselines/reference/minimal_relative(allowimportingtsextensions=true,noemit=false).trace.json new file mode 100644 index 0000000000000..40a02fe86a714 --- /dev/null +++ b/tests/baselines/reference/minimal_relative(allowimportingtsextensions=true,noemit=false).trace.json @@ -0,0 +1,68 @@ +[ + "======== Resolving module './a' from '/project/main.ts'. ========", + "Explicitly specified module resolution kind: 'Minimal'.", + "======== Module name './a' was not resolved. ========", + "======== Resolving module './a.js' from '/project/main.ts'. ========", + "Explicitly specified module resolution kind: 'Minimal'.", + "File name '/project/a.js' has a '.js' extension - stripping it.", + "File '/project/a.ts' exist - use it as a name resolution result.", + "======== Module name './a.js' was successfully resolved to '/project/a.ts'. ========", + "======== Resolving module './a.ts' from '/project/main.ts'. ========", + "Explicitly specified module resolution kind: 'Minimal'.", + "File name '/project/a.ts' has a '.ts' extension - stripping it.", + "File '/project/a.ts' exist - use it as a name resolution result.", + "======== Module name './a.ts' was successfully resolved to '/project/a.ts'. ========", + "======== Resolving module './b' from '/project/main.ts'. ========", + "Explicitly specified module resolution kind: 'Minimal'.", + "======== Module name './b' was not resolved. ========", + "======== Resolving module './b.js' from '/project/main.ts'. ========", + "Explicitly specified module resolution kind: 'Minimal'.", + "File name '/project/b.js' has a '.js' extension - stripping it.", + "File '/project/b.ts' exist - use it as a name resolution result.", + "======== Module name './b.js' was successfully resolved to '/project/b.ts'. ========", + "======== Resolving module './b.ts' from '/project/main.ts'. ========", + "Explicitly specified module resolution kind: 'Minimal'.", + "File name '/project/b.ts' has a '.ts' extension - stripping it.", + "File '/project/b.ts' exist - use it as a name resolution result.", + "======== Module name './b.ts' was successfully resolved to '/project/b.ts'. ========", + "======== Resolving module './b.d.ts' from '/project/main.ts'. ========", + "Explicitly specified module resolution kind: 'Minimal'.", + "File name '/project/b.d.ts' has a '.d.ts' extension - stripping it.", + "File '/project/b.d.ts' exist - use it as a name resolution result.", + "======== Module name './b.d.ts' was successfully resolved to '/project/b.d.ts'. ========", + "======== Resolving module './c.ts' from '/project/main.ts'. ========", + "Explicitly specified module resolution kind: 'Minimal'.", + "File name '/project/c.ts' has a '.ts' extension - stripping it.", + "File '/project/c.ts' exist - use it as a name resolution result.", + "======== Module name './c.ts' was successfully resolved to '/project/c.ts'. ========", + "======== Resolving module './c.tsx' from '/project/main.ts'. ========", + "Explicitly specified module resolution kind: 'Minimal'.", + "File name '/project/c.tsx' has a '.tsx' extension - stripping it.", + "File '/project/c.tsx' exist - use it as a name resolution result.", + "======== Module name './c.tsx' was successfully resolved to '/project/c.tsx'. ========", + "======== Resolving module './d' from '/project/main.ts'. ========", + "Explicitly specified module resolution kind: 'Minimal'.", + "======== Module name './d' was not resolved. ========", + "======== Resolving module './d/index' from '/project/main.ts'. ========", + "Explicitly specified module resolution kind: 'Minimal'.", + "======== Module name './d/index' was not resolved. ========", + "======== Resolving module './d/index.ts' from '/project/main.ts'. ========", + "Explicitly specified module resolution kind: 'Minimal'.", + "File name '/project/d/index.ts' has a '.ts' extension - stripping it.", + "File '/project/d/index.ts' exist - use it as a name resolution result.", + "======== Module name './d/index.ts' was successfully resolved to '/project/d/index.ts'. ========", + "======== Resolving module './e' from '/project/main.ts'. ========", + "Explicitly specified module resolution kind: 'Minimal'.", + "======== Module name './e' was not resolved. ========", + "======== Resolving module './a.ts' from '/project/types.d.ts'. ========", + "Resolution for module './a.ts' was found in cache from location '/project'.", + "======== Module name './a.ts' was successfully resolved to '/project/a.ts'. ========", + "======== Resolving module './a.d.ts' from '/project/types.d.ts'. ========", + "Explicitly specified module resolution kind: 'Minimal'.", + "File name '/project/a.d.ts' has a '.d.ts' extension - stripping it.", + "File '/project/a.d.ts' does not exist.", + "File name '/project/a.d.ts' has a '.d.ts' extension - stripping it.", + "File '/project/a.js' does not exist.", + "File '/project/a.jsx' does not exist.", + "======== Module name './a.d.ts' was not resolved. ========" +] \ No newline at end of file diff --git a/tests/baselines/reference/minimal_relative(allowimportingtsextensions=true,noemit=false).types b/tests/baselines/reference/minimal_relative(allowimportingtsextensions=true,noemit=false).types new file mode 100644 index 0000000000000..8087e521944d1 --- /dev/null +++ b/tests/baselines/reference/minimal_relative(allowimportingtsextensions=true,noemit=false).types @@ -0,0 +1,44 @@ +=== /project/a.ts === +export {}; +No type information for this code. +No type information for this code.=== /project/b.ts === +export {}; +No type information for this code. +No type information for this code.=== /project/b.d.ts === +export {}; +No type information for this code. +No type information for this code.=== /project/c.ts === +export {}; +No type information for this code. +No type information for this code.=== /project/c.tsx === +export {}; +No type information for this code. +No type information for this code.=== /project/d/index.ts === +export {}; +No type information for this code. +No type information for this code.=== /project/main.ts === +import {} from "./a"; +No type information for this code.import {} from "./a.js"; +No type information for this code.import {} from "./a.ts"; +No type information for this code. +No type information for this code.import {} from "./b"; +No type information for this code.import {} from "./b.js"; +No type information for this code.import {} from "./b.ts"; +No type information for this code.import {} from "./b.d.ts"; +No type information for this code.import type {} from "./b.d.ts"; +No type information for this code. +No type information for this code.import {} from "./c.ts"; +No type information for this code.import {} from "./c.tsx"; +No type information for this code. +No type information for this code.import {} from "./d"; +No type information for this code.import {} from "./d/index"; +No type information for this code.import {} from "./d/index.ts"; +No type information for this code. +No type information for this code.import {} from "./e"; +No type information for this code. +No type information for this code.=== /project/types.d.ts === +import {} from "./a.ts"; +No type information for this code.import {} from "./a.d.ts"; +No type information for this code.import type {} from "./a.d.ts"; +No type information for this code. +No type information for this code. \ No newline at end of file diff --git a/tests/baselines/reference/minimal_relative(allowimportingtsextensions=true,noemit=true).errors.txt b/tests/baselines/reference/minimal_relative(allowimportingtsextensions=true,noemit=true).errors.txt new file mode 100644 index 0000000000000..3ae5b03e5a120 --- /dev/null +++ b/tests/baselines/reference/minimal_relative(allowimportingtsextensions=true,noemit=true).errors.txt @@ -0,0 +1,90 @@ +error TS6231: Could not resolve the path '/project/e' with the extensions: '.ts', '.tsx', '.d.ts', '.cts', '.d.cts', '.mts', '.d.mts'. + The file is in the program because: + Root file specified for compilation +error TS6504: File '/project/b.js' is a JavaScript file. Did you mean to enable the 'allowJs' option? + The file is in the program because: + Root file specified for compilation +/project/main.ts(1,16): error TS2307: Cannot find module './a' or its corresponding type declarations. +/project/main.ts(5,16): error TS2307: Cannot find module './b' or its corresponding type declarations. +/project/main.ts(8,16): error TS2845: A declaration file cannot be imported without 'import type'. Did you mean to import an implementation file './b.js' instead? +/project/main.ts(12,16): error TS6142: Module './c.tsx' was resolved to '/project/c.tsx', but '--jsx' is not set. +/project/main.ts(14,16): error TS2307: Cannot find module './d' or its corresponding type declarations. +/project/main.ts(15,16): error TS2307: Cannot find module './d/index' or its corresponding type declarations. +/project/main.ts(18,16): error TS2307: Cannot find module './e' or its corresponding type declarations. +/project/types.d.ts(2,16): error TS2691: An import path cannot end with a '.d.ts' extension. Consider importing './a.js' instead. +/project/types.d.ts(3,21): error TS2691: An import path cannot end with a '.d.ts' extension. Consider importing './a.js' instead. + + +!!! error TS6231: Could not resolve the path '/project/e' with the extensions: '.ts', '.tsx', '.d.ts', '.cts', '.d.cts', '.mts', '.d.mts'. +!!! error TS6231: The file is in the program because: +!!! error TS6231: Root file specified for compilation +!!! error TS6504: File '/project/b.js' is a JavaScript file. Did you mean to enable the 'allowJs' option? +!!! error TS6504: The file is in the program because: +!!! error TS6504: Root file specified for compilation +==== /project/a.ts (0 errors) ==== + export {}; + +==== /project/b.ts (0 errors) ==== + export {}; + +==== /project/b.js (0 errors) ==== + export {}; + +==== /project/b.d.ts (0 errors) ==== + export {}; + +==== /project/c.ts (0 errors) ==== + export {}; + +==== /project/c.tsx (0 errors) ==== + export {}; + +==== /project/d/index.ts (0 errors) ==== + export {}; + +==== /project/e (0 errors) ==== + export {}; + +==== /project/main.ts (7 errors) ==== + import {} from "./a"; + ~~~~~ +!!! error TS2307: Cannot find module './a' or its corresponding type declarations. + import {} from "./a.js"; + import {} from "./a.ts"; + + import {} from "./b"; + ~~~~~ +!!! error TS2307: Cannot find module './b' or its corresponding type declarations. + import {} from "./b.js"; + import {} from "./b.ts"; + import {} from "./b.d.ts"; + ~~~~~~~~~~ +!!! error TS2845: A declaration file cannot be imported without 'import type'. Did you mean to import an implementation file './b.js' instead? + import type {} from "./b.d.ts"; + + import {} from "./c.ts"; + import {} from "./c.tsx"; + ~~~~~~~~~ +!!! error TS6142: Module './c.tsx' was resolved to '/project/c.tsx', but '--jsx' is not set. + + import {} from "./d"; + ~~~~~ +!!! error TS2307: Cannot find module './d' or its corresponding type declarations. + import {} from "./d/index"; + ~~~~~~~~~~~ +!!! error TS2307: Cannot find module './d/index' or its corresponding type declarations. + import {} from "./d/index.ts"; + + import {} from "./e"; + ~~~~~ +!!! error TS2307: Cannot find module './e' or its corresponding type declarations. + +==== /project/types.d.ts (2 errors) ==== + import {} from "./a.ts"; + import {} from "./a.d.ts"; + ~~~~~~~~~~ +!!! error TS2691: An import path cannot end with a '.d.ts' extension. Consider importing './a.js' instead. + import type {} from "./a.d.ts"; + ~~~~~~~~~~ +!!! error TS2691: An import path cannot end with a '.d.ts' extension. Consider importing './a.js' instead. + \ No newline at end of file diff --git a/tests/baselines/reference/minimal_relative(allowimportingtsextensions=true,noemit=true).symbols b/tests/baselines/reference/minimal_relative(allowimportingtsextensions=true,noemit=true).symbols new file mode 100644 index 0000000000000..8087e521944d1 --- /dev/null +++ b/tests/baselines/reference/minimal_relative(allowimportingtsextensions=true,noemit=true).symbols @@ -0,0 +1,44 @@ +=== /project/a.ts === +export {}; +No type information for this code. +No type information for this code.=== /project/b.ts === +export {}; +No type information for this code. +No type information for this code.=== /project/b.d.ts === +export {}; +No type information for this code. +No type information for this code.=== /project/c.ts === +export {}; +No type information for this code. +No type information for this code.=== /project/c.tsx === +export {}; +No type information for this code. +No type information for this code.=== /project/d/index.ts === +export {}; +No type information for this code. +No type information for this code.=== /project/main.ts === +import {} from "./a"; +No type information for this code.import {} from "./a.js"; +No type information for this code.import {} from "./a.ts"; +No type information for this code. +No type information for this code.import {} from "./b"; +No type information for this code.import {} from "./b.js"; +No type information for this code.import {} from "./b.ts"; +No type information for this code.import {} from "./b.d.ts"; +No type information for this code.import type {} from "./b.d.ts"; +No type information for this code. +No type information for this code.import {} from "./c.ts"; +No type information for this code.import {} from "./c.tsx"; +No type information for this code. +No type information for this code.import {} from "./d"; +No type information for this code.import {} from "./d/index"; +No type information for this code.import {} from "./d/index.ts"; +No type information for this code. +No type information for this code.import {} from "./e"; +No type information for this code. +No type information for this code.=== /project/types.d.ts === +import {} from "./a.ts"; +No type information for this code.import {} from "./a.d.ts"; +No type information for this code.import type {} from "./a.d.ts"; +No type information for this code. +No type information for this code. \ No newline at end of file diff --git a/tests/baselines/reference/minimal_relative(allowimportingtsextensions=true,noemit=true).trace.json b/tests/baselines/reference/minimal_relative(allowimportingtsextensions=true,noemit=true).trace.json new file mode 100644 index 0000000000000..40a02fe86a714 --- /dev/null +++ b/tests/baselines/reference/minimal_relative(allowimportingtsextensions=true,noemit=true).trace.json @@ -0,0 +1,68 @@ +[ + "======== Resolving module './a' from '/project/main.ts'. ========", + "Explicitly specified module resolution kind: 'Minimal'.", + "======== Module name './a' was not resolved. ========", + "======== Resolving module './a.js' from '/project/main.ts'. ========", + "Explicitly specified module resolution kind: 'Minimal'.", + "File name '/project/a.js' has a '.js' extension - stripping it.", + "File '/project/a.ts' exist - use it as a name resolution result.", + "======== Module name './a.js' was successfully resolved to '/project/a.ts'. ========", + "======== Resolving module './a.ts' from '/project/main.ts'. ========", + "Explicitly specified module resolution kind: 'Minimal'.", + "File name '/project/a.ts' has a '.ts' extension - stripping it.", + "File '/project/a.ts' exist - use it as a name resolution result.", + "======== Module name './a.ts' was successfully resolved to '/project/a.ts'. ========", + "======== Resolving module './b' from '/project/main.ts'. ========", + "Explicitly specified module resolution kind: 'Minimal'.", + "======== Module name './b' was not resolved. ========", + "======== Resolving module './b.js' from '/project/main.ts'. ========", + "Explicitly specified module resolution kind: 'Minimal'.", + "File name '/project/b.js' has a '.js' extension - stripping it.", + "File '/project/b.ts' exist - use it as a name resolution result.", + "======== Module name './b.js' was successfully resolved to '/project/b.ts'. ========", + "======== Resolving module './b.ts' from '/project/main.ts'. ========", + "Explicitly specified module resolution kind: 'Minimal'.", + "File name '/project/b.ts' has a '.ts' extension - stripping it.", + "File '/project/b.ts' exist - use it as a name resolution result.", + "======== Module name './b.ts' was successfully resolved to '/project/b.ts'. ========", + "======== Resolving module './b.d.ts' from '/project/main.ts'. ========", + "Explicitly specified module resolution kind: 'Minimal'.", + "File name '/project/b.d.ts' has a '.d.ts' extension - stripping it.", + "File '/project/b.d.ts' exist - use it as a name resolution result.", + "======== Module name './b.d.ts' was successfully resolved to '/project/b.d.ts'. ========", + "======== Resolving module './c.ts' from '/project/main.ts'. ========", + "Explicitly specified module resolution kind: 'Minimal'.", + "File name '/project/c.ts' has a '.ts' extension - stripping it.", + "File '/project/c.ts' exist - use it as a name resolution result.", + "======== Module name './c.ts' was successfully resolved to '/project/c.ts'. ========", + "======== Resolving module './c.tsx' from '/project/main.ts'. ========", + "Explicitly specified module resolution kind: 'Minimal'.", + "File name '/project/c.tsx' has a '.tsx' extension - stripping it.", + "File '/project/c.tsx' exist - use it as a name resolution result.", + "======== Module name './c.tsx' was successfully resolved to '/project/c.tsx'. ========", + "======== Resolving module './d' from '/project/main.ts'. ========", + "Explicitly specified module resolution kind: 'Minimal'.", + "======== Module name './d' was not resolved. ========", + "======== Resolving module './d/index' from '/project/main.ts'. ========", + "Explicitly specified module resolution kind: 'Minimal'.", + "======== Module name './d/index' was not resolved. ========", + "======== Resolving module './d/index.ts' from '/project/main.ts'. ========", + "Explicitly specified module resolution kind: 'Minimal'.", + "File name '/project/d/index.ts' has a '.ts' extension - stripping it.", + "File '/project/d/index.ts' exist - use it as a name resolution result.", + "======== Module name './d/index.ts' was successfully resolved to '/project/d/index.ts'. ========", + "======== Resolving module './e' from '/project/main.ts'. ========", + "Explicitly specified module resolution kind: 'Minimal'.", + "======== Module name './e' was not resolved. ========", + "======== Resolving module './a.ts' from '/project/types.d.ts'. ========", + "Resolution for module './a.ts' was found in cache from location '/project'.", + "======== Module name './a.ts' was successfully resolved to '/project/a.ts'. ========", + "======== Resolving module './a.d.ts' from '/project/types.d.ts'. ========", + "Explicitly specified module resolution kind: 'Minimal'.", + "File name '/project/a.d.ts' has a '.d.ts' extension - stripping it.", + "File '/project/a.d.ts' does not exist.", + "File name '/project/a.d.ts' has a '.d.ts' extension - stripping it.", + "File '/project/a.js' does not exist.", + "File '/project/a.jsx' does not exist.", + "======== Module name './a.d.ts' was not resolved. ========" +] \ No newline at end of file diff --git a/tests/baselines/reference/minimal_relative(allowimportingtsextensions=true,noemit=true).types b/tests/baselines/reference/minimal_relative(allowimportingtsextensions=true,noemit=true).types new file mode 100644 index 0000000000000..8087e521944d1 --- /dev/null +++ b/tests/baselines/reference/minimal_relative(allowimportingtsextensions=true,noemit=true).types @@ -0,0 +1,44 @@ +=== /project/a.ts === +export {}; +No type information for this code. +No type information for this code.=== /project/b.ts === +export {}; +No type information for this code. +No type information for this code.=== /project/b.d.ts === +export {}; +No type information for this code. +No type information for this code.=== /project/c.ts === +export {}; +No type information for this code. +No type information for this code.=== /project/c.tsx === +export {}; +No type information for this code. +No type information for this code.=== /project/d/index.ts === +export {}; +No type information for this code. +No type information for this code.=== /project/main.ts === +import {} from "./a"; +No type information for this code.import {} from "./a.js"; +No type information for this code.import {} from "./a.ts"; +No type information for this code. +No type information for this code.import {} from "./b"; +No type information for this code.import {} from "./b.js"; +No type information for this code.import {} from "./b.ts"; +No type information for this code.import {} from "./b.d.ts"; +No type information for this code.import type {} from "./b.d.ts"; +No type information for this code. +No type information for this code.import {} from "./c.ts"; +No type information for this code.import {} from "./c.tsx"; +No type information for this code. +No type information for this code.import {} from "./d"; +No type information for this code.import {} from "./d/index"; +No type information for this code.import {} from "./d/index.ts"; +No type information for this code. +No type information for this code.import {} from "./e"; +No type information for this code. +No type information for this code.=== /project/types.d.ts === +import {} from "./a.ts"; +No type information for this code.import {} from "./a.d.ts"; +No type information for this code.import type {} from "./a.d.ts"; +No type information for this code. +No type information for this code. \ No newline at end of file diff --git a/tests/cases/conformance/moduleResolution/minimal_pathsAndBaseUrl.ts b/tests/cases/conformance/moduleResolution/minimal_pathsAndBaseUrl.ts index a7fb1a2c4ebb6..74ae8ffcde21e 100644 --- a/tests/cases/conformance/moduleResolution/minimal_pathsAndBaseUrl.ts +++ b/tests/cases/conformance/moduleResolution/minimal_pathsAndBaseUrl.ts @@ -6,6 +6,7 @@ "compilerOptions": { "moduleResolution": "minimal", "noEmit": true, + "allowImportingTsExtensions": true, "baseUrl": ".", "paths": { "*": [ diff --git a/tests/cases/conformance/moduleResolution/minimal_relative.ts b/tests/cases/conformance/moduleResolution/minimal_relative.ts index b3428c435e48a..21eb4828223f5 100644 --- a/tests/cases/conformance/moduleResolution/minimal_relative.ts +++ b/tests/cases/conformance/moduleResolution/minimal_relative.ts @@ -1,6 +1,7 @@ // @moduleResolution: minimal // @outDir: dist // @noEmit: true,false +// @allowImportingTsExtensions: true,false // @traceResolution: true // @Filename: /project/a.ts @@ -46,3 +47,8 @@ import {} from "./d/index"; import {} from "./d/index.ts"; import {} from "./e"; + +// @Filename: /project/types.d.ts +import {} from "./a.ts"; +import {} from "./a.d.ts"; +import type {} from "./a.d.ts"; From 496ef994efcde07a1bceff1c3651e18dc647dfa1 Mon Sep 17 00:00:00 2001 From: Andrew Branch Date: Thu, 15 Sep 2022 13:35:48 -0700 Subject: [PATCH 07/14] Add module specifier resolution changes --- src/compiler/moduleSpecifiers.ts | 115 +++++++++++------- .../reference/api/tsserverlibrary.d.ts | 3 +- tests/baselines/reference/api/typescript.d.ts | 3 +- .../allowImportingTsExtensions/tsconfig.json | 5 + .../tsconfig.json | 1 + .../tsconfig.json | 1 + .../tsconfig.json | 1 + .../tsconfig.json | 1 + .../tsconfig.json | 1 + .../tsconfig.json | 1 + .../tsconfig.json | 1 + .../tsconfig.json | 1 + .../tsconfig.json | 1 + .../tsconfig.json | 1 + .../tsconfig.json | 1 + .../declarationDir-is-specified.js | 1 + ...-outDir-and-declarationDir-is-specified.js | 1 + .../when-outDir-is-specified.js | 1 + .../with-outFile.js | 1 + ...e-is-specified-with-declaration-enabled.js | 1 + .../without-outDir-or-outFile-is-specified.js | 1 + 21 files changed, 94 insertions(+), 49 deletions(-) create mode 100644 tests/baselines/reference/showConfig/Shows tsconfig for single option/allowImportingTsExtensions/tsconfig.json diff --git a/src/compiler/moduleSpecifiers.ts b/src/compiler/moduleSpecifiers.ts index 32640fcb81579..1f560927e3e55 100644 --- a/src/compiler/moduleSpecifiers.ts +++ b/src/compiler/moduleSpecifiers.ts @@ -8,44 +8,76 @@ namespace ts.moduleSpecifiers { // Processed preferences interface Preferences { readonly relativePreference: RelativePreference; - readonly ending: Ending; + /** + * @param syntaxImpliedNodeFormat Used when the import syntax implies ESM or CJS irrespective of the mode of the file. + */ + getAllowedEndingsInPrefererredOrder(syntaxImpliedNodeFormat?: SourceFile["impliedNodeFormat"]): Ending[]; } - function getPreferences(host: ModuleSpecifierResolutionHost, { importModuleSpecifierPreference, importModuleSpecifierEnding }: UserPreferences, compilerOptions: CompilerOptions, importingSourceFile: SourceFile): Preferences { + function getPreferences( + host: ModuleSpecifierResolutionHost, + { importModuleSpecifierPreference, importModuleSpecifierEnding }: UserPreferences, + compilerOptions: CompilerOptions, + importingSourceFile: SourceFile, + oldImportSpecifier?: string, + ): Preferences { + const preferredEnding = getPreferredEnding(); return { relativePreference: + oldImportSpecifier !== undefined ? (isExternalModuleNameRelative(oldImportSpecifier) ? + RelativePreference.Relative : + RelativePreference.NonRelative) : importModuleSpecifierPreference === "relative" ? RelativePreference.Relative : importModuleSpecifierPreference === "non-relative" ? RelativePreference.NonRelative : importModuleSpecifierPreference === "project-relative" ? RelativePreference.ExternalNonRelative : RelativePreference.Shortest, - ending: getEnding(), + getAllowedEndingsInPrefererredOrder: syntaxImpliedNodeFormat => { + if (syntaxImpliedNodeFormat === ModuleKind.ESNext || + getEmitModuleResolutionKind(compilerOptions) === ModuleResolutionKind.Minimal || + isFormatRequiringExtensions() + ) { + return [Ending.JsExtension]; + } + if (getEmitModuleResolutionKind(compilerOptions) === ModuleResolutionKind.Classic) { + return [Ending.Index, Ending.JsExtension]; + } + switch (preferredEnding) { + case Ending.JsExtension: return [Ending.JsExtension, Ending.Minimal, Ending.Index]; + case Ending.Index: return [Ending.Index, Ending.Minimal, Ending.JsExtension]; + case Ending.Minimal: return [Ending.Minimal, Ending.Index, Ending.JsExtension]; + default: Debug.assertNever(preferredEnding); + } + }, }; - function getEnding(): Ending { + + function getPreferredEnding(): Ending { + if (oldImportSpecifier !== undefined) { + if (hasJSFileExtension(oldImportSpecifier)) return Ending.JsExtension; + if (endsWith(oldImportSpecifier, "/index")) return Ending.Index; + } switch (importModuleSpecifierEnding) { case "minimal": return Ending.Minimal; case "index": return Ending.Index; case "js": return Ending.JsExtension; - default: return usesJsExtensionOnImports(importingSourceFile) || isFormatRequiringExtensions(compilerOptions, importingSourceFile.path, host) ? Ending.JsExtension - : getEmitModuleResolutionKind(compilerOptions) !== ModuleResolutionKind.NodeJs ? Ending.Index : Ending.Minimal; + default: return usesJsExtensionOnImports(importingSourceFile) ? Ending.JsExtension : Ending.Minimal; } } - } - - function getPreferencesForUpdate(compilerOptions: CompilerOptions, oldImportSpecifier: string, importingSourceFileName: Path, host: ModuleSpecifierResolutionHost): Preferences { - return { - relativePreference: isExternalModuleNameRelative(oldImportSpecifier) ? RelativePreference.Relative : RelativePreference.NonRelative, - ending: hasJSFileExtension(oldImportSpecifier) || isFormatRequiringExtensions(compilerOptions, importingSourceFileName, host) ? - Ending.JsExtension : - getEmitModuleResolutionKind(compilerOptions) !== ModuleResolutionKind.NodeJs || endsWith(oldImportSpecifier, "index") ? Ending.Index : Ending.Minimal, - }; - } - function isFormatRequiringExtensions(compilerOptions: CompilerOptions, importingSourceFileName: Path, host: ModuleSpecifierResolutionHost) { - if (getEmitModuleResolutionKind(compilerOptions) !== ModuleResolutionKind.Node16 - && getEmitModuleResolutionKind(compilerOptions) !== ModuleResolutionKind.NodeNext) { - return false; + function isFormatRequiringExtensions() { + switch (getEmitModuleResolutionKind(compilerOptions)) { + case ModuleResolutionKind.Minimal: + return true; + case ModuleResolutionKind.Node16: + case ModuleResolutionKind.NodeNext: + return getImpliedNodeFormatForFile( + importingSourceFile.path, + host.getPackageJsonInfoCache?.(), + getModuleResolutionHost(host), compilerOptions, + ) !== ModuleKind.CommonJS; + default: + return false; + } } - return getImpliedNodeFormatForFile(importingSourceFileName, host.getPackageJsonInfoCache?.(), getModuleResolutionHost(host), compilerOptions) !== ModuleKind.CommonJS; } function getModuleResolutionHost(host: ModuleSpecifierResolutionHost): ModuleResolutionHost { @@ -72,7 +104,7 @@ namespace ts.moduleSpecifiers { oldImportSpecifier: string, options: ModuleSpecifierOptions = {}, ): string | undefined { - const res = getModuleSpecifierWorker(compilerOptions, importingSourceFile, importingSourceFileName, toFileName, host, getPreferencesForUpdate(compilerOptions, oldImportSpecifier, importingSourceFileName, host), {}, options); + const res = getModuleSpecifierWorker(compilerOptions, importingSourceFile, importingSourceFileName, toFileName, host, getPreferences(host, {}, compilerOptions, importingSourceFile, oldImportSpecifier), {}, options); if (res === oldImportSpecifier) return undefined; return res; } @@ -293,11 +325,13 @@ namespace ts.moduleSpecifiers { return { getCanonicalFileName, importingSourceFileName, sourceDirectory }; } - function getLocalModuleSpecifier(moduleFileName: string, info: Info, compilerOptions: CompilerOptions, host: ModuleSpecifierResolutionHost, importMode: SourceFile["impliedNodeFormat"], { ending, relativePreference }: Preferences): string { + function getLocalModuleSpecifier(moduleFileName: string, info: Info, compilerOptions: CompilerOptions, host: ModuleSpecifierResolutionHost, importMode: SourceFile["impliedNodeFormat"], { getAllowedEndingsInPrefererredOrder, relativePreference }: Preferences): string { const { baseUrl, paths, rootDirs } = compilerOptions; const { sourceDirectory, getCanonicalFileName } = info; + const allowedEndings = getAllowedEndingsInPrefererredOrder(importMode); + const ending = allowedEndings[0]; const relativePath = rootDirs && tryGetModuleNameFromRootDirs(rootDirs, moduleFileName, sourceDirectory, getCanonicalFileName, ending, compilerOptions) || - removeExtensionAndIndexPostFix(ensurePathIsNonModuleName(getRelativePathFromDirectory(sourceDirectory, moduleFileName, getCanonicalFileName)), ending, compilerOptions); + processEnding(ensurePathIsNonModuleName(getRelativePathFromDirectory(sourceDirectory, moduleFileName, getCanonicalFileName)), ending, compilerOptions); if (!baseUrl && !paths || relativePreference === RelativePreference.Relative) { return relativePath; } @@ -308,8 +342,8 @@ namespace ts.moduleSpecifiers { return relativePath; } - const fromPaths = paths && tryGetModuleNameFromPaths(relativeToBaseUrl, paths, getAllowedEndings(ending, compilerOptions, importMode), host, compilerOptions); - const nonRelative = fromPaths === undefined && baseUrl !== undefined ? removeExtensionAndIndexPostFix(relativeToBaseUrl, ending, compilerOptions) : fromPaths; + const fromPaths = paths && tryGetModuleNameFromPaths(relativeToBaseUrl, paths, allowedEndings, host, compilerOptions); + const nonRelative = fromPaths === undefined && baseUrl !== undefined ? processEnding(relativeToBaseUrl, ending, compilerOptions) : fromPaths; if (!nonRelative) { return relativePath; } @@ -558,18 +592,6 @@ namespace ts.moduleSpecifiers { } } - function getAllowedEndings(preferredEnding: Ending, compilerOptions: CompilerOptions, importMode: SourceFile["impliedNodeFormat"]) { - if (getEmitModuleResolutionKind(compilerOptions) >= ModuleResolutionKind.Node16 && importMode === ModuleKind.ESNext) { - return [Ending.JsExtension]; - } - switch (preferredEnding) { - case Ending.JsExtension: return [Ending.JsExtension, Ending.Minimal, Ending.Index]; - case Ending.Index: return [Ending.Index, Ending.Minimal, Ending.JsExtension]; - case Ending.Minimal: return [Ending.Minimal, Ending.Index, Ending.JsExtension]; - default: Debug.assertNever(preferredEnding); - } - } - function tryGetModuleNameFromPaths(relativeToBaseUrl: string, paths: MapLike, allowedEndings: Ending[], host: ModuleSpecifierResolutionHost, compilerOptions: CompilerOptions): string | undefined { for (const key in paths) { for (const patternText of paths[key]) { @@ -613,7 +635,7 @@ namespace ts.moduleSpecifiers { // sorted among the others for a particular value of `importModuleSpecifierEnding`. const candidates: { ending: Ending | undefined, value: string }[] = allowedEndings.map(ending => ({ ending, - value: removeExtensionAndIndexPostFix(relativeToBaseUrl, ending, compilerOptions) + value: processEnding(relativeToBaseUrl, ending, compilerOptions) })); if (tryGetExtensionFromPath(pattern)) { candidates.push({ ending: undefined, value: relativeToBaseUrl }); @@ -650,7 +672,7 @@ namespace ts.moduleSpecifiers { // `Ending.Index` result, which should already be in the list of candidates if `Minimal` was. (Note: the assumption here is // that every module resolution mode that supports dropping extensions also supports dropping `/index`. Like literally // everything else in this file, this logic needs to be updated if that's not true in some future module resolution mode.) - return ending !== Ending.Minimal || value === removeExtensionAndIndexPostFix(relativeToBaseUrl, ending, compilerOptions, host); + return ending !== Ending.Minimal || value === processEnding(relativeToBaseUrl, ending, compilerOptions, host); } } @@ -733,13 +755,11 @@ namespace ts.moduleSpecifiers { const normalizedSourcePath = getPathRelativeToRootDirs(sourceDirectory, rootDirs, getCanonicalFileName); const relativePath = normalizedSourcePath !== undefined ? ensurePathIsNonModuleName(getRelativePathFromDirectory(normalizedSourcePath, normalizedTargetPath, getCanonicalFileName)) : normalizedTargetPath; - return getEmitModuleResolutionKind(compilerOptions) === ModuleResolutionKind.NodeJs - ? removeExtensionAndIndexPostFix(relativePath, ending, compilerOptions) - : removeFileExtension(relativePath); + return processEnding(relativePath, ending, compilerOptions); } function tryGetModuleNameAsNodeModule({ path, isRedirect }: ModulePath, { getCanonicalFileName, sourceDirectory }: Info, importingSourceFile: SourceFile , host: ModuleSpecifierResolutionHost, options: CompilerOptions, userPreferences: UserPreferences, packageNameOnly?: boolean, overrideMode?: ModuleKind.ESNext | ModuleKind.CommonJS): string | undefined { - if (!host.fileExists || !host.readFile) { + if (!host.fileExists || !host.readFile || getEmitModuleResolutionKind(options) === ModuleResolutionKind.Minimal) { return undefined; } const parts: NodeModulePathParts = getNodeModulePathParts(path)!; @@ -750,6 +770,7 @@ namespace ts.moduleSpecifiers { // Simplify the full file path to something that can be resolved by Node. const preferences = getPreferences(host, userPreferences, options, importingSourceFile); + const allowedEndings = preferences.getAllowedEndingsInPrefererredOrder(); let moduleSpecifier = path; let isPackageRootPath = false; if (!packageNameOnly) { @@ -776,7 +797,7 @@ namespace ts.moduleSpecifiers { // try with next level of directory packageRootIndex = path.indexOf(directorySeparator, packageRootIndex + 1); if (packageRootIndex === -1) { - moduleSpecifier = removeExtensionAndIndexPostFix(moduleFileName, preferences.ending, options, host); + moduleSpecifier = processEnding(moduleFileName, allowedEndings[0], options, host); break; } } @@ -832,7 +853,7 @@ namespace ts.moduleSpecifiers { const fromPaths = tryGetModuleNameFromPaths( subModuleName, versionPaths.paths, - getAllowedEndings(preferences.ending, options, importMode), + allowedEndings, host, options ); @@ -889,7 +910,7 @@ namespace ts.moduleSpecifiers { }); } - function removeExtensionAndIndexPostFix(fileName: string, ending: Ending, options: CompilerOptions, host?: ModuleSpecifierResolutionHost): string { + function processEnding(fileName: string, ending: Ending, options: CompilerOptions, host?: ModuleSpecifierResolutionHost): string { if (fileExtensionIsOneOf(fileName, [Extension.Json, Extension.Mjs, Extension.Cjs])) return fileName; const noExtension = removeFileExtension(fileName); if (fileName === noExtension) return fileName; diff --git a/tests/baselines/reference/api/tsserverlibrary.d.ts b/tests/baselines/reference/api/tsserverlibrary.d.ts index 936b189192bfe..ba647af4fc3eb 100644 --- a/tests/baselines/reference/api/tsserverlibrary.d.ts +++ b/tests/baselines/reference/api/tsserverlibrary.d.ts @@ -2993,6 +2993,7 @@ declare namespace ts { } export type CompilerOptionsValue = string | number | boolean | (string | number)[] | string[] | MapLike | PluginImport[] | ProjectReference[] | null | undefined; export interface CompilerOptions { + allowImportingTsExtensions?: boolean; allowJs?: boolean; allowSyntheticDefaultImports?: boolean; allowUmdGlobalAccess?: boolean; @@ -5059,7 +5060,7 @@ declare namespace ts { export function classicNameResolver(moduleName: string, containingFile: string, compilerOptions: CompilerOptions, host: ModuleResolutionHost, cache?: NonRelativeModuleNameResolutionCache, redirectedReference?: ResolvedProjectReference): ResolvedModuleWithFailedLookupLocations; export function minimalModuleNameResolver(moduleName: string, containingFile: string, compilerOptions: CompilerOptions, host: ModuleResolutionHost): ResolvedModuleWithFailedLookupLocations; export function shouldResolveTsExtension(compilerOptions: CompilerOptions): boolean; - export function shouldAllowTsExtension(compilerOptions: CompilerOptions): boolean; + export function shouldAllowImportingTsExtension(compilerOptions: CompilerOptions, fromFileName?: string): boolean | "" | undefined; export {}; } declare namespace ts { diff --git a/tests/baselines/reference/api/typescript.d.ts b/tests/baselines/reference/api/typescript.d.ts index 5f0a608c6962c..cf28270b66367 100644 --- a/tests/baselines/reference/api/typescript.d.ts +++ b/tests/baselines/reference/api/typescript.d.ts @@ -2993,6 +2993,7 @@ declare namespace ts { } export type CompilerOptionsValue = string | number | boolean | (string | number)[] | string[] | MapLike | PluginImport[] | ProjectReference[] | null | undefined; export interface CompilerOptions { + allowImportingTsExtensions?: boolean; allowJs?: boolean; allowSyntheticDefaultImports?: boolean; allowUmdGlobalAccess?: boolean; @@ -5059,7 +5060,7 @@ declare namespace ts { export function classicNameResolver(moduleName: string, containingFile: string, compilerOptions: CompilerOptions, host: ModuleResolutionHost, cache?: NonRelativeModuleNameResolutionCache, redirectedReference?: ResolvedProjectReference): ResolvedModuleWithFailedLookupLocations; export function minimalModuleNameResolver(moduleName: string, containingFile: string, compilerOptions: CompilerOptions, host: ModuleResolutionHost): ResolvedModuleWithFailedLookupLocations; export function shouldResolveTsExtension(compilerOptions: CompilerOptions): boolean; - export function shouldAllowTsExtension(compilerOptions: CompilerOptions): boolean; + export function shouldAllowImportingTsExtension(compilerOptions: CompilerOptions, fromFileName?: string): boolean | "" | undefined; export {}; } declare namespace ts { diff --git a/tests/baselines/reference/showConfig/Shows tsconfig for single option/allowImportingTsExtensions/tsconfig.json b/tests/baselines/reference/showConfig/Shows tsconfig for single option/allowImportingTsExtensions/tsconfig.json new file mode 100644 index 0000000000000..88c95f9eb8307 --- /dev/null +++ b/tests/baselines/reference/showConfig/Shows tsconfig for single option/allowImportingTsExtensions/tsconfig.json @@ -0,0 +1,5 @@ +{ + "compilerOptions": { + "allowImportingTsExtensions": true + } +} diff --git a/tests/baselines/reference/tsConfig/Default initialized TSConfig/tsconfig.json b/tests/baselines/reference/tsConfig/Default initialized TSConfig/tsconfig.json index 75dcaeac2e2b9..5cad175ba34fa 100644 --- a/tests/baselines/reference/tsConfig/Default initialized TSConfig/tsconfig.json +++ b/tests/baselines/reference/tsConfig/Default initialized TSConfig/tsconfig.json @@ -35,6 +35,7 @@ // "types": [], /* Specify type package names to be included without being referenced in a source file. */ // "allowUmdGlobalAccess": true, /* Allow accessing UMD globals from modules. */ // "moduleSuffixes": [], /* List of file name suffixes to search when resolving a module. */ + // "allowImportingTsExtensions": true, /* Allow imports to include TypeScript file extensions. Requires '--moduleResolution minimal' and either '--noEmit' or '--emitDeclarationOnly' to be set. */ // "resolveJsonModule": true, /* Enable importing .json files. */ // "noResolve": true, /* Disallow 'import's, 'require's or ''s from expanding the number of files TypeScript should add to a project. */ diff --git a/tests/baselines/reference/tsConfig/Initialized TSConfig with --help/tsconfig.json b/tests/baselines/reference/tsConfig/Initialized TSConfig with --help/tsconfig.json index 75dcaeac2e2b9..5cad175ba34fa 100644 --- a/tests/baselines/reference/tsConfig/Initialized TSConfig with --help/tsconfig.json +++ b/tests/baselines/reference/tsConfig/Initialized TSConfig with --help/tsconfig.json @@ -35,6 +35,7 @@ // "types": [], /* Specify type package names to be included without being referenced in a source file. */ // "allowUmdGlobalAccess": true, /* Allow accessing UMD globals from modules. */ // "moduleSuffixes": [], /* List of file name suffixes to search when resolving a module. */ + // "allowImportingTsExtensions": true, /* Allow imports to include TypeScript file extensions. Requires '--moduleResolution minimal' and either '--noEmit' or '--emitDeclarationOnly' to be set. */ // "resolveJsonModule": true, /* Enable importing .json files. */ // "noResolve": true, /* Disallow 'import's, 'require's or ''s from expanding the number of files TypeScript should add to a project. */ diff --git a/tests/baselines/reference/tsConfig/Initialized TSConfig with --watch/tsconfig.json b/tests/baselines/reference/tsConfig/Initialized TSConfig with --watch/tsconfig.json index 75dcaeac2e2b9..5cad175ba34fa 100644 --- a/tests/baselines/reference/tsConfig/Initialized TSConfig with --watch/tsconfig.json +++ b/tests/baselines/reference/tsConfig/Initialized TSConfig with --watch/tsconfig.json @@ -35,6 +35,7 @@ // "types": [], /* Specify type package names to be included without being referenced in a source file. */ // "allowUmdGlobalAccess": true, /* Allow accessing UMD globals from modules. */ // "moduleSuffixes": [], /* List of file name suffixes to search when resolving a module. */ + // "allowImportingTsExtensions": true, /* Allow imports to include TypeScript file extensions. Requires '--moduleResolution minimal' and either '--noEmit' or '--emitDeclarationOnly' to be set. */ // "resolveJsonModule": true, /* Enable importing .json files. */ // "noResolve": true, /* Disallow 'import's, 'require's or ''s from expanding the number of files TypeScript should add to a project. */ diff --git a/tests/baselines/reference/tsConfig/Initialized TSConfig with advanced options/tsconfig.json b/tests/baselines/reference/tsConfig/Initialized TSConfig with advanced options/tsconfig.json index ce36f2a0fcfd7..e1b9e67e7b66d 100644 --- a/tests/baselines/reference/tsConfig/Initialized TSConfig with advanced options/tsconfig.json +++ b/tests/baselines/reference/tsConfig/Initialized TSConfig with advanced options/tsconfig.json @@ -35,6 +35,7 @@ // "types": [], /* Specify type package names to be included without being referenced in a source file. */ // "allowUmdGlobalAccess": true, /* Allow accessing UMD globals from modules. */ // "moduleSuffixes": [], /* List of file name suffixes to search when resolving a module. */ + // "allowImportingTsExtensions": true, /* Allow imports to include TypeScript file extensions. Requires '--moduleResolution minimal' and either '--noEmit' or '--emitDeclarationOnly' to be set. */ // "resolveJsonModule": true, /* Enable importing .json files. */ // "noResolve": true, /* Disallow 'import's, 'require's or ''s from expanding the number of files TypeScript should add to a project. */ diff --git a/tests/baselines/reference/tsConfig/Initialized TSConfig with boolean value compiler options/tsconfig.json b/tests/baselines/reference/tsConfig/Initialized TSConfig with boolean value compiler options/tsconfig.json index a4be57dd3410e..cc29170683efb 100644 --- a/tests/baselines/reference/tsConfig/Initialized TSConfig with boolean value compiler options/tsconfig.json +++ b/tests/baselines/reference/tsConfig/Initialized TSConfig with boolean value compiler options/tsconfig.json @@ -35,6 +35,7 @@ // "types": [], /* Specify type package names to be included without being referenced in a source file. */ // "allowUmdGlobalAccess": true, /* Allow accessing UMD globals from modules. */ // "moduleSuffixes": [], /* List of file name suffixes to search when resolving a module. */ + // "allowImportingTsExtensions": true, /* Allow imports to include TypeScript file extensions. Requires '--moduleResolution minimal' and either '--noEmit' or '--emitDeclarationOnly' to be set. */ // "resolveJsonModule": true, /* Enable importing .json files. */ // "noResolve": true, /* Disallow 'import's, 'require's or ''s from expanding the number of files TypeScript should add to a project. */ diff --git a/tests/baselines/reference/tsConfig/Initialized TSConfig with enum value compiler options/tsconfig.json b/tests/baselines/reference/tsConfig/Initialized TSConfig with enum value compiler options/tsconfig.json index faa350ae98575..0b6e055e0a2cd 100644 --- a/tests/baselines/reference/tsConfig/Initialized TSConfig with enum value compiler options/tsconfig.json +++ b/tests/baselines/reference/tsConfig/Initialized TSConfig with enum value compiler options/tsconfig.json @@ -35,6 +35,7 @@ // "types": [], /* Specify type package names to be included without being referenced in a source file. */ // "allowUmdGlobalAccess": true, /* Allow accessing UMD globals from modules. */ // "moduleSuffixes": [], /* List of file name suffixes to search when resolving a module. */ + // "allowImportingTsExtensions": true, /* Allow imports to include TypeScript file extensions. Requires '--moduleResolution minimal' and either '--noEmit' or '--emitDeclarationOnly' to be set. */ // "resolveJsonModule": true, /* Enable importing .json files. */ // "noResolve": true, /* Disallow 'import's, 'require's or ''s from expanding the number of files TypeScript should add to a project. */ diff --git a/tests/baselines/reference/tsConfig/Initialized TSConfig with files options/tsconfig.json b/tests/baselines/reference/tsConfig/Initialized TSConfig with files options/tsconfig.json index 09587994ffbcd..01830a8f79b49 100644 --- a/tests/baselines/reference/tsConfig/Initialized TSConfig with files options/tsconfig.json +++ b/tests/baselines/reference/tsConfig/Initialized TSConfig with files options/tsconfig.json @@ -35,6 +35,7 @@ // "types": [], /* Specify type package names to be included without being referenced in a source file. */ // "allowUmdGlobalAccess": true, /* Allow accessing UMD globals from modules. */ // "moduleSuffixes": [], /* List of file name suffixes to search when resolving a module. */ + // "allowImportingTsExtensions": true, /* Allow imports to include TypeScript file extensions. Requires '--moduleResolution minimal' and either '--noEmit' or '--emitDeclarationOnly' to be set. */ // "resolveJsonModule": true, /* Enable importing .json files. */ // "noResolve": true, /* Disallow 'import's, 'require's or ''s from expanding the number of files TypeScript should add to a project. */ diff --git a/tests/baselines/reference/tsConfig/Initialized TSConfig with incorrect compiler option value/tsconfig.json b/tests/baselines/reference/tsConfig/Initialized TSConfig with incorrect compiler option value/tsconfig.json index abb2dfd47088b..6798430ea05ee 100644 --- a/tests/baselines/reference/tsConfig/Initialized TSConfig with incorrect compiler option value/tsconfig.json +++ b/tests/baselines/reference/tsConfig/Initialized TSConfig with incorrect compiler option value/tsconfig.json @@ -35,6 +35,7 @@ // "types": [], /* Specify type package names to be included without being referenced in a source file. */ // "allowUmdGlobalAccess": true, /* Allow accessing UMD globals from modules. */ // "moduleSuffixes": [], /* List of file name suffixes to search when resolving a module. */ + // "allowImportingTsExtensions": true, /* Allow imports to include TypeScript file extensions. Requires '--moduleResolution minimal' and either '--noEmit' or '--emitDeclarationOnly' to be set. */ // "resolveJsonModule": true, /* Enable importing .json files. */ // "noResolve": true, /* Disallow 'import's, 'require's or ''s from expanding the number of files TypeScript should add to a project. */ diff --git a/tests/baselines/reference/tsConfig/Initialized TSConfig with incorrect compiler option/tsconfig.json b/tests/baselines/reference/tsConfig/Initialized TSConfig with incorrect compiler option/tsconfig.json index 75dcaeac2e2b9..5cad175ba34fa 100644 --- a/tests/baselines/reference/tsConfig/Initialized TSConfig with incorrect compiler option/tsconfig.json +++ b/tests/baselines/reference/tsConfig/Initialized TSConfig with incorrect compiler option/tsconfig.json @@ -35,6 +35,7 @@ // "types": [], /* Specify type package names to be included without being referenced in a source file. */ // "allowUmdGlobalAccess": true, /* Allow accessing UMD globals from modules. */ // "moduleSuffixes": [], /* List of file name suffixes to search when resolving a module. */ + // "allowImportingTsExtensions": true, /* Allow imports to include TypeScript file extensions. Requires '--moduleResolution minimal' and either '--noEmit' or '--emitDeclarationOnly' to be set. */ // "resolveJsonModule": true, /* Enable importing .json files. */ // "noResolve": true, /* Disallow 'import's, 'require's or ''s from expanding the number of files TypeScript should add to a project. */ diff --git a/tests/baselines/reference/tsConfig/Initialized TSConfig with list compiler options with enum value/tsconfig.json b/tests/baselines/reference/tsConfig/Initialized TSConfig with list compiler options with enum value/tsconfig.json index 04aa9196bfc65..6bae69884ebdb 100644 --- a/tests/baselines/reference/tsConfig/Initialized TSConfig with list compiler options with enum value/tsconfig.json +++ b/tests/baselines/reference/tsConfig/Initialized TSConfig with list compiler options with enum value/tsconfig.json @@ -35,6 +35,7 @@ // "types": [], /* Specify type package names to be included without being referenced in a source file. */ // "allowUmdGlobalAccess": true, /* Allow accessing UMD globals from modules. */ // "moduleSuffixes": [], /* List of file name suffixes to search when resolving a module. */ + // "allowImportingTsExtensions": true, /* Allow imports to include TypeScript file extensions. Requires '--moduleResolution minimal' and either '--noEmit' or '--emitDeclarationOnly' to be set. */ // "resolveJsonModule": true, /* Enable importing .json files. */ // "noResolve": true, /* Disallow 'import's, 'require's or ''s from expanding the number of files TypeScript should add to a project. */ diff --git a/tests/baselines/reference/tsConfig/Initialized TSConfig with list compiler options/tsconfig.json b/tests/baselines/reference/tsConfig/Initialized TSConfig with list compiler options/tsconfig.json index 4eb9bb8aa4b84..c6de1fdcc3575 100644 --- a/tests/baselines/reference/tsConfig/Initialized TSConfig with list compiler options/tsconfig.json +++ b/tests/baselines/reference/tsConfig/Initialized TSConfig with list compiler options/tsconfig.json @@ -35,6 +35,7 @@ "types": ["jquery","mocha"], /* Specify type package names to be included without being referenced in a source file. */ // "allowUmdGlobalAccess": true, /* Allow accessing UMD globals from modules. */ // "moduleSuffixes": [], /* List of file name suffixes to search when resolving a module. */ + // "allowImportingTsExtensions": true, /* Allow imports to include TypeScript file extensions. Requires '--moduleResolution minimal' and either '--noEmit' or '--emitDeclarationOnly' to be set. */ // "resolveJsonModule": true, /* Enable importing .json files. */ // "noResolve": true, /* Disallow 'import's, 'require's or ''s from expanding the number of files TypeScript should add to a project. */ diff --git a/tests/baselines/reference/tscWatch/programUpdates/should-not-trigger-recompilation-because-of-program-emit/declarationDir-is-specified.js b/tests/baselines/reference/tscWatch/programUpdates/should-not-trigger-recompilation-because-of-program-emit/declarationDir-is-specified.js index 2cf43a8189e28..782dc8bc57911 100644 --- a/tests/baselines/reference/tscWatch/programUpdates/should-not-trigger-recompilation-because-of-program-emit/declarationDir-is-specified.js +++ b/tests/baselines/reference/tscWatch/programUpdates/should-not-trigger-recompilation-because-of-program-emit/declarationDir-is-specified.js @@ -56,6 +56,7 @@ interface Array { length: number; [n: number]: T; } // "types": [], /* Specify type package names to be included without being referenced in a source file. */ // "allowUmdGlobalAccess": true, /* Allow accessing UMD globals from modules. */ // "moduleSuffixes": [], /* List of file name suffixes to search when resolving a module. */ + // "allowImportingTsExtensions": true, /* Allow imports to include TypeScript file extensions. Requires '--moduleResolution minimal' and either '--noEmit' or '--emitDeclarationOnly' to be set. */ // "resolveJsonModule": true, /* Enable importing .json files. */ // "noResolve": true, /* Disallow 'import's, 'require's or ''s from expanding the number of files TypeScript should add to a project. */ diff --git a/tests/baselines/reference/tscWatch/programUpdates/should-not-trigger-recompilation-because-of-program-emit/when-outDir-and-declarationDir-is-specified.js b/tests/baselines/reference/tscWatch/programUpdates/should-not-trigger-recompilation-because-of-program-emit/when-outDir-and-declarationDir-is-specified.js index 0bdc2d356c5e3..54e482fe2570b 100644 --- a/tests/baselines/reference/tscWatch/programUpdates/should-not-trigger-recompilation-because-of-program-emit/when-outDir-and-declarationDir-is-specified.js +++ b/tests/baselines/reference/tscWatch/programUpdates/should-not-trigger-recompilation-because-of-program-emit/when-outDir-and-declarationDir-is-specified.js @@ -56,6 +56,7 @@ interface Array { length: number; [n: number]: T; } // "types": [], /* Specify type package names to be included without being referenced in a source file. */ // "allowUmdGlobalAccess": true, /* Allow accessing UMD globals from modules. */ // "moduleSuffixes": [], /* List of file name suffixes to search when resolving a module. */ + // "allowImportingTsExtensions": true, /* Allow imports to include TypeScript file extensions. Requires '--moduleResolution minimal' and either '--noEmit' or '--emitDeclarationOnly' to be set. */ // "resolveJsonModule": true, /* Enable importing .json files. */ // "noResolve": true, /* Disallow 'import's, 'require's or ''s from expanding the number of files TypeScript should add to a project. */ diff --git a/tests/baselines/reference/tscWatch/programUpdates/should-not-trigger-recompilation-because-of-program-emit/when-outDir-is-specified.js b/tests/baselines/reference/tscWatch/programUpdates/should-not-trigger-recompilation-because-of-program-emit/when-outDir-is-specified.js index 673a8e6669886..5b88985795b6e 100644 --- a/tests/baselines/reference/tscWatch/programUpdates/should-not-trigger-recompilation-because-of-program-emit/when-outDir-is-specified.js +++ b/tests/baselines/reference/tscWatch/programUpdates/should-not-trigger-recompilation-because-of-program-emit/when-outDir-is-specified.js @@ -56,6 +56,7 @@ interface Array { length: number; [n: number]: T; } // "types": [], /* Specify type package names to be included without being referenced in a source file. */ // "allowUmdGlobalAccess": true, /* Allow accessing UMD globals from modules. */ // "moduleSuffixes": [], /* List of file name suffixes to search when resolving a module. */ + // "allowImportingTsExtensions": true, /* Allow imports to include TypeScript file extensions. Requires '--moduleResolution minimal' and either '--noEmit' or '--emitDeclarationOnly' to be set. */ // "resolveJsonModule": true, /* Enable importing .json files. */ // "noResolve": true, /* Disallow 'import's, 'require's or ''s from expanding the number of files TypeScript should add to a project. */ diff --git a/tests/baselines/reference/tscWatch/programUpdates/should-not-trigger-recompilation-because-of-program-emit/with-outFile.js b/tests/baselines/reference/tscWatch/programUpdates/should-not-trigger-recompilation-because-of-program-emit/with-outFile.js index 83e6548b002fb..482495d68b2c7 100644 --- a/tests/baselines/reference/tscWatch/programUpdates/should-not-trigger-recompilation-because-of-program-emit/with-outFile.js +++ b/tests/baselines/reference/tscWatch/programUpdates/should-not-trigger-recompilation-because-of-program-emit/with-outFile.js @@ -56,6 +56,7 @@ interface Array { length: number; [n: number]: T; } // "types": [], /* Specify type package names to be included without being referenced in a source file. */ // "allowUmdGlobalAccess": true, /* Allow accessing UMD globals from modules. */ // "moduleSuffixes": [], /* List of file name suffixes to search when resolving a module. */ + // "allowImportingTsExtensions": true, /* Allow imports to include TypeScript file extensions. Requires '--moduleResolution minimal' and either '--noEmit' or '--emitDeclarationOnly' to be set. */ // "resolveJsonModule": true, /* Enable importing .json files. */ // "noResolve": true, /* Disallow 'import's, 'require's or ''s from expanding the number of files TypeScript should add to a project. */ diff --git a/tests/baselines/reference/tscWatch/programUpdates/should-not-trigger-recompilation-because-of-program-emit/without-outDir-or-outFile-is-specified-with-declaration-enabled.js b/tests/baselines/reference/tscWatch/programUpdates/should-not-trigger-recompilation-because-of-program-emit/without-outDir-or-outFile-is-specified-with-declaration-enabled.js index c87baf238012c..a80a8e8c3c89e 100644 --- a/tests/baselines/reference/tscWatch/programUpdates/should-not-trigger-recompilation-because-of-program-emit/without-outDir-or-outFile-is-specified-with-declaration-enabled.js +++ b/tests/baselines/reference/tscWatch/programUpdates/should-not-trigger-recompilation-because-of-program-emit/without-outDir-or-outFile-is-specified-with-declaration-enabled.js @@ -56,6 +56,7 @@ interface Array { length: number; [n: number]: T; } // "types": [], /* Specify type package names to be included without being referenced in a source file. */ // "allowUmdGlobalAccess": true, /* Allow accessing UMD globals from modules. */ // "moduleSuffixes": [], /* List of file name suffixes to search when resolving a module. */ + // "allowImportingTsExtensions": true, /* Allow imports to include TypeScript file extensions. Requires '--moduleResolution minimal' and either '--noEmit' or '--emitDeclarationOnly' to be set. */ // "resolveJsonModule": true, /* Enable importing .json files. */ // "noResolve": true, /* Disallow 'import's, 'require's or ''s from expanding the number of files TypeScript should add to a project. */ diff --git a/tests/baselines/reference/tscWatch/programUpdates/should-not-trigger-recompilation-because-of-program-emit/without-outDir-or-outFile-is-specified.js b/tests/baselines/reference/tscWatch/programUpdates/should-not-trigger-recompilation-because-of-program-emit/without-outDir-or-outFile-is-specified.js index 82310b617cd3d..b1b8e8a3eaedf 100644 --- a/tests/baselines/reference/tscWatch/programUpdates/should-not-trigger-recompilation-because-of-program-emit/without-outDir-or-outFile-is-specified.js +++ b/tests/baselines/reference/tscWatch/programUpdates/should-not-trigger-recompilation-because-of-program-emit/without-outDir-or-outFile-is-specified.js @@ -56,6 +56,7 @@ interface Array { length: number; [n: number]: T; } // "types": [], /* Specify type package names to be included without being referenced in a source file. */ // "allowUmdGlobalAccess": true, /* Allow accessing UMD globals from modules. */ // "moduleSuffixes": [], /* List of file name suffixes to search when resolving a module. */ + // "allowImportingTsExtensions": true, /* Allow imports to include TypeScript file extensions. Requires '--moduleResolution minimal' and either '--noEmit' or '--emitDeclarationOnly' to be set. */ // "resolveJsonModule": true, /* Enable importing .json files. */ // "noResolve": true, /* Disallow 'import's, 'require's or ''s from expanding the number of files TypeScript should add to a project. */ From 458c12596f10e3f0d347c14b7b89bd61f114a1ab Mon Sep 17 00:00:00 2001 From: Andrew Branch Date: Mon, 19 Sep 2022 11:11:20 -0700 Subject: [PATCH 08/14] Add auto-import tests --- src/compiler/moduleSpecifiers.ts | 18 ++++-- src/harness/fourslashImpl.ts | 64 +++++++++++++++++--- src/harness/fourslashInterfaceImpl.ts | 4 ++ src/services/utilities.ts | 3 +- tests/cases/fourslash/autoImportsMinimal1.ts | 17 ++++++ tests/cases/fourslash/autoImportsMinimal2.ts | 19 ++++++ tests/cases/fourslash/fourslash.ts | 1 + 7 files changed, 113 insertions(+), 13 deletions(-) create mode 100644 tests/cases/fourslash/autoImportsMinimal1.ts create mode 100644 tests/cases/fourslash/autoImportsMinimal2.ts diff --git a/src/compiler/moduleSpecifiers.ts b/src/compiler/moduleSpecifiers.ts index 1f560927e3e55..119a55565f34d 100644 --- a/src/compiler/moduleSpecifiers.ts +++ b/src/compiler/moduleSpecifiers.ts @@ -3,7 +3,7 @@ namespace ts.moduleSpecifiers { const enum RelativePreference { Relative, NonRelative, Shortest, ExternalNonRelative } // See UserPreferences#importPathEnding - const enum Ending { Minimal, Index, JsExtension } + const enum Ending { Minimal, Index, JsExtension, TsExtension } // Processed preferences interface Preferences { @@ -36,6 +36,9 @@ namespace ts.moduleSpecifiers { getEmitModuleResolutionKind(compilerOptions) === ModuleResolutionKind.Minimal || isFormatRequiringExtensions() ) { + if (shouldAllowImportingTsExtension(compilerOptions, importingSourceFile.fileName)) { + return [Ending.TsExtension, Ending.JsExtension]; + } return [Ending.JsExtension]; } if (getEmitModuleResolutionKind(compilerOptions) === ModuleResolutionKind.Classic) { @@ -43,6 +46,7 @@ namespace ts.moduleSpecifiers { } switch (preferredEnding) { case Ending.JsExtension: return [Ending.JsExtension, Ending.Minimal, Ending.Index]; + case Ending.TsExtension: return [Ending.TsExtension, Ending.TsExtension, Ending.Minimal, Ending.Index]; case Ending.Index: return [Ending.Index, Ending.Minimal, Ending.JsExtension]; case Ending.Minimal: return [Ending.Minimal, Ending.Index, Ending.JsExtension]; default: Debug.assertNever(preferredEnding); @@ -58,8 +62,10 @@ namespace ts.moduleSpecifiers { switch (importModuleSpecifierEnding) { case "minimal": return Ending.Minimal; case "index": return Ending.Index; - case "js": return Ending.JsExtension; - default: return usesJsExtensionOnImports(importingSourceFile) ? Ending.JsExtension : Ending.Minimal; + case "js": return shouldAllowImportingTsExtension(compilerOptions) ? Ending.TsExtension : Ending.JsExtension; + default: return usesExtensionsOnImports(importingSourceFile) + ? shouldAllowImportingTsExtension(compilerOptions) ? Ending.TsExtension : Ending.JsExtension + : Ending.Minimal; } } @@ -403,8 +409,8 @@ namespace ts.moduleSpecifiers { return count; } - function usesJsExtensionOnImports({ imports }: SourceFile): boolean { - return firstDefined(imports, ({ text }) => pathIsRelative(text) ? hasJSFileExtension(text) : undefined) || false; + function usesExtensionsOnImports({ imports }: SourceFile): boolean { + return firstDefined(imports, ({ text }) => pathIsRelative(text) ? (hasJSFileExtension(text) || hasTSFileExtension(text)) : undefined) || false; } function comparePathsByRedirectAndNumberOfDirectorySeparators(a: ModulePath, b: ModulePath) { @@ -928,6 +934,8 @@ namespace ts.moduleSpecifiers { return noExtension; case Ending.JsExtension: return noExtension + getJSExtensionForFile(fileName, options); + case Ending.TsExtension: + return fileName; default: return Debug.assertNever(ending); } diff --git a/src/harness/fourslashImpl.ts b/src/harness/fourslashImpl.ts index 46d2bc242e772..6883a6d25c554 100644 --- a/src/harness/fourslashImpl.ts +++ b/src/harness/fourslashImpl.ts @@ -798,16 +798,20 @@ namespace FourSlash { }); } - private renderMarkers(markers: { text: string, fileName: string, position: number }[]) { + private renderMarkers(markers: { text: string, fileName: string, position: number }[], useTerminalBoldSequence = true) { const filesToDisplay = ts.deduplicate(markers.map(m => m.fileName), ts.equateValues); return filesToDisplay.map(fileName => { const markersToRender = markers.filter(m => m.fileName === fileName).sort((a, b) => b.position - a.position); let fileContent = this.tryGetFileContent(fileName) || ""; for (const marker of markersToRender) { - fileContent = fileContent.slice(0, marker.position) + `\x1b[1;4m/*${marker.text}*/\x1b[0;31m` + fileContent.slice(marker.position); + fileContent = fileContent.slice(0, marker.position) + bold(`/*${marker.text}*/`) + fileContent.slice(marker.position); } return `// @Filename: ${fileName}\n${fileContent}`; }).join("\n\n"); + + function bold(text: string) { + return useTerminalBoldSequence ? `\x1b[1;4m${text}\x1b[0;31m` : text; + } } private verifyDefinitionTextSpan(defs: ts.DefinitionInfoAndBoundSpan, startMarkerName: string) { @@ -3127,6 +3131,48 @@ namespace FourSlash { assert.deepEqual(actualModuleSpecifiers, moduleSpecifiers); } + public baselineAutoImports(markerName: string, preferences?: ts.UserPreferences) { + const marker = this.getMarkerByName(markerName); + const baselineFile = this.getBaselineFileNameForContainingTestFile(`.baseline.md`); + const completionPreferences = { + includeCompletionsForModuleExports: true, + includeCompletionsWithInsertText: true, + allowIncompleteCompletions: true, + includeCompletionsWithSnippetText: true, + ...preferences + }; + + const ext = ts.getAnyExtensionFromPath(this.activeFile.fileName).slice(1); + const lang = ["mts", "cts"].includes(ext) ? "ts" : ext; + let baselineText = codeFence(this.renderMarkers([{ text: "|", fileName: marker.fileName, position: marker.position }], /*useTerminalBoldSequence*/ false), lang) + "\n\n"; + this.goToMarker(marker); + + const completions = this.getCompletionListAtCaret(completionPreferences)!; + + const autoImportCompletions = completions.entries.filter(c => c.hasAction && c.source && c.sortText === ts.Completions.SortText.AutoImportSuggestions); + if (autoImportCompletions.length) { + baselineText += `## From completions\n\n${autoImportCompletions.map(c => `- \`${c.name}\` from \`"${c.source}"\``).join("\n")}\n\n`; + autoImportCompletions.forEach(c => { + const details = this.getCompletionEntryDetails(c.name, c.source, c.data, completionPreferences); + assert(details?.codeActions, `Entry '${c.name}' from "${c.source}" returned no code actions from completion details request`); + assert(details.codeActions.length === 1, `Entry '${c.name}' from "${c.source}" returned more than one code action`); + assert(details.codeActions[0].changes.length === 1, `Entry '${c.name}' from "${c.source}" returned a code action changing more than one file`); + assert(details.codeActions[0].changes[0].fileName === this.activeFile.fileName, `Entry '${c.name}' from "${c.source}" returned a code action changing a different file`); + const changes = details.codeActions[0].changes[0].textChanges; + const completionChange: ts.TextChange = { newText: c.insertText || c.name, span: c.replacementSpan || completions.optionalReplacementSpan || { start: marker.position, length: 0 } }; + const sortedChanges = [...changes, completionChange].sort((a, b) => a.span.start - b.span.start); + let newFileContent = this.activeFile.content; + for (let i = sortedChanges.length - 1; i >= 0; i--) { + newFileContent = newFileContent.substring(0, sortedChanges[i].span.start) + sortedChanges[i].newText + newFileContent.substring(sortedChanges[i].span.start + sortedChanges[i].span.length); + } + baselineText += codeFence(newFileContent, lang) + "\n\n"; + }); + } + + // TODO: do codefixes too + Harness.Baseline.runBaseline(baselineFile, baselineText); + } + public verifyDocCommentTemplate(expected: ts.TextInsertion | undefined, options?: ts.DocCommentTemplateOptions) { const name = "verifyDocCommentTemplate"; const actual = this.languageService.getDocCommentTemplateAtPosition(this.activeFile.fileName, this.currentCaretPosition, options || { generateReturnInDocTemplate: true })!; @@ -4598,10 +4644,10 @@ namespace FourSlash { } return ranges; - } + } - // Adds an _ when the source string and the target string have a whitespace difference - function highlightDifferenceBetweenStrings(source: string, target: string) { + // Adds an _ when the source string and the target string have a whitespace difference + function highlightDifferenceBetweenStrings(source: string, target: string) { const ranges = rangesOfDiffBetweenTwoStrings(source, target); let emTarget = target; ranges.forEach((range, index) => { @@ -4613,9 +4659,13 @@ namespace FourSlash { range.start + 1 + additionalOffset, range.start + range.length + 1 + additionalOffset ); - const after = emTarget.slice(range.start + range.length + 1 + additionalOffset, emTarget.length); + const after = emTarget.slice(range.start + range.length + 1 + additionalOffset, emTarget.length); emTarget = before + lhs + between + rhs + after; }); return emTarget; - } + } + + function codeFence(code: string, lang?: string) { + return `\`\`\`${lang || ""}\n${code}\n\`\`\``; + } } diff --git a/src/harness/fourslashInterfaceImpl.ts b/src/harness/fourslashInterfaceImpl.ts index 4112072d38835..5065b5dba5bc1 100644 --- a/src/harness/fourslashInterfaceImpl.ts +++ b/src/harness/fourslashInterfaceImpl.ts @@ -486,6 +486,10 @@ namespace FourSlashInterface { this.state.verifyImportFixModuleSpecifiers(marker, moduleSpecifiers, preferences); } + public baselineAutoImports(marker: string, preferences?: ts.UserPreferences) { + this.state.baselineAutoImports(marker, preferences); + } + public navigationBar(json: any, options?: { checkSpans?: boolean }) { this.state.verifyNavigationBar(json, options); } diff --git a/src/services/utilities.ts b/src/services/utilities.ts index 4d24e57d051ee..b021cd350d563 100644 --- a/src/services/utilities.ts +++ b/src/services/utilities.ts @@ -1909,8 +1909,9 @@ namespace ts { export function programContainsEsModules(program: Program): boolean { return program.getSourceFiles().some(s => !s.isDeclarationFile && !program.isSourceFileFromExternalLibrary(s) && !!s.externalModuleIndicator); } + // TODO: this function is, at best, poorly named. Use sites are pretty suspicious. export function compilerOptionsIndicateEsModules(compilerOptions: CompilerOptions): boolean { - return !!compilerOptions.module || getEmitScriptTarget(compilerOptions) >= ScriptTarget.ES2015 || !!compilerOptions.noEmit; + return !!compilerOptions.module || getEmitScriptTarget(compilerOptions) >= ScriptTarget.ES2015 || !!compilerOptions.noEmit || getEmitModuleResolutionKind(compilerOptions) === ModuleResolutionKind.Minimal; } export function createModuleSpecifierResolutionHost(program: Program, host: LanguageServiceHost): ModuleSpecifierResolutionHost { diff --git a/tests/cases/fourslash/autoImportsMinimal1.ts b/tests/cases/fourslash/autoImportsMinimal1.ts new file mode 100644 index 0000000000000..175f731e3abf8 --- /dev/null +++ b/tests/cases/fourslash/autoImportsMinimal1.ts @@ -0,0 +1,17 @@ +/// + +// @moduleResolution: minimal + +// @Filename: /node_modules/@types/foo/index.d.ts +//// export const fromAtTypesFoo: number; + +// @Filename: /node_modules/bar/index.d.ts +//// export const fromBar: number; + +// @Filename: /local.ts +//// export const fromLocal: number; + +// @Filename: /main.ts +//// /**/ + +verify.baselineAutoImports(""); diff --git a/tests/cases/fourslash/autoImportsMinimal2.ts b/tests/cases/fourslash/autoImportsMinimal2.ts new file mode 100644 index 0000000000000..3ab44e1c00da4 --- /dev/null +++ b/tests/cases/fourslash/autoImportsMinimal2.ts @@ -0,0 +1,19 @@ +/// + +// @moduleResolution: minimal +// @allowImportingTsExtensions: true +// @noEmit: true + +// @Filename: /node_modules/@types/foo/index.d.ts +//// export const fromAtTypesFoo: number; + +// @Filename: /node_modules/bar/index.d.ts +//// export const fromBar: number; + +// @Filename: /local.ts +//// export const fromLocal: number; + +// @Filename: /main.ts +//// /**/ + +verify.baselineAutoImports(""); diff --git a/tests/cases/fourslash/fourslash.ts b/tests/cases/fourslash/fourslash.ts index 76ca5d33314d7..058632b616992 100644 --- a/tests/cases/fourslash/fourslash.ts +++ b/tests/cases/fourslash/fourslash.ts @@ -370,6 +370,7 @@ declare namespace FourSlashInterface { getAndApplyCodeFix(errorCode?: number, index?: number): void; importFixAtPosition(expectedTextArray: string[], errorCode?: number, options?: UserPreferences): void; importFixModuleSpecifiers(marker: string, moduleSpecifiers: string[], options?: UserPreferences): void; + baselineAutoImports(marker: string, options?: UserPreferences): void; navigationBar(json: any, options?: { checkSpans?: boolean }): void; navigationTree(json: any, options?: { checkSpans?: boolean }): void; From 7d64928117dbad08fa63888118d7b5cbcde9cde4 Mon Sep 17 00:00:00 2001 From: Andrew Branch Date: Mon, 26 Sep 2022 10:55:33 -0700 Subject: [PATCH 09/14] Disallow relative imports into node_modules --- src/compiler/checker.ts | 5 +++- src/compiler/diagnosticMessages.json | 4 +++ src/compiler/moduleNameResolver.ts | 13 ++++++++++ .../reference/minimal_nodeModules.errors.txt | 26 +++++++++++++++++++ .../reference/minimal_nodeModules.js | 21 +++++++++++++++ .../reference/minimal_nodeModules.symbols | 16 ++++++++++++ .../reference/minimal_nodeModules.types | 16 ++++++++++++ .../moduleResolution/minimal_nodeModules.ts | 16 ++++++++++++ 8 files changed, 116 insertions(+), 1 deletion(-) create mode 100644 tests/baselines/reference/minimal_nodeModules.errors.txt create mode 100644 tests/baselines/reference/minimal_nodeModules.js create mode 100644 tests/baselines/reference/minimal_nodeModules.symbols create mode 100644 tests/baselines/reference/minimal_nodeModules.types create mode 100644 tests/cases/conformance/moduleResolution/minimal_nodeModules.ts diff --git a/src/compiler/checker.ts b/src/compiler/checker.ts index 36e21f63f35d5..e9d5b3229213f 100644 --- a/src/compiler/checker.ts +++ b/src/compiler/checker.ts @@ -3740,7 +3740,10 @@ namespace ts { const moduleResolutionKind = getEmitModuleResolutionKind(compilerOptions); const resolutionIsNode16OrNext = moduleResolutionKind === ModuleResolutionKind.Node16 || moduleResolutionKind === ModuleResolutionKind.NodeNext; - if (tsExtension) { + if (moduleResolutionKind === ModuleResolutionKind.Minimal && pathContainsNodeModules(moduleReference)) { + error(errorNode, Diagnostics.Relative_imports_into_node_modules_are_not_allowed); + } + else if (tsExtension) { errorOnTSExtensionImport(tsExtension); } else if (!compilerOptions.resolveJsonModule && diff --git a/src/compiler/diagnosticMessages.json b/src/compiler/diagnosticMessages.json index c6614d6482b14..97238efc34650 100644 --- a/src/compiler/diagnosticMessages.json +++ b/src/compiler/diagnosticMessages.json @@ -3571,6 +3571,10 @@ "category": "Error", "code": 2845 }, + "Relative imports into 'node_modules' are not allowed.": { + "category": "Error", + "code": 2846 + }, "Import declaration '{0}' is using private name '{1}'.": { "category": "Error", diff --git a/src/compiler/moduleNameResolver.ts b/src/compiler/moduleNameResolver.ts index 6fc614ab5dc1a..7aa263db0a893 100644 --- a/src/compiler/moduleNameResolver.ts +++ b/src/compiler/moduleNameResolver.ts @@ -2705,6 +2705,19 @@ namespace ts { if (resolvedUsingSettings) { return resolvedUsingSettings; } + if (isExternalModuleNameRelative(moduleName) && pathContainsNodeModules(moduleName)) { + // A relative import into node_modules is a problem for a few reasons: + // 1. Portability - if the code gets published as a library, it will very likely break + // 2. It's unclear how we should resolve types. By typical relative import rules, we + // would ignore package.json fields that tell us where to find types and would have + // no special behavior linking up node_modules/@types with their implementations - + // we would only find .d.ts files as siblings of .js files. Any package that puts + // their types in a separate directory, or is typed by @types, would be broken. + // Some of these redirections would be safe to do, but others might reflect + // Node-specific resolution features that would only work with non-relative imports. + // There's a diagnostic issued for this case in the checker. + return noPackageId(/*resolved*/ undefined); + } const resolvedRelative = loadModuleFromFileNoImplicitExtensions(extensions, candidate, /*onlyRecordFailures*/ false, state); if (resolvedRelative) { return noPackageId(resolvedRelative); diff --git a/tests/baselines/reference/minimal_nodeModules.errors.txt b/tests/baselines/reference/minimal_nodeModules.errors.txt new file mode 100644 index 0000000000000..1f114980ccf67 --- /dev/null +++ b/tests/baselines/reference/minimal_nodeModules.errors.txt @@ -0,0 +1,26 @@ +/main.ts(1,16): error TS2307: Cannot find module 'foo' or its corresponding type declarations. +/main.ts(2,16): error TS2846: Relative imports into 'node_modules' are not allowed. +/main.ts(3,21): error TS2846: Relative imports into 'node_modules' are not allowed. + + +==== /node_modules/foo/index.d.ts (0 errors) ==== + import {} from "./other.js"; + export {}; + +==== /node_modules/foo/other.d.ts (0 errors) ==== + export {}; + +==== /node_modules/@types/foo/index.d.ts (0 errors) ==== + export {}; + +==== /main.ts (3 errors) ==== + import {} from "foo"; + ~~~~~ +!!! error TS2307: Cannot find module 'foo' or its corresponding type declarations. + import {} from "./node_modules/foo/index.js"; + ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +!!! error TS2846: Relative imports into 'node_modules' are not allowed. + import type {} from "./node_modules/@types/foo/index.d.ts"; + ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +!!! error TS2846: Relative imports into 'node_modules' are not allowed. + \ No newline at end of file diff --git a/tests/baselines/reference/minimal_nodeModules.js b/tests/baselines/reference/minimal_nodeModules.js new file mode 100644 index 0000000000000..25b341dfcd7e8 --- /dev/null +++ b/tests/baselines/reference/minimal_nodeModules.js @@ -0,0 +1,21 @@ +//// [tests/cases/conformance/moduleResolution/minimal_nodeModules.ts] //// + +//// [index.d.ts] +import {} from "./other.js"; +export {}; + +//// [other.d.ts] +export {}; + +//// [index.d.ts] +export {}; + +//// [main.ts] +import {} from "foo"; +import {} from "./node_modules/foo/index.js"; +import type {} from "./node_modules/@types/foo/index.d.ts"; + + +//// [main.js] +"use strict"; +exports.__esModule = true; diff --git a/tests/baselines/reference/minimal_nodeModules.symbols b/tests/baselines/reference/minimal_nodeModules.symbols new file mode 100644 index 0000000000000..584f016b4b220 --- /dev/null +++ b/tests/baselines/reference/minimal_nodeModules.symbols @@ -0,0 +1,16 @@ +=== /node_modules/foo/index.d.ts === +import {} from "./other.js"; +No type information for this code.export {}; +No type information for this code. +No type information for this code.=== /node_modules/foo/other.d.ts === +export {}; +No type information for this code. +No type information for this code.=== /node_modules/@types/foo/index.d.ts === +export {}; +No type information for this code. +No type information for this code.=== /main.ts === +import {} from "foo"; +No type information for this code.import {} from "./node_modules/foo/index.js"; +No type information for this code.import type {} from "./node_modules/@types/foo/index.d.ts"; +No type information for this code. +No type information for this code. \ No newline at end of file diff --git a/tests/baselines/reference/minimal_nodeModules.types b/tests/baselines/reference/minimal_nodeModules.types new file mode 100644 index 0000000000000..584f016b4b220 --- /dev/null +++ b/tests/baselines/reference/minimal_nodeModules.types @@ -0,0 +1,16 @@ +=== /node_modules/foo/index.d.ts === +import {} from "./other.js"; +No type information for this code.export {}; +No type information for this code. +No type information for this code.=== /node_modules/foo/other.d.ts === +export {}; +No type information for this code. +No type information for this code.=== /node_modules/@types/foo/index.d.ts === +export {}; +No type information for this code. +No type information for this code.=== /main.ts === +import {} from "foo"; +No type information for this code.import {} from "./node_modules/foo/index.js"; +No type information for this code.import type {} from "./node_modules/@types/foo/index.d.ts"; +No type information for this code. +No type information for this code. \ No newline at end of file diff --git a/tests/cases/conformance/moduleResolution/minimal_nodeModules.ts b/tests/cases/conformance/moduleResolution/minimal_nodeModules.ts new file mode 100644 index 0000000000000..1ddb7f9153345 --- /dev/null +++ b/tests/cases/conformance/moduleResolution/minimal_nodeModules.ts @@ -0,0 +1,16 @@ +// @moduleResolution: minimal + +// @Filename: /node_modules/foo/index.d.ts +import {} from "./other.js"; +export {}; + +// @Filename: /node_modules/foo/other.d.ts +export {}; + +// @Filename: /node_modules/@types/foo/index.d.ts +export {}; + +// @Filename: /main.ts +import {} from "foo"; +import {} from "./node_modules/foo/index.js"; +import type {} from "./node_modules/@types/foo/index.d.ts"; From 0249e0a93e08a4365764a0ff92b2b0dfd0daacc0 Mon Sep 17 00:00:00 2001 From: Andrew Branch Date: Mon, 26 Sep 2022 11:35:55 -0700 Subject: [PATCH 10/14] =?UTF-8?q?Ensure=20auto-imports=20don=E2=80=99t=20s?= =?UTF-8?q?uggest=20./node=5Fmodules;?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/compiler/checker.ts | 23 +++++++++++++++---- src/compiler/moduleNameResolver.ts | 13 ----------- src/services/codefixes/importFixes.ts | 3 ++- src/services/completions.ts | 11 ++++++--- .../reference/autoImportsMinimal1.baseline.md | 15 ++++++++++++ .../reference/autoImportsMinimal2.baseline.md | 15 ++++++++++++ 6 files changed, 59 insertions(+), 21 deletions(-) create mode 100644 tests/baselines/reference/autoImportsMinimal1.baseline.md create mode 100644 tests/baselines/reference/autoImportsMinimal2.baseline.md diff --git a/src/compiler/checker.ts b/src/compiler/checker.ts index e9d5b3229213f..afc8129b4322a 100644 --- a/src/compiler/checker.ts +++ b/src/compiler/checker.ts @@ -3598,6 +3598,7 @@ namespace ts { (isModuleDeclaration(location) ? location : location.parent && isModuleDeclaration(location.parent) && location.parent.name === location ? location.parent : undefined)?.name || (isLiteralImportTypeNode(location) ? location : undefined)?.argument.literal; const mode = contextSpecifier && isStringLiteralLike(contextSpecifier) ? getModeForUsageLocation(currentSourceFile, contextSpecifier) : currentSourceFile.impliedNodeFormat; + const moduleResolutionKind = getEmitModuleResolutionKind(compilerOptions); const resolvedModule = getResolvedModule(currentSourceFile, moduleReference, mode); const resolutionDiagnostic = resolvedModule && getResolutionDiagnostic(compilerOptions, resolvedModule); const sourceFile = resolvedModule @@ -3609,7 +3610,22 @@ namespace ts { error(errorNode, resolutionDiagnostic, moduleReference, resolvedModule.resolvedFileName); } - if (resolvedModule.resolvedUsingTsExtension && isDeclarationFileName(moduleReference)) { + if (moduleResolutionKind === ModuleResolutionKind.Minimal && pathContainsNodeModules(moduleReference)) { + // A relative import into node_modules is a problem for a few reasons: + // 1. Portability - if the code gets published as a library, it will very likely break + // 2. It's unclear how we should resolve types. By typical relative import rules, we + // would ignore package.json fields that tell us where to find types and would have + // no special behavior linking up node_modules/@types with their implementations - + // we would only find .d.ts files as siblings of .js files. Any package that puts + // their types in a separate directory, or is typed by @types, would be broken. + // Some of these redirections would be safe to do, but others might reflect + // Node-specific resolution features that would only work with non-relative imports. + // The module resolver still returns a result, because it's possible for a module in + // node_modules to end up in the program, and module specifier generation assumes that it + // is always possible to generate a module specifier, even if it also generates a diagnostic. + error(errorNode, Diagnostics.Relative_imports_into_node_modules_are_not_allowed); + } + else if (resolvedModule.resolvedUsingTsExtension && isDeclarationFileName(moduleReference)) { const importOrExport = findAncestor(location, isImportDeclaration)?.importClause || findAncestor(location, or(isImportEqualsDeclaration, isExportDeclaration)) as ImportEqualsDeclaration | ExportDeclaration | undefined; @@ -3629,7 +3645,7 @@ namespace ts { if (resolvedModule.isExternalLibraryImport && !resolutionExtensionIsTSOrJson(resolvedModule.extension)) { errorOnImplicitAnyModule(/*isError*/ false, errorNode, resolvedModule, moduleReference); } - if (getEmitModuleResolutionKind(compilerOptions) === ModuleResolutionKind.Node16 || getEmitModuleResolutionKind(compilerOptions) === ModuleResolutionKind.NodeNext) { + if (moduleResolutionKind === ModuleResolutionKind.Node16 || moduleResolutionKind === ModuleResolutionKind.NodeNext) { const isSyncImport = (currentSourceFile.impliedNodeFormat === ModuleKind.CommonJS && !findAncestor(location, isImportCall)) || !!findAncestor(location, isImportEqualsDeclaration); const overrideClauseHost = findAncestor(location, l => isImportTypeNode(l) || isExportDeclaration(l) || isImportDeclaration(l)) as ImportTypeNode | ImportDeclaration | ExportDeclaration | undefined; const overrideClause = overrideClauseHost && isImportTypeNode(overrideClauseHost) ? overrideClauseHost.assertions?.assertClause : overrideClauseHost?.assertClause; @@ -3737,7 +3753,6 @@ namespace ts { else { const tsExtension = tryExtractTSExtension(moduleReference); const isExtensionlessRelativePathImport = pathIsRelative(moduleReference) && !hasExtension(moduleReference); - const moduleResolutionKind = getEmitModuleResolutionKind(compilerOptions); const resolutionIsNode16OrNext = moduleResolutionKind === ModuleResolutionKind.Node16 || moduleResolutionKind === ModuleResolutionKind.NodeNext; if (moduleResolutionKind === ModuleResolutionKind.Minimal && pathContainsNodeModules(moduleReference)) { @@ -3748,7 +3763,7 @@ namespace ts { } else if (!compilerOptions.resolveJsonModule && fileExtensionIs(moduleReference, Extension.Json) && - getEmitModuleResolutionKind(compilerOptions) !== ModuleResolutionKind.Classic && + moduleResolutionKind !== ModuleResolutionKind.Classic && hasJsonModuleEmitEnabled(compilerOptions)) { error(errorNode, Diagnostics.Cannot_find_module_0_Consider_using_resolveJsonModule_to_import_module_with_json_extension, moduleReference); } diff --git a/src/compiler/moduleNameResolver.ts b/src/compiler/moduleNameResolver.ts index 7aa263db0a893..6fc614ab5dc1a 100644 --- a/src/compiler/moduleNameResolver.ts +++ b/src/compiler/moduleNameResolver.ts @@ -2705,19 +2705,6 @@ namespace ts { if (resolvedUsingSettings) { return resolvedUsingSettings; } - if (isExternalModuleNameRelative(moduleName) && pathContainsNodeModules(moduleName)) { - // A relative import into node_modules is a problem for a few reasons: - // 1. Portability - if the code gets published as a library, it will very likely break - // 2. It's unclear how we should resolve types. By typical relative import rules, we - // would ignore package.json fields that tell us where to find types and would have - // no special behavior linking up node_modules/@types with their implementations - - // we would only find .d.ts files as siblings of .js files. Any package that puts - // their types in a separate directory, or is typed by @types, would be broken. - // Some of these redirections would be safe to do, but others might reflect - // Node-specific resolution features that would only work with non-relative imports. - // There's a diagnostic issued for this case in the checker. - return noPackageId(/*resolved*/ undefined); - } const resolvedRelative = loadModuleFromFileNoImplicitExtensions(extensions, candidate, /*onlyRecordFailures*/ false, state); if (resolvedRelative) { return noPackageId(resolvedRelative); diff --git a/src/services/codefixes/importFixes.ts b/src/services/codefixes/importFixes.ts index 496a5d888a194..11e9d13f8bdf0 100644 --- a/src/services/codefixes/importFixes.ts +++ b/src/services/codefixes/importFixes.ts @@ -662,7 +662,8 @@ namespace ts.codefix { const compilerOptions = program.getCompilerOptions(); const moduleSpecifierResolutionHost = createModuleSpecifierResolutionHost(program, host); const getChecker = createGetChecker(program, host); - const rejectNodeModulesRelativePaths = moduleResolutionUsesNodeModules(getEmitModuleResolutionKind(compilerOptions)); + const moduleResolution = getEmitModuleResolutionKind(compilerOptions); + const rejectNodeModulesRelativePaths = moduleResolutionUsesNodeModules(moduleResolution) || moduleResolution === ModuleResolutionKind.Minimal; const getModuleSpecifiers = fromCacheOnly ? (moduleSymbol: Symbol) => ({ moduleSpecifiers: moduleSpecifiers.tryGetModuleSpecifiersFromCache(moduleSymbol, sourceFile, moduleSpecifierResolutionHost, preferences), computedWithoutCache: false }) : (moduleSymbol: Symbol, checker: TypeChecker) => moduleSpecifiers.getModuleSpecifiersWithCacheInfo(moduleSymbol, checker, compilerOptions, sourceFile, moduleSpecifierResolutionHost, preferences); diff --git a/src/services/completions.ts b/src/services/completions.ts index 48e1c28bf01de..439e674f88252 100644 --- a/src/services/completions.ts +++ b/src/services/completions.ts @@ -169,7 +169,7 @@ namespace ts.Completions { const enum GlobalsSearch { Continue, Success, Fail } - interface ModuleSpecifierResolutioContext { + interface ModuleSpecifierResolutionContext { tryResolve: (exportInfo: readonly SymbolExportInfo[], symbolName: string, isFromAmbientModule: boolean) => ModuleSpecifierResolutionResult; resolvedAny: () => boolean; skippedAny: () => boolean; @@ -190,15 +190,20 @@ namespace ts.Completions { preferences: UserPreferences, isForImportStatementCompletion: boolean, isValidTypeOnlyUseSite: boolean, - cb: (context: ModuleSpecifierResolutioContext) => TReturn, + cb: (context: ModuleSpecifierResolutionContext) => TReturn, ): TReturn { const start = timestamp(); + const moduleResolution = getEmitModuleResolutionKind(program.getCompilerOptions()); // Under `--moduleResolution nodenext`, we have to resolve module specifiers up front, because // package.json exports can mean we *can't* resolve a module specifier (that doesn't include a // relative path into node_modules), and we want to filter those completions out entirely. + // Under `--moduleResolution minimal`, we want to reject relative module specifiers into + // node_modules, so need to exhaust any other possibilities for how those can be referenced. // Import statement completions always need specifier resolution because the module specifier is // part of their `insertText`, not the `codeActions` creating edits away from the cursor. - const needsFullResolution = isForImportStatementCompletion || moduleResolutionRespectsExports(getEmitModuleResolutionKind(program.getCompilerOptions())); + const needsFullResolution = isForImportStatementCompletion + || moduleResolutionRespectsExports(moduleResolution) + || moduleResolution === ModuleResolutionKind.Minimal; let skippedAny = false; let ambientCount = 0; let resolvedCount = 0; diff --git a/tests/baselines/reference/autoImportsMinimal1.baseline.md b/tests/baselines/reference/autoImportsMinimal1.baseline.md new file mode 100644 index 0000000000000..cd47cab8187c3 --- /dev/null +++ b/tests/baselines/reference/autoImportsMinimal1.baseline.md @@ -0,0 +1,15 @@ +```ts +// @Filename: /main.ts +/*|*/ +``` + +## From completions + +- `fromLocal` from `"./local.js"` + +```ts +import { fromLocal } from "./local.js"; + +fromLocal +``` + diff --git a/tests/baselines/reference/autoImportsMinimal2.baseline.md b/tests/baselines/reference/autoImportsMinimal2.baseline.md new file mode 100644 index 0000000000000..56cf2c70c336a --- /dev/null +++ b/tests/baselines/reference/autoImportsMinimal2.baseline.md @@ -0,0 +1,15 @@ +```ts +// @Filename: /main.ts +/*|*/ +``` + +## From completions + +- `fromLocal` from `"./local.ts"` + +```ts +import { fromLocal } from "./local.ts"; + +fromLocal +``` + From 6242ee31a7cf36ae2ff29024d0145352220a6c45 Mon Sep 17 00:00:00 2001 From: Andrew Branch Date: Mon, 26 Sep 2022 11:40:13 -0700 Subject: [PATCH 11/14] Test a non-portable declaration emit issue --- ...mal_nodeModules_declarationEmit.errors.txt | 17 +++++++++++++++ .../minimal_nodeModules_declarationEmit.js | 20 ++++++++++++++++++ ...inimal_nodeModules_declarationEmit.symbols | 21 +++++++++++++++++++ .../minimal_nodeModules_declarationEmit.types | 21 +++++++++++++++++++ .../minimal_nodeModules_declarationEmit.ts | 14 +++++++++++++ 5 files changed, 93 insertions(+) create mode 100644 tests/baselines/reference/minimal_nodeModules_declarationEmit.errors.txt create mode 100644 tests/baselines/reference/minimal_nodeModules_declarationEmit.js create mode 100644 tests/baselines/reference/minimal_nodeModules_declarationEmit.symbols create mode 100644 tests/baselines/reference/minimal_nodeModules_declarationEmit.types create mode 100644 tests/cases/conformance/moduleResolution/minimal_nodeModules_declarationEmit.ts diff --git a/tests/baselines/reference/minimal_nodeModules_declarationEmit.errors.txt b/tests/baselines/reference/minimal_nodeModules_declarationEmit.errors.txt new file mode 100644 index 0000000000000..d0ce84ea82c5c --- /dev/null +++ b/tests/baselines/reference/minimal_nodeModules_declarationEmit.errors.txt @@ -0,0 +1,17 @@ +/main.ts(1,14): error TS2742: The inferred type of 'boom' cannot be named without a reference to './node_modules/foo/module.js'. This is likely not portable. A type annotation is necessary. + + +==== /node_modules/foo/module.d.ts (0 errors) ==== + export declare class SomeExportedClass { + private foo: any; + } + + declare global { + function returnsPrivateClassOhNo(): SomeExportedClass; + } + +==== /main.ts (1 errors) ==== + export const boom = returnsPrivateClassOhNo(); + ~~~~ +!!! error TS2742: The inferred type of 'boom' cannot be named without a reference to './node_modules/foo/module.js'. This is likely not portable. A type annotation is necessary. + \ No newline at end of file diff --git a/tests/baselines/reference/minimal_nodeModules_declarationEmit.js b/tests/baselines/reference/minimal_nodeModules_declarationEmit.js new file mode 100644 index 0000000000000..b31f1936f6f13 --- /dev/null +++ b/tests/baselines/reference/minimal_nodeModules_declarationEmit.js @@ -0,0 +1,20 @@ +//// [tests/cases/conformance/moduleResolution/minimal_nodeModules_declarationEmit.ts] //// + +//// [module.d.ts] +export declare class SomeExportedClass { + private foo: any; +} + +declare global { + function returnsPrivateClassOhNo(): SomeExportedClass; +} + +//// [main.ts] +export const boom = returnsPrivateClassOhNo(); + + +//// [main.js] +"use strict"; +exports.__esModule = true; +exports.boom = void 0; +exports.boom = returnsPrivateClassOhNo(); diff --git a/tests/baselines/reference/minimal_nodeModules_declarationEmit.symbols b/tests/baselines/reference/minimal_nodeModules_declarationEmit.symbols new file mode 100644 index 0000000000000..1930da5f26c77 --- /dev/null +++ b/tests/baselines/reference/minimal_nodeModules_declarationEmit.symbols @@ -0,0 +1,21 @@ +=== /node_modules/foo/module.d.ts === +export declare class SomeExportedClass { +>SomeExportedClass : Symbol(SomeExportedClass, Decl(module.d.ts, 0, 0)) + + private foo: any; +>foo : Symbol(SomeExportedClass.foo, Decl(module.d.ts, 0, 40)) +} + +declare global { +>global : Symbol(global, Decl(module.d.ts, 2, 1)) + + function returnsPrivateClassOhNo(): SomeExportedClass; +>returnsPrivateClassOhNo : Symbol(returnsPrivateClassOhNo, Decl(module.d.ts, 4, 16)) +>SomeExportedClass : Symbol(SomeExportedClass, Decl(module.d.ts, 0, 0)) +} + +=== /main.ts === +export const boom = returnsPrivateClassOhNo(); +>boom : Symbol(boom, Decl(main.ts, 0, 12)) +>returnsPrivateClassOhNo : Symbol(returnsPrivateClassOhNo, Decl(module.d.ts, 4, 16)) + diff --git a/tests/baselines/reference/minimal_nodeModules_declarationEmit.types b/tests/baselines/reference/minimal_nodeModules_declarationEmit.types new file mode 100644 index 0000000000000..ab1b8fd4423c6 --- /dev/null +++ b/tests/baselines/reference/minimal_nodeModules_declarationEmit.types @@ -0,0 +1,21 @@ +=== /node_modules/foo/module.d.ts === +export declare class SomeExportedClass { +>SomeExportedClass : SomeExportedClass + + private foo: any; +>foo : any +} + +declare global { +>global : typeof global + + function returnsPrivateClassOhNo(): SomeExportedClass; +>returnsPrivateClassOhNo : () => SomeExportedClass +} + +=== /main.ts === +export const boom = returnsPrivateClassOhNo(); +>boom : import("/node_modules/foo/module").SomeExportedClass +>returnsPrivateClassOhNo() : import("/node_modules/foo/module").SomeExportedClass +>returnsPrivateClassOhNo : () => import("/node_modules/foo/module").SomeExportedClass + diff --git a/tests/cases/conformance/moduleResolution/minimal_nodeModules_declarationEmit.ts b/tests/cases/conformance/moduleResolution/minimal_nodeModules_declarationEmit.ts new file mode 100644 index 0000000000000..b621aeab6431f --- /dev/null +++ b/tests/cases/conformance/moduleResolution/minimal_nodeModules_declarationEmit.ts @@ -0,0 +1,14 @@ +// @moduleResolution: minimal +// @declaration: true + +// @Filename: /node_modules/foo/module.d.ts +export declare class SomeExportedClass { + private foo: any; +} + +declare global { + function returnsPrivateClassOhNo(): SomeExportedClass; +} + +// @Filename: /main.ts +export const boom = returnsPrivateClassOhNo(); From 6cc0e18dca2006e4751f8d1d680fdb42723915aa Mon Sep 17 00:00:00 2001 From: Andrew Branch Date: Mon, 26 Sep 2022 11:44:03 -0700 Subject: [PATCH 12/14] Test auto-importing TSX file --- tests/baselines/reference/autoImportsMinimal1.baseline.md | 7 +++++++ tests/baselines/reference/autoImportsMinimal2.baseline.md | 7 +++++++ tests/cases/fourslash/autoImportsMinimal1.ts | 3 +++ tests/cases/fourslash/autoImportsMinimal2.ts | 3 +++ 4 files changed, 20 insertions(+) diff --git a/tests/baselines/reference/autoImportsMinimal1.baseline.md b/tests/baselines/reference/autoImportsMinimal1.baseline.md index cd47cab8187c3..c0a6fb0eeaaaa 100644 --- a/tests/baselines/reference/autoImportsMinimal1.baseline.md +++ b/tests/baselines/reference/autoImportsMinimal1.baseline.md @@ -5,8 +5,15 @@ ## From completions +- `Component` from `"./Component.js"` - `fromLocal` from `"./local.js"` +```ts +import { Component } from "./Component.js"; + +Component +``` + ```ts import { fromLocal } from "./local.js"; diff --git a/tests/baselines/reference/autoImportsMinimal2.baseline.md b/tests/baselines/reference/autoImportsMinimal2.baseline.md index 56cf2c70c336a..35b129182eab9 100644 --- a/tests/baselines/reference/autoImportsMinimal2.baseline.md +++ b/tests/baselines/reference/autoImportsMinimal2.baseline.md @@ -5,8 +5,15 @@ ## From completions +- `Component` from `"./Component.tsx"` - `fromLocal` from `"./local.ts"` +```ts +import { Component } from "./Component.tsx"; + +Component +``` + ```ts import { fromLocal } from "./local.ts"; diff --git a/tests/cases/fourslash/autoImportsMinimal1.ts b/tests/cases/fourslash/autoImportsMinimal1.ts index 175f731e3abf8..1796a03b00f28 100644 --- a/tests/cases/fourslash/autoImportsMinimal1.ts +++ b/tests/cases/fourslash/autoImportsMinimal1.ts @@ -11,6 +11,9 @@ // @Filename: /local.ts //// export const fromLocal: number; +// @Filename: /Component.tsx +//// export function Component() { return null; } + // @Filename: /main.ts //// /**/ diff --git a/tests/cases/fourslash/autoImportsMinimal2.ts b/tests/cases/fourslash/autoImportsMinimal2.ts index 3ab44e1c00da4..c98a84aa859be 100644 --- a/tests/cases/fourslash/autoImportsMinimal2.ts +++ b/tests/cases/fourslash/autoImportsMinimal2.ts @@ -13,6 +13,9 @@ // @Filename: /local.ts //// export const fromLocal: number; +// @Filename: /Component.tsx +//// export function Component() { return null; } + // @Filename: /main.ts //// /**/ From 240533a2361babab5e1fe5e38c4ac35fde77c5c8 Mon Sep 17 00:00:00 2001 From: Andrew Branch Date: Mon, 26 Sep 2022 12:59:25 -0700 Subject: [PATCH 13/14] Update path completions --- src/services/stringCompletions.ts | 85 ++++++++++--------- .../fourslash/pathCompletionsMinimal1.ts | 31 +++++++ .../fourslash/pathCompletionsMinimal2.ts | 33 +++++++ 3 files changed, 109 insertions(+), 40 deletions(-) create mode 100644 tests/cases/fourslash/pathCompletionsMinimal1.ts create mode 100644 tests/cases/fourslash/pathCompletionsMinimal2.ts diff --git a/src/services/stringCompletions.ts b/src/services/stringCompletions.ts index 922e50654bbe1..df0aeb202b2ae 100644 --- a/src/services/stringCompletions.ts +++ b/src/services/stringCompletions.ts @@ -377,8 +377,16 @@ namespace ts.Completions.StringCompletions { : getCompletionEntriesForNonRelativeModules(literalValue, scriptDirectory, mode, compilerOptions, host, getIncludeExtensionOption(), typeChecker); function getIncludeExtensionOption() { + const moduleResolution = getEmitModuleResolutionKind(compilerOptions); + if (moduleResolution === ModuleResolutionKind.Minimal) { + return shouldAllowImportingTsExtension(compilerOptions) + ? IncludeExtensionsOption.Include + : IncludeExtensionsOption.ModuleSpecifierCompletion; + } const mode = isStringLiteralLike(node) ? getModeForUsageLocation(sourceFile, node) : undefined; - return preferences.importModuleSpecifierEnding === "js" || mode === ModuleKind.ESNext ? IncludeExtensionsOption.ModuleSpecifierCompletion : IncludeExtensionsOption.Exclude; + return preferences.importModuleSpecifierEnding === "js" || mode === ModuleKind.ESNext + ? IncludeExtensionsOption.ModuleSpecifierCompletion + : IncludeExtensionsOption.Exclude; } } @@ -396,24 +404,14 @@ namespace ts.Completions.StringCompletions { compilerOptions.rootDirs, literalValue, scriptDirectory, extensionOptions, compilerOptions, host, scriptPath); } else { - return arrayFrom(getCompletionEntriesForDirectoryFragment(literalValue, scriptDirectory, extensionOptions, host, scriptPath).values()); + return arrayFrom(getCompletionEntriesForDirectoryFragment(literalValue, scriptDirectory, extensionOptions, host, /*moduleSpecifierIsRelative*/ false, scriptPath).values()); } } - function isEmitResolutionKindUsingNodeModules(compilerOptions: CompilerOptions): boolean { - return getEmitModuleResolutionKind(compilerOptions) === ModuleResolutionKind.NodeJs || - getEmitModuleResolutionKind(compilerOptions) === ModuleResolutionKind.Node16 || - getEmitModuleResolutionKind(compilerOptions) === ModuleResolutionKind.NodeNext; - } - - function isEmitModuleResolutionRespectingExportMaps(compilerOptions: CompilerOptions) { - return getEmitModuleResolutionKind(compilerOptions) === ModuleResolutionKind.Node16 || - getEmitModuleResolutionKind(compilerOptions) === ModuleResolutionKind.NodeNext; - } - function getSupportedExtensionsForModuleResolution(compilerOptions: CompilerOptions): readonly Extension[][] { const extensions = getSupportedExtensions(compilerOptions); - return isEmitResolutionKindUsingNodeModules(compilerOptions) ? + const moduleResolution = getEmitModuleResolutionKind(compilerOptions); + return moduleResolutionUsesNodeModules(moduleResolution) ? getSupportedExtensionsWithJsonIfResolveJsonModule(compilerOptions, extensions) : extensions; } @@ -441,7 +439,7 @@ namespace ts.Completions.StringCompletions { const basePath = compilerOptions.project || host.getCurrentDirectory(); const ignoreCase = !(host.useCaseSensitiveFileNames && host.useCaseSensitiveFileNames()); const baseDirectories = getBaseDirectoriesFromRootDirs(rootDirs, basePath, scriptDirectory, ignoreCase); - return flatMap(baseDirectories, baseDirectory => arrayFrom(getCompletionEntriesForDirectoryFragment(fragment, baseDirectory, extensionOptions, host, exclude).values())); + return flatMap(baseDirectories, baseDirectory => arrayFrom(getCompletionEntriesForDirectoryFragment(fragment, baseDirectory, extensionOptions, host, /*moduleSpecifierIsRelative*/ true, exclude).values())); } const enum IncludeExtensionsOption { @@ -454,9 +452,10 @@ namespace ts.Completions.StringCompletions { */ function getCompletionEntriesForDirectoryFragment( fragment: string, - scriptPath: string, + scriptDirectory: string, extensionOptions: ExtensionOptions, host: LanguageServiceHost, + moduleSpecifierIsRelative: boolean, exclude?: string, result = createNameAndKindSet() ): NameAndKindSet { @@ -480,23 +479,25 @@ namespace ts.Completions.StringCompletions { fragment = ensureTrailingDirectorySeparator(fragment); - const absolutePath = resolvePath(scriptPath, fragment); + const absolutePath = resolvePath(scriptDirectory, fragment); const baseDirectory = hasTrailingDirectorySeparator(absolutePath) ? absolutePath : getDirectoryPath(absolutePath); - // check for a version redirect - const packageJsonPath = findPackageJson(baseDirectory, host); - if (packageJsonPath) { - const packageJson = readJson(packageJsonPath, host as { readFile: (filename: string) => string | undefined }); - const typesVersions = (packageJson as any).typesVersions; - if (typeof typesVersions === "object") { - const versionPaths = getPackageJsonTypesVersionsPaths(typesVersions)?.paths; - if (versionPaths) { - const packageDirectory = getDirectoryPath(packageJsonPath); - const pathInPackage = absolutePath.slice(ensureTrailingDirectorySeparator(packageDirectory).length); - if (addCompletionEntriesFromPaths(result, pathInPackage, packageDirectory, extensionOptions, host, versionPaths)) { - // A true result means one of the `versionPaths` was matched, which will block relative resolution - // to files and folders from here. All reachable paths given the pattern match are already added. - return result; + if (!moduleSpecifierIsRelative) { + // check for a version redirect + const packageJsonPath = findPackageJson(baseDirectory, host); + if (packageJsonPath) { + const packageJson = readJson(packageJsonPath, host as { readFile: (filename: string) => string | undefined }); + const typesVersions = (packageJson as any).typesVersions; + if (typeof typesVersions === "object") { + const versionPaths = getPackageJsonTypesVersionsPaths(typesVersions)?.paths; + if (versionPaths) { + const packageDirectory = getDirectoryPath(packageJsonPath); + const pathInPackage = absolutePath.slice(ensureTrailingDirectorySeparator(packageDirectory).length); + if (addCompletionEntriesFromPaths(result, pathInPackage, packageDirectory, extensionOptions, host, versionPaths)) { + // A true result means one of the `versionPaths` was matched, which will block relative resolution + // to files and folders from here. All reachable paths given the pattern match are already added. + return result; + } } } } @@ -511,7 +512,7 @@ namespace ts.Completions.StringCompletions { if (files) { for (let filePath of files) { filePath = normalizePath(filePath); - if (exclude && comparePaths(filePath, exclude, scriptPath, ignoreCase) === Comparison.EqualTo) { + if (exclude && comparePaths(filePath, exclude, scriptDirectory, ignoreCase) === Comparison.EqualTo) { continue; } @@ -524,9 +525,10 @@ namespace ts.Completions.StringCompletions { const directories = tryGetDirectories(host, baseDirectory); if (directories) { + const moduleResolution = getEmitModuleResolutionKind(host.getCompilationSettings()); for (const directory of directories) { const directoryName = getBaseFileName(normalizePath(directory)); - if (directoryName !== "@types") { + if (directoryName !== "@types" && !(directoryName === "node_modules" && moduleResolution === ModuleResolutionKind.Minimal)) { result.add(directoryResult(directoryName)); } } @@ -638,11 +640,12 @@ namespace ts.Completions.StringCompletions { const { baseUrl, paths } = compilerOptions; const result = createNameAndKindSet(); + const moduleResolution = getEmitModuleResolutionKind(compilerOptions); const extensionOptions = getExtensionOptions(compilerOptions, includeExtensionsOption); if (baseUrl) { const projectDir = compilerOptions.project || host.getCurrentDirectory(); const absolute = normalizePath(combinePaths(projectDir, baseUrl)); - getCompletionEntriesForDirectoryFragment(fragment, absolute, extensionOptions, host, /*exclude*/ undefined, result); + getCompletionEntriesForDirectoryFragment(fragment, absolute, extensionOptions, host, /*moduleSpecifierIsRelative*/ false, /*exclude*/ undefined, result); if (paths) { addCompletionEntriesFromPaths(result, fragment, absolute, extensionOptions, host, paths); } @@ -653,9 +656,11 @@ namespace ts.Completions.StringCompletions { result.add(nameAndKind(ambientName, ScriptElementKind.externalModuleName, /*extension*/ undefined)); } - getCompletionEntriesFromTypings(host, compilerOptions, scriptPath, fragmentDirectory, extensionOptions, result); + if (moduleResolution !== ModuleResolutionKind.Minimal) { + getCompletionEntriesFromTypings(host, compilerOptions, scriptPath, fragmentDirectory, extensionOptions, result); + } - if (isEmitResolutionKindUsingNodeModules(compilerOptions)) { + if (moduleResolutionUsesNodeModules(moduleResolution)) { // If looking for a global package name, don't just include everything in `node_modules` because that includes dependencies' own dependencies. // (But do if we didn't find anything, e.g. 'package.json' missing.) let foundGlobal = false; @@ -672,10 +677,10 @@ namespace ts.Completions.StringCompletions { let ancestorLookup: (directory: string) => void | undefined = ancestor => { const nodeModules = combinePaths(ancestor, "node_modules"); if (tryDirectoryExists(host, nodeModules)) { - getCompletionEntriesForDirectoryFragment(fragment, nodeModules, extensionOptions, host, /*exclude*/ undefined, result); + getCompletionEntriesForDirectoryFragment(fragment, nodeModules, extensionOptions, host, /*moduleSpecifierIsRelative*/ false, /*exclude*/ undefined, result); } }; - if (fragmentDirectory && isEmitModuleResolutionRespectingExportMaps(compilerOptions)) { + if (fragmentDirectory && moduleResolutionRespectsExports(moduleResolution)) { const nodeModulesDirectoryLookup = ancestorLookup; ancestorLookup = ancestor => { const components = getPathComponents(fragment); @@ -876,7 +881,7 @@ namespace ts.Completions.StringCompletions { const [, prefix, kind, toComplete] = match; const scriptPath = getDirectoryPath(sourceFile.path); - const names = kind === "path" ? getCompletionEntriesForDirectoryFragment(toComplete, scriptPath, getExtensionOptions(compilerOptions, IncludeExtensionsOption.Include), host, sourceFile.path) + const names = kind === "path" ? getCompletionEntriesForDirectoryFragment(toComplete, scriptPath, getExtensionOptions(compilerOptions, IncludeExtensionsOption.Include), host, /*moduleSpecifierIsRelative*/ true, sourceFile.path) : kind === "types" ? getCompletionEntriesFromTypings(host, compilerOptions, scriptPath, getFragmentDirectory(toComplete), getExtensionOptions(compilerOptions)) : Debug.fail(); return addReplacementSpans(toComplete, range.pos + prefix.length, arrayFrom(names.values())); @@ -917,7 +922,7 @@ namespace ts.Completions.StringCompletions { const baseDirectory = combinePaths(directory, typeDirectoryName); const remainingFragment = tryRemoveDirectoryPrefix(fragmentDirectory, packageName, hostGetCanonicalFileName(host)); if (remainingFragment !== undefined) { - getCompletionEntriesForDirectoryFragment(remainingFragment, baseDirectory, extensionOptions, host, /*exclude*/ undefined, result); + getCompletionEntriesForDirectoryFragment(remainingFragment, baseDirectory, extensionOptions, host, /*moduleSpecifierIsRelative*/ false, /*exclude*/ undefined, result); } } } diff --git a/tests/cases/fourslash/pathCompletionsMinimal1.ts b/tests/cases/fourslash/pathCompletionsMinimal1.ts new file mode 100644 index 0000000000000..a3843b535f648 --- /dev/null +++ b/tests/cases/fourslash/pathCompletionsMinimal1.ts @@ -0,0 +1,31 @@ +/// + +// @moduleResolution: minimal + +// @Filename: /project/node_modules/@types/foo/index.d.ts +//// export const fromAtTypesFoo: number; + +// @Filename: /project/node_modules/bar/index.d.ts +//// export const fromBar: number; + +// @Filename: /project/local.ts +//// export const fromLocal: number; + +// @Filename: /project/Component.tsx +//// export function Component() { return null; } + +// @Filename: /project/main.ts +//// import {} from "/**/"; + +verify.completions({ + isNewIdentifierLocation: true, + marker: "", + exact: [] +}); + +edit.insert("./"); + +verify.completions({ + isNewIdentifierLocation: true, + exact: ["Component.js", "local.js"], +}); diff --git a/tests/cases/fourslash/pathCompletionsMinimal2.ts b/tests/cases/fourslash/pathCompletionsMinimal2.ts new file mode 100644 index 0000000000000..e9a27356b02b3 --- /dev/null +++ b/tests/cases/fourslash/pathCompletionsMinimal2.ts @@ -0,0 +1,33 @@ +/// + +// @moduleResolution: minimal +// @allowImportingTsExtensions: true +// @noEmit: true + +// @Filename: /project/node_modules/@types/foo/index.d.ts +//// export const fromAtTypesFoo: number; + +// @Filename: /project/node_modules/bar/index.d.ts +//// export const fromBar: number; + +// @Filename: /project/local.ts +//// export const fromLocal: number; + +// @Filename: /project/Component.tsx +//// export function Component() { return null; } + +// @Filename: /project/main.ts +//// import {} from "/**/"; + +verify.completions({ + isNewIdentifierLocation: true, + marker: "", + exact: [] +}); + +edit.insert("./"); + +verify.completions({ + isNewIdentifierLocation: true, + exact: ["Component.tsx", "local.ts"], +}); From 619843e0d0bbc116fffe364fe8264dcc3668308b Mon Sep 17 00:00:00 2001 From: Andrew Branch Date: Tue, 27 Sep 2022 10:20:31 -0700 Subject: [PATCH 14/14] Fix lint due to merge --- src/compiler/checker.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/compiler/checker.ts b/src/compiler/checker.ts index e27ddd533a58e..8842735df2942 100644 --- a/src/compiler/checker.ts +++ b/src/compiler/checker.ts @@ -3637,7 +3637,7 @@ namespace ts { else if (resolvedModule.resolvedUsingTsExtension && isDeclarationFileName(moduleReference)) { const importOrExport = findAncestor(location, isImportDeclaration)?.importClause || - findAncestor(location, or(isImportEqualsDeclaration, isExportDeclaration)) as ImportEqualsDeclaration | ExportDeclaration | undefined; + findAncestor(location, or(isImportEqualsDeclaration, isExportDeclaration)); if (importOrExport && !importOrExport.isTypeOnly || findAncestor(location, isImportCall)) { error( errorNode,