theme-check 0.1.2 → 0.3.2

Sign up to get free protection for your applications and to get access to all the features.
Files changed (47) hide show
  1. checksums.yaml +4 -4
  2. data/.gitignore +1 -0
  3. data/.rubocop.yml +1 -0
  4. data/CHANGELOG.md +27 -0
  5. data/CONTRIBUTING.md +2 -0
  6. data/README.md +62 -1
  7. data/RELEASING.md +41 -0
  8. data/Rakefile +38 -4
  9. data/config/default.yml +20 -1
  10. data/data/shopify_liquid/deprecated_filters.yml +10 -0
  11. data/data/shopify_liquid/plus_objects.yml +15 -0
  12. data/dev.yml +2 -0
  13. data/lib/theme_check.rb +6 -0
  14. data/lib/theme_check/analyzer.rb +15 -5
  15. data/lib/theme_check/check.rb +11 -0
  16. data/lib/theme_check/checks.rb +10 -0
  17. data/lib/theme_check/checks/deprecated_filter.rb +22 -0
  18. data/lib/theme_check/checks/missing_enable_comment.rb +31 -0
  19. data/lib/theme_check/checks/parser_blocking_javascript.rb +55 -0
  20. data/lib/theme_check/checks/space_inside_braces.rb +19 -7
  21. data/lib/theme_check/checks/template_length.rb +11 -3
  22. data/lib/theme_check/checks/undefined_object.rb +119 -36
  23. data/lib/theme_check/checks/valid_html_translation.rb +2 -2
  24. data/lib/theme_check/cli.rb +18 -4
  25. data/lib/theme_check/config.rb +97 -44
  26. data/lib/theme_check/corrector.rb +31 -0
  27. data/lib/theme_check/disabled_checks.rb +77 -0
  28. data/lib/theme_check/file_system_storage.rb +51 -0
  29. data/lib/theme_check/in_memory_storage.rb +37 -0
  30. data/lib/theme_check/json_file.rb +12 -10
  31. data/lib/theme_check/language_server/handler.rb +38 -13
  32. data/lib/theme_check/language_server/server.rb +2 -2
  33. data/lib/theme_check/liquid_check.rb +2 -2
  34. data/lib/theme_check/node.rb +13 -0
  35. data/lib/theme_check/offense.rb +25 -9
  36. data/lib/theme_check/packager.rb +51 -0
  37. data/lib/theme_check/printer.rb +13 -4
  38. data/lib/theme_check/shopify_liquid.rb +1 -0
  39. data/lib/theme_check/shopify_liquid/deprecated_filter.rb +28 -0
  40. data/lib/theme_check/shopify_liquid/object.rb +6 -0
  41. data/lib/theme_check/storage.rb +25 -0
  42. data/lib/theme_check/template.rb +32 -10
  43. data/lib/theme_check/theme.rb +14 -9
  44. data/lib/theme_check/version.rb +1 -1
  45. data/lib/theme_check/visitor.rb +14 -3
  46. data/packaging/homebrew/theme_check.base.rb +98 -0
  47. metadata +17 -2
@@ -0,0 +1,51 @@
1
+ # frozen_string_literal: true
2
+ module ThemeCheck
3
+ class Packager
4
+ ROOT = File.expand_path('../../..', __FILE__)
5
+ PACKAGING_DIR = File.join(ROOT, 'packaging')
6
+ BUILDS_DIR = File.join(PACKAGING_DIR, 'builds', ThemeCheck::VERSION)
7
+
8
+ def initialize
9
+ FileUtils.mkdir_p(BUILDS_DIR)
10
+ end
11
+
12
+ def build_homebrew
13
+ root_dir = File.join(PACKAGING_DIR, 'homebrew')
14
+
15
+ build_path = File.join(BUILDS_DIR, "theme-check.rb")
16
+ puts "\nBuilding Homebrew package"
17
+
18
+ puts "Generating formula..."
19
+ File.delete(build_path) if File.exist?(build_path)
20
+
21
+ spec_contents = File.read(File.join(root_dir, 'theme_check.base.rb'))
22
+ spec_contents = spec_contents.gsub('THEME_CHECK_VERSION', ThemeCheck::VERSION)
23
+
24
+ puts "Grabbing sha256 checksum from Rubygems.org"
25
+ require 'digest/sha2'
26
+ require 'open-uri'
27
+ gem_checksum = open("https://rubygems.org/downloads/theme-check-#{ThemeCheck::VERSION}.gem") do |io|
28
+ Digest::SHA256.new.hexdigest(io.read)
29
+ end
30
+
31
+ puts "Got sha256 checksum for gem: #{gem_checksum}"
32
+ spec_contents = spec_contents.gsub('THEME_CHECK_GEM_CHECKSUM', gem_checksum)
33
+
34
+ puts "Writing generated formula\n To: #{build_path}\n\n"
35
+ File.write(build_path, spec_contents)
36
+ end
37
+
38
+ private
39
+
40
+ def ensure_program_installed(program, installation_cmd)
41
+ unless system(program, '--version', out: File::NULL, err: File::NULL)
42
+ raise <<~MESSAGE
43
+
44
+ Could not find program #{program} which is required to build the package.
45
+ You can install it by running `#{installation_cmd}`.
46
+
47
+ MESSAGE
48
+ end
49
+ end
50
+ end
51
+ end
@@ -2,25 +2,34 @@
2
2
 
