@@ -319,33 +319,30 @@ namespace ts.moduleSpecifiers {
319
319
return undefined ;
320
320
}
321
321
322
- let packageJsonContent : any | undefined ;
323
- const packageRootPath = moduleFileName . substring ( 0 , parts . packageRootIndex ) ;
322
+ // Simplify the full file path to something that can be resolved by Node.
323
+
324
+ let moduleSpecifier = moduleFileName ;
324
325
if ( ! packageNameOnly ) {
325
- const packageJsonPath = combinePaths ( packageRootPath , "package.json" ) ;
326
- packageJsonContent = host . fileExists ( packageJsonPath )
327
- ? JSON . parse ( host . readFile ( packageJsonPath ) ! )
328
- : undefined ;
329
- const versionPaths = packageJsonContent && packageJsonContent . typesVersions
330
- ? getPackageJsonTypesVersionsPaths ( packageJsonContent . typesVersions )
331
- : undefined ;
332
- if ( versionPaths ) {
333
- const subModuleName = moduleFileName . slice ( parts . packageRootIndex + 1 ) ;
334
- const fromPaths = tryGetModuleNameFromPaths (
335
- removeFileExtension ( subModuleName ) ,
336
- removeExtensionAndIndexPostFix ( subModuleName , Ending . Minimal , options ) ,
337
- versionPaths . paths
338
- ) ;
339
- if ( fromPaths !== undefined ) {
340
- moduleFileName = combinePaths ( moduleFileName . slice ( 0 , parts . packageRootIndex ) , fromPaths ) ;
326
+ let packageRootIndex = parts . packageRootIndex ;
327
+ let moduleFileNameForExtensionless : string | undefined ;
328
+ while ( true ) {
329
+ // If the module could be imported by a directory name, use that directory's name
330
+ const { moduleFileToTry , packageRootPath } = tryDirectoryWithPackageJson ( packageRootIndex ) ;
331
+ if ( packageRootPath ) {
332
+ moduleSpecifier = packageRootPath ;
333
+ break ;
334
+ }
335
+ if ( ! moduleFileNameForExtensionless ) moduleFileNameForExtensionless = moduleFileToTry ;
336
+
337
+ // try with next level of directory
338
+ packageRootIndex = moduleFileName . indexOf ( directorySeparator , packageRootIndex + 1 ) ;
339
+ if ( packageRootIndex === - 1 ) {
340
+ moduleSpecifier = getExtensionlessFileName ( moduleFileNameForExtensionless ) ;
341
+ break ;
341
342
}
342
343
}
343
344
}
344
345
345
- // Simplify the full file path to something that can be resolved by Node.
346
-
347
- // If the module could be imported by a directory name, use that directory's name
348
- const moduleSpecifier = packageNameOnly ? moduleFileName : getDirectoryOrExtensionlessFileName ( moduleFileName ) ;
349
346
const globalTypingsCacheLocation = host . getGlobalTypingsCacheLocation && host . getGlobalTypingsCacheLocation ( ) ;
350
347
// Get a path that's relative to node_modules or the importing file's path
351
348
// if node_modules folder is in this folder or any of its parent folders, no need to keep it.
@@ -360,18 +357,40 @@ namespace ts.moduleSpecifiers {
360
357
// For classic resolution, only allow importing from node_modules/@types, not other node_modules
361
358
return getEmitModuleResolutionKind ( options ) !== ModuleResolutionKind . NodeJs && packageName === nodeModulesDirectoryName ? undefined : packageName ;
362
359
363
- function getDirectoryOrExtensionlessFileName ( path : string ) : string {
364
- // If the file is the main module, it can be imported by the package name
365
- if ( packageJsonContent ) {
360
+ function tryDirectoryWithPackageJson ( packageRootIndex : number ) {
361
+ const packageRootPath = moduleFileName . substring ( 0 , packageRootIndex ) ;
362
+ const packageJsonPath = combinePaths ( packageRootPath , "package.json" ) ;
363
+ let moduleFileToTry = moduleFileName ;
364
+ if ( host . fileExists ( packageJsonPath ) ) {
365
+ const packageJsonContent = JSON . parse ( host . readFile ! ( packageJsonPath ) ! ) ;
366
+ const versionPaths = packageJsonContent . typesVersions
367
+ ? getPackageJsonTypesVersionsPaths ( packageJsonContent . typesVersions )
368
+ : undefined ;
369
+ if ( versionPaths ) {
370
+ const subModuleName = moduleFileName . slice ( packageRootPath . length + 1 ) ;
371
+ const fromPaths = tryGetModuleNameFromPaths (
372
+ removeFileExtension ( subModuleName ) ,
373
+ removeExtensionAndIndexPostFix ( subModuleName , Ending . Minimal , options ) ,
374
+ versionPaths . paths
375
+ ) ;
376
+ if ( fromPaths !== undefined ) {
377
+ moduleFileToTry = combinePaths ( packageRootPath , fromPaths ) ;
378
+ }
379
+ }
380
+
381
+ // If the file is the main module, it can be imported by the package name
366
382
const mainFileRelative = packageJsonContent . typings || packageJsonContent . types || packageJsonContent . main ;
367
383
if ( isString ( mainFileRelative ) ) {
368
384
const mainExportFile = toPath ( mainFileRelative , packageRootPath , getCanonicalFileName ) ;
369
- if ( removeFileExtension ( mainExportFile ) === removeFileExtension ( getCanonicalFileName ( path ) ) ) {
370
- return packageRootPath ;
385
+ if ( removeFileExtension ( mainExportFile ) === removeFileExtension ( getCanonicalFileName ( moduleFileToTry ) ) ) {
386
+ return { packageRootPath, moduleFileToTry } ;
371
387
}
372
388
}
373
389
}
390
+ return { moduleFileToTry } ;
391
+ }
374
392
393
+ function getExtensionlessFileName ( path : string ) : string {
375
394
// We still have a file name - remove the extension
376
395
const fullModulePathWithoutExtension = removeFileExtension ( path ) ;
377
396
0 commit comments