haml_lint 0.52.0 → 0.54.0

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.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 24f37fc2b314359fb58b5209e58399fa01f53d51c977a4c60b66d9497e2acde5
4
- data.tar.gz: afb033a6021882a269ec1fdf989d06c83c6df8047a3f60233ac83ac9f234469d
3
+ metadata.gz: b017823b15563d033480ee99317c4d0c007624b10ad2ed3b53c254c5686289c8
4
+ data.tar.gz: cf83ac415fb7749551466fcc0b23a5a2019bbecb99a67b2c54051a78523f1a33
5
5
  SHA512:
6
- metadata.gz: abb4758509d1aca40826e598c8d1bdfb7daffbbbeb9d1955c18463e44c4799ce5102151ae34b58799198336d87ba2c4e922a699b8f9c28b13f94479d80f4607a
7
- data.tar.gz: f585fb701da7d6ca46ab9612055a25be83c640c97da530fa19ca20684e27056955ca80714a666fef1568fb8fa4bceba5830005167b3f4a76dc575732876d125e
6
+ metadata.gz: 17ea23cce399f12712d0f73560553b82068e2ac3be9124c590bbea78948a330811402c15fd2b5f8cbc0b5e8e044bc044e69df78f2e05462580665db814298595
7
+ data.tar.gz: d619d3018e139b00ce539da9b9f7e1bfef644c71c8e102d146778c3c322770458a16feb89bb44a1a3699eadacc6038c7186407fc8361e6b354f0c4bdbb2dcd57
@@ -1,6 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
- require 'haml_lint/adapter/haml_4'
4
3
  require 'haml_lint/adapter/haml_5'
5
4
  require 'haml_lint/adapter/haml_6'
6
5
  require 'haml_lint/exceptions'
@@ -19,7 +18,6 @@ module HamlLint
19
18
  def self.detect_class
20
19
  version = haml_version
21
20
  case version
22
- when '~> 4.0' then HamlLint::Adapter::Haml4
23
21
  when '~> 5.0', '~> 5.1', '~> 5.2' then HamlLint::Adapter::Haml5
24
22
  when '~> 6.0', '~> 6.0.a', '~> 6.1', '~> 6.2', '~> 6.3' then HamlLint::Adapter::Haml6
25
23
  else fail HamlLint::Exceptions::UnknownHamlVersion, "Cannot handle Haml version: #{version}"
@@ -6,5 +6,5 @@ module HamlLint
6
6
  APP_NAME = 'haml-lint'
7
7
 
8
8
  REPO_URL = 'https://github.com/sds/haml-lint'
9
- BUG_REPORT_URL = "#{REPO_URL}/issues"
9
+ BUG_REPORT_URL = "#{REPO_URL}/issues".freeze
10
10
  end
@@ -3,7 +3,7 @@
3
3
  module HamlLint
4
4
  # Handles linter configuration transformation via Haml comments.
5
5
  class Directive
6
- LINTER_REGEXP = /(?:[A-Z]\w+)/.freeze
6
+ LINTER_REGEXP = /(?:[A-Z]\w+)/
7
7
 
8
8
  DIRECTIVE_REGEXP = /
9
9
  # "haml-lint:" with optional spacing
@@ -14,7 +14,7 @@ module HamlLint
14
14
 
15
15
  # "all" or a comma-separated list (with optional spaces) of linters
