• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1/* @internal */
2namespace ts.codefix {
3    const fixName = "invalidImportSyntax";
4
5    function getCodeFixesForImportDeclaration(context: CodeFixContext, node: ImportDeclaration): CodeFixAction[] {
6        const sourceFile = getSourceFileOfNode(node);
7        const namespace = getNamespaceDeclarationNode(node) as NamespaceImport;
8        const opts = context.program.getCompilerOptions();
9        const variations: CodeFixAction[] = [];
10
11        // import Bluebird from "bluebird";
12        variations.push(createAction(context, sourceFile, node, makeImport(namespace.name, /*namedImports*/ undefined, node.moduleSpecifier, getQuotePreference(sourceFile, context.preferences))));
13
14        if (getEmitModuleKind(opts) === ModuleKind.CommonJS) {
15            // import Bluebird = require("bluebird");
16            variations.push(createAction(context, sourceFile, node, factory.createImportEqualsDeclaration(
17                /*decorators*/ undefined,
18                /*modifiers*/ undefined,
19                /*isTypeOnly*/ false,
20                namespace.name,
21                factory.createExternalModuleReference(node.moduleSpecifier)
22            )));
23        }
24
25        return variations;
26    }
27
28    function createAction(context: CodeFixContext, sourceFile: SourceFile, node: Node, replacement: Node): CodeFixAction {
29        const changes = textChanges.ChangeTracker.with(context, t => t.replaceNode(sourceFile, node, replacement));
30        return createCodeFixActionWithoutFixAll(fixName, changes, [Diagnostics.Replace_import_with_0, changes[0].textChanges[0].newText]);
31    }
32
33    registerCodeFix({
34        errorCodes: [
35            Diagnostics.This_expression_is_not_callable.code,
36            Diagnostics.This_expression_is_not_constructable.code,
37        ],
38        getCodeActions: getActionsForUsageOfInvalidImport
39    });
40
41    function getActionsForUsageOfInvalidImport(context: CodeFixContext): CodeFixAction[] | undefined {
42        const sourceFile = context.sourceFile;
43        const targetKind = Diagnostics.This_expression_is_not_callable.code === context.errorCode ? SyntaxKind.CallExpression : SyntaxKind.NewExpression;
44        const node = findAncestor(getTokenAtPosition(sourceFile, context.span.start), a => a.kind === targetKind) as CallExpression | NewExpression;
45        if (!node) {
46            return [];
47        }
48        const expr = node.expression;
49        return getImportCodeFixesForExpression(context, expr);
50    }
51
52    registerCodeFix({
53        errorCodes: [
54            // The following error codes cover pretty much all assignability errors that could involve an expression
55            Diagnostics.Argument_of_type_0_is_not_assignable_to_parameter_of_type_1.code,
56            Diagnostics.Type_0_does_not_satisfy_the_constraint_1.code,
57            Diagnostics.Type_0_is_not_assignable_to_type_1.code,
58            Diagnostics.Type_0_is_not_assignable_to_type_1_Two_different_types_with_this_name_exist_but_they_are_unrelated.code,
59            Diagnostics.Type_predicate_0_is_not_assignable_to_1.code,
60            Diagnostics.Property_0_of_type_1_is_not_assignable_to_string_index_type_2.code,
61            Diagnostics.Property_0_of_type_1_is_not_assignable_to_numeric_index_type_2.code,
62            Diagnostics.Numeric_index_type_0_is_not_assignable_to_string_index_type_1.code,
63            Diagnostics.Property_0_in_type_1_is_not_assignable_to_the_same_property_in_base_type_2.code,
64            Diagnostics.Property_0_in_type_1_is_not_assignable_to_type_2.code,
65            Diagnostics.Property_0_of_JSX_spread_attribute_is_not_assignable_to_target_property.code,
66            Diagnostics.The_this_context_of_type_0_is_not_assignable_to_method_s_this_of_type_1.code,
67        ],
68        getCodeActions: getActionsForInvalidImportLocation
69    });
70
71    function getActionsForInvalidImportLocation(context: CodeFixContext): CodeFixAction[] | undefined {
72        const sourceFile = context.sourceFile;
73        const node = findAncestor(getTokenAtPosition(sourceFile, context.span.start), a => a.getStart() === context.span.start && a.getEnd() === (context.span.start + context.span.length));
74        if (!node) {
75            return [];
76        }
77        return getImportCodeFixesForExpression(context, node);
78    }
79
80    function getImportCodeFixesForExpression(context: CodeFixContext, expr: Node): CodeFixAction[] | undefined {
81        const type = context.program.getTypeChecker().getTypeAtLocation(expr);
82        if (!(type.symbol && (type.symbol as TransientSymbol).originatingImport)) {
83            return [];
84        }
85        const fixes: CodeFixAction[] = [];
86        const relatedImport = (type.symbol as TransientSymbol).originatingImport!; // TODO: GH#18217
87        if (!isImportCall(relatedImport)) {
88            addRange(fixes, getCodeFixesForImportDeclaration(context, relatedImport));
89        }
90        if (isExpression(expr) && !(isNamedDeclaration(expr.parent) && expr.parent.name === expr)) {
91            const sourceFile = context.sourceFile;
92            const changes = textChanges.ChangeTracker.with(context, t => t.replaceNode(sourceFile, expr, factory.createPropertyAccessExpression(expr, "default"), {}));
93            fixes.push(createCodeFixActionWithoutFixAll(fixName, changes, Diagnostics.Use_synthetic_default_member));
94        }
95        return fixes;
96    }
97}
98