ruby-lsp-rails-factory-bot 0.2.0 → 0.3.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 28d0eed4aef05099e03470f4aae508ad687ce937db3d080289e5acf44d71b4a1
4
- data.tar.gz: cfa4ac0edb00841d67a6052a90ecea3c0649420fbe7acc00dcf0d1df0aca8651
3
+ metadata.gz: 01d1b4f936612100587a05ace6ca2c46fd654484c7d1125245e3c3afd7ce2fb2
4
+ data.tar.gz: cd15946860a27dbaa31ba14b8f429c5afb7f4bd21a9eeb1aca0f01411006bebf
5
5
  SHA512:
6
- metadata.gz: 69904e9e37c3a82cbc7f6c098d8c0c72fce15ae5e4c6a6cbf4a596d60b178be7e1577411776c191605ba0d359aef7c685dffc30ba756111f006b9b3873a44489
7
- data.tar.gz: bbaf4f6cad8a9e394b423c6c49a029fcd768543473e1165676780813e588de3d5518020bd1f0c9b0d1a11cea7d2cd2502e18ad5b0b4e8b90da6700774e639032
6
+ metadata.gz: e09bd8301b1003c30ba6efdba15c6c945f4f0ca0adbda81e8f290bcf4a0dff480c1c482e28499a5477d80a656a358018788a6a5022441da8698c940272089e2c
7
+ data.tar.gz: 3b145ca533d21b291cd545dde273f4c6f333ea255beca536c01f44e488b02a813d4beab114a4d4269b3c0add785b020df3cc875777d28183b2f338a7005a38df
data/README.md CHANGED
@@ -20,6 +20,24 @@ Hover over an attribute or factory definition
20
20
 
