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
@@ -1,29 +1,34 @@
|
|
1
1
|
module HamlLint
|
2
2
|
# Outputs report as a JSON document.
|
3
3
|
class Reporter::JsonReporter < Reporter
|
4
|
-
def
|
4
|
+
def display_report(report)
|
5
|
+
lints = report.lints
|
5
6
|
grouped = lints.group_by(&:filename)
|
6
7
|
|
7
|
-
|
8
|
-
metadata:
|
9
|
-
hamllint_version: VERSION,
|
10
|
-
ruby_engine: RUBY_ENGINE,
|
11
|
-
ruby_patchlevel: RUBY_PATCHLEVEL.to_s,
|
12
|
-
ruby_platform: RUBY_PLATFORM,
|
13
|
-
},
|
8
|
+
report_hash = {
|
9
|
+
metadata: metadata,
|
14
10
|
files: grouped.map { |l| map_file(l) },
|
15
11
|
summary: {
|
16
12
|
offense_count: lints.length,
|
17
13
|
target_file_count: grouped.length,
|
18
|
-
inspected_file_count: files.length,
|
14
|
+
inspected_file_count: report.files.length,
|
19
15
|
},
|
20
16
|
}
|
21
17
|
|
22
|
-
log.log
|
18
|
+
log.log report_hash.to_json
|
23
19
|
end
|
24
20
|
|
25
21
|
private
|
26
22
|
|
23
|
+
def metadata
|
24
|
+
{
|
25
|
+
haml_lint_version: HamlLint::VERSION,
|
26
|
+
ruby_engine: RUBY_ENGINE,
|
27
|
+
ruby_patchlevel: RUBY_PATCHLEVEL.to_s,
|
28
|
+
ruby_platform: RUBY_PLATFORM,
|
29
|
+
}
|
30
|
+
end
|
31
|
+
|
27
32
|
def map_file(file)
|
28
33
|
{
|
29
34
|
path: file.first,
|
data/lib/haml_lint/reporter.rb
CHANGED
@@ -1,36 +1,42 @@
|
|
1
1
|
module HamlLint
|
2
|
-
# Abstract lint reporter. Subclass and override {#
|
2
|
+
# Abstract lint reporter. Subclass and override {#display_report} to
|
3
3
|
# implement a custom lint reporter.
|
4
4
|
#
|
5
5
|
# @abstract
|
6
6
|
class Reporter
|
7
|
-
|
8
|
-
|
9
|
-
|
7
|
+
# Creates the reporter that will display the given report.
|
8
|
+
#
|
10
9
|
# @param logger [HamlLint::Logger]
|
11
|
-
|
12
|
-
def initialize(logger, report)
|
10
|
+
def initialize(logger)
|
13
11
|
@log = logger
|
14
|
-
@lints = report.lints
|
15
|
-
@files = report.files
|
16
12
|
end
|
17
13
|
|
18
14
|
# Implemented by subclasses to display lints from a {HamlLint::Report}.
|
19
|
-
|
20
|
-
|
15
|
+
#
|
16
|
+
# @param report [HamlLint::Report]
|
17
|
+
def display_report(report)
|
18
|
+
raise NotImplementedError,
|
19
|
+
"Implement `display_report` to display #{report}"
|
21
20
|
end
|
22
21
|
|
23
|
-
# Keep tracking all the descendants of this class for the list of available
|
22
|
+
# Keep tracking all the descendants of this class for the list of available
|
23
|
+
# reporters.
|
24
|
+
#
|
25
|
+
# @return [Array<Class>]
|
24
26
|
def self.descendants
|
25
27
|
@descendants ||= []
|
26
28
|
end
|
27
29
|
|
30
|
+
# Executed when this class is subclassed.
|
31
|
+
#
|
32
|
+
# @param descendant [Class]
|
28
33
|
def self.inherited(descendant)
|
29
34
|
descendants << descendant
|
30
35
|
end
|
31
36
|
|
32
37
|
private
|
33
38
|
|
39
|
+
# @return [HamlLint::Logger] logger to send output to
|
34
40
|
attr_reader :log
|
35
41
|
end
|
36
42
|
end
|
@@ -19,24 +19,33 @@ module HamlLint
|
|
19
19
|
# link_to 'Sign In', sign_in_path
|
20
20
|
# end
|
21
21
|
#
|
22
|
-
|
22
|
+
# The translation won't be perfect, and won't make any real sense, but the
|
23
|
+
# relationship between variable declarations/uses and the flow control graph
|
24
|
+
# will remain intact.
|
25
|
+
class RubyExtractor
|
23
26
|
include HamlVisitor
|
24
27
|
|
25
|
-
|
26
|
-
|
27
|
-
|
28
|
-
|
29
|
-
|
30
|
-
|
31
|
-
|
32
|
-
|
33
|
-
|
28
|
+
# Stores the extracted source and a map of lines of generated source to the
|
29
|
+
# original source that created them.
|
30
|
+
#
|
31
|
+
# @attr_reader source [String] generated source code
|
32
|
+
# @attr_reader source_map [Hash] map of line numbers from generated source
|
33
|
+
# to original source line number
|
34
|
+
RubySource = Struct.new(:source, :source_map)
|
35
|
+
|
36
|
+
# Extracts Ruby code from Sexp representing a Slim document.
|
37
|
+
#
|
38
|
+
# @param document [HamlLint::Document]
|
39
|
+
# @return [HamlLint::RubyExtractor::RubySource]
|
40
|
+
def extract(document)
|
41
|
+
visit(document.tree)
|
42
|
+
RubySource.new(@source_lines.join("\n"), @source_map)
|
34
43
|
end
|
35
44
|
|
36
45
|
def visit_root(_node)
|
37
|
-
@
|
38
|
-
@total_lines = 0
|
46
|
+
@source_lines = []
|
39
47
|
@source_map = {}
|
48
|
+
@line_count = 0
|
40
49
|
@indent_level = 0
|
41
50
|
|
42
51
|
yield # Collect lines of code from children
|
@@ -104,8 +113,8 @@ module HamlLint
|
|
104
113
|
end
|
105
114
|
else
|
106
115
|
add_line('puts', node)
|
107
|
-
HamlLint::Utils.extract_interpolated_values(node.text) do |interpolated_code|
|
108
|
-
add_line(interpolated_code, node)
|
116
|
+
HamlLint::Utils.extract_interpolated_values(node.text) do |interpolated_code, line|
|
117
|
+
add_line(interpolated_code, node.line + line)
|
109
118
|
end
|
110
119
|
end
|
111
120
|
end
|
@@ -140,7 +149,7 @@ module HamlLint
|
|
140
149
|
|
141
150
|
indent = (' ' * 2 * indent_level)
|
142
151
|
|
143
|
-
@
|
152
|
+
@source_lines << indent + code
|
144
153
|
|
145
154
|
original_line =
|
146
155
|
node_or_line.respond_to?(:line) ? node_or_line.line : node_or_line
|
@@ -149,8 +158,8 @@ module HamlLint
|
|
149
158
|
# resulting code will span multiple lines, so we need to create a
|
150
159
|
# mapping for each line.
|
151
160
|
(code.count("\n") + 1).times do
|
152
|
-
@
|
153
|
-
@source_map[@
|
161
|
+
@line_count += 1
|
162
|
+
@source_map[@line_count] = original_line
|
154
163
|
end
|
155
164
|
end
|
156
165
|
|
data/lib/haml_lint/runner.rb
CHANGED
@@ -1,76 +1,76 @@
|
|
1
1
|
module HamlLint
|
2
2
|
# Responsible for running the applicable linters against the desired files.
|
3
3
|
class Runner
|
4
|
-
# Make the list of applicable files available
|
5
|
-
attr_reader :files
|
6
|
-
|
7
4
|
# Runs the appropriate linters against the desired files given the specified
|
8
5
|
# options.
|
9
6
|
#
|
10
|
-
# @param
|
11
|
-
# @
|
7
|
+
# @param [Hash] options
|
8
|
+
# @option options :config_file [String] path of configuration file to load
|
9
|
+
# @option options :config [HamlLint::Configuration] configuration to use
|
10
|
+
# @option options :excluded_files [Array<String>]
|
11
|
+
# @option options :included_linters [Array<String>]
|
12
|
+
# @option options :excluded_linters [Array<String>]
|
12
13
|
# @return [HamlLint::Report] a summary of all lints found
|
13
14
|
def run(options = {})
|
14
15
|
config = load_applicable_config(options)
|
15
|
-
files = extract_applicable_files(
|
16
|
-
linters = extract_enabled_linters(config, options)
|
16
|
+
files = extract_applicable_files(config, options)
|
17
17
|
|
18
|
-
|
18
|
+
linter_selector = HamlLint::LinterSelector.new(config, options)
|
19
19
|
|
20
|
-
|
21
|
-
|
22
|
-
|
23
|
-
end
|
24
|
-
|
25
|
-
linters.each do |linter|
|
26
|
-
@lints += linter.lints
|
27
|
-
end
|
20
|
+
lints = files.map do |file|
|
21
|
+
collect_lints(file, linter_selector, config)
|
22
|
+
end.flatten
|
28
23
|
|
29
|
-
HamlLint::Report.new(
|
24
|
+
HamlLint::Report.new(lints, files)
|
30
25
|
end
|
31
26
|
|
32
27
|
private
|
33
28
|
|
29
|
+
# Returns the {HamlLint::Configuration} that should be used given the
|
30
|
+
# specified options.
|
31
|
+
#
|
32
|
+
# @param options [Hash]
|
33
|
+
# @return [HamlLint::Configuration]
|
34
34
|
def load_applicable_config(options)
|
35
35
|
if options[:config_file]
|
36
36
|
HamlLint::ConfigurationLoader.load_file(options[:config_file])
|
37
|
+
elsif options[:config]
|
38
|
+
options[:config]
|
37
39
|
else
|
38
40
|
HamlLint::ConfigurationLoader.load_applicable_config
|
39
41
|
end
|
40
42
|
end
|
41
43
|
|
42
|
-
|
43
|
-
|
44
|
-
|
45
|
-
|
46
|
-
|
47
|
-
|
48
|
-
|
49
|
-
|
50
|
-
|
51
|
-
|
52
|
-
|
53
|
-
(included_linters - excluded_linters).map do |linter_class|
|
54
|
-
linter_config = config.for_linter(linter_class)
|
55
|
-
linter_class.new(linter_config) if linter_config['enabled']
|
56
|
-
end.compact
|
57
|
-
end
|
58
|
-
|
59
|
-
def find_lints(file, linters, config)
|
60
|
-
parser = Parser.new(file, config.hash)
|
61
|
-
|
62
|
-
linters.each do |linter|
|
63
|
-
linter.run(parser)
|
44
|
+
# Runs all provided linters using the specified config against the given
|
45
|
+
# file.
|
46
|
+
#
|
47
|
+
# @param file [String] path to file to lint
|
48
|
+
# @param linter_selector [HamlLint::LinterSelector]
|
49
|
+
# @param config [HamlLint::Configuration]
|
50
|
+
def collect_lints(file, linter_selector, config)
|
51
|
+
begin
|
52
|
+
document = HamlLint::Document.new(File.read(file), file: file, config: config)
|
53
|
+
rescue Haml::Error => ex
|
54
|
+
return [HamlLint::Lint.new(nil, file, ex.line, ex.to_s, :error)]
|
64
55
|
end
|
65
|
-
|
66
|
-
|
56
|
+
|
57
|
+
linter_selector.linters_for_file(file).map do |linter|
|
58
|
+
linter.run(document)
|
59
|
+
end.flatten
|
67
60
|
end
|
68
61
|
|
69
|
-
|
62
|
+
# Returns the list of files that should be linted given the specified
|
63
|
+
# configuration and options.
|
64
|
+
#
|
65
|
+
# @param config [HamlLint::Configuration]
|
66
|
+
# @param options [Hash]
|
67
|
+
# @return [Array<String>]
|
68
|
+
def extract_applicable_files(config, options)
|
70
69
|
included_patterns = options[:files]
|
71
|
-
|
70
|
+
excluded_patterns = config['exclude']
|
71
|
+
excluded_patterns += options.fetch(:excluded_files, [])
|
72
72
|
|
73
|
-
HamlLint::FileFinder.new(config).find(included_patterns,
|
73
|
+
HamlLint::FileFinder.new(config).find(included_patterns, excluded_patterns)
|
74
74
|
end
|
75
75
|
end
|
76
76
|
end
|
data/lib/haml_lint/tree/node.rb
CHANGED
@@ -14,12 +14,11 @@ module HamlLint::Tree
|
|
14
14
|
|
15
15
|
# Creates a node wrapping the given {Haml::Parser::ParseNode} struct.
|
16
16
|
#
|
17
|
-
# @param
|
17
|
+
# @param document [HamlLint::Document] Haml document that created this node
|
18
18
|
# @param parse_node [Haml::Parser::ParseNode] parse node created by HAML's parser
|
19
|
-
def initialize(
|
20
|
-
# TODO: Change signature to take source code object, not parser
|
19
|
+
def initialize(document, parse_node)
|
21
20
|
@line = parse_node.line
|
22
|
-
@
|
21
|
+
@document = document
|
23
22
|
@value = parse_node.value
|
24
23
|
@type = parse_node.type
|
25
24
|
end
|
@@ -50,12 +49,12 @@ module HamlLint::Tree
|
|
50
49
|
if next_node
|
51
50
|
next_node.line - 1
|
52
51
|
else
|
53
|
-
@
|
52
|
+
@document.source_lines.count + 1
|
54
53
|
end
|
55
54
|
|
56
|
-
@
|
57
|
-
|
58
|
-
|
55
|
+
@document.source_lines[@line - 1...next_node_line]
|
56
|
+
.join("\n")
|
57
|
+
.gsub(/^\s*\z/m, '') # Remove blank lines at the end
|
59
58
|
end
|
60
59
|
|
61
60
|
def inspect
|
data/lib/haml_lint/utils.rb
CHANGED
@@ -3,56 +3,123 @@ module HamlLint
|
|
3
3
|
module Utils
|
4
4
|
module_function
|
5
5
|
|
6
|
-
#
|
7
|
-
|
8
|
-
|
6
|
+
# Returns whether a glob pattern (or any of a list of patterns) matches the
|
7
|
+
# specified file.
|
8
|
+
#
|
9
|
+
# This is defined here so our file globbing options are consistent
|
10
|
+
# everywhere we perform globbing.
|
11
|
+
#
|
12
|
+
# @param glob [String, Array]
|
13
|
+
# @param file [String]
|
14
|
+
# @return [Boolean]
|
15
|
+
def any_glob_matches?(globs_or_glob, file)
|
16
|
+
Array(globs_or_glob).any? do |glob|
|
17
|
+
::File.fnmatch?(glob, file,
|
18
|
+
::File::FNM_PATHNAME | # Wildcards don't match path separators
|
19
|
+
::File::FNM_DOTMATCH) # `*` wildcard matches dotfiles
|
20
|
+
end
|
21
|
+
end
|
22
|
+
|
23
|
+
# Yields interpolated values within a block of text.
|
24
|
+
#
|
25
|
+
# @param text [String]
|
26
|
+
# @yield Passes interpolated code and line number that code appears on in
|
27
|
+
# the text.
|
28
|
+
# @yieldparam interpolated_code [String] code that was interpolated
|
29
|
+
# @yieldparam line [Integer] line number code appears on in text
|
30
|
+
def extract_interpolated_values(text) # rubocop:disable Metrics/AbcSize
|
31
|
+
dumped_text = text.dump
|
32
|
+
newline_positions = extract_substring_positions(dumped_text, '\\\n')
|
33
|
+
|
34
|
+
Haml::Util.handle_interpolation(dumped_text) do |scan|
|
35
|
+
line = (newline_positions.find_index { |marker| scan.pos <= marker } ||
|
36
|
+
newline_positions.size) + 1
|
37
|
+
|
9
38
|
escape_count = (scan[2].size - 1) / 2
|
10
|
-
|
39
|
+
break unless escape_count.even?
|
11
40
|
|
12
41
|
dumped_interpolated_str = Haml::Util.balance(scan, '{', '}', 1)[0][0...-1]
|
13
42
|
|
14
43
|
# Hacky way to turn a dumped string back into a regular string
|
15
|
-
yield eval('"' + dumped_interpolated_str + '"') # rubocop:disable Eval
|
44
|
+
yield [eval('"' + dumped_interpolated_str + '"'), line] # rubocop:disable Eval
|
16
45
|
end
|
17
46
|
end
|
18
47
|
|
48
|
+
# Returns indexes of all occurrences of a substring within a string.
|
49
|
+
#
|
50
|
+
# Note, this will not return overlaping substrings, so searching for "aa"
|
51
|
+
# in "aaa" will only find one substring, not two.
|
52
|
+
#
|
53
|
+
# @param text [String] the text to search
|
54
|
+
# @param substr [String] the substring to search for
|
55
|
+
# @return [Array<Integer>] list of indexes where the substring occurs
|
56
|
+
def extract_substring_positions(text, substr)
|
57
|
+
positions = []
|
58
|
+
scanner = StringScanner.new(text)
|
59
|
+
positions << scanner.pos while scanner.scan(/(.*?)#{substr}/)
|
60
|
+
positions
|
61
|
+
end
|
62
|
+
|
19
63
|
# Converts a string containing underscores/hyphens/spaces into CamelCase.
|
20
64
|
def camel_case(str)
|
21
65
|
str.split(/_|-| /).map { |part| part.sub(/^\w/) { |c| c.upcase } }.join
|
22
66
|
end
|
23
67
|
|
24
|
-
# Find all consecutive
|
25
|
-
#
|
68
|
+
# Find all consecutive items satisfying the given block of a minimum size,
|
69
|
+
# yielding each group of consecutive items to the provided block.
|
26
70
|
#
|
27
71
|
# @param items [Array]
|
28
|
-
# @param min_size [Fixnum] minimum number of consecutive items before
|
29
|
-
# yielding
|
30
72
|
# @param satisfies [Proc] function that takes an item and returns true/false
|
31
|
-
|
32
|
-
|
73
|
+
# @param min_consecutive [Fixnum] minimum number of consecutive items before
|
74
|
+
# yielding the group
|
75
|
+
# @yield Passes list of consecutive items all matching the criteria defined
|
76
|
+
# by the `satisfies` {Proc} to the provided block
|
77
|
+
# @yieldparam group [Array] List of consecutive items
|
78
|
+
# @yieldreturn [Boolean] block should return whether item matches criteria
|
79
|
+
# for inclusion
|
80
|
+
def for_consecutive_items(items, satisfies, min_consecutive = 2)
|
81
|
+
current_index = -1
|
33
82
|
|
34
|
-
while (
|
35
|
-
next unless satisfies[items[
|
83
|
+
while (current_index += 1) < items.count
|
84
|
+
next unless satisfies[items[current_index]]
|
36
85
|
|
37
|
-
count = count_consecutive(items,
|
38
|
-
next unless count >=
|
86
|
+
count = count_consecutive(items, current_index, &satisfies)
|
87
|
+
next unless count >= min_consecutive
|
39
88
|
|
40
89
|
# Yield the chunk of consecutive items
|
41
|
-
yield items[
|
90
|
+
yield items[current_index...(current_index + count)]
|
42
91
|
|
43
|
-
|
92
|
+
current_index += count # Skip this patch of consecutive items to find more
|
44
93
|
end
|
45
94
|
end
|
46
95
|
|
47
96
|
# Count the number of consecutive items satisfying the given {Proc}.
|
48
97
|
#
|
49
98
|
# @param items [Array]
|
50
|
-
# @param offset [Fixnum] index to start searching
|
51
|
-
# @
|
52
|
-
|
99
|
+
# @param offset [Fixnum] index to start searching from
|
100
|
+
# @yield [item] Passes item to the provided block.
|
101
|
+
# @yieldparam item [Object] Item to evaluate as matching criteria for
|
102
|
+
# inclusion
|
103
|
+
# @yieldreturn [Boolean] whether to include the item
|
104
|
+
# @return [Integer]
|
105
|
+
def count_consecutive(items, offset = 0, &block)
|
53
106
|
count = 1
|
54
|
-
count += 1 while (offset + count < items.count) &&
|
107
|
+
count += 1 while (offset + count < items.count) && block.call(items[offset + count])
|
55
108
|
count
|
56
109
|
end
|
110
|
+
|
111
|
+
# Calls a block of code with a modified set of environment variables,
|
112
|
+
# restoring them once the code has executed.
|
113
|
+
def with_environment(env)
|
114
|
+
old_env = {}
|
115
|
+
env.each do |var, value|
|
116
|
+
old_env[var] = ENV[var.to_s]
|
117
|
+
ENV[var.to_s] = value
|
118
|
+
end
|
119
|
+
|
120
|
+
yield
|
121
|
+
ensure
|
122
|
+
old_env.each { |var, value| ENV[var.to_s] = value }
|
123
|
+
end
|
57
124
|
end
|
58
125
|
end
|
data/lib/haml_lint/version.rb
CHANGED
data/lib/haml_lint.rb
CHANGED
@@ -2,7 +2,7 @@ require 'haml_lint/constants'
|
|
2
2
|
require 'haml_lint/exceptions'
|
3
3
|
require 'haml_lint/configuration'
|
4
4
|
require 'haml_lint/configuration_loader'
|
5
|
-
require 'haml_lint/
|
5
|
+
require 'haml_lint/document'
|
6
6
|
require 'haml_lint/haml_visitor'
|
7
7
|
require 'haml_lint/lint'
|
8
8
|
require 'haml_lint/linter_registry'
|
@@ -11,6 +11,7 @@ require 'haml_lint/linter'
|
|
11
11
|
require 'haml_lint/logger'
|
12
12
|
require 'haml_lint/reporter'
|
13
13
|
require 'haml_lint/report'
|
14
|
+
require 'haml_lint/linter_selector'
|
14
15
|
require 'haml_lint/file_finder'
|
15
16
|
require 'haml_lint/runner'
|
16
17
|
require 'haml_lint/utils'
|
metadata
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: haml_lint
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.
|
4
|
+
version: 0.14.0
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Brigade Engineering
|
@@ -9,7 +9,7 @@ authors:
|
|
9
9
|
autorequire:
|
10
10
|
bindir: bin
|
11
11
|
cert_chain: []
|
12
|
-
date: 2015-
|
12
|
+
date: 2015-06-09 00:00:00.000000000 Z
|
13
13
|
dependencies:
|
14
14
|
- !ruby/object:Gem::Dependency
|
15
15
|
name: haml
|
@@ -97,6 +97,7 @@ files:
|
|
97
97
|
- lib/haml_lint/configuration.rb
|
98
98
|
- lib/haml_lint/configuration_loader.rb
|
99
99
|
- lib/haml_lint/constants.rb
|
100
|
+
- lib/haml_lint/document.rb
|
100
101
|
- lib/haml_lint/exceptions.rb
|
101
102
|
- lib/haml_lint/file_finder.rb
|
102
103
|
- lib/haml_lint/haml_visitor.rb
|
@@ -124,18 +125,18 @@ files:
|
|
124
125
|
- lib/haml_lint/linter/unnecessary_interpolation.rb
|
125
126
|
- lib/haml_lint/linter/unnecessary_string_output.rb
|
126
127
|
- lib/haml_lint/linter_registry.rb
|
128
|
+
- lib/haml_lint/linter_selector.rb
|
127
129
|
- lib/haml_lint/logger.rb
|
128
130
|
- lib/haml_lint/node_transformer.rb
|
129
131
|
- lib/haml_lint/options.rb
|
130
|
-
- lib/haml_lint/parser.rb
|
131
132
|
- lib/haml_lint/rake_task.rb
|
132
133
|
- lib/haml_lint/report.rb
|
133
134
|
- lib/haml_lint/reporter.rb
|
134
135
|
- lib/haml_lint/reporter/default_reporter.rb
|
135
136
|
- lib/haml_lint/reporter/json_reporter.rb
|
137
|
+
- lib/haml_lint/ruby_extractor.rb
|
136
138
|
- lib/haml_lint/ruby_parser.rb
|
137
139
|
- lib/haml_lint/runner.rb
|
138
|
-
- lib/haml_lint/script_extractor.rb
|
139
140
|
- lib/haml_lint/tree/comment_node.rb
|
140
141
|
- lib/haml_lint/tree/doctype_node.rb
|
141
142
|
- lib/haml_lint/tree/filter_node.rb
|
data/lib/haml_lint/parser.rb
DELETED
@@ -1,87 +0,0 @@
|
|
1
|
-
require 'haml'
|
2
|
-
|
3
|
-
module HamlLint
|
4
|
-
# Parses a HAML document for inspection by linters.
|
5
|
-
class Parser
|
6
|
-
attr_reader :contents, :filename, :lines, :tree
|
7
|
-
|
8
|
-
# Creates a parser containing the parse tree of a HAML document.
|
9
|
-
#
|
10
|
-
# @param haml_or_filename [String]
|
11
|
-
# @param options [Hash]
|
12
|
-
# @option options [true,false] 'skip_frontmatter' Whether to skip
|
13
|
-
# frontmatter included by frameworks such as Middleman or Jekyll
|
14
|
-
def initialize(haml_or_filename, options = {})
|
15
|
-
if File.exist?(haml_or_filename)
|
16
|
-
build_from_file(haml_or_filename)
|
17
|
-
else
|
18
|
-
build_from_string(haml_or_filename)
|
19
|
-
end
|
20
|
-
|
21
|
-
process_options(options)
|
22
|
-
|
23
|
-
build_parse_tree
|
24
|
-
end
|
25
|
-
|
26
|
-
private
|
27
|
-
|
28
|
-
# @param path [String]
|
29
|
-
def build_from_file(path)
|
30
|
-
@filename = path
|
31
|
-
@contents = File.read(path)
|
32
|
-
end
|
33
|
-
|
34
|
-
# @param haml [String]
|
35
|
-
def build_from_string(haml)
|
36
|
-
@contents = haml
|
37
|
-
end
|
38
|
-
|
39
|
-
def build_parse_tree
|
40
|
-
original_tree = Haml::Parser.new(@contents, Haml::Options.new).parse
|
41
|
-
|
42
|
-
# Remove the trailing empty HAML comment that the parser creates to signal
|
43
|
-
# the end of the HAML document
|
44
|
-
if Gem::Requirement.new('~> 4.0.0').satisfied_by?(Gem.loaded_specs['haml'].version)
|
45
|
-
original_tree.children.pop
|
46
|
-
end
|
47
|
-
|
48
|
-
@node_transformer = HamlLint::NodeTransformer.new(self)
|
49
|
-
@tree = convert_tree(original_tree)
|
50
|
-
end
|
51
|
-
|
52
|
-
def process_options(options)
|
53
|
-
if options['skip_frontmatter'] &&
|
54
|
-
@contents =~ /
|
55
|
-
# From the start of the string
|
56
|
-
\A
|
57
|
-
# First-capture match --- followed by optional whitespace up
|
58
|
-
# to a newline then 0 or more chars followed by an optional newline.
|
59
|
-
# This matches the --- and the contents of the frontmatter
|
60
|
-
(---\s*\n.*?\n?)
|
61
|
-
# From the start of the line
|
62
|
-
^
|
63
|
-
# Second capture match --- or ... followed by optional whitespace
|
64
|
-
# and newline. This matches the closing --- for the frontmatter.
|
65
|
-
(---|\.\.\.)\s*$\n?/mx
|
66
|
-
@contents = $POSTMATCH
|
67
|
-
end
|
68
|
-
|
69
|
-
@lines = @contents.split("\n")
|
70
|
-
end
|
71
|
-
|
72
|
-
# Converts a HAML parse tree to a tree of {HamlLint::Tree::Node} objects.
|
73
|
-
#
|
74
|
-
# This provides a cleaner interface with which the linters can interact with
|
75
|
-
# the parse tree.
|
76
|
-
def convert_tree(haml_node, parent = nil)
|
77
|
-
new_node = @node_transformer.transform(haml_node)
|
78
|
-
new_node.parent = parent
|
79
|
-
|
80
|
-
new_node.children = haml_node.children.map do |child|
|
81
|
-
convert_tree(child, new_node)
|
82
|
-
end
|
83
|
-
|
84
|
-
new_node
|
85
|
-
end
|
86
|
-
end
|
87
|
-
end
|