• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1/* @internal */
2namespace ts.codefix {
3    const errorCodes = [Diagnostics.This_import_is_never_used_as_a_value_and_must_use_import_type_because_importsNotUsedAsValues_is_set_to_error.code];
4    const fixId = "convertToTypeOnlyImport";
5    registerCodeFix({
6        errorCodes,
7        getCodeActions: function getCodeActionsToConvertToTypeOnlyImport(context) {
8            const changes = textChanges.ChangeTracker.with(context, t => {
9                const importDeclaration = getImportDeclarationForDiagnosticSpan(context.span, context.sourceFile);
10                fixSingleImportDeclaration(t, importDeclaration, context);
11            });
12            if (changes.length) {
13                return [createCodeFixAction(fixId, changes, Diagnostics.Convert_to_type_only_import, fixId, Diagnostics.Convert_all_imports_not_used_as_a_value_to_type_only_imports)];
14            }
15        },
16        fixIds: [fixId],
17        getAllCodeActions: function getAllCodeActionsToConvertToTypeOnlyImport(context) {
18            return codeFixAll(context, errorCodes, (changes, diag) => {
19                const importDeclaration = getImportDeclarationForDiagnosticSpan(diag, context.sourceFile);
20                fixSingleImportDeclaration(changes, importDeclaration, context);
21            });
22        }
23    });
24
25    function getImportDeclarationForDiagnosticSpan(span: TextSpan, sourceFile: SourceFile) {
26        return tryCast(getTokenAtPosition(sourceFile, span.start).parent, isImportDeclaration);
27    }
28
29    function fixSingleImportDeclaration(changes: textChanges.ChangeTracker, importDeclaration: ImportDeclaration | undefined, context: CodeFixContextBase) {
30        if (!importDeclaration?.importClause) {
31            return;
32        }
33
34        const { importClause } = importDeclaration;
35        // `changes.insertModifierBefore` produces a range that might overlap further changes
36        changes.insertText(context.sourceFile, importDeclaration.getStart() + "import".length, " type");
37
38        // `import type foo, { Bar }` is not allowed, so move `foo` to new declaration
39        if (importClause.name && importClause.namedBindings) {
40            changes.deleteNodeRangeExcludingEnd(context.sourceFile, importClause.name, importDeclaration.importClause.namedBindings);
41            changes.insertNodeBefore(context.sourceFile, importDeclaration, factory.updateImportDeclaration(
42                importDeclaration,
43                /*modifiers*/ undefined,
44                factory.createImportClause(
45                    /*isTypeOnly*/ true,
46                    importClause.name,
47                    /*namedBindings*/ undefined),
48                importDeclaration.moduleSpecifier,
49                /*assertClause*/ undefined));
50        }
51    }
52}
53