• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1/* @internal */
2namespace ts.codefix {
3    const fixName = "fixCannotFindModule";
4    const fixIdInstallTypesPackage = "installTypesPackage";
5
6    const errorCodeCannotFindModule = Diagnostics.Cannot_find_module_0_or_its_corresponding_type_declarations.code;
7    const errorCodes = [
8        errorCodeCannotFindModule,
9        Diagnostics.Could_not_find_a_declaration_file_for_module_0_1_implicitly_has_an_any_type.code,
10    ];
11    registerCodeFix({
12        errorCodes,
13        getCodeActions: context => {
14            const { host, sourceFile, span: { start } } = context;
15            const packageName = tryGetImportedPackageName(sourceFile, start);
16            if (packageName === undefined) return undefined;
17            const typesPackageName = getTypesPackageNameToInstall(packageName, host, context.errorCode);
18            return typesPackageName === undefined
19                ? []
20                : [createCodeFixAction(fixName, /*changes*/ [], [Diagnostics.Install_0, typesPackageName], fixIdInstallTypesPackage, Diagnostics.Install_all_missing_types_packages, getInstallCommand(sourceFile.fileName, typesPackageName))];
21        },
22        fixIds: [fixIdInstallTypesPackage],
23        getAllCodeActions: context => {
24            return codeFixAll(context, errorCodes, (_changes, diag, commands) => {
25                const packageName = tryGetImportedPackageName(diag.file, diag.start);
26                if (packageName === undefined) return undefined;
27                switch (context.fixId) {
28                    case fixIdInstallTypesPackage: {
29                        const pkg = getTypesPackageNameToInstall(packageName, context.host, diag.code);
30                        if (pkg) {
31                            commands.push(getInstallCommand(diag.file.fileName, pkg));
32                        }
33                        break;
34                    }
35                    default:
36                        Debug.fail(`Bad fixId: ${context.fixId}`);
37                }
38            });
39        },
40    });
41
42    function getInstallCommand(fileName: string, packageName: string): InstallPackageAction {
43        return { type: "install package", file: fileName, packageName };
44    }
45
46    function tryGetImportedPackageName(sourceFile: SourceFile, pos: number): string | undefined {
47        const moduleName = cast(getTokenAtPosition(sourceFile, pos), isStringLiteral).text;
48        const { packageName } = parsePackageName(moduleName);
49        return isExternalModuleNameRelative(packageName) ? undefined : packageName;
50    }
51
52    function getTypesPackageNameToInstall(packageName: string, host: LanguageServiceHost, diagCode: number): string | undefined {
53        return diagCode === errorCodeCannotFindModule
54            ? (JsTyping.nodeCoreModules.has(packageName) ? "@types/node" : undefined)
55            : (host.isKnownTypesPackageName?.(packageName) ? getTypesPackageName(packageName) : undefined);
56    }
57}
58