3
3
  module ThemeCheck
4
4
  class Printer
5
- def print(theme, offenses)
5
+ def print(theme, offenses, auto_correct)
6
6
  offenses.each do |offense|
7
- print_offense(offense)
7
+ print_offense(offense, auto_correct)
8
8
  puts
9
9
  end
10
10
 
11
- puts "#{theme.all.size} files inspected, #{red(offenses.size.to_s + ' offenses')} detected"
11
+ correctable = offenses.select(&:correctable?)
12
+ puts "#{theme.all.size} files inspected, #{red(offenses.size.to_s + ' offenses')} detected, \
13
+ #{yellow(correctable.size.to_s + ' offenses')} #{auto_correct ? 'corrected' : 'auto-correctable'}"
12
14
  end
13
15
 
14
- def print_offense(offense)
16
+ def print_offense(offense, auto_correct)
15
17
  location = if offense.location
16
18
  blue(offense.location) + ": "
17
19
  else
18
20
  ""
19
21
  end
20
22
 
23
+ corrected = if auto_correct && offense.correctable?
24
+ green("[Corrected] ")
25
+ else
26
+ ""
27
+ end
28
+
21
29
  puts location +
22
30
  colorized_severity(offense.severity) + ": " +
23
31
  yellow(offense.check_name) + ": " +
32
+ corrected +
24
33
  offense.message + "."
25
34
  if offense.source_excerpt
26
35
  puts "\t#{offense.source_excerpt}"
@@ -1,3 +1,4 @@
1
1
  # frozen_string_literal: true
2
+ require_relative 'shopify_liquid/deprecated_filter'
2
3
  require_relative 'shopify_liquid/filter'
3
4
  require_relative 'shopify_liquid/object'
@@ -0,0 +1,28 @@
1
+ # frozen_string_literal: true
2
+ require 'yaml'
3
+
4
+ module ThemeCheck
5
+ module ShopifyLiquid
6
+ module DeprecatedFilter
7
+ extend self
8
+
9
+ def alternatives(filter)
10
+ all.fetch(filter, nil)
11
+ end
12
+
13
+ private
14
+
15
+ def all
16
+ @all ||= begin
17
+ YAML.load(File.read("#{__dir__}/../../../data/shopify_liquid/deprecated_filters.yml"))
18
+ .values
19
+ .each_with_object({}) do |filters, acc|
20
+ filters.each do |(filter, alternatives)|
21
+ acc[filter] = alternatives
22
+ end
23
+ end
24
+ end
25
+ end
26
+ end
27
+ end
28
+ end
@@ -11,6 +11,12 @@ module ThemeCheck
11
11
  YAML.load(File.read("#{__dir__}/../../../data/shopify_liquid/objects.yml"))
12
12
  end
13
13
  end
14
+
15
+ def plus_labels
16
+ @plus_labels ||= begin
17
+ YAML.load(File.read("#{__dir__}/../../../data/shopify_liquid/plus_objects.yml"))
18
+ end
19
+ end
14
20
  end
15
21
  end
16
22
  end
@@ -0,0 +1,25 @@
1
+ # frozen_string_literal: true
2
+
3
+ module ThemeCheck
4
+ class Storage
5
+ def read(relative_path)
6
+ raise NotImplementedError
7
+ end
8
+
9
+ def write(relative_path, content)
10
+ raise NotImplementedError
11
+ end
12
+
13
+ def path(relative_path)
14
+ raise NotImplementedError
15
+ end
16
+
17
+ def files
18
+ raise NotImplementedError
19
+ end
20
+
21
+ def directories
22
+ raise NotImplementedError
23
+ end
24
+ end
25
+ end
@@ -3,15 +3,29 @@ require "pathname"
3
3
 
