theme-check 0.7.2 → 0.8.3

Sign up to get free protection for your applications and to get access to all the features.
Files changed (45) hide show
  1. checksums.yaml +4 -4
  2. data/.github/workflows/theme-check.yml +1 -0
  3. data/.rubocop.yml +1 -1
  4. data/CHANGELOG.md +33 -0
  5. data/RELEASING.md +5 -3
  6. data/config/default.yml +1 -1
  7. data/data/shopify_liquid/tags.yml +3 -0
  8. data/data/shopify_translation_keys.yml +1 -0
  9. data/dev.yml +1 -1
  10. data/docs/checks/nested_snippet.md +1 -1
  11. data/docs/checks/space_inside_braces.md +28 -0
  12. data/exe/theme-check +1 -1
  13. data/lib/theme_check.rb +5 -0
  14. data/lib/theme_check/analyzer.rb +19 -9
  15. data/lib/theme_check/bug.rb +20 -0
  16. data/lib/theme_check/check.rb +5 -1
  17. data/lib/theme_check/checks.rb +39 -8
  18. data/lib/theme_check/checks/missing_enable_comment.rb +4 -4
  19. data/lib/theme_check/checks/nested_snippet.rb +1 -1
  20. data/lib/theme_check/checks/space_inside_braces.rb +8 -2
  21. data/lib/theme_check/cli.rb +99 -64
  22. data/lib/theme_check/config.rb +6 -2
  23. data/lib/theme_check/disabled_check.rb +39 -0
  24. data/lib/theme_check/disabled_checks.rb +20 -32
  25. data/lib/theme_check/exceptions.rb +32 -0
  26. data/lib/theme_check/json_file.rb +5 -1
  27. data/lib/theme_check/language_server.rb +1 -1
  28. data/lib/theme_check/language_server/completion_engine.rb +1 -1
  29. data/lib/theme_check/language_server/completion_providers/object_completion_provider.rb +10 -8
  30. data/lib/theme_check/language_server/constants.rb +5 -1
  31. data/lib/theme_check/language_server/document_link_engine.rb +2 -2
  32. data/lib/theme_check/language_server/handler.rb +32 -24
  33. data/lib/theme_check/language_server/variable_lookup_finder.rb +295 -0
  34. data/lib/theme_check/node.rb +12 -0
  35. data/lib/theme_check/offense.rb +14 -48
  36. data/lib/theme_check/parsing_helpers.rb +1 -1
  37. data/lib/theme_check/position.rb +77 -0
  38. data/lib/theme_check/position_helper.rb +37 -0
  39. data/lib/theme_check/remote_asset_file.rb +3 -0
  40. data/lib/theme_check/shopify_liquid/tag.rb +13 -0
  41. data/lib/theme_check/version.rb +1 -1
  42. data/lib/theme_check/visitor.rb +9 -10
  43. data/theme-check.gemspec +2 -0
  44. metadata +10 -5
  45. data/lib/theme_check/language_server/position_helper.rb +0 -27
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: b516a7041c1025cd22bcbb4cab685b45893b38fa41ab55b539efad60cf67e100
4
- data.tar.gz: 86d5d5054247c0c86b4a31b066a579fc60fbcf4f0d32940354c4fc9793667498
3
+ metadata.gz: fc820b814467926919858c11517a275e70dd07aea017285f315dc3309e4b49a3
4
+ data.tar.gz: 949c2934821bb7270aa466c3430d8fb640e8af938fb239aa1a2a346c82580a50
5
5
  SHA512:
