@@ -340,10 +340,7 @@ namespace ts {
340340 }
341341
342342 const failedLookupLocations : string [ ] = [ ] ;
343- const features =
344- getEmitModuleResolutionKind ( options ) === ModuleResolutionKind . Node12 ? NodeResolutionFeatures . Node12Default :
345- getEmitModuleResolutionKind ( options ) === ModuleResolutionKind . NodeNext ? NodeResolutionFeatures . NodeNextDefault :
346- NodeResolutionFeatures . None ;
343+ const features = getDefaultNodeResolutionFeatures ( options ) ;
347344 const moduleResolutionState : ModuleResolutionState = { compilerOptions : options , host, traceEnabled, failedLookupLocations, packageJsonInfoCache : cache , features, conditions : [ "node" , "require" , "types" ] } ;
348345 let resolved = primaryLookup ( ) ;
349346 let primary = true ;
@@ -433,6 +430,42 @@ namespace ts {
433430 }
434431 }
435432
433+ function getDefaultNodeResolutionFeatures ( options : CompilerOptions ) {
434+ return getEmitModuleResolutionKind ( options ) === ModuleResolutionKind . Node12 ? NodeResolutionFeatures . Node12Default :
435+ getEmitModuleResolutionKind ( options ) === ModuleResolutionKind . NodeNext ? NodeResolutionFeatures . NodeNextDefault :
436+ NodeResolutionFeatures . None ;
437+ }
438+
439+ /**
440+ * @internal
441+ * Does not try `@types/${packageName}` - use a second pass if needed.
442+ */
443+ export function resolvePackageNameToPackageJson (
444+ packageName : string ,
445+ containingDirectory : string ,
446+ options : CompilerOptions ,
447+ host : ModuleResolutionHost ,
448+ cache : ModuleResolutionCache | undefined ,
449+ ) : PackageJsonInfo | undefined {
450+ const moduleResolutionState : ModuleResolutionState = {
451+ compilerOptions : options ,
452+ host,
453+ traceEnabled : isTraceEnabled ( options , host ) ,
454+ failedLookupLocations : [ ] ,
455+ packageJsonInfoCache : cache ?. getPackageJsonInfoCache ( ) ,
456+ conditions : emptyArray ,
457+ features : NodeResolutionFeatures . None ,
458+ } ;
459+
460+ return forEachAncestorDirectory ( containingDirectory , ancestorDirectory => {
461+ if ( getBaseFileName ( ancestorDirectory ) !== "node_modules" ) {
462+ const nodeModulesFolder = combinePaths ( ancestorDirectory , "node_modules" ) ;
463+ const candidate = combinePaths ( nodeModulesFolder , packageName ) ;
464+ return getPackageJsonInfo ( candidate , /*onlyRecordFailures*/ false , moduleResolutionState ) ;
465+ }
466+ } ) ;
467+ }
468+
436469 /**
437470 * Given a set of options, returns the set of type directive names
438471 * that should be included for this program automatically.
@@ -1171,11 +1204,6 @@ namespace ts {
11711204 return resolvedModule . resolvedFileName ;
11721205 }
11731206
1174- /* @internal */
1175- export function tryResolveJSModule ( moduleName : string , initialDir : string , host : ModuleResolutionHost ) {
1176- return tryResolveJSModuleWorker ( moduleName , initialDir , host ) . resolvedModule ;
1177- }
1178-
11791207 /* @internal */
11801208 enum NodeResolutionFeatures {
11811209 None = 0 ,
@@ -1536,11 +1564,124 @@ namespace ts {
15361564 return withPackageId ( packageInfo , loadNodeModuleFromDirectoryWorker ( extensions , candidate , onlyRecordFailures , state , packageJsonContent , versionPaths ) ) ;
15371565 }
15381566
1567+ /* @internal */
1568+ export function getEntrypointsFromPackageJsonInfo (
1569+ packageJsonInfo : PackageJsonInfo ,
1570+ options : CompilerOptions ,
1571+ host : ModuleResolutionHost ,
1572+ cache : ModuleResolutionCache | undefined ,
1573+ resolveJs ?: boolean ,
1574+ ) : string [ ] | false {
1575+ if ( ! resolveJs && packageJsonInfo . resolvedEntrypoints !== undefined ) {
1576+ // Cached value excludes resolutions to JS files - those could be
1577+ // cached separately, but they're used rarely.
1578+ return packageJsonInfo . resolvedEntrypoints ;
1579+ }
1580+
1581+ let entrypoints : string [ ] | undefined ;
1582+ const extensions = resolveJs ? Extensions . JavaScript : Extensions . TypeScript ;
1583+ const features = getDefaultNodeResolutionFeatures ( options ) ;
1584+ const requireState : ModuleResolutionState = {
1585+ compilerOptions : options ,
1586+ host,
1587+ traceEnabled : isTraceEnabled ( options , host ) ,
1588+ failedLookupLocations : [ ] ,
1589+ packageJsonInfoCache : cache ?. getPackageJsonInfoCache ( ) ,
1590+ conditions : [ "node" , "require" , "types" ] ,
1591+ features,
1592+ } ;
1593+ const requireResolution = loadNodeModuleFromDirectoryWorker (
1594+ extensions ,
1595+ packageJsonInfo . packageDirectory ,
1596+ /*onlyRecordFailures*/ false ,
1597+ requireState ,
1598+ packageJsonInfo . packageJsonContent ,
1599+ packageJsonInfo . versionPaths ) ;
1600+ entrypoints = append ( entrypoints , requireResolution ?. path ) ;
1601+
1602+ if ( features & NodeResolutionFeatures . Exports && packageJsonInfo . packageJsonContent . exports ) {
1603+ for ( const conditions of [ [ "node" , "import" , "types" ] , [ "node" , "require" , "types" ] ] ) {
1604+ const exportState = { ...requireState , failedLookupLocations : [ ] , conditions } ;
1605+ const exportResolutions = loadEntrypointsFromExportMap (
1606+ packageJsonInfo ,
1607+ packageJsonInfo . packageJsonContent . exports ,
1608+ exportState ,
1609+ extensions ) ;
1610+ if ( exportResolutions ) {
1611+ for ( const resolution of exportResolutions ) {
1612+ entrypoints = appendIfUnique ( entrypoints , resolution . path ) ;
1613+ }
1614+ }
1615+ }
1616+ }
1617+
1618+ return packageJsonInfo . resolvedEntrypoints = entrypoints || false ;
1619+ }
1620+
1621+ function loadEntrypointsFromExportMap (
1622+ scope : PackageJsonInfo ,
1623+ exports : object ,
1624+ state : ModuleResolutionState ,
1625+ extensions : Extensions ,
1626+ ) : PathAndExtension [ ] | undefined {
1627+ let entrypoints : PathAndExtension [ ] | undefined ;
1628+ if ( isArray ( exports ) ) {
1629+ for ( const target of exports ) {
1630+ loadEntrypointsFromTargetExports ( target ) ;
1631+ }
1632+ }
1633+ // eslint-disable-next-line no-null/no-null
1634+ else if ( typeof exports === "object" && exports !== null && allKeysStartWithDot ( exports as MapLike < unknown > ) ) {
1635+ for ( const key in exports ) {
1636+ loadEntrypointsFromTargetExports ( ( exports as MapLike < unknown > ) [ key ] ) ;
1637+ }
1638+ }
1639+ else {
1640+ loadEntrypointsFromTargetExports ( exports ) ;
1641+ }
1642+ return entrypoints ;
1643+
1644+ function loadEntrypointsFromTargetExports ( target : unknown ) : boolean | undefined {
1645+ if ( typeof target === "string" && startsWith ( target , "./" ) && target . indexOf ( "*" ) === - 1 ) {
1646+ const partsAfterFirst = getPathComponents ( target ) . slice ( 2 ) ;
1647+ if ( partsAfterFirst . indexOf ( ".." ) >= 0 || partsAfterFirst . indexOf ( "." ) >= 0 || partsAfterFirst . indexOf ( "node_modules" ) >= 0 ) {
1648+ return false ;
1649+ }
1650+ const resolvedTarget = combinePaths ( scope . packageDirectory , target ) ;
1651+ const finalPath = getNormalizedAbsolutePath ( resolvedTarget , state . host . getCurrentDirectory ?.( ) ) ;
1652+ const result = loadJSOrExactTSFileName ( extensions , finalPath , /*recordOnlyFailures*/ false , state ) ;
1653+ if ( result ) {
1654+ entrypoints = appendIfUnique ( entrypoints , result , ( a , b ) => a . path === b . path ) ;
1655+ return true ;
1656+ }
1657+ }
1658+ else if ( Array . isArray ( target ) ) {
1659+ for ( const t of target ) {
1660+ const success = loadEntrypointsFromTargetExports ( t ) ;
1661+ if ( success ) {
1662+ return true ;
1663+ }
1664+ }
1665+ }
1666+ // eslint-disable-next-line no-null/no-null
1667+ else if ( typeof target === "object" && target !== null ) {
1668+ return forEach ( getOwnKeys ( target as MapLike < unknown > ) , key => {
1669+ if ( key === "default" || contains ( state . conditions , key ) || isApplicableVersionedTypesKey ( state . conditions , key ) ) {
1670+ loadEntrypointsFromTargetExports ( ( target as MapLike < unknown > ) [ key ] ) ;
1671+ return true ;
1672+ }
1673+ } ) ;
1674+ }
1675+ }
1676+ }
1677+
15391678 /*@internal */
15401679 interface PackageJsonInfo {
15411680 packageDirectory : string ;
15421681 packageJsonContent : PackageJsonPathFields ;
15431682 versionPaths : VersionPaths | undefined ;
1683+ /** false: resolved to nothing. undefined: not yet resolved */
1684+ resolvedEntrypoints : string [ ] | false | undefined ;
15441685 }
15451686
15461687 /**
@@ -1606,7 +1747,7 @@ namespace ts {
16061747 trace ( host , Diagnostics . Found_package_json_at_0 , packageJsonPath ) ;
16071748 }
16081749 const versionPaths = readPackageJsonTypesVersionPaths ( packageJsonContent , state ) ;
1609- const result = { packageDirectory, packageJsonContent, versionPaths } ;
1750+ const result = { packageDirectory, packageJsonContent, versionPaths, resolvedEntrypoints : undefined } ;
16101751 state . packageJsonInfoCache ?. setPackageJsonInfo ( packageJsonPath , result ) ;
16111752 return result ;
16121753 }
0 commit comments