markdown_formatter 1.0.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 +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
|