kramdown 2.1.0 → 2.2.0

Sign up to get free protection for your applications and to get access to all the features.

Potentially problematic release.


This version of kramdown might be problematic. Click here for more details.

Files changed (64) hide show
  1. checksums.yaml +4 -4
  2. data/CONTRIBUTERS +11 -3
  3. data/VERSION +1 -1
  4. data/lib/kramdown/converter/base.rb +2 -1
  5. data/lib/kramdown/converter/html.rb +22 -14
  6. data/lib/kramdown/converter/kramdown.rb +9 -4
  7. data/lib/kramdown/converter/math_engine/mathjax.rb +7 -33
  8. data/lib/kramdown/converter/syntax_highlighter.rb +1 -1
  9. data/lib/kramdown/element.rb +16 -0
  10. data/lib/kramdown/options.rb +35 -8
  11. data/lib/kramdown/parser/base.rb +3 -1
  12. data/lib/kramdown/parser/html.rb +8 -8
  13. data/lib/kramdown/parser/kramdown.rb +8 -1
  14. data/lib/kramdown/parser/kramdown/autolink.rb +2 -2
  15. data/lib/kramdown/parser/kramdown/codespan.rb +12 -2
  16. data/lib/kramdown/parser/kramdown/emphasis.rb +1 -1
  17. data/lib/kramdown/parser/kramdown/header.rb +1 -1
  18. data/lib/kramdown/parser/kramdown/html.rb +2 -2
  19. data/lib/kramdown/parser/kramdown/list.rb +36 -9
  20. data/lib/kramdown/parser/kramdown/math.rb +1 -1
  21. data/lib/kramdown/parser/kramdown/table.rb +2 -2
  22. data/lib/kramdown/utils/html.rb +7 -0
  23. data/lib/kramdown/version.rb +1 -1
  24. data/man/man1/kramdown.1 +7 -0
  25. data/test/test_files.rb +12 -11
  26. data/test/testcases/block/04_header/atx_header.html +6 -0
  27. data/test/testcases/block/04_header/atx_header.text +6 -0
  28. data/test/testcases/block/09_html/standalone_image_in_div.htmlinput +7 -0
  29. data/test/testcases/block/09_html/standalone_image_in_div.text +8 -0
  30. data/test/testcases/block/12_extension/options.html +4 -4
  31. data/test/testcases/block/12_extension/options2.html +4 -4
  32. data/test/testcases/block/14_table/table_with_footnote.html +4 -4
  33. data/test/testcases/block/15_math/gh_128.html +1 -2
  34. data/test/testcases/block/15_math/normal.html +16 -15
  35. data/test/testcases/block/16_toc/toc_exclude.html +1 -1
  36. data/test/testcases/block/16_toc/toc_levels.html +1 -1
  37. data/test/testcases/block/16_toc/toc_with_footnotes.html +5 -5
  38. data/test/testcases/block/16_toc/toc_with_links.html +1 -1
  39. data/test/testcases/cjk-line-break.html +4 -0
  40. data/test/testcases/cjk-line-break.options +1 -0
  41. data/test/testcases/cjk-line-break.text +12 -0
  42. data/test/testcases/span/02_emphasis/normal.html +4 -0
  43. data/test/testcases/span/02_emphasis/normal.text +4 -0
  44. data/test/testcases/span/04_footnote/backlink_inline.html +21 -21
  45. data/test/testcases/span/04_footnote/backlink_text.html +4 -4
  46. data/test/testcases/span/04_footnote/footnote_nr.html +6 -6
  47. data/test/testcases/span/04_footnote/footnote_prefix.html +6 -6
  48. data/test/testcases/span/04_footnote/inside_footnote.html +9 -9
  49. data/test/testcases/span/04_footnote/markers.html +16 -16
  50. data/test/testcases/span/04_footnote/placement.html +4 -4
  51. data/test/testcases/span/04_footnote/regexp_problem.html +4 -4
  52. data/test/testcases/span/04_footnote/without_backlink.html +3 -3
  53. data/test/testcases/span/abbreviations/in_footnote.html +4 -4
  54. data/test/testcases/span/math/normal.html +4 -4
  55. metadata +22 -13
  56. data/test/testcases/block/15_math/mathjax_preview.html +0 -4
  57. data/test/testcases/block/15_math/mathjax_preview.options +0 -2
  58. data/test/testcases/block/15_math/mathjax_preview.text +0 -5
  59. data/test/testcases/block/15_math/mathjax_preview_as_code.html +0 -4
  60. data/test/testcases/block/15_math/mathjax_preview_as_code.options +0 -3
  61. data/test/testcases/block/15_math/mathjax_preview_as_code.text +0 -5
  62. data/test/testcases/block/15_math/mathjax_preview_simple.html +0 -4
  63. data/test/testcases/block/15_math/mathjax_preview_simple.options +0 -2
  64. data/test/testcases/block/15_math/mathjax_preview_simple.text +0 -5
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: e43c55f31bbce7153d1d863ab7c90bb24aee7741e7df3a0f6d89064286fe2344
4
- data.tar.gz: c53d7af0318896bae6bdcb9123eb714f9572e4c9918f04d093c7d228c2431b0e
3
+ metadata.gz: 0d90f86f716aa82f4766f16683887407deb66f637dd997f8b38114b8a48dfc34
4
+ data.tar.gz: e0de118de20cfdfc45027fccd10af6dfc71a109f62fc769b0de9540c7839b4ed
5
5
  SHA512:
