Repository: microsoft/TypeScript
File: src/services/stringCompletions.ts (TypeScript)

Code before:
    const ambientModulesExtensions = !typeChecker ? [] : mapDefined(typeChecker.getAmbientModules(),
        module => {
            const name = module.name.slice(1, -1);
            if (!name.startsWith("*.") || name.includes("/")) return;
            return name.slice(1);
        }
    );

    const extensions = [...getSupportedExtensions(compilerOptions), ambientModulesExtensions];
    const moduleResolution = getEmitModuleResolutionKind(compilerOptions);
    return moduleResolutionUsesNodeModules(moduleResolution) ?
        getSupportedExtensionsWithJsonIfResolveJsonModule(compilerOptions, extensions) :
        extensions;
}

/**
 * Takes a script path and returns paths for all potential folders that could be merged with its
 * containing folder via the "rootDirs" compiler option
 */
function getBaseDirectoriesFromRootDirs(rootDirs: string[], basePath: string, scriptDirectory: string, ignoreCase: boolean): readonly string[] {
    // Make all paths absolute/normalized if they are not already
    rootDirs = rootDirs.map(rootDirectory => normalizePath(isRootedDiskPath(rootDirectory) ? rootDirectory : combinePaths(basePath, rootDirectory)));

    // Determine the path to the directory containing the script relative to the root directory it is contained within
    const relativeDirectory = firstDefined(rootDirs, rootDirectory =>
        containsPath(rootDirectory, scriptDirectory, basePath, ignoreCase) ? scriptDirectory.substr(rootDirectory.length + 1) : undefined)!; // TODO: GH#18217

    // Now find a path for each potential directory that is to be merged with the one containing the script
    return deduplicate<string>(
        [...rootDirs.map(rootDirectory => combinePaths(rootDirectory, relativeDirectory)), scriptDirectory],
        equateStringsCaseSensitive,
        compareStringsCaseSensitive);
}

function getCompletionEntriesForDirectoryFragmentWithRootDirs(rootDirs: string[], fragment: string, scriptDirectory: string, extensionOptions: ExtensionOptions, compilerOptions: CompilerOptions, host: LanguageServiceHost, exclude: string): readonly NameAndKind[] {
    const basePath = compilerOptions.project || host.getCurrentDirectory();
    const ignoreCase = !(host.useCaseSensitiveFileNames && host.useCaseSensitiveFileNames());
    const baseDirectories = getBaseDirectoriesFromRootDirs(rootDirs, basePath, scriptDirectory, ignoreCase);
    return flatMap(baseDirectories, baseDirectory => arrayFrom(getCompletionEntriesForDirectoryFragment(fragment, baseDirectory, extensionOptions, host, /*moduleSpecifierIsRelative*/ true, exclude).values()));
}

const enum ReferenceKind {
    Filename,
    ModuleSpecifier,
}
/**
 * Given a path ending at a directory, gets the completions for the path, and filters for those entries containing the basename.
 */
function getCompletionEntriesForDirectoryFragment(
    fragment: string,
    scriptDirectory: string,

Review comment (bug):
Just doing "+1" isnt correct because this will fail when rootDirs is : `[/repo/src/,/repo/generated/]`

```ts
/// <reference path='fourslash.ts' />

// Should give correct completions for directories when invoked from within nested folders

// @rootDirs: /repo/src/,/repo/generated/

// @Filename: /dir/secret_file.ts
//// /*secret_file*/

// @Filename: /repo/src/dir/test.ts
//// import * as foo1 from ".//*import_as*/
//// import foo2 = require(".//*import_equals*/
//// var foo3 = require(".//*require*/

// @Filename: /repo/generated/dir/f.ts
//// /*f*/

verify.completions(
    {
        marker: ["import_as", "import_equals", "require"],
        exact: ["f"],
        isNewIdentifierLocation: true,
    }
);
```


Code after:
        endingPreference: preferences?.importModuleSpecifierEnding,
        resolutionMode,
    };
}
function getCompletionEntriesForRelativeModules(literalValue: string, scriptDirectory: string, compilerOptions: CompilerOptions, host: LanguageServiceHost, scriptPath: Path, extensionOptions: ExtensionOptions) {
    if (compilerOptions.rootDirs) {
        return getCompletionEntriesForDirectoryFragmentWithRootDirs(
            compilerOptions.rootDirs,
            literalValue,
            scriptDirectory,
            extensionOptions,
            compilerOptions,
            host,
            scriptPath,
        );
    }
    else {
        return arrayFrom(getCompletionEntriesForDirectoryFragment(literalValue, scriptDirectory, extensionOptions, host, /*moduleSpecifierIsRelative*/ true, scriptPath).values());
    }
}

function getSupportedExtensionsForModuleResolution(compilerOptions: CompilerOptions, typeChecker?: TypeChecker): readonly string[][] {
    /** file extensions from ambient modules declarations e.g. *.css */
    const ambientModulesExtensions = !typeChecker ? [] : mapDefined(typeChecker.getAmbientModules(), module => {
        const name = module.name.slice(1, -1);
        if (!name.startsWith("*.") || name.includes("/")) return;
        return name.slice(1);
    });

    const extensions = [...getSupportedExtensions(compilerOptions), ambientModulesExtensions];
    const moduleResolution = getEmitModuleResolutionKind(compilerOptions);
    return moduleResolutionUsesNodeModules(moduleResolution) ?
        getSupportedExtensionsWithJsonIfResolveJsonModule(compilerOptions, extensions) :
        extensions;
}

/**
 * Takes a script path and returns paths for all potential folders that could be merged with its
 * containing folder via the "rootDirs" compiler option
 */
function getBaseDirectoriesFromRootDirs(rootDirs: string[], basePath: string, scriptDirectory: string, ignoreCase: boolean): readonly string[] {
    // Make all paths absolute/normalized if they are not already
    rootDirs = rootDirs.map(rootDirectory => ensureTrailingDirectorySeparator(normalizePath(isRootedDiskPath(rootDirectory) ? rootDirectory : combinePaths(basePath, rootDirectory))));

    // Determine the path to the directory containing the script relative to the root directory it is contained within
    const relativeDirectory = firstDefined(rootDirs, rootDirectory => containsPath(rootDirectory, scriptDirectory, basePath, ignoreCase) ? scriptDirectory.substr(rootDirectory.length) : undefined)!; // TODO: GH#18217

    // Now find a path for each potential directory that is to be merged with the one containing the script
    return deduplicate<string>(
        [...rootDirs.map(rootDirectory => combinePaths(rootDirectory, relativeDirectory)), scriptDirectory].map(baseDir => removeTrailingDirectorySeparator(baseDir)),
        equateStringsCaseSensitive,