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.
Files changed (240) hide show
  1. checksums.yaml +7 -0
  2. data/.dockerignore +2 -0
  3. data/.gitignore +22 -0
  4. data/.rubocop.yml +555 -0
  5. data/CHANGELOG.md +5 -0
  6. data/CODE_OF_CONDUCT.md +74 -0
  7. data/CONTRIBUTING.md +209 -0
  8. data/Gemfile +33 -0
  9. data/Guardfile +7 -0
  10. data/LICENSE.md +10 -0
  11. data/Makefile +18 -0
  12. data/README.md +189 -0
  13. data/RELEASING.md +35 -0
  14. data/Rakefile +83 -0
  15. data/TROUBLESHOOTING.md +35 -0
  16. data/bin/platformos-check +29 -0
  17. data/bin/platformos-check-language-server +29 -0
  18. data/config/default.yml +98 -0
  19. data/config/nothing.yml +11 -0
  20. data/data/platformos_liquid/built_in_liquid_objects.json +66 -0
  21. data/data/platformos_liquid/deprecated_filters.json +22 -0
  22. data/data/platformos_liquid/documentation/filters.json +6 -0
  23. data/data/platformos_liquid/documentation/latest.json +2 -0
  24. data/data/platformos_liquid/documentation/objects.json +6 -0
  25. data/data/platformos_liquid/documentation/tags.json +6 -0
  26. data/docker/check.Dockerfile +3 -0
  27. data/docker/lsp.Dockerfile +21 -0
  28. data/docs/api/check.md +15 -0
  29. data/docs/api/html_check.md +46 -0
  30. data/docs/api/liquid_check.md +115 -0
  31. data/docs/api/yaml_check.md +19 -0
  32. data/docs/checks/TEMPLATE.md.erb +52 -0
  33. data/docs/checks/convert_include_to_render.md +48 -0
  34. data/docs/checks/deprecated_filter.md +30 -0
  35. data/docs/checks/html_parsing_error.md +50 -0
  36. data/docs/checks/img_lazy_loading.md +63 -0
  37. data/docs/checks/img_width_and_height.md +79 -0
  38. data/docs/checks/invalid_args.md +56 -0
  39. data/docs/checks/liquid_tag.md +65 -0
  40. data/docs/checks/missing_enable_comment.md +50 -0
  41. data/docs/checks/missing_template.md +65 -0
  42. data/docs/checks/parse_json_format.md +76 -0
  43. data/docs/checks/parser_blocking_javascript.md +97 -0
  44. data/docs/checks/required_layout_object.md +28 -0
  45. data/docs/checks/space_inside_braces.md +89 -0
  46. data/docs/checks/syntax_error.md +49 -0
  47. data/docs/checks/template_length.md +45 -0
  48. data/docs/checks/undefined_object.md +71 -0
  49. data/docs/checks/unknown_filter.md +46 -0
  50. data/docs/checks/unused_assign.md +63 -0
  51. data/docs/checks/unused_partial.md +32 -0
  52. data/docs/checks/valid_yaml.md +48 -0
  53. data/docs/flamegraph.svg +18488 -0
  54. data/docs/language_server/code-action-command-palette.png +0 -0
  55. data/docs/language_server/code-action-flow.png +0 -0
  56. data/docs/language_server/code-action-keyboard.png +0 -0
  57. data/docs/language_server/code-action-light-bulb.png +0 -0
  58. data/docs/language_server/code-action-problem.png +0 -0
  59. data/docs/language_server/code-action-quickfix.png +0 -0
  60. data/docs/language_server/how_to_correct_code_with_code_actions_and_execute_command.md +197 -0
  61. data/docs/preview.png +0 -0
  62. data/exe/platformos-check +6 -0
  63. data/exe/platformos-check-language-server +7 -0
  64. data/lib/platformos_check/analyzer.rb +178 -0
  65. data/lib/platformos_check/api_call_file.rb +9 -0
  66. data/lib/platformos_check/app.rb +138 -0
  67. data/lib/platformos_check/app_file.rb +89 -0
  68. data/lib/platformos_check/app_file_rewriter.rb +79 -0
  69. data/lib/platformos_check/asset_file.rb +34 -0
  70. data/lib/platformos_check/bug.rb +23 -0
  71. data/lib/platformos_check/check.rb +163 -0
  72. data/lib/platformos_check/checks/TEMPLATE.rb.erb +11 -0
  73. data/lib/platformos_check/checks/convert_include_to_render.rb +17 -0
  74. data/lib/platformos_check/checks/deprecated_filter.rb +123 -0
  75. data/lib/platformos_check/checks/html_parsing_error.rb +13 -0
  76. data/lib/platformos_check/checks/img_lazy_loading.rb +18 -0
  77. data/lib/platformos_check/checks/img_width_and_height.rb +46 -0
  78. data/lib/platformos_check/checks/invalid_args.rb +81 -0
  79. data/lib/platformos_check/checks/liquid_tag.rb +47 -0
  80. data/lib/platformos_check/checks/missing_enable_comment.rb +37 -0
  81. data/lib/platformos_check/checks/missing_template.rb +107 -0
  82. data/lib/platformos_check/checks/parse_json_format.rb +31 -0
  83. data/lib/platformos_check/checks/parser_blocking_javascript.rb +17 -0
  84. data/lib/platformos_check/checks/required_layout_object.rb +41 -0
  85. data/lib/platformos_check/checks/space_inside_braces.rb +150 -0
  86. data/lib/platformos_check/checks/syntax_error.rb +31 -0
  87. data/lib/platformos_check/checks/template_length.rb +20 -0
  88. data/lib/platformos_check/checks/undefined_object.rb +206 -0
  89. data/lib/platformos_check/checks/unknown_filter.rb +27 -0
  90. data/lib/platformos_check/checks/unused_assign.rb +101 -0
  91. data/lib/platformos_check/checks/unused_partial.rb +93 -0
  92. data/lib/platformos_check/checks/valid_yaml.rb +16 -0
  93. data/lib/platformos_check/checks.rb +73 -0
  94. data/lib/platformos_check/checks_tracking.rb +9 -0
  95. data/lib/platformos_check/cli.rb +239 -0
  96. data/lib/platformos_check/config.rb +219 -0
  97. data/lib/platformos_check/config_file.rb +6 -0
  98. data/lib/platformos_check/corrector.rb +68 -0
  99. data/lib/platformos_check/disabled_check.rb +44 -0
  100. data/lib/platformos_check/disabled_checks.rb +96 -0
  101. data/lib/platformos_check/email_file.rb +9 -0
  102. data/lib/platformos_check/exceptions.rb +36 -0
  103. data/lib/platformos_check/file_system_storage.rb +93 -0
  104. data/lib/platformos_check/graphql_file.rb +68 -0
  105. data/lib/platformos_check/html_check.rb +8 -0
  106. data/lib/platformos_check/html_node.rb +210 -0
  107. data/lib/platformos_check/html_visitor.rb +36 -0
  108. data/lib/platformos_check/in_memory_storage.rb +68 -0
  109. data/lib/platformos_check/json_file.rb +57 -0
  110. data/lib/platformos_check/json_helper.rb +73 -0
  111. data/lib/platformos_check/json_helpers.rb +24 -0
  112. data/lib/platformos_check/json_printer.rb +32 -0
  113. data/lib/platformos_check/language_server/bridge.rb +167 -0
  114. data/lib/platformos_check/language_server/channel.rb +69 -0
  115. data/lib/platformos_check/language_server/client_capabilities.rb +27 -0
  116. data/lib/platformos_check/language_server/code_action_engine.rb +32 -0
  117. data/lib/platformos_check/language_server/code_action_provider.rb +41 -0
  118. data/lib/platformos_check/language_server/code_action_providers/quickfix_code_action_provider.rb +85 -0
  119. data/lib/platformos_check/language_server/code_action_providers/source_fix_all_code_action_provider.rb +41 -0
  120. data/lib/platformos_check/language_server/completion_context.rb +52 -0
  121. data/lib/platformos_check/language_server/completion_engine.rb +32 -0
  122. data/lib/platformos_check/language_server/completion_helper.rb +26 -0
  123. data/lib/platformos_check/language_server/completion_provider.rb +53 -0
  124. data/lib/platformos_check/language_server/completion_providers/assignments_completion_provider.rb +40 -0
  125. data/lib/platformos_check/language_server/completion_providers/filter_completion_provider.rb +102 -0
  126. data/lib/platformos_check/language_server/completion_providers/object_attribute_completion_provider.rb +48 -0
  127. data/lib/platformos_check/language_server/completion_providers/object_completion_provider.rb +38 -0
  128. data/lib/platformos_check/language_server/completion_providers/render_snippet_completion_provider.rb +50 -0
  129. data/lib/platformos_check/language_server/completion_providers/tag_completion_provider.rb +41 -0
  130. data/lib/platformos_check/language_server/configuration.rb +89 -0
  131. data/lib/platformos_check/language_server/constants.rb +29 -0
  132. data/lib/platformos_check/language_server/diagnostic.rb +129 -0
  133. data/lib/platformos_check/language_server/diagnostics_engine.rb +131 -0
  134. data/lib/platformos_check/language_server/diagnostics_manager.rb +184 -0
  135. data/lib/platformos_check/language_server/document_change_corrector.rb +271 -0
  136. data/lib/platformos_check/language_server/document_link_engine.rb +21 -0
  137. data/lib/platformos_check/language_server/document_link_provider.rb +71 -0
  138. data/lib/platformos_check/language_server/document_link_providers/asset_document_link_provider.rb +11 -0
  139. data/lib/platformos_check/language_server/document_link_providers/include_document_link_provider.rb +11 -0
  140. data/lib/platformos_check/language_server/document_link_providers/render_document_link_provider.rb +11 -0
  141. data/lib/platformos_check/language_server/document_link_providers/section_document_link_provider.rb +11 -0
  142. data/lib/platformos_check/language_server/execute_command_engine.rb +19 -0
  143. data/lib/platformos_check/language_server/execute_command_provider.rb +30 -0
  144. data/lib/platformos_check/language_server/execute_command_providers/correction_execute_command_provider.rb +48 -0
  145. data/lib/platformos_check/language_server/execute_command_providers/run_checks_execute_command_provider.rb +28 -0
  146. data/lib/platformos_check/language_server/handler.rb +310 -0
  147. data/lib/platformos_check/language_server/hover_engine.rb +32 -0
  148. data/lib/platformos_check/language_server/hover_provider.rb +53 -0
  149. data/lib/platformos_check/language_server/hover_providers/filter_hover_provider.rb +113 -0
  150. data/lib/platformos_check/language_server/io_messenger.rb +109 -0
  151. data/lib/platformos_check/language_server/messenger.rb +27 -0
  152. data/lib/platformos_check/language_server/protocol.rb +55 -0
  153. data/lib/platformos_check/language_server/server.rb +188 -0
  154. data/lib/platformos_check/language_server/tokens.rb +55 -0
  155. data/lib/platformos_check/language_server/type_helper.rb +22 -0
  156. data/lib/platformos_check/language_server/uri_helper.rb +39 -0
  157. data/lib/platformos_check/language_server/variable_lookup_finder/assignments_finder/node_handler.rb +87 -0
  158. data/lib/platformos_check/language_server/variable_lookup_finder/assignments_finder/scope.rb +60 -0
  159. data/lib/platformos_check/language_server/variable_lookup_finder/assignments_finder/scope_visitor.rb +44 -0
  160. data/lib/platformos_check/language_server/variable_lookup_finder/assignments_finder.rb +76 -0
  161. data/lib/platformos_check/language_server/variable_lookup_finder/constants.rb +44 -0
  162. data/lib/platformos_check/language_server/variable_lookup_finder/liquid_fixer.rb +103 -0
  163. data/lib/platformos_check/language_server/variable_lookup_finder/potential_lookup.rb +10 -0
  164. data/lib/platformos_check/language_server/variable_lookup_finder/tolerant_parser.rb +94 -0
  165. data/lib/platformos_check/language_server/variable_lookup_finder.rb +262 -0
  166. data/lib/platformos_check/language_server/variable_lookup_traverser.rb +70 -0
  167. data/lib/platformos_check/language_server/versioned_in_memory_storage.rb +84 -0
  168. data/lib/platformos_check/language_server.rb +71 -0
  169. data/lib/platformos_check/layout_file.rb +15 -0
  170. data/lib/platformos_check/liquid_check.rb +10 -0
  171. data/lib/platformos_check/liquid_file.rb +102 -0
  172. data/lib/platformos_check/liquid_node.rb +570 -0
  173. data/lib/platformos_check/liquid_visitor.rb +39 -0
  174. data/lib/platformos_check/migration_file.rb +9 -0
  175. data/lib/platformos_check/node.rb +53 -0
  176. data/lib/platformos_check/offense.rb +228 -0
  177. data/lib/platformos_check/page_file.rb +9 -0
  178. data/lib/platformos_check/parsing_helpers.rb +21 -0
  179. data/lib/platformos_check/partial_file.rb +15 -0
  180. data/lib/platformos_check/platformos_liquid/deprecated_filter.rb +31 -0
  181. data/lib/platformos_check/platformos_liquid/documentation/markdown_template.rb +51 -0
  182. data/lib/platformos_check/platformos_liquid/documentation.rb +45 -0
  183. data/lib/platformos_check/platformos_liquid/filter.rb +19 -0
  184. data/lib/platformos_check/platformos_liquid/object.rb +15 -0
  185. data/lib/platformos_check/platformos_liquid/source_index/base_entry.rb +66 -0
  186. data/lib/platformos_check/platformos_liquid/source_index/base_state.rb +23 -0
  187. data/lib/platformos_check/platformos_liquid/source_index/filter_entry.rb +26 -0
  188. data/lib/platformos_check/platformos_liquid/source_index/filter_state.rb +11 -0
  189. data/lib/platformos_check/platformos_liquid/source_index/object_entry.rb +20 -0
  190. data/lib/platformos_check/platformos_liquid/source_index/object_state.rb +11 -0
  191. data/lib/platformos_check/platformos_liquid/source_index/parameter_entry.rb +25 -0
  192. data/lib/platformos_check/platformos_liquid/source_index/property_entry.rb +21 -0
  193. data/lib/platformos_check/platformos_liquid/source_index/return_type_entry.rb +41 -0
  194. data/lib/platformos_check/platformos_liquid/source_index/tag_entry.rb +24 -0
  195. data/lib/platformos_check/platformos_liquid/source_index/tag_state.rb +11 -0
  196. data/lib/platformos_check/platformos_liquid/source_index.rb +79 -0
  197. data/lib/platformos_check/platformos_liquid/source_manager.rb +116 -0
  198. data/lib/platformos_check/platformos_liquid/tag.rb +59 -0
  199. data/lib/platformos_check/platformos_liquid.rb +21 -0
  200. data/lib/platformos_check/position.rb +180 -0
  201. data/lib/platformos_check/position_helper.rb +57 -0
  202. data/lib/platformos_check/printer.rb +87 -0
  203. data/lib/platformos_check/regex_helpers.rb +21 -0
  204. data/lib/platformos_check/releaser.rb +43 -0
  205. data/lib/platformos_check/schema_file.rb +6 -0
  206. data/lib/platformos_check/sms_file.rb +9 -0
  207. data/lib/platformos_check/storage.rb +29 -0
  208. data/lib/platformos_check/string_helpers.rb +48 -0
  209. data/lib/platformos_check/tags/background.rb +67 -0
  210. data/lib/platformos_check/tags/base.rb +14 -0
  211. data/lib/platformos_check/tags/base_block.rb +14 -0
  212. data/lib/platformos_check/tags/base_tag_methods.rb +59 -0
  213. data/lib/platformos_check/tags/cache.rb +13 -0
  214. data/lib/platformos_check/tags/export.rb +30 -0
  215. data/lib/platformos_check/tags/form.rb +19 -0
  216. data/lib/platformos_check/tags/function.rb +58 -0
  217. data/lib/platformos_check/tags/graphql.rb +70 -0
  218. data/lib/platformos_check/tags/hash_assign.rb +75 -0
  219. data/lib/platformos_check/tags/log.rb +15 -0
  220. data/lib/platformos_check/tags/parse_json.rb +24 -0
  221. data/lib/platformos_check/tags/print.rb +20 -0
  222. data/lib/platformos_check/tags/redirect_to.rb +15 -0
  223. data/lib/platformos_check/tags/render.rb +60 -0
  224. data/lib/platformos_check/tags/response_headers.rb +20 -0
  225. data/lib/platformos_check/tags/response_status.rb +20 -0
  226. data/lib/platformos_check/tags/return.rb +20 -0
  227. data/lib/platformos_check/tags/session.rb +27 -0
  228. data/lib/platformos_check/tags/sign_in.rb +27 -0
  229. data/lib/platformos_check/tags/spam_protection.rb +15 -0
  230. data/lib/platformos_check/tags/theme_render.rb +58 -0
  231. data/lib/platformos_check/tags/try.rb +59 -0
  232. data/lib/platformos_check/tags.rb +65 -0
  233. data/lib/platformos_check/translation_file.rb +6 -0
  234. data/lib/platformos_check/user_schema_file.rb +6 -0
  235. data/lib/platformos_check/version.rb +5 -0
  236. data/lib/platformos_check/yaml_check.rb +11 -0
  237. data/lib/platformos_check/yaml_file.rb +57 -0
  238. data/lib/platformos_check.rb +106 -0
  239. data/platformos-check.gemspec +34 -0
  240. metadata +329 -0
