From f6dc15837326b1dc882e05b209056d0cdda69c52 Mon Sep 17 00:00:00 2001 From: Wesley Wigham Date: Wed, 16 Feb 2022 15:19:01 -0800 Subject: [PATCH 1/4] Allow export map entries to remap back to input files for a program --- src/compiler/moduleNameResolver.ts | 147 +++++++++++++++++- src/compiler/utilities.ts | 10 ++ .../nodeNextPackageSelfNameWithOutDir.js | 22 +++ .../nodeNextPackageSelfNameWithOutDir.symbols | 12 ++ .../nodeNextPackageSelfNameWithOutDir.types | 13 ++ ...odeNextPackageSelfNameWithOutDirDeclDir.js | 29 ++++ ...xtPackageSelfNameWithOutDirDeclDir.symbols | 12 ++ ...NextPackageSelfNameWithOutDirDeclDir.types | 13 ++ ...ckageSelfNameWithOutDirDeclDirComposite.js | 29 ++++ ...SelfNameWithOutDirDeclDirComposite.symbols | 12 ++ ...geSelfNameWithOutDirDeclDirComposite.types | 13 ++ ...ameWithOutDirDeclDirCompositeNestedDirs.js | 46 ++++++ ...thOutDirDeclDirCompositeNestedDirs.symbols | 25 +++ ...WithOutDirDeclDirCompositeNestedDirs.types | 26 ++++ ...kageSelfNameWithOutDirDeclDirNestedDirs.js | 46 ++++++ ...elfNameWithOutDirDeclDirNestedDirs.symbols | 25 +++ ...eSelfNameWithOutDirDeclDirNestedDirs.types | 26 ++++ ...PackageSelfNameWithOutDirDeclDirRootDir.js | 29 ++++ ...geSelfNameWithOutDirDeclDirRootDir.symbols | 12 ++ ...kageSelfNameWithOutDirDeclDirRootDir.types | 13 ++ .../nodeNextPackageSelfNameWithOutDir.ts | 16 ++ ...odeNextPackageSelfNameWithOutDirDeclDir.ts | 21 +++ ...ckageSelfNameWithOutDirDeclDirComposite.ts | 26 ++++ ...ameWithOutDirDeclDirCompositeNestedDirs.ts | 37 +++++ ...kageSelfNameWithOutDirDeclDirNestedDirs.ts | 37 +++++ ...PackageSelfNameWithOutDirDeclDirRootDir.ts | 22 +++ 26 files changed, 711 insertions(+), 8 deletions(-) create mode 100644 tests/baselines/reference/nodeNextPackageSelfNameWithOutDir.js create mode 100644 tests/baselines/reference/nodeNextPackageSelfNameWithOutDir.symbols create mode 100644 tests/baselines/reference/nodeNextPackageSelfNameWithOutDir.types create mode 100644 tests/baselines/reference/nodeNextPackageSelfNameWithOutDirDeclDir.js create mode 100644 tests/baselines/reference/nodeNextPackageSelfNameWithOutDirDeclDir.symbols create mode 100644 tests/baselines/reference/nodeNextPackageSelfNameWithOutDirDeclDir.types create mode 100644 tests/baselines/reference/nodeNextPackageSelfNameWithOutDirDeclDirComposite.js create mode 100644 tests/baselines/reference/nodeNextPackageSelfNameWithOutDirDeclDirComposite.symbols create mode 100644 tests/baselines/reference/nodeNextPackageSelfNameWithOutDirDeclDirComposite.types create mode 100644 tests/baselines/reference/nodeNextPackageSelfNameWithOutDirDeclDirCompositeNestedDirs.js create mode 100644 tests/baselines/reference/nodeNextPackageSelfNameWithOutDirDeclDirCompositeNestedDirs.symbols create mode 100644 tests/baselines/reference/nodeNextPackageSelfNameWithOutDirDeclDirCompositeNestedDirs.types create mode 100644 tests/baselines/reference/nodeNextPackageSelfNameWithOutDirDeclDirNestedDirs.js create mode 100644 tests/baselines/reference/nodeNextPackageSelfNameWithOutDirDeclDirNestedDirs.symbols create mode 100644 tests/baselines/reference/nodeNextPackageSelfNameWithOutDirDeclDirNestedDirs.types create mode 100644 tests/baselines/reference/nodeNextPackageSelfNameWithOutDirDeclDirRootDir.js create mode 100644 tests/baselines/reference/nodeNextPackageSelfNameWithOutDirDeclDirRootDir.symbols create mode 100644 tests/baselines/reference/nodeNextPackageSelfNameWithOutDirDeclDirRootDir.types create mode 100644 tests/cases/compiler/nodeNextPackageSelfNameWithOutDir.ts create mode 100644 tests/cases/compiler/nodeNextPackageSelfNameWithOutDirDeclDir.ts create mode 100644 tests/cases/compiler/nodeNextPackageSelfNameWithOutDirDeclDirComposite.ts create mode 100644 tests/cases/compiler/nodeNextPackageSelfNameWithOutDirDeclDirCompositeNestedDirs.ts create mode 100644 tests/cases/compiler/nodeNextPackageSelfNameWithOutDirDeclDirNestedDirs.ts create mode 100644 tests/cases/compiler/nodeNextPackageSelfNameWithOutDirDeclDirRootDir.ts diff --git a/src/compiler/moduleNameResolver.ts b/src/compiler/moduleNameResolver.ts index c63cc7917826d..a9f283f940aab 100644 --- a/src/compiler/moduleNameResolver.ts +++ b/src/compiler/moduleNameResolver.ts @@ -106,6 +106,7 @@ namespace ts { packageJsonInfoCache: PackageJsonInfoCache | undefined; features: NodeResolutionFeatures; conditions: string[]; + requestContainingDirectory: string | undefined; } /** Just the fields that we use for module resolution. */ @@ -352,7 +353,7 @@ namespace ts { features |= NodeResolutionFeatures.EsmMode; } const conditions = features & NodeResolutionFeatures.Exports ? features & NodeResolutionFeatures.EsmMode ? ["node", "import", "types"] : ["node", "require", "types"] : []; - const moduleResolutionState: ModuleResolutionState = { compilerOptions: options, host, traceEnabled, failedLookupLocations, packageJsonInfoCache: cache, features, conditions }; + const moduleResolutionState: ModuleResolutionState = { compilerOptions: options, host, traceEnabled, failedLookupLocations, packageJsonInfoCache: cache, features, conditions, requestContainingDirectory: containingDirectory }; let resolved = primaryLookup(); let primary = true; if (!resolved) { @@ -466,6 +467,7 @@ namespace ts { packageJsonInfoCache: cache?.getPackageJsonInfoCache(), conditions: emptyArray, features: NodeResolutionFeatures.None, + requestContainingDirectory: containingDirectory }; return forEachAncestorDirectory(containingDirectory, ancestorDirectory => { @@ -1305,7 +1307,8 @@ namespace ts { failedLookupLocations, packageJsonInfoCache: cache, features, - conditions: features & NodeResolutionFeatures.EsmMode ? ["node", "import", "types"] : ["node", "require", "types"] + conditions: features & NodeResolutionFeatures.EsmMode ? ["node", "import", "types"] : ["node", "require", "types"], + requestContainingDirectory: containingDirectory }; const result = forEach(extensions, ext => tryResolve(ext)); @@ -1497,9 +1500,9 @@ namespace ts { } function loadJSOrExactTSFileName(extensions: Extensions, candidate: string, onlyRecordFailures: boolean, state: ModuleResolutionState): PathAndExtension | undefined { - if ((extensions === Extensions.TypeScript || extensions === Extensions.DtsOnly) && fileExtensionIsOneOf(candidate, [Extension.Dts, Extension.Dcts, Extension.Dmts])) { + if ((extensions === Extensions.TypeScript || extensions === Extensions.DtsOnly) && fileExtensionIsOneOf(candidate, supportedTSExtensionsFlat)) { const result = tryFile(candidate, onlyRecordFailures, state); - return result !== undefined ? { path: candidate, ext: forEach([Extension.Dts, Extension.Dcts, Extension.Dmts], e => fileExtensionIs(candidate, e) ? e : undefined)! } : undefined; + return result !== undefined ? { path: candidate, ext: forEach([Extension.Dts, Extension.Dcts, Extension.Dmts, Extension.Mts, Extension.Cts, Extension.Tsx, Extension.Ts], e => fileExtensionIs(candidate, e) ? e : undefined)! } : undefined; } return loadModuleFromFileNoImplicitExtensions(extensions, candidate, onlyRecordFailures, state); @@ -1624,6 +1627,7 @@ namespace ts { packageJsonInfoCache: cache?.getPackageJsonInfoCache(), conditions: ["node", "require", "types"], features, + requestContainingDirectory: packageJsonInfo.packageDirectory }; const requireResolution = loadNodeModuleFromDirectoryWorker( extensions, @@ -1733,6 +1737,7 @@ namespace ts { packageJsonInfoCache: PackageJsonInfoCache | undefined; features: number; conditions: never[]; + requestContainingDirectory: string | undefined; } = { host, compilerOptions: options, @@ -1741,6 +1746,7 @@ namespace ts { packageJsonInfoCache, features: 0, conditions: [], + requestContainingDirectory: undefined }; const parts = getPathComponents(fileName); parts.pop(); @@ -2078,8 +2084,9 @@ namespace ts { } return toSearchResult(/*value*/ undefined); } - const finalPath = getNormalizedAbsolutePath(pattern ? resolvedTarget.replace(/\*/g, subpath) : resolvedTarget + subpath, state.host.getCurrentDirectory?.()); - + const finalPath = toAbsolutePath(pattern ? resolvedTarget.replace(/\*/g, subpath) : resolvedTarget + subpath); + const inputLink = tryLoadInputFileForPath(finalPath); + if (inputLink) return inputLink; return toSearchResult(withPackageId(scope, loadJSOrExactTSFileName(extensions, finalPath, /*onlyRecordFailures*/ false, state))); } else if (typeof target === "object" && target !== null) { // eslint-disable-line no-null/no-null @@ -2120,6 +2127,130 @@ namespace ts { trace(state.host, Diagnostics.package_json_scope_0_has_invalid_type_for_target_of_specifier_1, scope.packageDirectory, moduleName); } return toSearchResult(/*value*/ undefined); + + function toAbsolutePath(path: string): string; + function toAbsolutePath(path: string | undefined): string | undefined; + function toAbsolutePath(path: string | undefined): string | undefined { + if (path === undefined) return path; + return getNormalizedAbsolutePath(path, state.host.getCurrentDirectory?.()); + } + + function combineDirectoryPath(root: string, dir: string) { + return ensureTrailingDirectorySeparator(combinePaths(root, dir)); + } + + function useCaseSensitiveFileNames() { + return !state.host.useCaseSensitiveFileNames ? true : + typeof state.host.useCaseSensitiveFileNames === "boolean" ? state.host.useCaseSensitiveFileNames : + state.host.useCaseSensitiveFileNames(); + } + + function tryLoadInputFileForPath(finalPath: string) { + // Replace any references to outputs for files in the program with the input files to support package self-names used with outDir + // PROBLEM: We don't know how to calculate the output paths yet, because the "common source directory" we use as the base of the file structure + // we reproduce into the output directory is based on the set of input files, which we're still in the process of traversing and resolving! + // _Given that_, we have to guess what the base of the output directory is (obviously the user wrote the export map, so has some idea what it is!). + // We are going to probe _so many_ possible paths. We limit where we'll do this to try to reduce the possibilities of false positive lookups. + if ((extensions === Extensions.TypeScript || extensions === Extensions.JavaScript || extensions === Extensions.Json) + && (state.compilerOptions.declarationDir || state.compilerOptions.outDir) + && finalPath.indexOf("/node_modules/") === -1 + && (state.compilerOptions.configFile ? startsWith(toAbsolutePath(state.compilerOptions.configFile.fileName), scope.packageDirectory) : true) + ) { + // So that all means we'll only try these guesses for files outside `node_modules` in a directory where the `package.json` and `tsconfig.json` are siblings. + // Even with all that, we still don't know if the root of the output file structure will be (relative to the package file) + // `.`, `./src` or any other deeper directory structure. (If project references are used, it's definitely `.` by fiat, so that should be pretty common.) + + const commonSourceDirGuesses: [base: string, outputDirs: string[]][] = []; + // A `rootDir` compiler option strongly indicates the root location + if (state.compilerOptions.rootDir) { + const baseLocation = toAbsolutePath(state.compilerOptions.configFilePath && getDirectoryPath(state.compilerOptions.configFilePath) || state.host.getCurrentDirectory?.() || scope.packageDirectory); + const packageRoot = toAbsolutePath(combinePaths(baseLocation, state.compilerOptions.rootDir)); + commonSourceDirGuesses.push([packageRoot, getOutputDirectoriesForBaseDirectory(baseLocation)]); + } + // A `composite` project is using project references and has it's common src dir set to `.`, so it shouldn't need to check any other locations + else if (state.compilerOptions.composite && state.compilerOptions.configFilePath) { + const baseLocation = toAbsolutePath(getDirectoryPath(state.compilerOptions.configFilePath)); + commonSourceDirGuesses.push([baseLocation, getOutputDirectoriesForBaseDirectory(baseLocation)]); + } + else if (state.requestContainingDirectory) { + // However without either of those set we're in the dark. Let's say you have + // + // ./tools/index.ts + // ./src/index.ts + // ./dist/index.js + // ./package.json <-- references ./dist/index.js + // ./tsconfig.json <-- loads ./src/index.ts + // + // How do we know `./src` is the common src dir, and not `./tools`, given only the `./dist` out dir and `./dist/index.js` filename? + // Answer: We... don't. We know we're looking for an `index.ts` input file, but we have _no clue_ which subfolder it's supposed to be loaded from + // without more context. + // But we do have more context! Just a tiny bit more! We're resolving an import _for some other input file_! And that input file, too + // must be inside the common source directory! So we propagate that tidbit of info all the way to here via state.requestContainingDirectory + let baseDir = state.compilerOptions.configFilePath ? toAbsolutePath(getDirectoryPath(state.compilerOptions.configFilePath)) : toAbsolutePath(state.host.getCurrentDirectory?.() || scope.packageDirectory); + if (startsWith(state.requestContainingDirectory, baseDir)) { + // And we can try every folder between that request folder and the config/package base directory + // This technically can be wrong - we may load ./src/index.ts when ./src/sub/index.ts was right because we don't + // know if only `./src/sub` files were loaded by the program; but this has the best chance to be right of just about anything + // else we have. And, given that we're about to load `./src/index.ts` because we choose it as likely correct, there will then + // be a file outside of `./src/sub` in the program (the file we resolved to), making us de-facto right. So this fallback lookup + // logic may influence what files are pulled in by self-names, which in turn influences the output path shape, but it's all + // internally consistent so the paths should be stable so long as we prefer the "most general" (meaning: top-most-level directory) possible results first. + const outDirs = getOutputDirectoriesForBaseDirectory(baseDir); + commonSourceDirGuesses.push([baseDir, outDirs]); + + let fragment = ensureTrailingDirectorySeparator(state.requestContainingDirectory.slice(baseDir.length)); + while (fragment && fragment.length > 1) { + const parts = getPathComponents(fragment); + parts.shift(); // shift out root + const dir = parts.shift()!; + baseDir = combinePaths(baseDir, dir); + commonSourceDirGuesses.push([baseDir, getOutputDirectoriesForBaseDirectory(baseDir)]); + fragment = ensureTrailingDirectorySeparator(getPathFromPathComponents(parts)); + } + } + } + for (const [commonSourceDirGuess, candidateDirectories] of commonSourceDirGuesses) { + for (const candidateDir of candidateDirectories) { + if (startsWith(finalPath, candidateDir)) { + // The matched export is looking up something in either the out declaration or js dir, now map the written path back into the source dir and source extension + const pathFragment = finalPath.slice(candidateDir.length + 1); // +1 to also remove directory seperator + const possibleInputBase = combinePaths(commonSourceDirGuess, pathFragment); + const jsAndDtsExtensions = [Extension.Mjs, Extension.Cjs, Extension.Js, Extension.Json, Extension.Dmts, Extension.Dcts, Extension.Dts]; + for (const ext of jsAndDtsExtensions) { + if (fileExtensionIs(possibleInputBase, ext)) { + const inputExts = getPossibleOriginalInputExtensionForExtension(possibleInputBase); + for (const possibleExt of inputExts) { + const possibleInputWithInputExtension = changeAnyExtension(possibleInputBase, possibleExt, ext, !useCaseSensitiveFileNames()); + if ((extensions === Extensions.TypeScript && hasJSFileExtension(possibleInputWithInputExtension)) || + (extensions === Extensions.JavaScript && hasTSFileExtension(possibleInputWithInputExtension))) { + continue; + } + if (state.host.fileExists(possibleInputWithInputExtension)) { + return toSearchResult(withPackageId(scope, loadJSOrExactTSFileName(extensions, possibleInputWithInputExtension, /*onlyRecordFailures*/ false, state))); + } + } + } + } + } + } + } + } + return undefined; + + function getOutputDirectoriesForBaseDirectory(commonSourceDirGuess: string) { + // Config file ouput paths are processed to be relative to the host's current directory, while + // otherwise the paths are resolved relative to the common source dir the compiler puts together + const currentDir = state.compilerOptions.configFile ? state.host.getCurrentDirectory?.() || "" : commonSourceDirGuess; + const candidateDirectories = []; + if (state.compilerOptions.declarationDir) { + candidateDirectories.push(toAbsolutePath(combineDirectoryPath(currentDir, state.compilerOptions.declarationDir))); + } + if (state.compilerOptions.outDir && state.compilerOptions.outDir !== state.compilerOptions.declarationDir) { + candidateDirectories.push(toAbsolutePath(combineDirectoryPath(currentDir, state.compilerOptions.outDir))); + } + return candidateDirectories; + } + } } } @@ -2340,8 +2471,8 @@ namespace ts { export function classicNameResolver(moduleName: string, containingFile: string, compilerOptions: CompilerOptions, host: ModuleResolutionHost, cache?: NonRelativeModuleNameResolutionCache, redirectedReference?: ResolvedProjectReference): ResolvedModuleWithFailedLookupLocations { const traceEnabled = isTraceEnabled(compilerOptions, host); const failedLookupLocations: string[] = []; - const state: ModuleResolutionState = { compilerOptions, host, traceEnabled, failedLookupLocations, packageJsonInfoCache: cache, features: NodeResolutionFeatures.None, conditions: [] }; const containingDirectory = getDirectoryPath(containingFile); + const state: ModuleResolutionState = { compilerOptions, host, traceEnabled, failedLookupLocations, packageJsonInfoCache: cache, features: NodeResolutionFeatures.None, conditions: [], requestContainingDirectory: containingDirectory }; const resolved = tryResolve(Extensions.TypeScript) || tryResolve(Extensions.JavaScript); // No originalPath because classic resolution doesn't resolve realPath @@ -2390,7 +2521,7 @@ namespace ts { trace(host, Diagnostics.Auto_discovery_for_typings_is_enabled_in_project_0_Running_extra_resolution_pass_for_module_1_using_cache_location_2, projectName, moduleName, globalCache); } const failedLookupLocations: string[] = []; - const state: ModuleResolutionState = { compilerOptions, host, traceEnabled, failedLookupLocations, packageJsonInfoCache, features: NodeResolutionFeatures.None, conditions: [] }; + const state: ModuleResolutionState = { compilerOptions, host, traceEnabled, failedLookupLocations, packageJsonInfoCache, features: NodeResolutionFeatures.None, conditions: [], requestContainingDirectory: undefined }; const resolved = loadModuleFromImmediateNodeModulesDirectory(Extensions.DtsOnly, moduleName, globalCache, state, /*typesScopeOnly*/ false, /*cache*/ undefined, /*redirectedReference*/ undefined); return createResolvedModuleWithFailedLookupLocations(resolved, /*isExternalLibraryImport*/ true, failedLookupLocations, state.resultFromCache); } diff --git a/src/compiler/utilities.ts b/src/compiler/utilities.ts index 4aff8e0d0b121..5365b5312619a 100644 --- a/src/compiler/utilities.ts +++ b/src/compiler/utilities.ts @@ -4355,6 +4355,16 @@ namespace ts { Extension.Dts; } + /** + * This function is an inverse of `getDeclarationEmitExtensionForPath`. + */ + export function getPossibleOriginalInputExtensionForExtension(path: string) { + return fileExtensionIsOneOf(path, [Extension.Dmts, Extension.Mjs, Extension.Mts]) ? [Extension.Mts, Extension.Mjs] : + fileExtensionIsOneOf(path, [Extension.Dcts, Extension.Cjs, Extension.Cts]) ? [Extension.Cts, Extension.Cjs]: + fileExtensionIsOneOf(path, [`.json.d.ts`]) ? [Extension.Json] : + [Extension.Tsx, Extension.Ts, Extension.Jsx, Extension.Js]; + } + export function outFile(options: CompilerOptions) { return options.outFile || options.out; } diff --git a/tests/baselines/reference/nodeNextPackageSelfNameWithOutDir.js b/tests/baselines/reference/nodeNextPackageSelfNameWithOutDir.js new file mode 100644 index 0000000000000..d4451ed91fcb1 --- /dev/null +++ b/tests/baselines/reference/nodeNextPackageSelfNameWithOutDir.js @@ -0,0 +1,22 @@ +//// [tests/cases/compiler/nodeNextPackageSelfNameWithOutDir.ts] //// + +//// [package.json] +{ + "name": "@this/package", + "type": "module", + "exports": { + ".": "./dist/index.js" + } +} +//// [index.ts] +import * as me from "@this/package"; + +me.thing(); + +export function thing(): void {} + + +//// [index.js] +import * as me from "@this/package"; +me.thing(); +export function thing() { } diff --git a/tests/baselines/reference/nodeNextPackageSelfNameWithOutDir.symbols b/tests/baselines/reference/nodeNextPackageSelfNameWithOutDir.symbols new file mode 100644 index 0000000000000..8bcf39cdd7a89 --- /dev/null +++ b/tests/baselines/reference/nodeNextPackageSelfNameWithOutDir.symbols @@ -0,0 +1,12 @@ +=== tests/cases/compiler/index.ts === +import * as me from "@this/package"; +>me : Symbol(me, Decl(index.ts, 0, 6)) + +me.thing(); +>me.thing : Symbol(thing, Decl(index.ts, 2, 11)) +>me : Symbol(me, Decl(index.ts, 0, 6)) +>thing : Symbol(thing, Decl(index.ts, 2, 11)) + +export function thing(): void {} +>thing : Symbol(thing, Decl(index.ts, 2, 11)) + diff --git a/tests/baselines/reference/nodeNextPackageSelfNameWithOutDir.types b/tests/baselines/reference/nodeNextPackageSelfNameWithOutDir.types new file mode 100644 index 0000000000000..a22456ef499fb --- /dev/null +++ b/tests/baselines/reference/nodeNextPackageSelfNameWithOutDir.types @@ -0,0 +1,13 @@ +=== tests/cases/compiler/index.ts === +import * as me from "@this/package"; +>me : typeof me + +me.thing(); +>me.thing() : void +>me.thing : () => void +>me : typeof me +>thing : () => void + +export function thing(): void {} +>thing : () => void + diff --git a/tests/baselines/reference/nodeNextPackageSelfNameWithOutDirDeclDir.js b/tests/baselines/reference/nodeNextPackageSelfNameWithOutDirDeclDir.js new file mode 100644 index 0000000000000..d035a43f7c02e --- /dev/null +++ b/tests/baselines/reference/nodeNextPackageSelfNameWithOutDirDeclDir.js @@ -0,0 +1,29 @@ +//// [tests/cases/compiler/nodeNextPackageSelfNameWithOutDirDeclDir.ts] //// + +//// [package.json] +{ + "name": "@this/package", + "type": "module", + "exports": { + ".": { + "default": "./dist/index.js", + "types": "./types/index.d.ts" + } + } +} +//// [index.ts] +import * as me from "@this/package"; + +me.thing(); + +export function thing(): void {} + + +//// [index.js] +import * as me from "@this/package"; +me.thing(); +export function thing() { } + + +//// [index.d.ts] +export declare function thing(): void; diff --git a/tests/baselines/reference/nodeNextPackageSelfNameWithOutDirDeclDir.symbols b/tests/baselines/reference/nodeNextPackageSelfNameWithOutDirDeclDir.symbols new file mode 100644 index 0000000000000..8bcf39cdd7a89 --- /dev/null +++ b/tests/baselines/reference/nodeNextPackageSelfNameWithOutDirDeclDir.symbols @@ -0,0 +1,12 @@ +=== tests/cases/compiler/index.ts === +import * as me from "@this/package"; +>me : Symbol(me, Decl(index.ts, 0, 6)) + +me.thing(); +>me.thing : Symbol(thing, Decl(index.ts, 2, 11)) +>me : Symbol(me, Decl(index.ts, 0, 6)) +>thing : Symbol(thing, Decl(index.ts, 2, 11)) + +export function thing(): void {} +>thing : Symbol(thing, Decl(index.ts, 2, 11)) + diff --git a/tests/baselines/reference/nodeNextPackageSelfNameWithOutDirDeclDir.types b/tests/baselines/reference/nodeNextPackageSelfNameWithOutDirDeclDir.types new file mode 100644 index 0000000000000..a22456ef499fb --- /dev/null +++ b/tests/baselines/reference/nodeNextPackageSelfNameWithOutDirDeclDir.types @@ -0,0 +1,13 @@ +=== tests/cases/compiler/index.ts === +import * as me from "@this/package"; +>me : typeof me + +me.thing(); +>me.thing() : void +>me.thing : () => void +>me : typeof me +>thing : () => void + +export function thing(): void {} +>thing : () => void + diff --git a/tests/baselines/reference/nodeNextPackageSelfNameWithOutDirDeclDirComposite.js b/tests/baselines/reference/nodeNextPackageSelfNameWithOutDirDeclDirComposite.js new file mode 100644 index 0000000000000..0406bf886126c --- /dev/null +++ b/tests/baselines/reference/nodeNextPackageSelfNameWithOutDirDeclDirComposite.js @@ -0,0 +1,29 @@ +//// [tests/cases/compiler/nodeNextPackageSelfNameWithOutDirDeclDirComposite.ts] //// + +//// [package.json] +{ + "name": "@this/package", + "type": "module", + "exports": { + ".": { + "default": "./dist/index.js", + "types": "./types/index.d.ts" + } + } +} +//// [index.ts] +import * as me from "@this/package"; + +me.thing(); + +export function thing(): void {} + + +//// [index.js] +import * as me from "@this/package"; +me.thing(); +export function thing() { } + + +//// [index.d.ts] +export declare function thing(): void; diff --git a/tests/baselines/reference/nodeNextPackageSelfNameWithOutDirDeclDirComposite.symbols b/tests/baselines/reference/nodeNextPackageSelfNameWithOutDirDeclDirComposite.symbols new file mode 100644 index 0000000000000..8bcf39cdd7a89 --- /dev/null +++ b/tests/baselines/reference/nodeNextPackageSelfNameWithOutDirDeclDirComposite.symbols @@ -0,0 +1,12 @@ +=== tests/cases/compiler/index.ts === +import * as me from "@this/package"; +>me : Symbol(me, Decl(index.ts, 0, 6)) + +me.thing(); +>me.thing : Symbol(thing, Decl(index.ts, 2, 11)) +>me : Symbol(me, Decl(index.ts, 0, 6)) +>thing : Symbol(thing, Decl(index.ts, 2, 11)) + +export function thing(): void {} +>thing : Symbol(thing, Decl(index.ts, 2, 11)) + diff --git a/tests/baselines/reference/nodeNextPackageSelfNameWithOutDirDeclDirComposite.types b/tests/baselines/reference/nodeNextPackageSelfNameWithOutDirDeclDirComposite.types new file mode 100644 index 0000000000000..a22456ef499fb --- /dev/null +++ b/tests/baselines/reference/nodeNextPackageSelfNameWithOutDirDeclDirComposite.types @@ -0,0 +1,13 @@ +=== tests/cases/compiler/index.ts === +import * as me from "@this/package"; +>me : typeof me + +me.thing(); +>me.thing() : void +>me.thing : () => void +>me : typeof me +>thing : () => void + +export function thing(): void {} +>thing : () => void + diff --git a/tests/baselines/reference/nodeNextPackageSelfNameWithOutDirDeclDirCompositeNestedDirs.js b/tests/baselines/reference/nodeNextPackageSelfNameWithOutDirDeclDirCompositeNestedDirs.js new file mode 100644 index 0000000000000..21197f9881e40 --- /dev/null +++ b/tests/baselines/reference/nodeNextPackageSelfNameWithOutDirDeclDirCompositeNestedDirs.js @@ -0,0 +1,46 @@ +//// [tests/cases/compiler/nodeNextPackageSelfNameWithOutDirDeclDirCompositeNestedDirs.ts] //// + +//// [package.json] +{ + "name": "@this/package", + "type": "module", + "exports": { + ".": { + "default": "./dist/index.js", + "types": "./types/index.d.ts" + } + } +} +//// [index.ts] +export {srcthing as thing} from "./src/thing.js"; +//// [thing.ts] +// The following import should cause `index.ts` +// to be included in the build, which will, +// in turn, cause the common src directory to not be `src` +// (the harness is wierd here in that noImplicitReferences makes only +// this file get loaded as an entrypoint and emitted, while on the +// real command-line we'll crawl the imports for that set - a limitation +// of the harness, I suppose) +import * as me from "@this/package"; + +me.thing(); + +export function srcthing(): void {} + + + +//// [thing.js] +// The following import should cause `index.ts` +// to be included in the build, which will, +// in turn, cause the common src directory to not be `src` +// (the harness is wierd here in that noImplicitReferences makes only +// this file get loaded as an entrypoint and emitted, while on the +// real command-line we'll crawl the imports for that set - a limitation +// of the harness, I suppose) +import * as me from "@this/package"; +me.thing(); +export function srcthing() { } + + +//// [thing.d.ts] +export declare function srcthing(): void; diff --git a/tests/baselines/reference/nodeNextPackageSelfNameWithOutDirDeclDirCompositeNestedDirs.symbols b/tests/baselines/reference/nodeNextPackageSelfNameWithOutDirDeclDirCompositeNestedDirs.symbols new file mode 100644 index 0000000000000..38fc4efe3360d --- /dev/null +++ b/tests/baselines/reference/nodeNextPackageSelfNameWithOutDirDeclDirCompositeNestedDirs.symbols @@ -0,0 +1,25 @@ +=== tests/cases/compiler/src/thing.ts === +// The following import should cause `index.ts` +// to be included in the build, which will, +// in turn, cause the common src directory to not be `src` +// (the harness is wierd here in that noImplicitReferences makes only +// this file get loaded as an entrypoint and emitted, while on the +// real command-line we'll crawl the imports for that set - a limitation +// of the harness, I suppose) +import * as me from "@this/package"; +>me : Symbol(me, Decl(thing.ts, 7, 6)) + +me.thing(); +>me.thing : Symbol(me.thing, Decl(index.ts, 0, 8)) +>me : Symbol(me, Decl(thing.ts, 7, 6)) +>thing : Symbol(me.thing, Decl(index.ts, 0, 8)) + +export function srcthing(): void {} +>srcthing : Symbol(srcthing, Decl(thing.ts, 9, 11)) + + +=== tests/cases/compiler/index.ts === +export {srcthing as thing} from "./src/thing.js"; +>srcthing : Symbol(srcthing, Decl(thing.ts, 9, 11)) +>thing : Symbol(thing, Decl(index.ts, 0, 8)) + diff --git a/tests/baselines/reference/nodeNextPackageSelfNameWithOutDirDeclDirCompositeNestedDirs.types b/tests/baselines/reference/nodeNextPackageSelfNameWithOutDirDeclDirCompositeNestedDirs.types new file mode 100644 index 0000000000000..2d4d2bcd99441 --- /dev/null +++ b/tests/baselines/reference/nodeNextPackageSelfNameWithOutDirDeclDirCompositeNestedDirs.types @@ -0,0 +1,26 @@ +=== tests/cases/compiler/src/thing.ts === +// The following import should cause `index.ts` +// to be included in the build, which will, +// in turn, cause the common src directory to not be `src` +// (the harness is wierd here in that noImplicitReferences makes only +// this file get loaded as an entrypoint and emitted, while on the +// real command-line we'll crawl the imports for that set - a limitation +// of the harness, I suppose) +import * as me from "@this/package"; +>me : typeof me + +me.thing(); +>me.thing() : void +>me.thing : () => void +>me : typeof me +>thing : () => void + +export function srcthing(): void {} +>srcthing : () => void + + +=== tests/cases/compiler/index.ts === +export {srcthing as thing} from "./src/thing.js"; +>srcthing : () => void +>thing : () => void + diff --git a/tests/baselines/reference/nodeNextPackageSelfNameWithOutDirDeclDirNestedDirs.js b/tests/baselines/reference/nodeNextPackageSelfNameWithOutDirDeclDirNestedDirs.js new file mode 100644 index 0000000000000..433a7dfc98947 --- /dev/null +++ b/tests/baselines/reference/nodeNextPackageSelfNameWithOutDirDeclDirNestedDirs.js @@ -0,0 +1,46 @@ +//// [tests/cases/compiler/nodeNextPackageSelfNameWithOutDirDeclDirNestedDirs.ts] //// + +//// [package.json] +{ + "name": "@this/package", + "type": "module", + "exports": { + ".": { + "default": "./dist/index.js", + "types": "./types/index.d.ts" + } + } +} +//// [index.ts] +export {srcthing as thing} from "./src/thing.js"; +//// [thing.ts] +// The following import should cause `index.ts` +// to be included in the build, which will, +// in turn, cause the common src directory to not be `src` +// (the harness is wierd here in that noImplicitReferences makes only +// this file get loaded as an entrypoint and emitted, while on the +// real command-line we'll crawl the imports for that set - a limitation +// of the harness, I suppose) +import * as me from "@this/package"; + +me.thing(); + +export function srcthing(): void {} + + + +//// [thing.js] +// The following import should cause `index.ts` +// to be included in the build, which will, +// in turn, cause the common src directory to not be `src` +// (the harness is wierd here in that noImplicitReferences makes only +// this file get loaded as an entrypoint and emitted, while on the +// real command-line we'll crawl the imports for that set - a limitation +// of the harness, I suppose) +import * as me from "@this/package"; +me.thing(); +export function srcthing() { } + + +//// [thing.d.ts] +export declare function srcthing(): void; diff --git a/tests/baselines/reference/nodeNextPackageSelfNameWithOutDirDeclDirNestedDirs.symbols b/tests/baselines/reference/nodeNextPackageSelfNameWithOutDirDeclDirNestedDirs.symbols new file mode 100644 index 0000000000000..38fc4efe3360d --- /dev/null +++ b/tests/baselines/reference/nodeNextPackageSelfNameWithOutDirDeclDirNestedDirs.symbols @@ -0,0 +1,25 @@ +=== tests/cases/compiler/src/thing.ts === +// The following import should cause `index.ts` +// to be included in the build, which will, +// in turn, cause the common src directory to not be `src` +// (the harness is wierd here in that noImplicitReferences makes only +// this file get loaded as an entrypoint and emitted, while on the +// real command-line we'll crawl the imports for that set - a limitation +// of the harness, I suppose) +import * as me from "@this/package"; +>me : Symbol(me, Decl(thing.ts, 7, 6)) + +me.thing(); +>me.thing : Symbol(me.thing, Decl(index.ts, 0, 8)) +>me : Symbol(me, Decl(thing.ts, 7, 6)) +>thing : Symbol(me.thing, Decl(index.ts, 0, 8)) + +export function srcthing(): void {} +>srcthing : Symbol(srcthing, Decl(thing.ts, 9, 11)) + + +=== tests/cases/compiler/index.ts === +export {srcthing as thing} from "./src/thing.js"; +>srcthing : Symbol(srcthing, Decl(thing.ts, 9, 11)) +>thing : Symbol(thing, Decl(index.ts, 0, 8)) + diff --git a/tests/baselines/reference/nodeNextPackageSelfNameWithOutDirDeclDirNestedDirs.types b/tests/baselines/reference/nodeNextPackageSelfNameWithOutDirDeclDirNestedDirs.types new file mode 100644 index 0000000000000..2d4d2bcd99441 --- /dev/null +++ b/tests/baselines/reference/nodeNextPackageSelfNameWithOutDirDeclDirNestedDirs.types @@ -0,0 +1,26 @@ +=== tests/cases/compiler/src/thing.ts === +// The following import should cause `index.ts` +// to be included in the build, which will, +// in turn, cause the common src directory to not be `src` +// (the harness is wierd here in that noImplicitReferences makes only +// this file get loaded as an entrypoint and emitted, while on the +// real command-line we'll crawl the imports for that set - a limitation +// of the harness, I suppose) +import * as me from "@this/package"; +>me : typeof me + +me.thing(); +>me.thing() : void +>me.thing : () => void +>me : typeof me +>thing : () => void + +export function srcthing(): void {} +>srcthing : () => void + + +=== tests/cases/compiler/index.ts === +export {srcthing as thing} from "./src/thing.js"; +>srcthing : () => void +>thing : () => void + diff --git a/tests/baselines/reference/nodeNextPackageSelfNameWithOutDirDeclDirRootDir.js b/tests/baselines/reference/nodeNextPackageSelfNameWithOutDirDeclDirRootDir.js new file mode 100644 index 0000000000000..683dad9fb12d6 --- /dev/null +++ b/tests/baselines/reference/nodeNextPackageSelfNameWithOutDirDeclDirRootDir.js @@ -0,0 +1,29 @@ +//// [tests/cases/compiler/nodeNextPackageSelfNameWithOutDirDeclDirRootDir.ts] //// + +//// [package.json] +{ + "name": "@this/package", + "type": "module", + "exports": { + ".": { + "default": "./dist/index.js", + "types": "./types/index.d.ts" + } + } +} +//// [index.ts] +import * as me from "@this/package"; + +me.thing(); + +export function thing(): void {} + + +//// [index.js] +import * as me from "@this/package"; +me.thing(); +export function thing() { } + + +//// [index.d.ts] +export declare function thing(): void; diff --git a/tests/baselines/reference/nodeNextPackageSelfNameWithOutDirDeclDirRootDir.symbols b/tests/baselines/reference/nodeNextPackageSelfNameWithOutDirDeclDirRootDir.symbols new file mode 100644 index 0000000000000..beb1169cc7366 --- /dev/null +++ b/tests/baselines/reference/nodeNextPackageSelfNameWithOutDirDeclDirRootDir.symbols @@ -0,0 +1,12 @@ +=== /pkg/src/index.ts === +import * as me from "@this/package"; +>me : Symbol(me, Decl(index.ts, 0, 6)) + +me.thing(); +>me.thing : Symbol(thing, Decl(index.ts, 2, 11)) +>me : Symbol(me, Decl(index.ts, 0, 6)) +>thing : Symbol(thing, Decl(index.ts, 2, 11)) + +export function thing(): void {} +>thing : Symbol(thing, Decl(index.ts, 2, 11)) + diff --git a/tests/baselines/reference/nodeNextPackageSelfNameWithOutDirDeclDirRootDir.types b/tests/baselines/reference/nodeNextPackageSelfNameWithOutDirDeclDirRootDir.types new file mode 100644 index 0000000000000..17098101fce47 --- /dev/null +++ b/tests/baselines/reference/nodeNextPackageSelfNameWithOutDirDeclDirRootDir.types @@ -0,0 +1,13 @@ +=== /pkg/src/index.ts === +import * as me from "@this/package"; +>me : typeof me + +me.thing(); +>me.thing() : void +>me.thing : () => void +>me : typeof me +>thing : () => void + +export function thing(): void {} +>thing : () => void + diff --git a/tests/cases/compiler/nodeNextPackageSelfNameWithOutDir.ts b/tests/cases/compiler/nodeNextPackageSelfNameWithOutDir.ts new file mode 100644 index 0000000000000..71c1494aafbec --- /dev/null +++ b/tests/cases/compiler/nodeNextPackageSelfNameWithOutDir.ts @@ -0,0 +1,16 @@ +// @module: nodenext +// @outDir: ./dist +// @filename: package.json +{ + "name": "@this/package", + "type": "module", + "exports": { + ".": "./dist/index.js" + } +} +// @filename: index.ts +import * as me from "@this/package"; + +me.thing(); + +export function thing(): void {} diff --git a/tests/cases/compiler/nodeNextPackageSelfNameWithOutDirDeclDir.ts b/tests/cases/compiler/nodeNextPackageSelfNameWithOutDirDeclDir.ts new file mode 100644 index 0000000000000..f495002c9e415 --- /dev/null +++ b/tests/cases/compiler/nodeNextPackageSelfNameWithOutDirDeclDir.ts @@ -0,0 +1,21 @@ +// @module: nodenext +// @outDir: ./dist +// @declarationDir: ./types +// @declaration: true +// @filename: package.json +{ + "name": "@this/package", + "type": "module", + "exports": { + ".": { + "default": "./dist/index.js", + "types": "./types/index.d.ts" + } + } +} +// @filename: index.ts +import * as me from "@this/package"; + +me.thing(); + +export function thing(): void {} diff --git a/tests/cases/compiler/nodeNextPackageSelfNameWithOutDirDeclDirComposite.ts b/tests/cases/compiler/nodeNextPackageSelfNameWithOutDirDeclDirComposite.ts new file mode 100644 index 0000000000000..c8efa7f76775a --- /dev/null +++ b/tests/cases/compiler/nodeNextPackageSelfNameWithOutDirDeclDirComposite.ts @@ -0,0 +1,26 @@ +// @filename: tsconfig.json +{ + "compilerOptions": { + "module": "nodenext", + "outDir": "./dist", + "declarationDir": "./types", + "composite": true + } +} +// @filename: package.json +{ + "name": "@this/package", + "type": "module", + "exports": { + ".": { + "default": "./dist/index.js", + "types": "./types/index.d.ts" + } + } +} +// @filename: index.ts +import * as me from "@this/package"; + +me.thing(); + +export function thing(): void {} diff --git a/tests/cases/compiler/nodeNextPackageSelfNameWithOutDirDeclDirCompositeNestedDirs.ts b/tests/cases/compiler/nodeNextPackageSelfNameWithOutDirDeclDirCompositeNestedDirs.ts new file mode 100644 index 0000000000000..df09199ced68b --- /dev/null +++ b/tests/cases/compiler/nodeNextPackageSelfNameWithOutDirDeclDirCompositeNestedDirs.ts @@ -0,0 +1,37 @@ +// @noImplicitReferences: true +// @filename: tsconfig.json +{ + "compilerOptions": { + "module": "nodenext", + "outDir": "./dist", + "declarationDir": "./types", + "composite": true + } +} +// @filename: package.json +{ + "name": "@this/package", + "type": "module", + "exports": { + ".": { + "default": "./dist/index.js", + "types": "./types/index.d.ts" + } + } +} +// @filename: index.ts +export {srcthing as thing} from "./src/thing.js"; +// @filename: src/thing.ts +// The following import should cause `index.ts` +// to be included in the build, which will, +// in turn, cause the common src directory to not be `src` +// (the harness is wierd here in that noImplicitReferences makes only +// this file get loaded as an entrypoint and emitted, while on the +// real command-line we'll crawl the imports for that set - a limitation +// of the harness, I suppose) +import * as me from "@this/package"; + +me.thing(); + +export function srcthing(): void {} + diff --git a/tests/cases/compiler/nodeNextPackageSelfNameWithOutDirDeclDirNestedDirs.ts b/tests/cases/compiler/nodeNextPackageSelfNameWithOutDirDeclDirNestedDirs.ts new file mode 100644 index 0000000000000..f8e28e05f7cb7 --- /dev/null +++ b/tests/cases/compiler/nodeNextPackageSelfNameWithOutDirDeclDirNestedDirs.ts @@ -0,0 +1,37 @@ +// @noImplicitReferences: true +// @filename: tsconfig.json +{ + "compilerOptions": { + "module": "nodenext", + "outDir": "./dist", + "declarationDir": "./types", + "declaration": true + } +} +// @filename: package.json +{ + "name": "@this/package", + "type": "module", + "exports": { + ".": { + "default": "./dist/index.js", + "types": "./types/index.d.ts" + } + } +} +// @filename: index.ts +export {srcthing as thing} from "./src/thing.js"; +// @filename: src/thing.ts +// The following import should cause `index.ts` +// to be included in the build, which will, +// in turn, cause the common src directory to not be `src` +// (the harness is wierd here in that noImplicitReferences makes only +// this file get loaded as an entrypoint and emitted, while on the +// real command-line we'll crawl the imports for that set - a limitation +// of the harness, I suppose) +import * as me from "@this/package"; + +me.thing(); + +export function srcthing(): void {} + diff --git a/tests/cases/compiler/nodeNextPackageSelfNameWithOutDirDeclDirRootDir.ts b/tests/cases/compiler/nodeNextPackageSelfNameWithOutDirDeclDirRootDir.ts new file mode 100644 index 0000000000000..5857765749fa8 --- /dev/null +++ b/tests/cases/compiler/nodeNextPackageSelfNameWithOutDirDeclDirRootDir.ts @@ -0,0 +1,22 @@ +// @module: nodenext +// @outDir: /pkg/dist +// @declarationDir: /pkg/types +// @declaration: true +// @rootDir: /pkg/src +// @filename: /pkg/package.json +{ + "name": "@this/package", + "type": "module", + "exports": { + ".": { + "default": "./dist/index.js", + "types": "./types/index.d.ts" + } + } +} +// @filename: /pkg/src/index.ts +import * as me from "@this/package"; + +me.thing(); + +export function thing(): void {} From 6e44703ff6def381f780c6c60c7fc7dcda490c56 Mon Sep 17 00:00:00 2001 From: Wesley Wigham Date: Wed, 2 Mar 2022 13:05:03 -0800 Subject: [PATCH 2/4] Fix file casing issues on windows --- src/compiler/moduleNameResolver.ts | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/src/compiler/moduleNameResolver.ts b/src/compiler/moduleNameResolver.ts index a9f283f940aab..2178b44068821 100644 --- a/src/compiler/moduleNameResolver.ts +++ b/src/compiler/moduleNameResolver.ts @@ -2132,7 +2132,7 @@ namespace ts { function toAbsolutePath(path: string | undefined): string | undefined; function toAbsolutePath(path: string | undefined): string | undefined { if (path === undefined) return path; - return getNormalizedAbsolutePath(path, state.host.getCurrentDirectory?.()); + return hostGetCanonicalFileName({ useCaseSensitiveFileNames })(getNormalizedAbsolutePath(path, state.host.getCurrentDirectory?.())); } function combineDirectoryPath(root: string, dir: string) { @@ -2187,7 +2187,8 @@ namespace ts { // But we do have more context! Just a tiny bit more! We're resolving an import _for some other input file_! And that input file, too // must be inside the common source directory! So we propagate that tidbit of info all the way to here via state.requestContainingDirectory let baseDir = state.compilerOptions.configFilePath ? toAbsolutePath(getDirectoryPath(state.compilerOptions.configFilePath)) : toAbsolutePath(state.host.getCurrentDirectory?.() || scope.packageDirectory); - if (startsWith(state.requestContainingDirectory, baseDir)) { + const containingDir = toAbsolutePath(state.requestContainingDirectory); + if (startsWith(containingDir, baseDir)) { // And we can try every folder between that request folder and the config/package base directory // This technically can be wrong - we may load ./src/index.ts when ./src/sub/index.ts was right because we don't // know if only `./src/sub` files were loaded by the program; but this has the best chance to be right of just about anything @@ -2198,7 +2199,7 @@ namespace ts { const outDirs = getOutputDirectoriesForBaseDirectory(baseDir); commonSourceDirGuesses.push([baseDir, outDirs]); - let fragment = ensureTrailingDirectorySeparator(state.requestContainingDirectory.slice(baseDir.length)); + let fragment = ensureTrailingDirectorySeparator(containingDir.slice(baseDir.length)); while (fragment && fragment.length > 1) { const parts = getPathComponents(fragment); parts.shift(); // shift out root From 9c8df0db9684de2c305fee1c0d5cd43da32ebbb5 Mon Sep 17 00:00:00 2001 From: Wesley Wigham Date: Mon, 18 Apr 2022 12:31:33 -0700 Subject: [PATCH 3/4] Implement abiguity error, doesnt quite work --- src/compiler/diagnosticMessages.json | 8 +++ src/compiler/moduleNameResolver.ts | 59 +++++++++++++++----- src/compiler/program.ts | 32 +++++++++++ src/compiler/types.ts | 4 ++ src/testRunner/unittests/moduleResolution.ts | 6 ++ 5 files changed, 94 insertions(+), 15 deletions(-) diff --git a/src/compiler/diagnosticMessages.json b/src/compiler/diagnosticMessages.json index e8a765e514cb5..6c27f1e310db2 100644 --- a/src/compiler/diagnosticMessages.json +++ b/src/compiler/diagnosticMessages.json @@ -1510,6 +1510,14 @@ "category": "Error", "code": 2208 }, + "The project root is ambiguous, but is required to resolve export map entry '{0}' in file '{1}'. Supply the `rootDir` compiler option to disambiguate.": { + "category": "Error", + "code": 2209 + }, + "The project root is ambiguous, but is required to resolve import map entry '{0}' in file '{1}'. Supply the `rootDir` compiler option to disambiguate.": { + "category": "Error", + "code": 2210 + }, "Duplicate identifier '{0}'.": { "category": "Error", diff --git a/src/compiler/moduleNameResolver.ts b/src/compiler/moduleNameResolver.ts index b6a484bacbad2..a003e1399bde4 100644 --- a/src/compiler/moduleNameResolver.ts +++ b/src/compiler/moduleNameResolver.ts @@ -86,14 +86,15 @@ namespace ts { return { fileName: resolved.path, packageId: resolved.packageId }; } - function createResolvedModuleWithFailedLookupLocations(resolved: Resolved | undefined, isExternalLibraryImport: boolean | undefined, failedLookupLocations: string[], resultFromCache: ResolvedModuleWithFailedLookupLocations | undefined): ResolvedModuleWithFailedLookupLocations { + function createResolvedModuleWithFailedLookupLocations(resolved: Resolved | undefined, isExternalLibraryImport: boolean | undefined, failedLookupLocations: string[], diagnostics: Diagnostic[], resultFromCache: ResolvedModuleWithFailedLookupLocations | undefined): ResolvedModuleWithFailedLookupLocations { if (resultFromCache) { resultFromCache.failedLookupLocations.push(...failedLookupLocations); return resultFromCache; } return { resolvedModule: resolved && { resolvedFileName: resolved.path, originalPath: resolved.originalPath === true ? undefined : resolved.originalPath, extension: resolved.extension, isExternalLibraryImport, packageId: resolved.packageId }, - failedLookupLocations + failedLookupLocations, + resolutionDiagnostics: diagnostics }; } @@ -356,7 +357,18 @@ namespace ts { features |= NodeResolutionFeatures.EsmMode; } const conditions = features & NodeResolutionFeatures.Exports ? features & NodeResolutionFeatures.EsmMode ? ["node", "import", "types"] : ["node", "require", "types"] : []; - const moduleResolutionState: ModuleResolutionState = { compilerOptions: options, host, traceEnabled, failedLookupLocations, packageJsonInfoCache: cache, features, conditions, requestContainingDirectory: containingDirectory }; + const diagnostics: Diagnostic[] = []; + const moduleResolutionState: ModuleResolutionState = { + compilerOptions: options, + host, + traceEnabled, + failedLookupLocations, + packageJsonInfoCache: cache, + features, + conditions, + requestContainingDirectory: containingDirectory, + reportDiagnostic: diag => void diagnostics.push(diag), + }; let resolved = primaryLookup(); let primary = true; if (!resolved) { @@ -376,7 +388,7 @@ namespace ts { isExternalLibraryImport: pathContainsNodeModules(fileName), }; } - result = { resolvedTypeReferenceDirective, failedLookupLocations }; + result = { resolvedTypeReferenceDirective, failedLookupLocations, resolutionDiagnostics: diagnostics }; perFolderCache?.set(typeReferenceDirectiveName, /*mode*/ resolutionMode, result); if (traceEnabled) traceResult(result); return result; @@ -470,7 +482,8 @@ namespace ts { packageJsonInfoCache: cache?.getPackageJsonInfoCache(), conditions: emptyArray, features: NodeResolutionFeatures.None, - requestContainingDirectory: containingDirectory + requestContainingDirectory: containingDirectory, + reportDiagnostic: noop }; return forEachAncestorDirectory(containingDirectory, ancestorDirectory => { @@ -1320,6 +1333,7 @@ namespace ts { conditions.pop(); } + const diagnostics: Diagnostic[] = []; const state: ModuleResolutionState = { compilerOptions, host, @@ -1328,11 +1342,12 @@ namespace ts { packageJsonInfoCache: cache, features, conditions, - requestContainingDirectory: containingDirectory + requestContainingDirectory: containingDirectory, + reportDiagnostic: diag => void diagnostics.push(diag), }; const result = forEach(extensions, ext => tryResolve(ext)); - return createResolvedModuleWithFailedLookupLocations(result?.value?.resolved, result?.value?.isExternalLibraryImport, failedLookupLocations, state.resultFromCache); + return createResolvedModuleWithFailedLookupLocations(result?.value?.resolved, result?.value?.isExternalLibraryImport, failedLookupLocations, diagnostics, state.resultFromCache); function tryResolve(extensions: Extensions): SearchResult<{ resolved: Resolved, isExternalLibraryImport: boolean }> { const loader: ResolutionKindSpecificLoader = (extensions, candidate, onlyRecordFailures, state) => nodeLoadModuleByRelativeName(extensions, candidate, onlyRecordFailures, state, /*considerPackageJson*/ true); @@ -1659,7 +1674,8 @@ namespace ts { packageJsonInfoCache: cache?.getPackageJsonInfoCache(), conditions: ["node", "require", "types"], features, - requestContainingDirectory: packageJsonInfo.packageDirectory + requestContainingDirectory: packageJsonInfo.packageDirectory, + reportDiagnostic: noop }; const requireResolution = loadNodeModuleFromDirectoryWorker( extensions, @@ -1770,6 +1786,7 @@ namespace ts { features: number; conditions: never[]; requestContainingDirectory: string | undefined; + reportDiagnostic: DiagnosticReporter } = { host, compilerOptions: options, @@ -1778,7 +1795,8 @@ namespace ts { packageJsonInfoCache, features: 0, conditions: [], - requestContainingDirectory: undefined + requestContainingDirectory: undefined, + reportDiagnostic: noop }; const parts = getPathComponents(fileName); parts.pop(); @@ -2120,7 +2138,7 @@ namespace ts { return toSearchResult(/*value*/ undefined); } const finalPath = toAbsolutePath(pattern ? resolvedTarget.replace(/\*/g, subpath) : resolvedTarget + subpath); - const inputLink = tryLoadInputFileForPath(finalPath); + const inputLink = tryLoadInputFileForPath(finalPath, subpath, combinePaths(scope.packageDirectory, "package.json"), isImports); if (inputLink) return inputLink; return toSearchResult(withPackageId(scope, loadJSOrExactTSFileName(extensions, finalPath, /*onlyRecordFailures*/ false, state))); } @@ -2180,7 +2198,7 @@ namespace ts { state.host.useCaseSensitiveFileNames(); } - function tryLoadInputFileForPath(finalPath: string) { + function tryLoadInputFileForPath(finalPath: string, entry: string, packagePath: string, isImports: boolean) { // Replace any references to outputs for files in the program with the input files to support package self-names used with outDir // PROBLEM: We don't know how to calculate the output paths yet, because the "common source directory" we use as the base of the file structure // we reproduce into the output directory is based on the set of input files, which we're still in the process of traversing and resolving! @@ -2245,6 +2263,15 @@ namespace ts { } } } + if (commonSourceDirGuesses.length > 1) { + state.reportDiagnostic(createCompilerDiagnostic( + isImports + ? Diagnostics.The_project_root_is_ambiguous_but_is_required_to_resolve_import_map_entry_0_in_file_1_Supply_the_rootDir_compiler_option_to_disambiguate + : Diagnostics.The_project_root_is_ambiguous_but_is_required_to_resolve_export_map_entry_0_in_file_1_Supply_the_rootDir_compiler_option_to_disambiguate, + entry, + packagePath + )); + } for (const [commonSourceDirGuess, candidateDirectories] of commonSourceDirGuesses) { for (const candidateDir of candidateDirectories) { if (startsWith(finalPath, candidateDir)) { @@ -2508,11 +2535,12 @@ namespace ts { const traceEnabled = isTraceEnabled(compilerOptions, host); const failedLookupLocations: string[] = []; const containingDirectory = getDirectoryPath(containingFile); - const state: ModuleResolutionState = { compilerOptions, host, traceEnabled, failedLookupLocations, packageJsonInfoCache: cache, features: NodeResolutionFeatures.None, conditions: [], requestContainingDirectory: containingDirectory }; + const diagnostics: Diagnostic[] = []; + const state: ModuleResolutionState = { compilerOptions, host, traceEnabled, failedLookupLocations, packageJsonInfoCache: cache, features: NodeResolutionFeatures.None, conditions: [], requestContainingDirectory: containingDirectory, reportDiagnostic: diag => void diagnostics.push(diag) }; const resolved = tryResolve(Extensions.TypeScript) || tryResolve(Extensions.JavaScript); // No originalPath because classic resolution doesn't resolve realPath - return createResolvedModuleWithFailedLookupLocations(resolved && resolved.value, /*isExternalLibraryImport*/ false, failedLookupLocations, state.resultFromCache); + return createResolvedModuleWithFailedLookupLocations(resolved && resolved.value, /*isExternalLibraryImport*/ false, failedLookupLocations, diagnostics, state.resultFromCache); function tryResolve(extensions: Extensions): SearchResult { const resolvedUsingSettings = tryLoadModuleUsingOptionalResolutionSettings(extensions, moduleName, containingDirectory, loadModuleFromFileNoPackageId, state); @@ -2557,9 +2585,10 @@ namespace ts { trace(host, Diagnostics.Auto_discovery_for_typings_is_enabled_in_project_0_Running_extra_resolution_pass_for_module_1_using_cache_location_2, projectName, moduleName, globalCache); } const failedLookupLocations: string[] = []; - const state: ModuleResolutionState = { compilerOptions, host, traceEnabled, failedLookupLocations, packageJsonInfoCache, features: NodeResolutionFeatures.None, conditions: [], requestContainingDirectory: undefined }; + const diagnostics: Diagnostic[] = []; + const state: ModuleResolutionState = { compilerOptions, host, traceEnabled, failedLookupLocations, packageJsonInfoCache, features: NodeResolutionFeatures.None, conditions: [], requestContainingDirectory: undefined, reportDiagnostic: diag => void diagnostics.push(diag) }; const resolved = loadModuleFromImmediateNodeModulesDirectory(Extensions.DtsOnly, moduleName, globalCache, state, /*typesScopeOnly*/ false, /*cache*/ undefined, /*redirectedReference*/ undefined); - return createResolvedModuleWithFailedLookupLocations(resolved, /*isExternalLibraryImport*/ true, failedLookupLocations, state.resultFromCache); + return createResolvedModuleWithFailedLookupLocations(resolved, /*isExternalLibraryImport*/ true, failedLookupLocations, diagnostics, state.resultFromCache); } /** diff --git a/src/compiler/program.ts b/src/compiler/program.ts index 615d52fb68e44..cc9315db049db 100644 --- a/src/compiler/program.ts +++ b/src/compiler/program.ts @@ -1364,6 +1364,37 @@ namespace ts { return program; + function addResolutionDiagnostics(list: Diagnostic[] | undefined) { + if (!list) return; + for (const elem of list) { + programDiagnostics.add(elem); + } + } + + function pullDiagnosticsFromCache(names: string[] | readonly FileReference[], containingFile: SourceFile) { + const cache = host.getModuleResolutionCache?.(); + if (!cache) return; // Cache not exposed by host, no way to retrieve resolution diagnostics + const containingFileName = getNormalizedAbsolutePath(containingFile.originalFileName, currentDirectory); + const containingFileMode = !isString(containingFile) ? containingFile.impliedNodeFormat : undefined; + const containingDir = getDirectoryPath(containingFileName); + const redirectedReference = getRedirectReferenceForResolution(containingFile); + let i = 0; + for (const n of names) { + // mimics logic done in the resolution cache, should be resilient to upgrading it to use `FileReference`s for non-type-reference modal lookups to make it rely on the index in the list less + const mode = typeof n === "string" ? getModeForResolutionAtIndex(containingFile, i) : getModeForFileReference(n, containingFileMode); + const name = typeof n === "string" ? n : n.fileName; + i++; + // only nonrelative names hit the cache, and, at least as of right now, only nonrelative names can issue diagnostics + // (Since diagnostics are only issued via import or export map lookup) + // This may totally change if/when the issue of output paths not mapping to input files is fixed in a broader context + // When it is, how we extract diagnostics from the module name resolver will have the be refined - the current cache + // APIs wrapping the underlying resolver make it almost impossible to smuggle the diagnostics out in a generalized way + if (isExternalModuleNameRelative(name)) continue; + const diags = cache.getOrCreateCacheForModuleName(name, mode, redirectedReference).get(containingDir)?.resolutionDiagnostics; + addResolutionDiagnostics(diags); + } + } + function resolveModuleNamesWorker(moduleNames: string[], containingFile: SourceFile, reusedNames: string[] | undefined): readonly ResolvedModuleFull[] { if (!moduleNames.length) return emptyArray; const containingFileName = getNormalizedAbsolutePath(containingFile.originalFileName, currentDirectory); @@ -1374,6 +1405,7 @@ namespace ts { performance.mark("afterResolveModule"); performance.measure("ResolveModule", "beforeResolveModule", "afterResolveModule"); tracing?.pop(); + pullDiagnosticsFromCache(moduleNames, containingFile); return result; } diff --git a/src/compiler/types.ts b/src/compiler/types.ts index 3a88c1b5c3774..bd2845896135d 100644 --- a/src/compiler/types.ts +++ b/src/compiler/types.ts @@ -6710,6 +6710,8 @@ namespace ts { readonly resolvedModule: ResolvedModuleFull | undefined; /* @internal */ readonly failedLookupLocations: string[]; + /* @internal */ + readonly resolutionDiagnostics: Diagnostic[] } export interface ResolvedTypeReferenceDirective { @@ -6731,6 +6733,8 @@ namespace ts { export interface ResolvedTypeReferenceDirectiveWithFailedLookupLocations { readonly resolvedTypeReferenceDirective: ResolvedTypeReferenceDirective | undefined; readonly failedLookupLocations: string[]; + /* @internal */ + resolutionDiagnostics: Diagnostic[] } /* @internal */ diff --git a/src/testRunner/unittests/moduleResolution.ts b/src/testRunner/unittests/moduleResolution.ts index 87c3587ec2fed..872e9e8b17f71 100644 --- a/src/testRunner/unittests/moduleResolution.ts +++ b/src/testRunner/unittests/moduleResolution.ts @@ -215,6 +215,7 @@ namespace ts { extension: Extension.Ts, }, failedLookupLocations: [], + resolutionDiagnostics: [], }); assert.isDefined(cache.get("/sub")); assert.isUndefined(cache.get("/")); @@ -228,6 +229,7 @@ namespace ts { extension: Extension.Ts, }, failedLookupLocations: [], + resolutionDiagnostics: [], }); assert.isDefined(cache.get("/sub/dir/foo")); assert.isDefined(cache.get("/sub/dir")); @@ -243,6 +245,7 @@ namespace ts { extension: Extension.Ts, }, failedLookupLocations: [], + resolutionDiagnostics: [], }); assert.isDefined(cache.get("/foo/bar")); assert.isDefined(cache.get("/foo")); @@ -257,6 +260,7 @@ namespace ts { extension: Extension.Ts, }, failedLookupLocations: [], + resolutionDiagnostics: [], }); assert.isDefined(cache.get("/foo")); assert.isUndefined(cache.get("/")); @@ -270,6 +274,7 @@ namespace ts { extension: Extension.Ts, }, failedLookupLocations: [], + resolutionDiagnostics: [], }); assert.isDefined(cache.get("c:/foo")); assert.isDefined(cache.get("c:/")); @@ -279,6 +284,7 @@ namespace ts { cache.set("/foo/bar/baz", { resolvedModule: undefined, failedLookupLocations: [], + resolutionDiagnostics: [], }); assert.isDefined(cache.get("/foo/bar/baz")); assert.isDefined(cache.get("/foo/bar")); From eb5a03e427126c22d6211174769cb12231e81a47 Mon Sep 17 00:00:00 2001 From: Wesley Wigham Date: Mon, 18 Apr 2022 13:53:41 -0700 Subject: [PATCH 4/4] Refine selection logic in error case to use getCommonSourceDirectory, add more tests --- src/compiler/moduleNameResolver.ts | 60 +++++++++---------- src/compiler/program.ts | 5 +- ...sPackageSelfName(module=node12).errors.txt | 2 + ...ackageSelfName(module=nodenext).errors.txt | 2 + ...alPackageExports(module=node12).errors.txt | 2 + ...PackageExports(module=nodenext).errors.txt | 2 + ...JsPackageExports(module=node12).errors.txt | 2 + ...PackageExports(module=nodenext).errors.txt | 2 + ...JsPackageImports(module=node12).errors.txt | 2 + ...PackageImports(module=nodenext).errors.txt | 2 + ...alPackageExports(module=node12).errors.txt | 2 + ...PackageExports(module=nodenext).errors.txt | 2 + ...thPackageExports(module=node12).errors.txt | 2 + ...PackageExports(module=nodenext).errors.txt | 2 + ...esPackageExports(module=node12).errors.txt | 2 + ...PackageExports(module=nodenext).errors.txt | 2 + .../nodeNextPackageImportMapRootDir.js | 25 ++++++++ .../nodeNextPackageImportMapRootDir.symbols | 12 ++++ .../nodeNextPackageImportMapRootDir.types | 13 ++++ ...deNextPackageSelfNameWithOutDir.errors.txt | 19 ++++++ ...ackageSelfNameWithOutDirDeclDir.errors.txt | 22 +++++++ ...NameWithOutDirDeclDirNestedDirs.errors.txt | 41 +++++++++++++ ...odeNextPackageSelfNameWithOutDirRootDir.js | 22 +++++++ ...xtPackageSelfNameWithOutDirRootDir.symbols | 12 ++++ ...NextPackageSelfNameWithOutDirRootDir.types | 13 ++++ .../nodeNextPackageImportMapRootDir.ts | 20 +++++++ ...odeNextPackageSelfNameWithOutDirRootDir.ts | 17 ++++++ 27 files changed, 273 insertions(+), 36 deletions(-) create mode 100644 tests/baselines/reference/nodeNextPackageImportMapRootDir.js create mode 100644 tests/baselines/reference/nodeNextPackageImportMapRootDir.symbols create mode 100644 tests/baselines/reference/nodeNextPackageImportMapRootDir.types create mode 100644 tests/baselines/reference/nodeNextPackageSelfNameWithOutDir.errors.txt create mode 100644 tests/baselines/reference/nodeNextPackageSelfNameWithOutDirDeclDir.errors.txt create mode 100644 tests/baselines/reference/nodeNextPackageSelfNameWithOutDirDeclDirNestedDirs.errors.txt create mode 100644 tests/baselines/reference/nodeNextPackageSelfNameWithOutDirRootDir.js create mode 100644 tests/baselines/reference/nodeNextPackageSelfNameWithOutDirRootDir.symbols create mode 100644 tests/baselines/reference/nodeNextPackageSelfNameWithOutDirRootDir.types create mode 100644 tests/cases/compiler/nodeNextPackageImportMapRootDir.ts create mode 100644 tests/cases/compiler/nodeNextPackageSelfNameWithOutDirRootDir.ts diff --git a/src/compiler/moduleNameResolver.ts b/src/compiler/moduleNameResolver.ts index a003e1399bde4..6d0f5c58226df 100644 --- a/src/compiler/moduleNameResolver.ts +++ b/src/compiler/moduleNameResolver.ts @@ -2213,17 +2213,13 @@ namespace ts { // Even with all that, we still don't know if the root of the output file structure will be (relative to the package file) // `.`, `./src` or any other deeper directory structure. (If project references are used, it's definitely `.` by fiat, so that should be pretty common.) - const commonSourceDirGuesses: [base: string, outputDirs: string[]][] = []; + const getCanonicalFileName = hostGetCanonicalFileName({ useCaseSensitiveFileNames }); + const commonSourceDirGuesses: string[] = []; // A `rootDir` compiler option strongly indicates the root location - if (state.compilerOptions.rootDir) { - const baseLocation = toAbsolutePath(state.compilerOptions.configFilePath && getDirectoryPath(state.compilerOptions.configFilePath) || state.host.getCurrentDirectory?.() || scope.packageDirectory); - const packageRoot = toAbsolutePath(combinePaths(baseLocation, state.compilerOptions.rootDir)); - commonSourceDirGuesses.push([packageRoot, getOutputDirectoriesForBaseDirectory(baseLocation)]); - } // A `composite` project is using project references and has it's common src dir set to `.`, so it shouldn't need to check any other locations - else if (state.compilerOptions.composite && state.compilerOptions.configFilePath) { - const baseLocation = toAbsolutePath(getDirectoryPath(state.compilerOptions.configFilePath)); - commonSourceDirGuesses.push([baseLocation, getOutputDirectoriesForBaseDirectory(baseLocation)]); + if (state.compilerOptions.rootDir || (state.compilerOptions.composite && state.compilerOptions.configFilePath)) { + const commonDir = toAbsolutePath(getCommonSourceDirectory(state.compilerOptions, () => [], state.host.getCurrentDirectory?.() || "", getCanonicalFileName)); + commonSourceDirGuesses.push(commonDir); } else if (state.requestContainingDirectory) { // However without either of those set we're in the dark. Let's say you have @@ -2239,28 +2235,25 @@ namespace ts { // without more context. // But we do have more context! Just a tiny bit more! We're resolving an import _for some other input file_! And that input file, too // must be inside the common source directory! So we propagate that tidbit of info all the way to here via state.requestContainingDirectory - let baseDir = state.compilerOptions.configFilePath ? toAbsolutePath(getDirectoryPath(state.compilerOptions.configFilePath)) : toAbsolutePath(state.host.getCurrentDirectory?.() || scope.packageDirectory); - const containingDir = toAbsolutePath(state.requestContainingDirectory); - if (startsWith(containingDir, baseDir)) { - // And we can try every folder between that request folder and the config/package base directory - // This technically can be wrong - we may load ./src/index.ts when ./src/sub/index.ts was right because we don't - // know if only `./src/sub` files were loaded by the program; but this has the best chance to be right of just about anything - // else we have. And, given that we're about to load `./src/index.ts` because we choose it as likely correct, there will then - // be a file outside of `./src/sub` in the program (the file we resolved to), making us de-facto right. So this fallback lookup - // logic may influence what files are pulled in by self-names, which in turn influences the output path shape, but it's all - // internally consistent so the paths should be stable so long as we prefer the "most general" (meaning: top-most-level directory) possible results first. - const outDirs = getOutputDirectoriesForBaseDirectory(baseDir); - commonSourceDirGuesses.push([baseDir, outDirs]); - - let fragment = ensureTrailingDirectorySeparator(containingDir.slice(baseDir.length)); - while (fragment && fragment.length > 1) { - const parts = getPathComponents(fragment); - parts.shift(); // shift out root - const dir = parts.shift()!; - baseDir = combinePaths(baseDir, dir); - commonSourceDirGuesses.push([baseDir, getOutputDirectoriesForBaseDirectory(baseDir)]); - fragment = ensureTrailingDirectorySeparator(getPathFromPathComponents(parts)); - } + + const requestingFile = toAbsolutePath(combinePaths(state.requestContainingDirectory, "index.ts")); + // And we can try every folder above the common folder for the request folder and the config/package base directory + // This technically can be wrong - we may load ./src/index.ts when ./src/sub/index.ts was right because we don't + // know if only `./src/sub` files were loaded by the program; but this has the best chance to be right of just about anything + // else we have. And, given that we're about to load `./src/index.ts` because we choose it as likely correct, there will then + // be a file outside of `./src/sub` in the program (the file we resolved to), making us de-facto right. So this fallback lookup + // logic may influence what files are pulled in by self-names, which in turn influences the output path shape, but it's all + // internally consistent so the paths should be stable so long as we prefer the "most general" (meaning: top-most-level directory) possible results first. + const commonDir = toAbsolutePath(getCommonSourceDirectory(state.compilerOptions, () => [requestingFile, toAbsolutePath(packagePath)], state.host.getCurrentDirectory?.() || "", getCanonicalFileName)); + commonSourceDirGuesses.push(commonDir); + + let fragment = ensureTrailingDirectorySeparator(commonDir); + while (fragment && fragment.length > 1) { + const parts = getPathComponents(fragment); + parts.pop(); // remove a directory + const commonDir = getPathFromPathComponents(parts); + commonSourceDirGuesses.unshift(commonDir); + fragment = ensureTrailingDirectorySeparator(commonDir); } } if (commonSourceDirGuesses.length > 1) { @@ -2268,11 +2261,12 @@ namespace ts { isImports ? Diagnostics.The_project_root_is_ambiguous_but_is_required_to_resolve_import_map_entry_0_in_file_1_Supply_the_rootDir_compiler_option_to_disambiguate : Diagnostics.The_project_root_is_ambiguous_but_is_required_to_resolve_export_map_entry_0_in_file_1_Supply_the_rootDir_compiler_option_to_disambiguate, - entry, + entry === "" ? "." : entry, // replace empty string with `.` - the reverse of the operation done when entries are built - so main entrypoint errors don't look weird packagePath )); } - for (const [commonSourceDirGuess, candidateDirectories] of commonSourceDirGuesses) { + for (const commonSourceDirGuess of commonSourceDirGuesses) { + const candidateDirectories = getOutputDirectoriesForBaseDirectory(commonSourceDirGuess); for (const candidateDir of candidateDirectories) { if (startsWith(finalPath, candidateDir)) { // The matched export is looking up something in either the out declaration or js dir, now map the written path back into the source dir and source extension diff --git a/src/compiler/program.ts b/src/compiler/program.ts index cc9315db049db..8b7eeaebc81fa 100644 --- a/src/compiler/program.ts +++ b/src/compiler/program.ts @@ -1372,8 +1372,7 @@ namespace ts { } function pullDiagnosticsFromCache(names: string[] | readonly FileReference[], containingFile: SourceFile) { - const cache = host.getModuleResolutionCache?.(); - if (!cache) return; // Cache not exposed by host, no way to retrieve resolution diagnostics + if (!moduleResolutionCache) return; const containingFileName = getNormalizedAbsolutePath(containingFile.originalFileName, currentDirectory); const containingFileMode = !isString(containingFile) ? containingFile.impliedNodeFormat : undefined; const containingDir = getDirectoryPath(containingFileName); @@ -1390,7 +1389,7 @@ namespace ts { // When it is, how we extract diagnostics from the module name resolver will have the be refined - the current cache // APIs wrapping the underlying resolver make it almost impossible to smuggle the diagnostics out in a generalized way if (isExternalModuleNameRelative(name)) continue; - const diags = cache.getOrCreateCacheForModuleName(name, mode, redirectedReference).get(containingDir)?.resolutionDiagnostics; + const diags = moduleResolutionCache.getOrCreateCacheForModuleName(name, mode, redirectedReference).get(containingDir)?.resolutionDiagnostics; addResolutionDiagnostics(diags); } } diff --git a/tests/baselines/reference/nodeAllowJsPackageSelfName(module=node12).errors.txt b/tests/baselines/reference/nodeAllowJsPackageSelfName(module=node12).errors.txt index bdf6aba250c51..42a324dadf666 100644 --- a/tests/baselines/reference/nodeAllowJsPackageSelfName(module=node12).errors.txt +++ b/tests/baselines/reference/nodeAllowJsPackageSelfName(module=node12).errors.txt @@ -1,6 +1,8 @@ +error TS2209: The project root is ambiguous, but is required to resolve export map entry '.' in file 'tests/cases/conformance/node/allowJs/package.json'. Supply the `rootDir` compiler option to disambiguate. tests/cases/conformance/node/allowJs/index.cjs(2,23): error TS1471: Module 'package' cannot be imported using this construct. The specifier only resolves to an ES module, which cannot be imported synchronously. Use dynamic import instead. +!!! error TS2209: The project root is ambiguous, but is required to resolve export map entry '.' in file 'tests/cases/conformance/node/allowJs/package.json'. Supply the `rootDir` compiler option to disambiguate. ==== tests/cases/conformance/node/allowJs/index.js (0 errors) ==== // esm format file import * as self from "package"; diff --git a/tests/baselines/reference/nodeAllowJsPackageSelfName(module=nodenext).errors.txt b/tests/baselines/reference/nodeAllowJsPackageSelfName(module=nodenext).errors.txt index bdf6aba250c51..42a324dadf666 100644 --- a/tests/baselines/reference/nodeAllowJsPackageSelfName(module=nodenext).errors.txt +++ b/tests/baselines/reference/nodeAllowJsPackageSelfName(module=nodenext).errors.txt @@ -1,6 +1,8 @@ +error TS2209: The project root is ambiguous, but is required to resolve export map entry '.' in file 'tests/cases/conformance/node/allowJs/package.json'. Supply the `rootDir` compiler option to disambiguate. tests/cases/conformance/node/allowJs/index.cjs(2,23): error TS1471: Module 'package' cannot be imported using this construct. The specifier only resolves to an ES module, which cannot be imported synchronously. Use dynamic import instead. +!!! error TS2209: The project root is ambiguous, but is required to resolve export map entry '.' in file 'tests/cases/conformance/node/allowJs/package.json'. Supply the `rootDir` compiler option to disambiguate. ==== tests/cases/conformance/node/allowJs/index.js (0 errors) ==== // esm format file import * as self from "package"; diff --git a/tests/baselines/reference/nodeModulesAllowJsConditionalPackageExports(module=node12).errors.txt b/tests/baselines/reference/nodeModulesAllowJsConditionalPackageExports(module=node12).errors.txt index 83e50c001e74c..904a471431877 100644 --- a/tests/baselines/reference/nodeModulesAllowJsConditionalPackageExports(module=node12).errors.txt +++ b/tests/baselines/reference/nodeModulesAllowJsConditionalPackageExports(module=node12).errors.txt @@ -1,9 +1,11 @@ +error TS2209: The project root is ambiguous, but is required to resolve export map entry '.' in file 'tests/cases/conformance/node/allowJs/package.json'. Supply the `rootDir` compiler option to disambiguate. tests/cases/conformance/node/allowJs/index.cjs(3,22): error TS1471: Module 'package/mjs' cannot be imported using this construct. The specifier only resolves to an ES module, which cannot be imported synchronously. Use dynamic import instead. tests/cases/conformance/node/allowJs/index.cjs(4,23): error TS1471: Module 'package' cannot be imported using this construct. The specifier only resolves to an ES module, which cannot be imported synchronously. Use dynamic import instead. tests/cases/conformance/node/allowJs/node_modules/inner/index.d.mts(2,13): error TS2303: Circular definition of import alias 'cjs'. tests/cases/conformance/node/allowJs/node_modules/inner/index.d.ts(2,13): error TS2303: Circular definition of import alias 'cjs'. +!!! error TS2209: The project root is ambiguous, but is required to resolve export map entry '.' in file 'tests/cases/conformance/node/allowJs/package.json'. Supply the `rootDir` compiler option to disambiguate. ==== tests/cases/conformance/node/allowJs/index.js (0 errors) ==== // esm format file import * as cjs from "package/cjs"; diff --git a/tests/baselines/reference/nodeModulesAllowJsConditionalPackageExports(module=nodenext).errors.txt b/tests/baselines/reference/nodeModulesAllowJsConditionalPackageExports(module=nodenext).errors.txt index 83e50c001e74c..904a471431877 100644 --- a/tests/baselines/reference/nodeModulesAllowJsConditionalPackageExports(module=nodenext).errors.txt +++ b/tests/baselines/reference/nodeModulesAllowJsConditionalPackageExports(module=nodenext).errors.txt @@ -1,9 +1,11 @@ +error TS2209: The project root is ambiguous, but is required to resolve export map entry '.' in file 'tests/cases/conformance/node/allowJs/package.json'. Supply the `rootDir` compiler option to disambiguate. tests/cases/conformance/node/allowJs/index.cjs(3,22): error TS1471: Module 'package/mjs' cannot be imported using this construct. The specifier only resolves to an ES module, which cannot be imported synchronously. Use dynamic import instead. tests/cases/conformance/node/allowJs/index.cjs(4,23): error TS1471: Module 'package' cannot be imported using this construct. The specifier only resolves to an ES module, which cannot be imported synchronously. Use dynamic import instead. tests/cases/conformance/node/allowJs/node_modules/inner/index.d.mts(2,13): error TS2303: Circular definition of import alias 'cjs'. tests/cases/conformance/node/allowJs/node_modules/inner/index.d.ts(2,13): error TS2303: Circular definition of import alias 'cjs'. +!!! error TS2209: The project root is ambiguous, but is required to resolve export map entry '.' in file 'tests/cases/conformance/node/allowJs/package.json'. Supply the `rootDir` compiler option to disambiguate. ==== tests/cases/conformance/node/allowJs/index.js (0 errors) ==== // esm format file import * as cjs from "package/cjs"; diff --git a/tests/baselines/reference/nodeModulesAllowJsPackageExports(module=node12).errors.txt b/tests/baselines/reference/nodeModulesAllowJsPackageExports(module=node12).errors.txt index e6f4b3ce2eb2b..63e7af6ada0ac 100644 --- a/tests/baselines/reference/nodeModulesAllowJsPackageExports(module=node12).errors.txt +++ b/tests/baselines/reference/nodeModulesAllowJsPackageExports(module=node12).errors.txt @@ -1,3 +1,4 @@ +error TS2209: The project root is ambiguous, but is required to resolve export map entry '.' in file 'tests/cases/conformance/node/allowJs/package.json'. Supply the `rootDir` compiler option to disambiguate. tests/cases/conformance/node/allowJs/index.cjs(3,22): error TS1471: Module 'package/mjs' cannot be imported using this construct. The specifier only resolves to an ES module, which cannot be imported synchronously. Use dynamic import instead. tests/cases/conformance/node/allowJs/index.cjs(4,23): error TS1471: Module 'package' cannot be imported using this construct. The specifier only resolves to an ES module, which cannot be imported synchronously. Use dynamic import instead. tests/cases/conformance/node/allowJs/index.cjs(9,23): error TS1471: Module 'inner/mjs' cannot be imported using this construct. The specifier only resolves to an ES module, which cannot be imported synchronously. Use dynamic import instead. @@ -6,6 +7,7 @@ tests/cases/conformance/node/allowJs/node_modules/inner/index.d.ts(2,13): error tests/cases/conformance/node/allowJs/node_modules/inner/index.d.ts(3,22): error TS1471: Module 'inner/mjs' cannot be imported using this construct. The specifier only resolves to an ES module, which cannot be imported synchronously. Use dynamic import instead. +!!! error TS2209: The project root is ambiguous, but is required to resolve export map entry '.' in file 'tests/cases/conformance/node/allowJs/package.json'. Supply the `rootDir` compiler option to disambiguate. ==== tests/cases/conformance/node/allowJs/index.js (0 errors) ==== // esm format file import * as cjs from "package/cjs"; diff --git a/tests/baselines/reference/nodeModulesAllowJsPackageExports(module=nodenext).errors.txt b/tests/baselines/reference/nodeModulesAllowJsPackageExports(module=nodenext).errors.txt index e6f4b3ce2eb2b..63e7af6ada0ac 100644 --- a/tests/baselines/reference/nodeModulesAllowJsPackageExports(module=nodenext).errors.txt +++ b/tests/baselines/reference/nodeModulesAllowJsPackageExports(module=nodenext).errors.txt @@ -1,3 +1,4 @@ +error TS2209: The project root is ambiguous, but is required to resolve export map entry '.' in file 'tests/cases/conformance/node/allowJs/package.json'. Supply the `rootDir` compiler option to disambiguate. tests/cases/conformance/node/allowJs/index.cjs(3,22): error TS1471: Module 'package/mjs' cannot be imported using this construct. The specifier only resolves to an ES module, which cannot be imported synchronously. Use dynamic import instead. tests/cases/conformance/node/allowJs/index.cjs(4,23): error TS1471: Module 'package' cannot be imported using this construct. The specifier only resolves to an ES module, which cannot be imported synchronously. Use dynamic import instead. tests/cases/conformance/node/allowJs/index.cjs(9,23): error TS1471: Module 'inner/mjs' cannot be imported using this construct. The specifier only resolves to an ES module, which cannot be imported synchronously. Use dynamic import instead. @@ -6,6 +7,7 @@ tests/cases/conformance/node/allowJs/node_modules/inner/index.d.ts(2,13): error tests/cases/conformance/node/allowJs/node_modules/inner/index.d.ts(3,22): error TS1471: Module 'inner/mjs' cannot be imported using this construct. The specifier only resolves to an ES module, which cannot be imported synchronously. Use dynamic import instead. +!!! error TS2209: The project root is ambiguous, but is required to resolve export map entry '.' in file 'tests/cases/conformance/node/allowJs/package.json'. Supply the `rootDir` compiler option to disambiguate. ==== tests/cases/conformance/node/allowJs/index.js (0 errors) ==== // esm format file import * as cjs from "package/cjs"; diff --git a/tests/baselines/reference/nodeModulesAllowJsPackageImports(module=node12).errors.txt b/tests/baselines/reference/nodeModulesAllowJsPackageImports(module=node12).errors.txt index 261be58f1a221..ffbcbe24e9973 100644 --- a/tests/baselines/reference/nodeModulesAllowJsPackageImports(module=node12).errors.txt +++ b/tests/baselines/reference/nodeModulesAllowJsPackageImports(module=node12).errors.txt @@ -1,7 +1,9 @@ +error TS2210: The project root is ambiguous, but is required to resolve import map entry '.' in file 'tests/cases/conformance/node/allowJs/package.json'. Supply the `rootDir` compiler option to disambiguate. tests/cases/conformance/node/allowJs/index.cjs(3,22): error TS1471: Module '#mjs' cannot be imported using this construct. The specifier only resolves to an ES module, which cannot be imported synchronously. Use dynamic import instead. tests/cases/conformance/node/allowJs/index.cjs(4,23): error TS1471: Module '#type' cannot be imported using this construct. The specifier only resolves to an ES module, which cannot be imported synchronously. Use dynamic import instead. +!!! error TS2210: The project root is ambiguous, but is required to resolve import map entry '.' in file 'tests/cases/conformance/node/allowJs/package.json'. Supply the `rootDir` compiler option to disambiguate. ==== tests/cases/conformance/node/allowJs/index.js (0 errors) ==== // esm format file import * as cjs from "#cjs"; diff --git a/tests/baselines/reference/nodeModulesAllowJsPackageImports(module=nodenext).errors.txt b/tests/baselines/reference/nodeModulesAllowJsPackageImports(module=nodenext).errors.txt index 261be58f1a221..ffbcbe24e9973 100644 --- a/tests/baselines/reference/nodeModulesAllowJsPackageImports(module=nodenext).errors.txt +++ b/tests/baselines/reference/nodeModulesAllowJsPackageImports(module=nodenext).errors.txt @@ -1,7 +1,9 @@ +error TS2210: The project root is ambiguous, but is required to resolve import map entry '.' in file 'tests/cases/conformance/node/allowJs/package.json'. Supply the `rootDir` compiler option to disambiguate. tests/cases/conformance/node/allowJs/index.cjs(3,22): error TS1471: Module '#mjs' cannot be imported using this construct. The specifier only resolves to an ES module, which cannot be imported synchronously. Use dynamic import instead. tests/cases/conformance/node/allowJs/index.cjs(4,23): error TS1471: Module '#type' cannot be imported using this construct. The specifier only resolves to an ES module, which cannot be imported synchronously. Use dynamic import instead. +!!! error TS2210: The project root is ambiguous, but is required to resolve import map entry '.' in file 'tests/cases/conformance/node/allowJs/package.json'. Supply the `rootDir` compiler option to disambiguate. ==== tests/cases/conformance/node/allowJs/index.js (0 errors) ==== // esm format file import * as cjs from "#cjs"; diff --git a/tests/baselines/reference/nodeModulesConditionalPackageExports(module=node12).errors.txt b/tests/baselines/reference/nodeModulesConditionalPackageExports(module=node12).errors.txt index 7397e1e1dbd27..793f3f03da25d 100644 --- a/tests/baselines/reference/nodeModulesConditionalPackageExports(module=node12).errors.txt +++ b/tests/baselines/reference/nodeModulesConditionalPackageExports(module=node12).errors.txt @@ -1,9 +1,11 @@ +error TS2209: The project root is ambiguous, but is required to resolve export map entry '.' in file 'tests/cases/conformance/node/package.json'. Supply the `rootDir` compiler option to disambiguate. tests/cases/conformance/node/index.cts(3,22): error TS1471: Module 'package/mjs' cannot be imported using this construct. The specifier only resolves to an ES module, which cannot be imported synchronously. Use dynamic import instead. tests/cases/conformance/node/index.cts(4,23): error TS1471: Module 'package' cannot be imported using this construct. The specifier only resolves to an ES module, which cannot be imported synchronously. Use dynamic import instead. tests/cases/conformance/node/node_modules/inner/index.d.mts(2,13): error TS2303: Circular definition of import alias 'cjs'. tests/cases/conformance/node/node_modules/inner/index.d.ts(2,13): error TS2303: Circular definition of import alias 'cjs'. +!!! error TS2209: The project root is ambiguous, but is required to resolve export map entry '.' in file 'tests/cases/conformance/node/package.json'. Supply the `rootDir` compiler option to disambiguate. ==== tests/cases/conformance/node/index.ts (0 errors) ==== // esm format file import * as cjs from "package/cjs"; diff --git a/tests/baselines/reference/nodeModulesConditionalPackageExports(module=nodenext).errors.txt b/tests/baselines/reference/nodeModulesConditionalPackageExports(module=nodenext).errors.txt index 7397e1e1dbd27..793f3f03da25d 100644 --- a/tests/baselines/reference/nodeModulesConditionalPackageExports(module=nodenext).errors.txt +++ b/tests/baselines/reference/nodeModulesConditionalPackageExports(module=nodenext).errors.txt @@ -1,9 +1,11 @@ +error TS2209: The project root is ambiguous, but is required to resolve export map entry '.' in file 'tests/cases/conformance/node/package.json'. Supply the `rootDir` compiler option to disambiguate. tests/cases/conformance/node/index.cts(3,22): error TS1471: Module 'package/mjs' cannot be imported using this construct. The specifier only resolves to an ES module, which cannot be imported synchronously. Use dynamic import instead. tests/cases/conformance/node/index.cts(4,23): error TS1471: Module 'package' cannot be imported using this construct. The specifier only resolves to an ES module, which cannot be imported synchronously. Use dynamic import instead. tests/cases/conformance/node/node_modules/inner/index.d.mts(2,13): error TS2303: Circular definition of import alias 'cjs'. tests/cases/conformance/node/node_modules/inner/index.d.ts(2,13): error TS2303: Circular definition of import alias 'cjs'. +!!! error TS2209: The project root is ambiguous, but is required to resolve export map entry '.' in file 'tests/cases/conformance/node/package.json'. Supply the `rootDir` compiler option to disambiguate. ==== tests/cases/conformance/node/index.ts (0 errors) ==== // esm format file import * as cjs from "package/cjs"; diff --git a/tests/baselines/reference/nodeModulesDeclarationEmitWithPackageExports(module=node12).errors.txt b/tests/baselines/reference/nodeModulesDeclarationEmitWithPackageExports(module=node12).errors.txt index 11f39b9dd9366..4ee7f3c4cef3d 100644 --- a/tests/baselines/reference/nodeModulesDeclarationEmitWithPackageExports(module=node12).errors.txt +++ b/tests/baselines/reference/nodeModulesDeclarationEmitWithPackageExports(module=node12).errors.txt @@ -1,3 +1,4 @@ +error TS2209: The project root is ambiguous, but is required to resolve export map entry '.' in file 'tests/cases/conformance/node/package.json'. Supply the `rootDir` compiler option to disambiguate. tests/cases/conformance/node/index.cts(3,22): error TS1471: Module 'package/mjs' cannot be imported using this construct. The specifier only resolves to an ES module, which cannot be imported synchronously. Use dynamic import instead. tests/cases/conformance/node/index.cts(4,23): error TS1471: Module 'package' cannot be imported using this construct. The specifier only resolves to an ES module, which cannot be imported synchronously. Use dynamic import instead. tests/cases/conformance/node/index.cts(9,23): error TS1471: Module 'inner/mjs' cannot be imported using this construct. The specifier only resolves to an ES module, which cannot be imported synchronously. Use dynamic import instead. @@ -8,6 +9,7 @@ tests/cases/conformance/node/node_modules/inner/index.d.ts(3,22): error TS1471: tests/cases/conformance/node/node_modules/inner/index.d.ts(5,1): error TS1036: Statements are not allowed in ambient contexts. +!!! error TS2209: The project root is ambiguous, but is required to resolve export map entry '.' in file 'tests/cases/conformance/node/package.json'. Supply the `rootDir` compiler option to disambiguate. ==== tests/cases/conformance/node/index.ts (0 errors) ==== // esm format file import * as cjs from "package/cjs"; diff --git a/tests/baselines/reference/nodeModulesDeclarationEmitWithPackageExports(module=nodenext).errors.txt b/tests/baselines/reference/nodeModulesDeclarationEmitWithPackageExports(module=nodenext).errors.txt index 11f39b9dd9366..4ee7f3c4cef3d 100644 --- a/tests/baselines/reference/nodeModulesDeclarationEmitWithPackageExports(module=nodenext).errors.txt +++ b/tests/baselines/reference/nodeModulesDeclarationEmitWithPackageExports(module=nodenext).errors.txt @@ -1,3 +1,4 @@ +error TS2209: The project root is ambiguous, but is required to resolve export map entry '.' in file 'tests/cases/conformance/node/package.json'. Supply the `rootDir` compiler option to disambiguate. tests/cases/conformance/node/index.cts(3,22): error TS1471: Module 'package/mjs' cannot be imported using this construct. The specifier only resolves to an ES module, which cannot be imported synchronously. Use dynamic import instead. tests/cases/conformance/node/index.cts(4,23): error TS1471: Module 'package' cannot be imported using this construct. The specifier only resolves to an ES module, which cannot be imported synchronously. Use dynamic import instead. tests/cases/conformance/node/index.cts(9,23): error TS1471: Module 'inner/mjs' cannot be imported using this construct. The specifier only resolves to an ES module, which cannot be imported synchronously. Use dynamic import instead. @@ -8,6 +9,7 @@ tests/cases/conformance/node/node_modules/inner/index.d.ts(3,22): error TS1471: tests/cases/conformance/node/node_modules/inner/index.d.ts(5,1): error TS1036: Statements are not allowed in ambient contexts. +!!! error TS2209: The project root is ambiguous, but is required to resolve export map entry '.' in file 'tests/cases/conformance/node/package.json'. Supply the `rootDir` compiler option to disambiguate. ==== tests/cases/conformance/node/index.ts (0 errors) ==== // esm format file import * as cjs from "package/cjs"; diff --git a/tests/baselines/reference/nodeModulesPackageExports(module=node12).errors.txt b/tests/baselines/reference/nodeModulesPackageExports(module=node12).errors.txt index 464db33f319b0..8f7452ffa72aa 100644 --- a/tests/baselines/reference/nodeModulesPackageExports(module=node12).errors.txt +++ b/tests/baselines/reference/nodeModulesPackageExports(module=node12).errors.txt @@ -1,3 +1,4 @@ +error TS2209: The project root is ambiguous, but is required to resolve export map entry '.' in file 'tests/cases/conformance/node/package.json'. Supply the `rootDir` compiler option to disambiguate. tests/cases/conformance/node/index.cts(3,22): error TS1471: Module 'package/mjs' cannot be imported using this construct. The specifier only resolves to an ES module, which cannot be imported synchronously. Use dynamic import instead. tests/cases/conformance/node/index.cts(4,23): error TS1471: Module 'package' cannot be imported using this construct. The specifier only resolves to an ES module, which cannot be imported synchronously. Use dynamic import instead. tests/cases/conformance/node/index.cts(9,23): error TS1471: Module 'inner/mjs' cannot be imported using this construct. The specifier only resolves to an ES module, which cannot be imported synchronously. Use dynamic import instead. @@ -6,6 +7,7 @@ tests/cases/conformance/node/node_modules/inner/index.d.ts(2,13): error TS2303: tests/cases/conformance/node/node_modules/inner/index.d.ts(3,22): error TS1471: Module 'inner/mjs' cannot be imported using this construct. The specifier only resolves to an ES module, which cannot be imported synchronously. Use dynamic import instead. +!!! error TS2209: The project root is ambiguous, but is required to resolve export map entry '.' in file 'tests/cases/conformance/node/package.json'. Supply the `rootDir` compiler option to disambiguate. ==== tests/cases/conformance/node/index.ts (0 errors) ==== // esm format file import * as cjs from "package/cjs"; diff --git a/tests/baselines/reference/nodeModulesPackageExports(module=nodenext).errors.txt b/tests/baselines/reference/nodeModulesPackageExports(module=nodenext).errors.txt index 464db33f319b0..8f7452ffa72aa 100644 --- a/tests/baselines/reference/nodeModulesPackageExports(module=nodenext).errors.txt +++ b/tests/baselines/reference/nodeModulesPackageExports(module=nodenext).errors.txt @@ -1,3 +1,4 @@ +error TS2209: The project root is ambiguous, but is required to resolve export map entry '.' in file 'tests/cases/conformance/node/package.json'. Supply the `rootDir` compiler option to disambiguate. tests/cases/conformance/node/index.cts(3,22): error TS1471: Module 'package/mjs' cannot be imported using this construct. The specifier only resolves to an ES module, which cannot be imported synchronously. Use dynamic import instead. tests/cases/conformance/node/index.cts(4,23): error TS1471: Module 'package' cannot be imported using this construct. The specifier only resolves to an ES module, which cannot be imported synchronously. Use dynamic import instead. tests/cases/conformance/node/index.cts(9,23): error TS1471: Module 'inner/mjs' cannot be imported using this construct. The specifier only resolves to an ES module, which cannot be imported synchronously. Use dynamic import instead. @@ -6,6 +7,7 @@ tests/cases/conformance/node/node_modules/inner/index.d.ts(2,13): error TS2303: tests/cases/conformance/node/node_modules/inner/index.d.ts(3,22): error TS1471: Module 'inner/mjs' cannot be imported using this construct. The specifier only resolves to an ES module, which cannot be imported synchronously. Use dynamic import instead. +!!! error TS2209: The project root is ambiguous, but is required to resolve export map entry '.' in file 'tests/cases/conformance/node/package.json'. Supply the `rootDir` compiler option to disambiguate. ==== tests/cases/conformance/node/index.ts (0 errors) ==== // esm format file import * as cjs from "package/cjs"; diff --git a/tests/baselines/reference/nodeNextPackageImportMapRootDir.js b/tests/baselines/reference/nodeNextPackageImportMapRootDir.js new file mode 100644 index 0000000000000..df6506fa35c79 --- /dev/null +++ b/tests/baselines/reference/nodeNextPackageImportMapRootDir.js @@ -0,0 +1,25 @@ +//// [tests/cases/compiler/nodeNextPackageImportMapRootDir.ts] //// + +//// [package.json] +{ + "name": "@this/package", + "type": "module", + "exports": { + ".": "./dist/index.js" + }, + "imports": { + "#dep": "./dist/index.js" + } +} +//// [index.ts] +import * as me from "#dep"; + +me.thing(); + +export function thing(): void {} + + +//// [index.js] +import * as me from "#dep"; +me.thing(); +export function thing() { } diff --git a/tests/baselines/reference/nodeNextPackageImportMapRootDir.symbols b/tests/baselines/reference/nodeNextPackageImportMapRootDir.symbols new file mode 100644 index 0000000000000..f03b685e938dc --- /dev/null +++ b/tests/baselines/reference/nodeNextPackageImportMapRootDir.symbols @@ -0,0 +1,12 @@ +=== tests/cases/compiler/index.ts === +import * as me from "#dep"; +>me : Symbol(me, Decl(index.ts, 0, 6)) + +me.thing(); +>me.thing : Symbol(thing, Decl(index.ts, 2, 11)) +>me : Symbol(me, Decl(index.ts, 0, 6)) +>thing : Symbol(thing, Decl(index.ts, 2, 11)) + +export function thing(): void {} +>thing : Symbol(thing, Decl(index.ts, 2, 11)) + diff --git a/tests/baselines/reference/nodeNextPackageImportMapRootDir.types b/tests/baselines/reference/nodeNextPackageImportMapRootDir.types new file mode 100644 index 0000000000000..445dd91324a08 --- /dev/null +++ b/tests/baselines/reference/nodeNextPackageImportMapRootDir.types @@ -0,0 +1,13 @@ +=== tests/cases/compiler/index.ts === +import * as me from "#dep"; +>me : typeof me + +me.thing(); +>me.thing() : void +>me.thing : () => void +>me : typeof me +>thing : () => void + +export function thing(): void {} +>thing : () => void + diff --git a/tests/baselines/reference/nodeNextPackageSelfNameWithOutDir.errors.txt b/tests/baselines/reference/nodeNextPackageSelfNameWithOutDir.errors.txt new file mode 100644 index 0000000000000..6577aed8336cb --- /dev/null +++ b/tests/baselines/reference/nodeNextPackageSelfNameWithOutDir.errors.txt @@ -0,0 +1,19 @@ +error TS2209: The project root is ambiguous, but is required to resolve export map entry '.' in file 'tests/cases/compiler/package.json'. Supply the `rootDir` compiler option to disambiguate. + + +!!! error TS2209: The project root is ambiguous, but is required to resolve export map entry '.' in file 'tests/cases/compiler/package.json'. Supply the `rootDir` compiler option to disambiguate. +==== tests/cases/compiler/package.json (0 errors) ==== + { + "name": "@this/package", + "type": "module", + "exports": { + ".": "./dist/index.js" + } + } +==== tests/cases/compiler/index.ts (0 errors) ==== + import * as me from "@this/package"; + + me.thing(); + + export function thing(): void {} + \ No newline at end of file diff --git a/tests/baselines/reference/nodeNextPackageSelfNameWithOutDirDeclDir.errors.txt b/tests/baselines/reference/nodeNextPackageSelfNameWithOutDirDeclDir.errors.txt new file mode 100644 index 0000000000000..6ccce9cf141e7 --- /dev/null +++ b/tests/baselines/reference/nodeNextPackageSelfNameWithOutDirDeclDir.errors.txt @@ -0,0 +1,22 @@ +error TS2209: The project root is ambiguous, but is required to resolve export map entry '.' in file 'tests/cases/compiler/package.json'. Supply the `rootDir` compiler option to disambiguate. + + +!!! error TS2209: The project root is ambiguous, but is required to resolve export map entry '.' in file 'tests/cases/compiler/package.json'. Supply the `rootDir` compiler option to disambiguate. +==== tests/cases/compiler/package.json (0 errors) ==== + { + "name": "@this/package", + "type": "module", + "exports": { + ".": { + "default": "./dist/index.js", + "types": "./types/index.d.ts" + } + } + } +==== tests/cases/compiler/index.ts (0 errors) ==== + import * as me from "@this/package"; + + me.thing(); + + export function thing(): void {} + \ No newline at end of file diff --git a/tests/baselines/reference/nodeNextPackageSelfNameWithOutDirDeclDirNestedDirs.errors.txt b/tests/baselines/reference/nodeNextPackageSelfNameWithOutDirDeclDirNestedDirs.errors.txt new file mode 100644 index 0000000000000..14365276c312f --- /dev/null +++ b/tests/baselines/reference/nodeNextPackageSelfNameWithOutDirDeclDirNestedDirs.errors.txt @@ -0,0 +1,41 @@ +error TS2209: The project root is ambiguous, but is required to resolve export map entry '.' in file 'tests/cases/compiler/package.json'. Supply the `rootDir` compiler option to disambiguate. + + +!!! error TS2209: The project root is ambiguous, but is required to resolve export map entry '.' in file 'tests/cases/compiler/package.json'. Supply the `rootDir` compiler option to disambiguate. +==== tests/cases/compiler/tsconfig.json (0 errors) ==== + { + "compilerOptions": { + "module": "nodenext", + "outDir": "./dist", + "declarationDir": "./types", + "declaration": true + } + } +==== tests/cases/compiler/src/thing.ts (0 errors) ==== + // The following import should cause `index.ts` + // to be included in the build, which will, + // in turn, cause the common src directory to not be `src` + // (the harness is wierd here in that noImplicitReferences makes only + // this file get loaded as an entrypoint and emitted, while on the + // real command-line we'll crawl the imports for that set - a limitation + // of the harness, I suppose) + import * as me from "@this/package"; + + me.thing(); + + export function srcthing(): void {} + + +==== tests/cases/compiler/package.json (0 errors) ==== + { + "name": "@this/package", + "type": "module", + "exports": { + ".": { + "default": "./dist/index.js", + "types": "./types/index.d.ts" + } + } + } +==== tests/cases/compiler/index.ts (0 errors) ==== + export {srcthing as thing} from "./src/thing.js"; \ No newline at end of file diff --git a/tests/baselines/reference/nodeNextPackageSelfNameWithOutDirRootDir.js b/tests/baselines/reference/nodeNextPackageSelfNameWithOutDirRootDir.js new file mode 100644 index 0000000000000..7dad992a9462d --- /dev/null +++ b/tests/baselines/reference/nodeNextPackageSelfNameWithOutDirRootDir.js @@ -0,0 +1,22 @@ +//// [tests/cases/compiler/nodeNextPackageSelfNameWithOutDirRootDir.ts] //// + +//// [package.json] +{ + "name": "@this/package", + "type": "module", + "exports": { + ".": "./dist/index.js" + } +} +//// [index.ts] +import * as me from "@this/package"; + +me.thing(); + +export function thing(): void {} + + +//// [index.js] +import * as me from "@this/package"; +me.thing(); +export function thing() { } diff --git a/tests/baselines/reference/nodeNextPackageSelfNameWithOutDirRootDir.symbols b/tests/baselines/reference/nodeNextPackageSelfNameWithOutDirRootDir.symbols new file mode 100644 index 0000000000000..8bcf39cdd7a89 --- /dev/null +++ b/tests/baselines/reference/nodeNextPackageSelfNameWithOutDirRootDir.symbols @@ -0,0 +1,12 @@ +=== tests/cases/compiler/index.ts === +import * as me from "@this/package"; +>me : Symbol(me, Decl(index.ts, 0, 6)) + +me.thing(); +>me.thing : Symbol(thing, Decl(index.ts, 2, 11)) +>me : Symbol(me, Decl(index.ts, 0, 6)) +>thing : Symbol(thing, Decl(index.ts, 2, 11)) + +export function thing(): void {} +>thing : Symbol(thing, Decl(index.ts, 2, 11)) + diff --git a/tests/baselines/reference/nodeNextPackageSelfNameWithOutDirRootDir.types b/tests/baselines/reference/nodeNextPackageSelfNameWithOutDirRootDir.types new file mode 100644 index 0000000000000..a22456ef499fb --- /dev/null +++ b/tests/baselines/reference/nodeNextPackageSelfNameWithOutDirRootDir.types @@ -0,0 +1,13 @@ +=== tests/cases/compiler/index.ts === +import * as me from "@this/package"; +>me : typeof me + +me.thing(); +>me.thing() : void +>me.thing : () => void +>me : typeof me +>thing : () => void + +export function thing(): void {} +>thing : () => void + diff --git a/tests/cases/compiler/nodeNextPackageImportMapRootDir.ts b/tests/cases/compiler/nodeNextPackageImportMapRootDir.ts new file mode 100644 index 0000000000000..a0a8dfb8e7b4f --- /dev/null +++ b/tests/cases/compiler/nodeNextPackageImportMapRootDir.ts @@ -0,0 +1,20 @@ +// @module: nodenext +// @outDir: ./dist +// @rootDir: tests/cases/compiler +// @filename: package.json +{ + "name": "@this/package", + "type": "module", + "exports": { + ".": "./dist/index.js" + }, + "imports": { + "#dep": "./dist/index.js" + } +} +// @filename: index.ts +import * as me from "#dep"; + +me.thing(); + +export function thing(): void {} diff --git a/tests/cases/compiler/nodeNextPackageSelfNameWithOutDirRootDir.ts b/tests/cases/compiler/nodeNextPackageSelfNameWithOutDirRootDir.ts new file mode 100644 index 0000000000000..1e32c30e683a5 --- /dev/null +++ b/tests/cases/compiler/nodeNextPackageSelfNameWithOutDirRootDir.ts @@ -0,0 +1,17 @@ +// @module: nodenext +// @outDir: ./dist +// @rootDir: tests/cases/compiler +// @filename: package.json +{ + "name": "@this/package", + "type": "module", + "exports": { + ".": "./dist/index.js" + } +} +// @filename: index.ts +import * as me from "@this/package"; + +me.thing(); + +export function thing(): void {}