6
- metadata.gz: 351a0939690de3cf44107f5cad613d8d3dc945b6d47d0e78f8bf676081b7887f696e738fb9200779a6821a870161a3110a7e42911e7705cc7d79af59ff061da6
7
- data.tar.gz: dbd73556bc863c0d6a937705662909440fd1dea33415da9e98ac681e5cd33fbedde37a7311b1082c2bcd556aec2896c10ec1d203ca992783f05eae8e7572aea0
6
+ metadata.gz: 0dd3de9b72e755fe43ed33adc136eaba941e4675d739fa318eedf7e0f63e6db37f92b3564e6ac897014269f1aff48c7e2ad3b70abae490ee92795e830c94d776
7
+ data.tar.gz: 3710cd52ea508e2ffca6fd6ab1c84efca4308f91540ceb7169fe5e78f09cd33161ad07b287ad716c5b95e295e61018f3957196d6cc597afa197a2d6641d9061f
@@ -1,13 +1,13 @@
1
1
  Count Name
2
2
  ======= ====
3
- 913 Thomas Leitner <t_leitner@gmx.at>
3
+ 930 Thomas Leitner <t_leitner@gmx.at>
4
+ 18 Ashwin Maroli <ashmaroli@gmail.com>
4
5
  7 Christian Cornelssen <ccorn@1tein.de>
5
6
  6 Gioele Barabucci <gioele@svario.it>
7
+ 5 Gleb Mazovetskiy <glex.spb@gmail.com>
6
8
  4 Ted Pak <powerpak006@gmail.com>
7
9
  4 Shuanglei Tao <tsl0922@gmail.com>
8
- 4 Gleb Mazovetskiy <glex.spb@gmail.com>
9
10
  4 Dan Allen <dan.j.allen@gmail.com>
10
- 4 Ashwin Maroli <ashmaroli@gmail.com>
11
11
  4 Arne Brasseur <arne@arnebrasseur.net>
12
12
  3 Henning Perl <perl@fast-sicher.de>
13
13
  3 gettalong <t_leitner@gmx.at>
@@ -26,12 +26,15 @@
26
26
  1 utenmiki <utenmiki@gmail.com>
27
27
  1 Trevor Wennblom <trevor@well.com>
28
28
  1 tomykaira <tomykaira@gmail.com>
29
+ 1 tom93 <tomlevy93@gmail.com>
29
30
  1 Tim Blair <tim@bla.ir>
