haml_lint 0.13.0 → 0.14.0
Sign up to get free protection for your applications and to get access to all the features.
- 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
|