@@ -11,14 +11,15 @@ namespace ts.codefix {
11
11
Diagnostics . Property_0_is_missing_in_type_1_but_required_in_type_2 . code ,
12
12
Diagnostics . Type_0_is_missing_the_following_properties_from_type_1_Colon_2 . code ,
13
13
Diagnostics . Type_0_is_missing_the_following_properties_from_type_1_Colon_2_and_3_more . code ,
14
+ Diagnostics . Argument_of_type_0_is_not_assignable_to_parameter_of_type_1 . code ,
14
15
Diagnostics . Cannot_find_name_0 . code
15
16
] ;
16
17
17
18
registerCodeFix ( {
18
19
errorCodes,
19
20
getCodeActions ( context ) {
20
21
const typeChecker = context . program . getTypeChecker ( ) ;
21
- const info = getInfo ( context . sourceFile , context . span . start , typeChecker , context . program ) ;
22
+ const info = getInfo ( context . sourceFile , context . span . start , context . errorCode , typeChecker , context . program ) ;
22
23
if ( ! info ) {
23
24
return undefined ;
24
25
}
@@ -49,7 +50,7 @@ namespace ts.codefix {
49
50
50
51
return createCombinedCodeActions ( textChanges . ChangeTracker . with ( context , changes => {
51
52
eachDiagnostic ( context , errorCodes , diag => {
52
- const info = getInfo ( diag . file , diag . start , checker , context . program ) ;
53
+ const info = getInfo ( diag . file , diag . start , diag . code , checker , context . program ) ;
53
54
if ( ! info || ! addToSeen ( seen , getNodeId ( info . parentDeclaration ) + "#" + info . token . text ) ) {
54
55
return ;
55
56
}
@@ -139,6 +140,7 @@ namespace ts.codefix {
139
140
readonly token : Identifier ;
140
141
readonly properties : Symbol [ ] ;
141
142
readonly parentDeclaration : ObjectLiteralExpression ;
143
+ readonly indentation ?: number ;
142
144
}
143
145
144
146
interface JsxAttributesInfo {
@@ -148,21 +150,34 @@ namespace ts.codefix {
148
150
readonly parentDeclaration : JsxOpeningLikeElement ;
149
151
}
150
152
151
- function getInfo ( sourceFile : SourceFile , tokenPos : number , checker : TypeChecker , program : Program ) : Info | undefined {
153
+ function getInfo ( sourceFile : SourceFile , tokenPos : number , errorCode : number , checker : TypeChecker , program : Program ) : Info | undefined {
152
154
// The identifier of the missing property. eg:
153
155
// this.missing = 1;
154
156
// ^^^^^^^
155
157
const token = getTokenAtPosition ( sourceFile , tokenPos ) ;
156
- if ( ! isIdentifier ( token ) && ! isPrivateIdentifier ( token ) ) {
157
- return undefined ;
158
+ const parent = token . parent ;
159
+
160
+ if ( errorCode === Diagnostics . Argument_of_type_0_is_not_assignable_to_parameter_of_type_1 . code ) {
161
+ if ( ! ( token . kind === SyntaxKind . OpenBraceToken && isObjectLiteralExpression ( parent ) && isCallExpression ( parent . parent ) ) ) return undefined ;
162
+
163
+ const argIndex = findIndex ( parent . parent . arguments , arg => arg === parent ) ;
164
+ if ( argIndex < 0 ) return undefined ;
165
+
166
+ const signature = singleOrUndefined ( checker . getSignaturesOfType ( checker . getTypeAtLocation ( parent . parent . expression ) , SignatureKind . Call ) ) ;
167
+ if ( ! ( signature && signature . declaration && signature . parameters [ argIndex ] ) ) return undefined ;
168
+
169
+ const param = signature . parameters [ argIndex ] . valueDeclaration ;
170
+ if ( ! ( param && isParameter ( param ) && isIdentifier ( param . name ) ) ) return undefined ;
171
+
172
+ const properties = arrayFrom ( checker . getUnmatchedProperties ( checker . getTypeAtLocation ( parent ) , checker . getTypeAtLocation ( param ) , /* requireOptionalProperties */ false , /* matchDiscriminantProperties */ false ) ) ;
173
+ return length ( properties ) ? { kind : InfoKind . ObjectLiteral , token : param . name , properties, indentation : 0 , parentDeclaration : parent } : undefined ; ;
158
174
}
159
175
160
- const { parent } = token ;
176
+ if ( ! isMemberName ( token ) ) return undefined ;
177
+
161
178
if ( isIdentifier ( token ) && hasInitializer ( parent ) && parent . initializer && isObjectLiteralExpression ( parent . initializer ) ) {
162
179
const properties = arrayFrom ( checker . getUnmatchedProperties ( checker . getTypeAtLocation ( parent . initializer ) , checker . getTypeAtLocation ( token ) , /* requireOptionalProperties */ false , /* matchDiscriminantProperties */ false ) ) ;
163
- if ( length ( properties ) ) {
164
- return { kind : InfoKind . ObjectLiteral , token, properties, parentDeclaration : parent . initializer } ;
165
- }
180
+ return length ( properties ) ? { kind : InfoKind . ObjectLiteral , token, properties, indentation : undefined , parentDeclaration : parent . initializer } : undefined ;
166
181
}
167
182
168
183
if ( isIdentifier ( token ) && isJsxOpeningLikeElement ( token . parent ) ) {
@@ -176,15 +191,11 @@ namespace ts.codefix {
176
191
return { kind : InfoKind . Function , token, call : parent , sourceFile, modifierFlags : ModifierFlags . None , parentDeclaration : sourceFile } ;
177
192
}
178
193
179
- if ( ! isPropertyAccessExpression ( parent ) ) {
180
- return undefined ;
181
- }
194
+ if ( ! isPropertyAccessExpression ( parent ) ) return undefined ;
182
195
183
196
const leftExpressionType = skipConstraint ( checker . getTypeAtLocation ( parent . expression ) ) ;
184
- const { symbol } = leftExpressionType ;
185
- if ( ! symbol || ! symbol . declarations ) {
186
- return undefined ;
187
- }
197
+ const symbol = leftExpressionType . symbol ;
198
+ if ( ! symbol || ! symbol . declarations ) return undefined ;
188
199
189
200
if ( isIdentifier ( token ) && isCallExpression ( parent . parent ) ) {
190
201
const moduleDeclaration = find ( symbol . declarations , isModuleDeclaration ) ;
@@ -194,9 +205,7 @@ namespace ts.codefix {
194
205
}
195
206
196
207
const moduleSourceFile = find ( symbol . declarations , isSourceFile ) ;
197
- if ( sourceFile . commonJsModuleIndicator ) {
198
- return ;
199
- }
208
+ if ( sourceFile . commonJsModuleIndicator ) return undefined ;
200
209
201
210
if ( moduleSourceFile && ! isSourceFileFromLibrary ( program , moduleSourceFile ) ) {
202
211
return { kind : InfoKind . Function , token, call : parent . parent , sourceFile : moduleSourceFile , modifierFlags : ModifierFlags . Export , parentDeclaration : moduleSourceFile } ;
@@ -205,17 +214,13 @@ namespace ts.codefix {
205
214
206
215
const classDeclaration = find ( symbol . declarations , isClassLike ) ;
207
216
// Don't suggest adding private identifiers to anything other than a class.
208
- if ( ! classDeclaration && isPrivateIdentifier ( token ) ) {
209
- return undefined ;
210
- }
217
+ if ( ! classDeclaration && isPrivateIdentifier ( token ) ) return undefined ;
211
218
212
219
// Prefer to change the class instead of the interface if they are merged
213
220
const classOrInterface = classDeclaration || find ( symbol . declarations , isInterfaceDeclaration ) ;
214
221
if ( classOrInterface && ! isSourceFileFromLibrary ( program , classOrInterface . getSourceFile ( ) ) ) {
215
222
const makeStatic = ( ( leftExpressionType as TypeReference ) . target || leftExpressionType ) !== checker . getDeclaredTypeOfSymbol ( symbol ) ;
216
- if ( makeStatic && ( isPrivateIdentifier ( token ) || isInterfaceDeclaration ( classOrInterface ) ) ) {
217
- return undefined ;
218
- }
223
+ if ( makeStatic && ( isPrivateIdentifier ( token ) || isInterfaceDeclaration ( classOrInterface ) ) ) return undefined ;
219
224
220
225
const declSourceFile = classOrInterface . getSourceFile ( ) ;
221
226
const modifierFlags = ( makeStatic ? ModifierFlags . Static : 0 ) | ( startsWithUnderscore ( token . text ) ? ModifierFlags . Private : 0 ) ;
@@ -475,7 +480,12 @@ namespace ts.codefix {
475
480
const initializer = prop . valueDeclaration ? tryGetValueFromType ( context , checker , importAdder , quotePreference , checker . getTypeAtLocation ( prop . valueDeclaration ) ) : createUndefined ( ) ;
476
481
return factory . createPropertyAssignment ( prop . name , initializer ) ;
477
482
} ) ;
478
- changes . replaceNode ( context . sourceFile , info . parentDeclaration , factory . createObjectLiteralExpression ( [ ...info . parentDeclaration . properties , ...props ] , /*multiLine*/ true ) ) ;
483
+ const options = {
484
+ leadingTriviaOption : textChanges . LeadingTriviaOption . Exclude ,
485
+ trailingTriviaOption : textChanges . TrailingTriviaOption . Exclude ,
486
+ indentation : info . indentation
487
+ } ;
488
+ changes . replaceNode ( context . sourceFile , info . parentDeclaration , factory . createObjectLiteralExpression ( [ ...info . parentDeclaration . properties , ...props ] , /*multiLine*/ true ) , options ) ;
479
489
}
480
490
481
491
function tryGetValueFromType ( context : CodeFixContextBase , checker : TypeChecker , importAdder : ImportAdder , quotePreference : QuotePreference , type : Type ) : Expression {
0 commit comments