@@ -1066,6 +1066,16 @@ namespace ts {
10661066 let resolvedTypeReferenceDirectives : Map < ResolvedTypeReferenceDirective > = { } ;
10671067 let fileProcessingDiagnostics = createDiagnosticCollection ( ) ;
10681068
1069+ // The below settings are to track if a .js file should be add to the program if loaded via searching under node_modules.
1070+ // This works as imported modules are discovered recursively in a depth first manner, specifically:
1071+ // - For each root file, findSourceFile is called.
1072+ // - This calls processImportedModules for each module imported in the source file.
1073+ // - This calls resolveModuleNames, and then calls findSourceFile for each resolved module.
1074+ // As all these operations happen - and are nested - within the createProgram call, they close over the below variables.
1075+ // The current resolution depth is tracked by incrementing/decrementing as the depth first search progresses.
1076+ const maxNodeModulesJsDepth = options . maxNodeModuleJsDepth || 2 ;
1077+ let currentNodeModulesJsDepth = 0 ;
1078+
10691079 const start = new Date ( ) . getTime ( ) ;
10701080
10711081 host = host || createCompilerHost ( options ) ;
@@ -1869,7 +1879,7 @@ namespace ts {
18691879 }
18701880
18711881 // Get source file from normalized fileName
1872- function findSourceFile ( fileName : string , path : Path , isDefaultLib : boolean , isReference : boolean , refFile ?: SourceFile , refPos ?: number , refEnd ?: number , isFileFromNodeSearch ?: boolean ) : SourceFile {
1882+ function findSourceFile ( fileName : string , path : Path , isDefaultLib : boolean , isReference : boolean , refFile ?: SourceFile , refPos ?: number , refEnd ?: number ) : SourceFile {
18731883 if ( filesByName . contains ( path ) ) {
18741884 const file = filesByName . get ( path ) ;
18751885 // try to check if we've already seen this file but with a different casing in path
@@ -1878,12 +1888,6 @@ namespace ts {
18781888 reportFileNamesDifferOnlyInCasingError ( fileName , file . fileName , refFile , refPos , refEnd ) ;
18791889 }
18801890
1881- // If this was a file found by a node_modules search, set the nodeModuleSearchDistance to parent distance + 1.
1882- if ( isFileFromNodeSearch ) {
1883- const newDistance = ( refFile && refFile . nodeModuleSearchDistance ) === undefined ? 1 : refFile . nodeModuleSearchDistance + 1 ;
1884- // If already set on the file, don't overwrite if it was already found closer (which may be '0' if added as a root file)
1885- file . nodeModuleSearchDistance = ( typeof file . nodeModuleSearchDistance === "number" ) ? Math . min ( file . nodeModuleSearchDistance , newDistance ) : newDistance ;
1886- }
18871891 return file ;
18881892 }
18891893
@@ -1902,12 +1906,6 @@ namespace ts {
19021906 if ( file ) {
19031907 file . path = path ;
19041908
1905- // Default to same distance as parent. Add one if found by a search.
1906- file . nodeModuleSearchDistance = ( refFile && refFile . nodeModuleSearchDistance ) || 0 ;
1907- if ( isFileFromNodeSearch ) {
1908- file . nodeModuleSearchDistance ++ ;
1909- }
1910-
19111909 if ( host . useCaseSensitiveFileNames ( ) ) {
19121910 // for case-sensitive file systems check if we've already seen some file with similar filename ignoring case
19131911 const existingFile = filesByNameIgnoreCase . get ( path ) ;
@@ -2020,13 +2018,11 @@ namespace ts {
20202018 }
20212019
20222020 function processImportedModules ( file : SourceFile , basePath : string ) {
2023- const maxJsNodeModuleSearchDistance = options . maxNodeModuleJsDepth || 0 ;
20242021 collectExternalModuleReferences ( file ) ;
20252022 if ( file . imports . length || file . moduleAugmentations . length ) {
20262023 file . resolvedModules = { } ;
20272024 const moduleNames = map ( concatenate ( file . imports , file . moduleAugmentations ) , getTextOfLiteral ) ;
20282025 const resolutions = resolveModuleNamesWorker ( moduleNames , getNormalizedAbsolutePath ( file . fileName , currentDirectory ) ) ;
2029- file . nodeModuleSearchDistance = file . nodeModuleSearchDistance || 0 ;
20302026 for ( let i = 0 ; i < moduleNames . length ; i ++ ) {
20312027 const resolution = resolutions [ i ] ;
20322028 setResolvedModule ( file , moduleNames [ i ] , resolution ) ;
@@ -2035,32 +2031,24 @@ namespace ts {
20352031 // - noResolve is falsy
20362032 // - module name comes from the list of imports
20372033 // - it's not a top level JavaScript module that exceeded the search max
2038- const exceedsJsSearchDepth = resolution && resolution . isExternalLibraryImport &&
2039- hasJavaScriptFileExtension ( resolution . resolvedFileName ) &&
2040- file . nodeModuleSearchDistance >= maxJsNodeModuleSearchDistance ;
2041- const shouldAddFile = resolution && ! options . noResolve && i < file . imports . length && ! exceedsJsSearchDepth ;
2034+ let isJsFileUnderNodeModules = resolution && resolution . isExternalLibraryImport &&
2035+ hasJavaScriptFileExtension ( resolution . resolvedFileName ) ;
2036+ if ( isJsFileUnderNodeModules ) {
2037+ currentNodeModulesJsDepth ++ ;
2038+ }
2039+ const shouldAddFile = resolution && ! options . noResolve && i < file . imports . length &&
2040+ ! ( isJsFileUnderNodeModules && currentNodeModulesJsDepth > maxNodeModulesJsDepth ) ;
20422041
20432042 if ( shouldAddFile ) {
2044- // const importedFile = findSourceFile(resolution.resolvedFileName,
2045- // toPath(resolution.resolvedFileName, currentDirectory, getCanonicalFileName),
2046- // /*isDefaultLib*/ false, /*isReference*/ false,
2047- // file,
2048- // skipTrivia(file.text, file.imports[i].pos),
2049- // file.imports[i].end,
2050- // resolution.isExternalLibraryImport);
2051- //
2052- // // TODO (billti): Should we check here if a JavaScript file is a CommonJS file, or doesn't have /// references?
2053- // if (importedFile && resolution.isExternalLibraryImport && !hasJavaScriptFileExtension(importedFile.fileName)) {
2054- // if (!isExternalModule(importedFile) && importedFile.statements.length) {
2055- // const start = getTokenPosOfNode(file.imports[i], file);
2056- // fileProcessingDiagnostics.add(createFileDiagnostic(file, start, file.imports[i].end - start, Diagnostics.Exported_external_package_typings_file_0_is_not_a_module_Please_contact_the_package_author_to_update_the_package_definition, importedFile.fileName));
2057- // }
2058- // else if (importedFile.referencedFiles.length) {
2059- // const firstRef = importedFile.referencedFiles[0];
2060- // fileProcessingDiagnostics.add(createFileDiagnostic(importedFile, firstRef.pos, firstRef.end - firstRef.pos, Diagnostics.Exported_external_package_typings_file_cannot_contain_tripleslash_references_Please_contact_the_package_author_to_update_the_package_definition));
2061- // }
2062- // }
2063- findSourceFile ( resolution . resolvedFileName , toPath ( resolution . resolvedFileName , currentDirectory , getCanonicalFileName ) , /*isDefaultLib*/ false , /*isReference*/ false , file , skipTrivia ( file . text , file . imports [ i ] . pos ) , file . imports [ i ] . end ) ;
2043+ findSourceFile ( resolution . resolvedFileName ,
2044+ toPath ( resolution . resolvedFileName , currentDirectory , getCanonicalFileName ) ,
2045+ /*isDefaultLib*/ false , /*isReference*/ false ,
2046+ file ,
2047+ skipTrivia ( file . text , file . imports [ i ] . pos ) ,
2048+ file . imports [ i ] . end ) ;
2049+ }
2050+ if ( isJsFileUnderNodeModules ) {
2051+ currentNodeModulesJsDepth -- ;
20642052 }
20652053 }
20662054 }
0 commit comments