markly 0.6.1 → 0.7.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.
@@ -1,281 +0,0 @@
1
- # frozen_string_literal: true
2
-
3
- require 'cgi'
4
-
5
- module Markly
6
- class HTMLRenderer < Renderer
7
- def initialize(ids: false, tight: false, **options)
8
- super(**options)
9
-
10
- @ids = ids
11
- @section = nil
12
- @tight = tight
13
- end
14
-
15
- def document(_)
16
- @section = false
17
- super
18
- out("</ol>\n</section>\n") if @written_footnote_ix
19
- out("</section>") if @section
20
- end
21
-
22
- def id_for(node)
23
- if @ids
24
- id = node.to_plaintext.chomp.downcase.gsub(/\s+/, '-')
25
-
26
- return " id=\"#{CGI.escape_html id}\""
27
- end
28
- end
29
-
30
- def header(node)
31
- block do
32
- if @ids
33
- out('</section>') if @section
34
- @section = true
35
- out("<section#{id_for(node)}>")
36
- end
37
-
38
- out('<h', node.header_level, "#{source_position(node)}>", :children,
39
- '</h', node.header_level, '>')
40
- end
41
- end
42
-
43
- def paragraph(node)
44
- if @tight && node.parent.type != :blockquote
45
- out(:children)
46
- else
47
- block do
48
- container("<p#{source_position(node)}>", '</p>') do
49
- out(:children)
50
- if node.parent.type == :footnote_definition && node.next.nil?
51
- out(' ')
52
- out_footnote_backref
53
- end
54
- end
55
- end
56
- end
57
- end
58
-
59
- def list(node)
60
- old_tight = @tight
61
- @tight = node.list_tight
62
-
63
- block do
64
- if node.list_type == :bullet_list
65
- container("<ul#{source_position(node)}>\n", '</ul>') do
66
- out(:children)
67
- end
68
- else
69
- start = if node.list_start == 1
70
- "<ol#{source_position(node)}>\n"
71
- else
72
- "<ol start=\"#{node.list_start}\"#{source_position(node)}>\n"
73
- end
74
- container(start, '</ol>') do
75
- out(:children)
76
- end
77
- end
78
- end
79
-
80
- @tight = old_tight
81
- end
82
-
83
- def list_item(node)
84
- block do
85
- tasklist_data = tasklist(node)
86
- container("<li#{source_position(node)}#{tasklist_data}>#{' ' if tasklist?(node)}", '</li>') do
87
- out(:children)
88
- end
89
- end
90
- end
91
-
92
- def tasklist(node)
93
- return '' unless tasklist?(node)
94
-
95
- state = if checked?(node)
96
- 'checked="" disabled=""'
97
- else
98
- 'disabled=""'
99
- end
100
- "><input type=\"checkbox\" #{state} /"
101
- end
102
-
103
- def blockquote(node)
104
- block do
105
- container("<blockquote#{source_position(node)}>\n", '</blockquote>') do
106
- out(:children)
107
- end
108
- end
109
- end
110
-
111
- def hrule(node)
112
- block do
113
- out("<hr#{source_position(node)} />")
114
- end
115
- end
116
-
117
- def code_block(node)
118
- block do
119
- if flag_enabled?(GITHUB_PRE_LANG)
120
- out("<pre#{source_position(node)}")
121
- out(' lang="', node.fence_info.split(/\s+/)[0], '"') if node.fence_info && !node.fence_info.empty?
122
- out('><code>')
123
- else
124
- out("<pre#{source_position(node)}><code")
125
- if node.fence_info && !node.fence_info.empty?
126
- out(' class="language-', node.fence_info.split(/\s+/)[0], '">')
127
- else
128
- out('>')
129
- end
130
- end
131
- out(escape_html(node.string_content))
132
- out('</code></pre>')
133
- end
134
- end
135
-
136
- def html(node)
137
- block do
138
- if flag_enabled?(UNSAFE)
139
- out(tagfilter(node.string_content))
140
- else
141
- out('<!-- raw HTML omitted -->')
142
- end
143
- end
144
- end
145
-
146
- def inline_html(node)
147
- if flag_enabled?(UNSAFE)
148
- out(tagfilter(node.string_content))
149
- else
150
- out('<!-- raw HTML omitted -->')
151
- end
152
- end
153
-
154
- def emph(_)
155
- out('<em>', :children, '</em>')
156
- end
157
-
158
- def strong(_)
159
- out('<strong>', :children, '</strong>')
160
- end
161
-
162
- def link(node)
163
- out('<a href="', node.url.nil? ? '' : escape_href(node.url), '"')
164
- out(' title="', escape_html(node.title), '"') if node.title && !node.title.empty?
165
- out('>', :children, '</a>')
166
- end
167
-
168
- def image(node)
169
- out('<img src="', escape_href(node.url), '"')
170
- plain do
171
- out(' alt="', :children, '"')
172
- end
173
- out(' title="', escape_html(node.title), '"') if node.title && !node.title.empty?
174
- out(' />')
175
- end
176
-
177
- def text(node)
178
- out(escape_html(node.string_content))
179
- end
180
-
181
- def code(node)
182
- out('<code>')
183
- out(escape_html(node.string_content))
184
- out('</code>')
185
- end
186
-
187
- def linebreak(_node)
188
- out("<br />\n")
189
- end
190
-
191
- def softbreak(_)
192
- if flag_enabled?(HARD_BREAKS)
193
- out("<br />\n")
194
- elsif flag_enabled?(NO_BREAKS)
195
- out(' ')
196
- else
197
- out("\n")
198
- end
199
- end
200
-
201
- def table(node)
202
- @alignments = node.table_alignments
203
- @needs_close_tbody = false
204
- out("<table#{source_position(node)}>\n", :children)
205
- out("</tbody>\n") if @needs_close_tbody
206
- out("</table>\n")
207
- end
208
-
209
- def table_header(node)
210
- @column_index = 0
211
-
212
- @in_header = true
213
- out("<thead>\n<tr#{source_position(node)}>\n", :children, "</tr>\n</thead>\n")
214
- @in_header = false
215
- end
216
-
217
- def table_row(node)
218
- @column_index = 0
219
- if !@in_header && !@needs_close_tbody
220
- @needs_close_tbody = true
221
- out("<tbody>\n")
222
- end
223
- out("<tr#{source_position(node)}>\n", :children, "</tr>\n")
224
- end
225
-
226
- def table_cell(node)
227
- align = case @alignments[@column_index]
228
- when :left then ' align="left"'
229
- when :right then ' align="right"'
230
- when :center then ' align="center"'
231
- else; ''
232
- end
233
- out(@in_header ? "<th#{align}#{source_position(node)}>" : "<td#{align}#{source_position(node)}>", :children, @in_header ? "</th>\n" : "</td>\n")
234
- @column_index += 1
235
- end
236
-
237
- def strikethrough(_)
238
- out('<del>', :children, '</del>')
239
- end
240
-
241
- def footnote_reference(node)
242
- out("<sup class=\"footnote-ref\"><a href=\"#fn#{node.string_content}\" id=\"fnref#{node.string_content}\">#{node.string_content}</a></sup>")
243
- end
244
-
245
- def footnote_definition(_)
246
- unless @footnote_ix
247
- out("<section class=\"footnotes\">\n<ol>\n")
248
- @footnote_ix = 0
249
- end
250
-
251
- @footnote_ix += 1
252
- out("<li id=\"fn#{@footnote_ix}\">\n", :children)
253
- out("\n") if out_footnote_backref
254
- out("</li>\n")
255
- # </ol>
256
- # </section>
257
- end
258
-
259
- private
260
-
261
- def out_footnote_backref
262
- return false if @written_footnote_ix == @footnote_ix
263
-
264
- @written_footnote_ix = @footnote_ix
265
-
266
- out("<a href=\"#fnref#{@footnote_ix}\" class=\"footnote-backref\">↩</a>")
267
- true
268
- end
269
-
270
- def tasklist?(node)
271
- node.type_string == 'tasklist'
272
- end
273
-
274
- def checked?(node)
275
- node.tasklist_item_checked?
276
- end
277
- end
278
-
279
- # Legacy.
280
- HtmlRenderer = HTMLRenderer
281
- end
@@ -1,133 +0,0 @@
1
- # frozen_string_literal: true
2
-
3
- require 'set'
4
- require 'stringio'
5
-
6
- module Markly
7
- class Renderer
8
- attr_accessor :in_tight, :warnings, :in_plain
9
- def initialize(flags: DEFAULT, extensions: [])
10
- @flags = flags
11
- @stream = StringIO.new(+'')
12
- @need_blocksep = false
13
- @warnings = Set.new
14
- @in_tight = false
15
- @in_plain = false
16
- @tagfilter = extensions.include?(:tagfilter)
17
- end
18
-
19
- def out(*args)
20
- args.each do |arg|
21
- if arg == :children
22
- @node.each { |child| out(child) }
23
- elsif arg.is_a?(Array)
24
- arg.each { |x| render(x) }
25
- elsif arg.is_a?(Node)
26
- render(arg)
27
- else
28
- @stream.write(arg)
29
- end
30
- end
31
- end
32
-
33
- def render(node)
34
- @node = node
35
- if node.type == :document
36
- document(node)
37
- @stream.string
38
- elsif @in_plain && node.type != :text && node.type != :softbreak
39
- node.each { |child| render(child) }
40
- else
41
- begin
42
- send(node.type, node)
43
- rescue NoMethodError => e
44
- @warnings.add("WARNING: #{node.type} not implemented.")
45
- raise e
46
- end
47
- end
48
- end
49
-
50
- def document(_node)
51
- out(:children)
52
- end
53
-
54
- def code_block(node)
55
- code_block(node)
56
- end
57
-
58
- def reference_def(_node); end
59
-
60
- def cr
61
- return if @stream.string.empty? || @stream.string[-1] == "\n"
62
-
63
- out("\n")
64
- end
65
-
66
- def blocksep
67
- out("\n")
68
- end
69
-
70
- def containersep
71
- cr unless @in_tight
72
- end
73
-
74
- def block
75
- cr
76
- yield
77
- cr
78
- end
79
-
80
- def container(starter, ender)
81
- out(starter)
82
- yield
83
- out(ender)
84
- end
85
-
86
- def plain
87
- old_in_plain = @in_plain
88
- @in_plain = true
89
- yield
90
- @in_plain = old_in_plain
91
- end
92
-
93
- private
94
-
95
- def escape_href(str)
96
- @node.html_escape_href(str)
97
- end
98
-
99
- def escape_html(str)
100
- @node.html_escape_html(str)
101
- end
102
-
103
- def tagfilter(str)
104
- if @tagfilter
105
- str.gsub(
106
- %r{
107
- <
108
- (
109
- title|textarea|style|xmp|iframe|
110
- noembed|noframes|script|plaintext
111
- )
112
- (?=\s|>|/>)
113
- }xi,
114
- '&lt;\1'
115
- )
116
- else
117
- str
118
- end
119
- end
120
-
121
- def source_position(node)
122
- return '' unless flag_enabled?(SOURCE_POSITION)
123
-
124
- s = node.source_position
125
- " data-sourcepos=\"#{s[:start_line]}:#{s[:start_column]}-" \
126
- "#{s[:end_line]}:#{s[:end_column]}\""
127
- end
128
-
129
- def flag_enabled?(flag)
130
- (@flags & flag) != 0
131
- end
132
- end
133
- end