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) (#50747)

* 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 ea348f6 commit bb8cf90
Show file tree
Hide file tree
Showing 13 changed files with 220 additions and 69 deletions.
2 changes: 1 addition & 1 deletion src/compiler/checker.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3627,7 +3627,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
Original file line number Diff line number Diff line change
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
Original file line number Diff line number Diff line change
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 @@ -2828,7 +2828,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
Original file line number Diff line number Diff line change
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
Original file line number Diff line number Diff line change
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
Original file line number Diff line number Diff line change
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,
});
});
}
Original file line number Diff line number Diff line change
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[email protected]'. ========",
"======== Module name './' was successfully resolved to 'tests/cases/compiler/node_modules/@types/react/index.d.ts' with Package ID '@types/react/ndex[email protected]'. ========",
"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[email protected]'. ========",
"======== Module name './' was successfully resolved to 'tests/cases/compiler/node_modules/@types/react/index.d.ts' with Package ID '@types/react/ndex[email protected]'. ========",
"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[email protected]'. ========",
"======== Module name './' was successfully resolved to 'tests/cases/compiler/node_modules/@types/react/index.d.ts' with Package ID '@types/react/ndex[email protected]'. ========",
"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
Original file line number Diff line number Diff line change
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[email protected]'. ========",
"======== Module name './' was successfully resolved to 'tests/cases/compiler/node_modules/@types/react/index.d.ts' with Package ID '@types/react/ndex[email protected]'. ========",
"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[email protected]'. ========",
"======== Module name './' was successfully resolved to 'tests/cases/compiler/node_modules/@types/react/index.d.ts' with Package ID '@types/react/ndex[email protected]'. ========",
"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[email protected]'. ========",
"======== Module name './' was successfully resolved to 'tests/cases/compiler/node_modules/@types/react/index.d.ts' with Package ID '@types/react/ndex[email protected]'. ========",
"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
Original file line number Diff line number Diff line change
@@ -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/[email protected]'. ========
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/[email protected]'
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)

WatchedFiles::
/users/name/projects/lib-boilerplate/tsconfig.json:
{"fileName":"/Users/name/projects/lib-boilerplate/tsconfig.json","pollingInterval":250}
/users/name/projects/lib-boilerplate/src/index.ts:
{"fileName":"/Users/name/projects/lib-boilerplate/src/index.ts","pollingInterval":250}
/users/name/projects/lib-boilerplate/test/basic.spec.ts:
{"fileName":"/Users/name/projects/lib-boilerplate/test/basic.spec.ts","pollingInterval":250}
/a/lib/lib.es2021.full.d.ts:
{"fileName":"/a/lib/lib.es2021.full.d.ts","pollingInterval":250}
/users/name/projects/lib-boilerplate/package.json:
{"fileName":"/Users/name/projects/lib-boilerplate/package.json","pollingInterval":250}
/users/name/projects/lib-boilerplate/src/package.json:
{"fileName":"/Users/name/projects/lib-boilerplate/src/package.json","pollingInterval":250}
/users/name/projects/lib-boilerplate/test/package.json:
{"fileName":"/Users/name/projects/lib-boilerplate/test/package.json","pollingInterval":250}
/users/name/projects/lib-boilerplate/node_modules/@types:
{"fileName":"/Users/name/projects/lib-boilerplate/node_modules/@types","pollingInterval":500}

FsWatches::

FsWatchesRecursive::
/users/name/projects/lib-boilerplate/test:
{"directoryName":"/Users/name/projects/lib-boilerplate/test"}
/users/name/projects/lib-boilerplate:
{"directoryName":"/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 {};


Original file line number Diff line number Diff line change
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
Loading

0 comments on commit bb8cf90

Please sign in to comment.