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,87 @@
1
+ # frozen_string_literal: true
2
+
3
+ module PlatformosCheck
4
+ class Printer
5
+ def initialize(out_stream = STDOUT)
6
+ @out = out_stream
7
+ end
8
+
9
+ def print(platformos_app, offenses, auto_correct)
10
+ offenses.each do |offense|
11
+ print_offense(offense, auto_correct)
12
+ @out.puts
13
+ end
14
+
15
+ correctable = offenses.select(&:correctable?)
16
+ @out.puts "#{platformos_app.all.size} files inspected, #{red(offenses.size.to_s + ' offenses')} detected, \
17
+ #{yellow(correctable.size.to_s + ' offenses')} #{auto_correct ? 'corrected' : 'auto-correctable'}"
18
+ end
19
+
20
+ def print_offense(offense, auto_correct)
21
+ location = if offense.location
22
+ blue(offense.location) + ": "
23
+ else
24
+ ""
25
+ end
26
+
27
+ corrected = if auto_correct && offense.correctable?
28
+ green("[Corrected] ")
29
+ else
30
+ ""
31
+ end
32
+
33
+ @out.puts location +
34
+ colorized_severity(offense.severity) + ": " +
35
+ yellow(offense.check_name) + ": " +
36
+ corrected +
37
+ offense.message + "."
38
+ return unless offense.source_excerpt
39
+
40
+ @out.puts "\t#{offense.source_excerpt}"
41
+ return unless offense.markup_start_in_excerpt
42
+
43
+ @out.puts "\t" + (" " * offense.markup_start_in_excerpt) + ("^" * offense.markup.size)
44
+ end
45
+
46
+ private
47
+
48
+ def colorize(str, color_code)
49
+ "\e[#{color_code}m#{str}\e[0m"
50
+ end
51
+
52
+ def colorized_severity(severity)
53
+ case severity
54
+ when :error
55
+ red(severity)
56
+ when :suggestion
57
+ pink(severity)
58
+ when :style
59
+ light_blue(severity)
60
+ end
61
+ end
62
+
63
+ def red(str)
64
+ colorize(str, 31)
65
+ end
66
+
67
+ def green(str)
68
+ colorize(str, 32)
69
+ end
70
+
71
+ def yellow(str)
72
+ colorize(str, 33)
73
+ end
74
+
75
+ def blue(str)
76
+ colorize(str, 34)
77
+ end
78
+
79
+ def pink(str)
80
+ colorize(str, 35)
81
+ end
82
+
83
+ def light_blue(str)
84
+ colorize(str, 36)
85
+ end
86
+ end
87
+ end
@@ -0,0 +1,21 @@
1
+ # frozen_string_literal: true
2
+
3
+ module PlatformosCheck
4
+ module RegexHelpers
5
+ LIQUID_TAG = /#{Liquid::TagStart}.*?#{Liquid::TagEnd}/om
6
+ LIQUID_VARIABLE = /#{Liquid::VariableStart}.*?#{Liquid::VariableEnd}/om
7
+ LIQUID_TAG_OR_VARIABLE = /#{LIQUID_TAG}|#{LIQUID_VARIABLE}/om
8
+ HTML_LIQUID_PLACEHOLDER = /≬[0-9a-z\n]+[#\n]*≬/m
9
+ START_OR_END_QUOTE = /(^['"])|(['"]$)/
10
+
11
+ def matches(s, re)
12
+ start_at = 0
13
+ matches = []
14
+ while (m = s.match(re, start_at))
15
+ matches.push(m)
16
+ start_at = m.end(0)
17
+ end
18
+ matches
19
+ end
20
+ end
21
+ end
@@ -0,0 +1,43 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'platformos_check/version'
4
+
5
+ module PlatformosCheck
6
+ class Releaser
7
+ ROOT = File.expand_path('../..', __dir__)
8
+ LIB = File.join(ROOT, 'lib')
9
+
10
+ class VersionError < StandardError; end
11
+
12
+ def release(version)
13
+ raise VersionError, "Missing version argument." if version.nil?
14
+ raise VersionError, "Version should be a string." unless version.is_a?(String)
15
+ raise VersionError, "Version should be a valid semver version." unless /^\d+\.\d+.\d+$/.match?(version)
16
+
17
+ update_docs(version)
18
+ update_version(version)
19
+ end
20
+
21
+ def update_version(version)
22
+ version_file_path = File.join(LIB, 'platformos_check/version.rb')
23
+ version_file = File.read(version_file_path)
24
+ updated_version_file = version_file.gsub(PlatformosCheck::VERSION, version)
25
+
26
+ return if updated_version_file == version_file
27
+
28
+ puts "Updating version to #{version} in #{version_file_path}."
29
+ File.write(version_file_path, updated_version_file)
30
+ end
31
+
32
+ def update_docs(version)
33
+ Dir[ROOT + '/docs/checks/*.md'].each do |filename|
34
+ doc_content = File.read(filename)
35
+ updated_doc_content = doc_content.gsub('PLATFORMOS_CHECK_VERSION', version)
36
+ next if updated_doc_content == doc_content
37
+
38
+ puts "Replacing `PLATFORMOS_CHECK_VERSION` with #{version} in #{Pathname.new(filename).relative_path_from(ROOT)}"
39
+ File.write(filename, updated_doc_content)
40
+ end
41
+ end
42
+ end
43
+ end
@@ -0,0 +1,6 @@
1
+ # frozen_string_literal: true
2
+
3
+ module PlatformosCheck
4
+ class SchemaFile < YamlFile
5
+ end
6
+ end
@@ -0,0 +1,9 @@
1
+ # frozen_string_literal: true
2
+
3
+ module PlatformosCheck
4
+ class SmsFile < LiquidFile
5
+ def notification?
6
+ true
7
+ end
8
+ end
9
+ end
@@ -0,0 +1,29 @@
1
+ # frozen_string_literal: true
2
+
3
+ module PlatformosCheck
4
+ class Storage
5
+ def path(relative_path)
6
+ raise NotImplementedError
7
+ end
8
+
9
+ def read(relative_path)
10
+ raise NotImplementedError
11
+ end
12
+
13
+ def write(relative_path, content)
14
+ raise NotImplementedError
15
+ end
16
+
17
+ def files
18
+ raise NotImplementedError
19
+ end
20
+
21
+ def directories
22
+ raise NotImplementedError
23
+ end
24
+
25
+ def versioned?
26
+ false
27
+ end
28
+ end
29
+ end
@@ -0,0 +1,48 @@
1
+ # frozen_string_literal: true
2
+
3
+ module PlatformosCheck
4
+ module StringHelpers
5
+ extend self
6
+
7
+ # Removes the module part from the expression in the string.
8
+ # Ported from ActiveSupport
9
+ #
10
+ # demodulize('ActiveSupport::Inflector::Inflections') # => "Inflections"
11
+ # demodulize('Inflections') # => "Inflections"
12
+ # demodulize('::Inflections') # => "Inflections"
13
+ # demodulize('') # => ""
14
+ #
15
+ # See also #deconstantize.
16
+ def demodulize(path)
17
+ path = path.to_s
18
+ if (i = path.rindex("::"))
19
+ path[(i + 2)..-1]
20
+ else
21
+ path
22
+ end
23
+ end
24
+
25
+ # Makes an underscored, lowercase form from the expression in the string.
26
+ # Base on ActiveSupport's
27
+ #
28
+ # Changes '::' to '/' to convert namespaces to paths.
29
+ #
30
+ # underscore('ActiveModel') # => "active_model"
31
+ # underscore('ActiveModel::Errors') # => "active_model/errors"
32
+ #
33
+ # As a rule of thumb you can think of +underscore+ as the inverse of
34
+ # #camelize, though there are cases where that does not hold:
35
+ #
36
+ # camelize(underscore('SSLError')) # => "SslError"
37
+ def underscore(camel_cased_word)
38
+ return camel_cased_word unless /[A-Z-]|::/.match?(camel_cased_word)
39
+
40
+ word = camel_cased_word.to_s.gsub("::", "/")
41
+ word.gsub!(/([A-Z\d]+)([A-Z][a-z])/, '\1_\2')
42
+ word.gsub!(/([a-z\d])([A-Z])/, '\1_\2')
43
+ word.tr!("-", "_")
44
+ word.downcase!
45
+ word
46
+ end
47
+ end
48
+ end
@@ -0,0 +1,67 @@
1
+ # frozen_string_literal: true
2
+
3
+ module PlatformosCheck
4
+ module Tags
5
+ class Background < Base
6
+ PARTIAL_SYNTAX = /(#{Liquid::VariableSignature}+)\s*=\s*(.*)\s*/om
7
+ CLOSE_TAG_SYNTAX = /\A(.*)(?-mix:\{%-?)\s*(\w+)\s*(.*)?(?-mix:%\})\z/m # based on Liquid::Raw::FullTokenPossiblyInvalid
8
+
9
+ attr_reader :to, :from, :attributes, :value_expr
10
+
11
+ def initialize(tag_name, markup, options)
12
+ if markup =~ PARTIAL_SYNTAX
13
+ super
14
+ @to = Regexp.last_match(1)
15
+ @partial_syntax = true
16
+
17
+ after_assign_markup = Regexp.last_match(2).split('|')
18
+ parse_markup(tag_name, after_assign_markup.shift)
19
+ after_assign_markup.unshift(@to)
20
+ @from = Liquid::Variable.new(after_assign_markup.join('|'), options)
21
+ else
22
+ @partial_syntax = false
23
+ parse_markup(tag_name, markup)
24
+ super
25
+ end
26
+ end
27
+
28
+ def parse(tokens)
29
+ return super if @partial_syntax
30
+
31
+ @body = +''
32
+ while (token = tokens.send(:shift))
33
+ if token =~ CLOSE_TAG_SYNTAX && block_delimiter == Regexp.last_match(2)
34
+ @body << Regexp.last_match(1) if Regexp.last_match(1) != ''
35
+ return
36
+ end
37
+ @body << token unless token.empty?
38
+ end
39
+
40
+ raise Liquid::SyntaxError, parse_context.locale.t('errors.syntax.tag_never_closed', block_name:)
41
+ end
42
+
43
+ def block_name
44
+ @tag_name
45
+ end
46
+
47
+ def block_delimiter
48
+ @block_delimiter = "end#{block_name}"
49
+ end
50
+
51
+ def parse_main_value(tag_name, markup)
52
+ raise Liquid::SyntaxError, "Invalid syntax for #{tag_name} tag" unless markup =~ syntax
53
+
54
+ @main_value = Regexp.last_match(1)
55
+ @value_expr = @main_value ? Liquid::Expression.parse(@main_value) : nil
56
+ end
57
+
58
+ class ParseTreeVisitor < Liquid::ParseTreeVisitor
59
+ def children
60
+ [
61
+ @node.to
62
+ ].compact + @node.attributes_expr.values
63
+ end
64
+ end
65
+ end
66
+ end
67
+ end
@@ -0,0 +1,14 @@
1
+ # frozen_string_literal: true
2
+
3
+ module PlatformosCheck
4
+ module Tags
5
+ class Base < Liquid::Tag
6
+ include BaseTagMethods
7
+
8
+ def initialize(tag_name, markup, parse_context)
9
+ super
10
+ parse_markup(tag_name, markup)
11
+ end
12
+ end
13
+ end
14
+ end
@@ -0,0 +1,14 @@
1
+ # frozen_string_literal: true
2
+
3
+ module PlatformosCheck
4
+ module Tags
5
+ class BaseBlock < Liquid::Block
6
+ include BaseTagMethods
7
+
8
+ def initialize(tag_name, markup, options)
9
+ super
10
+ parse_markup(tag_name, markup)
11
+ end
12
+ end
13
+ end
14
+ end
@@ -0,0 +1,59 @@
1
+ # frozen_string_literal: true
2
+
3
+ module PlatformosCheck
4
+ module Tags
5
+ module BaseTagMethods
6
+ SYNTAX = /(#{Liquid::QuotedFragment}+)(\s*(#{Liquid::QuotedFragment}+))?/o
7
+ # this is Liquid::TagAttributes with the beginnig changed from \w+ to [\w-] to allow for
8
+ # attributes like html-id: 10, which was identified as id: 10, but should be html-id: 10.
9
+ # In other words - allow hyphens in key names.
10
+ TAG_ATTRIBUTES = /([\w-]+)\s*:\s*((?-mix:(?-mix:"[^"]*"|'[^']*')|(?:[^\s,|'"]|(?-mix:"[^"]*"|'[^']*'))+))/
11
+ BACKWARDS_COMPATIBILITY_KEYS = %w[method].freeze
12
+
13
+ attr_reader :main_value, :attributes_expr, :value_expr, :duplicated_attrs
14
+
15
+ protected
16
+
17
+ def parse_markup(tag_name, markup)
18
+ @remaining_markup = markup
19
+
20
+ parse_main_value(tag_name, markup)
21
+ parse_attributes(@remaining_markup)
22
+ end
23
+
24
+ def parse_main_value(tag_name, markup)
25
+ raise Liquid::SyntaxError, "Invalid syntax for #{tag_name} tag" unless markup =~ syntax
26
+
27
+ @main_value = Regexp.last_match(1)
28
+ @remaining_markup = markup[Regexp.last_match.end(1)..-1] if @main_value
29
+
30
+ @value_expr = @main_value ? Liquid::Expression.parse(@main_value) : nil
31
+ end
32
+
33
+ def parse_attributes(markup)
34
+ @attributes_expr = {}
35
+ @duplicated_attrs = []
36
+
37
+ markup.scan(TAG_ATTRIBUTES) do |key, value|
38
+ unless well_formed_object_access?(value)
39
+ raise Liquid::SyntaxError,
40
+ 'Invalid syntax for function tag, no spaces allowed when accessing array or hash.'
41
+ end
42
+
43
+ @duplicated_attrs << key if @attributes_expr.key?(key)
44
+ @attributes_expr[key] = Liquid::Expression.parse(value)
45
+ end
46
+ end
47
+
48
+ def well_formed_object_access?(representation)
49
+ return false if /\[\z/.match?(representation.to_s)
50
+
51
+ true
52
+ end
53
+
54
+ def syntax
55
+ SYNTAX
56
+ end
57
+ end
58
+ end
59
+ end
@@ -0,0 +1,13 @@
1
+ # frozen_string_literal: true
2
+
3
+ module PlatformosCheck
4
+ module Tags
5
+ class Cache < BaseBlock
6
+ class ParseTreeVisitor < Liquid::ParseTreeVisitor
7
+ def children
8
+ super + [@node.value_expr].compact + @node.attributes_expr.values
9
+ end
10
+ end
11
+ end
12
+ end
13
+ end
@@ -0,0 +1,30 @@
1
+ # frozen_string_literal: true
2
+
3
+ module PlatformosCheck
4
+ module Tags
5
+ class Export < Liquid::Tag
6
+ SYNTAX = /\A([\w-]+[\s,]*[\w\s,]*)\s*(namespace:\s*(.+))?\z/
7
+
8
+ attr_reader :namespace, :variables
9
+
10
+ def initialize(tag_name, markup, options)
11
+ super
12
+ raise Liquid::SyntaxError, "Syntax Error in 'export' - Valid syntax: export [var1], [var2], ..., namespace: [namespace]" unless markup =~ SYNTAX
13
+
14
+ @variables = Regexp.last_match(1).split(',').map { |v| Liquid::Expression.parse(v) }
15
+ @namespace = Liquid::Expression.parse(Regexp.last_match(3)&.strip)
16
+ end
17
+
18
+ def parse_main_value(_tag_name, _markup); end
19
+
20
+ class ParseTreeVisitor < Liquid::ParseTreeVisitor
21
+ def children
22
+ @node.variables +
23
+ [
24
+ @node.namespace
25
+ ]
26
+ end
27
+ end
28
+ end
29
+ end
30
+ end
@@ -0,0 +1,19 @@
1
+ # frozen_string_literal: true
2
+
3
+ module PlatformosCheck
4
+ module Tags
5
+ class Form < BaseBlock
6
+ def initialize(tag_name, markup, tokens)
7
+ super
8
+ @tag_name = tag_name
9
+ @markup = markup
10
+ @model_name = markup.scan(::Liquid::QuotedFragment).flatten.first
11
+ # we want to allow {% form method: delete %}, but also {% form form, method: delete %}
12
+ @model_name = 'form' if @model_name.nil? || @model_name == '' || @model_name[-1] == ':'
13
+ parse_attributes(markup)
14
+ end
15
+
16
+ def parse_main_value(_tag_name, _markup); end
17
+ end
18
+ end
19
+ end
@@ -0,0 +1,58 @@
1
+ # frozen_string_literal: true
2
+
3
+ module PlatformosCheck
4
+ module Tags
5
+ class Function < Base
6
+ # SYNTAX_HASH @to is the same as for hash_assign tag, but with mandatory brackets
7
+ SYNTAX_HASH = %r{((\(?[\w\-.]\)?)+)(\[.+\])+\s*=\s*([\w/\-."']+)\s*(.*)}om
8
+ # SYNTAX_VARIABLE @to is the original Liquid::VariableSignature but with bracket
9
+ # characters removed
10
+ SYNTAX_VARIABLE = %r{((?-mix:\(?[\w\-.]\)?)+)\s*=\s*([\w/\-."']+)\s*(.*)}om
11
+
12
+ attr_reader :to, :from, :attributes
13
+
14
+ def initialize(tag_name, markup, options)
15
+ super
16
+ if markup =~ SYNTAX_VARIABLE
17
+ @to = Regexp.last_match(1)
18
+ @from = Liquid::Expression.parse(Regexp.last_match(2))
19
+ # Rest of markup contains only the function parameters, an improvement made in
20
+ # another PR as well, to avoid other parts of the markup containing special
21
+ # characters from conflicting with ::Liquify::Tags::BaseTagMethods::TAG_ATTRIBUTES
22
+ @rest_of_markup = Regexp.last_match(3)
23
+
24
+ @assign_type = :variable
25
+ elsif markup =~ SYNTAX_HASH
26
+ @to = Regexp.last_match(1)
27
+ # No longer checking there is hash access as it's mandatory in the Regex
28
+ @from = Liquid::Expression.parse(Regexp.last_match(4))
29
+ @keys = parse_raw_keys(Regexp.last_match(3))
30
+ @rest_of_markup = Regexp.last_match(5)
31
+
32
+ @assign_type = :hash
33
+ else
34
+ raise Liquid::SyntaxError, 'Invalid syntax for function tag'
35
+ end
36
+
37
+ @attributes = {}
38
+ @rest_of_markup.scan(::PlatformosCheck::Tags::Base::TAG_ATTRIBUTES) do |key, value|
39
+ unless well_formed_object_access?(value)
40
+ raise Liquid::SyntaxError,
41
+ 'Invalid syntax for function tag, no spaces allowed when accessing array or hash.'
42
+ end
43
+
44
+ @attributes[key] = Liquid::Expression.parse(value)
45
+ end
46
+ end
47
+
48
+ class ParseTreeVisitor < Liquid::ParseTreeVisitor
49
+ def children
50
+ [
51
+ @node.from,
52
+ @node.main_value
53
+ ] + @node.attributes_expr.values
54
+ end
55
+ end
56
+ end
57
+ end
58
+ end
@@ -0,0 +1,70 @@
1
+ # frozen_string_literal: true
2
+
3
+ module PlatformosCheck
4
+ module Tags
5
+ class Graphql < Base
6
+ QUERY_NAME_SYNTAX = /(#{Liquid::VariableSignature}+)\s*=\s*(.*)\s*/om
7
+ INLINE_SYNTAX = /(#{Liquid::QuotedFragment}+)(\s*(#{Liquid::QuotedFragment}+))?/o
8
+ CLOSE_TAG_SYNTAX = /\A(.*)(?-mix:\{%-?)\s*(\w+)\s*(.*)?(?-mix:%\})\z/m # based on Liquid::Raw::FullTokenPossiblyInvalid
9
+
10
+ attr_reader :to, :from, :inline_query, :value_expr, :partial_name, :attributes_expr, :attributes
11
+
12
+ def initialize(tag_name, markup, options)
13
+ super
14
+ if markup =~ QUERY_NAME_SYNTAX
15
+ @to = Regexp.last_match(1)
16
+ @inline_query = false
17
+
18
+ # inline query looks like this:
19
+ # {% graph res = "my_query", id: "1" | dig: 'my_query' %}
20
+ # we want to first process "my_query, id: "1" , store it in "res" and then process
21
+ # it with filters like this:
22
+ # res | dig: 'my_query'
23
+ after_assign_markup = Regexp.last_match(2).split('|')
24
+ parse_markup(tag_name, after_assign_markup.shift)
25
+ @attributes = attributes_expr.keys
26
+
27
+ after_assign_markup.unshift(@to)
28
+ @partial_name = value_expr
29
+ @from = Liquid::Variable.new(after_assign_markup.join('|'), options)
30
+ elsif INLINE_SYNTAX.match?(markup)
31
+ @inline_query = true
32
+ parse_markup(tag_name, markup)
33
+ @attributes = attributes_expr.keys
34
+ @to = @value_expr.name
35
+ else
36
+ raise Liquid::SyntaxError, 'Invalid syntax for graphql tag'
37
+ end
38
+ end
39
+
40
+ def parse(tokens)
41
+ return super unless @inline_query
42
+
43
+ @body = +''
44
+ while (token = tokens.send(:shift))
45
+ if token =~ CLOSE_TAG_SYNTAX && block_delimiter == Regexp.last_match(2)
46
+ @body << Regexp.last_match(1) if Regexp.last_match(1) != ''
47
+ return
48
+ end
49
+ @body << token unless token.empty?
50
+ end
51
+
52
+ raise Liquid::SyntaxError, parse_context.locale.t('errors.syntax.tag_never_closed', block_name:)
53
+ end
54
+
55
+ def block_name
56
+ @tag_name
57
+ end
58
+
59
+ def block_delimiter
60
+ @block_delimiter = "end#{block_name}"
61
+ end
62
+
63
+ class ParseTreeVisitor < Liquid::ParseTreeVisitor
64
+ def children
65
+ [@node.to].compact + @node.attributes_expr.values
66
+ end
67
+ end
68
+ end
69
+ end
70
+ end
@@ -0,0 +1,75 @@
1
+ # frozen_string_literal: true
2
+
3
+ module PlatformosCheck
4
+ module Tags
5
+ class HashAssign < Base
6
+ SYNTAX = /((\(?[\w\-.]\)?)+)(\[.+\])*\s*=\s*(\S.*)\s*/om
7
+ KEYS = /[\w\-"'.]+/
8
+
9
+ attr_reader :keys, :to, :from
10
+
11
+ def initialize(tag_name, markup, options)
12
+ super
13
+ raise Liquid::SyntaxError, "Syntax Error in 'hash_assign' - Valid syntax: hash_assign hash[key] = value" unless markup =~ SYNTAX
14
+
15
+ @to = Regexp.last_match(1)
16
+ @from = Liquid::Variable.new(Regexp.last_match(4), options)
17
+ raw_keys = Regexp.last_match(3)
18
+ raise Liquid::SyntaxError, "Syntax Error in 'hash_assign' - Valid syntax: hash_assign hash[key] = value" unless raw_keys
19
+
20
+ @keys = parse_raw_keys(raw_keys)
21
+ end
22
+
23
+ # raw_keys can be something like
24
+ # "[item2][ item[0] ]['mich][ael']"
25
+ def parse_raw_keys(raw_keys)
26
+ nesting_level = 0
27
+ keys = []
28
+ current_key = ''
29
+ in_double_quote = false
30
+ in_single_quote = false
31
+ raw_keys.each_char do |char|
32
+ case char
33
+ when '['
34
+ if !in_double_quote && !in_single_quote
35
+ nesting_level += 1
36
+ current_key += char if nesting_level > 1
37
+ else
38
+ current_key += char
39
+ end
40
+ when ']'
41
+ if !in_double_quote && !in_single_quote
42
+ nesting_level -= 1
43
+ if nesting_level.zero?
44
+ keys << Liquid::Expression.parse(current_key)
45
+ current_key = ''
46
+ else
47
+ current_key += char
48
+ end
49
+ else
50
+ current_key += char
51
+ end
52
+ when '"'
53
+ in_double_quote = !in_double_quote unless in_single_quote
54
+ current_key += char
55
+ when "'"
56
+ in_single_quote = !in_single_quote unless in_double_quote
57
+ current_key += char
58
+ else
59
+ current_key += char
60
+ end
61
+ end
62
+
63
+ keys
64
+ end
65
+
66
+ class ParseTreeVisitor < Liquid::ParseTreeVisitor
67
+ def children
68
+ [
69
+ @node.from
70
+ ] + @node.keys
71
+ end
72
+ end
73
+ end
74
+ end
75
+ end