30
31
  1 Tim Besard <tim.besard@gmail.com>
31
32
  1 Tim Bates <tim@rumpuslabs.com>
32
33
  1 Sun Yaozhu <yzyzsun@gmail.com>
34
+ 1 Stephen <stephengroat@users.noreply.github.com>
33
35
  1 Stephen Crosby <stevecrozz@gmail.com>
34
36
  1 Simon Lydell <simon.lydell@gmail.com>
37
+ 1 Simon Coffey <simon.coffey@futurelearn.com>
35
38
  1 Shusaku NAKAZATO <cu393uc@gmail.com>
36
39
  1 Sebastian Boehm <sebastian@sometimesfood.org>
37
40
  1 scherr <maximilianscherr@gmail.com>
@@ -40,6 +43,7 @@
40
43
  1 myqlarson <myqlarson@gmail.com>
41
44
  1 milo.simpson <milo.simpson@bazaarvoice.com>
42
45
  1 Michal Till <michal.till@gmail.com>
46
+ 1 Maxime Kjaer <maxime.kjaer@gmail.com>
43
47
  1 Matt Hickford <matt.hickford@gmail.com>
44
48
  1 Martyn Chamberlin <martyn@perfectioncoding.com>
45
49
  1 Marek Tuchowski <marek@tuchowski.com.pl>
@@ -56,13 +60,17 @@
56
60
  1 Hector Correa <hector@hectorcorrea.com>
57
61
  1 Florian Klampfer <f.klampfer@gmail.com>
58
62
  1 Floreal Morandat florealm@gmail.com <florealm@gmail.com>
63
+ 1 Fangyi Zhou <me@fangyi.io>
59
64
  1 Diego Galeota <diegobg123@gmail.com>
65
+ 1 David Rodríguez <deivid.rodriguez@riseup.net>
60
66
  1 Damien Pollet <damien.pollet@gmail.com>
61
67
  1 Christopher Jefferson <caj21@st-andrews.ac.uk>
62
68
  1 Cédric Boutillier <cedric.boutillier@gmail.com>
69
+ 1 Bob Lail <lail@squareup.com>
63
70
  1 Ashe Connor <ashe@kivikakk.ee>
64
71
  1 Antoine Cotten <hello@acotten.com>
65
72
  1 Andrew <andrew.dale.wylie@gmail.com>
66
73
  1 Alpha Chen <alpha.chen@gmail.com>
67
74
  1 Alex Tomlins <alex.tomlins@digital.cabinet-office.gov.uk>
68
75
  1 Alexey Vasiliev <le0pard@users.noreply.github.com>
76
+ 1 284km <k.furuhashi10@gmail.com>
data/VERSION CHANGED
@@ -1 +1 @@
1
- 2.1.0
1
+ 2.2.0
@@ -106,7 +106,8 @@ module Kramdown
106
106
  end
107
107
  result = converter.convert(tree)
108
108
  if result.respond_to?(:encode!) && result.encoding != Encoding::BINARY
109
- result.encode!(tree.options[:encoding])
109
+ result.encode!(tree.options[:encoding] ||
110
+ (raise ::Kramdown::Error, "Missing encoding option on root element"))
110
111
  end
111
112
  if !converter.options[:template].empty? && converter.apply_template_after?
112
113
  result = apply_template(converter, result)
@@ -46,6 +46,9 @@ module Kramdown
46
46
  @toc_code = nil
47
47
  @indent = 2
48
48
  @stack = []
49
+
50
+ # stash string representation of symbol to avoid allocations from multiple interpolations.
51
+ @highlighter_class = " highlighter-#{options[:syntax_highlighter]}"
49
52
  end
50
53
 
51
54
  # The mapping of element type to conversion method.
@@ -78,7 +81,8 @@ module Kramdown
78
81
  end
79
82
 
80
83
  def convert_text(el, _indent)
81
- escape_html(el.value, :text)
84
+ escaped = escape_html(el.value, :text)
85
+ @options[:remove_line_breaks_for_cjk] ? fix_cjk_line_break(escaped) : escaped
82
86
  end
