liquid_lint 1.0.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (61) hide show
  1. checksums.yaml +7 -0
  2. data/LICENSE.md +1 -0
  3. data/bin/liquid-lint +7 -0
  4. data/config/default.yml +99 -0
  5. data/lib/liquid_lint/atom.rb +98 -0
  6. data/lib/liquid_lint/capture_map.rb +19 -0
  7. data/lib/liquid_lint/cli.rb +163 -0
  8. data/lib/liquid_lint/configuration.rb +109 -0
  9. data/lib/liquid_lint/configuration_loader.rb +86 -0
  10. data/lib/liquid_lint/constants.rb +10 -0
  11. data/lib/liquid_lint/document.rb +76 -0
  12. data/lib/liquid_lint/engine.rb +45 -0
  13. data/lib/liquid_lint/exceptions.rb +20 -0
  14. data/lib/liquid_lint/file_finder.rb +88 -0
  15. data/lib/liquid_lint/filters/attribute_processor.rb +31 -0
  16. data/lib/liquid_lint/filters/control_processor.rb +47 -0
  17. data/lib/liquid_lint/filters/inject_line_numbers.rb +43 -0
  18. data/lib/liquid_lint/filters/sexp_converter.rb +17 -0
  19. data/lib/liquid_lint/filters/splat_processor.rb +15 -0
  20. data/lib/liquid_lint/lint.rb +43 -0
  21. data/lib/liquid_lint/linter/comment_control_statement.rb +22 -0
  22. data/lib/liquid_lint/linter/consecutive_control_statements.rb +26 -0
  23. data/lib/liquid_lint/linter/control_statement_spacing.rb +24 -0
  24. data/lib/liquid_lint/linter/embedded_engines.rb +22 -0
  25. data/lib/liquid_lint/linter/empty_control_statement.rb +15 -0
  26. data/lib/liquid_lint/linter/empty_lines.rb +26 -0
  27. data/lib/liquid_lint/linter/file_length.rb +20 -0
  28. data/lib/liquid_lint/linter/line_length.rb +21 -0
  29. data/lib/liquid_lint/linter/redundant_div.rb +22 -0
  30. data/lib/liquid_lint/linter/rubocop.rb +116 -0
  31. data/lib/liquid_lint/linter/tab.rb +19 -0
  32. data/lib/liquid_lint/linter/tag_case.rb +15 -0
  33. data/lib/liquid_lint/linter/trailing_blank_lines.rb +21 -0
  34. data/lib/liquid_lint/linter/trailing_whitespace.rb +19 -0
  35. data/lib/liquid_lint/linter/zwsp.rb +18 -0
  36. data/lib/liquid_lint/linter.rb +93 -0
  37. data/lib/liquid_lint/linter_registry.rb +39 -0
  38. data/lib/liquid_lint/linter_selector.rb +79 -0
  39. data/lib/liquid_lint/logger.rb +103 -0
  40. data/lib/liquid_lint/matcher/anything.rb +11 -0
  41. data/lib/liquid_lint/matcher/base.rb +21 -0
  42. data/lib/liquid_lint/matcher/capture.rb +32 -0
  43. data/lib/liquid_lint/matcher/nothing.rb +13 -0
  44. data/lib/liquid_lint/options.rb +110 -0
  45. data/lib/liquid_lint/rake_task.rb +125 -0
  46. data/lib/liquid_lint/report.rb +25 -0
  47. data/lib/liquid_lint/reporter/checkstyle_reporter.rb +42 -0
  48. data/lib/liquid_lint/reporter/default_reporter.rb +41 -0
  49. data/lib/liquid_lint/reporter/emacs_reporter.rb +44 -0
  50. data/lib/liquid_lint/reporter/json_reporter.rb +52 -0
  51. data/lib/liquid_lint/reporter.rb +44 -0
  52. data/lib/liquid_lint/ruby_extract_engine.rb +36 -0
  53. data/lib/liquid_lint/ruby_extractor.rb +106 -0
  54. data/lib/liquid_lint/ruby_parser.rb +40 -0
  55. data/lib/liquid_lint/runner.rb +82 -0
  56. data/lib/liquid_lint/sexp.rb +106 -0
  57. data/lib/liquid_lint/sexp_visitor.rb +146 -0
  58. data/lib/liquid_lint/utils.rb +85 -0
  59. data/lib/liquid_lint/version.rb +6 -0
  60. data/lib/liquid_lint.rb +52 -0
  61. metadata +185 -0
