@@ -12,6 +12,12 @@ namespace ts {
1212
1313 const emptyArray : any [ ] = [ ] ;
1414
15+ const defaultLibrarySearchPaths = < Path [ ] > [
16+ "typings/" ,
17+ "node_modules/" ,
18+ "node_modules/@types/" ,
19+ ] ;
20+
1521 export const version = "1.9.0" ;
1622
1723 export function findConfigFile ( searchPath : string , fileExists : ( fileName : string ) => boolean ) : string {
@@ -370,7 +376,7 @@ namespace ts {
370376 const traceEnabled = isTraceEnabled ( compilerOptions , host ) ;
371377
372378 const failedLookupLocations : string [ ] = [ ] ;
373- const state = { compilerOptions, host, traceEnabled, skipTsx : false } ;
379+ const state = { compilerOptions, host, traceEnabled, skipTsx : false } ;
374380 let resolvedFileName = tryLoadModuleUsingOptionalResolutionSettings ( moduleName , containingDirectory , nodeLoadModuleByRelativeName ,
375381 failedLookupLocations , supportedExtensions , state ) ;
376382
@@ -406,7 +412,7 @@ namespace ts {
406412 }
407413
408414 /* @internal */
409- export function directoryProbablyExists ( directoryName : string , host : { directoryExists ?: ( directoryName : string ) => boolean } ) : boolean {
415+ export function directoryProbablyExists ( directoryName : string , host : { directoryExists ?: ( directoryName : string ) => boolean } ) : boolean {
410416 // if host does not support 'directoryExists' assume that directory will exist
411417 return ! host . directoryExists || host . directoryExists ( directoryName ) ;
412418 }
@@ -553,7 +559,7 @@ namespace ts {
553559
554560
555561 return referencedSourceFile
556- ? { resolvedModule : { resolvedFileName : referencedSourceFile } , failedLookupLocations }
562+ ? { resolvedModule : { resolvedFileName : referencedSourceFile } , failedLookupLocations }
557563 : { resolvedModule : undefined , failedLookupLocations } ;
558564 }
559565
@@ -653,9 +659,9 @@ namespace ts {
653659
654660 export function getPreEmitDiagnostics ( program : Program , sourceFile ?: SourceFile , cancellationToken ?: CancellationToken ) : Diagnostic [ ] {
655661 let diagnostics = program . getOptionsDiagnostics ( cancellationToken ) . concat (
656- program . getSyntacticDiagnostics ( sourceFile , cancellationToken ) ,
657- program . getGlobalDiagnostics ( cancellationToken ) ,
658- program . getSemanticDiagnostics ( sourceFile , cancellationToken ) ) ;
662+ program . getSyntacticDiagnostics ( sourceFile , cancellationToken ) ,
663+ program . getGlobalDiagnostics ( cancellationToken ) ,
664+ program . getSemanticDiagnostics ( sourceFile , cancellationToken ) ) ;
659665
660666 if ( program . getCompilerOptions ( ) . declaration ) {
661667 diagnostics = diagnostics . concat ( program . getDeclarationDiagnostics ( sourceFile , cancellationToken ) ) ;
@@ -694,6 +700,14 @@ namespace ts {
694700 let program : Program ;
695701 let files : SourceFile [ ] = [ ] ;
696702 let fileProcessingDiagnostics = createDiagnosticCollection ( ) ;
703+ const currentDirectory = host . getCurrentDirectory ( ) ;
704+ const resolvedLibraries : Map < ResolvedLibrary > = { } ;
705+ let libraryRoot =
706+ ( options . rootDir && ts . toPath ( options . rootDir , currentDirectory , host . getCanonicalFileName ) ) ||
707+ ( options . configFilePath && getDirectoryPath ( getNormalizedAbsolutePath ( options . configFilePath , currentDirectory ) ) ) ;
708+ if ( libraryRoot === undefined ) {
709+ libraryRoot = computeCommonSourceDirectoryOfFilenames ( rootNames ) ;
710+ }
697711 const programDiagnostics = createDiagnosticCollection ( ) ;
698712
699713 let commonSourceDirectory : string ;
@@ -710,7 +724,6 @@ namespace ts {
710724 // Map storing if there is emit blocking diagnostics for given input
711725 const hasEmitBlockingDiagnostics = createFileMap < boolean > ( getCanonicalFileName ) ;
712726
713- const currentDirectory = host . getCurrentDirectory ( ) ;
714727 const resolveModuleNamesWorker = host . resolveModuleNames
715728 ? ( ( moduleNames : string [ ] , containingFile : string ) => host . resolveModuleNames ( moduleNames , containingFile ) )
716729 : ( ( moduleNames : string [ ] , containingFile : string ) => {
@@ -897,8 +910,8 @@ namespace ts {
897910 const oldResolution = getResolvedModule ( oldSourceFile , moduleNames [ i ] ) ;
898911 const resolutionChanged = oldResolution
899912 ? ! newResolution ||
900- oldResolution . resolvedFileName !== newResolution . resolvedFileName ||
901- ! ! oldResolution . isExternalLibraryImport !== ! ! newResolution . isExternalLibraryImport
913+ oldResolution . resolvedFileName !== newResolution . resolvedFileName ||
914+ ! ! oldResolution . isExternalLibraryImport !== ! ! newResolution . isExternalLibraryImport
902915 : newResolution ;
903916
904917 if ( resolutionChanged ) {
@@ -1021,9 +1034,9 @@ namespace ts {
10211034 }
10221035
10231036 function getDiagnosticsHelper (
1024- sourceFile : SourceFile ,
1025- getDiagnostics : ( sourceFile : SourceFile , cancellationToken : CancellationToken ) => Diagnostic [ ] ,
1026- cancellationToken : CancellationToken ) : Diagnostic [ ] {
1037+ sourceFile : SourceFile ,
1038+ getDiagnostics : ( sourceFile : SourceFile , cancellationToken : CancellationToken ) => Diagnostic [ ] ,
1039+ cancellationToken : CancellationToken ) : Diagnostic [ ] {
10271040 if ( sourceFile ) {
10281041 return getDiagnostics ( sourceFile , cancellationToken ) ;
10291042 }
@@ -1498,6 +1511,7 @@ namespace ts {
14981511 const basePath = getDirectoryPath ( fileName ) ;
14991512 if ( ! options . noResolve ) {
15001513 processReferencedFiles ( file , basePath , /*isDefaultLib*/ isDefaultLib ) ;
1514+ processReferencedLibraries ( file , libraryRoot ) ;
15011515 }
15021516
15031517 // always process imported modules to record module name resolutions
@@ -1521,6 +1535,97 @@ namespace ts {
15211535 } ) ;
15221536 }
15231537
1538+ function findLibraryDefinition ( searchPath : string ) {
1539+ let typingFilename = "index.d.ts" ;
1540+ const packageJsonPath = combinePaths ( searchPath , "package.json" ) ;
1541+ if ( host . fileExists ( packageJsonPath ) ) {
1542+ let package : { typings ?: string } = { } ;
1543+ try {
1544+ package = JSON . parse ( host . readFile ( packageJsonPath ) ) ;
1545+ }
1546+ catch ( e ) { }
1547+
1548+ if ( package . typings ) {
1549+ typingFilename = package . typings ;
1550+ }
1551+ }
1552+
1553+ const combinedPath = normalizePath ( combinePaths ( searchPath , typingFilename ) ) ;
1554+ return host . fileExists ( combinedPath ) ? combinedPath : undefined ;
1555+ }
1556+
1557+ function processReferencedLibraries ( file : SourceFile , compilationRoot : string ) {
1558+ const primarySearchPaths = map ( getEffectiveLibraryPrimarySearchPaths ( ) , path => combinePaths ( compilationRoot , path ) ) ;
1559+
1560+ const failedSearchPaths : string [ ] = [ ] ;
1561+ const moduleResolutionState : ModuleResolutionState = {
1562+ compilerOptions : options ,
1563+ host : host ,
1564+ skipTsx : true ,
1565+ traceEnabled : false
1566+ } ;
1567+
1568+ for ( const ref of file . referencedLibraries ) {
1569+ // If we already found this library as a primary reference, or failed to find it, nothing to do
1570+ const previousResolution = resolvedLibraries [ ref . fileName ] ;
1571+ if ( previousResolution && ( previousResolution . primary || ( previousResolution . resolvedFileName === undefined ) ) ) {
1572+ continue ;
1573+ }
1574+
1575+ let foundIt = false ;
1576+
1577+ // Check primary library paths
1578+ for ( const primaryPath of primarySearchPaths ) {
1579+ const searchPath = combinePaths ( primaryPath , ref . fileName ) ;
1580+ const resolvedFile = findLibraryDefinition ( searchPath ) ;
1581+ if ( resolvedFile ) {
1582+ resolvedLibraries [ ref . fileName ] = { primary : true , resolvedFileName : resolvedFile } ;
1583+ processSourceFile ( resolvedFile , /*isDefaultLib*/ false , /*isReference*/ true , file , ref . pos , ref . end ) ;
1584+ foundIt = true ;
1585+ break ;
1586+ }
1587+ }
1588+
1589+ // Check secondary library paths
1590+ if ( ! foundIt ) {
1591+ const secondaryResult = loadModuleFromNodeModules ( ref . fileName , file . fileName , failedSearchPaths , moduleResolutionState ) ;
1592+ if ( secondaryResult ) {
1593+ foundIt = true ;
1594+ // If we already resolved to this file, it must have been a secondary reference. Check file contents
1595+ // for sameness and possibly issue an error
1596+ if ( previousResolution ) {
1597+ const otherFileText = host . readFile ( secondaryResult ) ;
1598+ if ( otherFileText !== getSourceFile ( previousResolution . resolvedFileName ) . text ) {
1599+ fileProcessingDiagnostics . add ( createFileDiagnostic ( file , ref . pos , ref . end - ref . pos ,
1600+ Diagnostics . Conflicting_library_definitions_for_0_found_at_1_and_2_Copy_the_correct_file_to_a_local_typings_folder_to_resolve_this_conflict ,
1601+ ref . fileName ,
1602+ secondaryResult ,
1603+ previousResolution . resolvedFileName ) ) ;
1604+ }
1605+ }
1606+ else {
1607+ // First resolution of this library
1608+ resolvedLibraries [ ref . fileName ] = { primary : false , resolvedFileName : secondaryResult } ;
1609+ processSourceFile ( secondaryResult , /*isDefaultLib*/ false , /*isReference*/ true , file , ref . pos , ref . end ) ;
1610+ }
1611+ }
1612+ }
1613+
1614+ if ( ! foundIt ) {
1615+ fileProcessingDiagnostics . add ( createFileDiagnostic ( file , ref . pos , ref . end - ref . pos , Diagnostics . Cannot_find_name_0 , ref . fileName ) ) ;
1616+ // Create an entry as a primary lookup result so we don't keep doing this
1617+ resolvedLibraries [ ref . fileName ] = { primary : true , resolvedFileName : undefined } ;
1618+ }
1619+ }
1620+ }
1621+
1622+ function getEffectiveLibraryPrimarySearchPaths ( ) : Path [ ] {
1623+ return < Path [ ] > ( options . librarySearchPaths ||
1624+ ( options . configFilePath ?
1625+ [ options . configFilePath ] . concat ( defaultLibrarySearchPaths ) :
1626+ defaultLibrarySearchPaths ) ) ;
1627+ }
1628+
15241629 function getCanonicalFileName ( fileName : string ) : string {
15251630 return host . getCanonicalFileName ( fileName ) ;
15261631 }
@@ -1567,15 +1672,11 @@ namespace ts {
15671672 return ;
15681673 }
15691674
1570- function computeCommonSourceDirectory ( sourceFiles : SourceFile [ ] ) : string {
1675+ function computeCommonSourceDirectoryOfFilenames ( fileNames : string [ ] ) : string {
15711676 let commonPathComponents : string [ ] ;
1572- const failed = forEach ( files , sourceFile => {
1677+ const failed = forEach ( fileNames , sourceFile => {
15731678 // Each file contributes into common source file path
1574- if ( isDeclarationFile ( sourceFile ) ) {
1575- return ;
1576- }
1577-
1578- const sourcePathComponents = getNormalizedPathComponents ( sourceFile . fileName , currentDirectory ) ;
1679+ const sourcePathComponents = getNormalizedPathComponents ( sourceFile , currentDirectory ) ;
15791680 sourcePathComponents . pop ( ) ; // The base file name is not part of the common directory path
15801681
15811682 if ( ! commonPathComponents ) {
@@ -1615,6 +1716,16 @@ namespace ts {
16151716 return getNormalizedPathFromPathComponents ( commonPathComponents ) ;
16161717 }
16171718
1719+ function computeCommonSourceDirectory ( sourceFiles : SourceFile [ ] ) : string {
1720+ const fileNames : string [ ] = [ ] ;
1721+ for ( const file of sourceFiles ) {
1722+ if ( ! file . isDeclarationFile ) {
1723+ fileNames . push ( file . fileName ) ;
1724+ }
1725+ }
1726+ return computeCommonSourceDirectoryOfFilenames ( fileNames ) ;
1727+ }
1728+
16181729 function checkSourceFilesBelongToPath ( sourceFiles : SourceFile [ ] , rootDirectory : string ) : boolean {
16191730 let allFilesBelongToPath = true ;
16201731 if ( sourceFiles ) {
@@ -1760,7 +1871,7 @@ namespace ts {
17601871
17611872 // If we failed to find a good common directory, but outDir is specified and at least one of our files is on a windows drive/URL/other resource, add a failure
17621873 if ( options . outDir && dir === "" && forEach ( files , file => getRootLength ( file . fileName ) > 1 ) ) {
1763- programDiagnostics . add ( createCompilerDiagnostic ( Diagnostics . Cannot_find_the_common_subdirectory_path_for_the_input_files ) ) ;
1874+ programDiagnostics . add ( createCompilerDiagnostic ( Diagnostics . Cannot_find_the_common_subdirectory_path_for_the_input_files ) ) ;
17641875 }
17651876 }
17661877
0 commit comments