83
87
 
84
88
  def convert_p(el, indent)
@@ -88,7 +92,7 @@ module Kramdown
88
92
  el.children.first.options[:ial]&.[](:refs)&.include?('standalone')
89
93
  convert_standalone_image(el.children.first, indent)
90
94
  else
91
- format_as_block_html(el.type, el.attr, inner(el, indent), indent)
95
+ format_as_block_html("p", el.attr, inner(el, indent), indent)
92
96
  end
93
97
  end
94
98
 
@@ -135,7 +139,7 @@ module Kramdown
135
139
  end
136
140
 
137
141
  def convert_blockquote(el, indent)
138
- format_as_indented_block_html(el.type, el.attr, inner(el, indent), indent)
142
+ format_as_indented_block_html("blockquote", el.attr, inner(el, indent), indent)
139
143
  end
140
144
 
141
145
  def convert_header(el, indent)
@@ -152,12 +156,15 @@ module Kramdown
152
156
  "#{' ' * indent}<hr#{html_attributes(el.attr)} />\n"
153
157
  end
154
158
 
159
+ ZERO_TO_ONETWENTYEIGHT = (0..128).to_a.freeze
160
+ private_constant :ZERO_TO_ONETWENTYEIGHT
161
+
155
162
  def convert_ul(el, indent)
156
163
  if !@toc_code && (el.options[:ial][:refs].include?('toc') rescue nil)
157
- @toc_code = [el.type, el.attr, (0..128).to_a.map { rand(36).to_s(36) }.join]
164
+ @toc_code = [el.type, el.attr, ZERO_TO_ONETWENTYEIGHT.map { rand(36).to_s(36) }.join]
158
165
  @toc_code.last
159
166
  elsif !@footnote_location && el.options[:ial] && (el.options[:ial][:refs] || []).include?('footnotes')
160
- @footnote_location = (0..128).to_a.map { rand(36).to_s(36) }.join
167
+ @footnote_location = ZERO_TO_ONETWENTYEIGHT.map { rand(36).to_s(36) }.join
161
168
  else
162
169
  format_as_indented_block_html(el.type, el.attr, inner(el, indent), indent)
163
170
  end
@@ -165,7 +172,7 @@ module Kramdown
165
172
  alias convert_ol convert_ul
166
173
 
167
174
  def convert_dl(el, indent)
168
- format_as_indented_block_html(el.type, el.attr, inner(el, indent), indent)
175
+ format_as_indented_block_html("dl", el.attr, inner(el, indent), indent)
169
176
  end
170
177
 
171
178
  def convert_li(el, indent)
@@ -188,7 +195,7 @@ module Kramdown
188
195
  break
189
196
  end
190
197
  end if !attr['id'] && @stack.last.options[:ial] && @stack.last.options[:ial][:refs]
191
- format_as_block_html(el.type, attr, inner(el, indent), indent)
198
+ format_as_block_html("dt", attr, inner(el, indent), indent)
192
199
  end
193
200
 
194
201
  def convert_html_element(el, indent)
@@ -263,7 +270,7 @@ module Kramdown
263
270
  end
264
271
 
265
272
  def convert_a(el, indent)
266
- format_as_span_html(el.type, el.attr, inner(el, indent))
273
+ format_as_span_html("a", el.attr, inner(el, indent))
267
274
  end
268
275
 
269
276
  def convert_img(el, _indent)
@@ -296,7 +303,7 @@ module Kramdown
296
303
  @footnotes << [name, el.value, number, 0]
297
304
  @footnotes_by_name[name] = @footnotes.last
298
305
  end
299
- "<sup id=\"fnref:#{name}#{repeat}\">" \
306
+ "<sup id=\"fnref:#{name}#{repeat}\" role=\"doc-noteref\">" \
300
307
  "<a href=\"#fn:#{name}\" class=\"footnote\">" \
301
308
  "#{number}</a></sup>"