@@ -0,0 +1,106 @@
1
+ # frozen_string_literal: true
2
+
3
+ module LiquidLint
4
+ # Symbolic expression which represents tree-structured data.
5
+ #
6
+ # The main use of this particular implementation is to provide a single
7
+ # location for defining convenience helpers when operating on Sexps.
8
+ class Sexp < Array
9
+ # Stores the line number of the code in the original document that
10
+ # corresponds to this Sexp.
11
+ attr_accessor :line
12
+
13
+ # Creates an {Sexp} from the given {Array}-based Sexp.
14
+ #
15
+ # This provides a convenient way to convert between literal arrays of
16
+ # {Symbol}s and {Sexp}s containing {Atom}s and nested {Sexp}s. These objects
17
+ # all expose a similar API that conveniently allows the two objects to be
18
+ # treated similarly due to duck typing.
19
+ #
20
+ # @param array_sexp [Array]
21
+ def initialize(array_sexp)
22
+ array_sexp.each do |atom_or_sexp|
23
+ case atom_or_sexp
24
+ when Array
25
+ push Sexp.new(atom_or_sexp)
26
+ else
27
+ push LiquidLint::Atom.new(atom_or_sexp)
28
+ end
29
+ end
30
+ end
31
+
32
+ # Returns whether this {Sexp} matches the given Sexp pattern.
33
+ #
34
+ # A Sexp pattern is simply an incomplete Sexp prefix.
35
+ #
36
+ # @example
37
+ # The following Sexp:
38
+ #
39
+ # [:html, :doctype, "html5"]
40
+ #
41
+ # ...will match the given patterns:
42
+ #
43
+ # [:html]
44
+ # [:html, :doctype]
45
+ # [:html, :doctype, "html5"]
46
+ #
47
+ # Note that nested Sexps will also be matched, so be careful about the cost
48
+ # of matching against a complicated pattern.
49
+ #
50
+ # @param sexp_pattern [Object,Array]
51
+ # @return [Boolean]
52
+ def match?(sexp_pattern)
53
+ # Delegate matching logic if we're comparing against a matcher
54
+ if sexp_pattern.is_a?(LiquidLint::Matcher::Base)
55
+ return sexp_pattern.match?(self)
56
+ end
57
+
58
+ # If there aren't enough items to compare then this obviously won't match
59
+ return false unless sexp_pattern.is_a?(Array) && length >= sexp_pattern.length
60
+
61
+ sexp_pattern.each_with_index do |sub_pattern, index|
62
+ return false unless self[index].match?(sub_pattern)
63
+ end
64
+
65
+ true
66
+ end
67
+
68
+ # Returns pretty-printed representation of this S-expression.
69
+ #
70
+ # @return [String]
71
+ def inspect
72
+ display
73
+ end
74
+
75
+ protected
76
+
77
+ # Pretty-prints this Sexp in a form that is more readable.
78
+ #
79
+ # @param depth [Integer] indentation level to display Sexp at
80
+ # @return [String]
81
+ def display(depth = 1) # rubocop:disable Metrics/AbcSize
82
+ indentation = ' ' * 2 * depth
83
+ output = '['.dup
84
+
85
+ each_with_index do |nested_sexp, index|
86
+ output << "\n"
87
+ output += indentation
88
+
89
+ output +=
90
+ if nested_sexp.is_a?(LiquidLint::Sexp)
91
+ nested_sexp.display(depth + 1)
92
+ else
93
+ nested_sexp.inspect
94
+ end
95
+
96
+ # Add trailing comma unless this is the last item
97
+ output += ',' if index < length - 1
98
+ end
99
+
100
+ output << "\n" << ' ' * 2 * (depth - 1) unless empty?
101
+ output << ']'
102
+
103
+ output
104
+ end
105
+ end
106
+ end
@@ -0,0 +1,146 @@
1
+ # frozen_string_literal: true
2
+
3
+ module LiquidLint
4
+ # Provides an interface which when included allows a class to visit nodes in
5
+ # the Sexp of a Liquid document.
6
+ module SexpVisitor
7
+ # Traverse the Sexp looking for matches with registered patterns, firing
8
+ # callbacks for all matches.
9
+ #
10
+ # @param sexp [LiquidLint::Sexp]
11
+ def trigger_pattern_callbacks(sexp)
12
+ return if on_start(sexp) == :stop
13
+
14
+ traverse sexp
15
+ end
16
+
17
+ # Traverse the given Sexp, firing callbacks if they are defined.
18
+ #
19
+ # @param sexp [LiquidLint::Sexp]
20
+ def traverse(sexp)
21
+ patterns.each do |pattern|
22
+ next unless sexp.match?(pattern.sexp)
23
+
24
+ result = method(pattern.callback_method_name).call(sexp)
25
+
26
+ # Returning :stop indicates we should stop searching this Sexp
27
+ # (i.e. stop descending this branch of depth-first search).
28
+ # The `return` here is very intentional.
29
+ return if result == :stop # rubocop:disable Lint/NonLocalExitFromIterator
30
+ end
31
+
32
+ # Continue traversing children by default (match blocks can return `:stop`
33
+ # to not continue).
34
+ traverse_children(sexp)
35
+ end
36
+
37
+ # Traverse the children of this {Sexp}.
38
+ #
39
+ # @param sexp [LiquidLint::Sexp]
40
+ def traverse_children(sexp)
41
+ sexp.each do |nested_sexp|
42
+ traverse nested_sexp if nested_sexp.is_a?(Sexp)
43
+ end
44
+ end
45
+
46
+ # Returns the map of capture names to captured values.
47
+ #
48
+ # @return [Hash, CaptureMap]
49
+ def captures
50
+ self.class.captures || {}
51
+ end
52
+
53
+ # Returns the list of registered Sexp patterns.
54
+ #
55
+ # @return [Array<LiquidLint::SexpVisitor::SexpPattern>]
56
+ def patterns
57
+ self.class.patterns || []
58
+ end
59
+
60
+ # Executed before searching for any pattern matches.
61
+ #
62
+ # @param sexp [LiquidLint::Sexp] see {SexpVisitor::DSL.on_start}
63
+ # @return [Symbol] see {SexpVisitor::DSL.on_start}
64
+ def on_start(*)
65
+ # Overidden by DSL.on_start
66
+ end
67
+
68
+ # Mapping of Sexp pattern to callback method name.
69
+ #
70
+ # @attr_reader sexp [Array] S-expression pattern that when matched triggers the
71
+ # callback
72
+ # @attr_reader callback_method_name [Symbol] name of the method to call when pattern is matched
73
+ SexpPattern = Struct.new(:sexp, :callback_method_name)
74
+ private_constant :SexpPattern
75
+
76
+ # Exposes a convenient Domain-specific Language (DSL) that makes declaring
77
+ # Sexp match patterns very easy.
78
+ #
79
+ # Include them with `extend LiquidLint::SexpVisitor::DSL`
80
+ module DSL
81
+ # Registered patterns that this visitor will look for when traversing the
82
+ # {LiquidLint::Sexp}.
83
+ attr_reader :patterns
84
+
85
+ # @return [Hash] map of capture names to captured values
86
+ attr_reader :captures
87
+
88
+ # DSL helper that defines a sexp pattern and block that will be executed if
89
+ # the given pattern is found.
90
+ #
91
+ # @param sexp_pattern [Sexp]
92
+ # @yield block to execute when the specified pattern is matched
93
+ # @yieldparam sexp [LiquidLint::Sexp] Sexp that matched the pattern
94
+ # @yieldreturn [LiquidLint::Sexp,Symbol,void]
95
+ # If a Sexp is returned, indicates that traversal should jump directly
96
+ # to that Sexp.
97
+ # If `:stop` is returned, halts further traversal down this branch
98
+ # (i.e. stops recursing, but traversal at higher levels will continue).
99
+ # Otherwise traversal will continue as normal.
100
+ def on(sexp_pattern, &block)
101
+ # TODO: Index Sexps on creation so we can quickly jump to potential
102
+ # matches instead of checking array.
103
+ @patterns ||= []
104
+ @pattern_number ||= 1
105
+
106
+ # Use a monotonically increasing number to identify the method so that in
107
+ # debugging we can simply look at the nth defintion in the class.
108
+ unique_method_name = :"on_pattern_#{@pattern_number}"
109
+ define_method(unique_method_name, block)
110
+
111
+ @pattern_number += 1
112
+ @patterns << SexpPattern.new(sexp_pattern, unique_method_name)
113
+ end
114
+
115
+ # Define a block of code to run before checking for any pattern matches.
116
+ #
117
+ # @yield block to execute
118
+ # @yieldparam sexp [LiquidLint::Sexp] the root Sexp
119
+ # @yieldreturn [Symbol] if `:stop`, indicates that no further processing
120
+ # should occur
121
+ def on_start(&block)
122
+ define_method(:on_start, block)
123
+ end
124
+
125
+ # Represents a pattern that matches anything.
126
+ #
127
+ # @return [LiquidLint::Matcher::Anything]
128
+ def anything
129
+ LiquidLint::Matcher::Anything.new
130
+ end
131
+
132
+ # Represents a pattern that matches the specified matcher, storing the
133
+ # matched value in the captures list under the given name.
134
+ #
135
+ # @param capture_name [Symbol]
136
+ # @param matcher [LiquidLint::Matcher::Base]
137
+ # @return [LiquidLint::Matcher::Capture]
138
+ def capture(capture_name, matcher)
139
+ @captures ||= LiquidLint::CaptureMap.new
140
+
141
+ @captures[capture_name] =
142
+ LiquidLint::Matcher::Capture.from_matcher(matcher)
143
+ end
144
+ end
145
+ end
146
+ end
@@ -0,0 +1,85 @@
1
+ # frozen_string_literal: true
2
+
3
+ module LiquidLint
4
+ # Miscellaneus collection of helper functions.
5
+ module Utils
6
+ module_function
7
+
8
+ # Returns whether a glob pattern (or any of a list of patterns) matches the
9
+ # specified file.
10
+ #
11
+ # This is defined here so our file globbing options are consistent
12
+ # everywhere we perform globbing.
13
+ #
14
+ # @param glob [String, Array]
15
+ # @param file [String]
16
+ # @return [Boolean]
17
+ def any_glob_matches?(globs_or_glob, file)
18
+ path = File.expand_path(file)
19
+ Array(globs_or_glob).any? do |glob|
20
+ ::File.fnmatch?(File.expand_path(glob), path,
21
+ ::File::FNM_PATHNAME | # Wildcards don't match path separators
22
+ ::File::FNM_DOTMATCH) # `*` wildcard matches dotfiles
23
+ end
24
+ end
25
+
26
+ # Find all consecutive items satisfying the given block of a minimum size,
27
+ # yielding each group of consecutive items to the provided block.
28
+ #
29
+ # @param items [Array]
30
+ # @param satisfies [Proc] function that takes an item and returns true/false
31
+ # @param min_consecutive [Fixnum] minimum number of consecutive items before
32
+ # yielding the group
33
+ # @yield Passes list of consecutive items all matching the criteria defined
34
+ # by the `satisfies` {Proc} to the provided block
35
+ # @yieldparam group [Array] List of consecutive items
36
+ # @yieldreturn [Boolean] block should return whether item matches criteria
37
+ # for inclusion
38
+ def for_consecutive_items(items, satisfies, min_consecutive = 2)
39
+ current_index = -1
40
+
41
+ while (current_index += 1) < items.count
42
+ next unless satisfies[items[current_index]]
43
+
44
+ count = count_consecutive(items, current_index, &satisfies)
45
+ next unless count >= min_consecutive
46
+
47
+ # Yield the chunk of consecutive items
48
+ yield items[current_index...(current_index + count)]
49
+
50
+ current_index += count # Skip this patch of consecutive items to find more
51
+ end
52
+ end
53
+
54
+ # Count the number of consecutive items satisfying the given {Proc}.
55
+ #
56
+ # @param items [Array]
57
+ # @param offset [Fixnum] index to start searching from
58
+ # @yield [item] Passes item to the provided block.
59
+ # @yieldparam item [Object] Item to evaluate as matching criteria for
60
+ # inclusion
61
+ # @yieldreturn [Boolean] whether to include the item
62
+ # @return [Integer]
63
+ def count_consecutive(items, offset = 0)
64
+ count = 1
65
+ count += 1 while (offset + count < items.count) && yield(items[offset + count])
66
+ count
67
+ end
68
+
69
+ # Calls a block of code with a modified set of environment variables,
70
+ # restoring them once the code has executed.
71
+ #
72
+ # @param env [Hash] environment variables to set
73
+ def with_environment(env)
74
+ old_env = {}
75
+ env.each do |var, value|
76
+ old_env[var] = ENV[var.to_s]
77
+ ENV[var.to_s] = value
78
+ end
79
+
80
+ yield
81
+ ensure
82
+ old_env.each { |var, value| ENV[var.to_s] = value }
83
+ end
84
+ end
85
+ end
@@ -0,0 +1,6 @@
1
+ # frozen_string_literal: true
2
+
3
+ # Defines the gem version.
4
+ module LiquidLint
5
+ VERSION = '1.0.0'
6
+ end
@@ -0,0 +1,52 @@
1
+ # frozen_string_literal: true
2
+
3
+ # Load all liquid-lint modules necessary to parse and lint a file.
4
+ # Ordering here can be important depending on class references in each module.
5
+
6
+ # Need to load liquid before we can reference some classes or define filters
7
+ require 'liquid'
8
+
9
+ require 'liquid_lint/constants'
10
+ require 'liquid_lint/exceptions'
11
+ require 'liquid_lint/configuration'
12
+ require 'liquid_lint/configuration_loader'
13
+ require 'liquid_lint/utils'
14
+ require 'liquid_lint/atom'
15
+ require 'liquid_lint/sexp'
16
+ require 'liquid_lint/file_finder'
17
+ require 'liquid_lint/linter_registry'
18
+ require 'liquid_lint/logger'
19
+ require 'liquid_lint/version'
20
+
21
+ # Load all filters (required by LiquidLint::Engine)
22
+ Dir[File.expand_path('liquid_lint/filters/*.rb', File.dirname(__FILE__))].sort.each do |file|
23
+ require file
24
+ end
25
+
26
+ require 'liquid_lint/engine'
27
+ require 'liquid_lint/document'
28
+ require 'liquid_lint/capture_map'
29
+ require 'liquid_lint/sexp_visitor'
30
+ require 'liquid_lint/lint'
31
+ require 'liquid_lint/ruby_parser'
32
+ require 'liquid_lint/linter'
33
+ require 'liquid_lint/reporter'
34
+ require 'liquid_lint/report'
35
+ require 'liquid_lint/linter_selector'
36
+ require 'liquid_lint/runner'
37
+
38
+ # Load all matchers
39
+ require 'liquid_lint/matcher/base'
40
+ Dir[File.expand_path('liquid_lint/matcher/*.rb', File.dirname(__FILE__))].sort.each do |file|
41
+ require file
42
+ end
43
+
44
+ # Load all linters
45
+ Dir[File.expand_path('liquid_lint/linter/*.rb', File.dirname(__FILE__))].sort.each do |file|
46
+ require file
47
+ end
48
+
49
+ # Load all reporters
50
+ Dir[File.expand_path('liquid_lint/reporter/*.rb', File.dirname(__FILE__))].sort.each do |file|
51
+ require file
52
+ end
metadata ADDED
@@ -0,0 +1,185 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: liquid_lint
3
+ version: !ruby/object:Gem::Version
4
+ version: 1.0.0
5
+ platform: ruby
6
+ authors:
7
+ - zeusintuivo
8
+ autorequire:
9
+ bindir: bin
10
+ cert_chain: []
11
+ date: 2023-10-30 00:00:00.000000000 Z
12
+ dependencies:
13
+ - !ruby/object:Gem::Dependency
14
+ name: rubocop
15
+ requirement: !ruby/object:Gem::Requirement
16
+ requirements:
17
+ - - ">="
18
+ - !ruby/object:Gem::Version
19
+ version: '1.0'
20
+ - - "<"
21
+ - !ruby/object:Gem::Version
22
+ version: '2.0'
23
+ type: :runtime
24
+ prerelease: false
25
+ version_requirements: !ruby/object:Gem::Requirement
26
+ requirements:
27
+ - - ">="
28
+ - !ruby/object:Gem::Version
29
+ version: '1.0'
30
+ - - "<"
31
+ - !ruby/object:Gem::Version
32
+ version: '2.0'
33
+ - !ruby/object:Gem::Dependency
34
+ name: liquid
35
+ requirement: !ruby/object:Gem::Requirement
36
+ requirements:
37
+ - - ">="
38
+ - !ruby/object:Gem::Version
39
+ version: '3.0'
40
+ - - "<"
41
+ - !ruby/object:Gem::Version
42
+ version: '6.0'
43
+ type: :runtime
44
+ prerelease: false
45
+ version_requirements: !ruby/object:Gem::Requirement
46
+ requirements:
47
+ - - ">="
48
+ - !ruby/object:Gem::Version
49
+ version: '3.0'
50
+ - - "<"
51
+ - !ruby/object:Gem::Version
52
+ version: '6.0'
53
+ - !ruby/object:Gem::Dependency
54
+ name: pry
55
+ requirement: !ruby/object:Gem::Requirement
56
+ requirements:
57
+ - - "~>"
58
+ - !ruby/object:Gem::Version
59
+ version: '0.13'
60
+ type: :development
61
+ prerelease: false
62
+ version_requirements: !ruby/object:Gem::Requirement
63
+ requirements:
64
+ - - "~>"
65
+ - !ruby/object:Gem::Version
66
+ version: '0.13'
67
+ - !ruby/object:Gem::Dependency
68
+ name: rspec
69
+ requirement: !ruby/object:Gem::Requirement
70
+ requirements:
71
+ - - "~>"
72
+ - !ruby/object:Gem::Version
73
+ version: '3.0'
74
+ type: :development
75
+ prerelease: false
76
+ version_requirements: !ruby/object:Gem::Requirement
77
+ requirements:
78
+ - - "~>"
79
+ - !ruby/object:Gem::Version
80
+ version: '3.0'
81
+ - !ruby/object:Gem::Dependency
82
+ name: rspec-its
83
+ requirement: !ruby/object:Gem::Requirement
84
+ requirements:
85
+ - - "~>"
86
+ - !ruby/object:Gem::Version
87
+ version: '1.0'
88
+ type: :development
89
+ prerelease: false
90
+ version_requirements: !ruby/object:Gem::Requirement
91
+ requirements:
92
+ - - "~>"
93
+ - !ruby/object:Gem::Version
94
+ version: '1.0'
95
+ description: Configurable tool for writing clean and consistent Liquid templates
96
+ email:
97
+ - zeus@intuivo.com
98
+ executables:
99
+ - liquid-lint
100
+ extensions: []
101
+ extra_rdoc_files: []
102
+ files:
103
+ - LICENSE.md
104
+ - bin/liquid-lint
105
+ - config/default.yml
106
+ - lib/liquid_lint.rb
107
+ - lib/liquid_lint/atom.rb
108
+ - lib/liquid_lint/capture_map.rb
109
+ - lib/liquid_lint/cli.rb
110
+ - lib/liquid_lint/configuration.rb
111
+ - lib/liquid_lint/configuration_loader.rb
112
+ - lib/liquid_lint/constants.rb
113
+ - lib/liquid_lint/document.rb
114
+ - lib/liquid_lint/engine.rb
115
+ - lib/liquid_lint/exceptions.rb
116
+ - lib/liquid_lint/file_finder.rb
117
+ - lib/liquid_lint/filters/attribute_processor.rb
118
+ - lib/liquid_lint/filters/control_processor.rb
119
+ - lib/liquid_lint/filters/inject_line_numbers.rb
120
+ - lib/liquid_lint/filters/sexp_converter.rb
121
+ - lib/liquid_lint/filters/splat_processor.rb
122
+ - lib/liquid_lint/lint.rb
123
+ - lib/liquid_lint/linter.rb
124
+ - lib/liquid_lint/linter/comment_control_statement.rb
125
+ - lib/liquid_lint/linter/consecutive_control_statements.rb
126
+ - lib/liquid_lint/linter/control_statement_spacing.rb
127
+ - lib/liquid_lint/linter/embedded_engines.rb
128
+ - lib/liquid_lint/linter/empty_control_statement.rb
129
+ - lib/liquid_lint/linter/empty_lines.rb
130
+ - lib/liquid_lint/linter/file_length.rb
131
+ - lib/liquid_lint/linter/line_length.rb
132
+ - lib/liquid_lint/linter/redundant_div.rb
133
+ - lib/liquid_lint/linter/rubocop.rb
134
+ - lib/liquid_lint/linter/tab.rb
135
+ - lib/liquid_lint/linter/tag_case.rb
136
+ - lib/liquid_lint/linter/trailing_blank_lines.rb
137
+ - lib/liquid_lint/linter/trailing_whitespace.rb
138
+ - lib/liquid_lint/linter/zwsp.rb
139
+ - lib/liquid_lint/linter_registry.rb
140
+ - lib/liquid_lint/linter_selector.rb
141
+ - lib/liquid_lint/logger.rb
142
+ - lib/liquid_lint/matcher/anything.rb
143
+ - lib/liquid_lint/matcher/base.rb
144
+ - lib/liquid_lint/matcher/capture.rb
145
+ - lib/liquid_lint/matcher/nothing.rb
146
+ - lib/liquid_lint/options.rb
147
+ - lib/liquid_lint/rake_task.rb
148
+ - lib/liquid_lint/report.rb
149
+ - lib/liquid_lint/reporter.rb
150
+ - lib/liquid_lint/reporter/checkstyle_reporter.rb
151
+ - lib/liquid_lint/reporter/default_reporter.rb
152
+ - lib/liquid_lint/reporter/emacs_reporter.rb
153
+ - lib/liquid_lint/reporter/json_reporter.rb
154
+ - lib/liquid_lint/ruby_extract_engine.rb
155
+ - lib/liquid_lint/ruby_extractor.rb
156
+ - lib/liquid_lint/ruby_parser.rb
157
+ - lib/liquid_lint/runner.rb
158
+ - lib/liquid_lint/sexp.rb
159
+ - lib/liquid_lint/sexp_visitor.rb
160
+ - lib/liquid_lint/utils.rb
161
+ - lib/liquid_lint/version.rb
162
+ homepage: https://github.com/zeusintuivo/liquid-lint
163
+ licenses:
164
+ - MIT
165
+ metadata: {}
166
+ post_install_message:
167
+ rdoc_options: []
168
+ require_paths:
169
+ - lib
170
+ required_ruby_version: !ruby/object:Gem::Requirement
171
+ requirements:
172
+ - - ">="
173
+ - !ruby/object:Gem::Version
174
+ version: 2.4.0
175
+ required_rubygems_version: !ruby/object:Gem::Requirement
176
+ requirements:
177
+ - - ">="
178
+ - !ruby/object:Gem::Version
179
+ version: '0'
180
+ requirements: []
181
+ rubygems_version: 3.4.21
182
+ signing_key:
183
+ specification_version: 4
184
+ summary: Liquid template linting tool
185
+ test_files: []