qiita_marker 0.23.2.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +7 -0
- data/LICENSE.txt +21 -0
- data/README.md +50 -0
- data/Rakefile +113 -0
- data/bin/qiita_marker +123 -0
- data/ext/qiita_marker/arena.c +103 -0
- data/ext/qiita_marker/autolink.c +425 -0
- data/ext/qiita_marker/autolink.h +8 -0
- data/ext/qiita_marker/blocks.c +1596 -0
- data/ext/qiita_marker/buffer.c +278 -0
- data/ext/qiita_marker/buffer.h +116 -0
- data/ext/qiita_marker/case_fold_switch.inc +4327 -0
- data/ext/qiita_marker/chunk.h +135 -0
- data/ext/qiita_marker/cmark-gfm-core-extensions.h +54 -0
- data/ext/qiita_marker/cmark-gfm-extension_api.h +736 -0
- data/ext/qiita_marker/cmark-gfm-extensions_export.h +42 -0
- data/ext/qiita_marker/cmark-gfm.h +817 -0
- data/ext/qiita_marker/cmark-gfm_export.h +42 -0
- data/ext/qiita_marker/cmark-gfm_version.h +7 -0
- data/ext/qiita_marker/cmark.c +55 -0
- data/ext/qiita_marker/cmark_ctype.c +44 -0
- data/ext/qiita_marker/cmark_ctype.h +33 -0
- data/ext/qiita_marker/commonmark.c +529 -0
- data/ext/qiita_marker/config.h +76 -0
- data/ext/qiita_marker/core-extensions.c +27 -0
- data/ext/qiita_marker/entities.inc +2138 -0
- data/ext/qiita_marker/ext_scanners.c +879 -0
- data/ext/qiita_marker/ext_scanners.h +24 -0
- data/ext/qiita_marker/extconf.rb +7 -0
- data/ext/qiita_marker/footnotes.c +63 -0
- data/ext/qiita_marker/footnotes.h +27 -0
- data/ext/qiita_marker/houdini.h +57 -0
- data/ext/qiita_marker/houdini_href_e.c +100 -0
- data/ext/qiita_marker/houdini_html_e.c +66 -0
- data/ext/qiita_marker/houdini_html_u.c +149 -0
- data/ext/qiita_marker/html.c +486 -0
- data/ext/qiita_marker/html.h +27 -0
- data/ext/qiita_marker/inlines.c +1691 -0
- data/ext/qiita_marker/inlines.h +29 -0
- data/ext/qiita_marker/iterator.c +159 -0
- data/ext/qiita_marker/iterator.h +26 -0
- data/ext/qiita_marker/latex.c +466 -0
- data/ext/qiita_marker/linked_list.c +37 -0
- data/ext/qiita_marker/man.c +278 -0
- data/ext/qiita_marker/map.c +122 -0
- data/ext/qiita_marker/map.h +41 -0
- data/ext/qiita_marker/node.c +979 -0
- data/ext/qiita_marker/node.h +125 -0
- data/ext/qiita_marker/parser.h +58 -0
- data/ext/qiita_marker/plaintext.c +235 -0
- data/ext/qiita_marker/plugin.c +36 -0
- data/ext/qiita_marker/plugin.h +34 -0
- data/ext/qiita_marker/qiita_marker.c +1321 -0
- data/ext/qiita_marker/qiita_marker.h +16 -0
- data/ext/qiita_marker/references.c +42 -0
- data/ext/qiita_marker/references.h +26 -0
- data/ext/qiita_marker/registry.c +63 -0
- data/ext/qiita_marker/registry.h +24 -0
- data/ext/qiita_marker/render.c +205 -0
- data/ext/qiita_marker/render.h +62 -0
- data/ext/qiita_marker/scanners.c +10520 -0
- data/ext/qiita_marker/scanners.h +62 -0
- data/ext/qiita_marker/scanners.re +341 -0
- data/ext/qiita_marker/strikethrough.c +167 -0
- data/ext/qiita_marker/strikethrough.h +9 -0
- data/ext/qiita_marker/syntax_extension.c +149 -0
- data/ext/qiita_marker/syntax_extension.h +34 -0
- data/ext/qiita_marker/table.c +822 -0
- data/ext/qiita_marker/table.h +12 -0
- data/ext/qiita_marker/tagfilter.c +60 -0
- data/ext/qiita_marker/tagfilter.h +8 -0
- data/ext/qiita_marker/tasklist.c +156 -0
- data/ext/qiita_marker/tasklist.h +8 -0
- data/ext/qiita_marker/utf8.c +317 -0
- data/ext/qiita_marker/utf8.h +35 -0
- data/ext/qiita_marker/xml.c +181 -0
- data/lib/qiita_marker/config.rb +52 -0
- data/lib/qiita_marker/node/inspect.rb +57 -0
- data/lib/qiita_marker/node.rb +83 -0
- data/lib/qiita_marker/renderer/html_renderer.rb +252 -0
- data/lib/qiita_marker/renderer.rb +135 -0
- data/lib/qiita_marker/version.rb +5 -0
- data/lib/qiita_marker.rb +45 -0
- data/qiita_marker.gemspec +40 -0
- data/test/benchmark.rb +32 -0
- data/test/fixtures/curly.md +1 -0
- data/test/fixtures/dingus.md +10 -0
- data/test/fixtures/strong.md +1 -0
- data/test/fixtures/table.md +10 -0
- data/test/test_attributes.rb +24 -0
- data/test/test_basics.rb +35 -0
- data/test/test_commands.rb +72 -0
- data/test/test_commonmark.rb +36 -0
- data/test/test_doc.rb +130 -0
- data/test/test_encoding.rb +23 -0
- data/test/test_extensions.rb +116 -0
- data/test/test_footnotes.rb +60 -0
- data/test/test_gc.rb +47 -0
- data/test/test_helper.rb +71 -0
- data/test/test_linebreaks.rb +15 -0
- data/test/test_maliciousness.rb +262 -0
- data/test/test_node.rb +89 -0
- data/test/test_options.rb +37 -0
- data/test/test_pathological_inputs.rb +94 -0
- data/test/test_plaintext.rb +46 -0
- data/test/test_renderer.rb +47 -0
- data/test/test_smartpunct.rb +27 -0
- data/test/test_spec.rb +30 -0
- data/test/test_tasklists.rb +43 -0
- data/test/test_xml.rb +107 -0
- metadata +313 -0
@@ -0,0 +1,135 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require 'set'
|
4
|
+
require 'stringio'
|
5
|
+
|
6
|
+
module QiitaMarker
|
7
|
+
class Renderer
|
8
|
+
attr_accessor :in_tight, :warnings, :in_plain
|
9
|
+
|
10
|
+
def initialize(options: :DEFAULT, extensions: [])
|
11
|
+
@opts = Config.process_options(options, :render)
|
12
|
+
@stream = StringIO.new(+'')
|
13
|
+
@need_blocksep = false
|
14
|
+
@warnings = Set.new []
|
15
|
+
@in_tight = false
|
16
|
+
@in_plain = false
|
17
|
+
@tagfilter = extensions.include?(:tagfilter)
|
18
|
+
end
|
19
|
+
|
20
|
+
def out(*args)
|
21
|
+
args.each do |arg|
|
22
|
+
case arg
|
23
|
+
when :children
|
24
|
+
@node.each { |child| out(child) }
|
25
|
+
when Array
|
26
|
+
arg.each { |x| render(x) }
|
27
|
+
when Node
|
28
|
+
render(arg)
|
29
|
+
else
|
30
|
+
@stream.write(arg)
|
31
|
+
end
|
32
|
+
end
|
33
|
+
end
|
34
|
+
|
35
|
+
def render(node)
|
36
|
+
@node = node
|
37
|
+
if node.type == :document
|
38
|
+
document(node)
|
39
|
+
@stream.string
|
40
|
+
elsif @in_plain && node.type != :text && node.type != :softbreak
|
41
|
+
node.each { |child| render(child) }
|
42
|
+
else
|
43
|
+
begin
|
44
|
+
send(node.type, node)
|
45
|
+
rescue NoMethodError => e
|
46
|
+
@warnings.add("WARNING: #{node.type} not implemented.")
|
47
|
+
raise e
|
48
|
+
end
|
49
|
+
end
|
50
|
+
end
|
51
|
+
|
52
|
+
def document(_node)
|
53
|
+
out(:children)
|
54
|
+
end
|
55
|
+
|
56
|
+
def code_block(node)
|
57
|
+
code_block(node)
|
58
|
+
end
|
59
|
+
|
60
|
+
def reference_def(_node); end
|
61
|
+
|
62
|
+
def cr
|
63
|
+
return if @stream.string.empty? || @stream.string[-1] == "\n"
|
64
|
+
|
65
|
+
out("\n")
|
66
|
+
end
|
67
|
+
|
68
|
+
def blocksep
|
69
|
+
out("\n")
|
70
|
+
end
|
71
|
+
|
72
|
+
def containersep
|
73
|
+
cr unless @in_tight
|
74
|
+
end
|
75
|
+
|
76
|
+
def block
|
77
|
+
cr
|
78
|
+
yield
|
79
|
+
cr
|
80
|
+
end
|
81
|
+
|
82
|
+
def container(starter, ender)
|
83
|
+
out(starter)
|
84
|
+
yield
|
85
|
+
out(ender)
|
86
|
+
end
|
87
|
+
|
88
|
+
def plain
|
89
|
+
old_in_plain = @in_plain
|
90
|
+
@in_plain = true
|
91
|
+
yield
|
92
|
+
@in_plain = old_in_plain
|
93
|
+
end
|
94
|
+
|
95
|
+
private
|
96
|
+
|
97
|
+
def escape_href(str)
|
98
|
+
@node.html_escape_href(str)
|
99
|
+
end
|
100
|
+
|
101
|
+
def escape_html(str)
|
102
|
+
@node.html_escape_html(str)
|
103
|
+
end
|
104
|
+
|
105
|
+
def tagfilter(str)
|
106
|
+
if @tagfilter
|
107
|
+
str.gsub(
|
108
|
+
%r{
|
109
|
+
<
|
110
|
+
(
|
111
|
+
title|textarea|style|xmp|iframe|
|
112
|
+
noembed|noframes|script|plaintext
|
113
|
+
)
|
114
|
+
(?=\s|>|/>)
|
115
|
+
}xi,
|
116
|
+
'<\1'
|
117
|
+
)
|
118
|
+
else
|
119
|
+
str
|
120
|
+
end
|
121
|
+
end
|
122
|
+
|
123
|
+
def sourcepos(node)
|
124
|
+
return '' unless option_enabled?(:SOURCEPOS)
|
125
|
+
|
126
|
+
s = node.sourcepos
|
127
|
+
" data-sourcepos=\"#{s[:start_line]}:#{s[:start_column]}-" \
|
128
|
+
"#{s[:end_line]}:#{s[:end_column]}\""
|
129
|
+
end
|
130
|
+
|
131
|
+
def option_enabled?(opt)
|
132
|
+
(@opts & QiitaMarker::Config::OPTS.dig(:render, opt)) != 0
|
133
|
+
end
|
134
|
+
end
|
135
|
+
end
|
data/lib/qiita_marker.rb
ADDED
@@ -0,0 +1,45 @@
|
|
1
|
+
#!/usr/bin/env ruby
|
2
|
+
# frozen_string_literal: true
|
3
|
+
|
4
|
+
require 'qiita_marker/qiita_marker'
|
5
|
+
require 'qiita_marker/config'
|
6
|
+
require 'qiita_marker/node'
|
7
|
+
require 'qiita_marker/renderer'
|
8
|
+
require 'qiita_marker/renderer/html_renderer'
|
9
|
+
require 'qiita_marker/version'
|
10
|
+
|
11
|
+
begin
|
12
|
+
require 'awesome_print'
|
13
|
+
rescue LoadError; end # rubocop:disable Lint/SuppressedException
|
14
|
+
module QiitaMarker
|
15
|
+
# Public: Parses a Markdown string into an HTML string.
|
16
|
+
#
|
17
|
+
# text - A {String} of text
|
18
|
+
# option - Either a {Symbol} or {Array of Symbol}s indicating the render options
|
19
|
+
# extensions - An {Array of Symbol}s indicating the extensions to use
|
20
|
+
#
|
21
|
+
# Returns a {String} of converted HTML.
|
22
|
+
def self.render_html(text, options = :DEFAULT, extensions = [])
|
23
|
+
raise TypeError, "text must be a String; got a #{text.class}!" unless text.is_a?(String)
|
24
|
+
|
25
|
+
opts = Config.process_options(options, :render)
|
26
|
+
text = text.encode('UTF-8')
|
27
|
+
html = Node.markdown_to_html(text, opts, extensions)
|
28
|
+
html.force_encoding('UTF-8')
|
29
|
+
end
|
30
|
+
|
31
|
+
# Public: Parses a Markdown string into a `document` node.
|
32
|
+
#
|
33
|
+
# string - {String} to be parsed
|
34
|
+
# option - A {Symbol} or {Array of Symbol}s indicating the parse options
|
35
|
+
# extensions - An {Array of Symbol}s indicating the extensions to use
|
36
|
+
#
|
37
|
+
# Returns the `document` node.
|
38
|
+
def self.render_doc(text, options = :DEFAULT, extensions = [])
|
39
|
+
raise TypeError, "text must be a String; got a #{text.class}!" unless text.is_a?(String)
|
40
|
+
|
41
|
+
opts = Config.process_options(options, :parse)
|
42
|
+
text = text.encode('UTF-8')
|
43
|
+
Node.parse_document(text, text.bytesize, opts, extensions)
|
44
|
+
end
|
45
|
+
end
|
@@ -0,0 +1,40 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
lib = File.expand_path('lib', __dir__)
|
4
|
+
$LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
|
5
|
+
require 'qiita_marker/version'
|
6
|
+
|
7
|
+
Gem::Specification.new do |s|
|
8
|
+
s.name = 'qiita_marker'
|
9
|
+
s.version = QiitaMarker::VERSION
|
10
|
+
s.summary = 'Qiita Marker is a Ruby library for Markdown processing, based on CommonMarker.'
|
11
|
+
s.description = 'A Ruby library that is the core module of the Qiita-specified markdown processor.'
|
12
|
+
s.authors = ['Increments Inc.']
|
13
|
+
s.homepage = 'https://github.com/increments/qiita_marker'
|
14
|
+
s.license = 'MIT'
|
15
|
+
|
16
|
+
s.files = %w[LICENSE.txt README.md Rakefile qiita_marker.gemspec bin/qiita_marker]
|
17
|
+
s.files += Dir.glob('lib/**/*.rb')
|
18
|
+
s.files += Dir.glob('ext/qiita_marker/*.*')
|
19
|
+
s.test_files = Dir.glob('test/**/*').reject { |f| f == 'test/benchinput.md' || f.start_with?('test/progit/') }
|
20
|
+
s.extensions = ['ext/qiita_marker/extconf.rb']
|
21
|
+
|
22
|
+
s.executables = ['qiita_marker']
|
23
|
+
s.require_paths = %w[lib ext]
|
24
|
+
s.required_ruby_version = ['>= 2.6', '< 4.0']
|
25
|
+
|
26
|
+
s.rdoc_options += ['-x', 'ext/qiita_marker/cmark/.*']
|
27
|
+
|
28
|
+
s.add_development_dependency 'awesome_print'
|
29
|
+
s.add_development_dependency 'json', '~> 2.3'
|
30
|
+
s.add_development_dependency 'minitest', '~> 5.6'
|
31
|
+
s.add_development_dependency 'minitest-focus', '~> 1.1'
|
32
|
+
s.add_development_dependency 'rake'
|
33
|
+
s.add_development_dependency 'rake-compiler', '~> 0.9'
|
34
|
+
s.add_development_dependency 'rdoc', '~> 6.2'
|
35
|
+
s.add_development_dependency 'rubocop'
|
36
|
+
s.add_development_dependency 'rubocop-standard'
|
37
|
+
s.metadata = {
|
38
|
+
'rubygems_mfa_required' => 'true'
|
39
|
+
}
|
40
|
+
end
|
data/test/benchmark.rb
ADDED
@@ -0,0 +1,32 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require 'qiita_marker'
|
4
|
+
require 'github/markdown'
|
5
|
+
require 'redcarpet'
|
6
|
+
require 'kramdown'
|
7
|
+
require 'benchmark'
|
8
|
+
|
9
|
+
def dobench(name, &blk)
|
10
|
+
puts name
|
11
|
+
puts Benchmark.measure(&blk)
|
12
|
+
end
|
13
|
+
|
14
|
+
benchinput = File.open('test/benchinput.md', 'r').read
|
15
|
+
|
16
|
+
printf("input size = %<bytes>d bytes\n\n", benchinput.bytesize)
|
17
|
+
|
18
|
+
dobench('redcarpet') do
|
19
|
+
Redcarpet::Markdown.new(Redcarpet::Render::HTML, autolink: false, tables: false).render(benchinput)
|
20
|
+
end
|
21
|
+
|
22
|
+
dobench('qiita_marker with to_html') do
|
23
|
+
QiitaMarker.render_html(benchinput)
|
24
|
+
end
|
25
|
+
|
26
|
+
dobench('qiita_marker with ruby HtmlRenderer') do
|
27
|
+
QiitaMarker::HtmlRenderer.new.render(QiitaMarker.render_doc(benchinput))
|
28
|
+
end
|
29
|
+
|
30
|
+
dobench('kramdown') do
|
31
|
+
Kramdown::Document.new(benchinput).to_html(benchinput)
|
32
|
+
end
|
@@ -0,0 +1 @@
|
|
1
|
+
This curly quote “makes qiita_marker throw an exception”.
|
@@ -0,0 +1 @@
|
|
1
|
+
I am **strong**
|
@@ -0,0 +1,24 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require 'test_helper'
|
4
|
+
|
5
|
+
class TestAttributes < Minitest::Test
|
6
|
+
def setup
|
7
|
+
contents = fixtures_file('dingus.md')
|
8
|
+
@doc = QiitaMarker.render_doc(contents.strip)
|
9
|
+
end
|
10
|
+
|
11
|
+
def test_sourcepos
|
12
|
+
sourcepos = []
|
13
|
+
|
14
|
+
@doc.walk do |node|
|
15
|
+
sourcepos << node.sourcepos
|
16
|
+
end
|
17
|
+
|
18
|
+
sourcepos.delete_if { |h| h.values.all?(&:zero?) }
|
19
|
+
|
20
|
+
result = [{ start_line: 1, start_column: 1, end_line: 10, end_column: 12 }, { start_line: 1, start_column: 1, end_line: 1, end_column: 17 }, { start_line: 1, start_column: 4, end_line: 1, end_column: 17 }, { start_line: 3, start_column: 1, end_line: 5, end_column: 36 }, { start_line: 3, start_column: 1, end_line: 3, end_column: 55 }, { start_line: 4, start_column: 1, end_line: 4, end_column: 53 }, { start_line: 4, start_column: 2, end_line: 4, end_column: 14 }, { start_line: 4, start_column: 54, end_line: 4, end_column: 58 }, { start_line: 5, start_column: 1, end_line: 5, end_column: 36 }, { start_line: 7, start_column: 1, end_line: 10, end_column: 12 }, { start_line: 7, start_column: 1, end_line: 7, end_column: 11 }, { start_line: 7, start_column: 4, end_line: 7, end_column: 11 }, { start_line: 7, start_column: 4, end_line: 7, end_column: 11 }, { start_line: 8, start_column: 1, end_line: 10, end_column: 12 }, { start_line: 8, start_column: 4, end_line: 8, end_column: 11 }, { start_line: 8, start_column: 4, end_line: 8, end_column: 11 }, { start_line: 9, start_column: 4, end_line: 10, end_column: 12 }, { start_line: 9, start_column: 4, end_line: 9, end_column: 12 }, { start_line: 9, start_column: 6, end_line: 9, end_column: 12 }, { start_line: 9, start_column: 6, end_line: 9, end_column: 12 }, { start_line: 10, start_column: 4, end_line: 10, end_column: 12 }, { start_line: 10, start_column: 6, end_line: 10, end_column: 12 }, { start_line: 10, start_column: 6, end_line: 10, end_column: 12 }]
|
21
|
+
|
22
|
+
assert_equal result, sourcepos
|
23
|
+
end
|
24
|
+
end
|
data/test/test_basics.rb
ADDED
@@ -0,0 +1,35 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require 'test_helper'
|
4
|
+
|
5
|
+
class TestBasics < Minitest::Test
|
6
|
+
def setup
|
7
|
+
@doc = QiitaMarker.render_doc('Hi *there*')
|
8
|
+
end
|
9
|
+
|
10
|
+
def test_to_html
|
11
|
+
assert_equal "<p>Hi <em>there</em></p>\n", @doc.to_html
|
12
|
+
end
|
13
|
+
|
14
|
+
def test_markdown_to_html
|
15
|
+
html = QiitaMarker.render_html('Hi *there*')
|
16
|
+
assert_equal "<p>Hi <em>there</em></p>\n", html
|
17
|
+
end
|
18
|
+
|
19
|
+
# basic test that just checks if every option is accepted & no errors are thrown
|
20
|
+
def test_accept_every_option
|
21
|
+
text = "Hello **world** -- how are _you_ today? I'm ~~fine~~, ~yourself~?"
|
22
|
+
parse_opt = %i[SOURCEPOS UNSAFE VALIDATE_UTF8 SMART LIBERAL_HTML_TAG FOOTNOTES STRIKETHROUGH_DOUBLE_TILDE]
|
23
|
+
render_opt = parse_opt + %i[HARDBREAKS NOBREAKS GITHUB_PRE_LANG TABLE_PREFER_STYLE_ATTRIBUTES FULL_INFO_STRING]
|
24
|
+
|
25
|
+
extensions = %i[table tasklist strikethrough autolink tagfilter]
|
26
|
+
|
27
|
+
assert_equal "<p>Hello <strong>world</strong> – how are <em>you</em> today? I’m <del>fine</del>, ~yourself~?</p>\n", QiitaMarker.render_doc(text, parse_opt, extensions).to_html
|
28
|
+
|
29
|
+
# NOTE: how tho the doc returned has sourcepos info, by default the renderer
|
30
|
+
# won't emit it. for that we need to pass in the render opt
|
31
|
+
assert_equal "<p data-sourcepos=\"1:1-1:65\">Hello <strong>world</strong> – how are <em>you</em> today? I’m <del>fine</del>, ~yourself~?</p>\n", QiitaMarker.render_doc(text, parse_opt, extensions).to_html(render_opt, extensions)
|
32
|
+
|
33
|
+
assert_equal "<p data-sourcepos=\"1:1-1:65\">Hello <strong>world</strong> – how are <em>you</em> today? I’m <del>fine</del>, ~yourself~?</p>\n", QiitaMarker.render_html(text, parse_opt, extensions)
|
34
|
+
end
|
35
|
+
end
|
@@ -0,0 +1,72 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require 'test_helper'
|
4
|
+
|
5
|
+
class TestCommands < Minitest::Test
|
6
|
+
def test_basic
|
7
|
+
out = make_bin('strong.md')
|
8
|
+
assert_equal('<p>I am <strong>strong</strong></p>', out)
|
9
|
+
end
|
10
|
+
|
11
|
+
def test_does_not_have_extensions
|
12
|
+
out = make_bin('table.md')
|
13
|
+
assert_includes out, '| a'
|
14
|
+
refute_includes out, '<p><del>hi</del>'
|
15
|
+
refute_includes out, '<table> <tr> <th> a </th> <td> c </td>'
|
16
|
+
end
|
17
|
+
|
18
|
+
def test_understands_extensions
|
19
|
+
out = make_bin('table.md', '--extension=table')
|
20
|
+
refute_includes out, '| a'
|
21
|
+
refute_includes out, '<p><del>hi</del>'
|
22
|
+
%w[<table> <tr> <th> a </th> <td> c </td>].each { |html| assert_includes out, html }
|
23
|
+
end
|
24
|
+
|
25
|
+
def test_understands_multiple_extensions
|
26
|
+
out = make_bin('table.md', '--extension=table,strikethrough')
|
27
|
+
refute_includes out, '| a'
|
28
|
+
assert_includes out, '<p><del>hi</del>'
|
29
|
+
%w[<table> <tr> <th> a </th> <td> c </td>].each { |html| assert_includes out, html }
|
30
|
+
end
|
31
|
+
|
32
|
+
def test_understands_html_format_with_renderer_and_extensions
|
33
|
+
out = make_bin('table.md', '--to=html --extension=table,strikethrough --html-renderer')
|
34
|
+
refute_includes out, '| a'
|
35
|
+
assert_includes out, '<p><del>hi</del>'
|
36
|
+
%w[<table> <tr> <th> a </th> <td> c </td>].each { |html| assert_includes out, html }
|
37
|
+
end
|
38
|
+
|
39
|
+
def test_understands_xml_format
|
40
|
+
out = make_bin('strong.md', '--to=xml')
|
41
|
+
assert_includes out, '<?xml version="1.0" encoding="UTF-8"?>'
|
42
|
+
assert_includes out, '<text xml:space="preserve">strong</text>'
|
43
|
+
end
|
44
|
+
|
45
|
+
def test_understands_commonmark_format
|
46
|
+
out = make_bin('strong.md', '--to=commonmark')
|
47
|
+
assert_equal('I am **strong**', out)
|
48
|
+
end
|
49
|
+
|
50
|
+
def test_understands_plaintext_format
|
51
|
+
out = make_bin('strong.md', '--to=plaintext')
|
52
|
+
assert_equal('I am strong', out)
|
53
|
+
end
|
54
|
+
|
55
|
+
def test_aborts_invalid_format
|
56
|
+
_out, err = capture_subprocess_io do
|
57
|
+
make_bin('strong.md', '--to=unknown')
|
58
|
+
end
|
59
|
+
|
60
|
+
assert_match "format 'unknown' not found", err
|
61
|
+
end
|
62
|
+
|
63
|
+
def test_aborts_format_and_html_renderer_combinations
|
64
|
+
(QiitaMarker::Config::OPTS[:format] - [:html]).each do |format|
|
65
|
+
_out, err = capture_subprocess_io do
|
66
|
+
make_bin('strong.md', "--to=#{format} --html-renderer")
|
67
|
+
end
|
68
|
+
|
69
|
+
assert_match "format '#{format}' does not support using the HtmlRenderer renderer", err
|
70
|
+
end
|
71
|
+
end
|
72
|
+
end
|
@@ -0,0 +1,36 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require 'test_helper'
|
4
|
+
|
5
|
+
class TestCommonmark < Minitest::Test
|
6
|
+
HTML_COMMENT = /<!--.*?-->\s?/.freeze
|
7
|
+
|
8
|
+
def setup
|
9
|
+
@markdown = <<~MD
|
10
|
+
Hi *there*!
|
11
|
+
|
12
|
+
1. I am a numeric list.
|
13
|
+
2. I continue the list.
|
14
|
+
* Suddenly, an unordered list!
|
15
|
+
* What fun!
|
16
|
+
|
17
|
+
Okay, _enough_.
|
18
|
+
|
19
|
+
| a | b |
|
20
|
+
| --- | --- |
|
21
|
+
| c | d |
|
22
|
+
MD
|
23
|
+
end
|
24
|
+
|
25
|
+
def render_doc(doc)
|
26
|
+
QiitaMarker.render_doc(doc, :DEFAULT, %i[table])
|
27
|
+
end
|
28
|
+
|
29
|
+
def test_to_commonmark
|
30
|
+
compare = render_doc(@markdown).to_commonmark
|
31
|
+
|
32
|
+
assert_equal \
|
33
|
+
render_doc(@markdown).to_html.squeeze(' ').gsub(HTML_COMMENT, ''),
|
34
|
+
render_doc(compare).to_html.squeeze(' ').gsub(HTML_COMMENT, '')
|
35
|
+
end
|
36
|
+
end
|
data/test/test_doc.rb
ADDED
@@ -0,0 +1,130 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require 'test_helper'
|
4
|
+
|
5
|
+
class TestDocNode < Minitest::Test
|
6
|
+
def setup
|
7
|
+
@doc = QiitaMarker.render_doc('Hi *there*. This has __many nodes__!')
|
8
|
+
@first_child = @doc.first_child
|
9
|
+
@last_child = @doc.last_child
|
10
|
+
@link = QiitaMarker.render_doc('[GitHub](https://www.github.com)').first_child.first_child
|
11
|
+
@image = QiitaMarker.render_doc('![alt text](https://github.com/favicon.ico "Favicon")')
|
12
|
+
@image = @image.first_child.first_child
|
13
|
+
@header = QiitaMarker.render_doc('### Header Three').first_child
|
14
|
+
@ul_list = QiitaMarker.render_doc("* Bullet\n*Bullet").first_child
|
15
|
+
@ol_list = QiitaMarker.render_doc("1. One\n2. Two").first_child
|
16
|
+
@fence = QiitaMarker.render_doc("``` ruby\nputs 'wow'\n```").first_child
|
17
|
+
end
|
18
|
+
|
19
|
+
def test_get_type
|
20
|
+
assert_equal(:document, @doc.type)
|
21
|
+
end
|
22
|
+
|
23
|
+
def test_get_type_string
|
24
|
+
assert_equal('document', @doc.type_string)
|
25
|
+
end
|
26
|
+
|
27
|
+
def test_get_first_child
|
28
|
+
assert_equal(:paragraph, @first_child.type)
|
29
|
+
end
|
30
|
+
|
31
|
+
def test_get_next
|
32
|
+
assert_equal(:emph, @first_child.first_child.next.type)
|
33
|
+
end
|
34
|
+
|
35
|
+
def test_insert_before
|
36
|
+
paragraph = Node.new(:paragraph)
|
37
|
+
assert(@first_child.insert_before(paragraph))
|
38
|
+
assert_match "<p></p>\n<p>Hi <em>there</em>.", @doc.to_html
|
39
|
+
end
|
40
|
+
|
41
|
+
def test_insert_after
|
42
|
+
paragraph = Node.new(:paragraph)
|
43
|
+
assert(@first_child.insert_after(paragraph))
|
44
|
+
assert_match "<strong>many nodes</strong>!</p>\n<p></p>\n", @doc.to_html
|
45
|
+
end
|
46
|
+
|
47
|
+
def test_prepend_child
|
48
|
+
code = Node.new(:code)
|
49
|
+
assert(@first_child.prepend_child(code))
|
50
|
+
assert_match '<p><code></code>Hi <em>there</em>.', @doc.to_html
|
51
|
+
end
|
52
|
+
|
53
|
+
def test_append_child
|
54
|
+
strong = Node.new(:strong)
|
55
|
+
assert(@first_child.append_child(strong))
|
56
|
+
assert_match "!<strong></strong></p>\n", @doc.to_html
|
57
|
+
end
|
58
|
+
|
59
|
+
def test_get_last_child
|
60
|
+
assert_equal(:paragraph, @last_child.type)
|
61
|
+
end
|
62
|
+
|
63
|
+
def test_get_parent
|
64
|
+
assert_equal(:paragraph, @first_child.first_child.next.parent.type)
|
65
|
+
end
|
66
|
+
|
67
|
+
def test_get_previous
|
68
|
+
assert_equal(:text, @first_child.first_child.next.previous.type)
|
69
|
+
end
|
70
|
+
|
71
|
+
def test_get_url
|
72
|
+
assert_equal('https://www.github.com', @link.url)
|
73
|
+
end
|
74
|
+
|
75
|
+
def test_set_url
|
76
|
+
assert_equal('https://www.mozilla.org', @link.url = 'https://www.mozilla.org')
|
77
|
+
end
|
78
|
+
|
79
|
+
def test_get_title
|
80
|
+
assert_equal('Favicon', @image.title)
|
81
|
+
end
|
82
|
+
|
83
|
+
def test_set_title
|
84
|
+
assert_equal('Octocat', @image.title = 'Octocat')
|
85
|
+
end
|
86
|
+
|
87
|
+
def test_get_header_level
|
88
|
+
assert_equal(3, @header.header_level)
|
89
|
+
end
|
90
|
+
|
91
|
+
def test_set_header_level
|
92
|
+
assert_equal(6, @header.header_level = 6)
|
93
|
+
end
|
94
|
+
|
95
|
+
def test_get_list_type
|
96
|
+
assert_equal(:bullet_list, @ul_list.list_type)
|
97
|
+
assert_equal(:ordered_list, @ol_list.list_type)
|
98
|
+
end
|
99
|
+
|
100
|
+
def test_set_list_type
|
101
|
+
assert_equal(:ordered_list, @ul_list.list_type = :ordered_list)
|
102
|
+
assert_equal(:bullet_list, @ol_list.list_type = :bullet_list)
|
103
|
+
end
|
104
|
+
|
105
|
+
def test_get_list_start
|
106
|
+
assert_equal(1, @ol_list.list_start)
|
107
|
+
end
|
108
|
+
|
109
|
+
def test_set_list_start
|
110
|
+
assert_equal(8, @ol_list.list_start = 8)
|
111
|
+
end
|
112
|
+
|
113
|
+
def test_get_list_tight
|
114
|
+
assert(@ul_list.list_tight)
|
115
|
+
assert(@ol_list.list_tight)
|
116
|
+
end
|
117
|
+
|
118
|
+
def test_set_list_tight
|
119
|
+
refute(@ul_list.list_tight = false)
|
120
|
+
refute(@ol_list.list_tight = false)
|
121
|
+
end
|
122
|
+
|
123
|
+
def test_get_fence_info
|
124
|
+
assert_equal('ruby', @fence.fence_info)
|
125
|
+
end
|
126
|
+
|
127
|
+
def test_set_fence_info
|
128
|
+
assert_equal('javascript', @fence.fence_info = 'javascript')
|
129
|
+
end
|
130
|
+
end
|
@@ -0,0 +1,23 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require 'test_helper'
|
4
|
+
|
5
|
+
class TestEncoding < Minitest::Test
|
6
|
+
# see http://git.io/vq4FR
|
7
|
+
def test_encoding
|
8
|
+
contents = fixtures_file('curly.md')
|
9
|
+
doc = QiitaMarker.render_doc(contents, :SMART)
|
10
|
+
render = doc.to_html
|
11
|
+
assert_equal('<p>This curly quote “makes qiita_marker throw an exception”.</p>', render.rstrip)
|
12
|
+
|
13
|
+
render = doc.to_xml
|
14
|
+
assert_includes(render, '<text xml:space="preserve">This curly quote “makes qiita_marker throw an exception”.</text>')
|
15
|
+
end
|
16
|
+
|
17
|
+
def test_string_content_is_utf8
|
18
|
+
doc = QiitaMarker.render_doc('Hi *there*')
|
19
|
+
text = doc.first_child.last_child.first_child
|
20
|
+
assert_equal('there', text.string_content)
|
21
|
+
assert_equal('UTF-8', text.string_content.encoding.name)
|
22
|
+
end
|
23
|
+
end
|