platformos-check 0.1.0 → 0.2.1
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 +13 -1
- data/CONTRIBUTING.md +2 -2
- data/README.md +1 -1
- data/config/default.yml +0 -1
- data/data/platformos_liquid/documentation/filters.json +1 -1
- data/data/platformos_liquid/documentation/latest.json +1 -1
- data/data/platformos_liquid/documentation/objects.json +1 -1
- data/data/platformos_liquid/documentation/tags.json +1 -1
- data/docs/checks/undefined_object.md +0 -5
- data/lib/platformos_check/analyzer.rb +1 -1
- data/lib/platformos_check/checks/undefined_object.rb +35 -39
- data/lib/platformos_check/checks/unused_assign.rb +4 -0
- data/lib/platformos_check/checks.rb +6 -0
- data/lib/platformos_check/language_server/completion_providers/object_completion_provider.rb +1 -0
- data/lib/platformos_check/language_server/completion_providers/tag_completion_provider.rb +10 -15
- data/lib/platformos_check/language_server/handler.rb +1 -1
- data/lib/platformos_check/language_server/hover_providers/tag_hover_provider.rb +36 -0
- data/lib/platformos_check/language_server/partial_completion_provider.rb +31 -8
- data/lib/platformos_check/liquid_visitor.rb +8 -1
- data/lib/platformos_check/platformos_liquid/source_index/object_entry.rb +4 -0
- data/lib/platformos_check/platformos_liquid/source_index/tag_entry.rb +28 -0
- data/lib/platformos_check/version.rb +1 -1
- metadata +3 -2
@@ -16,7 +16,7 @@ module PlatformosCheck
|
|
16
16
|
@app_file = app_file
|
17
17
|
end
|
18
18
|
|
19
|
-
attr_reader :all_assigns, :all_captures, :all_forloops, :app_file
|
19
|
+
attr_reader :all_assigns, :all_captures, :all_forloops, :app_file, :all_renders
|
20
20
|
|
21
21
|
def add_render(name:, node:)
|
22
22
|
@all_renders[name] = node
|
@@ -58,39 +58,32 @@ module PlatformosCheck
|
|
58
58
|
end
|
59
59
|
end
|
60
60
|
|
61
|
-
def
|
61
|
+
def self.single_file(**_args)
|
62
|
+
true
|
63
|
+
end
|
64
|
+
|
65
|
+
def initialize(config_type: :default)
|
62
66
|
@config_type = config_type
|
63
|
-
@exclude_partials = exclude_partials
|
64
67
|
@files = {}
|
65
68
|
end
|
66
69
|
|
67
70
|
def on_document(node)
|
68
|
-
return if ignore?(node)
|
69
|
-
|
70
71
|
@files[node.app_file.name] = TemplateInfo.new(app_file: node.app_file)
|
71
72
|
end
|
72
73
|
|
73
74
|
def on_assign(node)
|
74
|
-
return if ignore?(node)
|
75
|
-
|
76
75
|
@files[node.app_file.name].all_assigns[node.value.to] = node
|
77
76
|
end
|
78
77
|
|
79
78
|
def on_capture(node)
|
80
|
-
return if ignore?(node)
|
81
|
-
|
82
79
|
@files[node.app_file.name].all_captures[node.value.instance_variable_get(:@to)] = node
|
83
80
|
end
|
84
81
|
|
85
82
|
def on_parse_json(node)
|
86
|
-
return if ignore?(node)
|
87
|
-
|
88
83
|
@files[node.app_file.name].all_captures[node.value.to] = node
|
89
84
|
end
|
90
85
|
|
91
86
|
def on_for(node)
|
92
|
-
return if ignore?(node)
|
93
|
-
|
94
87
|
@files[node.app_file.name].all_forloops[node.value.variable_name] = node
|
95
88
|
end
|
96
89
|
|
@@ -99,7 +92,6 @@ module PlatformosCheck
|
|
99
92
|
end
|
100
93
|
|
101
94
|
def on_render(node)
|
102
|
-
return if ignore?(node)
|
103
95
|
return unless node.value.template_name_expr.is_a?(String)
|
104
96
|
|
105
97
|
partial_name = node.value.template_name_expr
|
@@ -110,45 +102,52 @@ module PlatformosCheck
|
|
110
102
|
end
|
111
103
|
|
112
104
|
def on_function(node)
|
113
|
-
|
105
|
+
@files[node.app_file.name].all_assigns[node.value.to] = node
|
106
|
+
|
107
|
+
return unless node.value.from.is_a?(String)
|
114
108
|
|
115
|
-
name = node.value.from.is_a?(String) ? node.value.from : node.value.from.name
|
116
109
|
@files[node.app_file.name].add_render(
|
117
|
-
name
|
110
|
+
name: node.value.from,
|
118
111
|
node:
|
119
112
|
)
|
120
|
-
|
121
|
-
@files[node.app_file.name].all_assigns[node.value.to] = node
|
122
113
|
end
|
123
114
|
|
124
115
|
def on_graphql(node)
|
125
|
-
return if ignore?(node)
|
126
|
-
|
127
116
|
@files[node.app_file.name].all_assigns[node.value.to] = node
|
128
117
|
end
|
129
118
|
|
130
119
|
def on_background(node)
|
131
|
-
return if ignore?(node)
|
132
120
|
return unless node.value.partial_syntax
|
121
|
+
|
122
|
+
@files[node.app_file.name].all_assigns[node.value.to] = node
|
123
|
+
|
133
124
|
return unless node.value.partial_name.is_a?(String)
|
134
125
|
|
135
126
|
@files[node.app_file.name].add_render(
|
136
127
|
name: node.value.partial_name,
|
137
128
|
node:
|
138
129
|
)
|
139
|
-
|
140
|
-
@files[node.app_file.name].all_assigns[node.value.to] = node
|
141
130
|
end
|
142
131
|
|
143
132
|
def on_variable_lookup(node)
|
144
|
-
return if ignore?(node)
|
145
|
-
|
146
133
|
@files[node.app_file.name].add_variable_lookup(
|
147
134
|
name: node.value.name,
|
148
135
|
node:
|
149
136
|
)
|
150
137
|
end
|
151
138
|
|
139
|
+
def single_file_end_dependencies(app_file)
|
140
|
+
@files[app_file.name].all_renders.keys.map do |partial_name|
|
141
|
+
next if @files[partial_name]
|
142
|
+
|
143
|
+
partial_file = @platformos_app.partials.detect { |p| p.name == partial_name } # NOTE: undefined partial
|
144
|
+
|
145
|
+
next unless partial_file
|
146
|
+
|
147
|
+
partial_file
|
148
|
+
end.compact
|
149
|
+
end
|
150
|
+
|
152
151
|
def on_end
|
153
152
|
all_global_objects = PlatformosCheck::PlatformosLiquid::Object.labels
|
154
153
|
all_global_objects.freeze
|
@@ -170,31 +169,28 @@ module PlatformosCheck
|
|
170
169
|
|
171
170
|
attr_reader :config_type
|
172
171
|
|
173
|
-
def ignore?(node)
|
174
|
-
@exclude_partials && node.app_file.partial?
|
175
|
-
end
|
176
|
-
|
177
172
|
def each_template
|
178
173
|
@files.each do |(name, info)|
|
179
|
-
next if info.app_file.partial?
|
180
|
-
|
181
174
|
yield [name, info]
|
182
175
|
end
|
183
176
|
end
|
184
177
|
|
185
|
-
def check_object(info, all_global_objects, render_node = nil, visited_partials = Set.new)
|
186
|
-
|
178
|
+
def check_object(info, all_global_objects, render_node = nil, visited_partials = Set.new, level = 0)
|
179
|
+
return if level > 1
|
180
|
+
|
181
|
+
check_undefined(info, all_global_objects, render_node) unless info.app_file.partial? && render_node.nil? # ||
|
187
182
|
|
188
183
|
info.each_partial do |(partial_name, node)|
|
184
|
+
next if visited_partials.include?(partial_name)
|
185
|
+
|
189
186
|
partial_info = @files[partial_name]
|
187
|
+
|
190
188
|
next unless partial_info # NOTE: undefined partial
|
191
189
|
|
192
190
|
partial_variables = node.value.attributes.keys +
|
193
191
|
[node.value.instance_variable_get(:@alias_name)]
|
194
|
-
|
195
|
-
|
196
|
-
check_object(partial_info, all_global_objects + partial_variables, node, visited_partials)
|
197
|
-
end
|
192
|
+
visited_partials << partial_name
|
193
|
+
check_object(partial_info, all_global_objects + partial_variables, node, visited_partials, level + 1)
|
198
194
|
end
|
199
195
|
end
|
200
196
|
|
@@ -213,7 +209,7 @@ module PlatformosCheck
|
|
213
209
|
|
214
210
|
if render_node
|
215
211
|
add_offense("Missing argument `#{name}`", node: render_node)
|
216
|
-
|
212
|
+
elsif !info.app_file.partial?
|
217
213
|
add_offense("Undefined object `#{name}`", node:, line_number:)
|
218
214
|
end
|
219
215
|
end
|
@@ -25,6 +25,12 @@ module PlatformosCheck
|
|
25
25
|
@single_file ||= self.class.new(select(&:single_file?))
|
26
26
|
end
|
27
27
|
|
28
|
+
def single_file_end_dependencies(app_file)
|
29
|
+
map do |check|
|
30
|
+
check.respond_to?(:single_file_end_dependencies) ? check.single_file_end_dependencies(app_file) : []
|
31
|
+
end.flatten.compact.uniq
|
32
|
+
end
|
33
|
+
|
28
34
|
private
|
29
35
|
|
30
36
|
def call_check_method(check, method, *args)
|
@@ -5,34 +5,29 @@ module PlatformosCheck
|
|
5
5
|
class TagCompletionProvider < CompletionProvider
|
6
6
|
def completions(context)
|
7
7
|
content = context.content
|
8
|
-
cursor = context.cursor
|
9
8
|
|
10
9
|
return [] if content.nil?
|
11
|
-
return [] unless can_complete?(
|
10
|
+
return [] unless can_complete?(context)
|
12
11
|
|
13
|
-
partial = first_word(
|
14
|
-
|
15
|
-
|
16
|
-
labels
|
17
|
-
.select { |w| w.start_with?(partial) }
|
18
|
-
.map { |tag| tag_to_completion(tag) }
|
12
|
+
partial = first_word(context.buffer.lines[context.line]) || ''
|
13
|
+
PlatformosLiquid::SourceIndex.tags.select { |tag| tag.name.start_with?(partial) }
|
14
|
+
.map { |tag| tag_to_completion(tag) }
|
19
15
|
end
|
20
16
|
|
21
|
-
def can_complete?(
|
22
|
-
content.start_with?(Liquid::TagStart) && (
|
23
|
-
cursor_on_first_word?(content, cursor) ||
|
24
|
-
cursor_on_start_content?(content, cursor, Liquid::TagStart)
|
25
|
-
)
|
17
|
+
def can_complete?(context)
|
18
|
+
context.content.start_with?(Liquid::TagStart) && (cursor_on_first_word?(context.buffer.lines[context.line], context.col) || cursor_on_start_content?(context.buffer.lines[context.line], context.col, Liquid::TagStart))
|
26
19
|
end
|
27
20
|
|
28
21
|
private
|
29
22
|
|
30
23
|
def tag_to_completion(tag)
|
31
|
-
content = PlatformosLiquid::Documentation.tag_doc(tag)
|
24
|
+
content = PlatformosLiquid::Documentation.tag_doc(tag.name)
|
32
25
|
|
33
26
|
{
|
34
|
-
|
27
|
+
contents: content,
|
28
|
+
label: tag.name,
|
35
29
|
kind: CompletionItemKinds::KEYWORD,
|
30
|
+
**format_hash(tag),
|
36
31
|
**doc_hash(content)
|
37
32
|
}
|
38
33
|
end
|
@@ -0,0 +1,36 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module PlatformosCheck
|
4
|
+
module LanguageServer
|
5
|
+
class TagHoverProvider < HoverProvider
|
6
|
+
def completions(context)
|
7
|
+
content = context.content
|
8
|
+
|
9
|
+
return [] if content.nil?
|
10
|
+
return [] unless can_complete?(context)
|
11
|
+
|
12
|
+
partial = first_word(context.buffer.lines[context.line]) || ''
|
13
|
+
PlatformosLiquid::SourceIndex.tags.select { |tag| tag.name.start_with?(partial) }
|
14
|
+
.map { |tag| tag_to_completion(tag) }.first
|
15
|
+
end
|
16
|
+
|
17
|
+
def can_complete?(context)
|
18
|
+
context.content.start_with?(Liquid::TagStart) && (cursor_on_first_word?(context.buffer.lines[context.line], context.col) || cursor_on_start_content?(context.buffer.lines[context.line], context.col, Liquid::TagStart))
|
19
|
+
end
|
20
|
+
|
21
|
+
private
|
22
|
+
|
23
|
+
def tag_to_completion(tag)
|
24
|
+
content = PlatformosLiquid::Documentation.tag_doc(tag.name)
|
25
|
+
|
26
|
+
{
|
27
|
+
contents: content,
|
28
|
+
label: tag.name,
|
29
|
+
kind: CompletionItemKinds::KEYWORD,
|
30
|
+
**format_hash(tag),
|
31
|
+
**doc_hash(content)
|
32
|
+
}
|
33
|
+
end
|
34
|
+
end
|
35
|
+
end
|
36
|
+
end
|
@@ -13,18 +13,18 @@ module PlatformosCheck
|
|
13
13
|
|
14
14
|
files
|
15
15
|
.select { |x| x.name.start_with?(@file_name) }
|
16
|
-
.map { |x| file_to_completion(x) }
|
16
|
+
.map { |x| file_to_completion(x, context) }
|
17
17
|
end
|
18
18
|
|
19
19
|
private
|
20
20
|
|
21
21
|
def cursor_on_quoted_argument?(content, cursor)
|
22
|
-
match = content.match(regexp)
|
23
|
-
return false if match.nil?
|
22
|
+
@match = content.match(regexp)
|
23
|
+
return false if @match.nil?
|
24
24
|
|
25
|
-
return false unless match.begin(:partial) <= cursor && cursor <= match.end(:partial)
|
25
|
+
return false unless @match.begin(:partial) <= cursor && cursor <= @match.end(:partial)
|
26
26
|
|
27
|
-
@file_name = match[:partial]
|
27
|
+
@file_name = @match[:partial][0, cursor - @match.begin(:partial)]
|
28
28
|
true
|
29
29
|
end
|
30
30
|
|
@@ -36,11 +36,34 @@ module PlatformosCheck
|
|
36
36
|
raise NotImplementedError
|
37
37
|
end
|
38
38
|
|
39
|
-
def file_to_completion(file)
|
39
|
+
def file_to_completion(file, context)
|
40
40
|
{
|
41
41
|
label: file.name,
|
42
|
-
kind: CompletionItemKinds::
|
43
|
-
detail: file.source
|
42
|
+
kind: CompletionItemKinds::TEXT,
|
43
|
+
detail: file.source,
|
44
|
+
textEdit: {
|
45
|
+
newText: file.name,
|
46
|
+
insert: {
|
47
|
+
start: {
|
48
|
+
line: context.line,
|
49
|
+
character: @match.begin(:partial)
|
50
|
+
},
|
51
|
+
end: {
|
52
|
+
line: context.line,
|
53
|
+
character: @match.end(:partial)
|
54
|
+
}
|
55
|
+
},
|
56
|
+
replace: {
|
57
|
+
start: {
|
58
|
+
line: context.line,
|
59
|
+
character: @match.begin(:partial)
|
60
|
+
},
|
61
|
+
end: {
|
62
|
+
line: context.line,
|
63
|
+
character: @match.end(:partial)
|
64
|
+
}
|
65
|
+
}
|
66
|
+
}
|
44
67
|
}
|
45
68
|
end
|
46
69
|
end
|
@@ -4,13 +4,20 @@ module PlatformosCheck
|
|
4
4
|
class LiquidVisitor
|
5
5
|
attr_reader :checks
|
6
6
|
|
7
|
-
def initialize(checks, disabled_checks)
|
7
|
+
def initialize(checks, disabled_checks, only_single_file: false)
|
8
8
|
@checks = checks
|
9
9
|
@disabled_checks = disabled_checks
|
10
|
+
@only_single_file = only_single_file
|
10
11
|
end
|
11
12
|
|
12
13
|
def visit_liquid_file(liquid_file)
|
13
14
|
visit(LiquidNode.new(liquid_file.root, nil, liquid_file))
|
15
|
+
|
16
|
+
if @only_single_file
|
17
|
+
checks.single_file_end_dependencies(liquid_file).each do |file|
|
18
|
+
visit(LiquidNode.new(file.root, nil, file))
|
19
|
+
end
|
20
|
+
end
|
14
21
|
rescue Liquid::Error => e
|
15
22
|
e.template_name = liquid_file.relative_path
|
16
23
|
call_checks(:on_error, e)
|
@@ -15,6 +15,34 @@ module PlatformosCheck
|
|
15
15
|
}
|
16
16
|
end
|
17
17
|
|
18
|
+
def description
|
19
|
+
@descritpion = begin
|
20
|
+
desc = hash['description']&.strip || ''
|
21
|
+
desc = '' if desc == 'returns'
|
22
|
+
if parameters.any?
|
23
|
+
desc += "\n\n---\n\nParameters:"
|
24
|
+
parameters.each { |p| desc += "\n- #{p.full_summary}" }
|
25
|
+
end
|
26
|
+
if hash['return_type']&.any?
|
27
|
+
rt = hash['return_type'].first
|
28
|
+
rt['description'] = nil if rt['description']&.strip == ''
|
29
|
+
desc += "\n\nReturns:"
|
30
|
+
desc += "\n- #{[rt['type'], rt['description']].compact.join(': ')}\n"
|
31
|
+
end
|
32
|
+
if hash['examples']
|
33
|
+
desc += "\n\n---\n\n"
|
34
|
+
hash['examples'].each_with_index do |e, i|
|
35
|
+
example = e['raw_liquid'].gsub(/[\n]+/, "\n").strip.split('=>')
|
36
|
+
input = example[0]&.strip
|
37
|
+
output = example[1]&.strip
|
38
|
+
desc += "\n - Example #{i}:\n\n```liquid\n#{input}\n```"
|
39
|
+
desc += "\n##\nOutput: #{output}" if output
|
40
|
+
end
|
41
|
+
end
|
42
|
+
end
|
43
|
+
desc
|
44
|
+
end
|
45
|
+
|
18
46
|
def platformos_documentation_url
|
19
47
|
"#{PLATFORMOS_DOCUMENTATION_URL}/api-reference/liquid/tags/#{hash['name']}"
|
20
48
|
end
|
metadata
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: platformos-check
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.1
|
4
|
+
version: 0.2.1
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Piotr Bliszczyk
|
@@ -10,7 +10,7 @@ authors:
|
|
10
10
|
autorequire:
|
11
11
|
bindir: exe
|
12
12
|
cert_chain: []
|
13
|
-
date: 2023-09-
|
13
|
+
date: 2023-09-14 00:00:00.000000000 Z
|
14
14
|
dependencies:
|
15
15
|
- !ruby/object:Gem::Dependency
|
16
16
|
name: graphql
|
@@ -237,6 +237,7 @@ files:
|
|
237
237
|
- lib/platformos_check/language_server/hover_engine.rb
|
238
238
|
- lib/platformos_check/language_server/hover_provider.rb
|
239
239
|
- lib/platformos_check/language_server/hover_providers/filter_hover_provider.rb
|
240
|
+
- lib/platformos_check/language_server/hover_providers/tag_hover_provider.rb
|
240
241
|
- lib/platformos_check/language_server/io_messenger.rb
|
241
242
|
- lib/platformos_check/language_server/messenger.rb
|
242
243
|
- lib/platformos_check/language_server/partial_completion_provider.rb
|