Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
22 changes: 11 additions & 11 deletions tsc/internal/modulespecifiers/specifiers.go
Original file line number Diff line number Diff line change
Expand Up @@ -760,11 +760,21 @@ func tryGetModuleNameAsNodeModule(
return ""
}

caseSensitive := host.UseCaseSensitiveFileNames()
globalTypingsCacheLocation := host.GetGlobalTypingsCacheLocation()
// Check reachability before consulting package.json exports, which can return
// a bare specifier directly. An exported path is only usable if the importing
// file can reach the package through node_modules.
pathToTopLevelNodeModules := pathObj.FileName[0:parts.TopLevelNodeModulesIndex]

if !stringutil.HasPrefix(info.SourceDirectory, pathToTopLevelNodeModules, caseSensitive) || len(globalTypingsCacheLocation) > 0 && stringutil.HasPrefix(globalTypingsCacheLocation, pathToTopLevelNodeModules, caseSensitive) {
Comment on lines +769 to +770
return ""
}
Comment on lines +765 to +772

// Simplify the full file path to something that can be resolved by Node.
preferences := getModuleSpecifierPreferences(userPreferences, host, options, importingSourceFile, "")
allowedEndings := preferences.getAllowedEndingsInPreferredOrder(core.ResolutionModeNone)

caseSensitive := host.UseCaseSensitiveFileNames()
moduleSpecifier := pathObj.FileName
isPackageRootPath := false
if !packageNameOnly {
Expand Down Expand Up @@ -794,7 +804,6 @@ func tryGetModuleNameAsNodeModule(
if verbatimFromExports {
return moduleFileToTry
}
//}
if len(packageRootPath) > 0 {
moduleSpecifier = packageRootPath
isPackageRootPath = true
Expand All @@ -816,15 +825,6 @@ func tryGetModuleNameAsNodeModule(
return ""
}

globalTypingsCacheLocation := host.GetGlobalTypingsCacheLocation()
// Get a path that's relative to node_modules or the importing file's path
// if node_modules folder is in this folder or any of its parent folders, no need to keep it.
pathToTopLevelNodeModules := moduleSpecifier[0:parts.TopLevelNodeModulesIndex]

if !stringutil.HasPrefix(info.SourceDirectory, pathToTopLevelNodeModules, caseSensitive) || len(globalTypingsCacheLocation) > 0 && stringutil.HasPrefix(globalTypingsCacheLocation, pathToTopLevelNodeModules, caseSensitive) {
return ""
}

// If the module was found in @types, get the actual Node package name
nodeModulesDirectoryName := moduleSpecifier[parts.TopLevelPackageNameIndex+1:]
return module.GetPackageNameFromTypesPackageName(nodeModulesDirectoryName)
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,50 @@
/packages/a/index.ts(2,14): error TS2883: The inferred type of 'thing' cannot be named without a reference to 'Thing' from '../s/node_modules/c-pattern/dist/Thing.js'. This is likely not portable. A type annotation is necessary.
/packages/a/index.ts(2,14): error TS2883: The inferred type of 'thing' cannot be named without a reference to 'Thing' from '../s/node_modules/c-root/dist/Thing.js'. This is likely not portable. A type annotation is necessary.
/packages/a/index.ts(2,14): error TS2883: The inferred type of 'thing' cannot be named without a reference to 'Thing' from '../s/node_modules/c-subpath/dist/Thing.js'. This is likely not portable. A type annotation is necessary.


==== /node_modules/.store/c-root/node_modules/c-root/package.json (0 errors) ====
{ "name": "c-root", "version": "1.0.0", "type": "module", "exports": { ".": "./dist/Thing.d.ts" } }
==== /node_modules/.store/c-root/node_modules/c-root/dist/Thing.d.ts (0 errors) ====
export interface Thing { readonly x: number; }
export declare const create: () => Thing;

==== /node_modules/.store/c-subpath/node_modules/c-subpath/package.json (0 errors) ====
{ "name": "c-subpath", "version": "1.0.0", "type": "module", "exports": { "./Thing": { "types": "./dist/Thing.d.ts", "default": "./dist/Thing.js" } } }
==== /node_modules/.store/c-subpath/node_modules/c-subpath/dist/Thing.d.ts (0 errors) ====
export interface Thing { readonly x: number; }
export declare const create: () => Thing;

==== /node_modules/.store/c-pattern/node_modules/c-pattern/package.json (0 errors) ====
{ "name": "c-pattern", "version": "1.0.0", "type": "module", "exports": { "./*": "./dist/*.d.ts" } }
==== /node_modules/.store/c-pattern/node_modules/c-pattern/dist/Thing.d.ts (0 errors) ====
export interface Thing { readonly x: number; }
export declare const create: () => Thing;

==== /packages/s/package.json (0 errors) ====
{ "name": "s", "type": "module", "exports": "./index.d.ts" }
==== /packages/s/index.d.ts (0 errors) ====
import { create as createRoot } from "c-root";
import { create as createSubpath } from "c-subpath/Thing";
import { create as createPattern } from "c-pattern/Thing";
export declare const root: ReturnType<typeof createRoot>;
export declare const subpath: ReturnType<typeof createSubpath>;
export declare const pattern: ReturnType<typeof createPattern>;

==== /packages/a/package.json (0 errors) ====
{ "name": "a", "type": "module" }
==== /packages/a/index.ts (3 errors) ====
import { root, subpath, pattern } from "s";
export const thing = { root, subpath, pattern };
~~~~~
!!! error TS2883: The inferred type of 'thing' cannot be named without a reference to 'Thing' from '../s/node_modules/c-pattern/dist/Thing.js'. This is likely not portable. A type annotation is necessary.
~~~~~
!!! error TS2883: The inferred type of 'thing' cannot be named without a reference to 'Thing' from '../s/node_modules/c-root/dist/Thing.js'. This is likely not portable. A type annotation is necessary.
~~~~~
!!! error TS2883: The inferred type of 'thing' cannot be named without a reference to 'Thing' from '../s/node_modules/c-subpath/dist/Thing.js'. This is likely not portable. A type annotation is necessary.

==== /packages/s/reachable.ts (0 errors) ====
import { root, subpath, pattern } from "./index.js";
export const thing = { root, subpath, pattern };


Original file line number Diff line number Diff line change
@@ -0,0 +1,50 @@
//// [tests/cases/compiler/declarationEmitUnreachablePackageExports.ts] ////

//// [package.json]
{ "name": "c-root", "version": "1.0.0", "type": "module", "exports": { ".": "./dist/Thing.d.ts" } }
//// [Thing.d.ts]
export interface Thing { readonly x: number; }
export declare const create: () => Thing;

//// [package.json]
{ "name": "c-subpath", "version": "1.0.0", "type": "module", "exports": { "./Thing": { "types": "./dist/Thing.d.ts", "default": "./dist/Thing.js" } } }
//// [Thing.d.ts]
export interface Thing { readonly x: number; }
export declare const create: () => Thing;

//// [package.json]
{ "name": "c-pattern", "version": "1.0.0", "type": "module", "exports": { "./*": "./dist/*.d.ts" } }
//// [Thing.d.ts]
export interface Thing { readonly x: number; }
export declare const create: () => Thing;

//// [package.json]
{ "name": "s", "type": "module", "exports": "./index.d.ts" }
//// [index.d.ts]
import { create as createRoot } from "c-root";
import { create as createSubpath } from "c-subpath/Thing";
import { create as createPattern } from "c-pattern/Thing";
export declare const root: ReturnType<typeof createRoot>;
export declare const subpath: ReturnType<typeof createSubpath>;
export declare const pattern: ReturnType<typeof createPattern>;

//// [package.json]
{ "name": "a", "type": "module" }
//// [index.ts]
import { root, subpath, pattern } from "s";
export const thing = { root, subpath, pattern };

//// [reachable.ts]
import { root, subpath, pattern } from "./index.js";
export const thing = { root, subpath, pattern };





//// [reachable.d.ts]
export declare const thing: {
root: import("c-root").Thing;
subpath: import("c-subpath/Thing").Thing;
pattern: import("c-pattern/Thing").Thing;
};
Original file line number Diff line number Diff line change
@@ -0,0 +1,50 @@
/packages/a/index.ts(2,14): error TS2883: The inferred type of 'thing' cannot be named without a reference to 'Thing' from '../s/node_modules/c-pattern/dist/Thing'. This is likely not portable. A type annotation is necessary.
/packages/a/index.ts(2,14): error TS2883: The inferred type of 'thing' cannot be named without a reference to 'Thing' from '../s/node_modules/c-root/dist/Thing'. This is likely not portable. A type annotation is necessary.
/packages/a/index.ts(2,14): error TS2883: The inferred type of 'thing' cannot be named without a reference to 'Thing' from '../s/node_modules/c-subpath/dist/Thing'. This is likely not portable. A type annotation is necessary.


==== /node_modules/.store/c-root/node_modules/c-root/package.json (0 errors) ====
{ "name": "c-root", "version": "1.0.0", "type": "module", "exports": { ".": "./dist/Thing.d.ts" } }
==== /node_modules/.store/c-root/node_modules/c-root/dist/Thing.d.ts (0 errors) ====
export interface Thing { readonly x: number; }
export declare const create: () => Thing;

==== /node_modules/.store/c-subpath/node_modules/c-subpath/package.json (0 errors) ====
{ "name": "c-subpath", "version": "1.0.0", "type": "module", "exports": { "./Thing": { "types": "./dist/Thing.d.ts", "default": "./dist/Thing.js" } } }
==== /node_modules/.store/c-subpath/node_modules/c-subpath/dist/Thing.d.ts (0 errors) ====
export interface Thing { readonly x: number; }
export declare const create: () => Thing;

==== /node_modules/.store/c-pattern/node_modules/c-pattern/package.json (0 errors) ====
{ "name": "c-pattern", "version": "1.0.0", "type": "module", "exports": { "./*": "./dist/*.d.ts" } }
==== /node_modules/.store/c-pattern/node_modules/c-pattern/dist/Thing.d.ts (0 errors) ====
export interface Thing { readonly x: number; }
export declare const create: () => Thing;

==== /packages/s/package.json (0 errors) ====
{ "name": "s", "type": "module", "exports": "./index.d.ts" }
==== /packages/s/index.d.ts (0 errors) ====
import { create as createRoot } from "c-root";
import { create as createSubpath } from "c-subpath/Thing";
import { create as createPattern } from "c-pattern/Thing";
export declare const root: ReturnType<typeof createRoot>;
export declare const subpath: ReturnType<typeof createSubpath>;
export declare const pattern: ReturnType<typeof createPattern>;

==== /packages/a/package.json (0 errors) ====
{ "name": "a", "type": "module" }
==== /packages/a/index.ts (3 errors) ====
import { root, subpath, pattern } from "s";
export const thing = { root, subpath, pattern };
~~~~~
!!! error TS2883: The inferred type of 'thing' cannot be named without a reference to 'Thing' from '../s/node_modules/c-pattern/dist/Thing'. This is likely not portable. A type annotation is necessary.
~~~~~
!!! error TS2883: The inferred type of 'thing' cannot be named without a reference to 'Thing' from '../s/node_modules/c-root/dist/Thing'. This is likely not portable. A type annotation is necessary.
~~~~~
!!! error TS2883: The inferred type of 'thing' cannot be named without a reference to 'Thing' from '../s/node_modules/c-subpath/dist/Thing'. This is likely not portable. A type annotation is necessary.

==== /packages/s/reachable.ts (0 errors) ====
import { root, subpath, pattern } from "./index.js";
export const thing = { root, subpath, pattern };


Original file line number Diff line number Diff line change
@@ -0,0 +1,50 @@
//// [tests/cases/compiler/declarationEmitUnreachablePackageExports.ts] ////

//// [package.json]
{ "name": "c-root", "version": "1.0.0", "type": "module", "exports": { ".": "./dist/Thing.d.ts" } }
//// [Thing.d.ts]
export interface Thing { readonly x: number; }
export declare const create: () => Thing;

//// [package.json]
{ "name": "c-subpath", "version": "1.0.0", "type": "module", "exports": { "./Thing": { "types": "./dist/Thing.d.ts", "default": "./dist/Thing.js" } } }
//// [Thing.d.ts]
export interface Thing { readonly x: number; }
export declare const create: () => Thing;

//// [package.json]
{ "name": "c-pattern", "version": "1.0.0", "type": "module", "exports": { "./*": "./dist/*.d.ts" } }
//// [Thing.d.ts]
export interface Thing { readonly x: number; }
export declare const create: () => Thing;

//// [package.json]
{ "name": "s", "type": "module", "exports": "./index.d.ts" }
//// [index.d.ts]
import { create as createRoot } from "c-root";
import { create as createSubpath } from "c-subpath/Thing";
import { create as createPattern } from "c-pattern/Thing";
export declare const root: ReturnType<typeof createRoot>;
export declare const subpath: ReturnType<typeof createSubpath>;
export declare const pattern: ReturnType<typeof createPattern>;

//// [package.json]
{ "name": "a", "type": "module" }
//// [index.ts]
import { root, subpath, pattern } from "s";
export const thing = { root, subpath, pattern };

//// [reachable.ts]
import { root, subpath, pattern } from "./index.js";
export const thing = { root, subpath, pattern };





//// [reachable.d.ts]
export declare const thing: {
root: import("c-root").Thing;
subpath: import("c-subpath/Thing").Thing;
pattern: import("c-pattern/Thing").Thing;
};
Original file line number Diff line number Diff line change
@@ -0,0 +1,48 @@
// @declaration: true
// @emitDeclarationOnly: true
// @strict: true
// @module: nodenext, preserve
// @noTypesAndSymbols: true

// @filename: /node_modules/.store/c-root/node_modules/c-root/package.json
{ "name": "c-root", "version": "1.0.0", "type": "module", "exports": { ".": "./dist/Thing.d.ts" } }
// @filename: /node_modules/.store/c-root/node_modules/c-root/dist/Thing.d.ts
export interface Thing { readonly x: number; }
export declare const create: () => Thing;

// @filename: /node_modules/.store/c-subpath/node_modules/c-subpath/package.json
{ "name": "c-subpath", "version": "1.0.0", "type": "module", "exports": { "./Thing": { "types": "./dist/Thing.d.ts", "default": "./dist/Thing.js" } } }
// @filename: /node_modules/.store/c-subpath/node_modules/c-subpath/dist/Thing.d.ts
export interface Thing { readonly x: number; }
export declare const create: () => Thing;

// @filename: /node_modules/.store/c-pattern/node_modules/c-pattern/package.json
{ "name": "c-pattern", "version": "1.0.0", "type": "module", "exports": { "./*": "./dist/*.d.ts" } }
// @filename: /node_modules/.store/c-pattern/node_modules/c-pattern/dist/Thing.d.ts
export interface Thing { readonly x: number; }
export declare const create: () => Thing;

// @filename: /packages/s/package.json
{ "name": "s", "type": "module", "exports": "./index.d.ts" }
// @filename: /packages/s/index.d.ts
import { create as createRoot } from "c-root";
import { create as createSubpath } from "c-subpath/Thing";
import { create as createPattern } from "c-pattern/Thing";
export declare const root: ReturnType<typeof createRoot>;
export declare const subpath: ReturnType<typeof createSubpath>;
export declare const pattern: ReturnType<typeof createPattern>;

// @filename: /packages/a/package.json
{ "name": "a", "type": "module" }
// @filename: /packages/a/index.ts
import { root, subpath, pattern } from "s";
export const thing = { root, subpath, pattern };

// @filename: /packages/s/reachable.ts
import { root, subpath, pattern } from "./index.js";
export const thing = { root, subpath, pattern };

// @link: /node_modules/.store/c-root/node_modules/c-root -> /packages/s/node_modules/c-root
// @link: /node_modules/.store/c-subpath/node_modules/c-subpath -> /packages/s/node_modules/c-subpath
// @link: /node_modules/.store/c-pattern/node_modules/c-pattern -> /packages/s/node_modules/c-pattern
// @link: /packages/s -> /packages/a/node_modules/s
Loading