mdl 0.9.0 → 0.10.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/bin/mdl +2 -2
- data/lib/mdl.rb +41 -32
- data/lib/mdl/cli.rb +92 -90
- data/lib/mdl/config.rb +2 -1
- data/lib/mdl/doc.rb +45 -54
- data/lib/mdl/kramdown_parser.rb +1 -1
- data/lib/mdl/rules.rb +206 -167
- data/lib/mdl/ruleset.rb +11 -10
- data/lib/mdl/style.rb +18 -16
- data/lib/mdl/styles/cirosantilli.rb +2 -2
- data/lib/mdl/styles/default.rb +1 -1
- data/lib/mdl/version.rb +1 -1
- data/mdl.gemspec +20 -18
- metadata +63 -35
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 870d0bc411951c203fcf0e352e6e903e4f7008b17543259dea919ea5780042fc
|
4
|
+
data.tar.gz: f796b7b245267e16f5e7e4d5be79b030b3f6775987f1df6838c526c4a7f7b58f
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 85bfc0cf05053e6bfc9aaa1c8f62c2fc1f99ba8f9b450c262fc1716de529e934e2cac5cb23c77c7a6c49ec33c7bddcc8c9e3cf17964c3b426695dafb4dbcd51f
|
7
|
+
data.tar.gz: '013659e46c8ec5ce00c4d8a096853badf15da2a0396cd33119f84a603eb525e62a4a44fadc04fc24c282c8a55cda90c811146b39a17db2eb28a744209ace5b15'
|
data/bin/mdl
CHANGED
@@ -3,8 +3,8 @@ begin
|
|
3
3
|
require 'mdl'
|
4
4
|
rescue LoadError
|
5
5
|
# For running in development without bundler
|
6
|
-
|
6
|
+
$LOAD_PATH << File.expand_path('../lib', File.dirname(__FILE__))
|
7
7
|
require 'mdl'
|
8
8
|
end
|
9
9
|
|
10
|
-
MarkdownLint
|
10
|
+
MarkdownLint.run
|
data/lib/mdl.rb
CHANGED
@@ -7,50 +7,55 @@ require_relative 'mdl/style'
|
|
7
7
|
require_relative 'mdl/version'
|
8
8
|
|
9
9
|
require 'kramdown'
|
10
|
+
require 'mixlib/shellout'
|
10
11
|
|
12
|
+
# Primary MDL container
|
11
13
|
module MarkdownLint
|
12
|
-
def self.run(argv=ARGV)
|
14
|
+
def self.run(argv = ARGV)
|
13
15
|
cli = MarkdownLint::CLI.new
|
14
16
|
cli.run(argv)
|
15
17
|
ruleset = RuleSet.new
|
16
|
-
unless Config[:skip_default_ruleset]
|
17
|
-
|
18
|
-
|
19
|
-
unless Config[:rulesets].nil?
|
20
|
-
Config[:rulesets].each do |r|
|
21
|
-
ruleset.load(r)
|
22
|
-
end
|
18
|
+
ruleset.load_default unless Config[:skip_default_ruleset]
|
19
|
+
Config[:rulesets]&.each do |r|
|
20
|
+
ruleset.load(r)
|
23
21
|
end
|
24
22
|
rules = ruleset.rules
|
25
23
|
Style.load(Config[:style], rules)
|
26
24
|
# Rule option filter
|
27
25
|
if Config[:rules]
|
28
|
-
|
29
|
-
|
30
|
-
|
31
|
-
|
32
|
-
|
33
|
-
|
26
|
+
unless Config[:rules][:include].empty?
|
27
|
+
rules.select! do |r, v|
|
28
|
+
Config[:rules][:include].include?(r) or
|
29
|
+
!(Config[:rules][:include] & v.aliases).empty?
|
30
|
+
end
|
31
|
+
end
|
32
|
+
unless Config[:rules][:exclude].empty?
|
33
|
+
rules.select! do |r, v|
|
34
|
+
!Config[:rules][:exclude].include?(r) and
|
35
|
+
(Config[:rules][:exclude] & v.aliases).empty?
|
36
|
+
end
|
37
|
+
end
|
34
38
|
end
|
35
39
|
# Tag option filter
|
36
40
|
if Config[:tags]
|
37
|
-
rules.
|
41
|
+
rules.reject! { |_r, v| (v.tags & Config[:tags][:include]).empty? } \
|
38
42
|
unless Config[:tags][:include].empty?
|
39
|
-
rules.select! {|
|
43
|
+
rules.select! { |_r, v| (v.tags & Config[:tags][:exclude]).empty? } \
|
40
44
|
unless Config[:tags][:exclude].empty?
|
41
45
|
end
|
42
46
|
|
43
47
|
if Config[:list_rules]
|
44
|
-
puts
|
45
|
-
|
46
|
-
|
47
|
-
|
48
|
-
|
49
|
-
|
50
|
-
|
51
|
-
|
52
|
-
|
48
|
+
puts 'Enabled rules:'
|
49
|
+
rules.each do |id, rule|
|
50
|
+
if Config[:verbose]
|
51
|
+
puts "#{id} (#{rule.aliases.join(', ')}) [#{rule.tags.join(', ')}] " +
|
52
|
+
"- #{rule.description}"
|
53
|
+
elsif Config[:show_aliases]
|
54
|
+
puts "#{rule.aliases.first || id} - #{rule.description}"
|
55
|
+
else
|
56
|
+
puts "#{id} - #{rule.description}"
|
53
57
|
end
|
58
|
+
end
|
54
59
|
exit 0
|
55
60
|
end
|
56
61
|
|
@@ -59,7 +64,9 @@ module MarkdownLint
|
|
59
64
|
if Dir.exist?(filename)
|
60
65
|
if Config[:git_recurse]
|
61
66
|
Dir.chdir(filename) do
|
62
|
-
cli.cli_arguments[i] =
|
67
|
+
cli.cli_arguments[i] =
|
68
|
+
Mixlib::ShellOut.new("git ls-files '*.md' '*.markdown'")
|
69
|
+
.run_command.stdout.lines
|
63
70
|
end
|
64
71
|
else
|
65
72
|
cli.cli_arguments[i] = Dir["#{filename}/**/*.{md,markdown}"]
|
@@ -73,9 +80,9 @@ module MarkdownLint
|
|
73
80
|
cli.cli_arguments.each do |filename|
|
74
81
|
puts "Checking #{filename}..." if Config[:verbose]
|
75
82
|
doc = Doc.new_from_file(filename, Config[:ignore_front_matter])
|
76
|
-
filename = '(stdin)' if filename ==
|
83
|
+
filename = '(stdin)' if filename == '-'
|
77
84
|
if Config[:show_kramdown_warnings]
|
78
|
-
status = 2
|
85
|
+
status = 2 unless doc.parsed.warnings.empty?
|
79
86
|
doc.parsed.warnings.each do |w|
|
80
87
|
puts "#{filename}: Kramdown Warning: #{w}"
|
81
88
|
end
|
@@ -83,7 +90,8 @@ module MarkdownLint
|
|
83
90
|
rules.sort.each do |id, rule|
|
84
91
|
puts "Processing rule #{id}" if Config[:verbose]
|
85
92
|
error_lines = rule.check.call(doc)
|
86
|
-
next if error_lines.nil?
|
93
|
+
next if error_lines.nil? || error_lines.empty?
|
94
|
+
|
87
95
|
status = 1
|
88
96
|
error_lines.each do |line|
|
89
97
|
line += doc.offset # Correct line numbers for any yaml front matter
|
@@ -96,7 +104,8 @@ module MarkdownLint
|
|
96
104
|
'description' => rule.description,
|
97
105
|
}
|
98
106
|
elsif Config[:show_aliases]
|
99
|
-
puts "#{filename}:#{line}: #{rule.aliases.first || id}
|
107
|
+
puts "#{filename}:#{line}: #{rule.aliases.first || id} " +
|
108
|
+
rule.description.to_s
|
100
109
|
else
|
101
110
|
puts "#{filename}:#{line}: #{id} #{rule.description}"
|
102
111
|
end
|
@@ -108,8 +117,8 @@ module MarkdownLint
|
|
108
117
|
require 'json'
|
109
118
|
puts JSON.generate(results)
|
110
119
|
elsif status != 0
|
111
|
-
puts "\nA detailed description of the rules is available at "
|
112
|
-
|
120
|
+
puts "\nA detailed description of the rules is available at " +
|
121
|
+
'https://github.com/markdownlint/markdownlint/blob/master/docs/RULES.md'
|
113
122
|
end
|
114
123
|
exit status
|
115
124
|
end
|
data/lib/mdl/cli.rb
CHANGED
@@ -2,124 +2,125 @@ require 'mixlib/cli'
|
|
2
2
|
require 'pathname'
|
3
3
|
|
4
4
|
module MarkdownLint
|
5
|
+
# Our Mixlib::CLI class
|
5
6
|
class CLI
|
6
7
|
include Mixlib::CLI
|
7
8
|
|
8
|
-
CONFIG_FILE = '.mdlrc'
|
9
|
+
CONFIG_FILE = '.mdlrc'.freeze
|
9
10
|
|
10
|
-
banner "Usage: #{File.basename($
|
11
|
+
banner "Usage: #{File.basename($PROGRAM_NAME)} [options] [FILE.md|DIR ...]"
|
11
12
|
|
12
13
|
option :show_aliases,
|
13
|
-
|
14
|
-
|
15
|
-
|
16
|
-
|
14
|
+
:short => '-a',
|
15
|
+
:long => '--[no-]show-aliases',
|
16
|
+
:description =>
|
17
|
+
'Show rule alias instead of rule ID when viewing rules',
|
18
|
+
:boolean => true
|
17
19
|
|
18
20
|
option :config_file,
|
19
|
-
|
20
|
-
|
21
|
-
|
22
|
-
|
21
|
+
:short => '-c',
|
22
|
+
:long => '--config FILE',
|
23
|
+
:description => 'The configuration file to use',
|
24
|
+
:default => CONFIG_FILE.to_s
|
23
25
|
|
24
26
|
option :verbose,
|
25
|
-
|
26
|
-
|
27
|
-
|
28
|
-
|
27
|
+
:short => '-v',
|
28
|
+
:long => '--[no-]verbose',
|
29
|
+
:description => 'Increase verbosity',
|
30
|
+
:boolean => true
|
29
31
|
|
30
32
|
option :ignore_front_matter,
|
31
|
-
|
32
|
-
|
33
|
-
|
34
|
-
|
33
|
+
:short => '-i',
|
34
|
+
:long => '--[no-]ignore-front-matter',
|
35
|
+
:boolean => true,
|
36
|
+
:description => 'Ignore YAML front matter'
|
35
37
|
|
36
38
|
option :show_kramdown_warnings,
|
37
|
-
|
38
|
-
|
39
|
-
|
40
|
-
|
39
|
+
:short => '-w',
|
40
|
+
:long => '--[no-]warnings',
|
41
|
+
:description => 'Show kramdown warnings',
|
42
|
+
:boolean => true
|
41
43
|
|
42
44
|
option :tags,
|
43
|
-
|
44
|
-
|
45
|
-
|
46
|
-
|
45
|
+
:short => '-t',
|
46
|
+
:long => '--tags TAG1,TAG2',
|
47
|
+
:description => 'Only process rules with these tags',
|
48
|
+
:proc => proc { |v| toggle_list(v, true) }
|
47
49
|
|
48
50
|
option :rules,
|
49
|
-
|
50
|
-
|
51
|
-
|
52
|
-
|
51
|
+
:short => '-r',
|
52
|
+
:long => '--rules RULE1,RULE2',
|
53
|
+
:description => 'Only process these rules',
|
54
|
+
:proc => proc { |v| toggle_list(v) }
|
53
55
|
|
54
56
|
option :style,
|
55
|
-
|
56
|
-
|
57
|
-
|
57
|
+
:short => '-s',
|
58
|
+
:long => '--style STYLE',
|
59
|
+
:description => 'Load the given style'
|
58
60
|
|
59
61
|
option :list_rules,
|
60
|
-
|
61
|
-
|
62
|
-
|
63
|
-
|
62
|
+
:short => '-l',
|
63
|
+
:long => '--list-rules',
|
64
|
+
:boolean => true,
|
65
|
+
:description => "Don't process any files, just list enabled rules"
|
64
66
|
|
65
67
|
option :git_recurse,
|
66
|
-
|
67
|
-
|
68
|
-
|
69
|
-
|
68
|
+
:short => '-g',
|
69
|
+
:long => '--git-recurse',
|
70
|
+
:boolean => true,
|
71
|
+
:description =>
|
72
|
+
'Only process files known to git when given a directory'
|
70
73
|
|
71
74
|
option :rulesets,
|
72
|
-
|
73
|
-
|
74
|
-
|
75
|
-
|
75
|
+
:short => '-u',
|
76
|
+
:long => '--rulesets RULESET1,RULESET2',
|
77
|
+
:proc => proc { |v| v.split(',') },
|
78
|
+
:description => 'Specify additional ruleset files to load'
|
76
79
|
|
77
80
|
option :skip_default_ruleset,
|
78
|
-
|
79
|
-
|
80
|
-
|
81
|
-
|
81
|
+
:short => '-d',
|
82
|
+
:long => '--skip-default-ruleset',
|
83
|
+
:boolean => true,
|
84
|
+
:description => "Don't load the default markdownlint ruleset"
|
82
85
|
|
83
86
|
option :help,
|
84
|
-
|
85
|
-
|
86
|
-
|
87
|
-
|
88
|
-
|
89
|
-
|
90
|
-
|
87
|
+
:on => :tail,
|
88
|
+
:short => '-h',
|
89
|
+
:long => '--help',
|
90
|
+
:description => 'Show this message',
|
91
|
+
:boolean => true,
|
92
|
+
:show_options => true,
|
93
|
+
:exit => 0
|
91
94
|
|
92
95
|
option :version,
|
93
|
-
|
94
|
-
|
95
|
-
|
96
|
-
|
97
|
-
|
98
|
-
|
99
|
-
|
96
|
+
:on => :tail,
|
97
|
+
:short => '-V',
|
98
|
+
:long => '--version',
|
99
|
+
:description => 'Show version',
|
100
|
+
:boolean => true,
|
101
|
+
:proc => proc { puts MarkdownLint::VERSION },
|
102
|
+
:exit => 0
|
100
103
|
|
101
104
|
option :json,
|
102
|
-
|
103
|
-
|
104
|
-
|
105
|
-
|
105
|
+
:short => '-j',
|
106
|
+
:long => '--json',
|
107
|
+
:description => 'JSON output',
|
108
|
+
:boolean => true
|
106
109
|
|
107
|
-
def run(argv=ARGV)
|
110
|
+
def run(argv = ARGV)
|
108
111
|
parse_options(argv)
|
109
112
|
|
110
113
|
# Load the config file if it's present
|
111
114
|
filename = CLI.probe_config_file(config[:config_file])
|
112
115
|
|
113
116
|
# Only fall back to ~/.mdlrc if we are using the default value for -c
|
114
|
-
if filename.nil?
|
117
|
+
if filename.nil? && (config[:config_file] == CONFIG_FILE)
|
115
118
|
filename = File.expand_path("~/#{CONFIG_FILE}")
|
116
119
|
end
|
117
120
|
|
118
|
-
if
|
121
|
+
if !filename.nil? && File.exist?(filename)
|
119
122
|
MarkdownLint::Config.from_file(filename.to_s)
|
120
|
-
if config[:verbose]
|
121
|
-
puts "Loaded config from #{filename}"
|
122
|
-
end
|
123
|
+
puts "Loaded config from #{filename}" if config[:verbose]
|
123
124
|
end
|
124
125
|
|
125
126
|
# Put values in the config file
|
@@ -128,30 +129,31 @@ module MarkdownLint
|
|
128
129
|
# Set the correct format for any rules/tags configuration loaded from
|
129
130
|
# the config file. Ideally this would probably be done as part of the
|
130
131
|
# config class itself rather than here.
|
131
|
-
MarkdownLint::Config[:rules]
|
132
|
-
MarkdownLint::Config[:rules]
|
133
|
-
|
134
|
-
|
135
|
-
|
132
|
+
unless MarkdownLint::Config[:rules].nil?
|
133
|
+
MarkdownLint::Config[:rules] = CLI.toggle_list(
|
134
|
+
MarkdownLint::Config[:rules],
|
135
|
+
)
|
136
|
+
end
|
137
|
+
unless MarkdownLint::Config[:tags].nil?
|
138
|
+
MarkdownLint::Config[:tags] = CLI.toggle_list(
|
139
|
+
MarkdownLint::Config[:tags], true
|
140
|
+
)
|
141
|
+
end
|
136
142
|
|
137
143
|
# Read from stdin if we didn't provide a filename
|
138
|
-
if cli_arguments.empty?
|
139
|
-
cli_arguments << "-"
|
140
|
-
end
|
144
|
+
cli_arguments << '-' if cli_arguments.empty? && !config[:list_rules]
|
141
145
|
end
|
142
146
|
|
143
|
-
def self.toggle_list(parts, to_sym=false)
|
144
|
-
if parts.class == String
|
145
|
-
parts = parts.split(',')
|
146
|
-
end
|
147
|
+
def self.toggle_list(parts, to_sym = false)
|
148
|
+
parts = parts.split(',') if parts.class == String
|
147
149
|
if parts.class == Array
|
148
|
-
inc = parts.
|
149
|
-
exc = parts.select{|p| p.start_with?('~')}.map{|p| p[1..-1]}
|
150
|
+
inc = parts.reject { |p| p.start_with?('~') }
|
151
|
+
exc = parts.select { |p| p.start_with?('~') }.map { |p| p[1..-1] }
|
150
152
|
if to_sym
|
151
|
-
inc.map!
|
152
|
-
exc.map!
|
153
|
+
inc.map!(&:to_sym)
|
154
|
+
exc.map!(&:to_sym)
|
153
155
|
end
|
154
|
-
{:include => inc, :exclude => exc}
|
156
|
+
{ :include => inc, :exclude => exc }
|
155
157
|
else
|
156
158
|
# We already converted the string into a list of include/exclude
|
157
159
|
# pairs, so just return as is
|
data/lib/mdl/config.rb
CHANGED
data/lib/mdl/doc.rb
CHANGED
@@ -4,7 +4,6 @@ require_relative 'kramdown_parser'
|
|
4
4
|
module MarkdownLint
|
5
5
|
##
|
6
6
|
# Representation of the markdown document passed to rule checks
|
7
|
-
|
8
7
|
class Doc
|
9
8
|
##
|
10
9
|
# A list of raw markdown source lines. Note that the list is 0-indexed,
|
@@ -12,32 +11,26 @@ module MarkdownLint
|
|
12
11
|
# subtract 1 from a line number to get the correct line. The element_line*
|
13
12
|
# methods take care of this for you.
|
14
13
|
|
15
|
-
attr_reader :lines
|
14
|
+
attr_reader :lines, :parsed, :elements, :offset
|
16
15
|
|
17
16
|
##
|
18
17
|
# A Kramdown::Document object containing the parsed markdown document.
|
19
18
|
|
20
|
-
attr_reader :parsed
|
21
|
-
|
22
19
|
##
|
23
20
|
# A list of top level Kramdown::Element objects from the parsed document.
|
24
21
|
|
25
|
-
attr_reader :elements
|
26
|
-
|
27
22
|
##
|
28
23
|
# The line number offset which is greater than zero when the
|
29
24
|
# markdown file contains YAML front matter that should be ignored.
|
30
25
|
|
31
|
-
attr_reader :offset
|
32
|
-
|
33
26
|
##
|
34
27
|
# Create a new document given a string containing the markdown source
|
35
28
|
|
36
29
|
def initialize(text, ignore_front_matter = false)
|
37
30
|
regex = /^---\n(.*?)---\n\n?/m
|
38
|
-
if ignore_front_matter
|
31
|
+
if ignore_front_matter && regex.match(text)
|
39
32
|
@offset = regex.match(text).to_s.split("\n").length
|
40
|
-
text.sub!(regex,'')
|
33
|
+
text.sub!(regex, '')
|
41
34
|
else
|
42
35
|
@offset = 0
|
43
36
|
end
|
@@ -51,10 +44,10 @@ module MarkdownLint
|
|
51
44
|
# Alternate 'constructor' passing in a filename
|
52
45
|
|
53
46
|
def self.new_from_file(filename, ignore_front_matter = false)
|
54
|
-
if filename ==
|
55
|
-
|
47
|
+
if filename == '-'
|
48
|
+
new($stdin.read, ignore_front_matter)
|
56
49
|
else
|
57
|
-
|
50
|
+
new(File.read(filename, :encoding => 'UTF-8'), ignore_front_matter)
|
58
51
|
end
|
59
52
|
end
|
60
53
|
|
@@ -69,8 +62,8 @@ module MarkdownLint
|
|
69
62
|
# If +nested+ is set to false, this returns only top level elements of a
|
70
63
|
# given type.
|
71
64
|
|
72
|
-
def find_type(type, nested=true)
|
73
|
-
find_type_elements(type, nested).map
|
65
|
+
def find_type(type, nested = true)
|
66
|
+
find_type_elements(type, nested).map(&:options)
|
74
67
|
end
|
75
68
|
|
76
69
|
##
|
@@ -83,14 +76,12 @@ module MarkdownLint
|
|
83
76
|
# If +nested+ is set to false, this returns only top level elements of a
|
84
77
|
# given type.
|
85
78
|
|
86
|
-
def find_type_elements(type, nested=true, elements
|
79
|
+
def find_type_elements(type, nested = true, elements = @elements)
|
87
80
|
results = []
|
88
|
-
if type.class == Symbol
|
89
|
-
type = [type]
|
90
|
-
end
|
81
|
+
type = [type] if type.class == Symbol
|
91
82
|
elements.each do |e|
|
92
83
|
results.push(e) if type.include?(e.type)
|
93
|
-
if nested
|
84
|
+
if nested && !e.children.empty?
|
94
85
|
results.concat(find_type_elements(type, nested, e.children))
|
95
86
|
end
|
96
87
|
end
|
@@ -107,19 +98,19 @@ module MarkdownLint
|
|
107
98
|
# Unlike find_type_elements, this method will always search for nested
|
108
99
|
# elements, and skip the element types given to nested_except.
|
109
100
|
|
110
|
-
def find_type_elements_except(
|
101
|
+
def find_type_elements_except(
|
102
|
+
type, nested_except = [], elements = @elements
|
103
|
+
)
|
111
104
|
results = []
|
112
|
-
if type.class == Symbol
|
113
|
-
|
114
|
-
end
|
115
|
-
if nested_except.class == Symbol
|
116
|
-
nested_except = [nested_except]
|
117
|
-
end
|
105
|
+
type = [type] if type.class == Symbol
|
106
|
+
nested_except = [nested_except] if nested_except.class == Symbol
|
118
107
|
elements.each do |e|
|
119
108
|
results.push(e) if type.include?(e.type)
|
120
|
-
|
121
|
-
|
122
|
-
|
109
|
+
next if nested_except.include?(e.type) || e.children.empty?
|
110
|
+
|
111
|
+
results.concat(
|
112
|
+
find_type_elements_except(type, nested_except, e.children),
|
113
|
+
)
|
123
114
|
end
|
124
115
|
results
|
125
116
|
end
|
@@ -167,11 +158,12 @@ module MarkdownLint
|
|
167
158
|
|
168
159
|
def header_style(header)
|
169
160
|
if header.type != :header
|
170
|
-
raise
|
161
|
+
raise 'header_style called with non-header element'
|
171
162
|
end
|
163
|
+
|
172
164
|
line = element_line(header)
|
173
|
-
if line.start_with?(
|
174
|
-
if line.strip.end_with?(
|
165
|
+
if line.start_with?('#')
|
166
|
+
if line.strip.end_with?('#')
|
175
167
|
:atx_closed
|
176
168
|
else
|
177
169
|
:atx
|
@@ -187,10 +179,9 @@ module MarkdownLint
|
|
187
179
|
# item. You can pass in either the element itself or an options hash here.
|
188
180
|
|
189
181
|
def list_style(item)
|
190
|
-
if item.type != :li
|
191
|
-
|
192
|
-
|
193
|
-
line = element_line(item).strip.gsub(/^>\s+/,'')
|
182
|
+
raise 'list_style called with non-list element' if item.type != :li
|
183
|
+
|
184
|
+
line = element_line(item).strip.gsub(/^>\s+/, '')
|
194
185
|
if line.start_with?('*')
|
195
186
|
:asterisk
|
196
187
|
elsif line.start_with?('+')
|
@@ -211,22 +202,24 @@ module MarkdownLint
|
|
211
202
|
# indent of 8 spaces. You need to pass in the raw string here.
|
212
203
|
|
213
204
|
def indent_for(line)
|
214
|
-
|
205
|
+
line.match(/^\s*/)[0].gsub("\t", ' ' * 8).length
|
215
206
|
end
|
216
207
|
|
217
208
|
##
|
218
209
|
# Returns line numbers for lines that match the given regular expression
|
219
210
|
|
220
|
-
def matching_lines(
|
221
|
-
@lines.each_with_index.select{|text,
|
222
|
-
|
211
|
+
def matching_lines(regex)
|
212
|
+
@lines.each_with_index.select { |text, _linenum| regex.match(text) }
|
213
|
+
.map do |i|
|
214
|
+
i[1] + 1
|
215
|
+
end
|
223
216
|
end
|
224
217
|
|
225
218
|
##
|
226
219
|
# Returns line numbers for lines that match the given regular expression.
|
227
220
|
# Only considers text inside of 'text' elements (i.e. regular markdown
|
228
221
|
# text and not code/links or other elements).
|
229
|
-
def matching_text_element_lines(
|
222
|
+
def matching_text_element_lines(regex, exclude_nested = [:a])
|
230
223
|
matches = []
|
231
224
|
find_type_elements_except(:text, exclude_nested).each do |e|
|
232
225
|
first_line = e.options[:location]
|
@@ -234,9 +227,10 @@ module MarkdownLint
|
|
234
227
|
# the current element. It's better to just not match in these cases
|
235
228
|
# rather than crash.
|
236
229
|
next if first_line.nil?
|
230
|
+
|
237
231
|
lines = e.value.split("\n")
|
238
232
|
lines.each_with_index do |l, i|
|
239
|
-
matches << first_line + i if
|
233
|
+
matches << first_line + i if regex.match(l)
|
240
234
|
end
|
241
235
|
end
|
242
236
|
matches
|
@@ -246,31 +240,29 @@ module MarkdownLint
|
|
246
240
|
# Extracts the text from an element whose children consist of text
|
247
241
|
# elements and other things
|
248
242
|
|
249
|
-
def extract_text(element, prefix=
|
243
|
+
def extract_text(element, prefix = '', restore_whitespace = true)
|
250
244
|
quotes = {
|
251
245
|
:rdquo => '"',
|
252
246
|
:ldquo => '"',
|
253
247
|
:lsquo => "'",
|
254
|
-
:rsquo => "'"
|
248
|
+
:rsquo => "'",
|
255
249
|
}
|
256
250
|
# If anything goes amiss here, e.g. unknown type, then nil will be
|
257
251
|
# returned and we'll just not catch that part of the text, which seems
|
258
252
|
# like a sensible failure mode.
|
259
|
-
lines = element.children.map
|
253
|
+
lines = element.children.map do |e|
|
260
254
|
if e.type == :text
|
261
255
|
e.value
|
262
|
-
elsif
|
256
|
+
elsif %i{strong em p codespan}.include?(e.type)
|
263
257
|
extract_text(e, prefix, restore_whitespace).join("\n")
|
264
258
|
elsif e.type == :smart_quote
|
265
259
|
quotes[e.value]
|
266
260
|
end
|
267
|
-
|
261
|
+
end.join.split("\n")
|
268
262
|
# Text blocks have whitespace stripped, so we need to add it back in at
|
269
263
|
# the beginning. Because this might be in something like a blockquote,
|
270
264
|
# we optionally strip off a prefix given to the function.
|
271
|
-
if restore_whitespace
|
272
|
-
lines[0] = element_line(element).sub(prefix, "")
|
273
|
-
end
|
265
|
+
lines[0] = element_line(element).sub(prefix, '') if restore_whitespace
|
274
266
|
lines
|
275
267
|
end
|
276
268
|
|
@@ -280,13 +272,12 @@ module MarkdownLint
|
|
280
272
|
# Adds a 'level' and 'parent' option to all elements to show how nested they
|
281
273
|
# are
|
282
274
|
|
283
|
-
def add_annotations(elements, level=1, parent=nil)
|
275
|
+
def add_annotations(elements, level = 1, parent = nil)
|
284
276
|
elements.each do |e|
|
285
277
|
e.options[:element_level] = level
|
286
278
|
e.options[:parent] = parent
|
287
|
-
add_annotations(e.children, level+1, e)
|
279
|
+
add_annotations(e.children, level + 1, e)
|
288
280
|
end
|
289
281
|
end
|
290
|
-
|
291
282
|
end
|
292
283
|
end
|