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

Code before:
function shouldUseRequire(sourceFile: SourceFile, program: Program): boolean {
    // 1. TypeScript files don't use require variable declarations
    if (!isSourceFileJS(sourceFile)) {
        return false;
    }

    // 2. If the current source file is unambiguously CJS or ESM, go with that
    if (sourceFile.commonJsModuleIndicator && !sourceFile.externalModuleIndicator) return true;
    if (sourceFile.externalModuleIndicator && !sourceFile.commonJsModuleIndicator) return false;

    // 3. If there's a tsconfig/jsconfig, use its module setting
    const compilerOptions = program.getCompilerOptions();
    if (compilerOptions.configFile) {
        return getEmitModuleKind(compilerOptions) < ModuleKind.ES2015;
    }

    // 4. Match the first other JS file in the program that's unambiguously CJS or ESM
    for (const otherFile of program.getSourceFiles()) {
        if (otherFile === sourceFile || !isSourceFileJS(otherFile) || program.isSourceFileFromExternalLibrary(otherFile)) continue;
        if (otherFile.commonJsModuleIndicator && !otherFile.externalModuleIndicator) return true;
        if (otherFile.externalModuleIndicator && !otherFile.commonJsModuleIndicator) return false;
    }

    // 5. Literally nothing to go on
    return true;
}

function createGetChecker(program: Program, host: LanguageServiceHost) {
    return memoizeOne((isFromPackageJson: boolean) => isFromPackageJson ? host.getPackageJsonAutoImportProvider!()!.getTypeChecker() : program.getTypeChecker());
}

function getNewImportFixes(
    program: Program,
    sourceFile: SourceFile,
    usagePosition: number | undefined,
    isValidTypeOnlyUseSite: boolean,
    useRequire: boolean,
    exportInfo: readonly SymbolExportInfo[],
    host: LanguageServiceHost,
    preferences: UserPreferences,
    fromCacheOnly?: boolean,
): { computedWithoutCacheCount: number, fixes: readonly (FixAddNewImport | FixAddJsdocTypeImport)[] } {
    const isJs = isSourceFileJS(sourceFile);
    const compilerOptions = program.getCompilerOptions();
    const moduleSpecifierResolutionHost = createModuleSpecifierResolutionHost(program, host);
    const getChecker = createGetChecker(program, host);
    const moduleResolution = getEmitModuleResolutionKind(compilerOptions);
    const rejectNodeModulesRelativePaths = moduleResolutionUsesNodeModules(moduleResolution);
    const getModuleSpecifiers = fromCacheOnly
        ? (moduleSymbol: Symbol) => ({ moduleSpecifiers: moduleSpecifiers.tryGetModuleSpecifiersFromCache(moduleSymbol, sourceFile, moduleSpecifierResolutionHost, preferences), computedWithoutCache: false })
        : (moduleSymbol: Symbol, checker: TypeChecker) => moduleSpecifiers.getModuleSpecifiersWithCacheInfo(moduleSymbol, checker, compilerOptions, sourceFile, moduleSpecifierResolutionHost, preferences);

Review comment (suggestion):
when checking with other file, would it be better to check their implied node format as well to determine what this file probably is supposed to be.

Code after:
function shouldUseRequire(sourceFile: SourceFile, program: Program): boolean {
    // 1. TypeScript files don't use require variable declarations
    if (!isSourceFileJS(sourceFile)) {
        return false;
    }

    // 2. If the current source file is unambiguously CJS or ESM, go with that
    if (sourceFile.commonJsModuleIndicator && !sourceFile.externalModuleIndicator) return true;
    if (sourceFile.externalModuleIndicator && !sourceFile.commonJsModuleIndicator) return false;

    // 3. If there's a tsconfig/jsconfig, use its module setting
    const compilerOptions = program.getCompilerOptions();
    if (compilerOptions.configFile) {
        return getEmitModuleKind(compilerOptions) < ModuleKind.ES2015;
    }

    // 4. In --module nodenext, assume we're not emitting JS -> JS, so use
    //    whatever syntax Node expects based on the detected module kind
    if (sourceFile.impliedNodeFormat === ModuleKind.CommonJS) return true;
    if (sourceFile.impliedNodeFormat === ModuleKind.ESNext) return false;

    // 5. Match the first other JS file in the program that's unambiguously CJS or ESM
    for (const otherFile of program.getSourceFiles()) {
        if (otherFile === sourceFile || !isSourceFileJS(otherFile) || program.isSourceFileFromExternalLibrary(otherFile)) continue;
        if (otherFile.commonJsModuleIndicator && !otherFile.externalModuleIndicator) return true;
        if (otherFile.externalModuleIndicator && !otherFile.commonJsModuleIndicator) return false;
    }

    // 6. Literally nothing to go on
    return true;
}

function createGetChecker(program: Program, host: LanguageServiceHost) {
    return memoizeOne((isFromPackageJson: boolean) => isFromPackageJson ? host.getPackageJsonAutoImportProvider!()!.getTypeChecker() : program.getTypeChecker());
}

function getNewImportFixes(
    program: Program,
    sourceFile: SourceFile,
    usagePosition: number | undefined,
    isValidTypeOnlyUseSite: boolean,
    useRequire: boolean,
    exportInfo: readonly SymbolExportInfo[],
    host: LanguageServiceHost,
    preferences: UserPreferences,
    fromCacheOnly?: boolean,
): { computedWithoutCacheCount: number, fixes: readonly (FixAddNewImport | FixAddJsdocTypeImport)[] } {
    const isJs = isSourceFileJS(sourceFile);
    const compilerOptions = program.getCompilerOptions();
    const moduleSpecifierResolutionHost = createModuleSpecifierResolutionHost(program, host);
    const getChecker = createGetChecker(program, host);