6
- metadata.gz: b76463ad9ecab829705519f163745fdd7cb6dea084558983c914dd3ddf923385050da1c535ad73f48a4442dd8a67bc797fd072e293aa85befb15a141870196db
7
- data.tar.gz: 67571132dcf7fd556c81d4eb7f7e15c8db6c7ccee70384bb6654915090d5c8c213dbbee9b9b36acd74f0cac02390630defe7c1de1956f41f61c9d30294cdd4a0
6
+ metadata.gz: 699907617f0401cd5737c7f774b7063fae97f17465a8ac06ad1e404992b969923e4de6ff877c5f85fb951a8af1433ac017ab651465132b69d6143ff77baa5495
7
+ data.tar.gz: 93d69bd9b50561cc0f10940f4b5e7c5b19fcef43d105d0896b4ae484a3df13301cfc51f6470dff4b83b1e3410a3736f54d5097dca9a80763fa7c4790f1761018
@@ -15,6 +15,7 @@ jobs:
15
15
  version:
16
16
  - 3.0.0
17
17
  - 2.7.1
18
+ - 2.6.6
18
19
 
19
20
  name: Ruby ${{ matrix.version }}
20
21
 
data/.rubocop.yml CHANGED
@@ -7,7 +7,7 @@ require:
7
7
  - rubocop-rake
8
8
 
9
9
  AllCops:
10
- TargetRubyVersion: 2.7
10
+ TargetRubyVersion: 2.6
11
11
  Exclude:
12
12
  - 'vendor/bundle/**/*'
13
13
  - 'packaging/builds/**/*'
data/CHANGELOG.md CHANGED
@@ -1,4 +1,37 @@
1
1
 