4
4
  module ThemeCheck
5
5
  class Template
6
- attr_reader :path
6
+ def initialize(relative_path, storage)
7
+ @storage = storage
8
+ @relative_path = relative_path
9
+ end
7
10
 
8
- def initialize(path, root)
9
- @path = Pathname(path)
10
- @root = Pathname(root)
11
+ def path
12
+ @storage.path(@relative_path)
11
13
  end
12
14
 
13
15
  def relative_path
14
- @path.relative_path_from(@root)
16
+ @relative_pathname ||= Pathname.new(@relative_path)
17
+ end
18
+
19
+ def source
20
+ @source ||= @storage.read(@relative_path)
21
+ end
22
+
23
+ def write
24
+ content = updated_content
25
+ if source != content
26
+ @storage.write(@relative_path, content)
27
+ @source = content
28
+ end
15
29
  end
16
30
 
17
31
  def name
@@ -30,18 +44,26 @@ module ThemeCheck
30
44
  name.start_with?('snippets')
31
45
  end
32
46
 
33
- def source
34
- @source ||= @path.read
47
+ def lines
48
+ # Retain trailing newline character
49
+ @lines ||= source.split("\n", -1)
35
50
  end
36
51
 
37
- def lines
38
- @lines ||= source.split("\n")
52
+ # Not entirely obvious but lines is mutable, corrections are to be
53
+ # applied on @lines.
54
+ def updated_content
55
+ lines.join("\n")
39
56
  end
40
57
 
41
58
  def excerpt(line)
42
59
  lines[line - 1].strip
43
60
  end
44
61
 
62
+ def source_excerpt(line)
63
+ original_lines = source.split("\n")
64
+ original_lines[line - 1].strip
65
+ end
66
+
45
67
  def full_line(line)
46
68
  lines[line - 1]
47
69
  end
@@ -59,7 +81,7 @@ module ThemeCheck
59
81
  end
60
82
 
61
83
  def ==(other)
62
- other.is_a?(Template) && @path == other.path
84
+ other.is_a?(Template) && relative_path == other.relative_path
63
85
  end
64
86
 
65
87
  def self.parse(source)
@@ -4,18 +4,27 @@ require "pathname"
4
4
  module ThemeCheck
5
5
  class Theme
6
6
  DEFAULT_LOCALE_REGEXP = %r{^locales/(.*)\.default$}
7
- attr_reader :root
7
+ LIQUID_REGEX = /\.liquid$/i
8
+ JSON_REGEX = /\.json$/i
8
9
 
9
- def initialize(root)
10
- @root = Pathname.new(root)
10
+ def initialize(storage)
11
+ @storage = storage
11
12
  end
12
13
 
13
14
  def liquid
14
- @liquid ||= @root.glob("**/*.liquid").map { |path| Template.new(path, @root) }
15
+ @liquid ||= @storage.files
16
+ .select { |path| LIQUID_REGEX.match?(path) }
17
+ .map { |path| Template.new(path, @storage) }
15
18
  end
16
19
 
17
20
  def json
18
- @json ||= @root.glob("**/*.json").map { |path| JsonFile.new(path, @root) }
21
+ @json ||= @storage.files
22
+ .select { |path| JSON_REGEX.match?(path) }
23
+ .map { |path| JsonFile.new(path, @storage) }
24
+ end
25
+
26
+ def directories
27
+ @storage.directories
19
28
  end
20
29
 
21
30
  def default_locale_json
@@ -52,9 +61,5 @@ module ThemeCheck
52
61
  def snippets
53
62
  liquid.select(&:snippet?)
54
63
  end
55
-
56
- def directories
57
- @directories ||= @root.glob('*').select { |f| File.directory?(f) }.map { |f| f.relative_path_from(@root) }
58
- end
59
64
  end
60
65
  end
@@ -1,4 +1,4 @@
1
1
  # frozen_string_literal: true
2
2
  module ThemeCheck
3
- VERSION = "0.1.2"
3
+ VERSION = "0.3.2"
4
4
  end
@@ -6,12 +6,15 @@ module ThemeCheck
6
6
  end
7
7
 
8
8
  def visit_template(template)
9
+ @disabled_checks = DisabledChecks.new
9
10
  visit(Node.new(template.root, nil, template))
10
11
  rescue Liquid::Error => exception
11
12
  exception.template_name = template.name
12
13
  call_checks(:on_error, exception)
13
14
  end
