theme-check 0.3.3 → 0.4.0

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: b17d14eb5abc8211b6b6ae9f3a676c44770775821a87ce0909412d3eddb81c35
4
- data.tar.gz: 7bcad0d34832338dd8cd83f220b14c45b061b84b81c5ae2b3a18805aeb9400eb
3
+ metadata.gz: 5543690a150f2a864a5a9900feca80286ffe4c00d545885ee31dc02c9d389b71
4
+ data.tar.gz: c1c518e2013a1106dc7ace3a14ef5158853e06929694503777a37c0fc695025a
5
5
  SHA512:
6
- metadata.gz: 241dfdae6ec38c560ca4697c4b9256d4ceaed0300e9a575c3c92e864ea4fa2fd56420efd87ec2c0f744240fe9db5c6cc7df24c1da8d9606fab020bdd1d630450
7
- data.tar.gz: bbb52dcf01cf1dcbc3f73fe90d822b9ee22407a31525aab314ad0121e1bd9f52c786b6528594e5eb6224d97e567108bd7962a8c7a67d6e17702a976bab3edb1a
6
+ metadata.gz: 405832fbd93d17f3412abb83181b8c76c0aee43e2405bc7329b7ace746c20887c32ab638bf49c99adf4598532fc92d5840a46dc24d2a20b89909849b8c2813a3
7
+ data.tar.gz: 40316910f51d646017059d4256cba23dfcb9e20822a0987b65a04ab79c40c160c882d4bdf7e0cc4d646b08971ba04bb58999a7c5b93a4741233a8ce1c5ce4ad9
data/CHANGELOG.md CHANGED
@@ -1,4 +1,11 @@
1
1
 
2
+ v0.4.0 / 2021-02-25
3
+ ==================
4
+
5
+ * Add Completion Engine ([#161](https://github.com/shopify/theme-check/issues/161))
6
+ * Add init command to CLI ([#174](https://github.com/shopify/theme-check/issues/174))
7
+ * Refactor start and end Position logic ([#172](https://github.com/shopify/theme-check/issues/172))
8
+
2
9
  v0.3.3 / 2021-02-18
3
10
  ==================
4
11
 
data/README.md CHANGED
@@ -8,8 +8,6 @@ Theme Check is also available [inside some code editors](https://github.com/Shop
8
8
 
9
9
  ![](docs/preview.png)
10
10
 
11
- _Disclaimer: This tool is not supported as part of the Partners program._
12
-
13
11
  ## Supported Checks
14
12
 
15
13
  Theme Check currently checks for the following:
@@ -0,0 +1,26 @@
1
+ ---
2
+ - assign
3
+ - break
4
+ - capture
5
+ - case
6
+ - comment
7
+ - continue
8
+ - cycle
9
+ - decrement
10
+ - echo
11
+ - for
12
+ - form
13
+ - if
14
+ - ifchanged
15
+ - increment
16
+ - javascript
17
+ - layout
18
+ - paginate
19
+ - raw
20
+ - render
21
+ - schema
22
+ - section
23
+ - style
24
+ - stylesheet
25
+ - tablerow
26
+ - unless
@@ -11,6 +11,7 @@ module ThemeCheck
11
11
  -x, [--exclude-category] # Exclude this category of checks
12
12
  -l, [--list] # List enabled checks
13
13
  -a, [--auto-correct] # Automatically fix offenses
14
+ --init # Generate a .theme-check.yml file in the current directory
14
15
  -h, [--help] # Show this. Hi!
15
16
  -v, [--version] # Print Theme Check version
16
17
 
@@ -22,7 +23,7 @@ module ThemeCheck
22
23
  END
23
24
 
24
25
  def run(argv)
25
- path = "."
26
+ @path = "."
26
27
 
27
28
  command = :check
28
29
  only_categories = []
@@ -44,15 +45,19 @@ module ThemeCheck
44
45
  command = :list
45
46
  when "--auto-correct", "-a"
46
47
  auto_correct = true
48
+ when "--init"
49
+ command = :init
47
50
  else
48
- path = arg
51
+ @path = arg
49
52
  end
50
53
  end
51
54
 
52
- @config = ThemeCheck::Config.from_path(path)
53
- @config.only_categories = only_categories
54
- @config.exclude_categories = exclude_categories
55
- @config.auto_correct = auto_correct
55
+ unless [:version, :init].include?(command)
56
+ @config = ThemeCheck::Config.from_path(@path)
57
+ @config.only_categories = only_categories
58
+ @config.exclude_categories = exclude_categories
59
+ @config.auto_correct = auto_correct
60
+ end
56
61
 
57
62
  send(command)
58
63
  end
@@ -75,6 +80,17 @@ module ThemeCheck
75
80
  puts ThemeCheck::VERSION
76
81
  end
77
82
 
83
+ def init
84
+ dotfile_path = ThemeCheck::Config.find(@path)
85
+ if dotfile_path.nil?
86
+ File.write(File.join(@path, ThemeCheck::Config::DOTFILE), File.read(ThemeCheck::Config::DEFAULT_CONFIG))
87
+
88
+ puts "Writing new #{ThemeCheck::Config::DOTFILE} to #{@path}"
89
+ else
90
+ raise Abort, "#{ThemeCheck::Config::DOTFILE} already exists at #{@path}."
91
+ end
92
+ end
93
+
78
94
  def check
79
95
  puts "Checking #{@config.root} ..."
80
96
  storage = ThemeCheck::FileSystemStorage.new(@config.root, ignored_patterns: @config.ignored_patterns)
@@ -6,7 +6,7 @@
6
6
  # as a big hash already, leave it like that and save yourself some IO.
7
7
  module ThemeCheck
8
8
  class InMemoryStorage < Storage
9
- def initialize(files)
9
+ def initialize(files = {})
10
10
  @files = files
11
11
  end
12
12
 
@@ -1,6 +1,16 @@
1
1
  # frozen_string_literal: true
2
+ require_relative "language_server/protocol"
2
3
  require_relative "language_server/handler"
3
4
  require_relative "language_server/server"
5
+ require_relative "language_server/tokens"
6
+ require_relative "language_server/position_helper"
7
+ require_relative "language_server/completion_helper"
8
+ require_relative "language_server/completion_provider"
9
+ require_relative "language_server/completion_engine"
10
+
11
+ Dir[__dir__ + "/language_server/completion_providers/*.rb"].each do |file|
12
+ require file
13
+ end
4
14
 
5
15
  module ThemeCheck
6
16
  module LanguageServer
@@ -0,0 +1,38 @@
1
+ # frozen_string_literal: true
2
+
3
+ module ThemeCheck
4
+ module LanguageServer
5
+ class CompletionEngine
6
+ include PositionHelper
7
+
8
+ def initialize(storage)
9
+ @storage = storage
10
+ @providers = CompletionProvider.all.map(&:new)
11
+ end
12
+
13
+ def completions(name, line, col)
14
+ buffer = @storage.read(name)
15
+ cursor = from_line_column_to_index(buffer, line, col)
16
+ token = find_token(buffer, cursor)
17
+ return [] if token.nil?
18
+
19
+ @providers.flat_map do |p|
20
+ p.completions(
21
+ token.content,
22
+ cursor - token.start
23
+ )
24
+ end
25
+ end
26
+
27
+ def find_token(buffer, cursor)
28
+ Tokens.new(buffer).find do |token|
29
+ # Here we include the next character and exclude the first
30
+ # one becase when we want to autocomplete inside a token
31
+ # and at most 1 outside it since the cursor could be placed
32
+ # at the end of the token.
33
+ token.start < cursor && cursor <= token.end
34
+ end
35
+ end
36
+ end
37
+ end
38
+ end
@@ -0,0 +1,35 @@
1
+ # frozen_string_literal: true
2
+
3
+ module ThemeCheck
4
+ module LanguageServer
5
+ module CompletionHelper
6
+ WORD = /\w+/
7
+
8
+ def cursor_on_start_content?(content, cursor, regex)
9
+ content.slice(0, cursor).match?(/#{regex}(?:\s|\n)*$/m)
10
+ end
11
+
12
+ def cursor_on_first_word?(content, cursor)
13
+ word = content.match(WORD)
14
+ return false if word.nil?
15
+ word_start = word.begin(0)
16
+ word_end = word.end(0)
17
+ word_start <= cursor && cursor <= word_end
18
+ end
19
+
20
+ def first_word(content)
21
+ return content.match(WORD)[0] if content.match?(WORD)
22
+ end
23
+
24
+ def matches(s, re)
25
+ start_at = 0
26
+ matches = []
27
+ while (m = s.match(re, start_at))
28
+ matches.push(m)
29
+ start_at = m.end(0)
30
+ end
31
+ matches
32
+ end
33
+ end
34
+ end
35
+ end
@@ -0,0 +1,23 @@
1
+ # frozen_string_literal: true
2
+
3
+ module ThemeCheck
4
+ module LanguageServer
5
+ class CompletionProvider
6
+ include CompletionHelper
7
+
8
+ class << self
9
+ def all
10
+ @all ||= []
11
+ end
12
+
13
+ def inherited(subclass)
14
+ all << subclass
15
+ end
16
+ end
17
+
18
+ def completions(content, cursor)
19
+ raise NotImplementedError
20
+ end
21
+ end
22
+ end
23
+ end
@@ -0,0 +1,47 @@
1
+ # frozen_string_literal: true
2
+
3
+ module ThemeCheck
4
+ module LanguageServer
5
+ class FilterCompletionProvider < CompletionProvider
6
+ NAMED_FILTER = /#{Liquid::FilterSeparator}\s*(\w+)/o
7
+
8
+ def completions(content, cursor)
9
+ return [] unless can_complete?(content, cursor)
10
+ ShopifyLiquid::Filter.labels
11
+ .select { |w| w.starts_with?(partial(content, cursor)) }
12
+ .map { |filter| filter_to_completion(filter) }
13
+ end
14
+
15
+ def can_complete?(content, cursor)
16
+ content.match?(Liquid::FilterSeparator) && (
17
+ cursor_on_start_content?(content, cursor, Liquid::FilterSeparator) ||
18
+ cursor_on_filter?(content, cursor)
19
+ )
20
+ end
21
+
22
+ private
23
+
24
+ def cursor_on_filter?(content, cursor)
25
+ return false unless content.match?(NAMED_FILTER)
26
+ matches(content, NAMED_FILTER).any? do |match|
27
+ match.begin(1) <= cursor && cursor < match.end(1) + 1 # including next character
28
+ end
29
+ end
30
+
31
+ def partial(content, cursor)
32
+ return '' unless content.match?(NAMED_FILTER)
33
+ partial_match = matches(content, NAMED_FILTER).find do |match|
34
+ match.begin(1) <= cursor && cursor < match.end(1) + 1 # including next character
35
+ end
36
+ partial_match[1]
37
+ end
38
+
39
+ def filter_to_completion(filter)
40
+ {
41
+ label: filter,
42
+ kind: CompletionItemKinds::FUNCTION,
43
+ }
44
+ end
45
+ end
46
+ end
47
+ end
@@ -0,0 +1,31 @@
1
+ # frozen_string_literal: true
2
+
3
+ module ThemeCheck
4
+ module LanguageServer
5
+ class ObjectCompletionProvider < CompletionProvider
6
+ def completions(content, cursor)
7
+ return [] unless can_complete?(content, cursor)
8
+ partial = first_word(content) || ''
9
+ ShopifyLiquid::Object.labels
10
+ .select { |w| w.starts_with?(partial) }
11
+ .map { |object| object_to_completion(object) }
12
+ end
13
+
14
+ def can_complete?(content, cursor)
15
+ content.match?(Liquid::VariableStart) && (
16
+ cursor_on_first_word?(content, cursor) ||
17
+ cursor_on_start_content?(content, cursor, Liquid::VariableStart)
18
+ )
19
+ end
20
+
21
+ private
22
+
23
+ def object_to_completion(object)
24
+ {
25
+ label: object,
26
+ kind: CompletionItemKinds::VARIABLE,
27
+ }
28
+ end
29
+ end
30
+ end
31
+ end
@@ -0,0 +1,31 @@
1
+ # frozen_string_literal: true
2
+
3
+ module ThemeCheck
4
+ module LanguageServer
5
+ class TagCompletionProvider < CompletionProvider
6
+ def completions(content, cursor)
7
+ return [] unless can_complete?(content, cursor)
8
+ partial = first_word(content) || ''
9
+ ShopifyLiquid::Tag.labels
10
+ .select { |w| w.starts_with?(partial) }
11
+ .map { |tag| tag_to_completion(tag) }
12
+ end
13
+
14
+ def can_complete?(content, cursor)
15
+ content.starts_with?(Liquid::TagStart) && (
16
+ cursor_on_first_word?(content, cursor) ||
17
+ cursor_on_start_content?(content, cursor, Liquid::TagStart)
18
+ )
19
+ end
20
+
21
+ private
22
+
23
+ def tag_to_completion(tag)
24
+ {
25
+ label: tag,
26
+ kind: CompletionItemKinds::KEYWORD,
27
+ }
28
+ end
29
+ end
30
+ end
31
+ end
@@ -4,9 +4,13 @@ module ThemeCheck
4
4
  module LanguageServer
5
5
  class Handler
6
6
  CAPABILITIES = {
7
+ completionProvider: {
8
+ triggerCharacters: ['.', '{{ ', '{% '],
9
+ context: true,
10
+ },
7
11
  textDocumentSync: {
8
12
  openClose: true,
9
- change: false,
13
+ change: TextDocumentSyncKind::FULL,
10
14
  willSave: false,
11
15
  save: true,
12
16
  },
@@ -15,6 +19,8 @@ module ThemeCheck
15
19
  def initialize(server)
16
20
  @server = server
17
21
  @previously_reported_files = Set.new
22
+ @storage = InMemoryStorage.new
23
+ @completion_engine = CompletionEngine.new(@storage)
18
24
  end
19
25
 
20
26
  def on_initialize(id, params)
@@ -31,14 +37,52 @@ module ThemeCheck
31
37
  def on_exit(_id, _params)
32
38
  close!
33
39
  end
40
+ alias_method :on_shutdown, :on_exit
41
+
42
+ def on_text_document_did_change(_id, params)
43
+ uri = text_document_uri(params)
44
+ @storage.write(uri, content_changes_text(params))
45
+ end
46
+
47
+ def on_text_document_did_close(_id, params)
48
+ uri = text_document_uri(params)
49
+ @storage.write(uri, nil)
50
+ end
34
51
 
35
52
  def on_text_document_did_open(_id, params)
36
- analyze_and_send_offenses(params.dig('textDocument', 'uri').sub('file://', ''))
53
+ uri = text_document_uri(params)
54
+ @storage.write(uri, text_document_text(params))
55
+ analyze_and_send_offenses(uri)
56
+ end
57
+
58
+ def on_text_document_did_save(_id, params)
59
+ analyze_and_send_offenses(text_document_uri(params))
60
+ end
61
+
62
+ def on_text_document_completion(id, params)
63
+ uri = text_document_uri(params)
64
+ line = params.dig('position', 'line')
65
+ col = params.dig('position', 'character')
66
+ send_response(
67
+ id: id,
68
+ result: completions(uri, line, col)
69
+ )
37
70
  end
38
- alias_method :on_text_document_did_save, :on_text_document_did_open
39
71
 
40
72
  private
41
73
 
74
+ def text_document_uri(params)
75
+ params.dig('textDocument', 'uri').sub('file://', '')
76
+ end
77
+
78
+ def text_document_text(params)
79
+ params.dig('textDocument', 'text')
80
+ end
81
+
82
+ def content_changes_text(params)
83
+ params.dig('contentChanges', 0, 'text')
84
+ end
85
+
42
86
  def analyze_and_send_offenses(file_path)
43
87
  root = ThemeCheck::Config.find(file_path) || @root_path
44
88
  config = ThemeCheck::Config.from_path(root)
@@ -60,6 +104,10 @@ module ThemeCheck
60
104
  analyzer.offenses
61
105
  end
62
106
 
107
+ def completions(uri, line, col)
108
+ @completion_engine.completions(uri, line, col)
109
+ end
110
+
63
111
  def send_diagnostics(offenses)
64
112
  reported_files = Set.new
65
113
 
@@ -0,0 +1,27 @@
1
+ # frozen_string_literal: true
2
+ # Note: Everything is 0-indexed here.
3
+
4
+ module ThemeCheck
5
+ module LanguageServer
6
+ module PositionHelper
7
+ def from_line_column_to_index(content, row, col)
8
+ i = 0
9
+ result = 0
10
+ lines = content.lines
11
+ while i < row
12
+ result += lines[i].size
13
+ i += 1
14
+ end
15
+ result += col
16
+ result
17
+ end
18
+
19
+ def from_index_to_line_column(content, index)
20
+ lines = content[0..index].lines
21
+ row = lines.size - 1
22
+ col = lines.last.size - 1
23
+ [row, col]
24
+ end
25
+ end
26
+ end
27
+ end
@@ -0,0 +1,41 @@
1
+ # frozen_string_literal: true
2
+ # Here we define the Language Server Protocol Constants we're using.
3
+ # For complete docs, see the following:
4
+ # https://microsoft.github.io/language-server-protocol/specifications/specification-current
5
+ module ThemeCheck
6
+ module LanguageServer
7
+ module CompletionItemKinds
8
+ TEXT = 1
9
+ METHOD = 2
10
+ FUNCTION = 3
11
+ CONSTRUCTOR = 4
12
+ FIELD = 5
13
+ VARIABLE = 6
14
+ CLASS = 7
15
+ INTERFACE = 8
16
+ MODULE = 9
17
+ PROPERTY = 10
18
+ UNIT = 11
19
+ VALUE = 12
20
+ ENUM = 13
21
+ KEYWORD = 14
22
+ SNIPPET = 15
23
+ COLOR = 16
24
+ FILE = 17
25
+ REFERENCE = 18
26
+ FOLDER = 19
27
+ ENUM_MEMBER = 20
28
+ CONSTANT = 21
29
+ STRUCT = 22
30
+ EVENT = 23
31
+ OPERATOR = 24
32
+ TYPE_PARAMETER = 25
33
+ end
34
+
35
+ module TextDocumentSyncKind
36
+ NONE = 0
37
+ FULL = 1
38
+ INCREMENTAL = 2
39
+ end
40
+ end
41
+ end
@@ -0,0 +1,55 @@
1
+ # frozen_string_literal: true
2
+
3
+ module ThemeCheck
4
+ Token = Struct.new(
5
+ :content,
6
+ :start, # inclusive
7
+ :end, # exclusive
8
+ )
9
+
10
+ TAG_START = Liquid::TagStart
11
+ TAG_END = Liquid::TagEnd
12
+ VARIABLE_START = Liquid::VariableStart
13
+ VARIABLE_END = Liquid::VariableEnd
14
+ SPLITTER = %r{
15
+ (?=(?:#{TAG_START}|#{VARIABLE_START}))| # positive lookahead on tag/variable start
16
+ (?<=(?:#{TAG_END}|#{VARIABLE_END})) # positive lookbehind on tag/variable end
17
+ }xom
18
+
19
+ # Implemented as an Enumerable so we stop iterating on the find once
20
+ # we have what we want. Kind of a perf thing.
21
+ class Tokens
22
+ include Enumerable
23
+
24
+ def initialize(buffer)
25
+ @buffer = buffer
26
+ end
27
+
28
+ def each(&block)
29
+ return to_enum(:each) unless block_given?
30
+
31
+ chunks = @buffer.split(SPLITTER)
32
+ chunks.shift if chunks[0]&.empty?
33
+
34
+ prev = Token.new('', 0, 0)
35
+ curr = Token.new('', 0, 0)
36
+
37
+ while (content = chunks.shift)
38
+
39
+ curr.start = prev.end
40
+ curr.end = curr.start + content.size
41
+
42
+ block.call(Token.new(
43
+ content,
44
+ curr.start,
45
+ curr.end,
46
+ ))
47
+
48
+ # recycling structs
49
+ tmp = prev
50
+ prev = curr
51
+ curr = tmp
52
+ end
53
+ end
54
+ end
55
+ end
@@ -1,5 +1,7 @@
1
1
  # frozen_string_literal: true
2
2
  module ThemeCheck
3
+ Position = Struct.new(:line, :column)
4
+
3
5
  class Offense
4
6
  MAX_SOURCE_EXCERPT_SIZE = 120
5
7
 
@@ -35,6 +37,9 @@ module ThemeCheck
35
37
  elsif @node
36
38
  @node.line_number
37
39
  end
40
+
41
+ @start_position = nil
42
+ @end_position = nil
38
43
  end
39
44
 
40
45
  def source_excerpt
@@ -50,29 +55,19 @@ module ThemeCheck
50
55
  end
51
56
 
52
57
  def start_line
53
- return 0 unless line_number
54
- line_number - 1
58
+ start_position.line
55
59
  end
56
60
 
57
- def end_line
58
- if markup&.ends_with?("\n")
59
- start_line + markup.count("\n") - 1
60
- elsif markup
61
- start_line + markup.count("\n")
62
- else
63
- start_line
64
- end
61
+ def start_column
62
+ start_position.column
65
63
  end
66
64
 
67
- def start_column
68
- return 0 unless line_number && markup
69
- template.full_line(start_line + 1).index(markup.split("\n", 2).first)
65
+ def end_line
66
+ end_position.line
70
67
  end
71
68
 
72
69
  def end_column
73
- return 0 unless line_number && markup
74
- markup_end = markup.split("\n").last
75
- template.full_line(end_line + 1).index(markup_end) + markup_end.size
70
+ end_position.column
76
71
  end
77
72
 
78
73
  def code_name
@@ -118,5 +113,45 @@ module ThemeCheck
118
113
  message
119
114
  end
120
115
  end
116
+
117
+ private
118
+
119
+ def full_line(line)
120
+ # Liquid::Template is 1-indexed.
121
+ template.full_line(line + 1)
122
+ end
123
+
124
+ def lines_of_content
125
+ @lines ||= markup.lines.map { |x| x.sub(/\n$/, '') }
126
+ end
127
+
128
+ # 0-indexed, inclusive
129
+ def start_position
130
+ return @start_position if @start_position
131
+ return @start_position = Position.new(0, 0) unless line_number && markup
132
+
133
+ position = Position.new
134
+ position.line = line_number - 1
135
+ position.column = full_line(position.line).index(lines_of_content.first) || 0
136
+
137
+ @start_position = position
138
+ end
139
+
140
+ # 0-indexed, exclusive. It's the line + col that are exclusive.
141
+ # This is why it doesn't make sense to calculate them separately.
142
+ def end_position
143
+ return @end_position if @end_position
144
+ return @end_position = Position.new(0, 0) unless line_number && markup
145
+
146
+ position = Position.new
147
+ position.line = start_line + lines_of_content.size - 1
148
+ position.column = if start_line == position.line
149
+ start_column + markup.size
150
+ else
151
+ lines_of_content.last.size
152
+ end
153
+
154
+ @end_position = position
155
+ end
121
156
  end
122
157
  end
@@ -2,3 +2,4 @@
2
2
  require_relative 'shopify_liquid/deprecated_filter'
3
3
  require_relative 'shopify_liquid/filter'
4
4
  require_relative 'shopify_liquid/object'
5
+ require_relative 'shopify_liquid/tag'
@@ -0,0 +1,16 @@
1
+ # frozen_string_literal: true
2
+ require 'yaml'
3
+
4
+ module ThemeCheck
5
+ module ShopifyLiquid
6
+ module Tag
7
+ extend self
8
+
9
+ def labels
10
+ @tags ||= begin
11
+ YAML.load(File.read("#{__dir__}/../../../data/shopify_liquid/tags.yml"))
12
+ end
13
+ end
14
+ end
15
+ end
16
+ end
@@ -1,4 +1,4 @@
1
1
  # frozen_string_literal: true
2
2
  module ThemeCheck
3
- VERSION = "0.3.3"
3
+ VERSION = "0.4.0"
4
4
  end
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: theme-check
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.3.3
4
+ version: 0.4.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Marc-André Cournoyer
8
8
  autorequire:
9
9
  bindir: exe
10
10
  cert_chain: []
11
- date: 2021-02-18 00:00:00.000000000 Z
11
+ date: 2021-02-25 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: liquid
@@ -80,6 +80,7 @@ files:
80
80
  - data/shopify_liquid/filters.yml
81
81
  - data/shopify_liquid/objects.yml
82
82
  - data/shopify_liquid/plus_objects.yml
83
+ - data/shopify_liquid/tags.yml
83
84
  - dev.yml
84
85
  - docs/preview.png
85
86
  - exe/theme-check
@@ -123,8 +124,17 @@ files:
123
124
  - lib/theme_check/json_file.rb
124
125
  - lib/theme_check/json_helpers.rb
125
126
  - lib/theme_check/language_server.rb
127
+ - lib/theme_check/language_server/completion_engine.rb
128
+ - lib/theme_check/language_server/completion_helper.rb
129
+ - lib/theme_check/language_server/completion_provider.rb
130
+ - lib/theme_check/language_server/completion_providers/filter_completion_provider.rb
131
+ - lib/theme_check/language_server/completion_providers/object_completion_provider.rb
132
+ - lib/theme_check/language_server/completion_providers/tag_completion_provider.rb
126
133
  - lib/theme_check/language_server/handler.rb
134
+ - lib/theme_check/language_server/position_helper.rb
135
+ - lib/theme_check/language_server/protocol.rb
127
136
  - lib/theme_check/language_server/server.rb
137
+ - lib/theme_check/language_server/tokens.rb
128
138
  - lib/theme_check/liquid_check.rb
129
139
  - lib/theme_check/locale_diff.rb
130
140
  - lib/theme_check/node.rb
@@ -136,6 +146,7 @@ files:
136
146
  - lib/theme_check/shopify_liquid/deprecated_filter.rb
137
147
  - lib/theme_check/shopify_liquid/filter.rb
138
148
  - lib/theme_check/shopify_liquid/object.rb
149
+ - lib/theme_check/shopify_liquid/tag.rb
139
150
  - lib/theme_check/storage.rb
140
151
  - lib/theme_check/tags.rb
141
152
  - lib/theme_check/template.rb