qiita-markdown 0.44.1 → 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.
Files changed (33) hide show
  1. checksums.yaml +4 -4
  2. data/.github/workflows/test.yml +2 -2
  3. data/.rubocop.yml +0 -4
  4. data/.rubocop_todo.yml +6 -44
  5. data/CHANGELOG.md +10 -0
  6. data/README.md +3 -1
  7. data/lib/qiita/markdown/filters/checkbox.rb +5 -1
  8. data/lib/qiita/markdown/filters/custom_block.rb +7 -6
  9. data/lib/qiita/markdown/filters/final_sanitizer.rb +8 -2
  10. data/lib/qiita/markdown/filters/heading_anchor.rb +44 -0
  11. data/lib/qiita/markdown/filters/html_toc.rb +67 -0
  12. data/lib/qiita/markdown/filters/qiita_marker.rb +55 -0
  13. data/lib/qiita/markdown/filters/user_input_sanitizer.rb +14 -9
  14. data/lib/qiita/markdown/processor.rb +2 -1
  15. data/lib/qiita/markdown/summary_processor.rb +1 -1
  16. data/lib/qiita/markdown/version.rb +1 -1
  17. data/lib/qiita/markdown.rb +4 -5
  18. data/qiita-markdown.gemspec +2 -3
  19. data/spec/qiita/markdown/filters/checkbox_spec.rb +28 -0
  20. data/spec/qiita/markdown/filters/heading_anchor_spec.rb +73 -0
  21. data/spec/qiita/markdown/filters/html_toc_spec.rb +223 -0
  22. data/spec/qiita/markdown/filters/qiita_marker_spec.rb +60 -0
  23. data/spec/qiita/markdown/processor_spec.rb +48 -54
  24. data/spec/qiita/markdown/summary_processor_spec.rb +2 -2
  25. metadata +23 -39
  26. data/benchmark/heading_anchor_rendering.rb +0 -248
  27. data/benchmark/sample.md +0 -317
  28. data/lib/qiita/markdown/filters/greenmat.rb +0 -38
  29. data/lib/qiita/markdown/greenmat/heading_rendering.rb +0 -61
  30. data/lib/qiita/markdown/greenmat/html_renderer.rb +0 -60
  31. data/lib/qiita/markdown/greenmat/html_toc_renderer.rb +0 -78
  32. data/spec/qiita/markdown/filters/greenmat_spec.rb +0 -15
  33. data/spec/qiita/markdown/greenmat/html_toc_renderer_spec.rb +0 -156
