From 06aae9839d7160c2aff8c3f14b9f1f2d3e76c2d4 Mon Sep 17 00:00:00 2001 From: TypeScript Bot Date: Thu, 28 Mar 2024 16:36:48 -0700 Subject: [PATCH] =?UTF-8?q?=F0=9F=A4=96=20Pick=20PR=20#57973=20(Compare=20?= =?UTF-8?q?package.json=20paths=20with=20cor...)=20into=20release-5.4=20(#?= =?UTF-8?q?57976)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-authored-by: Jake Bailey <5341706+jakebailey@users.noreply.github.com> --- src/compiler/moduleSpecifiers.ts | 9 +- .../unittests/tsc/declarationEmit.ts | 94 +++++++ ...ing-Windows-paths-and-uppercase-letters.js | 229 ++++++++++++++++++ 3 files changed, 331 insertions(+), 1 deletion(-) create mode 100644 tests/baselines/reference/tsc/declarationEmit/when-using-Windows-paths-and-uppercase-letters.js diff --git a/src/compiler/moduleSpecifiers.ts b/src/compiler/moduleSpecifiers.ts index fb2a6cb1bb7f3..40261c7e8e35f 100644 --- a/src/compiler/moduleSpecifiers.ts +++ b/src/compiler/moduleSpecifiers.ts @@ -550,7 +550,8 @@ function getLocalModuleSpecifier(moduleFileName: string, info: Info, compilerOpt const nearestTargetPackageJson = getNearestAncestorDirectoryWithPackageJson(host, getDirectoryPath(modulePath)); const nearestSourcePackageJson = getNearestAncestorDirectoryWithPackageJson(host, sourceDirectory); - if (nearestSourcePackageJson !== nearestTargetPackageJson) { + const ignoreCase = !hostUsesCaseSensitiveFileNames(host); + if (!packageJsonPathsAreEqual(nearestTargetPackageJson, nearestSourcePackageJson, ignoreCase)) { // 2. The importing and imported files are part of different packages. // // packages/a/ @@ -570,6 +571,12 @@ function getLocalModuleSpecifier(moduleFileName: string, info: Info, compilerOpt return isPathRelativeToParent(maybeNonRelative) || countPathComponents(relativePath) < countPathComponents(maybeNonRelative) ? relativePath : maybeNonRelative; } +function packageJsonPathsAreEqual(a: string | undefined, b: string | undefined, ignoreCase?: boolean) { + if (a === b) return true; + if (a === undefined || b === undefined) return false; + return comparePaths(a, b, ignoreCase) === Comparison.EqualTo; +} + /** @internal */ export function countPathComponents(path: string): number { let count = 0; diff --git a/src/testRunner/unittests/tsc/declarationEmit.ts b/src/testRunner/unittests/tsc/declarationEmit.ts index 9b531010e6dcb..6655fcc0249ac 100644 --- a/src/testRunner/unittests/tsc/declarationEmit.ts +++ b/src/testRunner/unittests/tsc/declarationEmit.ts @@ -258,4 +258,98 @@ ${pluginOneAction()}`, ], changeCaseFileTestPath: str => str.includes("/pkg1"), }); + + verifyTscWatch({ + scenario: "declarationEmit", + subScenario: "when using Windows paths and uppercase letters", + sys: () => + createWatchedSystem([ + { + path: `D:\\Work\\pkg1\\package.json`, + content: jsonToReadableText({ + name: "ts-specifier-bug", + version: "1.0.0", + description: "", + main: "index.js", + scripts: { + build: "tsc", + }, + keywords: [], + author: "", + license: "ISC", + dependencies: { + typescript: "5.4.0-dev.20231222", + }, + }), + }, + { + path: `D:\\Work\\pkg1\\tsconfig.json`, + content: jsonToReadableText({ + compilerOptions: { + module: "commonjs", + declaration: true, + removeComments: true, + emitDecoratorMetadata: true, + experimentalDecorators: true, + strictPropertyInitialization: false, + allowSyntheticDefaultImports: true, + target: "es2017", + sourceMap: true, + esModuleInterop: true, + outDir: "./dist", + baseUrl: "./", + skipLibCheck: true, + strictNullChecks: false, + noImplicitAny: false, + strictBindCallApply: false, + forceConsistentCasingInFileNames: false, + noFallthroughCasesInSwitch: false, + moduleResolution: "node", + resolveJsonModule: true, + }, + include: ["src"], + }), + }, + { + path: `D:\\Work\\pkg1\\src\\main.ts`, + content: Utils.dedent` + import { PartialType } from './utils'; + + class Common {} + + export class Sub extends PartialType(Common) { + id: string; + } + `, + }, + { + path: `D:\\Work\\pkg1\\src\\utils\\index.ts`, + content: Utils.dedent` + import { MyType, MyReturnType } from './type-helpers'; + + export function PartialType(classRef: MyType) { + abstract class PartialClassType { + constructor() {} + } + + return PartialClassType as MyReturnType; + } + `, + }, + { + path: `D:\\Work\\pkg1\\src\\utils\\type-helpers.ts`, + content: Utils.dedent` + export type MyReturnType = { + new (...args: any[]): any; + }; + + export interface MyType extends Function { + new (...args: any[]): T; + } + `, + }, + libFile, + ], { currentDirectory: "D:\\Work\\pkg1", windowsStyleRoot: "D:/" }), + commandLineArgs: ["-p", "D:\\Work\\pkg1", "--explainFiles"], + }); }); diff --git a/tests/baselines/reference/tsc/declarationEmit/when-using-Windows-paths-and-uppercase-letters.js b/tests/baselines/reference/tsc/declarationEmit/when-using-Windows-paths-and-uppercase-letters.js new file mode 100644 index 0000000000000..d8c7e26ff4268 --- /dev/null +++ b/tests/baselines/reference/tsc/declarationEmit/when-using-Windows-paths-and-uppercase-letters.js @@ -0,0 +1,229 @@ +currentDirectory:: D:\Work\pkg1 useCaseSensitiveFileNames: false +Input:: +//// [D:/Work/pkg1/package.json] +{ + "name": "ts-specifier-bug", + "version": "1.0.0", + "description": "", + "main": "index.js", + "scripts": { + "build": "tsc" + }, + "keywords": [], + "author": "", + "license": "ISC", + "dependencies": { + "typescript": "5.4.0-dev.20231222" + } +} + +//// [D:/Work/pkg1/tsconfig.json] +{ + "compilerOptions": { + "module": "commonjs", + "declaration": true, + "removeComments": true, + "emitDecoratorMetadata": true, + "experimentalDecorators": true, + "strictPropertyInitialization": false, + "allowSyntheticDefaultImports": true, + "target": "es2017", + "sourceMap": true, + "esModuleInterop": true, + "outDir": "./dist", + "baseUrl": "./", + "skipLibCheck": true, + "strictNullChecks": false, + "noImplicitAny": false, + "strictBindCallApply": false, + "forceConsistentCasingInFileNames": false, + "noFallthroughCasesInSwitch": false, + "moduleResolution": "node", + "resolveJsonModule": true + }, + "include": [ + "src" + ] +} + +//// [D:/Work/pkg1/src/main.ts] +import { PartialType } from './utils'; + +class Common {} + +export class Sub extends PartialType(Common) { + id: string; +} + + +//// [D:/Work/pkg1/src/utils/index.ts] +import { MyType, MyReturnType } from './type-helpers'; + +export function PartialType(classRef: MyType) { + abstract class PartialClassType { + constructor() {} + } + + return PartialClassType as MyReturnType; +} + + +//// [D:/Work/pkg1/src/utils/type-helpers.ts] +export type MyReturnType = { + new (...args: any[]): any; +}; + +export interface MyType extends Function { + new (...args: any[]): T; +} + + +//// [D:/a/lib/lib.d.ts] +/// +interface Boolean {} +interface Function {} +interface CallableFunction {} +interface NewableFunction {} +interface IArguments {} +interface Number { toExponential: any; } +interface Object {} +interface RegExp {} +interface String { charAt: any; } +interface Array { length: number; [n: number]: T; } + + +D:/a/lib/tsc.js -p D:\Work\pkg1 --explainFiles +Output:: +error TS2318: Cannot find global type 'Array'. + +error TS2318: Cannot find global type 'Boolean'. + +error TS2318: Cannot find global type 'Function'. + +error TS2318: Cannot find global type 'IArguments'. + +error TS2318: Cannot find global type 'Number'. + +error TS2318: Cannot find global type 'Object'. + +error TS2318: Cannot find global type 'RegExp'. + +error TS2318: Cannot find global type 'String'. + +error TS6053: File 'D:/a/lib/lib.es2017.full.d.ts' not found. + The file is in the program because: + Default library for target 'es2017' + + tsconfig.json:10:15 + 10 "target": "es2017", +    ~~~~~~~~ + File is default library for target specified here. + +src/utils/type-helpers.ts:5:42 - error TS4022: 'extends' clause of exported interface 'MyType' has or is using private name 'Function'. + +5 export interface MyType extends Function { +   ~~~~~~~~ + +src/utils/type-helpers.ts + Imported via './type-helpers' from file 'src/utils/index.ts' + Matched by include pattern 'src' in 'tsconfig.json' +src/utils/index.ts + Imported via './utils' from file 'src/main.ts' + Matched by include pattern 'src' in 'tsconfig.json' +src/main.ts + Matched by include pattern 'src' in 'tsconfig.json' + +Found 10 errors in the same file, starting at: src/utils/type-helpers.ts:5 + + + +//// [D:/Work/pkg1/dist/utils/type-helpers.js.map] +{"version":3,"file":"type-helpers.js","sourceRoot":"","sources":["../../src/utils/type-helpers.ts"],"names":[],"mappings":""} + +//// [D:/Work/pkg1/dist/utils/type-helpers.js] +"use strict"; +Object.defineProperty(exports, "__esModule", { value: true }); +//# sourceMappingURL=type-helpers.js.map + +//// [D:/Work/pkg1/dist/utils/index.js.map] +{"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/utils/index.ts"],"names":[],"mappings":";;;AAEA,SAAgB,WAAW,CAAI,QAAmB;IAC9C,MAAe,gBAAgB;QAC3B,gBAAe,CAAC;KACnB;IAED,OAAO,gBAAgC,CAAC;AAC5C,CAAC;AAND,kCAMC"} + +//// [D:/Work/pkg1/dist/utils/index.js] +"use strict"; +Object.defineProperty(exports, "__esModule", { value: true }); +exports.PartialType = void 0; +function PartialType(classRef) { + class PartialClassType { + constructor() { } + } + return PartialClassType; +} +exports.PartialType = PartialType; +//# sourceMappingURL=index.js.map + +//// [D:/Work/pkg1/dist/utils/index.d.ts] +import { MyType, MyReturnType } from './type-helpers'; +export declare function PartialType(classRef: MyType): MyReturnType; + + +//// [D:/Work/pkg1/dist/main.js.map] +{"version":3,"file":"main.js","sourceRoot":"","sources":["../src/main.ts"],"names":[],"mappings":";;;AAAA,mCAAsC;AAEtC,MAAM,MAAM;CAAG;AAEf,MAAa,GAAI,SAAQ,IAAA,mBAAW,EAAC,MAAM,CAAC;CAE3C;AAFD,kBAEC"} + +//// [D:/Work/pkg1/dist/main.js] +"use strict"; +Object.defineProperty(exports, "__esModule", { value: true }); +exports.Sub = void 0; +const utils_1 = require("./utils"); +class Common { +} +class Sub extends (0, utils_1.PartialType)(Common) { +} +exports.Sub = Sub; +//# sourceMappingURL=main.js.map + +//// [D:/Work/pkg1/dist/main.d.ts] +declare const Sub_base: import("./utils/type-helpers").MyReturnType; +export declare class Sub extends Sub_base { + id: string; +} +export {}; + + + +Program root files: [ + "D:/Work/pkg1/src/main.ts", + "D:/Work/pkg1/src/utils/index.ts", + "D:/Work/pkg1/src/utils/type-helpers.ts" +] +Program options: { + "module": 1, + "declaration": true, + "removeComments": true, + "emitDecoratorMetadata": true, + "experimentalDecorators": true, + "strictPropertyInitialization": false, + "allowSyntheticDefaultImports": true, + "target": 4, + "sourceMap": true, + "esModuleInterop": true, + "outDir": "D:/Work/pkg1/dist", + "baseUrl": "D:/Work/pkg1", + "skipLibCheck": true, + "strictNullChecks": false, + "noImplicitAny": false, + "strictBindCallApply": false, + "forceConsistentCasingInFileNames": false, + "noFallthroughCasesInSwitch": false, + "moduleResolution": 2, + "resolveJsonModule": true, + "project": "D:/Work/pkg1", + "explainFiles": true, + "configFilePath": "D:/Work/pkg1/tsconfig.json" +} +Program structureReused: Not +Program files:: +D:/Work/pkg1/src/utils/type-helpers.ts +D:/Work/pkg1/src/utils/index.ts +D:/Work/pkg1/src/main.ts + +exitCode:: ExitStatus.DiagnosticsPresent_OutputsSkipped