302
309
  end
@@ -400,7 +407,7 @@ module Kramdown
400
407
  # Add the syntax highlighter name to the 'class' attribute of the given attribute hash. And
401
408
  # overwrites or add a "language-LANG" part using the +lang+ parameter if +lang+ is not nil.
402
409
  def add_syntax_highlighter_to_class_attr(attr, lang = nil)
403
- (attr['class'] = (attr['class'] || '') + " highlighter-#{@options[:syntax_highlighter]}").lstrip!
410
+ (attr['class'] = (attr['class'] || '') + @highlighter_class).lstrip!
404
411
  attr['class'].sub!(/\blanguage-\S+|(^)/) { "language-#{lang}#{$1 ? ' ' : ''}" } if lang
405
412
  end
406
413
 
@@ -408,6 +415,7 @@ module Kramdown
408
415
  def generate_toc_tree(toc, type, attr)
409
416
  sections = Element.new(type, nil, attr.dup)
410
417
  sections.attr['id'] ||= 'markdown-toc'
418
+ sections.attr['role'] ||= 'doc-toc'
411
419
  stack = []
412
420
  toc.each do |level, id, children|
413
421
  li = Element.new(:li, nil, nil, level: level)
@@ -475,9 +483,9 @@ module Kramdown
475
483
  result
476
484
  end
477
485
 
478
- FOOTNOTE_BACKLINK_FMT = "%s<a href=\"#fnref:%s\" class=\"reversefootnote\">%s</a>"
486
+ FOOTNOTE_BACKLINK_FMT = "%s<a href=\"#fnref:%s\" class=\"reversefootnote\" role=\"doc-backlink\">%s</a>"
479
487
 
480
- # Return a HTML ordered list with the footnote content for the used footnotes.
488
+ # Return an HTML ordered list with the footnote content for the used footnotes.
481
489
  def footnote_content
482
490
  ol = Element.new(:ol)
483
491
  ol.attr['start'] = @footnote_start if @footnote_start != 1
@@ -485,7 +493,7 @@ module Kramdown
485
493
  backlink_text = escape_html(@options[:footnote_backlink], :text)
486
494
  while i < @footnotes.length
487
495
  name, data, _, repeat = *@footnotes[i]
488
- li = Element.new(:li, nil, 'id' => "fn:#{name}")
496
+ li = Element.new(:li, nil, 'id' => "fn:#{name}", 'role' => 'doc-endnote')
489
497
  li.children = Marshal.load(Marshal.dump(data.children))
490
498
 
491
499
  para = nil
@@ -520,7 +528,7 @@ module Kramdown
520
528
  if ol.children.empty?
521
529
  ''
522
530
  else
523
- format_as_indented_block_html('div', {class: "footnotes"}, convert(ol, 2), 0)
531
+ format_as_indented_block_html('div', {class: "footnotes", role: "doc-endnotes"}, convert(ol, 2), 0)
524
532
  end
525
533
  end
526
534
 
@@ -34,13 +34,13 @@ module Kramdown
34
34
  res = res.dup if res.frozen?
35
35
  if ![:html_element, :li, :dt, :dd, :td].include?(el.type) && (ial = ial_for_element(el))
36
36
  res << ial
37
- res << "\n\n" if Element.category(el) == :block
37
+ res << "\n\n" if el.block?
38
38
  elsif [:ul, :dl, :ol, :codeblock].include?(el.type) && opts[:next] &&
39
39
  ([el.type, :codeblock].include?(opts[:next].type) ||
40
40
  (opts[:next].type == :blank && opts[:nnext] &&
41
41
  [el.type, :codeblock].include?(opts[:nnext].type)))
42
42
  res << "^\n\n"
43
- elsif Element.category(el) == :block &&
43
+ elsif el.block? &&
44
44
  ![:li, :dd, :dt, :td, :th, :tr, :thead, :tbody, :tfoot, :blank].include?(el.type) &&
45
45
  (el.type != :html_element || @stack.last.type != :html_element) &&
