Skip to content

Commit

Permalink
Compare package.json paths with correct sensitivity in getLocalModule…
Browse files Browse the repository at this point in the history
…Specifier (#57973)
  • Loading branch information
jakebailey committed Mar 28, 2024
1 parent ebd0570 commit 35f4f03
Show file tree
Hide file tree
Showing 3 changed files with 330 additions and 1 deletion.
9 changes: 8 additions & 1 deletion src/compiler/moduleSpecifiers.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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/
Expand All @@ -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;
Expand Down
94 changes: 94 additions & 0 deletions src/testRunner/unittests/tsc/declarationEmit.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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<T>(classRef: MyType<T>) {
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<T = any> extends Function {
new (...args: any[]): T;
}
`,
},
libFile,
], { currentDirectory: "D:\\Work\\pkg1", windowsStyleRoot: "D:/" }),
commandLineArgs: ["-p", "D:\\Work\\pkg1", "--explainFiles"],
});
});
Original file line number Diff line number Diff line change
@@ -0,0 +1,228 @@
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<T>(classRef: MyType<T>) {
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<T = any> extends Function {
new (...args: any[]): T;
}


//// [D:/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; }


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<T = any> 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,kCAMC;AAND,SAAgB,WAAW,CAAI,QAAmB;IAC9C,MAAe,gBAAgB;QAC3B,gBAAe,CAAC;KACnB;IAED,OAAO,gBAAgC,CAAC;AAC5C,CAAC"}

//// [D:/Work/pkg1/dist/utils/index.js]
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
exports.PartialType = PartialType;
function PartialType(classRef) {
class PartialClassType {
constructor() { }
}
return PartialClassType;
}
//# sourceMappingURL=index.js.map

//// [D:/Work/pkg1/dist/utils/index.d.ts]
import { MyType, MyReturnType } from './type-helpers';
export declare function PartialType<T>(classRef: MyType<T>): 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

0 comments on commit 35f4f03

Please sign in to comment.