Skip to content

Commit

Permalink
Handle more places where package direcroy is converted to canonical f…
Browse files Browse the repository at this point in the history
…ile path (#50740)

* Add test for node16 resolution with package json lookup making casing incorrect

* Handle more places where package direcroy is converted to canonical file path
  • Loading branch information
sheetalkamat committed Sep 12, 2022
1 parent f5f2923 commit 6b890f9
Show file tree
Hide file tree
Showing 13 changed files with 219 additions and 68 deletions.
2 changes: 1 addition & 1 deletion src/compiler/checker.ts
Expand Up @@ -3630,7 +3630,7 @@ namespace ts {
if (ext === Extension.Ts || ext === Extension.Js || ext === Extension.Tsx || ext === Extension.Jsx) {
const scope = currentSourceFile.packageJsonScope;
const targetExt = ext === Extension.Ts ? Extension.Mts : ext === Extension.Js ? Extension.Mjs : undefined;
if (scope && !scope.packageJsonContent.type) {
if (scope && !scope.contents.packageJsonContent.type) {
if (targetExt) {
diagnosticDetails = chainDiagnosticMessages(
/*details*/ undefined,
Expand Down
82 changes: 43 additions & 39 deletions src/compiler/moduleNameResolver.ts

Large diffs are not rendered by default.

2 changes: 1 addition & 1 deletion src/compiler/moduleSpecifiers.ts
Expand Up @@ -807,7 +807,7 @@ namespace ts.moduleSpecifiers {
let maybeBlockedByTypesVersions = false;
const cachedPackageJson = host.getPackageJsonInfoCache?.()?.getPackageJsonInfo(packageJsonPath);
if (typeof cachedPackageJson === "object" || cachedPackageJson === undefined && host.fileExists(packageJsonPath)) {
const packageJsonContent = cachedPackageJson?.packageJsonContent || JSON.parse(host.readFile!(packageJsonPath)!);
const packageJsonContent = cachedPackageJson?.contents.packageJsonContent || JSON.parse(host.readFile!(packageJsonPath)!);
const importMode = overrideMode || importingSourceFile.impliedNodeFormat;
if (getEmitModuleResolutionKind(options) === ModuleResolutionKind.Node16 || getEmitModuleResolutionKind(options) === ModuleResolutionKind.NodeNext) {
const conditions = ["node", importMode === ModuleKind.ESNext ? "import" : "require", "types"];
Expand Down
6 changes: 3 additions & 3 deletions src/compiler/program.ts
Expand Up @@ -849,7 +849,7 @@ namespace ts {

/*@internal*/
export function getImpliedNodeFormatForFileWorker(
fileName: Path,
fileName: string,
packageJsonInfoCache: PackageJsonInfoCache | undefined,
host: ModuleResolutionHost,
options: CompilerOptions,
Expand All @@ -870,7 +870,7 @@ namespace ts {
state.failedLookupLocations = packageJsonLocations;
state.affectingLocations = packageJsonLocations;
const packageJsonScope = getPackageScopeForPath(fileName, state);
const impliedNodeFormat = packageJsonScope?.packageJsonContent.type === "module" ? ModuleKind.ESNext : ModuleKind.CommonJS;
const impliedNodeFormat = packageJsonScope?.contents.packageJsonContent.type === "module" ? ModuleKind.ESNext : ModuleKind.CommonJS;
return { impliedNodeFormat, packageJsonLocations, packageJsonScope };
}
}
Expand Down Expand Up @@ -2834,7 +2834,7 @@ namespace ts {
// It's a _little odd_ that we can't set `impliedNodeFormat` until the program step - but it's the first and only time we have a resolution cache
// and a freshly made source file node on hand at the same time, and we need both to set the field. Persisting the resolution cache all the way
// to the check and emit steps would be bad - so we much prefer detecting and storing the format information on the source file node upfront.
const result = getImpliedNodeFormatForFileWorker(toPath(fileName), moduleResolutionCache?.getPackageJsonInfoCache(), host, options);
const result = getImpliedNodeFormatForFileWorker(getNormalizedAbsolutePath(fileName, currentDirectory), moduleResolutionCache?.getPackageJsonInfoCache(), host, options);
const languageVersion = getEmitScriptTarget(options);
const setExternalModuleIndicator = getSetExternalModuleIndicator(options);
return typeof result === "object" ?
Expand Down
2 changes: 1 addition & 1 deletion src/compiler/watch.ts
Expand Up @@ -262,7 +262,7 @@ namespace ts {
if (file.packageJsonScope) {
(result ??= []).push(chainDiagnosticMessages(
/*details*/ undefined,
file.packageJsonScope.packageJsonContent.type ?
file.packageJsonScope.contents.packageJsonContent.type ?
Diagnostics.File_is_CommonJS_module_because_0_has_field_type_whose_value_is_not_module :
Diagnostics.File_is_CommonJS_module_because_0_does_not_have_field_type,
toFileName(last(file.packageJsonLocations!), fileNameConvertor)
Expand Down
2 changes: 1 addition & 1 deletion src/server/session.ts
Expand Up @@ -1378,7 +1378,7 @@ namespace ts.server {
const packageDirectory = fileName.substring(0, nodeModulesPathParts.packageRootIndex);
const packageJsonCache = project.getModuleResolutionCache()?.getPackageJsonInfoCache();
const compilerOptions = project.getCompilationSettings();
const packageJson = getPackageScopeForPath(project.toPath(packageDirectory + "/package.json"), getTemporaryModuleResolutionState(packageJsonCache, project, compilerOptions));
const packageJson = getPackageScopeForPath(getNormalizedAbsolutePath(packageDirectory + "/package.json", project.getCurrentDirectory()), getTemporaryModuleResolutionState(packageJsonCache, project, compilerOptions));
if (!packageJson) return undefined;
// Use fake options instead of actual compiler options to avoid following export map if the project uses node16 or nodenext -
// Mapping from an export map entry across packages is out of scope for now. Returned entrypoints will only be what can be
Expand Down
Expand Up @@ -326,5 +326,36 @@ a;b;
}, { currentDirectory: "/Users/name/projects/web" }),
changes: emptyArray,
});


verifyTscWatch({
scenario: "forceConsistentCasingInFileNames",
subScenario: "package json is looked up for file",
commandLineArgs: ["-w", "--explainFiles"],
sys: () => createWatchedSystem({
"/Users/name/projects/lib-boilerplate/package.json": JSON.stringify({
name: "lib-boilerplate",
version: "0.0.2",
type: "module",
exports: "./src/index.ts",
}),
"/Users/name/projects/lib-boilerplate/src/index.ts": Utils.dedent`
export function thing(): void {}
`,
"/Users/name/projects/lib-boilerplate/test/basic.spec.ts": Utils.dedent`
import { thing } from 'lib-boilerplate'
`,
"/Users/name/projects/lib-boilerplate/tsconfig.json": JSON.stringify({
compilerOptions: {
module: "node16",
target: "es2021",
forceConsistentCasingInFileNames: true,
traceResolution: true,
}
}),
"/a/lib/lib.es2021.full.d.ts": libFile.content,
}, { currentDirectory: "/Users/name/projects/lib-boilerplate" }),
changes: emptyArray,
});
});
}
Expand Up @@ -25,15 +25,15 @@
"'package.json' does not have a 'typings' field.",
"'package.json' has 'types' field 'index.d.ts' that references 'tests/cases/compiler/node_modules/@types/react/index.d.ts'.",
"File 'tests/cases/compiler/node_modules/@types/react/index.d.ts' exist - use it as a name resolution result.",
"======== Module name './' was successfully resolved to 'tests/cases/compiler/node_modules/@types/react/index.d.ts' with Package ID '@types/react/index.d.ts@0.0.1'. ========",
"======== Module name './' was successfully resolved to 'tests/cases/compiler/node_modules/@types/react/index.d.ts' with Package ID '@types/react/ndex.d.ts@0.0.1'. ========",
"File 'tests/cases/compiler/node_modules/@types/react/package.json' exists according to earlier cached lookups.",
"======== Resolving module './' from 'tests/cases/compiler/node_modules/@types/react/jsx-runtime.d.ts'. ========",
"Resolution for module './' was found in cache from location 'tests/cases/compiler/node_modules/@types/react'.",
"======== Module name './' was successfully resolved to 'tests/cases/compiler/node_modules/@types/react/index.d.ts' with Package ID '@types/react/index.d.ts@0.0.1'. ========",
"======== Module name './' was successfully resolved to 'tests/cases/compiler/node_modules/@types/react/index.d.ts' with Package ID '@types/react/ndex.d.ts@0.0.1'. ========",
"File 'tests/cases/compiler/node_modules/@types/react/package.json' exists according to earlier cached lookups.",
"======== Resolving module './' from 'tests/cases/compiler/node_modules/@types/react/jsx-dev-runtime.d.ts'. ========",
"Resolution for module './' was found in cache from location 'tests/cases/compiler/node_modules/@types/react'.",
"======== Module name './' was successfully resolved to 'tests/cases/compiler/node_modules/@types/react/index.d.ts' with Package ID '@types/react/index.d.ts@0.0.1'. ========",
"======== Module name './' was successfully resolved to 'tests/cases/compiler/node_modules/@types/react/index.d.ts' with Package ID '@types/react/ndex.d.ts@0.0.1'. ========",
"File 'package.json' does not exist.",
"File '/package.json' does not exist according to earlier cached lookups.",
"File 'package.json' does not exist according to earlier cached lookups.",
Expand Down
Expand Up @@ -19,15 +19,15 @@
"'package.json' does not have a 'typings' field.",
"'package.json' has 'types' field 'index.d.ts' that references 'tests/cases/compiler/node_modules/@types/react/index.d.ts'.",
"File 'tests/cases/compiler/node_modules/@types/react/index.d.ts' exist - use it as a name resolution result.",
"======== Module name './' was successfully resolved to 'tests/cases/compiler/node_modules/@types/react/index.d.ts' with Package ID '@types/react/index.d.ts@0.0.1'. ========",
"======== Module name './' was successfully resolved to 'tests/cases/compiler/node_modules/@types/react/index.d.ts' with Package ID '@types/react/ndex.d.ts@0.0.1'. ========",
"File 'tests/cases/compiler/node_modules/@types/react/package.json' exists according to earlier cached lookups.",
"======== Resolving module './' from 'tests/cases/compiler/node_modules/@types/react/jsx-runtime.d.ts'. ========",
"Resolution for module './' was found in cache from location 'tests/cases/compiler/node_modules/@types/react'.",
"======== Module name './' was successfully resolved to 'tests/cases/compiler/node_modules/@types/react/index.d.ts' with Package ID '@types/react/index.d.ts@0.0.1'. ========",
"======== Module name './' was successfully resolved to 'tests/cases/compiler/node_modules/@types/react/index.d.ts' with Package ID '@types/react/ndex.d.ts@0.0.1'. ========",
"File 'tests/cases/compiler/node_modules/@types/react/package.json' exists according to earlier cached lookups.",
"======== Resolving module './' from 'tests/cases/compiler/node_modules/@types/react/jsx-dev-runtime.d.ts'. ========",
"Resolution for module './' was found in cache from location 'tests/cases/compiler/node_modules/@types/react'.",
"======== Module name './' was successfully resolved to 'tests/cases/compiler/node_modules/@types/react/index.d.ts' with Package ID '@types/react/index.d.ts@0.0.1'. ========",
"======== Module name './' was successfully resolved to 'tests/cases/compiler/node_modules/@types/react/index.d.ts' with Package ID '@types/react/ndex.d.ts@0.0.1'. ========",
"File 'package.json' does not exist.",
"File '/package.json' does not exist.",
"File 'package.json' does not exist according to earlier cached lookups.",
Expand Down
@@ -0,0 +1,116 @@
Input::
//// [/Users/name/projects/lib-boilerplate/package.json]
{"name":"lib-boilerplate","version":"0.0.2","type":"module","exports":"./src/index.ts"}

//// [/Users/name/projects/lib-boilerplate/src/index.ts]
export function thing(): void {}


//// [/Users/name/projects/lib-boilerplate/test/basic.spec.ts]
import { thing } from 'lib-boilerplate'


//// [/Users/name/projects/lib-boilerplate/tsconfig.json]
{"compilerOptions":{"module":"node16","target":"es2021","forceConsistentCasingInFileNames":true,"traceResolution":true}}

//// [/a/lib/lib.es2021.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:29 AM] Starting compilation in watch mode...

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



Program root files: ["/Users/name/projects/lib-boilerplate/src/index.ts","/Users/name/projects/lib-boilerplate/test/basic.spec.ts"]
Program options: {"module":100,"target":8,"forceConsistentCasingInFileNames":true,"traceResolution":true,"watch":true,"explainFiles":true,"configFilePath":"/Users/name/projects/lib-boilerplate/tsconfig.json"}
Program structureReused: Not
Program files::
/a/lib/lib.es2021.full.d.ts
/Users/name/projects/lib-boilerplate/src/index.ts
/Users/name/projects/lib-boilerplate/test/basic.spec.ts

Semantic diagnostics in builder refreshed for::
/a/lib/lib.es2021.full.d.ts
/Users/name/projects/lib-boilerplate/src/index.ts
/Users/name/projects/lib-boilerplate/test/basic.spec.ts

Shape signatures in builder refreshed for::
/a/lib/lib.es2021.full.d.ts (used version)
/users/name/projects/lib-boilerplate/src/index.ts (used version)
/users/name/projects/lib-boilerplate/test/basic.spec.ts (used version)

PolledWatches::
/users/name/projects/lib-boilerplate/src/package.json:
{"pollingInterval":2000}
/users/name/projects/lib-boilerplate/test/package.json:
{"pollingInterval":2000}
/users/name/projects/lib-boilerplate/node_modules/@types:
{"pollingInterval":500}

FsWatches::
/users/name/projects/lib-boilerplate/tsconfig.json:
{}
/users/name/projects/lib-boilerplate/src/index.ts:
{}
/users/name/projects/lib-boilerplate/test/basic.spec.ts:
{}
/a/lib/lib.es2021.full.d.ts:
{}
/users/name/projects/lib-boilerplate/package.json:
{}

FsWatchesRecursive::
/users/name/projects/lib-boilerplate/test:
{}
/users/name/projects/lib-boilerplate:
{}

exitCode:: ExitStatus.undefined

//// [/Users/name/projects/lib-boilerplate/src/index.js]
export function thing() { }


//// [/Users/name/projects/lib-boilerplate/test/basic.spec.js]
export {};


Expand Up @@ -30,11 +30,11 @@ Output::
>> Screen clear
[12:00:23 AM] Starting compilation in watch mode...

Found 'package.json' at '/users/name/projects/web/package.json'.
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/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'. ========
Expand Down

0 comments on commit 6b890f9

Please sign in to comment.