Skip to content

[Bug]: useCaseSensitiveFileNames is not provided to ServiceHost, leading to issues in case-sensitive OSes #3665

@ferdaber

Description

@ferdaber

Version

latest

Steps to reproduce

  1. This needs to be run in a case-sensitive OS like WSL, Linux, or MacOS
  2. Clone my repo here: https://github.com/ferdaber/ts-jest-case-sensitivity
  3. Ensure that the cloned repo has at least one uppercase letter in its absolute file path
  4. Run npm install, which will copy over some mock packages into node_modules
  5. Run npx jest, and also run npx tsc
  6. Verify that npx jest fails via a ts-jest diagnostic error, and npx tsc does not.

Expected behavior

There should be no error via npx jest since it should mirror how TSC typechecks

Actual behavior

The TS language service created by ts-jest was unable to resolve a specific

Debug log

{"context":{"call":null,"logLevel":10,"namespace":"ts:serviceHost","package":"ts-jest","version":"28.0.5"},"message":"readFile","sequence":173,"time":"2022-07-01T20:18:52.201Z"}
{"context":{"cacheHit":false,"logLevel":10,"namespace":"ts-compiler","normalizedFileName":"/home/fbudhidharma/dev/Case-Sensitive-resolution-issue/node_modules/typescript/lib/lib.scripthost.d.ts","package":"ts-jest","version":"28.0.5"},"message":"getScriptSnapshot(): cache miss","sequence":174,"time":"2022-07-01T20:18:52.201Z"}
{"context":{"call":null,"logLevel":10,"namespace":"ts:serviceHost","package":"ts-jest","version":"28.0.5"},"message":"readFile","sequence":175,"time":"2022-07-01T20:18:52.201Z"}
{"context":{"cacheHit":false,"logLevel":10,"namespace":"ts-compiler","normalizedFileName":"/home/fbudhidharma/dev/Case-Sensitive-resolution-issue/node_modules/typescript/lib/lib.dom.iterable.d.ts","package":"ts-jest","version":"28.0.5"},"message":"getScriptSnapshot(): cache miss","sequence":176,"time":"2022-07-01T20:18:52.203Z"}
{"context":{"call":null,"logLevel":10,"namespace":"ts:serviceHost","package":"ts-jest","version":"28.0.5"},"message":"readFile","sequence":177,"time":"2022-07-01T20:18:52.203Z"}
{"context":{"call":null,"logLevel":20,"namespace":"hoist-jest","package":"ts-jest","version":"28.0.5"},"message":"visitSourceFileNode(): hoist jest","sequence":178,"time":"2022-07-01T20:18:52.464Z"}
{"context":{"fileName":"/home/fbudhidharma/dev/Case-Sensitive-resolution-issue/src/index.test.ts","logLevel":20,"namespace":"ts-compiler","package":"ts-jest","version":"28.0.5"},"message":"_doTypeChecking(): computing diagnostics using language service","sequence":179,"time":"2022-07-01T20:18:52.484Z"}
{"context":{"diagnosticCodes":[2688],"diagnosticText":"\u001b[96msrc/index.test.ts\u001b[0m:\u001b[93m1\u001b[0m:\u001b[93m23\u001b[0m - \u001b[91merror\u001b[0m\u001b[90m TS2688: \u001b[0mCannot find type definition file for 'package-with-exports/globaltypes'.\n\n\u001b[7m1\u001b[0m /// <reference types=\"package-with-exports/globaltypes\" />\n\u001b[7m \u001b[0m \u001b[91m                      ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~\u001b[0m\n","logLevel":20,"namespace":"TSError","package":"ts-jest","version":"28.0.5"},"message":"created new TSError","sequence":180,"time":"2022-07-01T20:18:52.485Z"}
{"context":{"logLevel":20,"namespace":"ts-jest-transformer","package":"ts-jest","version":"28.0.5"},"message":"created new transformer","sequence":181,"time":"2022-07-01T20:18:52.491Z"}

Additional context

I was only able to successfully replicate this in a simple project via a type reference into a package that is using the new exports package.json field, and with a node resolution of nodenext, but in my team's more complicated set up, the same error appears using nodenext but via a simple import { Value } from 'package' where package is only using the legacy main/types package.json fields.

After tracing through the TS compilation, it looks like the issue comes from how some lookups (depending on which code path within TSC it goes through) will attempt to call getCanonicalFileName to read files. This causes failures (again, depending on the code path which was very difficult to reliably replicate due to multiple layers of caching).

getCanonicalFileName relies on useCaseSensitiveFileNames to be passed in to the ServiceHost instance when creating the TS service host. Currently it is not being passed in so TSC will default to lower-casing all filepaths. This is what causes the typechecking errors because TSC ends up being unable to properly read files.

I was able to verify in my own code (and in the replication repo) that passing in the useCaseSensitiveFileNames method resolved all issues:

const fs = require('fs'), process = require('process');
const isCaseSensitive =
  process.platform === 'win32' || process.platform === 'win64' 
    ? false
    : fs.existsSync(__dirname) !== fs.existsSync(__dirname.toUpperCase())

Environment

System:
    OS: Linux 5.10 Ubuntu 20.04.4 LTS (Focal Fossa)
    CPU: (8) x64 Intel(R) Core(TM) i7-8565U CPU @ 1.80GHz
  Binaries:
    Node: 14.19.0 - ~/.nvm/versions/node/v14.19.0/bin/node
    Yarn: 1.22.5 - /mnt/c/Program Files (x86)/Yarn/bin/yarn
    npm: 6.14.16 - ~/.nvm/versions/node/v14.19.0/bin/npm
  npmPackages:
    jest: ^28.1.2 => 28.1.2

Metadata

Metadata

Assignees

No one assigned

    Labels

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions