|
1 | | -import { |
2 | | - createCodeFixAction, |
3 | | - createCombinedCodeActions, |
4 | | - createImportAdder, |
5 | | - eachDiagnostic, |
6 | | - registerCodeFix, |
7 | | - typeNodeToAutoImportableTypeNode, |
8 | | - typePredicateToAutoImportableTypeNode, |
9 | | - typeToMinimizedReferenceType, |
| 1 | +import { |
| 2 | + createCodeFixAction, |
| 3 | + createCombinedCodeActions, |
| 4 | + createImportAdder, |
| 5 | + eachDiagnostic, |
| 6 | + ImportAdder, |
| 7 | + importSymbols, |
| 8 | + registerCodeFix, |
| 9 | + tryGetAutoImportableReferenceFromTypeNode, |
| 10 | + typePredicateToAutoImportableTypeNode, |
| 11 | + typeToMinimizedReferenceType, |
10 | 12 | } from "../_namespaces/ts.codefix.js"; |
11 | 13 | import { |
12 | 14 | ArrayBindingPattern, |
@@ -38,15 +40,17 @@ import { |
38 | 40 | findAncestor, |
39 | 41 | FunctionDeclaration, |
40 | 42 | GeneratedIdentifierFlags, |
41 | | - getEmitScriptTarget, |
42 | | - getSourceFileOfNode, |
43 | | - getSynthesizedDeepClone, |
44 | | - getTokenAtPosition, |
| 43 | + getEmitScriptTarget, |
| 44 | + getNameForExportedSymbol, |
| 45 | + getSourceFileOfNode, |
| 46 | + getSynthesizedDeepClone, |
| 47 | + getTokenAtPosition, |
45 | 48 | getTrailingCommentRanges, |
46 | 49 | hasInitializer, |
47 | 50 | hasSyntacticModifier, |
48 | | - Identifier, |
49 | | - InternalNodeBuilderFlags, |
| 51 | + Identifier, |
| 52 | + ImportDeclaration, |
| 53 | + InternalNodeBuilderFlags, |
50 | 54 | isArrayBindingPattern, |
51 | 55 | isArrayLiteralExpression, |
52 | 56 | isAssertionExpression, |
@@ -80,16 +84,19 @@ import { |
80 | 84 | isValueSignatureDeclaration, |
81 | 85 | isVariableDeclaration, |
82 | 86 | ModifierFlags, |
83 | | - ModifierLike, |
84 | | - Node, |
| 87 | + ModifierLike, |
| 88 | + NamedImports, |
| 89 | + NamespaceImport, |
| 90 | + Node, |
85 | 91 | NodeBuilderFlags, |
86 | 92 | NodeFlags, |
87 | 93 | ObjectBindingPattern, |
88 | 94 | ObjectLiteralExpression, |
89 | 95 | ParameterDeclaration, |
90 | 96 | PropertyAccessExpression, |
91 | | - PropertyDeclaration, |
92 | | - setEmitFlags, |
| 97 | + PropertyDeclaration, |
| 98 | + ScriptTarget, |
| 99 | + setEmitFlags, |
93 | 100 | SignatureDeclaration, |
94 | 101 | some, |
95 | 102 | SourceFile, |
@@ -1097,22 +1104,22 @@ function withContext<T>( |
1097 | 1104 | return emptyInferenceResult; |
1098 | 1105 | } |
1099 | 1106 |
|
1100 | | - function typeToTypeNode(type: Type, enclosingDeclaration: Node, flags = NodeBuilderFlags.None): TypeNode | undefined { |
1101 | | - let isTruncated = false; |
1102 | | - const minimizedTypeNode = typeToMinimizedReferenceType(typeChecker, type, enclosingDeclaration, declarationEmitNodeBuilderFlags | flags, declarationEmitInternalNodeBuilderFlags, { |
1103 | | - moduleResolverHost: program, |
1104 | | - trackSymbol() { |
1105 | | - return true; |
1106 | | - }, |
1107 | | - reportTruncationError() { |
1108 | | - isTruncated = true; |
1109 | | - }, |
1110 | | - }); |
1111 | | - if (!minimizedTypeNode) { |
1112 | | - return undefined; |
1113 | | - } |
1114 | | - const result = typeNodeToAutoImportableTypeNode(minimizedTypeNode, importAdder, scriptTarget); |
1115 | | - return isTruncated ? factory.createKeywordTypeNode(SyntaxKind.AnyKeyword) : result; |
| 1107 | + function typeToTypeNode(type: Type, enclosingDeclaration: Node, flags = NodeBuilderFlags.None): TypeNode | undefined { |
| 1108 | + let isTruncated = false; |
| 1109 | + const minimizedTypeNode = typeToMinimizedReferenceType(typeChecker, type, enclosingDeclaration, declarationEmitNodeBuilderFlags | flags, declarationEmitInternalNodeBuilderFlags, { |
| 1110 | + moduleResolverHost: program, |
| 1111 | + trackSymbol() { |
| 1112 | + return true; |
| 1113 | + }, |
| 1114 | + reportTruncationError() { |
| 1115 | + isTruncated = true; |
| 1116 | + }, |
| 1117 | + }); |
| 1118 | + if (!minimizedTypeNode) { |
| 1119 | + return undefined; |
| 1120 | + } |
| 1121 | + const result = typeNodeToAutoImportableTypeNodeWithExistingImportCheck(minimizedTypeNode, importAdder, scriptTarget, sourceFile, typeChecker); |
| 1122 | + return isTruncated ? factory.createKeywordTypeNode(SyntaxKind.AnyKeyword) : result; |
1116 | 1123 | } |
1117 | 1124 |
|
1118 | 1125 | function typePredicateToTypeNode(typePredicate: TypePredicate, enclosingDeclaration: Node, flags = NodeBuilderFlags.None): TypeNode | undefined { |
@@ -1142,14 +1149,66 @@ function withContext<T>( |
1142 | 1149 | } |
1143 | 1150 | } |
1144 | 1151 |
|
1145 | | - function typeToStringForDiag(node: Node) { |
1146 | | - setEmitFlags(node, EmitFlags.SingleLine); |
1147 | | - const result = typePrinter.printNode(EmitHint.Unspecified, node, sourceFile); |
1148 | | - if (result.length > defaultMaximumTruncationLength) { |
1149 | | - return result.substring(0, defaultMaximumTruncationLength - "...".length) + "..."; |
1150 | | - } |
1151 | | - setEmitFlags(node, EmitFlags.None); |
1152 | | - return result; |
| 1152 | + function typeToStringForDiag(node: Node) { |
| 1153 | + setEmitFlags(node, EmitFlags.SingleLine); |
| 1154 | + const result = typePrinter.printNode(EmitHint.Unspecified, node, sourceFile); |
| 1155 | + if (result.length > defaultMaximumTruncationLength) { |
| 1156 | + return result.substring(0, defaultMaximumTruncationLength - "...".length) + "..."; |
| 1157 | + } |
| 1158 | + setEmitFlags(node, EmitFlags.None); |
| 1159 | + return result; |
| 1160 | + } |
| 1161 | + |
| 1162 | + function typeNodeToAutoImportableTypeNodeWithExistingImportCheck(typeNode: TypeNode, importAdder: ImportAdder, scriptTarget: ScriptTarget, sourceFile: SourceFile, typeChecker: TypeChecker): TypeNode | undefined { |
| 1163 | + const importableReference = tryGetAutoImportableReferenceFromTypeNode(typeNode, scriptTarget); |
| 1164 | + if (importableReference) { |
| 1165 | + // Check if symbols are already available before importing them |
| 1166 | + const symbolsToImport = importableReference.symbols.filter(symbol => { |
| 1167 | + const symbolName = getNameForExportedSymbol(symbol, scriptTarget); |
| 1168 | + return !isSymbolAlreadyAvailable(symbolName, sourceFile, typeChecker); |
| 1169 | + }); |
| 1170 | + |
| 1171 | + if (symbolsToImport.length > 0) { |
| 1172 | + importSymbols(importAdder, symbolsToImport); |
| 1173 | + } |
| 1174 | + typeNode = importableReference.typeNode; |
| 1175 | + } |
| 1176 | + |
| 1177 | + // Ensure nodes are fresh so they can have different positions when going through formatting. |
| 1178 | + return getSynthesizedDeepClone(typeNode); |
| 1179 | + } |
| 1180 | + |
| 1181 | + function isSymbolAlreadyAvailable(symbolName: string, sourceFile: SourceFile, _typeChecker: TypeChecker): boolean { |
| 1182 | + // Check if the symbol name is already imported in the current file |
| 1183 | + for (const statement of sourceFile.statements) { |
| 1184 | + if (statement.kind === SyntaxKind.ImportDeclaration) { |
| 1185 | + const importDecl = statement as ImportDeclaration; |
| 1186 | + if (importDecl.importClause) { |
| 1187 | + // Check default import |
| 1188 | + if (importDecl.importClause.name && importDecl.importClause.name.text === symbolName) { |
| 1189 | + return true; |
| 1190 | + } |
| 1191 | + // Check named imports |
| 1192 | + if (importDecl.importClause.namedBindings && importDecl.importClause.namedBindings.kind === SyntaxKind.NamedImports) { |
| 1193 | + const namedImports = importDecl.importClause.namedBindings; |
| 1194 | + for (const element of namedImports.elements) { |
| 1195 | + const name = element.name.text; |
| 1196 | + if (name === symbolName) { |
| 1197 | + return true; |
| 1198 | + } |
| 1199 | + } |
| 1200 | + } |
| 1201 | + // Check namespace import |
| 1202 | + if (importDecl.importClause.namedBindings && importDecl.importClause.namedBindings.kind === SyntaxKind.NamespaceImport) { |
| 1203 | + const namespaceImport = importDecl.importClause.namedBindings; |
| 1204 | + if (namespaceImport.name.text === symbolName) { |
| 1205 | + return true; |
| 1206 | + } |
| 1207 | + } |
| 1208 | + } |
| 1209 | + } |
| 1210 | + } |
| 1211 | + return false; |
1153 | 1212 | } |
1154 | 1213 |
|
1155 | 1214 | // Some --isolatedDeclarations errors are not present on the node that directly needs type annotation, so look in the |
|
0 commit comments