21
21
  ![lsp-factory-bot-hover](https://github.com/user-attachments/assets/6f570288-3cf3-4d12-acf9-71c86e834cd8)
22
22
 
23
+ Receive completion suggestions as you type
24
+
25
+ ![lsp-factory-bot-completion](https://github.com/user-attachments/assets/4255a86a-8f36-4de2-8d10-8cb5a3f49e50)
26
+
27
+ ### Supports
28
+
29
+ | | Hover | Completion | Go to definition |
30
+ | ------------- |-------------| -----| ----|
31
+ | Factory name | ✅ | ⭕️ | ❌ |
32
+ | Trait | ✅ | ⭕️ | ❌ |
33
+ | Attribute | ✅ | ✅ | ❌ |
34
+
35
+ Notes:
36
+
37
+ - The extension has "understanding" of factory/trait completion items, but due to limitations on when ruby-lsp displays the completion suggestions, they aren't visible for Symbols (eg. factory/trait names) :/ though they happen to be visible for symbols in Hash/Kw notation (ie with `:` after - `key: ...`)
38
+ - Go to definition not supported yet but might come soon
39
+
40
+
23
41
  ## Development
24
42
 
25
43
  After checking out the repo, run `bin/setup` to install dependencies. You can also run `bin/console` for an interactive prompt that will allow you to experiment.
@@ -27,15 +27,10 @@ module RubyLsp
27
27
  FactoryBot::ADDON_NAME
28
28
  end
29
29
 
30
- # def create_completion_listener(response_builder, node_context, dispatcher, uri)
31
- # path = uri.to_standardized_path
32
- # return unless path&.end_with?("_test.rb") || path&.end_with?("_spec.rb")
33
- # return unless factory_bot_call_args?(node_context)
34
-
35
- # ensure_addon_registered!
36
-
37
- # Completion.new(response_builder, node_context, dispatcher, runner_client)
38
- # end
30
+ def create_completion_listener(response_builder, node_context, dispatcher, _uri)
31
+ register_addon!
32
+ Completion.new(response_builder, node_context, dispatcher, runner_client)
33
+ end
39
34
 
40
35
  # TODO: need URI param to be able to filter by file name
41
36
  def create_hover_listener(response_builder, node_context, dispatcher)
@@ -75,18 +70,6 @@ module RubyLsp
75
70
  @rails_addon.rails_runner_client
76
71
  end
77
72
 
78
- FACTORY_BOT_METHODS = %i[
79
- create
80
- build
81
- build_stubbed
82
- attributes_for
83
- ].flat_map { |attr| [attr, :"#{attr}_list", :"#{attr}_pair"] }.freeze
84
-
85
- def factory_bot_call_args?(node_context)
86
- node_context.call_node && FACTORY_BOT_METHODS.include?(node_context.call_node.name)
87
- true
88
- end
89
-
90
73
  def log(msg)
91
74
  return if !@outgoing_queue || @outgoing_queue.closed?
92
75
 
@@ -8,11 +8,7 @@ module RubyLsp
8
8
  module Rails
9
9
  module FactoryBot
10
10
  # The listener that is created when the user requests autocomplete at the relevant time.
11
- #
12
- # NOTE: autocompletion is only triggered on certain node types - almost exclusively call nodes
13
- # and constants IIRC, so you cannot currently receive autocomplete options for symbols (eg.
14
- # factory or trait names) :/
15
- class Completion
11
+ class Completion # rubocop:disable Metrics/ClassLength
16
12
  include RubyLsp::Requests::Support::Common
17
13
 
18
14
  def initialize(response_builder, node_context, dispatcher, server_client)
@@ -24,10 +20,12 @@ module RubyLsp
24
20
  end
25
21
 
26
22
  def on_call_node_enter(node)
27
- return unless FactoryBot::FACTORY_BOT_METHODS.include?(node.name) ||
28
- FactoryBot::FACTORY_BOT_METHODS.include?(@node_context.parent.name)
23
+ call_node = @node_context.call_node
24
+ return unless call_node
29
25
 
30
- process_arguments_pattern(node, node.arguments)
26
+ return unless FactoryBot::FACTORY_BOT_METHODS.include?(call_node.name)
27
+
28
+ process_arguments_pattern(node, call_node.arguments&.arguments)
31
29
  rescue StandardError => e
32
30
  $stderr.write(e, e.backtrace)
33
31
  end
@@ -40,26 +38,50 @@ module RubyLsp
40
38
  handle_factory(factory_name_node, node_string_value(factory_name_node))
41
39
 
42
40
  in [Prism::SymbolNode => factory_name_node, *, Prism::SymbolNode => trait_node]
43
- handle_trait(node_string_value(factory_name_node), node, node_string_value(trait_node))
41
+ already_used_traits = gather_already_used_traits(arguments)
42
+ handle_trait(
43
+ node_string_value(factory_name_node), node, already_used_traits, node_string_value(trait_node),
44
+ )
44
45
 
45
46
  in [Prism::SymbolNode => _factory_name_node, *, Prism::KeywordHashNode => _kw_node] |
46
47
  [Prism::SymbolNode => _factory_name_node, *, Prism::HashNode => _kw_node] |
47
48
  [Prism::SymbolNode => _factory_name_node, *, Prism::CallNode => _call_node]
48
49
 
49
- attr_name = _call_node ? _call_node.message : _kw_node.elements.last.key.value&.to_s
50
- handle_attribute(node_string_value(_factory_name_node), node, attr_name)
50
+ attr_name = node_string_value(_call_node || _kw_node.elements.last.key)
51
+ already_used_attrs = gather_already_used_attrs(_kw_node)
52
+ handle_attribute(node_string_value(_factory_name_node), node, already_used_attrs, attr_name)
51
53
  else
52
54
  nil
53
55
  end
54
56
  end
55
57
 
56
58
  def node_string_value(node)
57
- node.value.to_s
59
+ case node
60
+ when Prism::CallNode
61
+ node.name.to_s
62
+ when Prism::SymbolNode
63
+ node.value.to_s
64
+ when nil
65
+ ""
66
+ end
67
+ end
68
+
69
+ def gather_already_used_attrs(kw_node)
70
+ attrs = Set.new
71
+ return attrs unless kw_node
72
+
73
+ kw_node.elements.each do |e|
74
+ attrs.add(node_string_value(e.key))
75
+ end
76
+
77
+ attrs
58
78
  end
59
79
 
60
- def handle_attribute(factory_name, node, value = "")
80
+ def handle_attribute(factory_name, node, already_used_attrs, value = "")
61
81
  range = range_from_node(node)
62
82
  make_request(:attributes, factory_name: factory_name, name: value)&.each do |attr|
83
+ next if already_used_attrs.member?(attr[:name].to_s)
84
+
63
85
  label_details = Interface::CompletionItemLabelDetails.new(description: attr[:type])
64
86
 
65
87
  @response_builder << serialise_attribute(attr[:name], label_details, attr[:owner], range)
@@ -77,24 +99,39 @@ module RubyLsp
77
99
  )
78
100
  end
79
101
 
80
- def handle_trait(factory_name, node, value = "")
102
+ def gather_already_used_traits(arguments)
103
+ trait_names = Set.new
104
+ # skip the first one because it's factory name
105
+ 1.upto(arguments.length - 1) do |i|
106
+ arg = arguments[i]
107
+ next if arg.is_a?(Prism::IntegerNode)
108
+ break unless arg.is_a?(Prism::SymbolNode)
109
+
110
+ trait_names.add(arg.value.to_s)
111
+ end
112
+ trait_names
113
+ end
114
+
115
+ def handle_trait(factory_name, node, already_used_traits, value = "")
81
116
  make_request(:traits, factory_name: factory_name, name: value)&.each do |tr|
117
+ next if already_used_traits.member?(tr[:name].to_s)
118
+
82
119
  label_details = Interface::CompletionItemLabelDetails.new(description: tr[:owner])
83
120
  range = range_from_node(node)
84
121
  name = tr[:name]
85
122
 
86
- @response_builder << serialise_trait(name, range, label_details)
123
+ @response_builder << serialise_trait(name, range, label_details, tr[:owner])
87
124
  end
88
125
  end
89
126
 
90
- def serialise_trait(name, range, label_details)
127
+ def serialise_trait(name, range, label_details, owner)
91
128
  Interface::CompletionItem.new(
92
129
  label: name,
93
130
  filter_text: name,
94
131
  label_details: label_details,
95
132
  text_edit: Interface::TextEdit.new(range: range, new_text: name),
96
133
  kind: Constant::CompletionItemKind::PROPERTY,
97
- data: { owner_name: nil, guessed_type: tr[:owner] },
134
+ data: { owner_name: nil, guessed_type: owner },
98
135
  )
99
136
  end
100
137
 
@@ -3,7 +3,7 @@
3
3
  module RubyLsp
4
4
  module Rails
5
5
  module FactoryBot
6
- VERSION = "0.2.0"
6
+ VERSION = "0.3.0"
7
7
  REQUIRED_RUBY_LSP_RAILS_VERSION = "~> 0.4"
8
8
  end
9
9
  end
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: ruby-lsp-rails-factory-bot
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.2.0
4
+ version: 0.3.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - johansenja
8
8
  autorequire:
9
9
  bindir: exe
10
10
  cert_chain: []
11
- date: 2025-02-20 00:00:00.000000000 Z
11
+ date: 2025-02-21 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: factory_bot