16
16
  (?<linters>all | (?:#{LINTER_REGEXP}\s*,\s*)* #{LINTER_REGEXP})
17
- /x.freeze
17
+ /x
18
18
 
19
19
  # Constructs a directive from source code as a given line.
20
20
  #
@@ -14,6 +14,9 @@ module HamlLint
14
14
  # @return [String] Haml template file path
15
15
  attr_reader :file
16
16
 
17
+ # @return [Boolean] true if source changes (from autocorrect) should be written to stdout instead of disk
18
+ attr_reader :write_to_stdout
19
+
17
20
  # @return [HamlLint::Tree::Node] Root of the parse tree
18
21
  attr_reader :tree
19
22
 
@@ -36,10 +39,12 @@ module HamlLint
36
39
  # @param source [String] Haml code to parse
37
40
  # @param options [Hash]
38
41
  # @option options :file [String] file name of document that was parsed
42
+ # @option options :write_to_stdout [Boolean] true if source changes should be written to stdout
39
43
  # @raise [Haml::Parser::Error] if there was a problem parsing the document
40
44
  def initialize(source, options)
41
45
  @config = options[:config]
42
46
  @file = options.fetch(:file, STRING_SOURCE)
47
+ @write_to_stdout = options[:write_to_stdout]
43
48
  @source_was_changed = false
44
49
  process_source(source)
45
50
  end
@@ -82,7 +87,11 @@ module HamlLint
82
87
  if file == STRING_SOURCE
83
88
  raise HamlLint::Exceptions::InvalidFilePath, 'Cannot write without :file option'
84
89
  end
85
- File.write(file, unstrip_frontmatter(source))
90
+ if @write_to_stdout
91
+ $stdout << unstrip_frontmatter(source)
92
+ else
93
+ File.write(file, unstrip_frontmatter(source))
94
+ end
86
95
  @source_was_changed = false
87
96
  end
88
97
 
@@ -3,7 +3,7 @@
3
3
  module HamlLint
4
4
  # Checks for tabs that are placed for alignment of tag content
5
5
  class Linter::AlignmentTabs < Linter
6
- REGEX = /[^\s*]\t+/.freeze
6
+ REGEX = /[^\s*]\t+/
7
7
 
8
8
  def visit_tag(node)
9
9
  if REGEX.match?(node.source_code)
@@ -20,7 +20,7 @@ module HamlLint
20
20
 
21
21
  STATIC_TYPES = %i[str sym].freeze
22
22
 
23
- VALID_CLASS_REGEX = /^-?[_a-zA-Z]+[_a-zA-Z0-9-]*$/.freeze
23
+ VALID_CLASS_REGEX = /^-?[_a-zA-Z]+[_a-zA-Z0-9-]*$/
24
24
 
25
25
  def visit_tag(node)
26
26
  return unless contains_class_attribute?(node.dynamic_attributes_sources)
@@ -11,7 +11,7 @@ module HamlLint
11
11
  tab: /^\t*(?! )/,
12
12
  }.freeze
13
13
 
14
- LEADING_SPACES_REGEX = /^( +)(?! )/.freeze
14
+ LEADING_SPACES_REGEX = /^( +)(?! )/
15
15
 
16
16
  def visit_root(root)
17
17
  character = config['character'].to_sym
@@ -31,7 +31,7 @@ module HamlLint
31
31
 
32
32
  private
33
33
 
34
- MULTILINE_PIPE_REGEX = /\s+\|\s*$/.freeze
34
+ MULTILINE_PIPE_REGEX = /\s+\|\s*$/
35
35
 
36
36
  def line_text_for_node(node)
37
37
  document.source_lines[node.line - 1]
@@ -6,8 +6,8 @@ module HamlLint
6
6
  include LinterRegistry
7
7
 
8
8
  MSG = 'Placeholders attributes should not be used.'
9
- HASH_REGEXP = /:?['"]?placeholder['"]?(?::| *=>)/.freeze
10
- HTML_REGEXP = /placeholder=/.freeze
9
+ HASH_REGEXP = /:?['"]?placeholder['"]?(?::| *=>)/
10
+ HTML_REGEXP = /placeholder=/
11
11
 
12
12
  def visit_tag(node)
13
13
  return unless node.hash_attributes_source =~ HASH_REGEXP || node.html_attributes_source =~ HTML_REGEXP
@@ -32,7 +32,7 @@ module HamlLint
32
32
 
33
33
  private
34
34
 
35
- def add_linter_options(parser) # rubocop:disable Metrics/MethodLength
35
+ def add_linter_options(parser) # rubocop:disable Metrics/AbcSize, Metrics/MethodLength
36
36
  parser.on('--auto-gen-config', 'Generate a configuration file acting as a TODO list') do
37
37
  @options[:auto_gen_config] = true
38
38
  end
@@ -70,7 +70,13 @@ module HamlLint
70
70
  @options[:autocorrect] ||= :safe
71
71
  end
72
72
 
73
- parser.on('--stderr', 'Write all output to stderr') do
73
+ parser.on('-s', '--stdin FILE', 'Pipe source from STDIN, using FILE in ' \
74
+ 'offense when combined with --auto-correct and --stdin.') do |file_path|
75
+ @options[:stdin] = file_path
76
+ end
77
+
78
+ parser.on('--stderr', 'Write all output to stderr except for the autocorrected source. ' \
79
+ 'This is especially useful when combined with --auto-correct and --stdin') do
74
80
  @options[:stderr] = true
75
81
  end
76
82
  end
@@ -84,7 +84,35 @@ module HamlLint::RubyExtraction
84
84
  def visit_comment(node)
85
85
  line = @original_haml_lines[node.line - 1]
86
86
  indent = line.index(/\S/)
87
+
87
88
  @ruby_chunks << PlaceholderMarkerChunk.new(node, 'comment', indent: indent)
89
+
90
+ # Comment can have subnodes, such as plain. This happens for conditional comments, such as:
91
+ # %head
92
+ # /[if mso]
93
+ # %div
94
+ if node.children
95
+ # We don't want to use a block because assignments in a block are local to that block,
96
+ # so the semantics of the extracted ruby would be different from the one generated by
97
+ # Haml. Those differences can make some cops, such as UselessAssignment, have false
98
+ # positives
99
+ begin_chunk = AdHocChunk.new(node, [' ' * indent + 'begin'])
100
+ @ruby_chunks << begin_chunk
101
+ indent += 2
102
+
103
+ yield
104
+
105
+ indent -= 2
106
+
107
+ if @ruby_chunks.last.equal?(begin_chunk)
108
+ # So there is nothing nesting, remove the wrapping "begin"
109
+ @ruby_chunks.pop
110
+ else
111
+ @ruby_chunks << AdHocChunk.new(node,
112
+ [' ' * indent + 'ensure', ' ' * indent + ' HL.noop', ' ' * indent + 'end'],
113
+ haml_line_index: @ruby_chunks.last.haml_end_line_index)
114
+ end
115
+ end
88
116
  end
89
117
 
90
118
  # Visit a script which outputs. Lines looking like ` = foo`
@@ -1,6 +1,7 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  require 'parallel'
4
+ require_relative 'source'
4
5
 
5
6
  module HamlLint
6
7
  # Responsible for running the applicable linters against the desired files.
@@ -20,12 +21,13 @@ module HamlLint
20
21
  # @return [HamlLint::Report] a summary of all lints found
21
22
  def run(options = {})
22
23
  @config = load_applicable_config(options)
23
- @files = extract_applicable_files(config, options)
24
+ @sources = extract_applicable_sources(config, options)
24
25
  @linter_selector = HamlLint::LinterSelector.new(config, options)
25
26
  @fail_fast = options.fetch(:fail_fast, false)
26
27
  @cache = {}
27
28
  @autocorrect = options[:autocorrect]
28
29
  @autocorrect_only = options[:autocorrect_only]
30
+ @autocorrect_stdout = options[:stdin] && options[:stderr]
29
31
 
30
32
  report(options)
31
33
  end
@@ -48,10 +50,10 @@ module HamlLint
48
50
  # @return [true, false]
49
51
  alias fail_fast? fail_fast
50
52
 
51
- # The list of files to lint during this run.
53
+ # The list of sources to lint during this run.
52
54
  #
53
- # @return [Array<String>]
54
- attr_reader :files
55
+ # @return [Array<HamlLint::Source>]
56
+ attr_reader :sources
55
57
 
56
58
  # The selector for which linters to run during this run.
57
59
  #
@@ -79,18 +81,20 @@ module HamlLint
79
81
  # Runs all provided linters using the specified config against the given
80
82
  # file.
81
83
  #
82
- # @param file [String] path to file to lint
84
+ # @param source [HamlLint::Source] source to lint
83
85
  # @param linter_selector [HamlLint::LinterSelector]
84
86
  # @param config [HamlLint::Configuration]
85
- def collect_lints(file, linter_selector, config)
87
+ def collect_lints(source, linter_selector, config)
86
88
  begin
87
- document = HamlLint::Document.new(File.read(file), file: file, config: config)
89
+ document = HamlLint::Document.new source.contents, file: source.path,
90
+ config: config,
91
+ write_to_stdout: @autocorrect_stdout
88
92
  rescue HamlLint::Exceptions::ParseError => e
89
- return [HamlLint::Lint.new(HamlLint::Linter::Syntax.new(config), file,
93
+ return [HamlLint::Lint.new(HamlLint::Linter::Syntax.new(config), source.path,
90
94
  e.line, e.to_s, :error)]
91
95
  end
92
96
 
93
- linters = linter_selector.linters_for_file(file)
97
+ linters = linter_selector.linters_for_file(source.path)
94
98
  lint_arrays = []
95
99
 
96
100
  if @autocorrect
@@ -125,40 +129,46 @@ module HamlLint
125
129
  lint_arrays
126
130
  end
127
131
 
128
- # Returns the list of files that should be linted given the specified
132
+ # Returns the list of sources that should be linted given the specified
129
133
  # configuration and options.
130
134
  #
131
135
  # @param config [HamlLint::Configuration]
132
136
  # @param options [Hash]
133
- # @return [Array<String>]
134
- def extract_applicable_files(config, options)
135
- included_patterns = options[:files]
136
- excluded_patterns = config['exclude']
137
- excluded_patterns += options.fetch(:excluded_files, [])
137
+ # @return [Array<HamlLint::Source>]
138
+ def extract_applicable_sources(config, options)
139
+ if options[:stdin]
140
+ [HamlLint::Source.new($stdin, options[:stdin])]
141
+ else
142
+ included_patterns = options[:files]
143
+ excluded_patterns = config['exclude']
144
+ excluded_patterns += options.fetch(:excluded_files, [])
138
145
 
139
- HamlLint::FileFinder.new(config).find(included_patterns, excluded_patterns)
146
+ HamlLint::FileFinder.new(config).find(included_patterns, excluded_patterns).map do |file_path|
147
+ HamlLint::Source.new File.new(file_path), file_path
148
+ end
149
+ end
140
150
  end
141
151
 
142
- # Process the files and add them to the given report.
152
+ # Process the sources and add them to the given report.
143
153
  #
144
154
  # @param report [HamlLint::Report]
145
155
  # @return [void]
146
- def process_files(report)
147
- files.each do |file|
148
- process_file(file, report)
156
+ def process_sources(report)
157
+ sources.each do |source|
158
+ process_source(source, report)
149
159
  break if report.failed? && fail_fast?
150
160
  end
151
161
  end
152
162
 
153
163
  # Process a file and add it to the given report.
154
164
  #
155
- # @param file [String] the name of the file to process
165
+ # @param source [HamlLint::Source] the source to process
156
166
  # @param report [HamlLint::Report]
157
167
  # @return [void]
158
- def process_file(file, report)
159
- lints = @cache[file] || collect_lints(file, linter_selector, config)
168
+ def process_source(source, report)
169
+ lints = @cache[source.path] || collect_lints(source, linter_selector, config)
160
170
  lints.each { |lint| report.add_lint(lint) }
161
- report.finish_file(file, lints)
171
+ report.finish_file(source.path, lints)
162
172
  end
163
173
 
164
174
  # Generates a report based on the given options.
@@ -168,9 +178,9 @@ module HamlLint
168
178
  # @return [HamlLint::Report]
169
179
  def report(options)
170
180
  report = HamlLint::Report.new(reporter: options[:reporter], fail_level: options[:fail_level])
171
- report.start(@files)
181
+ report.start(sources.map(&:path))
172
182
  warm_cache if options[:parallel]
173
- process_files(report)
183
+ process_sources(report)
174
184
  report
175
185
  end
176
186
 
@@ -178,9 +188,9 @@ module HamlLint
178
188
  #
179
189
  # @return [void]
180
190
  def warm_cache
181
- results = Parallel.map(files) do |file|
182
- lints = collect_lints(file, linter_selector, config)
183
- [file, lints]
191
+ results = Parallel.map(sources) do |source|
192
+ lints = collect_lints(source, linter_selector, config)
193
+ [source.path, lints]
184
194
  end
185
195
  @cache = results.to_h
186
196
  end
@@ -0,0 +1,24 @@
1
+ # frozen_string_literal: true
2
+
3
+ module HamlLint
4
+ # Wrapper class representing a single target for HamlLint::Runner to run against, comprised of an IO object
5
+ # containing haml code, as well as a file path.
6
+ class Source
7
+ # @return [String] File path associated with the given IO object.
8
+ attr_reader :path
9
+
10
+ # Wraps an IO object and file path to a source object.
11
+ #
12
+ # @param [IO] io
13
+ # @param [String] path
14
+ def initialize(io, path)
15
+ @io = io
16
+ @path = path
17
+ end
18
+
19
+ # @return [String] Contents of the given IO object.
20
+ def contents
21
+ @contents ||= @io.read
22
+ end
23
+ end
24
+ end
@@ -2,5 +2,5 @@
2
2
 
3
3
  # Defines the gem version.
4
4
  module HamlLint
5
- VERSION = '0.52.0'
5
+ VERSION = '0.54.0'
6
6
  end
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: haml_lint
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.52.0
4
+ version: 0.54.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Shane da Silva
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2023-12-13 00:00:00.000000000 Z
11
+ date: 2024-01-23 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: haml
@@ -16,14 +16,14 @@ dependencies:
16
16
  requirements:
17
17
  - - ">="
18
18
  - !ruby/object:Gem::Version
19
- version: '4.0'
19
+ version: '5.0'
20
20
  type: :runtime
21
21
  prerelease: false
22
22
  version_requirements: !ruby/object:Gem::Requirement
23
23
  requirements:
24
24
  - - ">="
25
25
  - !ruby/object:Gem::Version
26
- version: '4.0'
26
+ version: '5.0'
27
27
  - !ruby/object:Gem::Dependency
28
28
  name: parallel
29
29
  requirement: !ruby/object:Gem::Requirement
@@ -93,7 +93,6 @@ files:
93
93
  - config/forced_rubocop_config.yml
94
94
  - lib/haml_lint.rb
95
95
  - lib/haml_lint/adapter.rb
96
- - lib/haml_lint/adapter/haml_4.rb
97
96
  - lib/haml_lint/adapter/haml_5.rb
98
97
  - lib/haml_lint/adapter/haml_6.rb
99
98
  - lib/haml_lint/cli.rb
@@ -177,6 +176,7 @@ files:
177
176
  - lib/haml_lint/ruby_parser.rb
178
177
  - lib/haml_lint/runner.rb
179
178
  - lib/haml_lint/severity.rb
179
+ - lib/haml_lint/source.rb
180
180
  - lib/haml_lint/spec.rb
181
181
  - lib/haml_lint/spec/matchers/report_lint.rb
182
182
  - lib/haml_lint/spec/normalize_indent.rb
@@ -208,14 +208,14 @@ required_ruby_version: !ruby/object:Gem::Requirement
208
208
  requirements:
209
209
  - - ">="
210
210
  - !ruby/object:Gem::Version
211
- version: 2.7.0
211
+ version: '3.0'
212
212
  required_rubygems_version: !ruby/object:Gem::Requirement
213
213
  requirements:
214
214
  - - ">="
215
215
  - !ruby/object:Gem::Version
216
216
  version: '0'
217
217
  requirements: []
218
- rubygems_version: 3.1.6
218
+ rubygems_version: 3.4.10
219
219
  signing_key:
220
220
  specification_version: 4
221
221
  summary: HAML lint tool
@@ -1,62 +0,0 @@
1
- # frozen_string_literal: true
2
-
3
- require 'forwardable'
4
-
5
- module HamlLint
6
- class Adapter
7
- # Adapts the Haml::Parser from Haml 4 for use in HamlLint
8
- # :reek:UncommunicativeModuleName
9
- class Haml4 < Adapter
10
- extend Forwardable
11
-
12
- # Parses the specified Haml code into an abstract syntax tree
13
- #
14
- # @example
15
- # HamlLint::Adapter::Haml4.new('%div')
16
- #
17
- # @api public
18
- # @param source [String] Haml code to parse
19
- # @param options [Haml::Options]
20
- def initialize(source, options = Haml::Options.new)
21
- @source = source
22
- @parser = Haml::Parser.new(source, options)
23
- end
24
-
25
- def precompile
26
- # Haml uses the filters as part of precompilation... we don't care about those,
27
- # but without this tweak, it would fail on filters that are not loaded.
28
- real_defined = Haml::Filters.defined
29
- Haml::Filters.instance_variable_set(:@defined, Hash.new { real_defined['plain'] })
30
-
31
- ::Haml::Engine.new(source).precompiled
32
- ensure
33
- Haml::Filters.instance_variable_set(:@defined, real_defined)
34
- end
35
-
36
- # @!method
37
- # Parses the source code into an abstract syntax tree
38
- #
39
- # @example
40
- # HamlLint::Adapter::Haml4.new('%div')
41
- #
42
- # @api public
43
- # @return [Haml::Parser::ParseNode]
44
- # @raise [Haml::Error]
45
- def_delegator :parser, :parse
46
-
47
- private
48
-
49
- # The Haml parser to adapt for HamlLint
50
- #
51
- # @api private
52
- # @return [Haml::Parser] the Haml 4 parser
53
- attr_reader :parser
54
-
55
- # The Haml code to parse
56
- #
57
- # @api private
58
- # @return [String] Haml code to parse
59
- attr_reader :source
60
- end
61
- end
62
- end