11/* @internal */
22namespace ts . Completions . PathCompletions {
3- export function getStringLiteralCompletionEntriesFromModuleNames ( node : StringLiteral , compilerOptions : CompilerOptions , host : LanguageServiceHost , typeChecker : TypeChecker ) : CompletionInfo {
3+ export function getStringLiteralCompletionsFromModuleNames ( node : StringLiteral , compilerOptions : CompilerOptions , host : LanguageServiceHost , typeChecker : TypeChecker ) : CompletionEntry [ ] {
44 const literalValue = normalizeSlashes ( node . text ) ;
55
66 const scriptPath = node . getSourceFile ( ) . path ;
77 const scriptDirectory = getDirectoryPath ( scriptPath ) ;
88
99 const span = getDirectoryFragmentTextSpan ( ( < StringLiteral > node ) . text , node . getStart ( ) + 1 ) ;
10- let entries : CompletionEntry [ ] ;
1110 if ( isPathRelativeToScript ( literalValue ) || isRootedDiskPath ( literalValue ) ) {
1211 const extensions = getSupportedExtensions ( compilerOptions ) ;
1312 if ( compilerOptions . rootDirs ) {
14- entries = getCompletionEntriesForDirectoryFragmentWithRootDirs (
13+ return getCompletionEntriesForDirectoryFragmentWithRootDirs (
1514 compilerOptions . rootDirs , literalValue , scriptDirectory , extensions , /*includeExtensions*/ false , span , compilerOptions , host , scriptPath ) ;
1615 }
1716 else {
18- entries = getCompletionEntriesForDirectoryFragment (
17+ return getCompletionEntriesForDirectoryFragment (
1918 literalValue , scriptDirectory , extensions , /*includeExtensions*/ false , span , host , scriptPath ) ;
2019 }
2120 }
2221 else {
2322 // Check for node modules
24- entries = getCompletionEntriesForNonRelativeModules ( literalValue , scriptDirectory , span , compilerOptions , host , typeChecker ) ;
23+ return getCompletionEntriesForNonRelativeModules ( literalValue , scriptDirectory , span , compilerOptions , host , typeChecker ) ;
2524 }
26- return {
27- isGlobalCompletion : false ,
28- isMemberCompletion : false ,
29- isNewIdentifierLocation : true ,
30- entries
31- } ;
3225 }
3326
3427 /**
@@ -37,14 +30,14 @@ namespace ts.Completions.PathCompletions {
3730 */
3831 function getBaseDirectoriesFromRootDirs ( rootDirs : string [ ] , basePath : string , scriptPath : string , ignoreCase : boolean ) : string [ ] {
3932 // Make all paths absolute/normalized if they are not already
40- rootDirs = map ( rootDirs , rootDirectory => normalizePath ( isRootedDiskPath ( rootDirectory ) ? rootDirectory : combinePaths ( basePath , rootDirectory ) ) ) ;
33+ rootDirs = rootDirs . map ( rootDirectory => normalizePath ( isRootedDiskPath ( rootDirectory ) ? rootDirectory : combinePaths ( basePath , rootDirectory ) ) ) ;
4134
4235 // Determine the path to the directory containing the script relative to the root directory it is contained within
43- const relativeDirectory = forEach ( rootDirs , rootDirectory =>
36+ const relativeDirectory = firstDefined ( rootDirs , rootDirectory =>
4437 containsPath ( rootDirectory , scriptPath , basePath , ignoreCase ) ? scriptPath . substr ( rootDirectory . length ) : undefined ) ;
4538
4639 // Now find a path for each potential directory that is to be merged with the one containing the script
47- return deduplicate ( map ( rootDirs , rootDirectory => combinePaths ( rootDirectory , relativeDirectory ) ) ) ;
40+ return deduplicate ( rootDirs . map ( rootDirectory => combinePaths ( rootDirectory , relativeDirectory ) ) ) ;
4841 }
4942
5043 function getCompletionEntriesForDirectoryFragmentWithRootDirs ( rootDirs : string [ ] , fragment : string , scriptPath : string , extensions : ReadonlyArray < string > , includeExtensions : boolean , span : TextSpan , compilerOptions : CompilerOptions , host : LanguageServiceHost , exclude ?: string ) : CompletionEntry [ ] {
@@ -283,61 +276,35 @@ namespace ts.Completions.PathCompletions {
283276 return deduplicate ( nonRelativeModuleNames ) ;
284277 }
285278
286- export function getTripleSlashReferenceCompletion ( sourceFile : SourceFile , position : number , compilerOptions : CompilerOptions , host : LanguageServiceHost ) : CompletionInfo {
279+ export function getTripleSlashReferenceCompletion ( sourceFile : SourceFile , position : number , compilerOptions : CompilerOptions , host : LanguageServiceHost ) : CompletionEntry [ ] | undefined {
287280 const token = getTokenAtPosition ( sourceFile , position , /*includeJsDocComment*/ false ) ;
288- if ( ! token ) {
289- return undefined ;
290- }
291- const commentRanges : CommentRange [ ] = getLeadingCommentRanges ( sourceFile . text , token . pos ) ;
292-
293- if ( ! commentRanges || ! commentRanges . length ) {
294- return undefined ;
295- }
296-
297- const range = forEach ( commentRanges , commentRange => position >= commentRange . pos && position <= commentRange . end && commentRange ) ;
298-
281+ const commentRanges = getLeadingCommentRanges ( sourceFile . text , token . pos ) ;
282+ const range = commentRanges && find ( commentRanges , commentRange => position >= commentRange . pos && position <= commentRange . end ) ;
299283 if ( ! range ) {
300284 return undefined ;
301285 }
302-
303- const completionInfo : CompletionInfo = {
304- /**
305- * We don't want the editor to offer any other completions, such as snippets, inside a comment.
306- */
307- isGlobalCompletion : false ,
308- isMemberCompletion : false ,
309- /**
310- * The user may type in a path that doesn't yet exist, creating a "new identifier"
311- * with respect to the collection of identifiers the server is aware of.
312- */
313- isNewIdentifierLocation : true ,
314-
315- entries : [ ]
316- } ;
317-
318- const text = sourceFile . text . substr ( range . pos , position - range . pos ) ;
319-
286+ const text = sourceFile . text . slice ( range . pos , position ) ;
320287 const match = tripleSlashDirectiveFragmentRegex . exec ( text ) ;
288+ if ( ! match ) {
289+ return undefined ;
290+ }
321291
322- if ( match ) {
323- const prefix = match [ 1 ] ;
324- const kind = match [ 2 ] ;
325- const toComplete = match [ 3 ] ;
326-
327- const scriptPath = getDirectoryPath ( sourceFile . path ) ;
328- if ( kind === "path" ) {
292+ const [ , prefix , kind , toComplete ] = match ;
293+ const scriptPath = getDirectoryPath ( sourceFile . path ) ;
294+ switch ( kind ) {
295+ case "path" : {
329296 // Give completions for a relative path
330- const span : TextSpan = getDirectoryFragmentTextSpan ( toComplete , range . pos + prefix . length ) ;
331- completionInfo . entries = getCompletionEntriesForDirectoryFragment ( toComplete , scriptPath , getSupportedExtensions ( compilerOptions ) , /*includeExtensions*/ true , span , host , sourceFile . path ) ;
297+ const span = getDirectoryFragmentTextSpan ( toComplete , range . pos + prefix . length ) ;
298+ return getCompletionEntriesForDirectoryFragment ( toComplete , scriptPath , getSupportedExtensions ( compilerOptions ) , /*includeExtensions*/ true , span , host , sourceFile . path ) ;
332299 }
333- else {
300+ case "types" : {
334301 // Give completions based on the typings available
335- const span : TextSpan = { start : range . pos + prefix . length , length : match [ 0 ] . length - prefix . length } ;
336- completionInfo . entries = getCompletionEntriesFromTypings ( host , compilerOptions , scriptPath , span ) ;
302+ const span = createTextSpan ( range . pos + prefix . length , match [ 0 ] . length - prefix . length ) ;
303+ return getCompletionEntriesFromTypings ( host , compilerOptions , scriptPath , span ) ;
337304 }
305+ default :
306+ return undefined ;
338307 }
339-
340- return completionInfo ;
341308 }
342309
343310 function getCompletionEntriesFromTypings ( host : LanguageServiceHost , options : CompilerOptions , scriptPath : string , span : TextSpan , result : CompletionEntry [ ] = [ ] ) : CompletionEntry [ ] {
@@ -385,26 +352,15 @@ namespace ts.Completions.PathCompletions {
385352 }
386353 }
387354
388- function findPackageJsons ( currentDir : string , host : LanguageServiceHost ) : string [ ] {
355+ function findPackageJsons ( directory : string , host : LanguageServiceHost ) : string [ ] {
389356 const paths : string [ ] = [ ] ;
390- let currentConfigPath : string ;
391- while ( true ) {
392- currentConfigPath = findConfigFile ( currentDir , ( f ) => tryFileExists ( host , f ) , "package.json" ) ;
393- if ( currentConfigPath ) {
394- paths . push ( currentConfigPath ) ;
395-
396- currentDir = getDirectoryPath ( currentConfigPath ) ;
397- const parent = getDirectoryPath ( currentDir ) ;
398- if ( currentDir === parent ) {
399- break ;
400- }
401- currentDir = parent ;
402- }
403- else {
404- break ;
357+ forEachAncestorDirectory ( directory , ancestor => {
358+ const currentConfigPath = findConfigFile ( ancestor , ( f ) => tryFileExists ( host , f ) , "package.json" ) ;
359+ if ( ! currentConfigPath ) {
360+ return true ; // break out
405361 }
406- }
407-
362+ paths . push ( currentConfigPath ) ;
363+ } ) ;
408364 return paths ;
409365 }
410366
0 commit comments