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.
@@ -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 initialize(config_type: :default, exclude_partials: true)
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
- return if ignore?(node)
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
- check_undefined(info, all_global_objects, render_node)
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
- unless visited_partials.include?(partial_name)
195
- visited_partials << partial_name
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
- else
212
+ elsif !info.app_file.partial?
217
213
  add_offense("Undefined object `#{name}`", node:, line_number:)
218
214
  end
219
215
  end
@@ -21,6 +21,10 @@ module PlatformosCheck
21
21
  end
22
22
  end
23
23
 
24
+ def self.single_file(**_args)
25
+ true
26
+ end
27
+
24
28
  def initialize
25
29
  @templates = {}
26
30
  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)
@@ -13,6 +13,7 @@ module PlatformosCheck
13
13
 
14
14
  PlatformosLiquid::SourceIndex
15
15
  .objects
16
+ .select(&:global?)
16
17
  .select { |object| object.name.start_with?(partial(variable_lookup)) }
17
18
  .map { |object| object_to_completion(object) }
18
19
  end
@@ -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?(content, cursor)
10
+ return [] unless can_complete?(context)
12
11
 
13
- partial = first_word(content) || ''
14
- labels = PlatformosLiquid::Tag.labels
15
- labels += PlatformosLiquid::Tag.end_labels
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?(content, cursor)
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
- label: tag,
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
@@ -24,7 +24,7 @@ module PlatformosCheck
24
24
 
25
25
  CAPABILITIES = {
26
26
  completionProvider: {
27
- triggerCharacters: ['.', '{{ ', '{% '],
27
+ triggerCharacters: ['.', '{{ ', '{% ', '/'],
28
28
  context: true
29
29
  },
30
30
  codeActionProvider: {
@@ -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::SNIPPET,
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)
@@ -14,6 +14,10 @@ module PlatformosCheck
14
14
  def platformos_documentation_url
15
15
  "#{PLATFORMOS_DOCUMENTATION_URL}/developer-guide/variables/context-variable##{hash['name']}"
16
16
  end
17
+
18
+ def global?
19
+ hash.dig('access', 'global')
20
+ end
17
21
  end
18
22
  end
19
23
  end
@@ -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
@@ -1,5 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module PlatformosCheck
4
- VERSION = "0.1.0"
4
+ VERSION = "0.2.1"
5
5
  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.0
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 00:00:00.000000000 Z
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