haml_lint 0.13.0 → 0.14.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 +4 -4
- data/config/default.yml +1 -0
- data/lib/haml_lint/cli.rb +25 -8
- data/lib/haml_lint/configuration.rb +56 -34
- data/lib/haml_lint/configuration_loader.rb +22 -6
- data/lib/haml_lint/constants.rb +1 -1
- data/lib/haml_lint/document.rb +102 -0
- data/lib/haml_lint/file_finder.rb +14 -5
- data/lib/haml_lint/lint.rb +17 -1
- data/lib/haml_lint/linter/alt_text.rb +1 -1
- data/lib/haml_lint/linter/class_attribute_with_static_value.rb +2 -2
- data/lib/haml_lint/linter/classes_before_ids.rb +2 -2
- data/lib/haml_lint/linter/consecutive_comments.rb +3 -5
- data/lib/haml_lint/linter/consecutive_silent_scripts.rb +5 -5
- data/lib/haml_lint/linter/empty_script.rb +1 -1
- data/lib/haml_lint/linter/html_attributes.rb +2 -2
- data/lib/haml_lint/linter/implicit_div.rb +3 -3
- data/lib/haml_lint/linter/leading_comment_space.rb +1 -1
- data/lib/haml_lint/linter/line_length.rb +2 -2
- data/lib/haml_lint/linter/multiline_pipe.rb +3 -3
- data/lib/haml_lint/linter/multiline_script.rb +3 -3
- data/lib/haml_lint/linter/object_reference_attributes.rb +1 -1
- data/lib/haml_lint/linter/rubocop.rb +60 -34
- data/lib/haml_lint/linter/ruby_comments.rb +1 -1
- data/lib/haml_lint/linter/space_before_script.rb +4 -4
- data/lib/haml_lint/linter/space_inside_hash_attributes.rb +2 -2
- data/lib/haml_lint/linter/tag_name.rb +1 -1
- data/lib/haml_lint/linter/trailing_whitespace.rb +2 -2
- data/lib/haml_lint/linter/unnecessary_interpolation.rb +3 -3
- data/lib/haml_lint/linter/unnecessary_string_output.rb +10 -3
- data/lib/haml_lint/linter.rb +30 -10
- data/lib/haml_lint/linter_registry.rb +13 -2
- data/lib/haml_lint/linter_selector.rb +77 -0
- data/lib/haml_lint/node_transformer.rb +5 -5
- data/lib/haml_lint/options.rb +13 -6
- data/lib/haml_lint/rake_task.rb +18 -3
- data/lib/haml_lint/report.rb +7 -0
- data/lib/haml_lint/reporter/default_reporter.rb +2 -2
- data/lib/haml_lint/reporter/json_reporter.rb +15 -10
- data/lib/haml_lint/reporter.rb +17 -11
- data/lib/haml_lint/{script_extractor.rb → ruby_extractor.rb} +26 -17
- data/lib/haml_lint/runner.rb +44 -44
- data/lib/haml_lint/tree/node.rb +7 -8
- data/lib/haml_lint/utils.rb +88 -21
- data/lib/haml_lint/version.rb +1 -1
- data/lib/haml_lint.rb +2 -1
- metadata +5 -4
- data/lib/haml_lint/parser.rb +0 -87
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: fdd406c711a12f70bba2b26982550e7f190b2c61
|
4
|
+
data.tar.gz: 2cd4a631a543de9987408c30a4367d18bff33d6b
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 89371444076d421e9589f2b34b3867b6b0387f0f07af00f119a520d20b296b3a77088e425e36cf5b29a1b043cd24e4987b15557a9bc8c0e502985b5c124d0014
|
7
|
+
data.tar.gz: 3053c5a7d28d8cc7e242bb0346cc83e8e6a65935dad36042678eedd2d8a21f8784085c67887a528baec7698fae8e2ceb958a76e5ce787e251c41b2ffa6f346ef
|
data/config/default.yml
CHANGED
data/lib/haml_lint/cli.rb
CHANGED
@@ -1,3 +1,4 @@
|
|
1
|
+
require 'haml_lint'
|
1
2
|
require 'haml_lint/options'
|
2
3
|
|
3
4
|
require 'sysexits'
|
@@ -5,8 +6,8 @@ require 'sysexits'
|
|
5
6
|
module HamlLint
|
6
7
|
# Command line application interface.
|
7
8
|
class CLI
|
8
|
-
|
9
|
-
|
9
|
+
# Create a CLI that outputs to the specified logger.
|
10
|
+
#
|
10
11
|
# @param logger [HamlLint::Logger]
|
11
12
|
def initialize(logger)
|
12
13
|
@log = logger
|
@@ -16,7 +17,7 @@ module HamlLint
|
|
16
17
|
# based on those arguments.
|
17
18
|
#
|
18
19
|
# @param args [Array<String>] command line arguments
|
19
|
-
# @return [
|
20
|
+
# @return [Integer] exit status code
|
20
21
|
def run(args)
|
21
22
|
options = HamlLint::Options.new.parse(args)
|
22
23
|
act_on_options(options)
|
@@ -28,6 +29,9 @@ module HamlLint
|
|
28
29
|
|
29
30
|
attr_reader :log
|
30
31
|
|
32
|
+
# Given the provided options, execute the appropriate command.
|
33
|
+
#
|
34
|
+
# @return [Integer] exit status code
|
31
35
|
def act_on_options(options)
|
32
36
|
log.color_enabled = options.fetch(:color, log.tty?)
|
33
37
|
|
@@ -48,6 +52,8 @@ module HamlLint
|
|
48
52
|
end
|
49
53
|
end
|
50
54
|
|
55
|
+
# Outputs a message and returns an appropriate error code for the specified
|
56
|
+
# exception.
|
51
57
|
def handle_exception(ex)
|
52
58
|
case ex
|
53
59
|
when HamlLint::Exceptions::ConfigurationError
|
@@ -69,21 +75,27 @@ module HamlLint
|
|
69
75
|
end
|
70
76
|
end
|
71
77
|
|
78
|
+
# Scans the files specified by the given options for lints.
|
79
|
+
#
|
80
|
+
# @return [Integer] exit status code
|
72
81
|
def scan_for_lints(options)
|
73
82
|
report = Runner.new.run(options)
|
74
83
|
print_report(report, options)
|
75
84
|
report.failed? ? Sysexits::EX_DATAERR : Sysexits::EX_OK
|
76
85
|
end
|
77
86
|
|
87
|
+
# Outputs a report of the linter run using the specified reporter.
|
78
88
|
def print_report(report, options)
|
79
|
-
reporter = options.fetch(:reporter,
|
80
|
-
|
89
|
+
reporter = options.fetch(:reporter,
|
90
|
+
HamlLint::Reporter::DefaultReporter).new(log)
|
91
|
+
reporter.display_report(report)
|
81
92
|
end
|
82
93
|
|
94
|
+
# Outputs a list of all currently available linters.
|
83
95
|
def print_available_linters
|
84
96
|
log.info 'Available linters:'
|
85
97
|
|
86
|
-
linter_names = LinterRegistry.linters.map do |linter|
|
98
|
+
linter_names = HamlLint::LinterRegistry.linters.map do |linter|
|
87
99
|
linter.name.split('::').last
|
88
100
|
end
|
89
101
|
|
@@ -92,10 +104,11 @@ module HamlLint
|
|
92
104
|
end
|
93
105
|
end
|
94
106
|
|
107
|
+
# Outputs a list of currently available reporters.
|
95
108
|
def print_available_reporters
|
96
109
|
log.info 'Available reporters:'
|
97
110
|
|
98
|
-
reporter_names = Reporter.descendants.map do |reporter|
|
111
|
+
reporter_names = HamlLint::Reporter.descendants.map do |reporter|
|
99
112
|
reporter.name.split('::').last.sub(/Reporter$/, '').downcase
|
100
113
|
end
|
101
114
|
|
@@ -104,14 +117,18 @@ module HamlLint
|
|
104
117
|
end
|
105
118
|
end
|
106
119
|
|
120
|
+
# Outputs help documentation.
|
107
121
|
def print_help(options)
|
108
122
|
log.log options[:help]
|
109
123
|
end
|
110
124
|
|
125
|
+
# Outputs the application name and version.
|
111
126
|
def print_version
|
112
|
-
log.log "#{APP_NAME} #{HamlLint::VERSION}"
|
127
|
+
log.log "#{HamlLint::APP_NAME} #{HamlLint::VERSION}"
|
113
128
|
end
|
114
129
|
|
130
|
+
# Outputs the backtrace of an exception with instructions on how to report
|
131
|
+
# the issue.
|
115
132
|
def print_unexpected_exception(ex)
|
116
133
|
log.bold_error ex.message
|
117
134
|
log.error ex.backtrace.join("\n")
|
@@ -1,6 +1,12 @@
|
|
1
1
|
module HamlLint
|
2
|
-
# Stores configuration for
|
2
|
+
# Stores runtime configuration for the application.
|
3
|
+
#
|
4
|
+
# The purpose of this class is to validate and ensure all configurations
|
5
|
+
# satisfy some basic pre-conditions so other parts of the application don't
|
6
|
+
# have to check the configuration for errors. It should have no knowledge of
|
7
|
+
# how these configuration values are ultimately used.
|
3
8
|
class Configuration
|
9
|
+
# Internal hash storing the configuration.
|
4
10
|
attr_reader :hash
|
5
11
|
|
6
12
|
# Creates a configuration from the given options hash.
|
@@ -11,6 +17,14 @@ module HamlLint
|
|
11
17
|
validate
|
12
18
|
end
|
13
19
|
|
20
|
+
# Access the configuration as if it were a hash.
|
21
|
+
#
|
22
|
+
# @param key [String]
|
23
|
+
# @return [Array,Hash,Number,String]
|
24
|
+
def [](key)
|
25
|
+
@hash[key]
|
26
|
+
end
|
27
|
+
|
14
28
|
# Compares this configuration with another.
|
15
29
|
#
|
16
30
|
# @param other [HamlLint::Configuration]
|
@@ -30,19 +44,9 @@ module HamlLint
|
|
30
44
|
linter.name.split('::').last
|
31
45
|
when HamlLint::Linter
|
32
46
|
linter.name
|
33
|
-
else
|
34
|
-
linter.to_s
|
35
47
|
end
|
36
48
|
|
37
|
-
|
38
|
-
@hash['linters'].fetch(linter_name, {})).freeze
|
39
|
-
end
|
40
|
-
|
41
|
-
# Returns whether the specified linter is enabled by this configuration.
|
42
|
-
#
|
43
|
-
# @param linter [HamlLint::Linter,String]
|
44
|
-
def linter_enabled?(linter)
|
45
|
-
for_linter(linter)['enabled'] != false
|
49
|
+
@hash['linters'].fetch(linter_name, {}).dup.freeze
|
46
50
|
end
|
47
51
|
|
48
52
|
# Merges the given configuration with this one, returning a new
|
@@ -56,18 +60,14 @@ module HamlLint
|
|
56
60
|
|
57
61
|
private
|
58
62
|
|
59
|
-
#
|
60
|
-
#
|
61
|
-
|
62
|
-
|
63
|
-
|
64
|
-
end
|
65
|
-
|
63
|
+
# Merge two hashes such that nested hashes are merged rather than replaced.
|
64
|
+
#
|
65
|
+
# @param parent [Hash]
|
66
|
+
# @param child [Hash]
|
67
|
+
# @return [Hash]
|
66
68
|
def smart_merge(parent, child)
|
67
69
|
parent.merge(child) do |_key, old, new|
|
68
70
|
case old
|
69
|
-
when Array
|
70
|
-
old + Array(new)
|
71
71
|
when Hash
|
72
72
|
smart_merge(old, new)
|
73
73
|
else
|
@@ -76,21 +76,43 @@ module HamlLint
|
|
76
76
|
end
|
77
77
|
end
|
78
78
|
|
79
|
-
|
80
|
-
|
81
|
-
|
79
|
+
# Validates the configuration for any invalid options, normalizing it where
|
80
|
+
# possible.
|
81
|
+
def validate
|
82
|
+
ensure_exclude_option_array_exists
|
83
|
+
ensure_linter_section_exists
|
84
|
+
ensure_linter_include_exclude_arrays_exist
|
85
|
+
ensure_linter_severity_valid
|
86
|
+
end
|
87
|
+
|
88
|
+
# Ensures the `exclude` global option is an array.
|
89
|
+
def ensure_exclude_option_array_exists
|
90
|
+
@hash['exclude'] = Array(@hash['exclude'])
|
91
|
+
end
|
92
|
+
|
93
|
+
# Ensures the `linters` configuration section exists.
|
94
|
+
def ensure_linter_section_exists
|
95
|
+
@hash['linters'] ||= {}
|
96
|
+
end
|
97
|
+
|
98
|
+
# Ensure `include` and `exclude` options for linters are arrays
|
99
|
+
# (since users can specify a single string glob pattern for convenience)
|
100
|
+
def ensure_linter_include_exclude_arrays_exist
|
101
|
+
@hash['linters'].keys.each do |linter_name|
|
102
|
+
%w[include exclude].each do |option|
|
103
|
+
linter_config = @hash['linters'][linter_name]
|
104
|
+
linter_config[option] = Array(linter_config[option])
|
105
|
+
end
|
106
|
+
end
|
82
107
|
end
|
83
108
|
|
84
|
-
def
|
85
|
-
hash.
|
86
|
-
|
87
|
-
|
88
|
-
|
89
|
-
|
90
|
-
|
91
|
-
value
|
92
|
-
end
|
93
|
-
h
|
109
|
+
def ensure_linter_severity_valid
|
110
|
+
@hash['linters'].each do |linter_name, linter_config|
|
111
|
+
severity = linter_config['severity']
|
112
|
+
unless [nil, 'warning', 'error'].include?(severity)
|
113
|
+
raise HamlLint::Exceptions::ConfigurationError,
|
114
|
+
"Invalid severity '#{severity}' specified for #{linter_name}"
|
115
|
+
end
|
94
116
|
end
|
95
117
|
end
|
96
118
|
end
|
@@ -4,10 +4,12 @@ require 'yaml'
|
|
4
4
|
module HamlLint
|
5
5
|
# Manages configuration file loading.
|
6
6
|
class ConfigurationLoader
|
7
|
-
DEFAULT_CONFIG_PATH = File.join(
|
7
|
+
DEFAULT_CONFIG_PATH = File.join(HamlLint::HOME, 'config', 'default.yml')
|
8
8
|
CONFIG_FILE_NAME = '.haml-lint.yml'
|
9
9
|
|
10
10
|
class << self
|
11
|
+
# Load configuration file given the current working directory the
|
12
|
+
# application is running within.
|
11
13
|
def load_applicable_config
|
12
14
|
directory = File.expand_path(Dir.pwd)
|
13
15
|
config_file = possible_config_files(directory).find(&:file?)
|
@@ -19,33 +21,42 @@ module HamlLint
|
|
19
21
|
end
|
20
22
|
end
|
21
23
|
|
24
|
+
# Loads the built-in default configuration.
|
22
25
|
def default_configuration
|
23
26
|
@default_config ||= load_from_file(DEFAULT_CONFIG_PATH)
|
24
27
|
end
|
25
28
|
|
26
29
|
# Loads a configuration, ensuring it extends the default configuration.
|
30
|
+
#
|
31
|
+
# @param file [String]
|
32
|
+
# @return [HamlLint::Configuration]
|
27
33
|
def load_file(file)
|
28
34
|
config = load_from_file(file)
|
29
35
|
|
30
36
|
default_configuration.merge(config)
|
31
|
-
rescue => error
|
37
|
+
rescue Psych::SyntaxError, Errno::ENOENT => error
|
32
38
|
raise HamlLint::Exceptions::ConfigurationError,
|
33
39
|
"Unable to load configuration from '#{file}': #{error}",
|
34
40
|
error.backtrace
|
35
41
|
end
|
36
42
|
|
43
|
+
# Creates a configuration from the specified hash, ensuring it extends the
|
44
|
+
# default configuration.
|
45
|
+
#
|
46
|
+
# @param hash [Hash]
|
47
|
+
# @return [HamlLint::Configuration]
|
37
48
|
def load_hash(hash)
|
38
49
|
config = HamlLint::Configuration.new(hash)
|
39
50
|
|
40
51
|
default_configuration.merge(config)
|
41
|
-
rescue => error
|
42
|
-
raise HamlLint::Exceptions::ConfigurationError,
|
43
|
-
"Unable to load configuration from '#{file}': #{error}",
|
44
|
-
error.backtrace
|
45
52
|
end
|
46
53
|
|
47
54
|
private
|
48
55
|
|
56
|
+
# Parses and loads a configuration from the given file.
|
57
|
+
#
|
58
|
+
# @param file [String]
|
59
|
+
# @return [HamlLint::Configuration]
|
49
60
|
def load_from_file(file)
|
50
61
|
hash =
|
51
62
|
if yaml = YAML.load_file(file)
|
@@ -57,6 +68,11 @@ module HamlLint
|
|
57
68
|
HamlLint::Configuration.new(hash)
|
58
69
|
end
|
59
70
|
|
71
|
+
# Returns a list of possible configuration files given the context of the
|
72
|
+
# specified directory.
|
73
|
+
#
|
74
|
+
# @param directory [String]
|
75
|
+
# @return [Array<Pathname>]
|
60
76
|
def possible_config_files(directory)
|
61
77
|
files = Pathname.new(directory)
|
62
78
|
.enum_for(:ascend)
|
data/lib/haml_lint/constants.rb
CHANGED
@@ -1,6 +1,6 @@
|
|
1
1
|
# Global application constants.
|
2
2
|
module HamlLint
|
3
|
-
|
3
|
+
HOME = File.expand_path(File.join(File.dirname(__FILE__), '..', '..'))
|
4
4
|
APP_NAME = 'haml-lint'
|
5
5
|
|
6
6
|
REPO_URL = 'https://github.com/brigade/haml-lint'
|
@@ -0,0 +1,102 @@
|
|
1
|
+
module HamlLint
|
2
|
+
# Represents a parsed Haml document and its associated metadata.
|
3
|
+
class Document
|
4
|
+
# File name given to source code parsed from just a string.
|
5
|
+
STRING_SOURCE = '(string)'
|
6
|
+
|
7
|
+
# @return [HamlLint::Configuration] Configuration used to parse template
|
8
|
+
attr_reader :config
|
9
|
+
|
10
|
+
# @return [String] Haml template file path
|
11
|
+
attr_reader :file
|
12
|
+
|
13
|
+
# @return [HamlLint::Tree::Node] Root of the parse tree
|
14
|
+
attr_reader :tree
|
15
|
+
|
16
|
+
# @return [String] original source code
|
17
|
+
attr_reader :source
|
18
|
+
|
19
|
+
# @return [Array<String>] original source code as an array of lines
|
20
|
+
attr_reader :source_lines
|
21
|
+
|
22
|
+
# Parses the specified Haml code into a {Document}.
|
23
|
+
#
|
24
|
+
# @param source [String] Haml code to parse
|
25
|
+
# @param options [Hash]
|
26
|
+
# @option options :file [String] file name of document that was parsed
|
27
|
+
# @raise [Haml::Parser::Error] if there was a problem parsing the document
|
28
|
+
def initialize(source, options)
|
29
|
+
@config = options[:config]
|
30
|
+
@file = options.fetch(:file, STRING_SOURCE)
|
31
|
+
|
32
|
+
process_source(source)
|
33
|
+
end
|
34
|
+
|
35
|
+
private
|
36
|
+
|
37
|
+
# @param source [String] Haml code to parse
|
38
|
+
# @raise [Haml::Parser::Error] if there was a problem parsing the document
|
39
|
+
def process_source(source)
|
40
|
+
@source = strip_frontmatter(source)
|
41
|
+
@source_lines = @source.split("\n")
|
42
|
+
|
43
|
+
@tree = process_tree(Haml::Parser.new(@source, Haml::Options.new).parse)
|
44
|
+
end
|
45
|
+
|
46
|
+
# Processes the {Haml::Parser::ParseNode} tree and returns a tree composed
|
47
|
+
# of friendlier {HamlLint::Tree::Node}s.
|
48
|
+
#
|
49
|
+
# @param original_tree [Haml::Parser::ParseNode]
|
50
|
+
# @return [Haml::Tree::Node]
|
51
|
+
def process_tree(original_tree)
|
52
|
+
# Remove the trailing empty HAML comment that the parser creates to signal
|
53
|
+
# the end of the HAML document
|
54
|
+
if Gem::Requirement.new('~> 4.0.0').satisfied_by?(Gem.loaded_specs['haml'].version)
|
55
|
+
original_tree.children.pop
|
56
|
+
end
|
57
|
+
|
58
|
+
@node_transformer = HamlLint::NodeTransformer.new(self)
|
59
|
+
convert_tree(original_tree)
|
60
|
+
end
|
61
|
+
|
62
|
+
# Converts a HAML parse tree to a tree of {HamlLint::Tree::Node} objects.
|
63
|
+
#
|
64
|
+
# This provides a cleaner interface with which the linters can interact with
|
65
|
+
# the parse tree.
|
66
|
+
#
|
67
|
+
# @param haml_node [Haml::Parser::ParseNode]
|
68
|
+
# @param parent [Haml::Tree::Node]
|
69
|
+
# @return [Haml::Tree::Node]
|
70
|
+
def convert_tree(haml_node, parent = nil)
|
71
|
+
new_node = @node_transformer.transform(haml_node)
|
72
|
+
new_node.parent = parent
|
73
|
+
|
74
|
+
new_node.children = haml_node.children.map do |child|
|
75
|
+
convert_tree(child, new_node)
|
76
|
+
end
|
77
|
+
|
78
|
+
new_node
|
79
|
+
end
|
80
|
+
|
81
|
+
# Removes YAML frontmatter
|
82
|
+
def strip_frontmatter(source)
|
83
|
+
if config['skip_frontmatter'] &&
|
84
|
+
source =~ /
|
85
|
+
# From the start of the string
|
86
|
+
\A
|
87
|
+
# First-capture match --- followed by optional whitespace up
|
88
|
+
# to a newline then 0 or more chars followed by an optional newline.
|
89
|
+
# This matches the --- and the contents of the frontmatter
|
90
|
+
(---\s*\n.*?\n?)
|
91
|
+
# From the start of the line
|
92
|
+
^
|
93
|
+
# Second capture match --- or ... followed by optional whitespace
|
94
|
+
# and newline. This matches the closing --- for the frontmatter.
|
95
|
+
(---|\.\.\.)\s*$\n?/mx
|
96
|
+
source = $POSTMATCH
|
97
|
+
end
|
98
|
+
|
99
|
+
source
|
100
|
+
end
|
101
|
+
end
|
102
|
+
end
|
@@ -1,13 +1,15 @@
|
|
1
1
|
require 'find'
|
2
2
|
|
3
3
|
module HamlLint
|
4
|
-
# Finds
|
4
|
+
# Finds Haml files that should be linted given a specified list of paths, glob
|
5
5
|
# patterns, and configuration.
|
6
6
|
class FileFinder
|
7
7
|
# List of extensions of files to include under a directory when a directory
|
8
8
|
# is specified instead of a file.
|
9
9
|
VALID_EXTENSIONS = %w[.haml]
|
10
10
|
|
11
|
+
# Create a file finder using the specified configuration.
|
12
|
+
#
|
11
13
|
# @param config [HamlLint::Configuration]
|
12
14
|
def initialize(config)
|
13
15
|
@config = config
|
@@ -22,15 +24,18 @@ module HamlLint
|
|
22
24
|
def find(patterns, excluded_patterns)
|
23
25
|
extract_files_from(patterns).reject do |file|
|
24
26
|
excluded_patterns.any? do |exclusion_glob|
|
25
|
-
::
|
26
|
-
::File::FNM_PATHNAME | # Wildcards don't match path separators
|
27
|
-
::File::FNM_DOTMATCH) # `*` wildcard matches dotfiles
|
27
|
+
HamlLint::Utils.any_glob_matches?(exclusion_glob, file)
|
28
28
|
end
|
29
29
|
end
|
30
30
|
end
|
31
31
|
|
32
32
|
private
|
33
33
|
|
34
|
+
# Extract the list of matching files given the list of glob patterns, file
|
35
|
+
# paths, and directories.
|
36
|
+
#
|
37
|
+
# @param patterns [Array<String>]
|
38
|
+
# @return [Array<String>]
|
34
39
|
def extract_files_from(patterns) # rubocop:disable MethodLength
|
35
40
|
files = []
|
36
41
|
|
@@ -57,9 +62,13 @@ module HamlLint
|
|
57
62
|
end
|
58
63
|
end
|
59
64
|
|
60
|
-
files.uniq
|
65
|
+
files.uniq.sort
|
61
66
|
end
|
62
67
|
|
68
|
+
# Whether the given file should be treated as a Haml file.
|
69
|
+
#
|
70
|
+
# @param file [String]
|
71
|
+
# @return [Boolean]
|
63
72
|
def haml_file?(file)
|
64
73
|
return false unless ::FileTest.file?(file)
|
65
74
|
|
data/lib/haml_lint/lint.rb
CHANGED
@@ -1,7 +1,20 @@
|
|
1
1
|
module HamlLint
|
2
2
|
# Contains information about a problem or issue with a HAML document.
|
3
3
|
class Lint
|
4
|
-
|
4
|
+
# @return [String] file path to which the lint applies
|
5
|
+
attr_reader :filename
|
6
|
+
|
7
|
+
# @return [String] line number of the file the lint corresponds to
|
8
|
+
attr_reader :line
|
9
|
+
|
10
|
+
# @return [SlimLint::Linter] linter that reported the lint
|
11
|
+
attr_reader :linter
|
12
|
+
|
13
|
+
# @return [String] error/warning message to display to user
|
14
|
+
attr_reader :message
|
15
|
+
|
16
|
+
# @return [Symbol] whether this lint is a warning or an error
|
17
|
+
attr_reader :severity
|
5
18
|
|
6
19
|
# Creates a new lint.
|
7
20
|
#
|
@@ -18,6 +31,9 @@ module HamlLint
|
|
18
31
|
@severity = severity
|
19
32
|
end
|
20
33
|
|
34
|
+
# Return whether this lint has a severity of error.
|
35
|
+
#
|
36
|
+
# @return [Boolean]
|
21
37
|
def error?
|
22
38
|
@severity == :error
|
23
39
|
end
|
@@ -18,8 +18,8 @@ module HamlLint
|
|
18
18
|
def visit_tag(node)
|
19
19
|
return unless contains_class_attribute?(node.dynamic_attributes_sources)
|
20
20
|
|
21
|
-
|
22
|
-
|
21
|
+
record_lint(node, 'Avoid defining `class` in attributes hash ' \
|
22
|
+
'for static class names')
|
23
23
|
end
|
24
24
|
|
25
25
|
private
|
@@ -17,8 +17,8 @@ module HamlLint
|
|
17
17
|
next unless components[index].start_with?('.') &&
|
18
18
|
components[index - 1].start_with?('#')
|
19
19
|
|
20
|
-
|
21
|
-
|
20
|
+
record_lint(node, 'Classes should be listed before IDs '\
|
21
|
+
"(#{components[index]} should precede #{components[index - 1]})")
|
22
22
|
break
|
23
23
|
end
|
24
24
|
end
|
@@ -3,17 +3,15 @@ module HamlLint
|
|
3
3
|
class Linter::ConsecutiveComments < Linter
|
4
4
|
include LinterRegistry
|
5
5
|
|
6
|
-
MIN_CONSECUTIVE = 2
|
7
6
|
COMMENT_DETECTOR = ->(child) { child.type == :haml_comment }
|
8
7
|
|
9
8
|
def visit_root(node)
|
10
|
-
HamlLint::Utils.
|
9
|
+
HamlLint::Utils.for_consecutive_items(
|
11
10
|
node.children,
|
12
|
-
MIN_CONSECUTIVE,
|
13
11
|
COMMENT_DETECTOR,
|
14
12
|
) do |group|
|
15
|
-
|
16
|
-
|
13
|
+
record_lint(group.first,
|
14
|
+
"#{group.count} consecutive comments can be merged into one")
|
17
15
|
end
|
18
16
|
end
|
19
17
|
end
|
@@ -9,14 +9,14 @@ module HamlLint
|
|
9
9
|
end
|
10
10
|
|
11
11
|
def visit_root(node)
|
12
|
-
HamlLint::Utils.
|
12
|
+
HamlLint::Utils.for_consecutive_items(
|
13
13
|
node.children,
|
14
|
-
config['max_consecutive'] + 1,
|
15
14
|
SILENT_SCRIPT_DETECTOR,
|
15
|
+
config['max_consecutive'] + 1,
|
16
16
|
) do |group|
|
17
|
-
|
18
|
-
|
19
|
-
|
17
|
+
record_lint(group.first,
|
18
|
+
"#{group.count} consecutive Ruby scripts can be merged " \
|
19
|
+
'into a single `:ruby` filter')
|
20
20
|
end
|
21
21
|
end
|
22
22
|
end
|
@@ -7,8 +7,8 @@ module HamlLint
|
|
7
7
|
def visit_tag(node)
|
8
8
|
return unless node.html_attributes?
|
9
9
|
|
10
|
-
|
11
|
-
|
10
|
+
record_lint(node, "Prefer the hash attributes syntax (%tag{ lang: 'en' }) " \
|
11
|
+
'over HTML attributes syntax (%tag(lang=en))')
|
12
12
|
end
|
13
13
|
end
|
14
14
|
end
|
@@ -12,9 +12,9 @@ module HamlLint
|
|
12
12
|
tag = node.source_code[/\s*([^\s={\(\[]+)/, 1]
|
13
13
|
return unless tag.start_with?('%div')
|
14
14
|
|
15
|
-
|
16
|
-
|
17
|
-
|
15
|
+
record_lint(node,
|
16
|
+
"`#{tag}` can be written as `#{node.static_attributes_source}` " \
|
17
|
+
'since `%div` is implicit')
|
18
18
|
end
|
19
19
|
end
|
20
20
|
end
|
@@ -9,10 +9,10 @@ module HamlLint
|
|
9
9
|
max_length = config['max']
|
10
10
|
dummy_node = Struct.new(:line)
|
11
11
|
|
12
|
-
|
12
|
+
document.source_lines.each_with_index do |line, index|
|
13
13
|
next if line.length <= max_length
|
14
14
|
|
15
|
-
|
15
|
+
record_lint(dummy_node.new(index + 1), format(MSG, line.length, max_length))
|
16
16
|
end
|
17
17
|
end
|
18
18
|
end
|