Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Do not canonicalize the file names when getting absolute paths during nodenext resolution #50557

Merged
merged 5 commits into from Sep 1, 2022
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
6 changes: 3 additions & 3 deletions src/compiler/moduleNameResolver.ts
Expand Up @@ -2227,7 +2227,7 @@ namespace ts {
function toAbsolutePath(path: string | undefined): string | undefined;
function toAbsolutePath(path: string | undefined): string | undefined {
if (path === undefined) return path;
return hostGetCanonicalFileName({ useCaseSensitiveFileNames })(getNormalizedAbsolutePath(path, state.host.getCurrentDirectory?.()));
return getNormalizedAbsolutePath(path, state.host.getCurrentDirectory?.());
}

function combineDirectoryPath(root: string, dir: string) {
Expand All @@ -2249,7 +2249,7 @@ namespace ts {
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)
&& (state.compilerOptions.configFile ? containsPath(scope.packageDirectory, toAbsolutePath(state.compilerOptions.configFile.fileName), !useCaseSensitiveFileNames()) : 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)
Expand Down Expand Up @@ -2310,7 +2310,7 @@ namespace ts {
for (const commonSourceDirGuess of commonSourceDirGuesses) {
const candidateDirectories = getOutputDirectoriesForBaseDirectory(commonSourceDirGuess);
for (const candidateDir of candidateDirectories) {
if (startsWith(finalPath, candidateDir)) {
if (containsPath(candidateDir, finalPath, !useCaseSensitiveFileNames())) {
// 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);
Expand Down
Expand Up @@ -262,5 +262,69 @@ a;b;
verifyDirSymlink("when import matches disk but directory symlink target does not", `${projectRoot}/XY`, `${projectRoot}/XY`, `./Xy`);
verifyDirSymlink("when import and directory symlink target agree but do not match disk", `${projectRoot}/XY`, `${projectRoot}/Xy`, `./Xy`);
verifyDirSymlink("when import, directory symlink target, and disk are all different", `${projectRoot}/XY`, `${projectRoot}/Xy`, `./yX`);

verifyTscWatch({
scenario: "forceConsistentCasingInFileNames",
subScenario: "with nodeNext resolution",
commandLineArgs: ["--w", "--explainFiles"],
sys: () => createWatchedSystem({
"/Users/name/projects/web/src/bin.ts": `import { foo } from "yargs";`,
"/Users/name/projects/web/node_modules/@types/yargs/index.d.ts": "export function foo(): void;",
"/Users/name/projects/web/node_modules/@types/yargs/index.d.mts": "export function foo(): void;",
"/Users/name/projects/web/node_modules/@types/yargs/package.json": JSON.stringify({
name: "yargs",
version: "17.0.12",
exports: {
".": {
types: {
import: "./index.d.mts",
default: "./index.d.ts"
}
},
}
}),
"/Users/name/projects/web/tsconfig.json": JSON.stringify({
compilerOptions: {
moduleResolution: "nodenext",
forceConsistentCasingInFileNames: true,
traceResolution: true,
}
}),
[libFile.path]: libFile.content,
}, { currentDirectory: "/Users/name/projects/web" }),
changes: emptyArray,
});

verifyTscWatch({
scenario: "forceConsistentCasingInFileNames",
subScenario: "self name package reference",
commandLineArgs: ["-w", "--explainFiles"],
sys: () => createWatchedSystem({
"/Users/name/projects/web/package.json": JSON.stringify({
name: "@this/package",
type: "module",
exports: {
".": "./dist/index.js"
}
}),
"/Users/name/projects/web/index.ts": Utils.dedent`
import * as me from "@this/package";
me.thing();
export function thing(): void {}
`,
"/Users/name/projects/web/tsconfig.json": JSON.stringify({
compilerOptions: {
module: "nodenext",
outDir: "./dist",
declarationDir: "./types",
composite: true,
forceConsistentCasingInFileNames: true,
traceResolution: true,
}
}),
"/a/lib/lib.esnext.full.d.ts": libFile.content,
}, { currentDirectory: "/Users/name/projects/web" }),
changes: emptyArray,
});
});
}
@@ -0,0 +1,148 @@
Input::
//// [/Users/name/projects/web/package.json]
{"name":"@this/package","type":"module","exports":{".":"./dist/index.js"}}

//// [/Users/name/projects/web/index.ts]
import * as me from "@this/package";
me.thing();
export function thing(): void {}


//// [/Users/name/projects/web/tsconfig.json]
{"compilerOptions":{"module":"nodenext","outDir":"./dist","declarationDir":"./types","composite":true,"forceConsistentCasingInFileNames":true,"traceResolution":true}}

//// [/a/lib/lib.esnext.full.d.ts]
/// <reference no-default-lib="true"/>
interface Boolean {}
interface Function {}
interface CallableFunction {}
interface NewableFunction {}
interface IArguments {}
interface Number { toExponential: any; }
interface Object {}
interface RegExp {}
interface String { charAt: any; }
interface Array<T> { length: number; [n: number]: T; }


/a/lib/tsc.js -w --explainFiles
Output::
>> Screen clear
[12:00:23 AM] Starting compilation in watch mode...

Found 'package.json' at '/users/name/projects/web/package.json'.
'package.json' does not have a 'typesVersions' field.
======== Resolving module '@this/package' from '/Users/name/projects/web/index.ts'. ========
Module resolution kind is not specified, using 'NodeNext'.
File '/users/name/projects/web/package.json' exists according to earlier cached lookups.
File '/Users/name/projects/web/index.ts' exist - use it as a name resolution result.
Resolving real path for '/Users/name/projects/web/index.ts', result '/Users/name/projects/web/index.ts'.
======== Module name '@this/package' was successfully resolved to '/Users/name/projects/web/index.ts'. ========
File '/a/lib/package.json' does not exist.
File '/a/package.json' does not exist.
File '/package.json' does not exist.
../../../../a/lib/lib.esnext.full.d.ts
Default library for target 'esnext'
index.ts
Matched by default include pattern '**/*'
Imported via "@this/package" from file 'index.ts'
File is ECMAScript module because 'package.json' has field "type" with value "module"
[12:00:36 AM] Found 0 errors. Watching for file changes.



Program root files: ["/Users/name/projects/web/index.ts"]
Program options: {"module":199,"outDir":"/Users/name/projects/web/dist","declarationDir":"/Users/name/projects/web/types","composite":true,"forceConsistentCasingInFileNames":true,"traceResolution":true,"watch":true,"explainFiles":true,"configFilePath":"/Users/name/projects/web/tsconfig.json"}
Program structureReused: Not
Program files::
/a/lib/lib.esnext.full.d.ts
/Users/name/projects/web/index.ts

Semantic diagnostics in builder refreshed for::
/a/lib/lib.esnext.full.d.ts
/Users/name/projects/web/index.ts

Shape signatures in builder refreshed for::
/a/lib/lib.esnext.full.d.ts (used version)
/users/name/projects/web/index.ts (computed .d.ts during emit)

WatchedFiles::
/users/name/projects/web/tsconfig.json:
{"fileName":"/Users/name/projects/web/tsconfig.json","pollingInterval":250}
/users/name/projects/web/index.ts:
{"fileName":"/Users/name/projects/web/index.ts","pollingInterval":250}
/a/lib/lib.esnext.full.d.ts:
{"fileName":"/a/lib/lib.esnext.full.d.ts","pollingInterval":250}
/users/name/projects/web/package.json:
{"fileName":"/Users/name/projects/web/package.json","pollingInterval":250}
/users/name/projects/web/node_modules/@types:
{"fileName":"/Users/name/projects/web/node_modules/@types","pollingInterval":500}

FsWatches::

FsWatchesRecursive::
/users/name/projects/web:
{"directoryName":"/users/name/projects/web"}

exitCode:: ExitStatus.undefined

//// [/Users/name/projects/web/dist/index.js]
import * as me from "@this/package";
me.thing();
export function thing() { }


//// [/Users/name/projects/web/types/index.d.ts]
export declare function thing(): void;


//// [/Users/name/projects/web/dist/tsconfig.tsbuildinfo]
{"program":{"fileNames":["../../../../../a/lib/lib.esnext.full.d.ts","../index.ts"],"fileInfos":[{"version":"-7698705165-/// <reference no-default-lib=\"true\"/>\ninterface Boolean {}\ninterface Function {}\ninterface CallableFunction {}\ninterface NewableFunction {}\ninterface IArguments {}\ninterface Number { toExponential: any; }\ninterface Object {}\ninterface RegExp {}\ninterface String { charAt: any; }\ninterface Array<T> { length: number; [n: number]: T; }","affectsGlobalScope":true,"impliedFormat":1},{"version":"14361483761-import * as me from \"@this/package\";\nme.thing();\nexport function thing(): void {}\n","signature":"-2724770439-export declare function thing(): void;\n","impliedFormat":99}],"options":{"composite":true,"declarationDir":"../types","module":199,"outDir":"./"},"fileIdsList":[[2]],"referencedMap":[[2,1]],"exportedModulesMap":[],"semanticDiagnosticsPerFile":[1,2],"latestChangedDtsFile":"../types/index.d.ts"},"version":"FakeTSVersion"}

//// [/Users/name/projects/web/dist/tsconfig.tsbuildinfo.readable.baseline.txt]
{
"program": {
"fileNames": [
"../../../../../a/lib/lib.esnext.full.d.ts",
"../index.ts"
],
"fileNamesList": [
[
"../index.ts"
]
],
"fileInfos": {
"../../../../../a/lib/lib.esnext.full.d.ts": {
"version": "-7698705165-/// <reference no-default-lib=\"true\"/>\ninterface Boolean {}\ninterface Function {}\ninterface CallableFunction {}\ninterface NewableFunction {}\ninterface IArguments {}\ninterface Number { toExponential: any; }\ninterface Object {}\ninterface RegExp {}\ninterface String { charAt: any; }\ninterface Array<T> { length: number; [n: number]: T; }",
"signature": "-7698705165-/// <reference no-default-lib=\"true\"/>\ninterface Boolean {}\ninterface Function {}\ninterface CallableFunction {}\ninterface NewableFunction {}\ninterface IArguments {}\ninterface Number { toExponential: any; }\ninterface Object {}\ninterface RegExp {}\ninterface String { charAt: any; }\ninterface Array<T> { length: number; [n: number]: T; }",
"affectsGlobalScope": true,
"impliedFormat": "commonjs"
},
"../index.ts": {
"version": "14361483761-import * as me from \"@this/package\";\nme.thing();\nexport function thing(): void {}\n",
"signature": "-2724770439-export declare function thing(): void;\n",
"impliedFormat": "esnext"
}
},
"options": {
"composite": true,
"declarationDir": "../types",
"module": 199,
"outDir": "./"
},
"referencedMap": {
"../index.ts": [
"../index.ts"
]
},
"exportedModulesMap": {},
"semanticDiagnosticsPerFile": [
"../../../../../a/lib/lib.esnext.full.d.ts",
"../index.ts"
],
"latestChangedDtsFile": "../types/index.d.ts"
},
"version": "FakeTSVersion",
"size": 974
}

@@ -0,0 +1,141 @@
Input::
//// [/Users/name/projects/web/src/bin.ts]
import { foo } from "yargs";

//// [/Users/name/projects/web/node_modules/@types/yargs/index.d.ts]
export function foo(): void;

//// [/Users/name/projects/web/node_modules/@types/yargs/index.d.mts]
export function foo(): void;

//// [/Users/name/projects/web/node_modules/@types/yargs/package.json]
{"name":"yargs","version":"17.0.12","exports":{".":{"types":{"import":"./index.d.mts","default":"./index.d.ts"}}}}

//// [/Users/name/projects/web/tsconfig.json]
{"compilerOptions":{"moduleResolution":"nodenext","forceConsistentCasingInFileNames":true,"traceResolution":true}}

//// [/a/lib/lib.d.ts]
/// <reference no-default-lib="true"/>
interface Boolean {}
interface Function {}
interface CallableFunction {}
interface NewableFunction {}
interface IArguments {}
interface Number { toExponential: any; }
interface Object {}
interface RegExp {}
interface String { charAt: any; }
interface Array<T> { length: number; [n: number]: T; }


/a/lib/tsc.js --w --explainFiles
Output::
>> Screen clear
[12:00:35 AM] Starting compilation in watch mode...

File '/users/name/projects/web/src/package.json' does not exist.
File '/users/name/projects/web/package.json' does not exist.
File '/users/name/projects/package.json' does not exist.
File '/users/name/package.json' does not exist.
File '/users/package.json' does not exist.
File '/package.json' does not exist.
======== Resolving module 'yargs' from '/Users/name/projects/web/src/bin.ts'. ========
Explicitly specified module resolution kind: 'NodeNext'.
File '/users/name/projects/web/src/package.json' does not exist according to earlier cached lookups.
File '/users/name/projects/web/package.json' does not exist according to earlier cached lookups.
File '/users/name/projects/package.json' does not exist according to earlier cached lookups.
File '/users/name/package.json' does not exist according to earlier cached lookups.
File '/users/package.json' does not exist according to earlier cached lookups.
File '/package.json' does not exist according to earlier cached lookups.
Loading module 'yargs' from 'node_modules' folder, target file type 'TypeScript'.
Directory '/Users/name/projects/web/src/node_modules' does not exist, skipping all lookups in it.
File '/Users/name/projects/web/node_modules/yargs.ts' does not exist.
File '/Users/name/projects/web/node_modules/yargs.tsx' does not exist.
File '/Users/name/projects/web/node_modules/yargs.d.ts' does not exist.
Found 'package.json' at '/Users/name/projects/web/node_modules/@types/yargs/package.json'.
'package.json' does not have a 'typesVersions' field.
File '/Users/name/projects/web/node_modules/@types/yargs/index.d.ts' exist - use it as a name resolution result.
Resolving real path for '/Users/name/projects/web/node_modules/@types/yargs/index.d.ts', result '/Users/name/projects/web/node_modules/@types/yargs/index.d.ts'.
======== Module name 'yargs' was successfully resolved to '/Users/name/projects/web/node_modules/@types/yargs/index.d.ts' with Package ID 'yargs/index.d.ts@17.0.12'. ========
File '/users/name/projects/web/node_modules/@types/yargs/package.json' exists according to earlier cached lookups.
======== Resolving type reference directive 'yargs', containing file '/Users/name/projects/web/__inferred type names__.ts', root directory '/Users/name/projects/web/node_modules/@types'. ========
Resolving with primary search path '/Users/name/projects/web/node_modules/@types'.
File '/Users/name/projects/web/node_modules/@types/yargs/package.json' exists according to earlier cached lookups.
'package.json' does not have a 'typings' field.
'package.json' does not have a 'types' field.
File '/Users/name/projects/web/node_modules/@types/yargs/index.d.ts' exist - use it as a name resolution result.
Resolving real path for '/Users/name/projects/web/node_modules/@types/yargs/index.d.ts', result '/Users/name/projects/web/node_modules/@types/yargs/index.d.ts'.
======== Type reference directive 'yargs' was successfully resolved to '/Users/name/projects/web/node_modules/@types/yargs/index.d.ts' with Package ID 'yargs/index.d.ts@17.0.12', primary: true. ========
File '/a/lib/package.json' does not exist.
File '/a/package.json' does not exist.
File '/package.json' does not exist according to earlier cached lookups.
../../../../a/lib/lib.d.ts
Default library for target 'es3'
node_modules/@types/yargs/index.d.ts
Imported via "yargs" from file 'src/bin.ts' with packageId 'yargs/index.d.ts@17.0.12'
Entry point for implicit type library 'yargs' with packageId 'yargs/index.d.ts@17.0.12'
File is CommonJS module because 'node_modules/@types/yargs/package.json' does not have field "type"
src/bin.ts
Matched by default include pattern '**/*'
File is CommonJS module because 'package.json' was not found
[12:00:38 AM] Found 0 errors. Watching for file changes.



Program root files: ["/Users/name/projects/web/src/bin.ts"]
Program options: {"moduleResolution":99,"forceConsistentCasingInFileNames":true,"traceResolution":true,"watch":true,"explainFiles":true,"configFilePath":"/Users/name/projects/web/tsconfig.json"}
Program structureReused: Not
Program files::
/a/lib/lib.d.ts
/Users/name/projects/web/node_modules/@types/yargs/index.d.ts
/Users/name/projects/web/src/bin.ts

Semantic diagnostics in builder refreshed for::
/a/lib/lib.d.ts
/Users/name/projects/web/node_modules/@types/yargs/index.d.ts
/Users/name/projects/web/src/bin.ts

Shape signatures in builder refreshed for::
/a/lib/lib.d.ts (used version)
/users/name/projects/web/node_modules/@types/yargs/index.d.ts (used version)
/users/name/projects/web/src/bin.ts (used version)

WatchedFiles::
/users/name/projects/web/tsconfig.json:
{"fileName":"/Users/name/projects/web/tsconfig.json","pollingInterval":250}
/users/name/projects/web/src/bin.ts:
{"fileName":"/Users/name/projects/web/src/bin.ts","pollingInterval":250}
/users/name/projects/web/node_modules/@types/yargs/index.d.ts:
{"fileName":"/Users/name/projects/web/node_modules/@types/yargs/index.d.ts","pollingInterval":250}
/a/lib/lib.d.ts:
{"fileName":"/a/lib/lib.d.ts","pollingInterval":250}
/users/name/projects/web/node_modules/@types/yargs/package.json:
{"fileName":"/Users/name/projects/web/node_modules/@types/yargs/package.json","pollingInterval":250}
/users/name/projects/web/src/package.json:
{"fileName":"/Users/name/projects/web/src/package.json","pollingInterval":250}
/users/name/projects/web/package.json:
{"fileName":"/Users/name/projects/web/package.json","pollingInterval":250}
/users/name/projects/package.json:
{"fileName":"/Users/name/projects/package.json","pollingInterval":250}

FsWatches::
/users/name/projects/web:
{"directoryName":"/Users/name/projects/web"}

FsWatchesRecursive::
/users/name/projects/web/src:
{"directoryName":"/users/name/projects/web/src"}
/users/name/projects/web/node_modules:
{"directoryName":"/Users/name/projects/web/node_modules"}
/users/name/projects/web/node_modules/@types:
{"directoryName":"/Users/name/projects/web/node_modules/@types"}
/users/name/projects/web:
{"directoryName":"/users/name/projects/web"}

exitCode:: ExitStatus.undefined

//// [/Users/name/projects/web/src/bin.js]
"use strict";
exports.__esModule = true;