ruby-lsp-ree 0.1.6 → 0.1.8
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 +4 -4
- data/CHANGELOG.md +15 -0
- data/Gemfile.lock +1 -1
- data/lib/ruby_lsp/ruby_lsp_ree/formatters/base_formatter.rb +13 -0
- data/lib/ruby_lsp/ruby_lsp_ree/formatters/missing_error_contracts_formatter.rb +53 -0
- data/lib/ruby_lsp/ruby_lsp_ree/formatters/missing_error_definitions_formatter.rb +54 -0
- data/lib/ruby_lsp/ruby_lsp_ree/formatters/missing_error_locales_formatter.rb +84 -0
- data/lib/ruby_lsp/ruby_lsp_ree/formatters/sort_links_formatter.rb +51 -0
- data/lib/ruby_lsp/ruby_lsp_ree/handlers/definition_handler.rb +65 -1
- data/lib/ruby_lsp/ruby_lsp_ree/handlers/hover_handler.rb +83 -0
- data/lib/ruby_lsp/ruby_lsp_ree/listeners/definition_listener.rb +14 -2
- data/lib/ruby_lsp/ruby_lsp_ree/listeners/hover_listener.rb +18 -1
- data/lib/ruby_lsp/ruby_lsp_ree/parsing/parsed_document.rb +56 -1
- data/lib/ruby_lsp/ruby_lsp_ree/parsing/parsed_document_builder.rb +3 -3
- data/lib/ruby_lsp/ruby_lsp_ree/parsing/parsed_method_node.rb +115 -0
- data/lib/ruby_lsp/ruby_lsp_ree/ree_context.rb +28 -0
- data/lib/ruby_lsp/ruby_lsp_ree/ree_formatter.rb +55 -34
- data/lib/ruby_lsp/ruby_lsp_ree/ree_object_finder.rb +11 -0
- data/lib/ruby_lsp/ruby_lsp_ree/utils/ree_locale_utils.rb +40 -0
- data/lib/ruby_lsp/ruby_lsp_ree/utils/ree_lsp_utils.rb +12 -1
- data/lib/ruby_lsp/ruby_lsp_ree/utils/yaml_file_parser.rb +53 -0
- data/lib/ruby_lsp_ree/version.rb +1 -1
- metadata +11 -2
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: ccc9c39cc6ca44feeb3c8c5369e259a790dc01c02a0aecf9a14eee2d19e65015
|
4
|
+
data.tar.gz: 61233b0b379f7ab994f102fc748e2ef54eed53e605017bb0d28793ea160a45d7
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 07cf2e0c6c6670f5405a967e7fffe9af19af8a29dc55d33afef3b9dd0f231df826a0cd11d4e5b91ad23b7348635107c0186a7bb8b878bce00d9a480710267608
|
7
|
+
data.tar.gz: 5a5bcdf420fe934e46ec0b0318c6325cd5c6a0753ca18ea73a8188f54dc19a1c7abd6b3e41a777fb4f0a8b6f6bf83c8fd015226ceb21ee54c8228264874f0aaf
|
data/CHANGELOG.md
CHANGED
@@ -1,3 +1,18 @@
|
|
1
|
+
## [0.1.8] - 2025-03-21
|
2
|
+
|
3
|
+
- hover: show missing locales
|
4
|
+
- formatter: add raised error definition if missing
|
5
|
+
- formatter: add placeholder for missing locale
|
6
|
+
- formatter: improved adding raised errors into contract throw section
|
7
|
+
- Go To Definition: improved location for error locales
|
8
|
+
- Go To Definition: got to missing locale placeholder
|
9
|
+
|
10
|
+
## [0.1.7] - 2025-03-14
|
11
|
+
|
12
|
+
- Go To Definition for ree errors into locales
|
13
|
+
- hover for ree error locales
|
14
|
+
- formatter: add raised ree errors to `throws` section
|
15
|
+
|
1
16
|
## [0.1.6] - 2025-03-04
|
2
17
|
|
3
18
|
- file rename triggers class name change
|
data/Gemfile.lock
CHANGED
@@ -0,0 +1,53 @@
|
|
1
|
+
require_relative 'base_formatter'
|
2
|
+
|
3
|
+
module RubyLsp
|
4
|
+
module Ree
|
5
|
+
class MissingErrorContractsFormatter < BaseFormatter
|
6
|
+
def call(source, _uri)
|
7
|
+
parsed_doc = RubyLsp::Ree::ParsedDocumentBuilder.build_from_source(source)
|
8
|
+
return source if !parsed_doc || !parsed_doc.class_node
|
9
|
+
|
10
|
+
parsed_doc.parse_error_definitions
|
11
|
+
parsed_doc.parse_instance_methods
|
12
|
+
|
13
|
+
parsed_doc.doc_instance_methods.select(&:has_contract?).each do |doc_instance_method|
|
14
|
+
doc_instance_method.parse_nested_local_methods(parsed_doc.doc_instance_methods)
|
15
|
+
|
16
|
+
raised_errors = doc_instance_method.raised_errors_nested
|
17
|
+
throws_errors = doc_instance_method.throws_errors
|
18
|
+
|
19
|
+
missed_errors = raised_errors - throws_errors
|
20
|
+
source = add_missed_errors(source, doc_instance_method, missed_errors)
|
21
|
+
end
|
22
|
+
|
23
|
+
source
|
24
|
+
end
|
25
|
+
|
26
|
+
private
|
27
|
+
|
28
|
+
def add_missed_errors(source, doc_instance_method, missed_errors)
|
29
|
+
return source if missed_errors.size == 0
|
30
|
+
|
31
|
+
source_lines = source.lines
|
32
|
+
|
33
|
+
if doc_instance_method.has_throw_section?
|
34
|
+
position = doc_instance_method.throw_arguments_end_position
|
35
|
+
line = doc_instance_method.throw_arguments_end_line
|
36
|
+
|
37
|
+
if source_lines[line].strip.end_with?(")")
|
38
|
+
source_lines[line] = source_lines[line][0..position] + ", #{missed_errors.join(', ')})\n"
|
39
|
+
else
|
40
|
+
source_lines[line] = source_lines[line][0..position] + ", #{missed_errors.join(', ')}\n"
|
41
|
+
end
|
42
|
+
else
|
43
|
+
position = doc_instance_method.contract_node_end_position
|
44
|
+
line = doc_instance_method.contract_node_end_line
|
45
|
+
|
46
|
+
source_lines[line] = source_lines[line][0..position] + ".throws(#{missed_errors.join(', ')})\n"
|
47
|
+
end
|
48
|
+
|
49
|
+
source_lines.join
|
50
|
+
end
|
51
|
+
end
|
52
|
+
end
|
53
|
+
end
|
@@ -0,0 +1,54 @@
|
|
1
|
+
require_relative 'base_formatter'
|
2
|
+
|
3
|
+
module RubyLsp
|
4
|
+
module Ree
|
5
|
+
class MissingErrorDefinitionsFormatter < BaseFormatter
|
6
|
+
include RubyLsp::Ree::ReeLspUtils
|
7
|
+
|
8
|
+
def call(source, _uri)
|
9
|
+
parsed_doc = RubyLsp::Ree::ParsedDocumentBuilder.build_from_source(source)
|
10
|
+
return source if !parsed_doc || !parsed_doc.class_node
|
11
|
+
|
12
|
+
parsed_doc.parse_error_definitions
|
13
|
+
parsed_doc.parse_instance_methods
|
14
|
+
parsed_doc.parse_links
|
15
|
+
|
16
|
+
existing_errors = parsed_doc.error_definition_names + parsed_doc.imported_constants
|
17
|
+
|
18
|
+
missed_errors = []
|
19
|
+
parsed_doc.doc_instance_methods.each do |doc_instance_method|
|
20
|
+
doc_instance_method.parse_nested_local_methods(parsed_doc.doc_instance_methods)
|
21
|
+
|
22
|
+
raised_errors = doc_instance_method.raised_errors_nested
|
23
|
+
|
24
|
+
missed_errors += raised_errors - existing_errors
|
25
|
+
end
|
26
|
+
|
27
|
+
missed_errors = missed_errors.uniq.reject{ Object.const_defined?(_1) }
|
28
|
+
|
29
|
+
add_missed_error_definitions(source, parsed_doc, missed_errors.uniq)
|
30
|
+
end
|
31
|
+
|
32
|
+
private
|
33
|
+
|
34
|
+
def add_missed_error_definitions(source, parsed_doc, missed_errors)
|
35
|
+
return source if missed_errors.size == 0
|
36
|
+
|
37
|
+
source_lines = source.lines
|
38
|
+
|
39
|
+
if parsed_doc.error_definitions.size > 0
|
40
|
+
change_line = parsed_doc.error_definitions.map{ _1.location.start_line }.max - 1
|
41
|
+
else
|
42
|
+
change_line = parsed_doc.links_container_node.location.end_line - 1
|
43
|
+
source_lines[change_line] += "\n"
|
44
|
+
end
|
45
|
+
|
46
|
+
missed_errors.each do |err|
|
47
|
+
source_lines[change_line] += "\s\s#{err} = invalid_param_error(:#{underscore(err)})\n"
|
48
|
+
end
|
49
|
+
|
50
|
+
source_lines.join
|
51
|
+
end
|
52
|
+
end
|
53
|
+
end
|
54
|
+
end
|
@@ -0,0 +1,84 @@
|
|
1
|
+
require_relative 'base_formatter'
|
2
|
+
|
3
|
+
module RubyLsp
|
4
|
+
module Ree
|
5
|
+
class MissingErrorLocalesFormatter < BaseFormatter
|
6
|
+
include RubyLsp::Ree::ReeLspUtils
|
7
|
+
include RubyLsp::Ree::ReeLocaleUtils
|
8
|
+
|
9
|
+
MISSING_LOCALE_PLACEHOLDER = '_MISSING_LOCALE_'
|
10
|
+
|
11
|
+
def call(source, uri)
|
12
|
+
parsed_doc = RubyLsp::Ree::ParsedDocumentBuilder.build_from_source(source)
|
13
|
+
|
14
|
+
locales_folder = package_locales_folder_path(URI.parse(uri.to_s).path)
|
15
|
+
return source if !locales_folder || !File.directory?(locales_folder)
|
16
|
+
|
17
|
+
result = []
|
18
|
+
key_paths = []
|
19
|
+
parsed_doc.parse_error_definitions
|
20
|
+
parsed_doc.error_definitions.each do |error_definition|
|
21
|
+
key_path = if error_definition.value.arguments.arguments.size > 1
|
22
|
+
error_definition.value.arguments.arguments[1].unescaped
|
23
|
+
else
|
24
|
+
mod = underscore(parsed_doc.module_name)
|
25
|
+
"#{mod}.errors.#{error_definition.value.arguments.arguments[0].unescaped}"
|
26
|
+
end
|
27
|
+
|
28
|
+
key_paths << key_path
|
29
|
+
end
|
30
|
+
|
31
|
+
Dir.glob(File.join(locales_folder, '**/*.yml')).each do |locale_file|
|
32
|
+
key_paths.each do |key_path|
|
33
|
+
value = find_locale_value(locale_file, key_path)
|
34
|
+
unless value
|
35
|
+
loc_key = File.basename(locale_file, '.yml')
|
36
|
+
|
37
|
+
add_locale_placeholder(locale_file, key_path)
|
38
|
+
end
|
39
|
+
end
|
40
|
+
end
|
41
|
+
|
42
|
+
source
|
43
|
+
end
|
44
|
+
|
45
|
+
private
|
46
|
+
|
47
|
+
def add_locale_placeholder(file_path, key_path)
|
48
|
+
loc_key = File.basename(file_path, '.yml')
|
49
|
+
key_parts = [loc_key] + key_path.split('.')
|
50
|
+
|
51
|
+
last_found_index = 0
|
52
|
+
last_found_key = nil
|
53
|
+
current_node = YamlFileParser.parse_with_key_coordinates(file_path)
|
54
|
+
|
55
|
+
key_parts.each_with_index do |key_part, index|
|
56
|
+
found_key, next_node = YamlFileParser.find_key_in_node(current_node, key_part)
|
57
|
+
|
58
|
+
break unless found_key
|
59
|
+
|
60
|
+
current_node = next_node
|
61
|
+
last_found_index = index
|
62
|
+
last_found_key = found_key
|
63
|
+
end
|
64
|
+
|
65
|
+
missed_key_parts = key_parts[last_found_index+1..-1]
|
66
|
+
|
67
|
+
identation = last_found_key.column
|
68
|
+
adding_string = ''
|
69
|
+
missed_key_parts.each_with_index do |key_part, index|
|
70
|
+
identation += 2
|
71
|
+
if index == missed_key_parts.size - 1
|
72
|
+
adding_string += "\s" * identation + "#{key_part}: #{MISSING_LOCALE_PLACEHOLDER}\n"
|
73
|
+
else
|
74
|
+
adding_string += "\s" * identation + "#{key_part}:\n"
|
75
|
+
end
|
76
|
+
end
|
77
|
+
|
78
|
+
lines = File.read(file_path).lines
|
79
|
+
lines[last_found_key.line] += adding_string
|
80
|
+
File.write(file_path, lines.join)
|
81
|
+
end
|
82
|
+
end
|
83
|
+
end
|
84
|
+
end
|
@@ -0,0 +1,51 @@
|
|
1
|
+
require_relative 'base_formatter'
|
2
|
+
|
3
|
+
module RubyLsp
|
4
|
+
module Ree
|
5
|
+
class SortLinksFormatter < BaseFormatter
|
6
|
+
def call(source, _uri)
|
7
|
+
parsed_doc = RubyLsp::Ree::ParsedDocumentBuilder.build_from_source(source)
|
8
|
+
return source if !parsed_doc || !parsed_doc.link_nodes&.any?
|
9
|
+
|
10
|
+
if parsed_doc.link_nodes.any?{ _1.location.start_line != _1.location.end_line }
|
11
|
+
$stderr.puts("multiline link definitions, don't sort")
|
12
|
+
return source
|
13
|
+
end
|
14
|
+
|
15
|
+
# sort link nodes
|
16
|
+
sorted_link_nodes = parsed_doc.link_nodes.sort{ |a, b|
|
17
|
+
a_name = a.node.arguments.arguments.first
|
18
|
+
b_name = b.node.arguments.arguments.first
|
19
|
+
|
20
|
+
if a_name.is_a?(Prism::SymbolNode) && !b_name.is_a?(Prism::SymbolNode)
|
21
|
+
-1
|
22
|
+
elsif b_name.is_a?(Prism::SymbolNode) && !a_name.is_a?(Prism::SymbolNode)
|
23
|
+
1
|
24
|
+
else
|
25
|
+
a_name.unescaped <=> b_name.unescaped
|
26
|
+
end
|
27
|
+
}
|
28
|
+
|
29
|
+
# check if no re-order
|
30
|
+
if parsed_doc.link_nodes.map{ _1.node.arguments.arguments.first.unescaped } == sorted_link_nodes.map{ _1.node.arguments.arguments.first.unescaped }
|
31
|
+
return source
|
32
|
+
end
|
33
|
+
|
34
|
+
# insert nodes to source
|
35
|
+
link_lines = parsed_doc.link_nodes.map{ _1.location.start_line }
|
36
|
+
|
37
|
+
source_lines = source.lines
|
38
|
+
|
39
|
+
sorted_lines = sorted_link_nodes.map do |sorted_link|
|
40
|
+
source_lines[sorted_link.location.start_line - 1]
|
41
|
+
end
|
42
|
+
|
43
|
+
link_lines.each_with_index do |link_line, index|
|
44
|
+
source_lines[link_line - 1] = sorted_lines[index]
|
45
|
+
end
|
46
|
+
|
47
|
+
source_lines.join()
|
48
|
+
end
|
49
|
+
end
|
50
|
+
end
|
51
|
+
end
|
@@ -2,17 +2,20 @@ require_relative "../utils/ree_lsp_utils"
|
|
2
2
|
require_relative "../ree_object_finder"
|
3
3
|
require_relative "../parsing/parsed_link_node"
|
4
4
|
require_relative "../parsing/parsed_document_builder"
|
5
|
+
require_relative "../utils/ree_locale_utils"
|
5
6
|
|
6
7
|
module RubyLsp
|
7
8
|
module Ree
|
8
9
|
class DefinitionHandler
|
9
10
|
include Requests::Support::Common
|
10
11
|
include RubyLsp::Ree::ReeLspUtils
|
12
|
+
include RubyLsp::Ree::ReeLocaleUtils
|
11
13
|
|
12
14
|
def initialize(index, uri, node_context)
|
13
15
|
@index = index
|
14
16
|
@uri = uri
|
15
17
|
@node_context = node_context
|
18
|
+
@root_node = @node_context.instance_variable_get(:@nesting_nodes).first
|
16
19
|
@finder = ReeObjectFinder.new(@index)
|
17
20
|
end
|
18
21
|
|
@@ -71,7 +74,15 @@ module RubyLsp
|
|
71
74
|
message = node.message
|
72
75
|
result = []
|
73
76
|
|
74
|
-
|
77
|
+
parsed_doc = RubyLsp::Ree::ParsedDocumentBuilder.build_from_ast(@root_node, @uri)
|
78
|
+
link_node = parsed_doc.find_link_node(message)
|
79
|
+
|
80
|
+
definition_item = if link_node
|
81
|
+
@finder.find_object_for_package(message, link_node.link_package_name)
|
82
|
+
else
|
83
|
+
@finder.find_object(message)
|
84
|
+
end
|
85
|
+
|
75
86
|
return [] unless definition_item
|
76
87
|
|
77
88
|
definition_uri = definition_item.uri.to_s
|
@@ -127,6 +138,59 @@ module RubyLsp
|
|
127
138
|
),
|
128
139
|
)
|
129
140
|
end
|
141
|
+
|
142
|
+
def get_error_locales_definition_items(node)
|
143
|
+
locales_folder = package_locales_folder_path(@uri.path)
|
144
|
+
|
145
|
+
return [] unless File.directory?(locales_folder)
|
146
|
+
|
147
|
+
result = []
|
148
|
+
key_path = node.unescaped
|
149
|
+
|
150
|
+
Dir.glob(File.join(locales_folder, '**/*.yml')).each do |locale_file|
|
151
|
+
location = find_locale_key_location(locale_file, key_path)
|
152
|
+
|
153
|
+
result << Interface::Location.new(
|
154
|
+
uri: locale_file,
|
155
|
+
range: Interface::Range.new(
|
156
|
+
start: Interface::Position.new(line: location.line, character: location.column),
|
157
|
+
end: Interface::Position.new(line: location.line, character: location.column),
|
158
|
+
),
|
159
|
+
)
|
160
|
+
end
|
161
|
+
|
162
|
+
result
|
163
|
+
end
|
164
|
+
|
165
|
+
def get_error_code_definition_items(node)
|
166
|
+
locales_folder = package_locales_folder_path(@uri.path)
|
167
|
+
return [] unless File.directory?(locales_folder)
|
168
|
+
|
169
|
+
result = []
|
170
|
+
|
171
|
+
key_path = if @node_context.parent.arguments.arguments.size > 1
|
172
|
+
@node_context.parent.arguments.arguments[1].unescaped
|
173
|
+
else
|
174
|
+
parsed_doc = RubyLsp::Ree::ParsedDocumentBuilder.build_from_ast(@root_node, @uri)
|
175
|
+
|
176
|
+
mod = underscore(parsed_doc.module_name)
|
177
|
+
"#{mod}.errors.#{node.unescaped}"
|
178
|
+
end
|
179
|
+
|
180
|
+
Dir.glob(File.join(locales_folder, '**/*.yml')).each do |locale_file|
|
181
|
+
location = find_locale_key_location(locale_file, key_path)
|
182
|
+
|
183
|
+
result << Interface::Location.new(
|
184
|
+
uri: locale_file,
|
185
|
+
range: Interface::Range.new(
|
186
|
+
start: Interface::Position.new(line: location.line, character: location.column),
|
187
|
+
end: Interface::Position.new(line: location.line, character: location.column),
|
188
|
+
),
|
189
|
+
)
|
190
|
+
end
|
191
|
+
|
192
|
+
result
|
193
|
+
end
|
130
194
|
end
|
131
195
|
end
|
132
196
|
end
|
@@ -2,17 +2,22 @@ require_relative "../ree_object_finder"
|
|
2
2
|
require_relative "../parsing/parsed_document_builder"
|
3
3
|
require_relative "../parsing/parsed_link_node"
|
4
4
|
require_relative "../utils/ree_lsp_utils"
|
5
|
+
require_relative "../utils/ree_locale_utils"
|
5
6
|
|
6
7
|
module RubyLsp
|
7
8
|
module Ree
|
8
9
|
class HoverHandler
|
9
10
|
include Requests::Support::Common
|
10
11
|
include RubyLsp::Ree::ReeLspUtils
|
12
|
+
include RubyLsp::Ree::ReeLocaleUtils
|
13
|
+
|
14
|
+
MISSING_LOCALE_PLACEHOLDER = '_MISSING_LOCALE_'
|
11
15
|
|
12
16
|
def initialize(index, node_context)
|
13
17
|
@index = index
|
14
18
|
@node_context = node_context
|
15
19
|
@finder = ReeObjectFinder.new(@index)
|
20
|
+
@root_node = @node_context.instance_variable_get(:@nesting_nodes).first
|
16
21
|
end
|
17
22
|
|
18
23
|
def get_ree_object_hover_items(node)
|
@@ -61,6 +66,84 @@ module RubyLsp
|
|
61
66
|
|
62
67
|
signature.parameters.map(&:decorated_name).join(', ')
|
63
68
|
end
|
69
|
+
|
70
|
+
def get_error_locales_hover_items(node)
|
71
|
+
parsed_doc = RubyLsp::Ree::ParsedDocumentBuilder.build_from_ast(@root_node, nil)
|
72
|
+
uri = get_uri_from_object(parsed_doc)
|
73
|
+
|
74
|
+
locales_folder = package_locales_folder_path(uri.path)
|
75
|
+
return [] unless File.directory?(locales_folder)
|
76
|
+
|
77
|
+
result = []
|
78
|
+
key_path = node.unescaped
|
79
|
+
|
80
|
+
documentation = ''
|
81
|
+
|
82
|
+
Dir.glob(File.join(locales_folder, '**/*.yml')).each do |locale_file|
|
83
|
+
value = find_locale_value(locale_file, key_path)
|
84
|
+
loc_key = File.basename(locale_file, '.yml')
|
85
|
+
|
86
|
+
if value
|
87
|
+
if value == MISSING_LOCALE_PLACEHOLDER
|
88
|
+
value_location = find_locale_key_location(locale_file, key_path)
|
89
|
+
file_uri = "#{locale_file}" # TODO add line to uri :#{value_location.line+1}:#{value_location.column}"
|
90
|
+
documentation += "#{loc_key}: [#{value}](#{file_uri})\n\n"
|
91
|
+
else
|
92
|
+
documentation += "#{loc_key}: #{value}\n\n"
|
93
|
+
end
|
94
|
+
else
|
95
|
+
documentation += "#{loc_key}: [MISSING TRANSLATION](#{locale_file})\n\n"
|
96
|
+
end
|
97
|
+
end
|
98
|
+
|
99
|
+
[documentation]
|
100
|
+
end
|
101
|
+
|
102
|
+
def get_error_code_hover_items(node)
|
103
|
+
parsed_doc = RubyLsp::Ree::ParsedDocumentBuilder.build_from_ast(@root_node, nil)
|
104
|
+
uri = get_uri_from_object(parsed_doc)
|
105
|
+
|
106
|
+
locales_folder = package_locales_folder_path(uri.path)
|
107
|
+
return [] unless File.directory?(locales_folder)
|
108
|
+
|
109
|
+
result = []
|
110
|
+
|
111
|
+
key_path = if @node_context.parent.arguments.arguments.size > 1
|
112
|
+
@node_context.parent.arguments.arguments[1].unescaped
|
113
|
+
else
|
114
|
+
mod = underscore(parsed_doc.module_name)
|
115
|
+
"#{mod}.errors.#{node.unescaped}"
|
116
|
+
end
|
117
|
+
|
118
|
+
documentation = ''
|
119
|
+
|
120
|
+
Dir.glob(File.join(locales_folder, '**/*.yml')).each do |locale_file|
|
121
|
+
value = find_locale_value(locale_file, key_path)
|
122
|
+
|
123
|
+
loc_key = File.basename(locale_file, '.yml')
|
124
|
+
|
125
|
+
if value
|
126
|
+
if value == MISSING_LOCALE_PLACEHOLDER
|
127
|
+
value_location = find_locale_key_location(locale_file, key_path)
|
128
|
+
file_uri = "#{locale_file}" # TODO add line to uri :#{value_location.line+1}:#{value_location.column}"
|
129
|
+
documentation += "#{loc_key}: [#{value}](#{file_uri})\n\n"
|
130
|
+
else
|
131
|
+
documentation += "#{loc_key}: #{value}\n\n"
|
132
|
+
end
|
133
|
+
else
|
134
|
+
documentation += "#{loc_key}: [MISSING TRANSLATION](#{locale_file})\n\n"
|
135
|
+
end
|
136
|
+
end
|
137
|
+
|
138
|
+
[documentation]
|
139
|
+
end
|
140
|
+
|
141
|
+
def get_uri_from_object(parsed_doc)
|
142
|
+
obj = parsed_doc.links_container_node_name
|
143
|
+
|
144
|
+
ree_obj = @finder.find_object(obj)
|
145
|
+
ree_obj.uri
|
146
|
+
end
|
64
147
|
end
|
65
148
|
end
|
66
149
|
end
|
@@ -1,4 +1,5 @@
|
|
1
1
|
require_relative "../handlers/definition_handler"
|
2
|
+
require_relative "../ree_context"
|
2
3
|
|
3
4
|
module RubyLsp
|
4
5
|
module Ree
|
@@ -8,6 +9,7 @@ module RubyLsp
|
|
8
9
|
def initialize(response_builder, node_context, index, dispatcher, uri)
|
9
10
|
@response_builder = response_builder
|
10
11
|
@handler = RubyLsp::Ree::DefinitionHandler.new(index, uri, node_context)
|
12
|
+
@ree_context = RubyLsp::Ree::ReeContext.new(node_context)
|
11
13
|
|
12
14
|
dispatcher.register(
|
13
15
|
self,
|
@@ -40,14 +42,24 @@ module RubyLsp
|
|
40
42
|
end
|
41
43
|
|
42
44
|
def on_symbol_node_enter(node)
|
43
|
-
definition_items = @
|
45
|
+
definition_items = if @ree_context.is_error_definition?
|
46
|
+
@handler.get_error_code_definition_items(node)
|
47
|
+
else
|
48
|
+
@handler.get_linked_object_definition_items(node)
|
49
|
+
end
|
50
|
+
|
44
51
|
put_items_into_response(definition_items)
|
45
52
|
rescue => e
|
46
53
|
$stderr.puts("error in definition listener(on_symbol_node_enter): #{e.message} : #{e.backtrace.first}")
|
47
54
|
end
|
48
55
|
|
49
56
|
def on_string_node_enter(node)
|
50
|
-
definition_items = @
|
57
|
+
definition_items = if @ree_context.is_error_definition?
|
58
|
+
@handler.get_error_locales_definition_items(node)
|
59
|
+
else
|
60
|
+
@handler.get_linked_filepath_definition_items(node)
|
61
|
+
end
|
62
|
+
|
51
63
|
put_items_into_response(definition_items)
|
52
64
|
rescue => e
|
53
65
|
$stderr.puts("error in definition listener(on_string_node_enter): #{e.message} : #{e.backtrace.first}")
|
@@ -8,11 +8,13 @@ module RubyLsp
|
|
8
8
|
def initialize(response_builder, node_context, index, dispatcher)
|
9
9
|
@response_builder = response_builder
|
10
10
|
@handler = RubyLsp::Ree::HoverHandler.new(index, node_context)
|
11
|
+
@ree_context = RubyLsp::Ree::ReeContext.new(node_context)
|
11
12
|
|
12
13
|
dispatcher.register(
|
13
14
|
self,
|
14
15
|
:on_call_node_enter,
|
15
16
|
:on_symbol_node_enter,
|
17
|
+
:on_string_node_enter,
|
16
18
|
:on_constant_read_node_enter
|
17
19
|
)
|
18
20
|
end
|
@@ -36,8 +38,23 @@ module RubyLsp
|
|
36
38
|
$stderr.puts("error in hover listener(on_call_node_enter): #{e.message} : #{e.backtrace.first}")
|
37
39
|
end
|
38
40
|
|
41
|
+
def on_string_node_enter(node)
|
42
|
+
return unless @ree_context.is_error_definition?
|
43
|
+
|
44
|
+
hover_items = @handler.get_error_locales_hover_items(node)
|
45
|
+
|
46
|
+
put_items_into_response(hover_items)
|
47
|
+
rescue => e
|
48
|
+
$stderr.puts("error in hover listener(on_string_node_enter): #{e.message} : #{e.backtrace.first}")
|
49
|
+
end
|
50
|
+
|
39
51
|
def on_symbol_node_enter(node)
|
40
|
-
hover_items = @
|
52
|
+
hover_items = if @ree_context.is_error_definition?
|
53
|
+
@handler.get_error_code_hover_items(node)
|
54
|
+
else
|
55
|
+
@handler.get_linked_object_hover_items(node)
|
56
|
+
end
|
57
|
+
|
41
58
|
put_items_into_response(hover_items)
|
42
59
|
rescue => e
|
43
60
|
$stderr.puts("error in hover listener(on_symbol_node_enter): #{e.message} : #{e.backtrace.first}")
|
@@ -1,4 +1,5 @@
|
|
1
1
|
require_relative 'parsed_link_node'
|
2
|
+
require_relative 'parsed_method_node'
|
2
3
|
require 'ostruct'
|
3
4
|
|
4
5
|
class RubyLsp::Ree::ParsedDocument
|
@@ -6,9 +7,26 @@ class RubyLsp::Ree::ParsedDocument
|
|
6
7
|
|
7
8
|
LINK_DSL_MODULE = 'Ree::LinkDSL'
|
8
9
|
|
10
|
+
ERROR_DEFINITION_NAMES = [
|
11
|
+
:auth_error,
|
12
|
+
:build_error,
|
13
|
+
:conflict_error,
|
14
|
+
:invalid_param_error,
|
15
|
+
:not_found_error,
|
16
|
+
:payment_required_error,
|
17
|
+
:permission_error,
|
18
|
+
:validation_error
|
19
|
+
]
|
20
|
+
|
21
|
+
CONTRACT_CALL_NODE_NAMES = [
|
22
|
+
:contract,
|
23
|
+
:throws
|
24
|
+
]
|
25
|
+
|
9
26
|
attr_reader :ast, :package_name, :class_node, :fn_node, :class_includes,
|
10
27
|
:link_nodes, :values, :action_node, :dao_node, :filters,
|
11
|
-
:bean_node, :bean_methods, :mapper_node, :links_container_block_node, :aggregate_node
|
28
|
+
:bean_node, :bean_methods, :mapper_node, :links_container_block_node, :aggregate_node,
|
29
|
+
:error_definitions, :error_definition_names, :doc_instance_methods
|
12
30
|
|
13
31
|
def initialize(ast)
|
14
32
|
@ast = ast
|
@@ -161,6 +179,25 @@ class RubyLsp::Ree::ParsedDocument
|
|
161
179
|
.map{ OpenStruct.new(name: node_name(_1).to_s, signatures: parse_signatures_from_params(_1.parameters)) }
|
162
180
|
end
|
163
181
|
|
182
|
+
def parse_instance_methods
|
183
|
+
@doc_instance_methods = []
|
184
|
+
|
185
|
+
current_contract_node = nil
|
186
|
+
class_node.body.body.each do |node|
|
187
|
+
if node.is_a?(Prism::CallNode) && CONTRACT_CALL_NODE_NAMES.include?(node_name(node))
|
188
|
+
current_contract_node = node
|
189
|
+
else
|
190
|
+
if node.is_a?(Prism::DefNode)
|
191
|
+
@doc_instance_methods << RubyLsp::Ree::ParsedMethodNode.new(node, current_contract_node)
|
192
|
+
end
|
193
|
+
|
194
|
+
current_contract_node = nil
|
195
|
+
end
|
196
|
+
end
|
197
|
+
|
198
|
+
@doc_instance_methods
|
199
|
+
end
|
200
|
+
|
164
201
|
def parse_filter_signature(filter_node)
|
165
202
|
return [] unless filter_node
|
166
203
|
|
@@ -175,10 +212,24 @@ class RubyLsp::Ree::ParsedDocument
|
|
175
212
|
[RubyIndexer::Entry::Signature.new(signature_params)]
|
176
213
|
end
|
177
214
|
|
215
|
+
def parse_error_definitions
|
216
|
+
return unless class_node
|
217
|
+
|
218
|
+
@error_definitions = class_node.body.body
|
219
|
+
.select{ _1.is_a?(Prism::ConstantWriteNode) }
|
220
|
+
.select{ ERROR_DEFINITION_NAMES.include?(node_name(_1.value)) }
|
221
|
+
|
222
|
+
@error_definition_names = @error_definitions.map(&:name)
|
223
|
+
end
|
224
|
+
|
178
225
|
def class_name
|
179
226
|
class_node.constant_path.name.to_s
|
180
227
|
end
|
181
228
|
|
229
|
+
def module_name
|
230
|
+
class_node.constant_path&.parent&.name.to_s
|
231
|
+
end
|
232
|
+
|
182
233
|
def full_class_name
|
183
234
|
name_parts = [class_node.constant_path&.parent&.name, class_node.constant_path.name]
|
184
235
|
name_parts.compact.map(&:to_s).join('::')
|
@@ -193,4 +244,8 @@ class RubyLsp::Ree::ParsedDocument
|
|
193
244
|
|
194
245
|
node.name
|
195
246
|
end
|
247
|
+
|
248
|
+
def imported_constants
|
249
|
+
@link_nodes.map(&:imports).flatten.map(&:to_sym)
|
250
|
+
end
|
196
251
|
end
|
@@ -38,11 +38,11 @@ class RubyLsp::Ree::ParsedDocumentBuilder
|
|
38
38
|
when :bean
|
39
39
|
build_bean_document(ast)
|
40
40
|
else
|
41
|
-
|
41
|
+
build_detected_document_type(ast)
|
42
42
|
end
|
43
43
|
end
|
44
44
|
|
45
|
-
def self.
|
45
|
+
def self.build_detected_document_type(ast)
|
46
46
|
if has_root_class?(ast)
|
47
47
|
build_regular_document(ast)
|
48
48
|
elsif has_root_rspec_call?(ast)
|
@@ -53,7 +53,7 @@ class RubyLsp::Ree::ParsedDocumentBuilder
|
|
53
53
|
end
|
54
54
|
|
55
55
|
def self.has_root_class?(ast)
|
56
|
-
ast.statements.body.detect{ |node| node.is_a?(Prism::ClassNode) }
|
56
|
+
!!ast.statements.body.detect{ |node| node.is_a?(Prism::ClassNode) }
|
57
57
|
end
|
58
58
|
|
59
59
|
def self.has_root_rspec_call?(ast)
|
@@ -0,0 +1,115 @@
|
|
1
|
+
require 'prism'
|
2
|
+
|
3
|
+
class RubyLsp::Ree::ParsedMethodNode
|
4
|
+
attr_reader :method_node, :contract_node
|
5
|
+
|
6
|
+
def initialize(method_node, contract_node)
|
7
|
+
@method_node = method_node
|
8
|
+
@contract_node = contract_node
|
9
|
+
end
|
10
|
+
|
11
|
+
def name
|
12
|
+
@method_node.name
|
13
|
+
end
|
14
|
+
|
15
|
+
def has_contract?
|
16
|
+
!!@contract_node
|
17
|
+
end
|
18
|
+
|
19
|
+
def start_line
|
20
|
+
@method_node.location.start_line - 1
|
21
|
+
end
|
22
|
+
|
23
|
+
def end_line
|
24
|
+
@method_node.location.end_line - 1
|
25
|
+
end
|
26
|
+
|
27
|
+
def raised_errors_nested
|
28
|
+
return @raised_errors_nested if @raised_errors_nested
|
29
|
+
raised = raised_errors
|
30
|
+
|
31
|
+
@nested_local_methods.each do |nested_method|
|
32
|
+
raised += nested_method.raised_errors_nested
|
33
|
+
end
|
34
|
+
|
35
|
+
@raised_errors_nested = raised
|
36
|
+
end
|
37
|
+
|
38
|
+
def raised_errors
|
39
|
+
return @raised_errors if @raised_errors
|
40
|
+
return [] unless @method_node.body
|
41
|
+
|
42
|
+
call_objects = parse_body_call_objects(@method_node.body.body)
|
43
|
+
raise_objects = call_objects.select{ _1.name == :raise }
|
44
|
+
@raised_errors = raise_objects.map{ parse_raised_class_name(_1) }.compact
|
45
|
+
end
|
46
|
+
|
47
|
+
def parse_raised_class_name(raise_node)
|
48
|
+
return unless raise_node.arguments
|
49
|
+
|
50
|
+
if raise_node.arguments.arguments.first.is_a?(Prism::ConstantReadNode)
|
51
|
+
raise_node.arguments.arguments.first.name
|
52
|
+
elsif raise_node.arguments.arguments.first.is_a?(Prism::CallNode)
|
53
|
+
raise_node.arguments.arguments.first.receiver.name
|
54
|
+
else
|
55
|
+
nil
|
56
|
+
end
|
57
|
+
end
|
58
|
+
|
59
|
+
def throws_errors
|
60
|
+
return [] unless has_contract?
|
61
|
+
return [] unless has_throw_section?
|
62
|
+
|
63
|
+
@contract_node.arguments.arguments.map{ _1.name }
|
64
|
+
end
|
65
|
+
|
66
|
+
def has_throw_section?
|
67
|
+
@contract_node && @contract_node.name == :throws
|
68
|
+
end
|
69
|
+
|
70
|
+
def throw_arguments_end_position
|
71
|
+
@contract_node.arguments.arguments.last.location.end_column - 1
|
72
|
+
end
|
73
|
+
|
74
|
+
def throw_arguments_end_line
|
75
|
+
@contract_node.arguments.arguments.last.location.end_line - 1
|
76
|
+
end
|
77
|
+
|
78
|
+
def contract_node_end_position
|
79
|
+
@contract_node.location.end_column - 1
|
80
|
+
end
|
81
|
+
|
82
|
+
def contract_node_end_line
|
83
|
+
@contract_node.location.end_line - 1
|
84
|
+
end
|
85
|
+
|
86
|
+
def parse_nested_local_methods(local_methods)
|
87
|
+
unless @method_node.body
|
88
|
+
@nested_local_methods = []
|
89
|
+
return
|
90
|
+
end
|
91
|
+
|
92
|
+
local_method_names = local_methods.map(&:name)
|
93
|
+
call_nodes = parse_body_call_objects(@method_node.body.body)
|
94
|
+
call_node_names = call_nodes.map(&:name)
|
95
|
+
|
96
|
+
@nested_local_methods = local_methods.select{ call_node_names.include?(_1.name) }
|
97
|
+
@nested_local_methods.each{ _1.parse_nested_local_methods(local_methods) }
|
98
|
+
end
|
99
|
+
|
100
|
+
def parse_body_call_objects(node_body)
|
101
|
+
call_nodes = []
|
102
|
+
|
103
|
+
node_body.each do |node|
|
104
|
+
if node.is_a?(Prism::CallNode) && !node.receiver
|
105
|
+
call_nodes << node
|
106
|
+
elsif node.respond_to?(:statements)
|
107
|
+
call_nodes += parse_body_call_objects(node.statements.body)
|
108
|
+
elsif node.respond_to?(:block) && node.block
|
109
|
+
call_nodes += parse_body_call_objects(node.block.body.body)
|
110
|
+
end
|
111
|
+
end
|
112
|
+
|
113
|
+
call_nodes
|
114
|
+
end
|
115
|
+
end
|
@@ -0,0 +1,28 @@
|
|
1
|
+
require 'prism'
|
2
|
+
|
3
|
+
module RubyLsp
|
4
|
+
module Ree
|
5
|
+
class ReeContext
|
6
|
+
ERROR_DEFINITION_NAMES = [
|
7
|
+
:auth_error,
|
8
|
+
:build_error,
|
9
|
+
:conflict_error,
|
10
|
+
:invalid_param_error,
|
11
|
+
:not_found_error,
|
12
|
+
:payment_required_error,
|
13
|
+
:permission_error,
|
14
|
+
:validation_error
|
15
|
+
]
|
16
|
+
|
17
|
+
def initialize(node_context)
|
18
|
+
@node_context = node_context
|
19
|
+
end
|
20
|
+
|
21
|
+
def is_error_definition?
|
22
|
+
return false if !@node_context || !@node_context.parent || !@node_context.parent.is_a?(Prism::CallNode)
|
23
|
+
|
24
|
+
ERROR_DEFINITION_NAMES.include?(@node_context.parent.name)
|
25
|
+
end
|
26
|
+
end
|
27
|
+
end
|
28
|
+
end
|
@@ -1,63 +1,84 @@
|
|
1
|
+
require_relative 'formatters/sort_links_formatter'
|
2
|
+
require_relative 'formatters/missing_error_definitions_formatter'
|
3
|
+
require_relative 'formatters/missing_error_contracts_formatter'
|
4
|
+
require_relative 'formatters/missing_error_locales_formatter'
|
5
|
+
|
1
6
|
module RubyLsp
|
2
7
|
module Ree
|
3
8
|
class ReeFormatter
|
4
9
|
include RubyLsp::Requests::Support::Formatter
|
5
10
|
include RubyLsp::Ree::ReeLspUtils
|
6
|
-
|
7
|
-
def initialize
|
8
|
-
end
|
11
|
+
include RubyLsp::Ree::ReeLocaleUtils
|
9
12
|
|
10
13
|
def run_formatting(uri, document)
|
11
14
|
source = document.source
|
12
|
-
|
15
|
+
|
16
|
+
formatters = [
|
17
|
+
RubyLsp::Ree::SortLinksFormatter,
|
18
|
+
RubyLsp::Ree::MissingErrorDefinitionsFormatter,
|
19
|
+
RubyLsp::Ree::MissingErrorContractsFormatter,
|
20
|
+
RubyLsp::Ree::MissingErrorLocalesFormatter
|
21
|
+
]
|
22
|
+
|
23
|
+
formatters.reduce(source){ |s, formatter| formatter.call(s, uri) }
|
13
24
|
rescue => e
|
14
25
|
$stderr.puts("error in ree_formatter: #{e.message} : #{e.backtrace.first}")
|
15
26
|
end
|
16
27
|
|
17
|
-
|
28
|
+
def run_diagnostic(uri, document)
|
29
|
+
$stderr.puts("ree_formatter_diagnostic")
|
30
|
+
detect_missing_error_locales(uri, document)
|
31
|
+
rescue => e
|
32
|
+
$stderr.puts("error in ree_formatter_diagnostic: #{e.message} : #{e.backtrace.first}")
|
33
|
+
end
|
18
34
|
|
19
|
-
|
20
|
-
parsed_doc = RubyLsp::Ree::ParsedDocumentBuilder.build_from_source(source)
|
21
|
-
return source if !parsed_doc.link_nodes&.any?
|
35
|
+
private
|
22
36
|
|
23
|
-
|
24
|
-
|
25
|
-
return source
|
26
|
-
end
|
37
|
+
def detect_missing_error_locales(uri, document)
|
38
|
+
parsed_doc = RubyLsp::Ree::ParsedDocumentBuilder.build_from_source(document.source)
|
27
39
|
|
28
|
-
|
29
|
-
|
30
|
-
a_name = a.node.arguments.arguments.first
|
31
|
-
b_name = b.node.arguments.arguments.first
|
40
|
+
locales_folder = package_locales_folder_path(uri.path)
|
41
|
+
return [] unless File.directory?(locales_folder)
|
32
42
|
|
33
|
-
|
34
|
-
|
35
|
-
|
36
|
-
|
43
|
+
result = []
|
44
|
+
key_paths = []
|
45
|
+
parsed_doc.parse_error_definitions
|
46
|
+
parsed_doc.error_definitions.each do |error_definition|
|
47
|
+
key_path = if error_definition.value.arguments.arguments.size > 1
|
48
|
+
error_definition.value.arguments.arguments[1].unescaped
|
37
49
|
else
|
38
|
-
|
50
|
+
mod = underscore(parsed_doc.module_name)
|
51
|
+
"#{mod}.errors.#{error_definition.value.arguments.arguments[0].unescaped}"
|
39
52
|
end
|
40
|
-
}
|
41
53
|
|
42
|
-
|
43
|
-
if parsed_doc.link_nodes.map{ _1.node.arguments.arguments.first.unescaped } == sorted_link_nodes.map{ _1.node.arguments.arguments.first.unescaped }
|
44
|
-
return source
|
54
|
+
key_paths << key_path
|
45
55
|
end
|
46
56
|
|
47
|
-
#
|
48
|
-
link_lines = parsed_doc.link_nodes.map{ _1.location.start_line }
|
57
|
+
$stderr.puts("ree_formatter_diagnostic #{key_paths}")
|
49
58
|
|
50
|
-
|
59
|
+
Dir.glob(File.join(locales_folder, '**/*.yml')).each do |locale_file|
|
60
|
+
key_paths.each do |key_path|
|
61
|
+
value = find_locale_value(locale_file, key_path)
|
62
|
+
unless value
|
63
|
+
loc_key = File.basename(locale_file, '.yml')
|
51
64
|
|
52
|
-
|
53
|
-
source_lines[sorted_link.location.start_line - 1]
|
54
|
-
end
|
65
|
+
$stderr.puts("ree_formatter_diagnostic add diagnostic")
|
55
66
|
|
56
|
-
|
57
|
-
|
67
|
+
# TODO correct error range
|
68
|
+
result << RubyLsp::Interface::Diagnostic.new(
|
69
|
+
message: "Missing locale #{loc_key}: #{key_path}",
|
70
|
+
source: "Ree formatter",
|
71
|
+
severity: RubyLsp::Constant::DiagnosticSeverity::ERROR,
|
72
|
+
range: RubyLsp::Interface::Range.new(
|
73
|
+
start: RubyLsp::Interface::Position.new(line: 0, character: 0),
|
74
|
+
end: RubyLsp::Interface::Position.new(line: 0, character: 0),
|
75
|
+
),
|
76
|
+
)
|
77
|
+
end
|
78
|
+
end
|
58
79
|
end
|
59
80
|
|
60
|
-
|
81
|
+
result
|
61
82
|
end
|
62
83
|
end
|
63
84
|
end
|
@@ -1,6 +1,10 @@
|
|
1
|
+
require_relative "utils/ree_lsp_utils"
|
2
|
+
|
1
3
|
module RubyLsp
|
2
4
|
module Ree
|
3
5
|
class ReeObjectFinder
|
6
|
+
include RubyLsp::Ree::ReeLspUtils
|
7
|
+
|
4
8
|
MAX_LIMIT = 1000
|
5
9
|
|
6
10
|
REE_OBJECT_STRING = 'ree_object'
|
@@ -42,6 +46,13 @@ module RubyLsp
|
|
42
46
|
objects_by_name.detect{ _1.comments.to_s.lines.first&.chomp == REE_OBJECT_STRING }
|
43
47
|
end
|
44
48
|
|
49
|
+
def find_object_for_package(name, package_name)
|
50
|
+
objects_by_name = @index[name]
|
51
|
+
return unless objects_by_name
|
52
|
+
|
53
|
+
objects_by_name.detect{ _1.comments.to_s.lines.first&.chomp == REE_OBJECT_STRING && package_name_from_uri(_1.uri) == package_name }
|
54
|
+
end
|
55
|
+
|
45
56
|
def find_objects_by_types(name, types)
|
46
57
|
objects_by_name = @index[name]
|
47
58
|
return [] unless objects_by_name
|
@@ -0,0 +1,40 @@
|
|
1
|
+
require 'yaml'
|
2
|
+
require_relative 'yaml_file_parser'
|
3
|
+
|
4
|
+
module RubyLsp
|
5
|
+
module Ree
|
6
|
+
module ReeLocaleUtils
|
7
|
+
def package_locales_folder_path(uri)
|
8
|
+
uri_parts = uri.to_s.chomp(File.extname(uri.to_s)).split('/')
|
9
|
+
|
10
|
+
package_folder_index = uri_parts.index('package')
|
11
|
+
return unless package_folder_index
|
12
|
+
|
13
|
+
path_parts = uri_parts.take(package_folder_index+2) + ['locales']
|
14
|
+
path_parts.join('/')
|
15
|
+
end
|
16
|
+
|
17
|
+
def find_locale_value(file_path, key_path)
|
18
|
+
loc_yaml = YAML.load_file(file_path)
|
19
|
+
loc_key = File.basename(file_path, '.yml')
|
20
|
+
key_parts = [loc_key] + key_path.split('.')
|
21
|
+
|
22
|
+
loc_yaml.dig(*key_parts)
|
23
|
+
end
|
24
|
+
|
25
|
+
def find_locale_key_location(file_path, key_path)
|
26
|
+
loc_key = File.basename(file_path, '.yml')
|
27
|
+
|
28
|
+
key_parts = [loc_key] + key_path.split('.')
|
29
|
+
parsed_yaml = RubyLsp::Ree::YamlFileParser.parse(file_path)
|
30
|
+
key_location = parsed_yaml.dig(*key_parts)
|
31
|
+
|
32
|
+
if key_location
|
33
|
+
OpenStruct.new(line: key_location.line, column: key_location.column)
|
34
|
+
else
|
35
|
+
OpenStruct.new(line: 0, column: 0)
|
36
|
+
end
|
37
|
+
end
|
38
|
+
end
|
39
|
+
end
|
40
|
+
end
|
@@ -7,7 +7,7 @@ module RubyLsp
|
|
7
7
|
file_name = file_path + ".rb"
|
8
8
|
Dir[File.join('**', file_name)].first
|
9
9
|
end
|
10
|
-
|
10
|
+
|
11
11
|
def package_name_from_uri(uri)
|
12
12
|
uri_parts = uri.to_s.split('/')
|
13
13
|
|
@@ -170,6 +170,17 @@ module RubyLsp
|
|
170
170
|
:"(#{names_with_commas})"
|
171
171
|
end
|
172
172
|
end
|
173
|
+
|
174
|
+
# copied from ree string_utils
|
175
|
+
def underscore(camel_cased_word)
|
176
|
+
return camel_cased_word unless /[A-Z-]|::/.match?(camel_cased_word)
|
177
|
+
word = camel_cased_word.to_s.gsub("::".freeze, "/".freeze)
|
178
|
+
word.gsub!(/([A-Z\d]+)([A-Z][a-z])/, '\1_\2'.freeze)
|
179
|
+
word.gsub!(/([a-z\d])([A-Z])/, '\1_\2'.freeze)
|
180
|
+
word.tr!("-".freeze, "_".freeze)
|
181
|
+
word.downcase!
|
182
|
+
word
|
183
|
+
end
|
173
184
|
end
|
174
185
|
end
|
175
186
|
end
|
@@ -0,0 +1,53 @@
|
|
1
|
+
require 'psych'
|
2
|
+
|
3
|
+
module RubyLsp
|
4
|
+
module Ree
|
5
|
+
class NodeVisitor < Psych::Visitors::ToRuby
|
6
|
+
def visit_Psych_Nodes_Scalar(o)
|
7
|
+
register(o, OpenStruct.new(value: deserialize(o), line: o.start_line, column: o.start_column))
|
8
|
+
end
|
9
|
+
end
|
10
|
+
|
11
|
+
class YamlFileParser
|
12
|
+
def self.parse(file_path)
|
13
|
+
parser = Psych::Parser.new(Psych::TreeBuilder.new)
|
14
|
+
parser.parse(File.read(file_path))
|
15
|
+
|
16
|
+
parse_result = NodeVisitor.create.accept(parser.handler.root)
|
17
|
+
normalize_hash_keys(parse_result.first)
|
18
|
+
end
|
19
|
+
|
20
|
+
def self.parse_with_key_coordinates(file_path)
|
21
|
+
parser = Psych::Parser.new(Psych::TreeBuilder.new)
|
22
|
+
parser.parse(File.read(file_path))
|
23
|
+
|
24
|
+
NodeVisitor.create.accept(parser.handler.root).first
|
25
|
+
end
|
26
|
+
|
27
|
+
def self.find_key_in_node(current_node, key)
|
28
|
+
matched_key_el = current_node.detect{ _1[0].value == key }
|
29
|
+
return [nil, nil] unless matched_key_el
|
30
|
+
matched_key_el
|
31
|
+
end
|
32
|
+
|
33
|
+
def self.normalize_hash_keys(res)
|
34
|
+
deep_transform_keys_in_object!(res){ |k| k.value }
|
35
|
+
end
|
36
|
+
|
37
|
+
def self.deep_transform_keys_in_object!(object, &block)
|
38
|
+
case object
|
39
|
+
when Hash
|
40
|
+
object.keys.each do |key|
|
41
|
+
value = object.delete(key)
|
42
|
+
object[yield(key)] = deep_transform_keys_in_object!(value, &block)
|
43
|
+
end
|
44
|
+
object
|
45
|
+
when Array
|
46
|
+
object.map! { |e| deep_transform_keys_in_object!(e, &block) }
|
47
|
+
else
|
48
|
+
object
|
49
|
+
end
|
50
|
+
end
|
51
|
+
end
|
52
|
+
end
|
53
|
+
end
|
data/lib/ruby_lsp_ree/version.rb
CHANGED
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: ruby-lsp-ree
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.1.
|
4
|
+
version: 0.1.8
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Ruslan Gatiyatov
|
8
8
|
autorequire:
|
9
9
|
bindir: exe
|
10
10
|
cert_chain: []
|
11
|
-
date: 2025-03-
|
11
|
+
date: 2025-03-21 00:00:00.000000000 Z
|
12
12
|
dependencies: []
|
13
13
|
description: A Ruby LSP addon that adds extra editor functionality for Ree applications
|
14
14
|
email:
|
@@ -26,6 +26,11 @@ files:
|
|
26
26
|
- README.md
|
27
27
|
- Rakefile
|
28
28
|
- lib/ruby_lsp/ruby_lsp_ree/addon.rb
|
29
|
+
- lib/ruby_lsp/ruby_lsp_ree/formatters/base_formatter.rb
|
30
|
+
- lib/ruby_lsp/ruby_lsp_ree/formatters/missing_error_contracts_formatter.rb
|
31
|
+
- lib/ruby_lsp/ruby_lsp_ree/formatters/missing_error_definitions_formatter.rb
|
32
|
+
- lib/ruby_lsp/ruby_lsp_ree/formatters/missing_error_locales_formatter.rb
|
33
|
+
- lib/ruby_lsp/ruby_lsp_ree/formatters/sort_links_formatter.rb
|
29
34
|
- lib/ruby_lsp/ruby_lsp_ree/handlers/completion_handler.rb
|
30
35
|
- lib/ruby_lsp/ruby_lsp_ree/handlers/definition_handler.rb
|
31
36
|
- lib/ruby_lsp/ruby_lsp_ree/handlers/hover_handler.rb
|
@@ -35,13 +40,17 @@ files:
|
|
35
40
|
- lib/ruby_lsp/ruby_lsp_ree/parsing/parsed_document.rb
|
36
41
|
- lib/ruby_lsp/ruby_lsp_ree/parsing/parsed_document_builder.rb
|
37
42
|
- lib/ruby_lsp/ruby_lsp_ree/parsing/parsed_link_node.rb
|
43
|
+
- lib/ruby_lsp/ruby_lsp_ree/parsing/parsed_method_node.rb
|
38
44
|
- lib/ruby_lsp/ruby_lsp_ree/parsing/parsed_rspec_document.rb
|
45
|
+
- lib/ruby_lsp/ruby_lsp_ree/ree_context.rb
|
39
46
|
- lib/ruby_lsp/ruby_lsp_ree/ree_formatter.rb
|
40
47
|
- lib/ruby_lsp/ruby_lsp_ree/ree_indexing_enhancement.rb
|
41
48
|
- lib/ruby_lsp/ruby_lsp_ree/ree_object_finder.rb
|
42
49
|
- lib/ruby_lsp/ruby_lsp_ree/ree_rename_handler.rb
|
43
50
|
- lib/ruby_lsp/ruby_lsp_ree/ree_template_applicator.rb
|
51
|
+
- lib/ruby_lsp/ruby_lsp_ree/utils/ree_locale_utils.rb
|
44
52
|
- lib/ruby_lsp/ruby_lsp_ree/utils/ree_lsp_utils.rb
|
53
|
+
- lib/ruby_lsp/ruby_lsp_ree/utils/yaml_file_parser.rb
|
45
54
|
- lib/ruby_lsp_ree.rb
|
46
55
|
- lib/ruby_lsp_ree/version.rb
|
47
56
|
- ruby-lsp-ree.gemspec
|