@@ -1,38 +0,0 @@
1
- module Qiita
2
- module Markdown
3
- module Filters
4
- class Greenmat < HTML::Pipeline::TextFilter
5
- DEFAULT_OPTIONS = {
6
- footnotes: true,
7
- }.freeze
8
-
9
- # @return [Nokogiri::HTML::DocumentFragment]
10
- def call
11
- Nokogiri::HTML.fragment(greenmat.render(@text))
12
- end
13
-
14
- private
15
-
16
- # Memoize.
17
- # @return [Greenmat::Markdown]
18
- def greenmat
19
- @renderer ||= ::Greenmat::Markdown.new(
20
- Qiita::Markdown::Greenmat::HTMLRenderer.new(hard_wrap: true, with_toc_data: true),
21
- autolink: true,
22
- fenced_code_blocks: true,
23
- fenced_custom_blocks: true,
24
- footnotes: options[:footnotes],
25
- no_intra_emphasis: true,
26
- no_mention_emphasis: true,
27
- strikethrough: true,
28
- tables: true,
29
- )
30
- end
31
-
32
- def options
33
- @options ||= DEFAULT_OPTIONS.merge(context[:markdown] || {})
34
- end
35
- end
36
- end
37
- end
38
- end
@@ -1,61 +0,0 @@
1
- module Qiita
2
- module Markdown
3
- module Greenmat
4
- module HeadingRendering
5
- def heading_counter
6
- @counter ||= Hash.new(0)
7
- end
8
-
9
- class AbstractHeading
10
- attr_reader :raw_body, :level, :counter, :escape_html
11
- alias escape_html? escape_html
12
-
13
- def initialize(raw_body, level, counter, escape_html = false)
14
- @raw_body = raw_body
15
- @level = level
16
- @counter = counter
17
- @escape_html = escape_html
18
- end
19
-
20
- def to_s
21
- raise NotImplementedError
22
- end
23
-
24
- def increment
25
- raise NotImplementedError
26
- end
27
-
28
- private
29
-
30
- def count
31
- counter[id]
32
- end
33
-
34
- def has_count?
35
- count > 0
36
- end
37
-
38
- def body
39
- escape_html? ? CGI.escape_html(raw_body) : raw_body
40
- end
41
-
42
- def id
43
- @id ||= text.downcase.gsub(/[^\p{Word}\- ]/u, "").tr(" ", "-")
44
- end
45
-
46
- def text
47
- Nokogiri::HTML.fragment(raw_body).text
48
- end
49
-
50
- def suffix
51
- has_count? ? "-#{count}" : ""
52
- end
53
-
54
- def suffixed_id
55
- @suffixed_id ||= "#{id}#{suffix}"
56
- end
57
- end
58
- end
59
- end
60
- end
61
- end
@@ -1,60 +0,0 @@
1
- require "uri"
2
-
3
- module Qiita
4
- module Markdown
5
- module Greenmat
6
- class HTMLRenderer < ::Greenmat::Render::HTML
7
- include HeadingRendering
8
-
9
- def initialize(extensions = {})
10
- super
11
- @with_toc_data = extensions[:with_toc_data]
12
- end
13
-
14
- # https://github.com/vmg/redcarpet/blob/v3.2.3/ext/redcarpet/html.c#L76-L116
15
- def autolink(link, link_type)
16
- if link_type == :email
17
- %(<a href="mailto:#{link}" class="autolink">#{link}</a>)
18
- else
19
- %(<a href="#{link}" class="autolink">#{link}</a>)
20
- end
21
- end
22
-
23
- def header(text, level)
24
- heading = heading_class.new(text, level, heading_counter)
25
- heading.to_s.tap do
26
- heading.increment
27
- end
28
- end
29
-
30
- private
31
-
32
- def heading_class
33
- @heading_class ||= (@with_toc_data ? HeadingWithAnchor : Heading)
34
- end
35
-
36
- class Heading < AbstractHeading
37
- # For reference, C implementation of Redcarpet::Render::HTML#header is the following:
38
- # https://github.com/vmg/redcarpet/blob/v3.2.3/ext/redcarpet/html.c#L281-L296
39
- def to_s
40
- "\n<h#{level}>#{body}</h#{level}>\n"
41
- end
42
-
43
- def increment
44
- # No-op
45
- end
46
- end
47
-
48
- class HeadingWithAnchor < AbstractHeading
49
- def to_s
50
- %(\n<h#{level} id="#{suffixed_id}">#{body}</h#{level}>\n)
51
- end
52
-
53
- def increment
54
- counter[id] += 1
55
- end
56
- end
57
- end
58
- end
59
- end
60
- end
@@ -1,78 +0,0 @@
1
- module Qiita
2
- module Markdown
3
- module Greenmat
4
- class HTMLToCRenderer < ::Greenmat::Render::HTML_TOC
5
- include HeadingRendering
6
-
7
- def initialize(extensions = {})
8
- super
9
- @extensions = extensions
10
- @last_level = 0
11
- end
12
-
13
- # https://github.com/vmg/redcarpet/blob/v3.2.3/ext/redcarpet/html.c#L609-L642
14
- def header(text, level)
15
- @level_offset ||= level - 1
16
-
17
- level -= @level_offset
18
- level = 1 if level < 1
19
-
20
- difference = level - @last_level
21
- @last_level = level
22
-
23
- generate_heading_html(text, level, difference)
24
- end
25
-
26
- # https://github.com/vmg/redcarpet/blob/v3.2.3/ext/redcarpet/html.c#L652-L661
27
- def doc_footer
28
- "</li>\n</ul>\n" * @last_level
29
- end
30
-
31
- private
32
-
33
- def generate_heading_html(text, level, level_difference)
34
- html = list_item_preceding_html(level_difference)
35
-
36
- anchor = HeadingAnchor.new(text, level, heading_counter, escape_html?)
37
- html << anchor.to_s
38
- anchor.increment
39
-
40
- html
41
- end
42
-
43
- def list_item_preceding_html(level_difference)
44
- html = case
45
- when level_difference > 0
46
- "<ul>\n" * level_difference
47
- when level_difference < 0
48
- "</li>\n" << ("</ul>\n</li>\n" * level_difference.abs)
49
- else
50
- "</li>\n"
51
- end
52
-
53
- html << "<li>\n"
54
- end
55
-
56
- def escape_html?
57
- @extensions[:escape_html]
58
- end
59
-
60
- class HeadingAnchor < AbstractHeading
61
- def to_s
62
- "<a href=\"##{suffixed_id}\">#{body}</a>\n"
63
- end
64
-
65
- def increment
66
- counter[id] += 1
67
- end
68
-
69
- private
70
-
71
- def body
72
- escape_html? ? CGI.escape_html(text) : raw_body
73
- end
74
- end
75
- end
76
- end
77
- end
78
- end
@@ -1,15 +0,0 @@
1
- describe Qiita::Markdown::Filters::Greenmat do
2
- subject(:filter) do
3
- described_class.new(markdown)
4
- end
5
-
6
- context "with headings" do
7
- let(:markdown) do
8
- "# foo"
9
- end
10
-
11
- it "does not generate FontAwesome classes so that we can say that they're inputted by user" do
12
- expect(filter.call.to_s).to eq(%(\n<h1 id="foo">foo</h1>\n))
13
- end
14
- end
15
- end
@@ -1,156 +0,0 @@
1
- require "active_support/core_ext/string/strip"
2
-
3
- describe Qiita::Markdown::Greenmat::HTMLToCRenderer do
4
- let(:renderer) { described_class.new(extension) }
5
- let(:extension) { {} }
6
- let(:greenmat) { ::Greenmat::Markdown.new(renderer) }
7
- subject(:rendered_html) { greenmat.render(markdown) }
8
-
9
- context "with duplicated heading names" do
10
- let(:markdown) do
11
- <<-EOS.strip_heredoc
12
- # a
13
- ## a
14
- ### a
15
- ### a
16
- EOS
17
- end
18
-
19
- it "renders ToC anchors with unique ids" do
20
- should eq <<-EOS.strip_heredoc
21
- <ul>
22
- <li>
23
- <a href="#a">a</a>
24
- <ul>
25
- <li>
26
- <a href="#a-1">a</a>
27
- <ul>
28
- <li>
29
- <a href="#a-2">a</a>
30
- </li>
31
- <li>
32
- <a href="#a-3">a</a>
33
- </li>
34
- </ul>
35
- </li>
36
- </ul>
37
- </li>
38
- </ul>
39
- EOS
40
- end
41
- end
42
-
43
- context "with a document starting with level 2 heading" do
44
- let(:markdown) do
45
- <<-EOS.strip_heredoc
46
- ## a
47
- ### a
48
- ## a
49
- EOS
50
- end
51
-
52
- it "offsets the heading levels" do
53
- should eq <<-EOS.strip_heredoc
54
- <ul>
55
- <li>
56
- <a href="#a">a</a>
57
- <ul>
58
- <li>
59
- <a href="#a-1">a</a>
60
- </li>
61
- </ul>
62
- </li>
63
- <li>
64
- <a href="#a-2">a</a>
65
- </li>
66
- </ul>
67
- EOS
68
- end
69
- end
70
-
71
- context "with a document starting with level 2 heading but includes level 1 heading at the end" do
72
- let(:markdown) do
73
- <<-EOS.strip_heredoc
74
- ## a
75
- ### a
76
- # a
77
- EOS
78
- end
79
-
80
- it "does not generate invalid list structure" do
81
- should eq <<-EOS.strip_heredoc
82
- <ul>
83
- <li>
84
- <a href="#a">a</a>
85
- <ul>
86
- <li>
87
- <a href="#a-1">a</a>
88
- </li>
89
- </ul>
90
- </li>
91
- <li>
92
- <a href="#a-2">a</a>
93
- </li>
94
- </ul>
95
- EOS
96
- end
97
- end
98
-
99
- context "with heading title including special HTML characters" do
100
- let(:markdown) do
101
- <<-EOS.strip_heredoc
102
- # <b>R&amp;B</b>
103
- EOS
104
- end
105
-
106
- it "generates fragment identifier by sanitizing the characters in the title" do
107
- should eq <<-EOS.strip_heredoc
108
- <ul>
109
- <li>
110
- <a href="#rb"><b>R&amp;B</b></a>
111
- </li>
112
- </ul>
113
- EOS
114
- end
115
- end
116
-
117
- context "with :escape_html extension" do
118
- let(:extension) { { escape_html: true } }
119
-
120
- context "with heading title including HTML tags" do
121
- let(:markdown) do
122
- <<-EOS.strip_heredoc
123
- # <b>R&amp;B</b>
124
- EOS
125
- end
126
-
127
- it "strips HTML characters in heading title" do
128
- should eq <<-EOS.strip_heredoc
129
- <ul>
130
- <li>
131
- <a href="#rb">R&amp;B</a>
132
- </li>
133
- </ul>
134
- EOS
135
- end
136
- end
137
-
138
- context "with heading title including HTML tags inside of code" do
139
- let(:markdown) do
140
- <<-EOS.strip_heredoc
141
- # `<div>`
142
- EOS
143
- end
144
-
145
- it "escapes HTML tags inside of code" do
146
- should eq <<-EOS.strip_heredoc
147
- <ul>
148
- <li>
149
- <a href="#div">&lt;div&gt;</a>
150
- </li>
151
- </ul>
152
- EOS
153
- end
154
- end
155
- end
156
- end