theme-check 0.8.2 → 0.10.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 (53) hide show
  1. checksums.yaml +4 -4
  2. data/.github/workflows/theme-check.yml +3 -0
  3. data/CHANGELOG.md +45 -0
  4. data/CONTRIBUTING.md +20 -90
  5. data/README.md +4 -1
  6. data/RELEASING.md +5 -3
  7. data/Rakefile +31 -0
  8. data/config/default.yml +45 -0
  9. data/docs/api/check.md +15 -0
  10. data/docs/api/html_check.md +46 -0
  11. data/docs/api/json_check.md +19 -0
  12. data/docs/api/liquid_check.md +99 -0
  13. data/docs/checks/{CHECK_DOCS_TEMPLATE.md → TEMPLATE.md.erb} +5 -5
  14. data/docs/checks/asset_url_filters.md +56 -0
  15. data/docs/checks/content_for_header_modification.md +42 -0
  16. data/docs/checks/img_lazy_loading.md +61 -0
  17. data/docs/checks/parser_blocking_script_tag.md +53 -0
  18. data/exe/theme-check-language-server +1 -2
  19. data/lib/theme_check.rb +8 -1
  20. data/lib/theme_check/analyzer.rb +72 -16
  21. data/lib/theme_check/bug.rb +1 -0
  22. data/lib/theme_check/check.rb +32 -7
  23. data/lib/theme_check/checks.rb +9 -1
  24. data/lib/theme_check/checks/TEMPLATE.rb.erb +11 -0
  25. data/lib/theme_check/checks/asset_url_filters.rb +46 -0
  26. data/lib/theme_check/checks/content_for_header_modification.rb +41 -0
  27. data/lib/theme_check/checks/img_lazy_loading.rb +25 -0
  28. data/lib/theme_check/checks/img_width_and_height.rb +18 -49
  29. data/lib/theme_check/checks/missing_template.rb +1 -0
  30. data/lib/theme_check/checks/parser_blocking_javascript.rb +6 -38
  31. data/lib/theme_check/checks/parser_blocking_script_tag.rb +20 -0
  32. data/lib/theme_check/checks/remote_asset.rb +21 -79
  33. data/lib/theme_check/checks/template_length.rb +3 -0
  34. data/lib/theme_check/checks/valid_html_translation.rb +1 -0
  35. data/lib/theme_check/config.rb +2 -0
  36. data/lib/theme_check/disabled_check.rb +6 -4
  37. data/lib/theme_check/disabled_checks.rb +25 -9
  38. data/lib/theme_check/html_check.rb +7 -0
  39. data/lib/theme_check/html_node.rb +56 -0
  40. data/lib/theme_check/html_visitor.rb +38 -0
  41. data/lib/theme_check/json_file.rb +13 -0
  42. data/lib/theme_check/language_server.rb +1 -0
  43. data/lib/theme_check/language_server/completion_providers/filter_completion_provider.rb +1 -0
  44. data/lib/theme_check/language_server/diagnostics_tracker.rb +66 -0
  45. data/lib/theme_check/language_server/handler.rb +31 -26
  46. data/lib/theme_check/language_server/server.rb +1 -1
  47. data/lib/theme_check/liquid_check.rb +1 -4
  48. data/lib/theme_check/offense.rb +18 -0
  49. data/lib/theme_check/template.rb +9 -0
  50. data/lib/theme_check/theme.rb +7 -2
  51. data/lib/theme_check/version.rb +1 -1
  52. data/lib/theme_check/visitor.rb +2 -11
  53. metadata +20 -3
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 8b455dde358a80264581b4c6b62e70c071510d5e50ff8b253e98550ac64be3db
4
- data.tar.gz: 5fc99066d47dd69ba0d56bea7bf60b20ccf4c67364b19999c2e5feba8cc4da12
3
+ metadata.gz: 56b6a91e5ac4b1e2045b1e4fb2748e5ecb9600206f9ba07df401c1410bf494fc
4
+ data.tar.gz: b6fb1b3957ae5aecd7b2efbaa76a2e3c07390ec442f94d416ea5b20ca2cbf966
5
5
  SHA512:
6
- metadata.gz: 6ee8807bab14aa44d5d2f1722d846f2c07c58656c7aa23dcc1da7a2e0e4f8b76cf2ca862c2ad7a9c1fd88c470b7cc4517fc74684af55a31d36eba4e60b6990bd
7
- data.tar.gz: fd0d6012b3f991df7de47f4f7de27348a35d9582908d8564140fd900e81da9e6203b4485c7fb13dec78ddd2201acf7829b893d0004dcd1436fea4b1ea6098767
6
+ metadata.gz: e2ca68b31968949dc52240c8ee5ca607e10e063b500cda0a7b06306589849f2bc0098f1b0742f962a91a0ca282aa504acb9f7c0de6b785afff0b577b84fa6eba
7
+ data.tar.gz: c7186299a1168c5ad1e3cd6544ee8c8248b96a492e1dc82481c26a69e75fb1f04172ceb58da61e310a393fd36c9b990464542e7528810c7bea556b5b8ce9b61d
@@ -34,3 +34,6 @@ jobs:
34
34
  run: bundle install --jobs=3 --retry=3 --path=vendor/bundle
35
35
  - name: Run tests
36
36
  run: bundle exec rake
37
+ - name: Test runtime
38
+ # Testing that runtime can execute, not testing the results themselves
39
+ run: bundle exec theme-check ./test/theme | grep -q "files inspected"
data/CHANGELOG.md CHANGED
@@ -1,4 +1,49 @@
1
1
 
2
+ v0.10.1 / 2021-06-11
3
+ ==================
4
+
5
+ * Fix LSP diagnostics not being merged properly when analyzing a single file.
6
+ Causing VSCode problems not being cleared after fixing.
7
+
8
+ v0.10.0 / 2021-06-08
9
+ ==================
10
+
11
+ * Add ImgLazyLoading check for recommending loading="lazy" attribute
12
+
13
+ v0.9.1 / 2021-06-04
14
+ ==================
15
+
16
+ * Convert `RemoteAsset` into an `HtmlCheck`
17
+ * Move Liquid logic from `RemoteAsset` to a new `AssetUrlFilters` check
18
+
19
+ v0.9.0 / 2021-05-28
20
+ ==================
21
+
22
+ * Introduce HtmlCheck, and convert ParserBlockingJavaScript & ImgWidthAndHeight to it
23
+ * Move `script-tag` validation from ParserBlockingJavaScript to ParserBlockingScriptTag
24
+ * Add ability to ignore individual checks using file patterns
25
+ * Introduce single file and whole theme checks to optimize LSP diagnostics
26
+ * Fix TemplateLength counter not being reseted on each document
27
+ * Add missing category to ValidHTMLTranslation
28
+ * Set Ruby default encodings to UTF-8 to fix encoding issues
29
+ * Add ContentForHeaderModification check to prevent relying on the content of ``content_for_header`
30
+ * Fix `Content-Length` in LSP responses
31
+ * Fix disabling checks that emit offences in `on_end`
32
+ * Fix completion bug in `filter_completion_provider`
33
+
34
+ v0.8.3 / 2021-05-17
35
+ ==================
36
+
37
+ * Making sure VERSION is set before referencing it
38
+
39
+ v0.8.2 / 2021-05-14
40
+ ===================
41
+
42
+ * Bump NestedSnippet max_nesting_level to 3
43
+ * Add a message to help debug errors, and timeout checks after 5 sec
44
+ * Object Completions Everywhere!
45
+ * Include operators to space inside braces check
46
+
2
47
  0.8.1 / 2021-04-22
3
48
  ==================
4
49
 
data/CONTRIBUTING.md CHANGED
@@ -36,102 +36,32 @@ bundle exec theme-check /path/to/your/theme
36
36
 
37
37
  ## Creating a new "Check"
38
38
 
39
- Under `lib/theme_check/checks`, create new Ruby file with a unique name describing what you want to check for.
39
+ Run `bundle exec rake "new_check[MyNewCheckName]"` to generate all the files required to create a new check.
40
40
 
41
- ```ruby
42
- module ThemeCheck
43
- # Does one thing, and does it well!
44
- # NOTE: inherit from JsonCheck to implement a JSON based check.
45
- class MyCheckName < LiquidCheck
46
- severity :suggestion # :error or :style
47
-
48
- def on_document(node)
49
- # Called with the root node of all templates
50
- node.value # is the original Liquid object for this node. See Liquid source code for details.
51
- node.template # is the template being analyzed, See lib/theme_check/template.rb.
52
- node.parent # is the parent node.
53
- node.children # are the children nodes.
54
- # See lib/theme_check/node.rb for more helper methods
55
- theme # Gives you access to all the templates in the theme. See lib/theme_check/theme.rb.
56
- end
57
-
58
- def on_node(node)
59
- # Called for every node
60
- end
61
-
62
- def on_tag(node)
63
- # Called for each tag (if, include, for, assign, etc.)
64
- end
65
-
66
- def after_tag(node)
67
- # Called after the tag children have been visited
68
-
69
- # If you find an issue, add an offense:
70
- add_offense("Describe the problem...", node: node)
71
- # Or, if the offense is related to the whole template:
72
- add_offense("Describe the problem...", template: node.template)
73
- end
74
-
75
- def on_assign(node)
76
- # Called only for {% assign ... %} tags
77
- end
78
-
79
- def on_string(node)
80
- # Called for every `String` (including inside if conditions).
81
- if node.parent.block?
82
- # If parent is a block, `node.value` is a String written directly to the output when
83
- # the template is rendered.
84
- end
85
- end
86
-
87
- def on_error(exception)
88
- # Called each time a Liquid exception is raised while parsing the template
89
- end
90
-
91
- def on_end
92
- # A special callback after we're done visiting all the templates
93
- end
94
-
95
- # Each type of node has a corresponding `on_node_class_name` & `after_node_class_name`
96
- # A few common examples:
97
- # on_block_body(node)
98
- # on_capture(node)
99
- # on_case(node)
100
- # on_comment(node)
101
- # on_condition(node)
102
- # on_document(node)
103
- # on_else_condition(node)
104
- # on_for(node)
105
- # on_form(node)
106
- # on_if(node)
107
- # on_include(node)
108
- # on_integer(node)
109
- # on_layout(node)
110
- # on_method_literal(node)
111
- # on_paginate(node)
112
- # on_range(node)
113
- # on_render(node)
114
- # on_schema(node)
115
- # on_section(node)
116
- # on_style(node)
117
- # on_unless(node)
118
- # on_variable(node)
119
- # on_variable_lookup(node)
120
- end
121
- end
122
- ```
41
+ Check the [Check API](/docs/api/check.md) for how to implement a check. Also take a look at other checks in [lib/theme_check/checks](/lib/theme_check/checks).
123
42
 
124
- Add the new check to `config/default.yml` to enable it. If the check is configurable, the `initialize` argument name and default values should also be duplicated inside `config/default.yml`.
43
+ We done implementing your check, add it to `config/default.yml` to enable it:
125
44
 
126
45
  ```yaml
127
- MyCheckName:
46
+ MyNewCheckName:
128
47
  enabled: true
48
+ ignore: []
129
49
  ```
130
50
 
131
- Add a corresponding test file under `test/checks`.
132
-
133
- Add a documentation file in `docs/checks/#{name_of_check}.md` based off of the [check documentation template][doctemplate].
51
+ If the check is configurable, the `initialize` argument names and default values should also be duplicated inside `config/default.yml`. eg.:
134
52
 
135
- When done, run the tests with `dev test`.
53
+ ```ruby
54
+ class MyCheckName < LiquidCheck
55
+ def initialize(muffin_mode: true)
56
+ @muffin_mode = muffin_mode
57
+ end
58
+ # ...
59
+ end
60
+ ```
136
61
 
137
- [doctemplate]: /docs/checks/CHECK_DOCS_TEMPLATE.md
62
+ ```yaml
63
+ MyNewCheckName:
64
+ enabled: true
65
+ ignore: []
66
+ muffin_mode: true
67
+ ```
data/README.md CHANGED
@@ -92,11 +92,14 @@ root: dist
92
92
  require:
93
93
  - ./path/to/my_custom_check.rb
94
94
 
95
- # Disable some checks
96
95
  TemplateLength:
96
+ # Disable some checks
97
97
  enabled: false
98
98
  # Or configure options
99
99
  max_length: 300
100
+ # Or ignore certain paths
101
+ ignore:
102
+ - snippets/icon-*
100
103
 
101
104
  # Enable a custom check
102
105
  MyCustomCheck
data/RELEASING.md CHANGED
@@ -9,11 +9,13 @@
9
9
  rake prerelease[$VERSION]
10
10
  ```
11
11
 
12
- 3. Commit your changes and make a PR.
12
+ 3. Run [`git changelog`](https://github.com/tj/git-extras) to update `CHANGELOG.md`.
13
13
 
14
- 4. Merge your PR to master.
14
+ 4. Commit your changes and make a PR.
15
15
 
16
- 5. On [Shipit](https://shipit.shopify.io/shopify/theme-check/rubygems), deploy your commit.
16
+ 5. Merge your PR to master.
17
+
18
+ 6. On [Shipit](https://shipit.shopify.io/shopify/theme-check/rubygems), deploy your commit.
17
19
 
18
20
  ## Homebrew Release Process
19
21
 
data/Rakefile CHANGED
@@ -52,3 +52,34 @@ task :prerelease, [:version] do |_t, args|
52
52
  require 'theme_check/releaser'
53
53
  ThemeCheck::Releaser.new.release(args.version)
54
54
  end
55
+
56
+ desc "Create a new check"
57
+ task :new_check, [:name] do |_t, args|
58
+ require "theme_check/string_helpers"
59
+ class_name = args.name
60
+ base_name = ThemeCheck::StringHelpers.underscore(class_name)
61
+ code_source = "lib/theme_check/checks/#{base_name}.rb"
62
+ doc_source = "docs/checks/#{base_name}.md"
63
+ test_source = "test/checks/#{base_name}_test.rb"
64
+ erb(
65
+ "lib/theme_check/checks/TEMPLATE.rb.erb", code_source,
66
+ class_name: class_name,
67
+ )
68
+ erb(
69
+ "test/checks/TEMPLATE.rb.erb", test_source,
70
+ class_name: class_name,
71
+ )
72
+ erb(
73
+ "docs/checks/TEMPLATE.md.erb", doc_source,
74
+ class_name: class_name,
75
+ code_source: code_source,
76
+ doc_source: doc_source,
77
+ )
78
+ sh "bundle exec ruby -Itest test/checks/my_new_check_test.rb"
79
+ end
80
+
81
+ def erb(file, to, **args)
82
+ require "erb"
83
+ File.write(to, ERB.new(File.read(file)).result_with_hash(args))
84
+ puts "Generated #{to}"
85
+ end
data/config/default.yml CHANGED
@@ -7,92 +7,137 @@ ignore:
7
7
 
8
8
  ConvertIncludeToRender:
9
9
  enabled: true
10
+ ignore: []
10
11
 
11
12
  LiquidTag:
12
13
  enabled: true
14
+ ignore: []
13
15
  min_consecutive_statements: 4
14
16
 
15
17
  MissingTemplate:
16
18
  enabled: true
19
+ ignore: []
17
20
 
18
21
  NestedSnippet:
19
22
  enabled: true
23
+ ignore: []
20
24
  max_nesting_level: 3
21
25
 
22
26
  RequiredLayoutThemeObject:
23
27
  enabled: true
28
+ ignore: []
24
29
 
25
30
  SpaceInsideBraces:
26
31
  enabled: true
32
+ ignore: []
27
33
 
28
34
  SyntaxError:
29
35
  enabled: true
36
+ ignore: []
30
37
 
31
38
  TemplateLength:
32
39
  enabled: true
40
+ ignore: []
33
41
  max_length: 200
34
42
  # Exclude content of {% schema %} in line count
35
43
  exclude_schema: true
36
44
 
37
45
  UnknownFilter:
38
46
  enabled: true
47
+ ignore: []
39
48
 
40
49
  UnusedAssign:
41
50
  enabled: true
51
+ ignore: []
42
52
 
43
53
  UnusedSnippet:
44
54
  enabled: true
55
+ ignore: []
45
56
 
46
57
  MatchingSchemaTranslations:
47
58
  enabled: true
59
+ ignore: []
48
60
 
49
61
  MatchingTranslations:
50
62
  enabled: true
63
+ ignore: []
51
64
 
52
65
  DefaultLocale:
53
66
  enabled: true
67
+ ignore: []
54
68
 
55
69
  TranslationKeyExists:
56
70
  enabled: true
71
+ ignore: []
57
72
 
58
73
  ValidHTMLTranslation:
59
74
  enabled: true
75
+ ignore: []
60
76
 
61
77
  ValidJson:
62
78
  enabled: true
79
+ ignore: []
63
80
 
64
81
  ValidSchema:
65
82
  enabled: true
83
+ ignore: []
66
84
 
67
85
  MissingRequiredTemplateFiles:
68
86
  enabled: true
87
+ ignore: []
69
88
 
70
89
  UndefinedObject:
71
90
  enabled: true
91
+ ignore: []
72
92
  exclude_snippets: true
73
93
 
74
94
  RequiredDirectories:
75
95
  enabled: true
96
+ ignore: []
76
97
 
77
98
  DeprecatedFilter:
78
99
  enabled: true
100
+ ignore: []
79
101
 
80
102
  MissingEnableComment:
81
103
  enabled: true
104
+ ignore: []
82
105
 
83
106
  ParserBlockingJavaScript:
84
107
  enabled: true
108
+ ignore: []
109
+
110
+ ParserBlockingScriptTag:
111
+ enabled: true
85
112
 
86
113
  AssetSizeJavaScript:
87
114
  enabled: false
115
+ ignore: []
88
116
  threshold_in_bytes: 10_000
117
+ ignore: []
89
118
 
90
119
  AssetSizeCSS:
91
120
  enabled: false
121
+ ignore: []
92
122
  threshold_in_bytes: 100_000
123
+ ignore: []
93
124
 
94
125
  ImgWidthAndHeight:
95
126
  enabled: true
127
+ ignore: []
96
128
 
97
129
  RemoteAsset:
98
130
  enabled: true
131
+ ignore: []
132
+
133
+ AssetUrlFilters:
134
+ enabled: true
135
+ ignore: []
136
+
137
+ ContentForHeaderModification:
138
+ enabled: true
139
+ ignore: []
140
+
141
+ ImgLazyLoading:
142
+ enabled: true
143
+ ignore: []
data/docs/api/check.md ADDED
@@ -0,0 +1,15 @@
1
+ # Check API
2
+
3
+ Theme Check uses static analysis. It parses theme files into an AST, and then calls the appropriate checks to analyze it.
4
+
5
+ An [AST](https://en.wikipedia.org/wiki/Abstract_syntax_tree) is a tree of node, representing the theme file.
6
+
7
+ Checks are Ruby classes with callback methods:
8
+ - `on_TYPE` that runs before a node of the specific TYPE is visited.
9
+ - `after_TYPE` that runs after a node of the specific TYPE is visited.
10
+
11
+ There are three types of checks currently supported:
12
+
13
+ - [`LiquidCheck`](/docs/api/liquid_check.md)
14
+ - [`HtmlCheck`](/docs/api/html_check.md)
15
+ - [`JsonCheck`](/docs/api/html_check.md)
@@ -0,0 +1,46 @@
1
+ # HTML check API
2
+
3
+ For checking HTML elements in `.liquid` files.
4
+
5
+ If you need to check an HTML tag or its attributes, use an `HtmlCheck`.
6
+
7
+ The HTML in Liquid files is parsed using the Nokogiri, by consequence you will get [`Nokogiri::XML::Node`][nokogiri].
8
+
9
+
10
+ ```ruby
11
+ module ThemeCheck
12
+ class MyCheckName < HtmlCheck
13
+ category :html,
14
+ # A check can belong to multiple categories. Valid ones:
15
+ categories :translation, :performance
16
+ severity :suggestion # :error or :style
17
+
18
+ def on_document(node)
19
+ # Called with the root node of all templates
20
+ node.value # is an instance of Nokogiri::XML::Node
21
+ node.template # is the template being analyzed, See lib/theme_check/template.rb.
22
+ node.parent # is the parent node.
23
+ node.children # are the children nodes.
24
+ # See lib/theme_check/html_node.rb for more helper methods
25
+ theme # Gives you access to all the templates in the theme. See lib/theme_check/theme.rb.
26
+ end
27
+
28
+ def on_img(node)
29
+ # Called for every <img> element in the file.
30
+ node.attrbutes["class"] # Get the class attribute of the img element.
31
+ end
32
+
33
+ def on_a(node)
34
+ # Called for every <a> element in the file.
35
+ end
36
+ end
37
+ end
38
+ ```
39
+
40
+ ## Resources
41
+
42
+ - [Nokogiri::XML::Node API doc][nokogiri]
43
+
44
+ [nokogiri]: https://www.rubydoc.info/github/sparklemotion/nokogiri/Nokogiri/XML/Node
45
+
46
+