Skip to content

Commit

Permalink
[flow][match] Quickfix for invalid object pattern shorthand
Browse files Browse the repository at this point in the history
Summary:
Adds quickfixes for invalid object pattern shorthand error, one for each intended possibility.

Future work will include adding more support for match expressions/statements in the ast differ so that we get more fine-grained changes.

Changelog: [internal]

Reviewed By: panagosg7

Differential Revision: D70727295

fbshipit-source-id: d4d097cefb54ea5351f80f3169dd18d7a3259644
  • Loading branch information
gkz authored and facebook-github-bot committed Mar 7, 2025
1 parent 0e6fb6b commit 9248060
Show file tree
Hide file tree
Showing 6 changed files with 177 additions and 0 deletions.
Original file line number Diff line number Diff line change
@@ -0,0 +1,71 @@
{
"method": "textDocument/codeAction",
"result": [
{
"title": "Convert to `const foo`",
"kind": "quickfix",
"diagnostics": [],
"edit": {
"changes": {
"<PLACEHOLDER_PROJECT_URL>/fix-match-invalid-object-shorthand.js": [
{
"range": {
"start": {
"line": 4,
"character": 12
},
"end": {
"line": 7,
"character": 1
}
},
"newText": "match (x) {\n {const foo}: 0,\n _: 0,\n}"
}
]
}
},
"command": {
"title": "",
"command": "log:org.flow:<PLACEHOLDER_PROJECT_URL>",
"arguments": [
"textDocument/codeAction",
"convert_match_object_shorthand_to_const",
"Convert to `const foo`"
]
}
},
{
"title": "Convert to `foo: foo`",
"kind": "quickfix",
"diagnostics": [],
"edit": {
"changes": {
"<PLACEHOLDER_PROJECT_URL>/fix-match-invalid-object-shorthand.js": [
{
"range": {
"start": {
"line": 4,
"character": 12
},
"end": {
"line": 7,
"character": 1
}
},
"newText": "match (x) {\n {foo: foo}: 0,\n _: 0,\n}"
}
]
}
},
"command": {
"title": "",
"command": "log:org.flow:<PLACEHOLDER_PROJECT_URL>",
"arguments": [
"textDocument/codeAction",
"convert_match_object_shorthand_to_reference",
"Convert to `foo: foo`"
]
}
}
]
}
2 changes: 2 additions & 0 deletions newtests/lsp/code-action/quickfix/_flowconfig_match
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
[options]
experimental.pattern_matching=true
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
// @flow

declare const x: {foo: 1};

const out = match (x) {
{foo}: 0,
_: 0,
};
27 changes: 27 additions & 0 deletions newtests/lsp/code-action/quickfix/test.js
Original file line number Diff line number Diff line change
Expand Up @@ -1979,5 +1979,32 @@ module.exports = (suite(
['textDocument/publishDiagnostics', ...lspIgnoreStatusAndCancellation],
),
]),
test('match invalid object shorthand quickfix', [
addFile(
'fix-match-invalid-object-shorthand.js.ignored',
'fix-match-invalid-object-shorthand.js',
),
lspStartAndConnect(),
lspRequestAndWaitUntilResponse('textDocument/codeAction', {
textDocument: {
uri: '<PLACEHOLDER_PROJECT_URL>/fix-match-invalid-object-shorthand.js',
},
range: {
start: {line: 5, character: 5},
end: {line: 5, character: 5},
},
context: {
only: ['quickfix'],
diagnostics: [],
},
}).verifyLSPMessageSnapshot(
path.join(
__dirname,
'__snapshots__',
'fix-match-invalid-object-shorthand.json',
),
['textDocument/publishDiagnostics', ...lspIgnoreStatusAndCancellation],
),
]).flowConfig('_flowconfig_match'),
],
): SuiteType);
50 changes: 50 additions & 0 deletions src/services/code_action/autofix_match_syntax.ml
Original file line number Diff line number Diff line change
@@ -0,0 +1,50 @@
(*
* Copyright (c) Meta Platforms, Inc. and affiliates.
*
* This source code is licensed under the MIT license found in the
* LICENSE file in the root directory of this source tree.
*)

type kind =
| ObjShorthandToConst
| ObjShorthandToReference

class mapper target_loc ~kind =
object (this)
inherit Flow_ast_contains_mapper.mapper target_loc as super

method! match_object_pattern_property prop =
let open Flow_ast.MatchPattern.ObjectPattern in
let (loc, _) = prop in
if not @@ this#is_target loc then
super#match_object_pattern_property prop
else
match prop with
| (_, Property.Valid _) -> super#match_object_pattern_property prop
| (_, Property.InvalidShorthand id) ->
let key = Property.Identifier id in
(match kind with
| ObjShorthandToConst ->
let pattern =
( Loc.none,
Flow_ast.MatchPattern.BindingPattern
{
Flow_ast.MatchPattern.BindingPattern.kind = Flow_ast.Variable.Const;
id;
comments = None;
}
)
in
(Loc.none, Property.Valid { Property.key; pattern; shorthand = true; comments = None })
| ObjShorthandToReference ->
let pattern = (Loc.none, Flow_ast.MatchPattern.IdentifierPattern id) in
(Loc.none, Property.Valid { Property.key; pattern; shorthand = false; comments = None }))
end

let convert_object_shorthand_to_const ast loc =
let mapper = new mapper loc ~kind:ObjShorthandToConst in
mapper#program ast

let convert_object_shorthand_to_reference ast loc =
let mapper = new mapper loc ~kind:ObjShorthandToReference in
mapper#program ast
19 changes: 19 additions & 0 deletions src/services/code_action/code_action_service.ml
Original file line number Diff line number Diff line change
Expand Up @@ -1085,6 +1085,25 @@ let ast_transforms_of_error ~loc_of_aloc ?loc = function
]
else
[]
| Error_message.EMatchInvalidObjectShorthand { loc = error_loc; name } ->
if loc_opt_intersects ~error_loc ~loc then
[
{
title = Utils_js.spf "Convert to `const %s`" name;
diagnostic_title = "convert_match_object_shorthand_to_const";
transform = untyped_ast_transform Autofix_match_syntax.convert_object_shorthand_to_const;
target_loc = error_loc;
};
{
title = Utils_js.spf "Convert to `%s: %s`" name name;
diagnostic_title = "convert_match_object_shorthand_to_reference";
transform =
untyped_ast_transform Autofix_match_syntax.convert_object_shorthand_to_reference;
target_loc = error_loc;
};
]
else
[]
| error_message ->
(match error_message |> Error_message.friendly_message_of_msg with
| Error_message.PropMissing
Expand Down

0 comments on commit 9248060

Please sign in to comment.