46
46
  (el.type != :p || !el.options[:transparent])
@@ -184,10 +184,15 @@ module Kramdown
184
184
 
185
185
  HTML_TAGS_WITH_BODY = ['div', 'script', 'iframe', 'textarea']
186
186
 
187
+ HTML_ELEMENT_TYPES = [:entity, :text, :html_element].freeze
188
+ private_constant :HTML_ELEMENT_TYPES
189
+
187
190
  def convert_html_element(el, opts)
188
191
  markdown_attr = el.options[:category] == :block && el.children.any? do |c|
189
- c.type != :html_element && (c.type != :p || !c.options[:transparent]) &&
190
- Element.category(c) == :block
192
+ c.type != :html_element &&
193
+ (c.type != :p || !c.options[:transparent] ||
194
+ c.children.any? {|t| !HTML_ELEMENT_TYPES.member?(t.type) }) &&
195
+ c.block?
191
196
  end
192
197
  opts[:force_raw_text] = true if %w[script pre code].include?(el.value)
193
198
  opts[:raw_text] = opts[:force_raw_text] || opts[:block_raw_text] || \
@@ -16,40 +16,14 @@ module Kramdown::Converter::MathEngine
16
16
  module Mathjax
17
17
 
18
18
  def self.call(converter, el, opts)
19
- type = el.options[:category]
20
- text = (el.value =~ /<|&/ ? "% <![CDATA[\n#{el.value} %]]>" : el.value).dup
21
- text.gsub!(/<\/?script>?/, '')
22
-
23
- preview = preview_string(converter, el, opts).dup
24
-
25
- attr = {type: "math/tex#{type == :block ? '; mode=display' : ''}"}
26
- preview << if type == :block
27
- converter.format_as_block_html('script', attr, text, opts[:indent])
28
- else
29
- converter.format_as_span_html('script', attr, text)
30
- end
31
- end
32
-
33
- def self.preview_string(converter, el, opts)
34
- preview = converter.options[:math_engine_opts][:preview]
35
- return '' unless preview
36
-
37
- preview = (preview == true ? converter.escape_html(el.value) : preview.to_s)
38
-
39
- preview_as_code = converter.options[:math_engine_opts][:preview_as_code]
40
-
41
- if el.options[:category] == :block
42
- if preview_as_code
43
- converter.format_as_block_html('pre', {'class' => 'MathJax_Preview'},
44
- converter.format_as_span_html('code', {}, preview),
45
- opts[:indent])
46
- else
47
- converter.format_as_block_html('div', {'class' => 'MathJax_Preview'}, preview,
48
- opts[:indent])
49
- end
19
+ value = converter.escape_html(el.value)
20
+ result = el.options[:category] == :block ? "\\[#{value}\\]\n" : "\\(#{value}\\)"
21
+ if el.attr.empty?
22
+ result
23
+ elsif el.options[:category] == :block
24
+ converter.format_as_block_html('div', el.attr, result, opts[:indent])
50
25
  else
51
- converter.format_as_span_html(preview_as_code ? 'code' : 'span',
52
- {'class' => 'MathJax_Preview'}, preview)
26
+ converter.format_as_span_html('span', el.attr, "$#{el.value}$")
53
27
  end
54
28
  end
55
29
 
@@ -42,7 +42,7 @@ module Kramdown
42
42
  #
43
43
  # == Special Implementation Details
44
44
  #
45
- # HTML converter:: If the syntax highlighter is used with a HTML converter, it should return
45
+ # HTML converter:: If the syntax highlighter is used with an HTML converter, it should return
46
46
  # :block type text correctly wrapped (i.e. normally inside a pre-tag, but may
47
47
  # also be a table-tag or just a div-tag) but :span type text *without* a
48
48
  # code-tag!
@@ -522,6 +522,22 @@ module Kramdown
522
522
  CATEGORY[el.type] || el.options[:category]
523
523
  end
524
524
 
525
+ # syntactic sugar to simplify calls such as +Kramdown::Element.category(el) == :block+ with
526
+ # +el.block?+.
527
+ #
528
+ # Returns boolean true or false.
529
+ def block?
530
+ (CATEGORY[type] || options[:category]) == :block
531
+ end
532
+
533
+ # syntactic sugar to simplify calls such as +Kramdown::Element.category(el) == :span+ with
534
+ # +el.span?+.
535
+ #
536
+ # Returns boolean true or false.
537
+ def span?
538
+ (CATEGORY[type] || options[:category]) == :span
539
+ end
540
+
525
541
  end
526
542
 
527
543
  end
@@ -328,7 +328,11 @@ module Kramdown
328
328
  Used by: HTML converter, kramdown converter
329
329
  EOF
330
330
 
331
- define(:toc_levels, Object, (1..6).to_a, <<~EOF) do |val|
331
+ TOC_LEVELS_RANGE = (1..6).freeze
332
+ TOC_LEVELS_ARRAY = TOC_LEVELS_RANGE.to_a.freeze
333
+ private_constant :TOC_LEVELS_RANGE, :TOC_LEVELS_ARRAY
334
+
335
+ define(:toc_levels, Object, TOC_LEVELS_ARRAY, <<~EOF) do |val|
332
336
  Defines the levels that are used for the table of contents
333
337
 
334
338
  The individual levels can be specified by separating them with commas
@@ -347,12 +351,20 @@ module Kramdown
347
351
  else
348
352
  raise Kramdown::Error, "Invalid syntax for option toc_levels"
349
353
  end
350
- when Array, Range
351
- val = val.map(&:to_i).uniq
354
+ when Array
355
+ unless val.eql?(TOC_LEVELS_ARRAY)
356
+ val = val.map(&:to_i).uniq
357
+ end
358
+ when Range
359
+ if val.eql?(TOC_LEVELS_RANGE)
360
+ val = TOC_LEVELS_ARRAY
361
+ else
362
+ val = val.map(&:to_i).uniq
363
+ end
352
364
  else
353
365
  raise Kramdown::Error, "Invalid type #{val.class} for option toc_levels"
354
366
  end
355
- if val.any? {|i| !(1..6).cover?(i) }
367
+ if val.any? {|i| !TOC_LEVELS_RANGE.cover?(i) }
356
368
  raise Kramdown::Error, "Level numbers for option toc_levels have to be integers from 1 to 6"
357
369
  end
358
370
  val
@@ -377,7 +389,11 @@ module Kramdown
377
389
  simple_array_validator(val, :latex_headers, 6)
378
390
  end
379
391
 
380
- define(:smart_quotes, Object, %w[lsquo rsquo ldquo rdquo], <<~EOF) do |val|
392
+ SMART_QUOTES_ENTITIES = %w[lsquo rsquo ldquo rdquo].freeze
393
+ SMART_QUOTES_STR = SMART_QUOTES_ENTITIES.join(',').freeze
394
+ private_constant :SMART_QUOTES_ENTITIES, :SMART_QUOTES_STR
395
+
396
+ define(:smart_quotes, Object, SMART_QUOTES_ENTITIES, <<~EOF) do |val|
381
397
  Defines the HTML entity names or code points for smart quote output
382
398
 
383
399
  The entities identified by entity name or code point that should be
@@ -388,9 +404,13 @@ module Kramdown
388
404
  Default: lsquo,rsquo,ldquo,rdquo
389
405
  Used by: HTML/Latex converter
390
406
  EOF
391
- val = simple_array_validator(val, :smart_quotes, 4)
392
- val.map! {|v| Integer(v) rescue v }
393
- val
407
+ if val == SMART_QUOTES_STR || val == SMART_QUOTES_ENTITIES
408
+ SMART_QUOTES_ENTITIES
409
+ else
410
+ val = simple_array_validator(val, :smart_quotes, 4)
411
+ val.map! {|v| Integer(v) rescue v }
412
+ val
413
+ end
394
414
  end
395
415
 
396
416
  define(:typographic_symbols, Object, {}, <<~EOF) do |val|
@@ -562,6 +582,13 @@ module Kramdown
562
582
  Used by: HTML
563
583
  EOF
564
584
 
585
+ define(:remove_line_breaks_for_cjk, Boolean, false, <<~EOF)
586
+ Specifies whether line breaks should be removed between CJK characters
587
+
588
+ Default: false
589
+ Used by: HTML converter
590
+ EOF
591
+
565
592
  end
566
593
 
567
594
  end
@@ -93,7 +93,9 @@ module Kramdown
93
93
  raise "The source text contains invalid characters for the used encoding #{source.encoding}"
94
94
  end
95
95
  source = source.encode('UTF-8')
96
- source.gsub(/\r\n?/, "\n").chomp + "\n"
96
+ source.gsub!(/\r\n?/, "\n")
97
+ source.chomp!
98
+ source << "\n"
97
99
  end
98
100
 
99
101
  # This helper method adds the given +text+ either to the last element in the +tree+ if it is a
@@ -16,7 +16,7 @@ module Kramdown
16
16
 
17
17
  module Parser
18
18
 
19
- # Used for parsing a HTML document.
19
+ # Used for parsing an HTML document.
20
20
  #
21
21
  # The parsing code is in the Parser module that can also be used by other parsers.
22
22
  class Html < Base
@@ -286,7 +286,7 @@ module Kramdown
286
286
  src = Kramdown::Utils::StringScanner.new(raw)
287
287
  result = []
288
288
  until src.eos?
289
- if (tmp = src.scan_until(/(?=#{HTML_ENTITY_RE})/))
289
+ if (tmp = src.scan_until(/(?=#{HTML_ENTITY_RE})/o))
290
290
  result << Element.new(:text, tmp)
291
291
  src.scan(HTML_ENTITY_RE)
292
292
  val = src[1] || (src[2]&.to_i) || src[3].hex
@@ -324,7 +324,7 @@ module Kramdown
324
324
  tmp = []
325
325
  last_is_p = false
326
326
  el.children.each do |c|
327
- if Element.category(c) != :block || c.type == :text
327
+ if !c.block? || c.type == :text
328
328
  unless last_is_p
329
329
  tmp << Element.new(:p, nil, nil, transparent: true)
330
330
  last_is_p = true
@@ -354,8 +354,8 @@ module Kramdown
354
354
  el.children = el.children.reject do |c|
355
355
  i += 1
356
356
  c.type == :text && c.value.strip.empty? &&
357
- (i == 0 || i == el.children.length - 1 || (Element.category(el.children[i - 1]) == :block &&
358
- Element.category(el.children[i + 1]) == :block))
357
+ (i == 0 || i == el.children.length - 1 || ((el.children[i - 1]).block? &&
358
+ (el.children[i + 1]).block?))
359
359
  end
360
360
  end
361
361
 
@@ -581,11 +581,11 @@ module Kramdown
581
581
  @src = Kramdown::Utils::StringScanner.new(adapt_source(source))
582
582
 
583
583
  while true
584
- if (result = @src.scan(/\s*#{HTML_INSTRUCTION_RE}/))
584
+ if (result = @src.scan(/\s*#{HTML_INSTRUCTION_RE}/o))
585
585
  @tree.children << Element.new(:xml_pi, result.strip, nil, category: :block)
586
- elsif (result = @src.scan(/\s*#{HTML_DOCTYPE_RE}/))
586
+ elsif (result = @src.scan(/\s*#{HTML_DOCTYPE_RE}/o))
587
587
  # ignore the doctype
588
- elsif (result = @src.scan(/\s*#{HTML_COMMENT_RE}/))
588
+ elsif (result = @src.scan(/\s*#{HTML_COMMENT_RE}/o))
589
589
  @tree.children << Element.new(:xml_comment, result.strip, nil, category: :block)
590
590
  else
591
591
  break