@@ -0,0 +1,39 @@
1
+ # frozen_string_literal: true
2
+
3
+ module PlatformosCheck
4
+ class LiquidVisitor
5
+ attr_reader :checks
6
+
7
+ def initialize(checks, disabled_checks)
8
+ @checks = checks
9
+ @disabled_checks = disabled_checks
10
+ end
11
+
12
+ def visit_liquid_file(liquid_file)
13
+ visit(LiquidNode.new(liquid_file.root, nil, liquid_file))
14
+ rescue Liquid::Error => e
15
+ e.template_name = liquid_file.name
16
+ call_checks(:on_error, e)
17
+ end
18
+
19
+ private
20
+
21
+ def visit(node)
22
+ call_checks(:on_node, node)
23
+ call_checks(:on_tag, node) if node.tag?
24
+ call_checks(:"on_#{node.type_name}", node)
25
+ node.children.each { |child| visit(child) }
26
+ unless node.literal?
27
+ call_checks(:"after_#{node.type_name}", node)
28
+ call_checks(:after_tag, node) if node.tag?
29
+ call_checks(:after_node, node)
30
+ end
31
+
32
+ @disabled_checks.update(node) if node.comment? || node.inline_comment?
33
+ end
34
+
35
+ def call_checks(method, *)
36
+ checks.call(method, *)
37
+ end
38
+ end
39
+ end
@@ -0,0 +1,9 @@
1
+ # frozen_string_literal: true
2
+
3
+ module PlatformosCheck
4
+ class MigrationFile < LiquidFile
5
+ def migration?
6
+ true
7
+ end
8
+ end
9
+ end
@@ -0,0 +1,53 @@
1
+ # frozen_string_literal: true
2
+
3
+ module PlatformosCheck
4
+ class Node
5
+ def parent
6
+ raise NotImplementedError
7
+ end
8
+
9
+ def app_file
10
+ raise NotImplementedError
11
+ end
12
+
13
+ def value
14
+ raise NotImplementedError
15
+ end
16
+
17
+ def children
18
+ raise NotImplementedError
19
+ end
20
+
21
+ def markup
22
+ raise NotImplementedError
23
+ end
24
+
25
+ def line_number
26
+ raise NotImplementedError
27
+ end
28
+
29
+ def start_index
30
+ raise NotImplementedError
31
+ end
32
+
33
+ def start_row
34
+ raise NotImplementedError
35
+ end
36
+
37
+ def start_column
38
+ raise NotImplementedError
39
+ end
40
+
41
+ def end_index
42
+ raise NotImplementedError
43
+ end
44
+
45
+ def end_row
46
+ raise NotImplementedError
47
+ end
48
+
49
+ def end_column
50
+ raise NotImplementedError
51
+ end
52
+ end
53
+ end
@@ -0,0 +1,228 @@
1
+ # frozen_string_literal: true
2
+
3
+ module PlatformosCheck
4
+ class Offense
5
+ include PositionHelper
6
+
7
+ MAX_SOURCE_EXCERPT_SIZE = 120
8
+
9
+ attr_reader :check, :message, :app_file, :node, :markup, :line_number, :correction
10
+
11
+ def initialize(
12
+ check:, # instance of a PlatformosCheck::Check
13
+ message: nil, # error message for the offense
14
+ app_file: nil, # AppFile
15
+ node: nil, # Node
16
+ markup: nil, # string
17
+ line_number: nil, # line number of the error (1-indexed)
18
+ # node_markup_offset is the index inside node.markup to start
19
+ # looking for markup :mindblow:.
20
+ # This is so we can accurately highlight node substrings.
21
+ # e.g. if we have the following scenario in which we
22
+ # want to highlight the middle comma
23
+ # * node.markup == "replace ',',', '"
24
+ # * markup == ","
25
+ # Then we need some way of telling our Position class to start
26
+ # looking for the second comma. This is done with node_markup_offset.
27
+ # More context can be found in #376.
28
+ node_markup_offset: 0,
29
+ correction: nil # block
30
+ )
31
+ @check = check
32
+ @correction = correction
33
+
34
+ if message
35
+ @message = message
36
+ elsif defined?(check.class::MESSAGE)
37
+ @message = check.class::MESSAGE
38
+ else
39
+ raise ArgumentError, "message required"
40
+ end
41
+
42
+ @node = node
43
+ @app_file = node&.app_file || app_file
44
+ @markup = markup || node&.markup
45
+
46
+ raise ArgumentError, "Offense markup cannot be an empty string" if @markup.is_a?(String) && @markup.empty?
47
+
48
+ @line_number = line_number || @node&.line_number
49
+
50
+ @position = Position.new(
51
+ @markup,
52
+ @app_file&.source,
53
+ line_number_1_indexed: @line_number,
54
+ node_markup_offset:,
55
+ node_markup: node&.markup
56
+ )
57
+ end
58
+
59
+ def source_excerpt
60
+ return unless line_number
61
+
62
+ @source_excerpt ||= begin
63
+ excerpt = app_file.source_excerpt(line_number)
64
+ if excerpt.size > MAX_SOURCE_EXCERPT_SIZE
65
+ excerpt[0, MAX_SOURCE_EXCERPT_SIZE - 3] + '...'
66
+ else
67
+ excerpt
68
+ end
69
+ end
70
+ end
71
+
72
+ def in_range?(other_range)
73
+ # Zero length ranges are OK and considered the same as size 1 ranges
74
+ other_range = other_range.first..other_range.end if other_range.size == 0 # rubocop:disable Style/ZeroLengthPredicate
75
+ range.cover?(other_range) || other_range.cover?(range)
76
+ end
77
+
78
+ def range
79
+ @range ||= if start_index == end_index
80
+ (start_index..end_index)
81
+ else
82
+ (start_index...end_index) # end_index is excluded
83
+ end
84
+ end
85
+
86
+ def start_index
87
+ @position.start_index
88
+ end
89
+
90
+ def start_row
91
+ @position.start_row
92
+ end
93
+
94
+ def start_column
95
+ @position.start_column
96
+ end
97
+
98
+ def end_index
99
+ @position.end_index
100
+ end
101
+
102
+ def end_row
103
+ @position.end_row
104
+ end
105
+
106
+ def end_column
107
+ @position.end_column
108
+ end
109
+
110
+ def code_name
111
+ check.code_name
112
+ end
113
+
114
+ def markup_start_in_excerpt
115
+ source_excerpt.index(markup) if markup
116
+ end
117
+
118
+ def severity
119
+ check.severity
120
+ end
121
+
122
+ def check_name
123
+ StringHelpers.demodulize(check.class.name)
124
+ end
125
+
126
+ def version
127
+ app_file&.version
128
+ end
129
+
130
+ def doc
131
+ check.doc
132
+ end
133
+
134
+ def location
135
+ tokens = [app_file&.relative_path, line_number].compact
136
+ tokens.join(":") if tokens.any?
137
+ end
138
+
139
+ def location_range
140
+ tokens = [app_file&.relative_path, start_index, end_index].compact
141
+ tokens.join(":") if tokens.any?
142
+ end
143
+
144
+ def correctable?
145
+ !!correction
146
+ end
147
+
148
+ def correct(corrector = nil)
149
+ if correctable?
150
+ corrector ||= Corrector.new(app_file:)
151
+ correction.call(corrector)
152
+ end
153
+ rescue StandardError => e
154
+ PlatformosCheck.bug(<<~EOS)
155
+ Exception while running `Offense#correct`:
156
+ ```
157
+ #{e.class}: #{e.message}
158
+ #{e.backtrace.join("\n ")}
159
+ ```
160
+
161
+ Offense:
162
+ ```
163
+ #{JSON.pretty_generate(to_h)}
164
+ ```
165
+ Check options:
166
+ ```
167
+ #{check.options.pretty_inspect}
168
+ ```
169
+ Markup:
170
+ ```
171
+ #{markup}
172
+ ```
173
+ Node.Markup:
174
+ ```
175
+ #{node&.markup}
176
+ ```
177
+ EOS
178
+ exit(2)
179
+ end
180
+
181
+ def whole_platformos_app?
182
+ check.whole_platformos_app?
183
+ end
184
+
185
+ def single_file?
186
+ check.single_file?
187
+ end
188
+
189
+ def ==(other)
190
+ other.is_a?(Offense) &&
191
+ code_name == other.code_name &&
192
+ message == other.message &&
193
+ location == other.location &&
194
+ start_index == other.start_index &&
195
+ end_index == other.end_index
196
+ end
197
+ alias eql? ==
198
+
199
+ def to_s
200
+ if app_file
201
+ "#{message} at #{location}"
202
+ else
203
+ message
204
+ end
205
+ end
206
+
207
+ def to_s_range
208
+ if app_file
209
+ "#{message} at #{location_range}"
210
+ else
211
+ message
212
+ end
213
+ end
214
+
215
+ def to_h
216
+ {
217
+ check: check.code_name,
218
+ path: app_file&.relative_path,
219
+ severity: check.severity_value,
220
+ start_row:,
221
+ start_column:,
222
+ end_row:,
223
+ end_column:,
224
+ message:
225
+ }
226
+ end
227
+ end
228
+ end
@@ -0,0 +1,9 @@
1
+ # frozen_string_literal: true
2
+
3
+ module PlatformosCheck
4
+ class PageFile < LiquidFile
5
+ def page?
6
+ true
7
+ end
8
+ end
9
+ end
@@ -0,0 +1,21 @@
1
+ # frozen_string_literal: true
2
+
3
+ module PlatformosCheck
4
+ module ParsingHelpers
5
+ # Yield each chunk outside of "...", '...'
6
+ def outside_of_strings(markup)
7
+ scanner = StringScanner.new(markup)
8
+
9
+ while scanner.scan(/.*?("|')/m)
10
+ chunk_start = scanner.pre_match.size
11
+ yield scanner.matched[0..-2], chunk_start
12
+ quote = scanner.matched[-1] == "'" ? "'" : "\""
13
+ # Skip to the end of the string
14
+ # Check for empty string first, since follow regexp uses lookahead
15
+ scanner.skip(/#{quote}/) || scanner.skip_until(/[^\\]#{quote}/)
16
+ end
17
+
18
+ yield scanner.rest, scanner.charpos if scanner.rest?
19
+ end
20
+ end
21
+ end
@@ -0,0 +1,15 @@
1
+ # frozen_string_literal: true
2
+
3
+ module PlatformosCheck
4
+ class PartialFile < LiquidFile
5
+ DIR_PREFIX = %r{\A/?((marketplace_builder|app)/(views/partials|liquid_views|views|lib)/|modules/((\w|-)*)/(private|public)/(views/partials|liquid_views|views|lib)/)}
6
+
7
+ def partial?
8
+ true
9
+ end
10
+
11
+ def dir_prefix
12
+ DIR_PREFIX
13
+ end
14
+ end
15
+ end
@@ -0,0 +1,31 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'yaml'
4
+
5
+ module PlatformosCheck
6
+ module PlatformosLiquid
7
+ module DeprecatedFilter
8
+ extend self
9
+
10
+ def alternatives(filter)
11
+ all.fetch(filter, nil)
12
+ end
13
+
14
+ def labels
15
+ @labels ||= all.keys
16
+ end
17
+
18
+ private
19
+
20
+ def all
21
+ @all ||= SourceIndex.deprecated_filters
22
+ .values
23
+ .each_with_object({}) do |filters, acc|
24
+ filters.each do |(filter, alternatives)|
25
+ acc[filter] = alternatives
26
+ end
27
+ end
28
+ end
29
+ end
30
+ end
31
+ end
@@ -0,0 +1,51 @@
1
+ # frozen_string_literal: true
2
+
3
+ module PlatformosCheck
4
+ module PlatformosLiquid
5
+ class Documentation
6
+ class MarkdownTemplate
7
+ MARKDOWN_RELATIVE_LINK = %r{(\[([^\[]+)\]\((/[^\)]+)\))*}
8
+
9
+ def render(entry)
10
+ [
11
+ title(entry),
12
+ body(entry)
13
+ ].reject(&:empty?).join("\n")
14
+ end
15
+
16
+ private
17
+
18
+ def title(entry)
19
+ "### [#{entry.name}](#{entry.platformos_documentation_url})"
20
+ end
21
+
22
+ def body(entry)
23
+ [entry.deprecation_reason, entry.summary, entry.description]
24
+ .reject(&:nil?)
25
+ .reject(&:empty?)
26
+ .join(horizontal_rule)
27
+ .tap { |body| break(patch_urls!(body)) }
28
+ end
29
+
30
+ def horizontal_rule
31
+ "\n\n---\n\n"
32
+ end
33
+
34
+ def patch_urls!(body)
35
+ body.gsub(MARKDOWN_RELATIVE_LINK) do |original_link|
36
+ match = Regexp.last_match
37
+
38
+ text = match[2]
39
+ path = match[3]
40
+
41
+ if text && path
42
+ "[#{text}](https://documentation.platformos.com#{path})"
43
+ else
44
+ original_link
45
+ end
46
+ end
47
+ end
48
+ end
49
+ end
50
+ end
51
+ end
@@ -0,0 +1,45 @@
1
+ # frozen_string_literal: true
2
+
3
+ require_relative 'documentation/markdown_template'
4
+
5
+ module PlatformosCheck
6
+ module PlatformosLiquid
7
+ class Documentation
8
+ class << self
9
+ def filter_doc(filter_name)
10
+ render_doc(SourceIndex.filters.find { |entry| entry.name == filter_name })
11
+ end
12
+
13
+ def object_doc(object_name)
14
+ render_doc(SourceIndex.objects.find { |entry| entry.name == object_name })
15
+ end
16
+
17
+ def tag_doc(tag_name)
18
+ render_doc(SourceIndex.tags.find { |entry| entry.name == tag_name })
19
+ end
20
+
21
+ def object_property_doc(object_name, property_name)
22
+ property_entry = SourceIndex
23
+ .objects
24
+ .find { |entry| entry.name == object_name }
25
+ &.properties
26
+ &.find { |prop| prop.name == property_name }
27
+
28
+ render_doc(property_entry)
29
+ end
30
+
31
+ def render_doc(entry)
32
+ return nil unless entry
33
+
34
+ markdown_template.render(entry)
35
+ end
36
+
37
+ private
38
+
39
+ def markdown_template
40
+ @markdown_template ||= MarkdownTemplate.new
41
+ end
42
+ end
43
+ end
44
+ end
45
+ end
@@ -0,0 +1,19 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'yaml'
4
+
5
+ module PlatformosCheck
6
+ module PlatformosLiquid
7
+ module Filter
8
+ extend self
9
+
10
+ def labels
11
+ @labels ||= SourceIndex.filters.map(&:name)
12
+ end
13
+
14
+ def aliases
15
+ @aliases ||= SourceIndex.filters.map(&:aliases).flatten
16
+ end
17
+ end
18
+ end
19
+ end
@@ -0,0 +1,15 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'yaml'
4
+
5
+ module PlatformosCheck
6
+ module PlatformosLiquid
7
+ module Object
8
+ extend self
9
+
10
+ def labels
11
+ @labels ||= SourceIndex.objects.map(&:name)
12
+ end
13
+ end
14
+ end
15
+ end
@@ -0,0 +1,66 @@
1
+ # frozen_string_literal: true
2
+
3
+ require "forwardable"
4
+
5
+ module PlatformosCheck
6
+ module PlatformosLiquid
7
+ class SourceIndex
8
+ class BaseEntry
9
+ extend Forwardable
10
+
11
+ attr_reader :hash
12
+
13
+ def_delegators :return_type_instance, :generic_type?, :array_type?, :array_type, :to_s, :denied_filters
14
+
15
+ PLATFORMOS_DOCUMENTATION_URL = "https://documentation.platformos.com"
16
+
17
+ def initialize(hash = {})
18
+ @hash = hash || {}
19
+ @return_type = nil
20
+ end
21
+
22
+ def name
23
+ hash['name']
24
+ end
25
+
26
+ def summary
27
+ hash['summary'] || ''
28
+ end
29
+
30
+ def description
31
+ hash['description'] || ''
32
+ end
33
+
34
+ def deprecated?
35
+ hash['deprecated']
36
+ end
37
+
38
+ def deprecation_reason
39
+ return nil unless deprecated?
40
+
41
+ hash['deprecation_reason'] || nil
42
+ end
43
+
44
+ def platformos_documentation_url
45
+ PLATFORMOS_DOCUMENTATION_URL
46
+ end
47
+
48
+ attr_writer :return_type
49
+
50
+ def return_type
51
+ @return_type || to_s
52
+ end
53
+
54
+ def return_type_instance
55
+ ReturnTypeEntry.new(return_type_hash)
56
+ end
57
+
58
+ private
59
+
60
+ def return_type_hash
61
+ hash['return_type']&.first
62
+ end
63
+ end
64
+ end
65
+ end
66
+ end
@@ -0,0 +1,23 @@
1
+ # frozen_string_literal: true
2
+
3
+ module PlatformosCheck
4
+ module PlatformosLiquid
5
+ class SourceIndex
6
+ class BaseState
7
+ class << self
8
+ def mark_outdated
9
+ @up_to_date = false
10
+ end
11
+
12
+ def mark_up_to_date
13
+ @up_to_date = true
14
+ end
15
+
16
+ def outdated?
17
+ @up_to_date == false
18
+ end
19
+ end
20
+ end
21
+ end
22
+ end
23
+ end
@@ -0,0 +1,26 @@
1
+ # frozen_string_literal: true
2
+
3
+ module PlatformosCheck
4
+ module PlatformosLiquid
5
+ class SourceIndex
6
+ class FilterEntry < BaseEntry
7
+ def parameters
8
+ (hash['parameters'] || [])
9
+ .map { |hash| ParameterEntry.new(hash) }
10
+ end
11
+
12
+ def aliases
13
+ hash['aliases'] || []
14
+ end
15
+
16
+ def input_type
17
+ @input_type ||= hash['syntax'].split(' | ')[0]
18
+ end
19
+
20
+ def platformos_documentation_url
21
+ "#{PLATFORMOS_DOCUMENTATION_URL}/api-reference/liquid/filters/#{hash['name']}"
22
+ end
23
+ end
24
+ end
25
+ end
26
+ end
@@ -0,0 +1,11 @@
1
+ # frozen_string_literal: true
2
+
3
+ module PlatformosCheck
4
+ module PlatformosLiquid
5
+ class SourceIndex
6
+ class FilterState < BaseState
7
+ @up_to_date = false
8
+ end
9
+ end
10
+ end
11
+ end
@@ -0,0 +1,20 @@
1
+ # frozen_string_literal: true
2
+
3
+ module PlatformosCheck
4
+ module PlatformosLiquid
5
+ class SourceIndex
6
+ class ObjectEntry < BaseEntry
7
+ def properties
8
+ (hash['properties'] || [])
9
+ .map do |prop_hash|
10
+ PropertyEntry.new(prop_hash, hash['name'])
11
+ end
12
+ end
13
+
14
+ def platformos_documentation_url
15
+ "#{PLATFORMOS_DOCUMENTATION_URL}/developer-guide/variables/context-variable##{hash['name']}"
16
+ end
17
+ end
18
+ end
19
+ end
20
+ end