2
+ v0.8.3 / 2021-05-17
3
+ ==================
4
+
5
+ * Making sure VERSION is set before referencing it
6
+
7
+ v0.8.2 / 2021-05-14
8
+ ===================
9
+
10
+ * Bump NestedSnippet max_nesting_level to 3
11
+ * Add a message to help debug errors, and timeout checks after 5 sec
12
+ * Object Completions Everywhere!
13
+ * Include operators to space inside braces check
14
+
15
+ 0.8.1 / 2021-04-22
16
+ ==================
17
+
18
+ * Add consistent spacing around the pipe character (`|`) in variable expressions to the `SpaceInsideBrace` check ([#73](https://github.com/shopify/theme-check/issues/73))
19
+ * Add ReCaptcha system translation ([#265](https://github.com/shopify/theme-check/issues/265))
20
+ * Fix document links in `{% liquid %}` tags ([#263](https://github.com/shopify/theme-check/issues/263))
21
+ * Fix theme-check-disable for checks based on regular expressions ([#242](https://github.com/shopify/theme-check/issues/242))
22
+ * Fix VS Code crash on new window ([#264](https://github.com/shopify/theme-check/issues/264))
23
+ * Rescue errors thrown by remote_asset_file
24
+
25
+ 0.8.0 / 2021-04-13
26
+ ==================
27
+
28
+ * Set minimal Ruby version to 2.6
29
+
30
+ 0.7.3 / 2021-04-13
31
+ ==================
32
+
33
+ * Refactor CLI option parsing
34
+
2
35
  0.7.2 / 2021-04-12
3
36
  ==================
4
37
 
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/config/default.yml CHANGED
@@ -17,7 +17,7 @@ MissingTemplate:
17
17
 
18
18
  NestedSnippet:
19
19
  enabled: true
20
- max_nesting_level: 2
20
+ max_nesting_level: 3
21
21
 
22
22
  RequiredLayoutThemeObject:
23
23
  enabled: true
@@ -8,6 +8,8 @@
8
8
  - cycle
9
9
  - decrement
10
10
  - echo
11
+ - else
12
+ - elsif
11
13
  - for
12
14
  - form
13
15
  - if
@@ -25,3 +27,4 @@
25
27
  - stylesheet
26
28
  - tablerow
27
29
  - unless
30
+ - when
@@ -848,3 +848,4 @@
848
848
  - shopify.store_availability.pick_up_time.two_to_four_hours
849
849
  - shopify.store_availability.pick_up_time.immediately
850
850
  - shopify.store_availability.pick_up_time.next_day
851
+ - shopify.online_store.spam_detection.disclaimer_html
data/dev.yml CHANGED
@@ -3,7 +3,7 @@ name: theme-check
3
3
  type: ruby
4
4
 
5
5
  up:
6
- - ruby: 2.7.1
6
+ - ruby: 2.6.6
7
7
  - bundler
8
8
 
9
9
  commands:
@@ -45,7 +45,7 @@ The default configuration for this check is the following:
45
45
  ```yaml
46
46
  NestedSnippet:
47
47
  enabled: true
48
- max_nesting_level: 2
48
+ max_nesting_level: 3
49
49
  ```
50
50
 
51
51
  ### `max_nesting_level`
@@ -17,6 +17,14 @@ This check is aimed at eliminating ugly Liquid:
17
17
  <!-- After commas and semicolons -->
18
18
  {% form 'type', object, key:value %}
19
19
  {% endform %}
20
+
21
+ <!-- Arround filter pipelines -->
22
+ {{ url | asset_url | img_tag }}
23
+ {% assign my_upcase_string = "Hello world"| upcase %}
24
+
25
+ <!-- Arround symbol operators -->
26
+ {%- if target == product and product.price_varies -%}
27
+ {%- if product.featured_media.width >=165 -%}
20
28
  ```
21
29
 
22
30
  :+1: Examples of **correct** code for this check:
@@ -33,6 +41,10 @@ This check is aimed at eliminating ugly Liquid:
33
41
  media_size: section.settings.product_recommendations_image_ratio,
34
42
  center_align_text: section.settings.center_align_text
35
43
  %}
44
+ {{ url | asset_url | img_tag }}
45
+ {% assign my_upcase_string = "Hello world" | upcase %}
46
+ {%- if target == product and product.price_varies -%}
47
+ {%- if product.featured_media.width >= 165 -%}
36
48
  ```
37
49
 
38
50
  ## Check Options
@@ -44,6 +56,22 @@ SpaceInsideBraces:
44
56
  enabled: true
45
57
  ```
46
58
 
59
+ ## Auto-correction
60
+
61
+ This check can automatically trim or add spaces around `{{ ... }}`.
62
+
63
+ ```liquid
64
+ {{ x}}
65
+ {{x}}
66
+ {{ x }}
67
+ ```
68
+
69
+ Can all be auto-corrected with the `--auto-correct` option to:
70
+
71
+ ```liquid
72
+ {{ x }}
73
+ ```
74
+
47
75
  ## When Not To Use It
48
76
 
49
77
  If you don't care about the look of your code.
data/exe/theme-check CHANGED
@@ -3,4 +3,4 @@
3
3
 
4
4
  require "theme_check"
5
5
 
6
- ThemeCheck::Cli.new.run!(ARGV)
6
+ ThemeCheck::Cli.parse_and_run(ARGV)
data/lib/theme_check.rb CHANGED
@@ -1,10 +1,13 @@
1
1
  # frozen_string_literal: true
2
2
  require "liquid"
3
3
 
4
+ require_relative "theme_check/bug"
5
+ require_relative "theme_check/exceptions"
4
6
  require_relative "theme_check/analyzer"
5
7
  require_relative "theme_check/check"
6
8
  require_relative "theme_check/checks_tracking"
7
9
  require_relative "theme_check/cli"
10
+ require_relative "theme_check/disabled_check"
8
11
  require_relative "theme_check/disabled_checks"
9
12
  require_relative "theme_check/liquid_check"
10
13
  require_relative "theme_check/locale_diff"
@@ -14,6 +17,8 @@ require_relative "theme_check/regex_helpers"
14
17
  require_relative "theme_check/json_check"
15
18
  require_relative "theme_check/json_file"
16
19
  require_relative "theme_check/json_helpers"
20
+ require_relative "theme_check/position_helper"
21
+ require_relative "theme_check/position"
17
22
  require_relative "theme_check/language_server"
18
23
  require_relative "theme_check/checks"
19
24
  require_relative "theme_check/config"
@@ -1,11 +1,8 @@
1
1
  # frozen_string_literal: true
2
2
  module ThemeCheck
3
3
  class Analyzer
4
- attr_reader :offenses
5
-
6
4
  def initialize(theme, checks = Check.all.map(&:new), auto_correct = false)
7
5
  @theme = theme
8
- @offenses = []
9
6
  @auto_correct = auto_correct
10
7
 
11
8
  @liquid_checks = Checks.new
@@ -13,7 +10,6 @@ module ThemeCheck
13
10
 
14
11
  checks.each do |check|
15
12
  check.theme = @theme
16
- check.offenses = @offenses
17
13
 
18
14
  case check
19
15
  when LiquidCheck
@@ -26,26 +22,40 @@ module ThemeCheck
26
22
  @visitor = Visitor.new(@liquid_checks)
27
23
  end
28
24
 
25
+ def offenses
26
+ @liquid_checks.flat_map(&:offenses) + @json_checks.flat_map(&:offenses)
27
+ end
28
+
29
+ def offenses_clear!
30
+ @liquid_checks.each do |check|
31
+ check.offenses.clear
32
+ end
33
+
34
+ @json_checks.each do |check|
35
+ check.offenses.clear
36
+ end
37
+ end
38
+
29
39
  def analyze_theme
30
- @offenses.clear
40
+ offenses_clear!
31
41
  @theme.liquid.each { |template| @visitor.visit_template(template) }
32
42
  @theme.json.each { |json_file| @json_checks.call(:on_file, json_file) }
33
43
  @liquid_checks.call(:on_end)
34
44
  @json_checks.call(:on_end)
35
- @offenses
45
+ offenses
36
46
  end
37
47
 
38
48
  def uncorrectable_offenses
39
49
  unless @auto_correct
40
- return @offenses
50
+ return offenses
41
51
  end
42
52
 
43
- @offenses.select { |offense| !offense.correctable? }
53
+ offenses.select { |offense| !offense.correctable? }
44
54
  end
45
55
 
46
56
  def correct_offenses
47
57
  if @auto_correct
48
- @offenses.each(&:correct)
58
+ offenses.each(&:correct)
49
59
  @theme.liquid.each(&:write)
50
60
  end
51
61
  end
@@ -0,0 +1,20 @@
1
+ # frozen_string_literal: true
2
+ require 'theme_check/version'
3
+
4
+ module ThemeCheck
5
+ BUG_POSTAMBLE = <<~EOS
6
+ Theme Check Version: #{VERSION}
7
+ Ruby Version: #{RUBY_VERSION}
8
+ Platform: #{RUBY_PLATFORM}
9
+ Muffin mode: activated
10
+
11
+ ------------------------
12
+ Whoops! It looks like you found a bug in Theme Check.
13
+ Please report it at https://github.com/Shopify/theme-check/issues, and include the message above.
14
+ Or cross your fingers real hard, and try again.
15
+ EOS
16
+
17
+ def self.bug(message)
18
+ abort(message + BUG_POSTAMBLE)
19
+ end
20
+ end
@@ -6,8 +6,8 @@ module ThemeCheck
6
6
  include JsonHelpers
7
7
 
8
8
  attr_accessor :theme
9
- attr_accessor :offenses
10
9
  attr_accessor :options
10
+ attr_writer :offenses
11
11
 
12
12
  SEVERITIES = [
13
13
  :error,
@@ -69,6 +69,10 @@ module ThemeCheck
69
69
  end
70
70
  end
71
71
 
72
+ def offenses
73
+ @offenses ||= []
74
+ end
75
+
72
76
  def severity
73
77
  self.class.severity
74
78
  end
@@ -1,22 +1,53 @@
1
1
  # frozen_string_literal: true
2
+ require "pp"
3
+ require "timeout"
4
+
2
5
  module ThemeCheck
3
6
  class Checks < Array
7
+ CHECK_METHOD_TIMEOUT = 5 # sec
8
+
4
9
  def call(method, *args)
5
10
  each do |check|
6
- if check.respond_to?(method) && !check.ignored?
7
- check.send(method, *args)
8
- end
11
+ call_check_method(check, method, *args)
9
12
  end
10
13
  end
11
14
 
12
- def always_enabled
13
- self.class.new(reject(&:can_disable?))
15
+ def disableable
16
+ self.class.new(select(&:can_disable?))
14
17
  end
15
18
 
16
- def except_for(disabled_checks)
17
- still_enabled = reject { |check| disabled_checks.all.include?(check.code_name) }
19
+ private
20
+
21
+ def call_check_method(check, method, *args)
22
+ return unless check.respond_to?(method) && !check.ignored?
23
+
24
+ Timeout.timeout(CHECK_METHOD_TIMEOUT) do
25
+ check.send(method, *args)
26
+ end
27
+ rescue Liquid::Error
28
+ # Pass-through Liquid errors
29
+ raise
30
+ rescue => e
31
+ node = args.first
32
+ template = node.respond_to?(:template) ? node.template.relative_path : "?"
33
+ markup = node.respond_to?(:markup) ? node.markup : ""
34
+ node_class = node.respond_to?(:value) ? node.value.class : "?"
35
+
36
+ ThemeCheck.bug(<<~EOS)
37
+ Exception while running `#{check.code_name}##{method}`:
38
+ ```
39
+ #{e.class}: #{e.message}
40
+ #{e.backtrace.join("\n ")}
41
+ ```
18
42
 
19
- self.class.new((always_enabled + still_enabled).uniq)
43
+ Template: `#{template}`
44
+ Node: `#{node_class}`
45
+ Markup:
46
+ ```
47
+ #{markup}
48
+ ```
49
+ Check options: `#{check.options.pretty_inspect}`
50
+ EOS
20
51
  end
21
52
  end
22
53
  end
@@ -17,13 +17,13 @@ module ThemeCheck
17
17
  end
18
18
 
19
19
  def after_document(node)
20
- return if @disabled_checks.full_document_disabled?
21
- return unless @disabled_checks.any?
20
+ checks_missing_end_index = @disabled_checks.checks_missing_end_index
21
+ return if checks_missing_end_index.empty?
22
22
 
23
- message = if @disabled_checks.all_disabled?
23
+ message = if checks_missing_end_index.any? { |name| name == :all }
24
24
  "All checks were"
25
25
  else
26
- @disabled_checks.all.join(', ') + " " + (@disabled_checks.all.size == 1 ? "was" : "were")
26
+ checks_missing_end_index.join(', ') + " " + (checks_missing_end_index.size == 1 ? "was" : "were")
27
27
  end
28
28
 
29
29
  add_offense("#{message} disabled but not re-enabled with theme-check-enable", node: node)
@@ -20,7 +20,7 @@ module ThemeCheck
20
20
  end
21
21
  end
22
22
 
23
- def initialize(max_nesting_level: 2)
23
+ def initialize(max_nesting_level: 3)
24
24
  @max_nesting_level = max_nesting_level
25
25
  @templates = {}
26
26
  end
@@ -15,12 +15,18 @@ module ThemeCheck
15
15
  return if :assign == node.type_name
16
16
 
17
17
  outside_of_strings(node.markup) do |chunk|
18
- chunk.scan(/([,:]) +/) do |_match|
18
+ chunk.scan(/([,:|]|==|<>|<=|>=|<|>|!=) +/) do |_match|
19
19
  add_offense("Too many spaces after '#{Regexp.last_match(1)}'", node: node, markup: Regexp.last_match(0))
20
20
  end
21
- chunk.scan(/([,:])\S/) do |_match|
21
+ chunk.scan(/([,:|]|==|<>|<=|>=|<\b|>\b|!=)(\S|\z)/) do |_match|
22
22
  add_offense("Space missing after '#{Regexp.last_match(1)}'", node: node, markup: Regexp.last_match(0))
23
23
  end
24
+ chunk.scan(/ (\||==|<>|<=|>=|<|>|!=)+/) do |_match|
25
+ add_offense("Too many spaces before '#{Regexp.last_match(1)}'", node: node, markup: Regexp.last_match(0))
26
+ end
27
+ chunk.scan(/(\A|\S)(?<match>\||==|<>|<=|>=|<|\b>|!=)/) do |_match|
28
+ add_offense("Space missing before '#{Regexp.last_match(1)}'", node: node, markup: Regexp.last_match(0))
29
+ end
24
30
  end
25
31
  end
26
32
 
@@ -1,85 +1,104 @@
1
1
  # frozen_string_literal: true
2
+ require "optparse"
3
+
2
4
  module ThemeCheck
3
5
  class Cli
4
6
  class Abort < StandardError; end
5
7
 
6
- USAGE = <<~END
7
- Usage: theme-check [options] /path/to/your/theme
8
-
9
- Basic Options:
10
- -C, --config <path> Use the config provided, overriding .theme-check.yml if present
11
- -c, --category <category> Only run this category of checks
12
- -x, --exclude-category <category> Exclude this category of checks
13
- -a, --auto-correct Automatically fix offenses
14
-
15
- Miscellaneous:
16
- --init Generate a .theme-check.yml file
17
- --print-config Output active config to STDOUT
18
- -h, --help Show this. Hi!
19
- -l, --list List enabled checks
20
- -v, --version Print Theme Check version
21
-
22
- Description:
23
- Theme Check helps you follow Shopify Themes & Liquid best practices by analyzing the
24
- Liquid & JSON inside your theme.
25
-
26
- You can configure checks in the .theme-check.yml file of your theme root directory.
27
- END
8
+ attr_accessor :path
28
9
 
29
- def run(argv)
10
+ def initialize
30
11
  @path = "."
12
+ @command = :check
13
+ @only_categories = []
14
+ @exclude_categories = []
15
+ @auto_correct = false
16
+ @config_path = nil
17
+ end
31
18
 
32
- command = :check
33
- only_categories = []
34
- exclude_categories = []
35
- auto_correct = false
36
- config_path = nil
37
-
38
- args = argv.dup
39
- while (arg = args.shift)
40
- case arg
41
- when "--help", "-h"
42
- raise Abort, USAGE
43
- when "--version", "-v"
44
- command = :version
45
- when "--config", "-C"
46
- config_path = Pathname.new(args.shift)
47
- when "--category", "-c"
48
- only_categories << args.shift.to_sym
49
- when "--exclude-category", "-x"
50
- exclude_categories << args.shift.to_sym
51
- when "--list", "-l"
52
- command = :list
53
- when "--auto-correct", "-a"
54
- auto_correct = true
55
- when "--init"
56
- command = :init
57
- when "--print"
58
- command = :print
59
- else
60
- @path = arg
61
- end
62
- end
19
+ def option_parser(parser = OptionParser.new, help: true)
20
+ return @option_parser if defined?(@option_parser)
21
+ @option_parser = parser
22
+ @option_parser.banner = "Usage: theme-check [options] [/path/to/your/theme]"
23
+
24
+ @option_parser.separator("")
25
+ @option_parser.separator("Basic Options:")
26
+ @option_parser.on(
27
+ "-C", "--config PATH",
28
+ "Use the config provided, overriding .theme-check.yml if present"
29
+ ) { |path| @config_path = path }
30
+ @option_parser.on(
31
+ "-c", "--category CATEGORY",
32
+ "Only run this category of checks"
33
+ ) { |category| @only_categories << category.to_sym }
34
+ @option_parser.on(
35
+ "-x", "--exclude-category CATEGORY",
36
+ "Exclude this category of checks"
37
+ ) { |category| @exclude_categories << category.to_sym }
38
+ @option_parser.on(
39
+ "-a", "--auto-correct",
40
+ "Automatically fix offenses"
41
+ ) { @auto_correct = true }
42
+
43
+ @option_parser.separator("")
44
+ @option_parser.separator("Miscellaneous:")
45
+ @option_parser.on(
46
+ "--init",
47
+ "Generate a .theme-check.yml file"
48
+ ) { @command = :init }
49
+ @option_parser.on(
50
+ "--print",
51
+ "Output active config to STDOUT"
52
+ ) { @command = :print }
53
+ @option_parser.on(
54
+ "-h", "--help",
55
+ "Show this. Hi!"
56
+ ) { @command = :help } if help
57
+ @option_parser.on(
58
+ "-l", "--list",
59
+ "List enabled checks"
60
+ ) { @command = :list }
61
+ @option_parser.on(
62
+ "-v", "--version",
63
+ "Print Theme Check version"
64
+ ) { @command = :version }
65
+
66
+ @option_parser.separator("")
67
+ @option_parser.separator(<<~EOS)
68
+ Description:
69
+ Theme Check helps you follow Shopify Themes & Liquid best practices by analyzing the
70
+ Liquid & JSON inside your theme.
71
+
72
+ You can configure checks in the .theme-check.yml file of your theme root directory.
73
+ EOS
74
+
75
+ @option_parser
76
+ end
77
+
78
+ def parse(argv)
79
+ @path = option_parser.parse(argv).first || "."
80
+ end
63
81
 
64
- unless [:version, :init].include?(command)
65
- @config = if config_path
82
+ def run!
83
+ unless [:version, :init, :help].include?(@command)
84
+ @config = if @config_path
66
85
  ThemeCheck::Config.new(
67
86
  root: @path,
68
- configuration: ThemeCheck::Config.load_file(config_path)
87
+ configuration: ThemeCheck::Config.load_file(@config_path)
69
88
  )
70
89
  else
71
90
  ThemeCheck::Config.from_path(@path)
72
91
  end
73
- @config.only_categories = only_categories
74
- @config.exclude_categories = exclude_categories
75
- @config.auto_correct = auto_correct
92
+ @config.only_categories = @only_categories
93
+ @config.exclude_categories = @exclude_categories
94
+ @config.auto_correct = @auto_correct
76
95
  end
77
96
 
78
- send(command)
97
+ send(@command)
79
98
  end
80
99
 
81
- def run!(argv)
82
- run(argv)
100
+ def run
101
+ run!
83
102
  rescue Abort => e
84
103
  if e.message.empty?
85
104
  exit(1)
@@ -88,6 +107,18 @@ module ThemeCheck
88
107
  end
89
108
  end
90
109
 
110
+ def self.parse_and_run!(argv)
111
+ cli = new
112
+ cli.parse(argv)
113
+ cli.run!
114
+ end
115
+
116
+ def self.parse_and_run(argv)
117
+ cli = new
118
+ cli.parse(argv)
119
+ cli.run
120
+ end
121
+
91
122
  def list
92
123
  puts @config.enabled_checks
93
124
  end
@@ -111,12 +142,16 @@ module ThemeCheck
111
142
  puts YAML.dump(@config.to_h)
112
143
  end
113
144
 
145
+ def help
146
+ puts option_parser.to_s
147
+ end
148
+
114
149
  def check
115
150
  puts "Checking #{@config.root} ..."
116
151
  storage = ThemeCheck::FileSystemStorage.new(@config.root, ignored_patterns: @config.ignored_patterns)
117
152
  theme = ThemeCheck::Theme.new(storage)
118
153
  if theme.all.empty?
119
- raise Abort, "No templates found.\n#{USAGE}"
154
+ raise Abort, "No templates found."
120
155
  end
121
156
  analyzer = ThemeCheck::Analyzer.new(theme, @config.enabled_checks, @config.auto_correct)
122
157
  analyzer.analyze_theme