theme-check 0.8.2 → 0.10.1

Sign up to get free protection for your applications and to get access to all the features.
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
+