markdown_formatter 1.0.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +7 -0
- checksums.yaml.gz.sig +0 -0
- data.tar.gz.sig +1 -0
- data/.gitignore +12 -0
- data/.rspec +3 -0
- data/.travis.yml +5 -0
- data/Gemfile +4 -0
- data/LICENSE.txt +21 -0
- data/README.md +46 -0
- data/Rakefile +6 -0
- data/bin/console +14 -0
- data/bin/setup +8 -0
- data/exe/mdfmt +27 -0
- data/lib/markdown_formatter.rb +57 -0
- data/lib/markdown_formatter/ast.rb +47 -0
- data/lib/markdown_formatter/cli.rb +13 -0
- data/lib/markdown_formatter/nodes/base.rb +11 -0
- data/lib/markdown_formatter/nodes/blank.rb +9 -0
- data/lib/markdown_formatter/nodes/block_quote.rb +22 -0
- data/lib/markdown_formatter/nodes/code_block.rb +9 -0
- data/lib/markdown_formatter/nodes/code_span.rb +9 -0
- data/lib/markdown_formatter/nodes/container_block.rb +23 -0
- data/lib/markdown_formatter/nodes/emphasis.rb +10 -0
- data/lib/markdown_formatter/nodes/entity.rb +9 -0
- data/lib/markdown_formatter/nodes/footnote.rb +9 -0
- data/lib/markdown_formatter/nodes/header.rb +9 -0
- data/lib/markdown_formatter/nodes/html_element.rb +9 -0
- data/lib/markdown_formatter/nodes/image.rb +9 -0
- data/lib/markdown_formatter/nodes/inline.rb +29 -0
- data/lib/markdown_formatter/nodes/leaf_block.rb +27 -0
- data/lib/markdown_formatter/nodes/link.rb +9 -0
- data/lib/markdown_formatter/nodes/list.rb +23 -0
- data/lib/markdown_formatter/nodes/list_item.rb +38 -0
- data/lib/markdown_formatter/nodes/paragraph.rb +39 -0
- data/lib/markdown_formatter/nodes/smart_quote.rb +14 -0
- data/lib/markdown_formatter/nodes/strong.rb +10 -0
- data/lib/markdown_formatter/nodes/thematic_break.rb +9 -0
- data/lib/markdown_formatter/nodes/typographic_sym.rb +9 -0
- data/lib/markdown_formatter/version.rb +3 -0
- data/lib/monkey_patches/kramdown/parser/gfm.rb +21 -0
- data/lib/monkey_patches/kramdown/parser/kramdown/autolink.rb +16 -0
- data/lib/monkey_patches/kramdown/parser/kramdown/blockquote.rb +22 -0
- data/lib/monkey_patches/kramdown/parser/kramdown/code_block.rb +34 -0
- data/lib/monkey_patches/kramdown/parser/kramdown/code_span.rb +31 -0
- data/lib/monkey_patches/kramdown/parser/kramdown/emphasis.rb +48 -0
- data/lib/monkey_patches/kramdown/parser/kramdown/escaped_chars.rb +12 -0
- data/lib/monkey_patches/kramdown/parser/kramdown/footnote.rb +27 -0
- data/lib/monkey_patches/kramdown/parser/kramdown/header.rb +38 -0
- data/lib/monkey_patches/kramdown/parser/kramdown/horizontal_rule.rb +14 -0
- data/lib/monkey_patches/kramdown/parser/kramdown/html.rb +60 -0
- data/lib/monkey_patches/kramdown/parser/kramdown/link.rb +116 -0
- data/lib/monkey_patches/kramdown/parser/kramdown/list.rb +115 -0
- data/lib/monkey_patches/kramdown/parser/kramdown/paragraph.rb +26 -0
- data/lib/monkey_patches/kramdown/parser/kramdown/typographic_symbol.rb +26 -0
- data/lib/monkey_patches/kramdown/utils/entities.rb +1911 -0
- data/markdown_formatter.gemspec +29 -0
- metadata +192 -0
- metadata.gz.sig +0 -0
@@ -0,0 +1,29 @@
|
|
1
|
+
module MarkdownFormatter
|
2
|
+
module ASTNode
|
3
|
+
class Inline < Base
|
4
|
+
def to_s
|
5
|
+
case node[:type]
|
6
|
+
when :a
|
7
|
+
Link.new(c).to_s
|
8
|
+
when :text
|
9
|
+
node[:value]
|
10
|
+
when :br
|
11
|
+
# skip
|
12
|
+
when :smart_quote
|
13
|
+
SmartQuote.new(c).to_s
|
14
|
+
when :typographic_sym
|
15
|
+
TypographicSym.new(c).to_s
|
16
|
+
when :img
|
17
|
+
Image.new(c).to_s
|
18
|
+
when :entity
|
19
|
+
Entity.new(c).to_s
|
20
|
+
when :footnote
|
21
|
+
Footnote.new(c).to_s
|
22
|
+
else
|
23
|
+
pp c
|
24
|
+
raise "Unexpected type `#{c[:type]}'"
|
25
|
+
end
|
26
|
+
end
|
27
|
+
end
|
28
|
+
end
|
29
|
+
end
|
@@ -0,0 +1,27 @@
|
|
1
|
+
module MarkdownFormatter
|
2
|
+
module ASTNode
|
3
|
+
class LeafBlock < Base
|
4
|
+
def to_s
|
5
|
+
case node[:type]
|
6
|
+
when :a
|
7
|
+
Link.new(c).to_s
|
8
|
+
when :p
|
9
|
+
Paragraph.new(c).to_s
|
10
|
+
when :strong
|
11
|
+
Strong.new(c).to_s
|
12
|
+
when :codespan
|
13
|
+
CodeSpan.new(c).to_s
|
14
|
+
when :em
|
15
|
+
Emphasis.new(c).to_s
|
16
|
+
when :html_element
|
17
|
+
str += HTMLElement.new(c).to_s
|
18
|
+
when :footnote
|
19
|
+
str += Footnote.new(c).to_s
|
20
|
+
else
|
21
|
+
pp c
|
22
|
+
raise "Unexpected type `#{c[:type]}'"
|
23
|
+
end
|
24
|
+
end
|
25
|
+
end
|
26
|
+
end
|
27
|
+
end
|
@@ -0,0 +1,23 @@
|
|
1
|
+
module MarkdownFormatter
|
2
|
+
module ASTNode
|
3
|
+
class List < Base
|
4
|
+
def initialize(node, nest_level = 0)
|
5
|
+
super(node)
|
6
|
+
@nest_level = nest_level
|
7
|
+
end
|
8
|
+
|
9
|
+
def to_s
|
10
|
+
node[:children].map do |c|
|
11
|
+
case c[:type]
|
12
|
+
when :blank
|
13
|
+
""
|
14
|
+
when :li
|
15
|
+
ListItem.new(c, @nest_level).to_s
|
16
|
+
else
|
17
|
+
raise "Unexpected type. #{c[:type]}"
|
18
|
+
end
|
19
|
+
end.join("\n") + "\n"
|
20
|
+
end
|
21
|
+
end
|
22
|
+
end
|
23
|
+
end
|
@@ -0,0 +1,38 @@
|
|
1
|
+
module MarkdownFormatter
|
2
|
+
module ASTNode
|
3
|
+
class ListItem < Base
|
4
|
+
def initialize(node, nest_level = 0)
|
5
|
+
super(node)
|
6
|
+
@nest_level = nest_level
|
7
|
+
end
|
8
|
+
|
9
|
+
def to_s
|
10
|
+
/^(?<prefix>\s*([0-9]+\.|[-+*])\s*)/ =~ node.dig(:options, :raw_text)
|
11
|
+
indents = node.dig(:options, :raw_text).lstrip.split(/\R/).map do |line|
|
12
|
+
line.match(/^\s+/).to_s
|
13
|
+
end
|
14
|
+
|
15
|
+
(prefix + node[:children].map { |c|
|
16
|
+
if c[:type] != :blank
|
17
|
+
indent, * = indents.shift(c.dig(:options, :raw_text).scan(/\R/).size)
|
18
|
+
else
|
19
|
+
indents.shift(c[:value].scan(/\R/).size)
|
20
|
+
end
|
21
|
+
|
22
|
+
case c[:type]
|
23
|
+
when :p
|
24
|
+
indent + Paragraph.new(c).to_s.gsub(/\R/, " ").split.join(" ")
|
25
|
+
when :blank
|
26
|
+
""
|
27
|
+
when :codeblock
|
28
|
+
CodeBlock.new(c).to_s.indent(indent.size)
|
29
|
+
when :ul
|
30
|
+
List.new(c, @nest_level + 1).to_s.chomp
|
31
|
+
else
|
32
|
+
raise "Unexpected type #{c[:type]}"
|
33
|
+
end
|
34
|
+
}.join("\n")).indent(@nest_level.zero? ? 0 : 2)
|
35
|
+
end
|
36
|
+
end
|
37
|
+
end
|
38
|
+
end
|
@@ -0,0 +1,39 @@
|
|
1
|
+
module MarkdownFormatter
|
2
|
+
module ASTNode
|
3
|
+
class Paragraph < Base
|
4
|
+
def to_s
|
5
|
+
node[:children].map do |c|
|
6
|
+
case c[:type]
|
7
|
+
when :a
|
8
|
+
Link.new(c).to_s
|
9
|
+
when :text
|
10
|
+
c[:value]
|
11
|
+
when :strong
|
12
|
+
Strong.new(c).to_s
|
13
|
+
when :codespan
|
14
|
+
CodeSpan.new(c).to_s
|
15
|
+
when :br
|
16
|
+
# skip
|
17
|
+
when :em
|
18
|
+
Emphasis.new(c).to_s
|
19
|
+
when :smart_quote
|
20
|
+
SmartQuote.new(c).to_s
|
21
|
+
when :typographic_sym
|
22
|
+
TypographicSym.new(c).to_s
|
23
|
+
when :img
|
24
|
+
Image.new(c).to_s
|
25
|
+
when :html_element
|
26
|
+
HTMLElement.new(c).to_s
|
27
|
+
when :entity
|
28
|
+
Entity.new(c).to_s
|
29
|
+
when :footnote
|
30
|
+
Footnote.new(c).to_s
|
31
|
+
else
|
32
|
+
pp c
|
33
|
+
raise "Unexpected type `#{c[:type]}'"
|
34
|
+
end
|
35
|
+
end.join
|
36
|
+
end
|
37
|
+
end
|
38
|
+
end
|
39
|
+
end
|
@@ -0,0 +1,21 @@
|
|
1
|
+
module Kramdown
|
2
|
+
module Parser
|
3
|
+
class GFM < Kramdown::Parser::Kramdown
|
4
|
+
|
5
|
+
# Copied from kramdown/parser/kramdown/header.rb, removed the first line
|
6
|
+
def parse_atx_header_gfm_quirk
|
7
|
+
start_line_number = @src.current_line_number
|
8
|
+
@src.check(ATX_HEADER_MATCH)
|
9
|
+
level, text, id = @src[1], @src[2].to_s.strip, @src[3]
|
10
|
+
return false if text.empty?
|
11
|
+
|
12
|
+
@src.pos += @src.matched_size
|
13
|
+
el = new_block_el(:header, nil, nil, :level => level.length, :raw_text => text, :location => start_line_number, :original_text => @src[0].chomp)
|
14
|
+
add_text(text, el)
|
15
|
+
el.attr['id'] = id if id
|
16
|
+
@tree.children << el
|
17
|
+
true
|
18
|
+
end
|
19
|
+
end
|
20
|
+
end
|
21
|
+
end
|
@@ -0,0 +1,16 @@
|
|
1
|
+
module Kramdown
|
2
|
+
module Parser
|
3
|
+
class Kramdown
|
4
|
+
|
5
|
+
# Parse the autolink at the current location.
|
6
|
+
def parse_autolink
|
7
|
+
start_line_number = @src.current_line_number
|
8
|
+
@src.pos += @src.matched_size
|
9
|
+
href = (@src[2].nil? ? "mailto:#{@src[1]}" : @src[1])
|
10
|
+
el = Element.new(:a, nil, {'href' => href}, :location => start_line_number, :raw_text => @src[0].dup)
|
11
|
+
add_text(@src[1].sub(/^mailto:/, ''), el)
|
12
|
+
@tree.children << el
|
13
|
+
end
|
14
|
+
end
|
15
|
+
end
|
16
|
+
end
|
@@ -0,0 +1,22 @@
|
|
1
|
+
module Kramdown
|
2
|
+
module Parser
|
3
|
+
class Kramdown
|
4
|
+
|
5
|
+
# Parse the blockquote at the current location.
|
6
|
+
def parse_blockquote
|
7
|
+
start_line_number = @src.current_line_number
|
8
|
+
result = @src.scan(PARAGRAPH_MATCH)
|
9
|
+
while !@src.match?(self.class::LAZY_END)
|
10
|
+
result << @src.scan(PARAGRAPH_MATCH)
|
11
|
+
end
|
12
|
+
raw_text = result.dup
|
13
|
+
result.gsub!(BLOCKQUOTE_START, '')
|
14
|
+
|
15
|
+
el = new_block_el(:blockquote, nil, nil, :location => start_line_number, :raw_text => raw_text)
|
16
|
+
@tree.children << el
|
17
|
+
parse_blocks(el, result)
|
18
|
+
true
|
19
|
+
end
|
20
|
+
end
|
21
|
+
end
|
22
|
+
end
|
@@ -0,0 +1,34 @@
|
|
1
|
+
module Kramdown
|
2
|
+
module Parser
|
3
|
+
class Kramdown
|
4
|
+
|
5
|
+
# Parse the indented codeblock at the current location.
|
6
|
+
def parse_codeblock
|
7
|
+
start_line_number = @src.current_line_number
|
8
|
+
data = @src.scan(self.class::CODEBLOCK_MATCH)
|
9
|
+
data.gsub!(/\n( {0,3}\S)/, ' \\1')
|
10
|
+
data.gsub!(INDENT, '')
|
11
|
+
@tree.children << new_block_el(:codeblock, data, nil, :location => start_line_number, :raw_text => @src.matched.dup)
|
12
|
+
true
|
13
|
+
end
|
14
|
+
|
15
|
+
# Parse the fenced codeblock at the current location.
|
16
|
+
def parse_codeblock_fenced
|
17
|
+
if @src.check(self.class::FENCED_CODEBLOCK_MATCH)
|
18
|
+
start_line_number = @src.current_line_number
|
19
|
+
@src.pos += @src.matched_size
|
20
|
+
el = new_block_el(:codeblock, @src[5], nil, :location => start_line_number, :raw_text => @src.matched.dup)
|
21
|
+
lang = @src[3].to_s.strip
|
22
|
+
unless lang.empty?
|
23
|
+
el.options[:lang] = lang
|
24
|
+
el.attr['class'] = "language-#{@src[4]}"
|
25
|
+
end
|
26
|
+
@tree.children << el
|
27
|
+
true
|
28
|
+
else
|
29
|
+
false
|
30
|
+
end
|
31
|
+
end
|
32
|
+
end
|
33
|
+
end
|
34
|
+
end
|
@@ -0,0 +1,31 @@
|
|
1
|
+
module Kramdown
|
2
|
+
module Parser
|
3
|
+
class Kramdown
|
4
|
+
# Parse the codespan at the current scanner location.
|
5
|
+
def parse_codespan
|
6
|
+
start_line_number = @src.current_line_number
|
7
|
+
result = @src.scan(CODESPAN_DELIMITER)
|
8
|
+
simple = (result.length == 1)
|
9
|
+
saved_pos = @src.save_pos
|
10
|
+
|
11
|
+
if simple && @src.pre_match =~ /\s\Z/ && @src.match?(/\s/)
|
12
|
+
add_text(result)
|
13
|
+
return
|
14
|
+
end
|
15
|
+
|
16
|
+
if text = @src.scan_until(/#{result}/)
|
17
|
+
raw_text = result + text
|
18
|
+
text.sub!(/#{result}\Z/, '')
|
19
|
+
if !simple
|
20
|
+
text = text[1..-1] if text[0..0] == ' '
|
21
|
+
text = text[0..-2] if text[-1..-1] == ' '
|
22
|
+
end
|
23
|
+
@tree.children << Element.new(:codespan, text, nil, :location => start_line_number, :raw_text => raw_text)
|
24
|
+
else
|
25
|
+
@src.revert_pos(saved_pos)
|
26
|
+
add_text(result)
|
27
|
+
end
|
28
|
+
end
|
29
|
+
end
|
30
|
+
end
|
31
|
+
end
|
@@ -0,0 +1,48 @@
|
|
1
|
+
module Kramdown
|
2
|
+
module Parser
|
3
|
+
class Kramdown
|
4
|
+
|
5
|
+
# Parse the emphasis at the current location.
|
6
|
+
def parse_emphasis
|
7
|
+
start_line_number = @src.current_line_number
|
8
|
+
saved_pos = @src.save_pos
|
9
|
+
|
10
|
+
result = @src.scan(EMPHASIS_START)
|
11
|
+
element = (result.length == 2 ? :strong : :em)
|
12
|
+
type = result[0..0]
|
13
|
+
|
14
|
+
if (type == '_' && @src.pre_match =~ /[[:alpha:]-]\z/) || @src.check(/\s/) ||
|
15
|
+
@tree.type == element || @stack.any? { |el, _| el.type == element }
|
16
|
+
add_text(result)
|
17
|
+
return
|
18
|
+
end
|
19
|
+
|
20
|
+
sub_parse = lambda do |delim, elem|
|
21
|
+
el = Element.new(elem, nil, nil, :location => start_line_number, :delim => delim)
|
22
|
+
stop_re = /#{Regexp.escape(delim)}/
|
23
|
+
found = parse_spans(el, stop_re) do
|
24
|
+
(@src.pre_match[-1, 1] !~ /\s/) &&
|
25
|
+
(elem != :em || !@src.match?(/#{Regexp.escape(delim*2)}(?!#{Regexp.escape(delim)})/)) &&
|
26
|
+
(type != '_' || !@src.match?(/#{Regexp.escape(delim)}[[:alnum:]]/)) && el.children.size > 0
|
27
|
+
end
|
28
|
+
[found, el, stop_re]
|
29
|
+
end
|
30
|
+
|
31
|
+
found, el, stop_re = sub_parse.call(result, element)
|
32
|
+
if !found && element == :strong && @tree.type != :em
|
33
|
+
@src.revert_pos(saved_pos)
|
34
|
+
@src.pos += 1
|
35
|
+
found, el, stop_re = sub_parse.call(type, :em)
|
36
|
+
end
|
37
|
+
if found
|
38
|
+
@src.scan(stop_re)
|
39
|
+
@tree.children << el
|
40
|
+
else
|
41
|
+
@src.revert_pos(saved_pos)
|
42
|
+
@src.pos += result.length
|
43
|
+
add_text(result)
|
44
|
+
end
|
45
|
+
end
|
46
|
+
end
|
47
|
+
end
|
48
|
+
end
|
@@ -0,0 +1,27 @@
|
|
1
|
+
module Kramdown
|
2
|
+
module Parser
|
3
|
+
class Kramdown
|
4
|
+
# Parse the footnote marker at the current location.
|
5
|
+
def parse_footnote_marker
|
6
|
+
start_line_number = @src.current_line_number
|
7
|
+
@src.pos += @src.matched_size
|
8
|
+
fn_def = @footnotes[@src[1]]
|
9
|
+
if fn_def
|
10
|
+
if fn_def[:eob]
|
11
|
+
update_attr_with_ial(fn_def[:eob].attr, fn_def[:eob].options[:ial] || {})
|
12
|
+
fn_def[:attr] = fn_def[:eob].attr
|
13
|
+
fn_def[:options] = fn_def[:eob].options
|
14
|
+
fn_def.delete(:eob)
|
15
|
+
end
|
16
|
+
fn_def[:marker] ||= []
|
17
|
+
fn_def[:marker].push(Element.new(:footnote, fn_def[:content], fn_def[:attr],
|
18
|
+
fn_def[:options].merge(:name => @src[1], :location => start_line_number, :raw_text => @src[0].dup)))
|
19
|
+
@tree.children << fn_def[:marker].last
|
20
|
+
else
|
21
|
+
warning("Footnote definition for '#{@src[1]}' not found on line #{start_line_number}")
|
22
|
+
add_text(@src.matched)
|
23
|
+
end
|
24
|
+
end
|
25
|
+
end
|
26
|
+
end
|
27
|
+
end
|