14
15
 
16
+ private
17
+
15
18
  def visit(node)
16
19
  call_checks(:on_node, node)
17
20
  call_checks(:on_tag, node) if node.tag?
@@ -22,16 +25,24 @@ module ThemeCheck
22
25
  call_checks(:after_tag, node) if node.tag?
23
26
  call_checks(:after_node, node)
24
27
  end
25
- end
26
28
 
27
- private
29
+ @disabled_checks.update(node) if node.comment?
30
+ end
28
31
 
29
32
  def visit_children(node)
30
33
  node.children.each { |child| visit(child) }
31
34
  end
32
35
 
33
36
  def call_checks(method, *args)
34
- @checks.call(method, *args)
37
+ checks.call(method, *args)
38
+ end
39
+
40
+ def checks
41
+ return @checks unless @disabled_checks.any?
42
+
43
+ return @checks.always_enabled if @disabled_checks.all_disabled?
44
+
45
+ @checks.except_for(@disabled_checks)
35
46
  end
36
47
  end
37
48
  end
@@ -0,0 +1,98 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'formula'
4
+ require 'fileutils'
5
+
6
+ class ThemeCheck < Formula
7
+ module RubyBin
8
+ def ruby_bin
9
+ Formula["ruby"].opt_bin
10
+ end
11
+ end
12
+
13
+ class RubyGemsDownloadStrategy < AbstractDownloadStrategy
14
+ include RubyBin
15
+
16
+ def fetch
17
+ ohai("Fetching theme-check from gem source")
18
+ cache.cd do
19
+ ENV['GEM_SPEC_CACHE'] = "#{cache}/gem_spec_cache"
20
+ system("#{ruby_bin}/gem", "fetch", "theme-check", "--version", gem_version)
21
+ end
22
+ end
23
+
24
+ def cached_location
25
+ Pathname.new("#{cache}/theme-check-#{gem_version}.gem")
26
+ end
27
+
28
+ def cache
29
+ @cache ||= HOMEBREW_CACHE
30
+ end
31
+
32
+ def gem_version
33
+ return @version if defined?(@version) && @version
34
+ @version = @resource.version if defined?(@resource)
35
+ raise "Unable to determine version; did Homebrew change?" unless @version
36
+ @version
37
+ end
38
+
39
+ def clear_cache
40
+ cached_location.unlink if cached_location.exist?
41
+ end
42
+ end
43
+
44
+ include RubyBin
45
+
46
+ url "theme-check", using: RubyGemsDownloadStrategy
47
+ version "THEME_CHECK_VERSION"
48
+ sha256 'THEME_CHECK_GEM_CHECKSUM'
49
+ depends_on "ruby"
50
+
51
+ def install
52
+ # set GEM_HOME and GEM_PATH to make sure we package all the dependent gems
53
+ # together without accidently picking up other gems on the gem path since
54
+ # they might not be there if, say, we change to a different rvm gemset
55
+ ENV['GEM_HOME'] = prefix.to_s
56
+ ENV['GEM_PATH'] = prefix.to_s
57
+
58
+ # Use /usr/local/bin at the front of the path instead of Homebrew shims,
59
+ # which mess with Ruby's own compiler config when building native extensions
60
+ if defined?(HOMEBREW_SHIMS_PATH)
61
+ ENV['PATH'] = ENV['PATH'].sub(HOMEBREW_SHIMS_PATH.to_s, '/usr/local/bin')
62
+ end
63
+
64
+ system(
65
+ "#{ruby_bin}/gem",
66
+ "install",
67
+ cached_download,
68
+ "--no-document",
69
+ "--no-wrapper",
70
+ "--no-user-install",
71
+ "--install-dir", prefix,
72
+ "--bindir", bin
73
+ )
74
+
75
+ raise "gem install 'theme-check' failed with status #{$CHILD_STATUS.exitstatus}" unless $CHILD_STATUS.success?
76
+
77
+ bin.rmtree if bin.exist?
78
+ bin.mkpath
79
+
80
+ brew_gem_prefix = "#{prefix}/gems/theme-check-#{version}"
81
+
82
+ gemspec = Gem::Specification.load("#{prefix}/specifications/theme-check-#{version}.gemspec")
83
+ ruby_libs = Dir.glob("#{prefix}/gems/*/lib")
84
+ gemspec.executables.each do |exe|
85
+ file = Pathname.new("#{brew_gem_prefix}/#{gemspec.bindir}/#{exe}")
86
+ (bin + file.basename).open('w') do |f|
87
+ f << <<~RUBY
88
+ #!#{ruby_bin}/ruby --disable-gems
89
+ ENV['GEM_HOME']="#{prefix}"
90
+ ENV['GEM_PATH']="#{prefix}"
91
+ require 'rubygems'
92
+ $:.unshift(#{ruby_libs.map(&:inspect).join(',')})
93
+ load "#{file}"
94
+ RUBY
95
+ end
96
+ end
97
+ end
98
+ end
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: theme-check
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.1.2
4
+ version: 0.3.2
5
5
  platform: ruby
6
6
  authors:
7
7
  - Marc-André Cournoyer
8
8
  autorequire:
9
9
  bindir: exe
10
10
  cert_chain: []
11
- date: 2021-01-06 00:00:00.000000000 Z
11
+ date: 2021-02-17 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: liquid
@@ -65,17 +65,21 @@ files:
65
65
  - ".github/workflows/theme-check.yml"
66
66
  - ".gitignore"
67
67
  - ".rubocop.yml"
68
+ - CHANGELOG.md
68
69
  - CODE_OF_CONDUCT.md
69
70
  - CONTRIBUTING.md
70
71
  - Gemfile
71
72
  - Guardfile
72
73
  - LICENSE.md
73
74
  - README.md
75
+ - RELEASING.md
74
76
  - Rakefile
75
77
  - bin/liquid-server
76
78
  - config/default.yml
79
+ - data/shopify_liquid/deprecated_filters.yml
77
80
  - data/shopify_liquid/filters.yml
78
81
  - data/shopify_liquid/objects.yml
82
+ - data/shopify_liquid/plus_objects.yml
79
83
  - dev.yml
80
84
  - docs/preview.png
81
85
  - exe/theme-check
@@ -86,12 +90,15 @@ files:
86
90
  - lib/theme_check/checks.rb
87
91
  - lib/theme_check/checks/convert_include_to_render.rb
88
92
  - lib/theme_check/checks/default_locale.rb
93
+ - lib/theme_check/checks/deprecated_filter.rb
89
94
  - lib/theme_check/checks/liquid_tag.rb
90
95
  - lib/theme_check/checks/matching_schema_translations.rb
91
96
  - lib/theme_check/checks/matching_translations.rb
97
+ - lib/theme_check/checks/missing_enable_comment.rb
92
98
  - lib/theme_check/checks/missing_required_template_files.rb
93
99
  - lib/theme_check/checks/missing_template.rb
94
100
  - lib/theme_check/checks/nested_snippet.rb
101
+ - lib/theme_check/checks/parser_blocking_javascript.rb
95
102
  - lib/theme_check/checks/required_directories.rb
96
103
  - lib/theme_check/checks/required_layout_theme_object.rb
97
104
  - lib/theme_check/checks/space_inside_braces.rb
@@ -108,6 +115,10 @@ files:
108
115
  - lib/theme_check/checks_tracking.rb
109
116
  - lib/theme_check/cli.rb
110
117
  - lib/theme_check/config.rb
118
+ - lib/theme_check/corrector.rb
119
+ - lib/theme_check/disabled_checks.rb
120
+ - lib/theme_check/file_system_storage.rb
121
+ - lib/theme_check/in_memory_storage.rb
111
122
  - lib/theme_check/json_check.rb
112
123
  - lib/theme_check/json_file.rb
113
124
  - lib/theme_check/json_helpers.rb
@@ -118,16 +129,20 @@ files:
118
129
  - lib/theme_check/locale_diff.rb
119
130
  - lib/theme_check/node.rb
120
131
  - lib/theme_check/offense.rb
132
+ - lib/theme_check/packager.rb
121
133
  - lib/theme_check/parsing_helpers.rb
122
134
  - lib/theme_check/printer.rb
123
135
  - lib/theme_check/shopify_liquid.rb
136
+ - lib/theme_check/shopify_liquid/deprecated_filter.rb
124
137
  - lib/theme_check/shopify_liquid/filter.rb
125
138
  - lib/theme_check/shopify_liquid/object.rb
139
+ - lib/theme_check/storage.rb
126
140
  - lib/theme_check/tags.rb
127
141
  - lib/theme_check/template.rb
128
142
  - lib/theme_check/theme.rb
129
143
  - lib/theme_check/version.rb
130
144
  - lib/theme_check/visitor.rb
145
+ - packaging/homebrew/theme_check.base.rb
131
146
  - theme-check.gemspec
132
147
  homepage: https://github.com/Shopify/theme-check
133
148
  licenses: