platformos-check 0.0.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 +7 -0
- data/.dockerignore +2 -0
- data/.gitignore +22 -0
- data/.rubocop.yml +555 -0
- data/CHANGELOG.md +5 -0
- data/CODE_OF_CONDUCT.md +74 -0
- data/CONTRIBUTING.md +209 -0
- data/Gemfile +33 -0
- data/Guardfile +7 -0
- data/LICENSE.md +10 -0
- data/Makefile +18 -0
- data/README.md +189 -0
- data/RELEASING.md +35 -0
- data/Rakefile +83 -0
- data/TROUBLESHOOTING.md +35 -0
- data/bin/platformos-check +29 -0
- data/bin/platformos-check-language-server +29 -0
- data/config/default.yml +98 -0
- data/config/nothing.yml +11 -0
- data/data/platformos_liquid/built_in_liquid_objects.json +66 -0
- data/data/platformos_liquid/deprecated_filters.json +22 -0
- data/data/platformos_liquid/documentation/filters.json +6 -0
- data/data/platformos_liquid/documentation/latest.json +2 -0
- data/data/platformos_liquid/documentation/objects.json +6 -0
- data/data/platformos_liquid/documentation/tags.json +6 -0
- data/docker/check.Dockerfile +3 -0
- data/docker/lsp.Dockerfile +21 -0
- data/docs/api/check.md +15 -0
- data/docs/api/html_check.md +46 -0
- data/docs/api/liquid_check.md +115 -0
- data/docs/api/yaml_check.md +19 -0
- data/docs/checks/TEMPLATE.md.erb +52 -0
- data/docs/checks/convert_include_to_render.md +48 -0
- data/docs/checks/deprecated_filter.md +30 -0
- data/docs/checks/html_parsing_error.md +50 -0
- data/docs/checks/img_lazy_loading.md +63 -0
- data/docs/checks/img_width_and_height.md +79 -0
- data/docs/checks/invalid_args.md +56 -0
- data/docs/checks/liquid_tag.md +65 -0
- data/docs/checks/missing_enable_comment.md +50 -0
- data/docs/checks/missing_template.md +65 -0
- data/docs/checks/parse_json_format.md +76 -0
- data/docs/checks/parser_blocking_javascript.md +97 -0
- data/docs/checks/required_layout_object.md +28 -0
- data/docs/checks/space_inside_braces.md +89 -0
- data/docs/checks/syntax_error.md +49 -0
- data/docs/checks/template_length.md +45 -0
- data/docs/checks/undefined_object.md +71 -0
- data/docs/checks/unknown_filter.md +46 -0
- data/docs/checks/unused_assign.md +63 -0
- data/docs/checks/unused_partial.md +32 -0
- data/docs/checks/valid_yaml.md +48 -0
- data/docs/flamegraph.svg +18488 -0
- data/docs/language_server/code-action-command-palette.png +0 -0
- data/docs/language_server/code-action-flow.png +0 -0
- data/docs/language_server/code-action-keyboard.png +0 -0
- data/docs/language_server/code-action-light-bulb.png +0 -0
- data/docs/language_server/code-action-problem.png +0 -0
- data/docs/language_server/code-action-quickfix.png +0 -0
- data/docs/language_server/how_to_correct_code_with_code_actions_and_execute_command.md +197 -0
- data/docs/preview.png +0 -0
- data/exe/platformos-check +6 -0
- data/exe/platformos-check-language-server +7 -0
- data/lib/platformos_check/analyzer.rb +178 -0
- data/lib/platformos_check/api_call_file.rb +9 -0
- data/lib/platformos_check/app.rb +138 -0
- data/lib/platformos_check/app_file.rb +89 -0
- data/lib/platformos_check/app_file_rewriter.rb +79 -0
- data/lib/platformos_check/asset_file.rb +34 -0
- data/lib/platformos_check/bug.rb +23 -0
- data/lib/platformos_check/check.rb +163 -0
- data/lib/platformos_check/checks/TEMPLATE.rb.erb +11 -0
- data/lib/platformos_check/checks/convert_include_to_render.rb +17 -0
- data/lib/platformos_check/checks/deprecated_filter.rb +123 -0
- data/lib/platformos_check/checks/html_parsing_error.rb +13 -0
- data/lib/platformos_check/checks/img_lazy_loading.rb +18 -0
- data/lib/platformos_check/checks/img_width_and_height.rb +46 -0
- data/lib/platformos_check/checks/invalid_args.rb +81 -0
- data/lib/platformos_check/checks/liquid_tag.rb +47 -0
- data/lib/platformos_check/checks/missing_enable_comment.rb +37 -0
- data/lib/platformos_check/checks/missing_template.rb +107 -0
- data/lib/platformos_check/checks/parse_json_format.rb +31 -0
- data/lib/platformos_check/checks/parser_blocking_javascript.rb +17 -0
- data/lib/platformos_check/checks/required_layout_object.rb +41 -0
- data/lib/platformos_check/checks/space_inside_braces.rb +150 -0
- data/lib/platformos_check/checks/syntax_error.rb +31 -0
- data/lib/platformos_check/checks/template_length.rb +20 -0
- data/lib/platformos_check/checks/undefined_object.rb +206 -0
- data/lib/platformos_check/checks/unknown_filter.rb +27 -0
- data/lib/platformos_check/checks/unused_assign.rb +101 -0
- data/lib/platformos_check/checks/unused_partial.rb +93 -0
- data/lib/platformos_check/checks/valid_yaml.rb +16 -0
- data/lib/platformos_check/checks.rb +73 -0
- data/lib/platformos_check/checks_tracking.rb +9 -0
- data/lib/platformos_check/cli.rb +239 -0
- data/lib/platformos_check/config.rb +219 -0
- data/lib/platformos_check/config_file.rb +6 -0
- data/lib/platformos_check/corrector.rb +68 -0
- data/lib/platformos_check/disabled_check.rb +44 -0
- data/lib/platformos_check/disabled_checks.rb +96 -0
- data/lib/platformos_check/email_file.rb +9 -0
- data/lib/platformos_check/exceptions.rb +36 -0
- data/lib/platformos_check/file_system_storage.rb +93 -0
- data/lib/platformos_check/graphql_file.rb +68 -0
- data/lib/platformos_check/html_check.rb +8 -0
- data/lib/platformos_check/html_node.rb +210 -0
- data/lib/platformos_check/html_visitor.rb +36 -0
- data/lib/platformos_check/in_memory_storage.rb +68 -0
- data/lib/platformos_check/json_file.rb +57 -0
- data/lib/platformos_check/json_helper.rb +73 -0
- data/lib/platformos_check/json_helpers.rb +24 -0
- data/lib/platformos_check/json_printer.rb +32 -0
- data/lib/platformos_check/language_server/bridge.rb +167 -0
- data/lib/platformos_check/language_server/channel.rb +69 -0
- data/lib/platformos_check/language_server/client_capabilities.rb +27 -0
- data/lib/platformos_check/language_server/code_action_engine.rb +32 -0
- data/lib/platformos_check/language_server/code_action_provider.rb +41 -0
- data/lib/platformos_check/language_server/code_action_providers/quickfix_code_action_provider.rb +85 -0
- data/lib/platformos_check/language_server/code_action_providers/source_fix_all_code_action_provider.rb +41 -0
- data/lib/platformos_check/language_server/completion_context.rb +52 -0
- data/lib/platformos_check/language_server/completion_engine.rb +32 -0
- data/lib/platformos_check/language_server/completion_helper.rb +26 -0
- data/lib/platformos_check/language_server/completion_provider.rb +53 -0
- data/lib/platformos_check/language_server/completion_providers/assignments_completion_provider.rb +40 -0
- data/lib/platformos_check/language_server/completion_providers/filter_completion_provider.rb +102 -0
- data/lib/platformos_check/language_server/completion_providers/object_attribute_completion_provider.rb +48 -0
- data/lib/platformos_check/language_server/completion_providers/object_completion_provider.rb +38 -0
- data/lib/platformos_check/language_server/completion_providers/render_snippet_completion_provider.rb +50 -0
- data/lib/platformos_check/language_server/completion_providers/tag_completion_provider.rb +41 -0
- data/lib/platformos_check/language_server/configuration.rb +89 -0
- data/lib/platformos_check/language_server/constants.rb +29 -0
- data/lib/platformos_check/language_server/diagnostic.rb +129 -0
- data/lib/platformos_check/language_server/diagnostics_engine.rb +131 -0
- data/lib/platformos_check/language_server/diagnostics_manager.rb +184 -0
- data/lib/platformos_check/language_server/document_change_corrector.rb +271 -0
- data/lib/platformos_check/language_server/document_link_engine.rb +21 -0
- data/lib/platformos_check/language_server/document_link_provider.rb +71 -0
- data/lib/platformos_check/language_server/document_link_providers/asset_document_link_provider.rb +11 -0
- data/lib/platformos_check/language_server/document_link_providers/include_document_link_provider.rb +11 -0
- data/lib/platformos_check/language_server/document_link_providers/render_document_link_provider.rb +11 -0
- data/lib/platformos_check/language_server/document_link_providers/section_document_link_provider.rb +11 -0
- data/lib/platformos_check/language_server/execute_command_engine.rb +19 -0
- data/lib/platformos_check/language_server/execute_command_provider.rb +30 -0
- data/lib/platformos_check/language_server/execute_command_providers/correction_execute_command_provider.rb +48 -0
- data/lib/platformos_check/language_server/execute_command_providers/run_checks_execute_command_provider.rb +28 -0
- data/lib/platformos_check/language_server/handler.rb +310 -0
- data/lib/platformos_check/language_server/hover_engine.rb +32 -0
- data/lib/platformos_check/language_server/hover_provider.rb +53 -0
- data/lib/platformos_check/language_server/hover_providers/filter_hover_provider.rb +113 -0
- data/lib/platformos_check/language_server/io_messenger.rb +109 -0
- data/lib/platformos_check/language_server/messenger.rb +27 -0
- data/lib/platformos_check/language_server/protocol.rb +55 -0
- data/lib/platformos_check/language_server/server.rb +188 -0
- data/lib/platformos_check/language_server/tokens.rb +55 -0
- data/lib/platformos_check/language_server/type_helper.rb +22 -0
- data/lib/platformos_check/language_server/uri_helper.rb +39 -0
- data/lib/platformos_check/language_server/variable_lookup_finder/assignments_finder/node_handler.rb +87 -0
- data/lib/platformos_check/language_server/variable_lookup_finder/assignments_finder/scope.rb +60 -0
- data/lib/platformos_check/language_server/variable_lookup_finder/assignments_finder/scope_visitor.rb +44 -0
- data/lib/platformos_check/language_server/variable_lookup_finder/assignments_finder.rb +76 -0
- data/lib/platformos_check/language_server/variable_lookup_finder/constants.rb +44 -0
- data/lib/platformos_check/language_server/variable_lookup_finder/liquid_fixer.rb +103 -0
- data/lib/platformos_check/language_server/variable_lookup_finder/potential_lookup.rb +10 -0
- data/lib/platformos_check/language_server/variable_lookup_finder/tolerant_parser.rb +94 -0
- data/lib/platformos_check/language_server/variable_lookup_finder.rb +262 -0
- data/lib/platformos_check/language_server/variable_lookup_traverser.rb +70 -0
- data/lib/platformos_check/language_server/versioned_in_memory_storage.rb +84 -0
- data/lib/platformos_check/language_server.rb +71 -0
- data/lib/platformos_check/layout_file.rb +15 -0
- data/lib/platformos_check/liquid_check.rb +10 -0
- data/lib/platformos_check/liquid_file.rb +102 -0
- data/lib/platformos_check/liquid_node.rb +570 -0
- data/lib/platformos_check/liquid_visitor.rb +39 -0
- data/lib/platformos_check/migration_file.rb +9 -0
- data/lib/platformos_check/node.rb +53 -0
- data/lib/platformos_check/offense.rb +228 -0
- data/lib/platformos_check/page_file.rb +9 -0
- data/lib/platformos_check/parsing_helpers.rb +21 -0
- data/lib/platformos_check/partial_file.rb +15 -0
- data/lib/platformos_check/platformos_liquid/deprecated_filter.rb +31 -0
- data/lib/platformos_check/platformos_liquid/documentation/markdown_template.rb +51 -0
- data/lib/platformos_check/platformos_liquid/documentation.rb +45 -0
- data/lib/platformos_check/platformos_liquid/filter.rb +19 -0
- data/lib/platformos_check/platformos_liquid/object.rb +15 -0
- data/lib/platformos_check/platformos_liquid/source_index/base_entry.rb +66 -0
- data/lib/platformos_check/platformos_liquid/source_index/base_state.rb +23 -0
- data/lib/platformos_check/platformos_liquid/source_index/filter_entry.rb +26 -0
- data/lib/platformos_check/platformos_liquid/source_index/filter_state.rb +11 -0
- data/lib/platformos_check/platformos_liquid/source_index/object_entry.rb +20 -0
- data/lib/platformos_check/platformos_liquid/source_index/object_state.rb +11 -0
- data/lib/platformos_check/platformos_liquid/source_index/parameter_entry.rb +25 -0
- data/lib/platformos_check/platformos_liquid/source_index/property_entry.rb +21 -0
- data/lib/platformos_check/platformos_liquid/source_index/return_type_entry.rb +41 -0
- data/lib/platformos_check/platformos_liquid/source_index/tag_entry.rb +24 -0
- data/lib/platformos_check/platformos_liquid/source_index/tag_state.rb +11 -0
- data/lib/platformos_check/platformos_liquid/source_index.rb +79 -0
- data/lib/platformos_check/platformos_liquid/source_manager.rb +116 -0
- data/lib/platformos_check/platformos_liquid/tag.rb +59 -0
- data/lib/platformos_check/platformos_liquid.rb +21 -0
- data/lib/platformos_check/position.rb +180 -0
- data/lib/platformos_check/position_helper.rb +57 -0
- data/lib/platformos_check/printer.rb +87 -0
- data/lib/platformos_check/regex_helpers.rb +21 -0
- data/lib/platformos_check/releaser.rb +43 -0
- data/lib/platformos_check/schema_file.rb +6 -0
- data/lib/platformos_check/sms_file.rb +9 -0
- data/lib/platformos_check/storage.rb +29 -0
- data/lib/platformos_check/string_helpers.rb +48 -0
- data/lib/platformos_check/tags/background.rb +67 -0
- data/lib/platformos_check/tags/base.rb +14 -0
- data/lib/platformos_check/tags/base_block.rb +14 -0
- data/lib/platformos_check/tags/base_tag_methods.rb +59 -0
- data/lib/platformos_check/tags/cache.rb +13 -0
- data/lib/platformos_check/tags/export.rb +30 -0
- data/lib/platformos_check/tags/form.rb +19 -0
- data/lib/platformos_check/tags/function.rb +58 -0
- data/lib/platformos_check/tags/graphql.rb +70 -0
- data/lib/platformos_check/tags/hash_assign.rb +75 -0
- data/lib/platformos_check/tags/log.rb +15 -0
- data/lib/platformos_check/tags/parse_json.rb +24 -0
- data/lib/platformos_check/tags/print.rb +20 -0
- data/lib/platformos_check/tags/redirect_to.rb +15 -0
- data/lib/platformos_check/tags/render.rb +60 -0
- data/lib/platformos_check/tags/response_headers.rb +20 -0
- data/lib/platformos_check/tags/response_status.rb +20 -0
- data/lib/platformos_check/tags/return.rb +20 -0
- data/lib/platformos_check/tags/session.rb +27 -0
- data/lib/platformos_check/tags/sign_in.rb +27 -0
- data/lib/platformos_check/tags/spam_protection.rb +15 -0
- data/lib/platformos_check/tags/theme_render.rb +58 -0
- data/lib/platformos_check/tags/try.rb +59 -0
- data/lib/platformos_check/tags.rb +65 -0
- data/lib/platformos_check/translation_file.rb +6 -0
- data/lib/platformos_check/user_schema_file.rb +6 -0
- data/lib/platformos_check/version.rb +5 -0
- data/lib/platformos_check/yaml_check.rb +11 -0
- data/lib/platformos_check/yaml_file.rb +57 -0
- data/lib/platformos_check.rb +106 -0
- data/platformos-check.gemspec +34 -0
- metadata +329 -0
|
@@ -0,0 +1,103 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module PlatformosCheck
|
|
4
|
+
module LanguageServer
|
|
5
|
+
module VariableLookupFinder
|
|
6
|
+
##
|
|
7
|
+
# Attempt to turn the code of the token until the cursor position into
|
|
8
|
+
# valid liquid code.
|
|
9
|
+
#
|
|
10
|
+
class LiquidFixer
|
|
11
|
+
include Constants
|
|
12
|
+
|
|
13
|
+
attr_reader :content, :cursor
|
|
14
|
+
|
|
15
|
+
def initialize(content, cursor = nil)
|
|
16
|
+
@content = content
|
|
17
|
+
@cursor = cursor || content.size
|
|
18
|
+
end
|
|
19
|
+
|
|
20
|
+
def parsable
|
|
21
|
+
# Welcome to Hackcity
|
|
22
|
+
@markup = content[0...cursor]
|
|
23
|
+
|
|
24
|
+
catch(:empty_lookup_markup) do
|
|
25
|
+
# close open delimiters
|
|
26
|
+
@markup += "'" if @markup.count("'").odd?
|
|
27
|
+
@markup += '"' if @markup.count('"').odd?
|
|
28
|
+
@markup += "]" if UNCLOSED_SQUARE_BRACKET.match?(@markup)
|
|
29
|
+
|
|
30
|
+
@ends_with_blank_potential_lookup = @markup =~ ENDS_WITH_BLANK_POTENTIAL_LOOKUP
|
|
31
|
+
@markup = last_line if liquid_tag?
|
|
32
|
+
|
|
33
|
+
@markup = "{% #{@markup}" unless has_start_tag?
|
|
34
|
+
|
|
35
|
+
# close the tag
|
|
36
|
+
@markup += tag_end unless has_end_tag?
|
|
37
|
+
|
|
38
|
+
# close if statements
|
|
39
|
+
@markup += '{% endif %}' if tag?('if')
|
|
40
|
+
|
|
41
|
+
# close unless statements
|
|
42
|
+
@markup += '{% endunless %}' if tag?('unless')
|
|
43
|
+
|
|
44
|
+
# close elsif statements
|
|
45
|
+
@markup = "{% if x %}#{@markup}{% endif %}" if tag?('elsif')
|
|
46
|
+
|
|
47
|
+
# close case statements
|
|
48
|
+
@markup += '{% endcase %}' if tag?('case')
|
|
49
|
+
|
|
50
|
+
# close when statements
|
|
51
|
+
@markup = "{% case x %}#{@markup}{% endcase %}" if tag?('when')
|
|
52
|
+
|
|
53
|
+
# close for statements
|
|
54
|
+
@markup += '{% endfor %}' if tag?('for')
|
|
55
|
+
|
|
56
|
+
# close tablerow statements
|
|
57
|
+
@markup += '{% endtablerow %}' if tag?('tablerow')
|
|
58
|
+
|
|
59
|
+
@markup
|
|
60
|
+
end
|
|
61
|
+
end
|
|
62
|
+
|
|
63
|
+
private
|
|
64
|
+
|
|
65
|
+
def tag?(tag_name)
|
|
66
|
+
if @markup&.match?(tag_regex(tag_name))
|
|
67
|
+
throw(:empty_lookup_markup, '') if @ends_with_blank_potential_lookup
|
|
68
|
+
true
|
|
69
|
+
else
|
|
70
|
+
false
|
|
71
|
+
end
|
|
72
|
+
end
|
|
73
|
+
|
|
74
|
+
def last_line
|
|
75
|
+
lines = @markup.rstrip.lines
|
|
76
|
+
|
|
77
|
+
last_line = lines.pop.lstrip while last_line.nil? || last_line =~ ANY_ENDING_TAG
|
|
78
|
+
last_line
|
|
79
|
+
end
|
|
80
|
+
|
|
81
|
+
def liquid_tag?
|
|
82
|
+
@markup =~ tag_regex('liquid')
|
|
83
|
+
end
|
|
84
|
+
|
|
85
|
+
def has_start_tag?
|
|
86
|
+
@markup =~ ANY_STARTING_TAG
|
|
87
|
+
end
|
|
88
|
+
|
|
89
|
+
def has_end_tag?
|
|
90
|
+
@markup =~ ANY_ENDING_TAG
|
|
91
|
+
end
|
|
92
|
+
|
|
93
|
+
def tag_end
|
|
94
|
+
VARIABLE_START.match?(@markup) ? ' }}' : ' %}'
|
|
95
|
+
end
|
|
96
|
+
|
|
97
|
+
def tag_regex(tag_name)
|
|
98
|
+
PlatformosLiquid::Tag.tag_regex(tag_name)
|
|
99
|
+
end
|
|
100
|
+
end
|
|
101
|
+
end
|
|
102
|
+
end
|
|
103
|
+
end
|
|
@@ -0,0 +1,94 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module PlatformosCheck
|
|
4
|
+
module LanguageServer
|
|
5
|
+
module VariableLookupFinder
|
|
6
|
+
module TolerantParser
|
|
7
|
+
class Template
|
|
8
|
+
class << self
|
|
9
|
+
def parse(content)
|
|
10
|
+
##
|
|
11
|
+
# The tolerant parser relies on a tolerant custom parse
|
|
12
|
+
# context to creates a new 'Template' object, even when
|
|
13
|
+
# a block is not closed.
|
|
14
|
+
Liquid::Template.parse(content, custom_parse_context)
|
|
15
|
+
end
|
|
16
|
+
|
|
17
|
+
private
|
|
18
|
+
|
|
19
|
+
def custom_parse_context
|
|
20
|
+
ParseContext.new
|
|
21
|
+
end
|
|
22
|
+
end
|
|
23
|
+
end
|
|
24
|
+
|
|
25
|
+
class ParseContext < Liquid::ParseContext
|
|
26
|
+
def new_block_body
|
|
27
|
+
BlockBody.new
|
|
28
|
+
end
|
|
29
|
+
end
|
|
30
|
+
|
|
31
|
+
class BlockBody < Liquid::BlockBody
|
|
32
|
+
##
|
|
33
|
+
# The tags are statically defined and referenced at the
|
|
34
|
+
# 'Liquid::Template', so the TolerantParser just uses the
|
|
35
|
+
# redefined tags at this custom block body. Thus, there's
|
|
36
|
+
# no side-effects between the regular and the tolerant parsers.
|
|
37
|
+
def registered_tags
|
|
38
|
+
Tags.new(super)
|
|
39
|
+
end
|
|
40
|
+
end
|
|
41
|
+
|
|
42
|
+
class Tags
|
|
43
|
+
module TolerantBlockBody
|
|
44
|
+
##
|
|
45
|
+
# This module defines the tolerant parse body that doesn't
|
|
46
|
+
# raise syntax errors when a block is not closed. Thus, the
|
|
47
|
+
# tolerant parser can build the AST for templates with this
|
|
48
|
+
# kind of error, which is quite common in language servers.
|
|
49
|
+
def parse_body(body, tokens)
|
|
50
|
+
super
|
|
51
|
+
rescue StandardError
|
|
52
|
+
false
|
|
53
|
+
end
|
|
54
|
+
end
|
|
55
|
+
|
|
56
|
+
class Case < Liquid::Case
|
|
57
|
+
include TolerantBlockBody
|
|
58
|
+
end
|
|
59
|
+
|
|
60
|
+
class For < Liquid::For
|
|
61
|
+
include TolerantBlockBody
|
|
62
|
+
end
|
|
63
|
+
|
|
64
|
+
class If < Liquid::If
|
|
65
|
+
include TolerantBlockBody
|
|
66
|
+
end
|
|
67
|
+
|
|
68
|
+
class TableRow < Liquid::TableRow
|
|
69
|
+
include TolerantBlockBody
|
|
70
|
+
end
|
|
71
|
+
|
|
72
|
+
class Unless < Liquid::Unless
|
|
73
|
+
include TolerantBlockBody
|
|
74
|
+
end
|
|
75
|
+
|
|
76
|
+
def initialize(standard_tags)
|
|
77
|
+
@standard_tags = standard_tags
|
|
78
|
+
@tolerant_tags = {
|
|
79
|
+
'case' => Case,
|
|
80
|
+
'for' => For,
|
|
81
|
+
'if' => If,
|
|
82
|
+
'tablerow' => TableRow,
|
|
83
|
+
'unless' => Unless
|
|
84
|
+
}
|
|
85
|
+
end
|
|
86
|
+
|
|
87
|
+
def [](key)
|
|
88
|
+
@tolerant_tags[key] || @standard_tags[key]
|
|
89
|
+
end
|
|
90
|
+
end
|
|
91
|
+
end
|
|
92
|
+
end
|
|
93
|
+
end
|
|
94
|
+
end
|
|
@@ -0,0 +1,262 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
require 'ostruct'
|
|
4
|
+
|
|
5
|
+
module PlatformosCheck
|
|
6
|
+
module LanguageServer
|
|
7
|
+
module VariableLookupFinder
|
|
8
|
+
include Constants
|
|
9
|
+
include TypeHelper
|
|
10
|
+
extend self
|
|
11
|
+
|
|
12
|
+
def lookup(context)
|
|
13
|
+
content = context.content
|
|
14
|
+
cursor = context.cursor
|
|
15
|
+
|
|
16
|
+
return if cursor_is_on_bracket_position_that_cant_be_completed(content, cursor)
|
|
17
|
+
|
|
18
|
+
variable_lookup = lookup_liquid_variable(content, cursor) || lookup_liquid_tag(content, cursor)
|
|
19
|
+
|
|
20
|
+
return variable_lookup if variable_lookup.is_a?(PotentialLookup)
|
|
21
|
+
return unless variable_lookup.is_a?(Liquid::VariableLookup)
|
|
22
|
+
|
|
23
|
+
potential_lookup(variable_lookup, context)
|
|
24
|
+
end
|
|
25
|
+
|
|
26
|
+
def lookup_literal(context)
|
|
27
|
+
lookup_liquid_variable(context.content, context.cursor)
|
|
28
|
+
end
|
|
29
|
+
|
|
30
|
+
private
|
|
31
|
+
|
|
32
|
+
def potential_lookup(variable, context)
|
|
33
|
+
return as_potential_lookup(variable) if context.buffer.nil? || context.buffer.empty?
|
|
34
|
+
|
|
35
|
+
buffer = context.buffer[0...context.absolute_cursor]
|
|
36
|
+
lookups = variable.lookups
|
|
37
|
+
assignments = find_assignments(buffer)
|
|
38
|
+
assignments_path = []
|
|
39
|
+
|
|
40
|
+
while assignments[variable.name] && !assignments_path.include?(assignments[variable.name])
|
|
41
|
+
variable = assignments[variable.name]
|
|
42
|
+
lookups = variable.lookups + lookups
|
|
43
|
+
|
|
44
|
+
assignments_path << variable
|
|
45
|
+
end
|
|
46
|
+
|
|
47
|
+
as_potential_lookup(variable, lookups:)
|
|
48
|
+
end
|
|
49
|
+
|
|
50
|
+
def find_assignments(buffer)
|
|
51
|
+
finder = AssignmentsFinder.new(buffer)
|
|
52
|
+
finder.find!
|
|
53
|
+
finder.assignments
|
|
54
|
+
end
|
|
55
|
+
|
|
56
|
+
def as_potential_lookup(variable, lookups: nil)
|
|
57
|
+
PotentialLookup.new(variable.name, lookups || variable.lookups)
|
|
58
|
+
end
|
|
59
|
+
|
|
60
|
+
def cursor_is_on_bracket_position_that_cant_be_completed(content, cursor)
|
|
61
|
+
content_before_cursor = content[0..cursor - 1]
|
|
62
|
+
return false unless /[\[\]]/.match?(content_before_cursor)
|
|
63
|
+
|
|
64
|
+
content_before_cursor =~ ENDS_IN_BRACKET_POSITION_THAT_CANT_BE_COMPLETED
|
|
65
|
+
end
|
|
66
|
+
|
|
67
|
+
def cursor_is_on_liquid_variable_lookup_position(content, cursor)
|
|
68
|
+
previous_char = content[cursor - 1]
|
|
69
|
+
is_liquid_variable = content =~ Liquid::VariableStart
|
|
70
|
+
is_in_variable_segment = previous_char =~ VARIABLE_LOOKUP_CHARACTERS
|
|
71
|
+
is_on_blank_variable_lookup_position = content[0..cursor - 1] =~ /[{:,-]\s+$/
|
|
72
|
+
(
|
|
73
|
+
is_liquid_variable && (
|
|
74
|
+
is_in_variable_segment ||
|
|
75
|
+
is_on_blank_variable_lookup_position
|
|
76
|
+
)
|
|
77
|
+
)
|
|
78
|
+
end
|
|
79
|
+
|
|
80
|
+
def lookup_liquid_variable(content, cursor)
|
|
81
|
+
return unless cursor_is_on_liquid_variable_lookup_position(content, cursor)
|
|
82
|
+
|
|
83
|
+
start_index = content.match(/#{Liquid::VariableStart}-?/o).end(0) + 1
|
|
84
|
+
end_index = cursor - 1
|
|
85
|
+
|
|
86
|
+
# We take the following content
|
|
87
|
+
# - start after the first two {{
|
|
88
|
+
# - end at cursor position
|
|
89
|
+
#
|
|
90
|
+
# That way, we'll have a partial liquid variable that
|
|
91
|
+
# can be parsed such that the "last" variable_lookup
|
|
92
|
+
# will be the one we're trying to complete.
|
|
93
|
+
markup = content[start_index..end_index]
|
|
94
|
+
|
|
95
|
+
# Early return for incomplete variables
|
|
96
|
+
return empty_lookup if /\s+$/.match?(markup)
|
|
97
|
+
|
|
98
|
+
# Now we go to hack city... The cursor might be in the middle
|
|
99
|
+
# of a string/square bracket lookup. We need to close those
|
|
100
|
+
# otherwise the variable parse won't work.
|
|
101
|
+
markup += "'" if markup.count("'").odd?
|
|
102
|
+
markup += '"' if markup.count('"').odd?
|
|
103
|
+
markup += "]" if UNCLOSED_SQUARE_BRACKET.match?(markup)
|
|
104
|
+
|
|
105
|
+
variable = variable_from_markup(markup)
|
|
106
|
+
|
|
107
|
+
variable_lookup_for_liquid_variable(variable)
|
|
108
|
+
end
|
|
109
|
+
|
|
110
|
+
def cursor_is_on_liquid_tag_lookup_position(content, cursor)
|
|
111
|
+
markup = content[0..cursor - 1]
|
|
112
|
+
is_liquid_tag = content.match?(Liquid::TagStart)
|
|
113
|
+
is_in_variable_segment = markup =~ ENDS_WITH_POTENTIAL_LOOKUP
|
|
114
|
+
is_on_blank_variable_lookup_position = markup =~ ENDS_WITH_BLANK_POTENTIAL_LOOKUP
|
|
115
|
+
(
|
|
116
|
+
is_liquid_tag && (
|
|
117
|
+
is_in_variable_segment ||
|
|
118
|
+
is_on_blank_variable_lookup_position
|
|
119
|
+
)
|
|
120
|
+
)
|
|
121
|
+
end
|
|
122
|
+
|
|
123
|
+
# Context:
|
|
124
|
+
#
|
|
125
|
+
# We know full well that the code as it is being typed is probably not
|
|
126
|
+
# something that can be parsed by liquid.
|
|
127
|
+
#
|
|
128
|
+
# How this works:
|
|
129
|
+
#
|
|
130
|
+
# 1. Attempt to turn the code of the token until the cursor position into
|
|
131
|
+
# valid liquid code with some hacks.
|
|
132
|
+
# 2. If the code ends in space at a "potential lookup" spot
|
|
133
|
+
# a. Then return an empty variable lookup
|
|
134
|
+
# 3. Parse the valid liquid code
|
|
135
|
+
# 4. Attempt to extract a VariableLookup from Liquid::Template
|
|
136
|
+
def lookup_liquid_tag(content, cursor)
|
|
137
|
+
return unless cursor_is_on_liquid_tag_lookup_position(content, cursor)
|
|
138
|
+
|
|
139
|
+
markup = parseable_markup(content, cursor)
|
|
140
|
+
return empty_lookup if markup.empty?
|
|
141
|
+
|
|
142
|
+
template = Liquid::Template.parse(markup)
|
|
143
|
+
current_tag = template.root.nodelist[0]
|
|
144
|
+
|
|
145
|
+
case current_tag&.tag_name
|
|
146
|
+
when "if", "unless"
|
|
147
|
+
variable_lookup_for_if_tag(current_tag)
|
|
148
|
+
when "case"
|
|
149
|
+
variable_lookup_for_case_tag(current_tag)
|
|
150
|
+
when "cycle"
|
|
151
|
+
variable_lookup_for_cycle_tag(current_tag)
|
|
152
|
+
when "for"
|
|
153
|
+
variable_lookup_for_for_tag(current_tag)
|
|
154
|
+
when "tablerow"
|
|
155
|
+
variable_lookup_for_tablerow_tag(current_tag)
|
|
156
|
+
when "render"
|
|
157
|
+
variable_lookup_for_render_tag(current_tag)
|
|
158
|
+
when "assign"
|
|
159
|
+
variable_lookup_for_assign_tag(current_tag)
|
|
160
|
+
when "echo"
|
|
161
|
+
variable_lookup_for_echo_tag(current_tag)
|
|
162
|
+
else
|
|
163
|
+
empty_lookup
|
|
164
|
+
end
|
|
165
|
+
rescue Liquid::SyntaxError
|
|
166
|
+
# We don't complete variable for liquid syntax errors
|
|
167
|
+
empty_lookup
|
|
168
|
+
end
|
|
169
|
+
|
|
170
|
+
def parseable_markup(content, cursor = nil)
|
|
171
|
+
LiquidFixer.new(content, cursor).parsable
|
|
172
|
+
end
|
|
173
|
+
|
|
174
|
+
def variable_lookup_for_if_tag(if_tag)
|
|
175
|
+
condition = if_tag.blocks.last
|
|
176
|
+
variable_lookup_for_condition(condition)
|
|
177
|
+
end
|
|
178
|
+
|
|
179
|
+
def variable_lookup_for_condition(condition)
|
|
180
|
+
return variable_lookup_for_condition(condition.child_condition) if condition.child_condition
|
|
181
|
+
return condition.right if condition.right
|
|
182
|
+
|
|
183
|
+
condition.left
|
|
184
|
+
end
|
|
185
|
+
|
|
186
|
+
def variable_lookup_for_case_tag(case_tag)
|
|
187
|
+
return variable_lookup_for_case_block(case_tag.blocks.last) unless case_tag.blocks.empty?
|
|
188
|
+
|
|
189
|
+
case_tag.left
|
|
190
|
+
end
|
|
191
|
+
|
|
192
|
+
def variable_lookup_for_case_block(condition)
|
|
193
|
+
condition.right
|
|
194
|
+
end
|
|
195
|
+
|
|
196
|
+
def variable_lookup_for_cycle_tag(cycle_tag)
|
|
197
|
+
cycle_tag.variables.last
|
|
198
|
+
end
|
|
199
|
+
|
|
200
|
+
def variable_lookup_for_for_tag(for_tag)
|
|
201
|
+
for_tag.collection_name
|
|
202
|
+
end
|
|
203
|
+
|
|
204
|
+
def variable_lookup_for_tablerow_tag(tablerow_tag)
|
|
205
|
+
tablerow_tag.collection_name
|
|
206
|
+
end
|
|
207
|
+
|
|
208
|
+
def variable_lookup_for_render_tag(render_tag)
|
|
209
|
+
return empty_lookup if /:\s*$/.match?(render_tag.raw)
|
|
210
|
+
|
|
211
|
+
render_tag.attributes.values.last
|
|
212
|
+
end
|
|
213
|
+
|
|
214
|
+
def variable_lookup_for_assign_tag(assign_tag)
|
|
215
|
+
variable_lookup_for_liquid_variable(assign_tag.from)
|
|
216
|
+
end
|
|
217
|
+
|
|
218
|
+
def variable_lookup_for_echo_tag(echo_tag)
|
|
219
|
+
variable_lookup_for_liquid_variable(echo_tag.variable)
|
|
220
|
+
end
|
|
221
|
+
|
|
222
|
+
def variable_lookup_for_liquid_variable(variable)
|
|
223
|
+
has_filters = !variable.filters.empty?
|
|
224
|
+
|
|
225
|
+
# Can complete after trailing comma or :
|
|
226
|
+
if has_filters && variable.raw =~ /[:,]\s*$/
|
|
227
|
+
empty_lookup
|
|
228
|
+
elsif has_filters
|
|
229
|
+
last_filter_argument(variable.filters)
|
|
230
|
+
elsif variable.name.nil?
|
|
231
|
+
empty_lookup
|
|
232
|
+
elsif variable.name.is_a?(Liquid::VariableLookup)
|
|
233
|
+
variable.name
|
|
234
|
+
else
|
|
235
|
+
PotentialLookup.new(input_type_of(variable.name), [])
|
|
236
|
+
end
|
|
237
|
+
end
|
|
238
|
+
|
|
239
|
+
def empty_lookup
|
|
240
|
+
Liquid::VariableLookup.parse('')
|
|
241
|
+
end
|
|
242
|
+
|
|
243
|
+
# We want the last thing in variable.filters which is at most
|
|
244
|
+
# an array that looks like [name, positional_args, hash_arg]
|
|
245
|
+
def last_filter_argument(filters)
|
|
246
|
+
filter = filters.last
|
|
247
|
+
return filter[2].values.last if filter.size == 3
|
|
248
|
+
return filter[1].last if filter.size == 2
|
|
249
|
+
|
|
250
|
+
nil
|
|
251
|
+
end
|
|
252
|
+
|
|
253
|
+
def variable_from_markup(markup, parse_context = Liquid::ParseContext.new)
|
|
254
|
+
Liquid::Variable.new(markup, parse_context)
|
|
255
|
+
end
|
|
256
|
+
|
|
257
|
+
def tag_regex(tag)
|
|
258
|
+
PlatformosLiquid::Tag.tag_regex(tag)
|
|
259
|
+
end
|
|
260
|
+
end
|
|
261
|
+
end
|
|
262
|
+
end
|
|
@@ -0,0 +1,70 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module PlatformosCheck
|
|
4
|
+
module LanguageServer
|
|
5
|
+
module VariableLookupTraverser
|
|
6
|
+
extend self
|
|
7
|
+
|
|
8
|
+
def lookup_object_and_property(potential_lookup)
|
|
9
|
+
object, generic_type = find_object_and_generic_type(potential_lookup)
|
|
10
|
+
property = nil
|
|
11
|
+
|
|
12
|
+
potential_lookup.lookups.each do |name|
|
|
13
|
+
prop = find_property(object, name)
|
|
14
|
+
|
|
15
|
+
next unless prop
|
|
16
|
+
|
|
17
|
+
generic_type = generic_type(prop) if generic_type?(prop)
|
|
18
|
+
|
|
19
|
+
property = prop
|
|
20
|
+
property.return_type = generic_type if prop.generic_type?
|
|
21
|
+
object = find_object(prop.return_type)
|
|
22
|
+
end
|
|
23
|
+
|
|
24
|
+
[object, property]
|
|
25
|
+
end
|
|
26
|
+
|
|
27
|
+
def find_object_and_generic_type(potential_lookup)
|
|
28
|
+
generic_type = nil
|
|
29
|
+
object = find_object(potential_lookup.name)
|
|
30
|
+
|
|
31
|
+
# Objects like 'product' are a complex structure with fields
|
|
32
|
+
# and their return type is not present.
|
|
33
|
+
#
|
|
34
|
+
# However, we also handle objects that have simple built-in types,
|
|
35
|
+
# like 'current_tags', which is an 'array'. So, we follow them until
|
|
36
|
+
# the source type:
|
|
37
|
+
while object&.return_type
|
|
38
|
+
generic_type = generic_type(object) if generic_type?(object)
|
|
39
|
+
object = find_object(object.return_type)
|
|
40
|
+
end
|
|
41
|
+
|
|
42
|
+
[object, generic_type]
|
|
43
|
+
end
|
|
44
|
+
|
|
45
|
+
# Currently, we're handling generic types only for arrays,
|
|
46
|
+
# so we get the array type
|
|
47
|
+
def generic_type(object)
|
|
48
|
+
object.array_type
|
|
49
|
+
end
|
|
50
|
+
|
|
51
|
+
# Currently, we're handling generic types only for arrays,
|
|
52
|
+
# so we check if it's an array type
|
|
53
|
+
def generic_type?(object)
|
|
54
|
+
object.array_type?
|
|
55
|
+
end
|
|
56
|
+
|
|
57
|
+
def find_property(object, property_name)
|
|
58
|
+
object
|
|
59
|
+
&.properties
|
|
60
|
+
&.find { |property| property.name == property_name }
|
|
61
|
+
end
|
|
62
|
+
|
|
63
|
+
def find_object(object_name)
|
|
64
|
+
PlatformosLiquid::SourceIndex
|
|
65
|
+
.objects
|
|
66
|
+
.find { |entry| entry.name == object_name }
|
|
67
|
+
end
|
|
68
|
+
end
|
|
69
|
+
end
|
|
70
|
+
end
|
|
@@ -0,0 +1,84 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module PlatformosCheck
|
|
4
|
+
class VersionedInMemoryStorage < InMemoryStorage
|
|
5
|
+
Version = Struct.new(:id, :version)
|
|
6
|
+
|
|
7
|
+
attr_reader :versions
|
|
8
|
+
|
|
9
|
+
def initialize(files, root = "/dev/null")
|
|
10
|
+
super(files, root)
|
|
11
|
+
@versions = {} # Hash<relative_path, number>
|
|
12
|
+
@mutex = Mutex.new
|
|
13
|
+
end
|
|
14
|
+
|
|
15
|
+
# Motivations:
|
|
16
|
+
# - Need way for LanguageServer to know on which version of a file
|
|
17
|
+
# the check was run on, because we need to know where the
|
|
18
|
+
# TextEdit goes. If the text changed, our TextEdit might not be
|
|
19
|
+
# in the right spot. e.g.
|
|
20
|
+
#
|
|
21
|
+
# Example:
|
|
22
|
+
#
|
|
23
|
+
# ```
|
|
24
|
+
# Hi
|
|
25
|
+
# {{world}}
|
|
26
|
+
# ```
|
|
27
|
+
#
|
|
28
|
+
# Would produce two "SpaceInsideBrace" errors:
|
|
29
|
+
#
|
|
30
|
+
# - One after {{ at index 5 to 6
|
|
31
|
+
# - One before }} at index 10 to 11
|
|
32
|
+
#
|
|
33
|
+
# If the user goes in and changes Hi to Sup, and _then_
|
|
34
|
+
# right clicks to apply the code edit at index 5 to 6, he'd
|
|
35
|
+
# get the following:
|
|
36
|
+
#
|
|
37
|
+
# ```
|
|
38
|
+
# Sup
|
|
39
|
+
# { {world}}
|
|
40
|
+
# ```
|
|
41
|
+
#
|
|
42
|
+
# Which is not a fix at all.
|
|
43
|
+
#
|
|
44
|
+
# Solution:
|
|
45
|
+
# - Have the LanguageServer store the version on textDocument/did{Open,Change,Close}
|
|
46
|
+
# - Have AppFile store the version right after @storage.read.
|
|
47
|
+
# - Add version to the diagnostic meta data
|
|
48
|
+
# - Use diagnostic meta data to determine if we can make a code edit or not
|
|
49
|
+
# - Only offer fixes on "clean" files (or offer the change but specify the version so the editor knows what to do with it)
|
|
50
|
+
def write(relative_path, content, version)
|
|
51
|
+
@mutex.synchronize do
|
|
52
|
+
if version.nil?
|
|
53
|
+
@versions.delete(relative_path)
|
|
54
|
+
else
|
|
55
|
+
@versions[relative_path] = version
|
|
56
|
+
end
|
|
57
|
+
super(relative_path, content)
|
|
58
|
+
end
|
|
59
|
+
end
|
|
60
|
+
|
|
61
|
+
def read_version(relative_path)
|
|
62
|
+
@mutex.synchronize { [read(relative_path), version(relative_path)] }
|
|
63
|
+
end
|
|
64
|
+
|
|
65
|
+
def remove(relative_path)
|
|
66
|
+
@mutex.synchronize do
|
|
67
|
+
@versions.delete(relative_path)
|
|
68
|
+
super(relative_path)
|
|
69
|
+
end
|
|
70
|
+
end
|
|
71
|
+
|
|
72
|
+
def versioned?
|
|
73
|
+
true
|
|
74
|
+
end
|
|
75
|
+
|
|
76
|
+
def version(relative_path)
|
|
77
|
+
@versions[relative_path.to_s]
|
|
78
|
+
end
|
|
79
|
+
|
|
80
|
+
def opened_files
|
|
81
|
+
@versions.keys
|
|
82
|
+
end
|
|
83
|
+
end
|
|
84
|
+
end
|
|
@@ -0,0 +1,71 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
require_relative "language_server/protocol"
|
|
4
|
+
require_relative "language_server/constants"
|
|
5
|
+
require_relative "language_server/configuration"
|
|
6
|
+
require_relative "language_server/channel"
|
|
7
|
+
require_relative "language_server/messenger"
|
|
8
|
+
require_relative "language_server/io_messenger"
|
|
9
|
+
require_relative "language_server/bridge"
|
|
10
|
+
require_relative "language_server/uri_helper"
|
|
11
|
+
require_relative "language_server/type_helper"
|
|
12
|
+
require_relative "language_server/server"
|
|
13
|
+
require_relative "language_server/tokens"
|
|
14
|
+
require_relative "language_server/variable_lookup_finder/potential_lookup"
|
|
15
|
+
require_relative "language_server/variable_lookup_finder/tolerant_parser"
|
|
16
|
+
require_relative "language_server/variable_lookup_finder/assignments_finder/node_handler"
|
|
17
|
+
require_relative "language_server/variable_lookup_finder/assignments_finder/scope_visitor"
|
|
18
|
+
require_relative "language_server/variable_lookup_finder/assignments_finder/scope"
|
|
19
|
+
require_relative "language_server/variable_lookup_finder/assignments_finder"
|
|
20
|
+
require_relative "language_server/variable_lookup_finder/constants"
|
|
21
|
+
require_relative "language_server/variable_lookup_finder/liquid_fixer"
|
|
22
|
+
require_relative "language_server/variable_lookup_finder"
|
|
23
|
+
require_relative "language_server/variable_lookup_traverser"
|
|
24
|
+
require_relative "language_server/diagnostic"
|
|
25
|
+
require_relative "language_server/diagnostics_manager"
|
|
26
|
+
require_relative "language_server/diagnostics_engine"
|
|
27
|
+
require_relative "language_server/document_change_corrector"
|
|
28
|
+
require_relative "language_server/versioned_in_memory_storage"
|
|
29
|
+
require_relative "language_server/client_capabilities"
|
|
30
|
+
|
|
31
|
+
require_relative "language_server/completion_context"
|
|
32
|
+
require_relative "language_server/completion_helper"
|
|
33
|
+
require_relative "language_server/completion_provider"
|
|
34
|
+
require_relative "language_server/completion_engine"
|
|
35
|
+
Dir[__dir__ + "/language_server/completion_providers/*.rb"].each do |file|
|
|
36
|
+
require file
|
|
37
|
+
end
|
|
38
|
+
|
|
39
|
+
require_relative "language_server/hover_provider"
|
|
40
|
+
require_relative "language_server/hover_engine"
|
|
41
|
+
Dir[__dir__ + "/language_server/hover_providers/*.rb"].each do |file|
|
|
42
|
+
require file
|
|
43
|
+
end
|
|
44
|
+
|
|
45
|
+
require_relative "language_server/document_link_provider"
|
|
46
|
+
require_relative "language_server/document_link_engine"
|
|
47
|
+
Dir[__dir__ + "/language_server/document_link_providers/*.rb"].each do |file|
|
|
48
|
+
require file
|
|
49
|
+
end
|
|
50
|
+
|
|
51
|
+
require_relative "language_server/execute_command_provider"
|
|
52
|
+
require_relative "language_server/execute_command_engine"
|
|
53
|
+
Dir[__dir__ + "/language_server/execute_command_providers/*.rb"].each do |file|
|
|
54
|
+
require file
|
|
55
|
+
end
|
|
56
|
+
|
|
57
|
+
require_relative "language_server/code_action_provider"
|
|
58
|
+
require_relative "language_server/code_action_engine"
|
|
59
|
+
Dir[__dir__ + "/language_server/code_action_providers/*.rb"].each do |file|
|
|
60
|
+
require file
|
|
61
|
+
end
|
|
62
|
+
|
|
63
|
+
require_relative "language_server/handler"
|
|
64
|
+
|
|
65
|
+
module PlatformosCheck
|
|
66
|
+
module LanguageServer
|
|
67
|
+
def self.start
|
|
68
|
+
Server.new(messenger: IOMessenger.new).listen
|
|
69
|
+
end
|
|
70
|
+
end
|
|
71
|
+
end
|