motion-markdown-it 0.4.0.3.0 → 4.1.0.1
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/README.md +14 -13
- data/lib/motion-markdown-it/common/simpleidn.rb +268 -0
- data/lib/motion-markdown-it/common/utils.rb +4 -13
- data/lib/motion-markdown-it/index.rb +55 -63
- data/lib/motion-markdown-it/renderer.rb +2 -0
- data/lib/motion-markdown-it/rules_core/linkify.rb +93 -95
- data/lib/motion-markdown-it/rules_core/replacements.rb +1 -1
- data/lib/motion-markdown-it/rules_core/smartquotes.rb +2 -2
- data/lib/motion-markdown-it/rules_inline/strikethrough.rb +2 -2
- data/lib/motion-markdown-it/version.rb +1 -1
- data/lib/motion-markdown-it.rb +2 -0
- data/spec/motion-markdown-it/bench_mark_spec.rb +5 -5
- data/spec/motion-markdown-it/misc_spec.rb +241 -221
- data/spec/motion-markdown-it/utils_spec.rb +0 -12
- metadata +5 -4
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: ff09df2d99031e399da64902f3d11648574bd646
|
4
|
+
data.tar.gz: f6f52c3479c1805ec267503ff12f567d7539df61
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: c145910ac522f1e62985bce82e1509fb79f6ab803d52d35886ac1c370d3e84d3bc495c4c9592b501bd25775146a505471422ff17875ac78f97ebb7f25c5518fd
|
7
|
+
data.tar.gz: 2d20509844c9f7d40b2702a0cb366dca3a65e8a0b2ed693b3c3c3e79b953004a460c6843a4e5d88ce415669c674d3cb3d4191302af5bd9965ae2077960700749
|
data/README.md
CHANGED
@@ -1,8 +1,10 @@
|
|
1
1
|
# motion-markdown-it
|
2
2
|
|
3
|
-
|
3
|
+
[![Gem Version](https://badge.fury.io/rb/motion-markdown-it.svg)](http://badge.fury.io/rb/motion-markdown-it)
|
4
4
|
|
5
|
-
|
5
|
+
Ruby/RubyMotion version of Markdown-it (CommonMark compliant and extendable)
|
6
|
+
|
7
|
+
This gem is a port of the [markdown-it Javascript package](https://github.com/markdown-it/markdown-it) by Vitaly Puzrin and Alex Kocharin. Currently synced with markdown-it 4.0.3
|
6
8
|
|
7
9
|
__[Javascript Live demo](https://markdown-it.github.io)__
|
8
10
|
|
@@ -11,14 +13,14 @@ __[Javascript Live demo](https://markdown-it.github.io)__
|
|
11
13
|
- High speed
|
12
14
|
- Community-written plugins
|
13
15
|
|
14
|
-
## Beta
|
15
|
-
|
16
|
-
The gem is still a work in progress. There are several areas to get working better, including plugins and performance. It will track as closely as possible to fixes and enhancements in the main _markdown-it_ implementation. Currently synced with markdown-it 4.0.3
|
17
|
-
|
18
16
|
## Benefit
|
19
17
|
|
20
18
|
The benefit of this project, for me at least, is to have a standardized CommonMark compliant, fast, and extendable, Markdown parser which can be used from Javascript, Ruby, and/or RubyMotion, as the development situation warrants.
|
21
19
|
|
20
|
+
## Performance
|
21
|
+
|
22
|
+
Performance is still an issue. While it performs reasonably well with small to medium files, it degrades for large files. Work in progres...
|
23
|
+
|
22
24
|
## Table of content
|
23
25
|
|
24
26
|
- [Install](#install)
|
@@ -61,20 +63,19 @@ and run `bundle install`
|
|
61
63
|
|
62
64
|
```ruby
|
63
65
|
parser = MarkdownIt::Parser.new(:commonmark, { html: false })
|
64
|
-
parser.render('# markdown-it
|
66
|
+
parser.render('# markdown-it in **Ruby**')
|
65
67
|
```
|
66
68
|
|
67
69
|
Single line rendering, without paragraph wrap:
|
68
70
|
|
69
71
|
```ruby
|
70
|
-
result = MarkdownIt::Parser.new.renderInline('__markdown-it__
|
72
|
+
result = MarkdownIt::Parser.new.renderInline('__markdown-it__ in Ruby')
|
71
73
|
```
|
72
74
|
|
73
75
|
### Init with presets and options
|
74
76
|
|
75
|
-
(*)
|
76
|
-
`:commonmark`, `:zero` or `:default` (if skipped).
|
77
|
-
[markdown-it Javascript API docs](https://markdown-it.github.io/markdown-it/#MarkdownIt.new) for more details.
|
77
|
+
(*) presets define combinations of active rules and options. Can be
|
78
|
+
`:commonmark`, `:zero` or `:default` (if skipped).
|
78
79
|
|
79
80
|
```ruby
|
80
81
|
#--- commonmark mode
|
@@ -104,8 +105,8 @@ parser = MarkdownIt::Parser.new({
|
|
104
105
|
quotes: '“”‘’',
|
105
106
|
|
106
107
|
# Highlighter function. Should return escaped HTML,
|
107
|
-
# or
|
108
|
-
highlight: lambda {|str, lang| return
|
108
|
+
# or nil if the source string is not changed and should be escaped externaly.
|
109
|
+
highlight: lambda {|str, lang| return nil}
|
109
110
|
})
|
110
111
|
```
|
111
112
|
|
@@ -0,0 +1,268 @@
|
|
1
|
+
# encoding: UTF-8
|
2
|
+
# Borrowed from https://github.com/mmriis/simpleidn
|
3
|
+
#------------------------------------------------------------------------------
|
4
|
+
class Integer
|
5
|
+
def to_utf8_character
|
6
|
+
[self].pack("U*")
|
7
|
+
end
|
8
|
+
end
|
9
|
+
|
10
|
+
module SimpleIDN
|
11
|
+
|
12
|
+
module Punycode
|
13
|
+
|
14
|
+
INITIAL_N = 0x80
|
15
|
+
INITIAL_BIAS = 72
|
16
|
+
DELIMITER = 0x2D
|
17
|
+
BASE = 36
|
18
|
+
DAMP = 700
|
19
|
+
TMIN = 1
|
20
|
+
TMAX = 26
|
21
|
+
SKEW = 38
|
22
|
+
MAXINT = 0x7FFFFFFF
|
23
|
+
|
24
|
+
module_function
|
25
|
+
|
26
|
+
# decode_digit(cp) returns the numeric value of a basic code
|
27
|
+
# point (for use in representing integers) in the range 0 to
|
28
|
+
# base-1, or base if cp is does not represent a value.
|
29
|
+
def decode_digit(cp)
|
30
|
+
cp - 48 < 10 ? cp - 22 : cp - 65 < 26 ? cp - 65 : cp - 97 < 26 ? cp - 97 : BASE
|
31
|
+
end
|
32
|
+
|
33
|
+
# encode_digit(d,flag) returns the basic code point whose value
|
34
|
+
# (when used for representing integers) is d, which needs to be in
|
35
|
+
# the range 0 to base-1. The lowercase form is used unless flag is
|
36
|
+
# nonzero, in which case the uppercase form is used. The behavior
|
37
|
+
# is undefined if flag is nonzero and digit d has no uppercase form.
|
38
|
+
def encode_digit(d)
|
39
|
+
d + 22 + 75 * (d < 26 ? 1 : 0)
|
40
|
+
# 0..25 map to ASCII a..z or A..Z
|
41
|
+
# 26..35 map to ASCII 0..9
|
42
|
+
end
|
43
|
+
|
44
|
+
# Bias adaptation function
|
45
|
+
def adapt(delta, numpoints, firsttime)
|
46
|
+
delta = firsttime ? (delta / DAMP) : (delta >> 1)
|
47
|
+
delta += (delta / numpoints)
|
48
|
+
|
49
|
+
k = 0
|
50
|
+
while delta > (((BASE - TMIN) * TMAX) / 2) do
|
51
|
+
delta /= BASE - TMIN
|
52
|
+
k += BASE
|
53
|
+
end
|
54
|
+
return k + (BASE - TMIN + 1) * delta / (delta + SKEW)
|
55
|
+
end
|
56
|
+
|
57
|
+
# encode_basic(bcp,flag) forces a basic code point to lowercase if flag is zero,
|
58
|
+
# uppercase if flag is nonzero, and returns the resulting code point.
|
59
|
+
# The code point is unchanged if it is caseless.
|
60
|
+
# The behavior is undefined if bcp is not a basic code point.
|
61
|
+
def encode_basic(bcp, flag)
|
62
|
+
bcp -= (bcp - 97 < 26 ? 1 : 0) << 5
|
63
|
+
return bcp + ((!flag && (bcp - 65 < 26 ? 1 : 0)) << 5)
|
64
|
+
end
|
65
|
+
|
66
|
+
# Main decode
|
67
|
+
def decode(input)
|
68
|
+
output = []
|
69
|
+
|
70
|
+
# Initialize the state:
|
71
|
+
n = INITIAL_N
|
72
|
+
i = 0
|
73
|
+
bias = INITIAL_BIAS
|
74
|
+
|
75
|
+
# Handle the basic code points: Let basic be the number of input code
|
76
|
+
# points before the last delimiter, or 0 if there is none, then
|
77
|
+
# copy the first basic code points to the output.
|
78
|
+
basic = input.rindex(DELIMITER.to_utf8_character) || 0
|
79
|
+
|
80
|
+
input.unpack("U*")[0, basic].each do |char|
|
81
|
+
raise(RangeError, "Illegal input >= 0x80") if char >= 0x80
|
82
|
+
output << char.chr # to_utf8_character not needed her because ord < 0x80 (128) which is within US-ASCII.
|
83
|
+
end
|
84
|
+
|
85
|
+
# Main decoding loop: Start just after the last delimiter if any
|
86
|
+
# basic code points were copied; start at the beginning otherwise.
|
87
|
+
|
88
|
+
ic = basic > 0 ? basic + 1 : 0
|
89
|
+
while ic < input.length do
|
90
|
+
# ic is the index of the next character to be consumed,
|
91
|
+
|
92
|
+
# Decode a generalized variable-length integer into delta,
|
93
|
+
# which gets added to i. The overflow checking is easier
|
94
|
+
# if we increase i as we go, then subtract off its starting
|
95
|
+
# value at the end to obtain delta.
|
96
|
+
oldi = i
|
97
|
+
w = 1
|
98
|
+
k = BASE
|
99
|
+
while true do
|
100
|
+
raise(RangeError, "punycode_bad_input(1)") if ic >= input.length
|
101
|
+
|
102
|
+
digit = decode_digit(input[ic].ord)
|
103
|
+
ic += 1
|
104
|
+
|
105
|
+
raise(RangeError, "punycode_bad_input(2)") if digit >= BASE
|
106
|
+
|
107
|
+
raise(RangeError, "punycode_overflow(1)") if digit > (MAXINT - i) / w
|
108
|
+
|
109
|
+
i += digit * w
|
110
|
+
t = k <= bias ? TMIN : k >= bias + TMAX ? TMAX : k - bias
|
111
|
+
break if digit < t
|
112
|
+
raise(RangeError, "punycode_overflow(2)") if w > MAXINT / (BASE - t)
|
113
|
+
|
114
|
+
w *= BASE - t
|
115
|
+
k += BASE
|
116
|
+
end
|
117
|
+
|
118
|
+
out = output.length + 1
|
119
|
+
bias = adapt(i - oldi, out, oldi == 0)
|
120
|
+
|
121
|
+
# i was supposed to wrap around from out to 0,
|
122
|
+
# incrementing n each time, so we'll fix that now:
|
123
|
+
raise(RangeError, "punycode_overflow(3)") if (i / out) > MAXINT - n
|
124
|
+
|
125
|
+
n += (i / out)
|
126
|
+
i %= out
|
127
|
+
|
128
|
+
# Insert n at position i of the output:
|
129
|
+
output.insert(i, n.to_utf8_character)
|
130
|
+
i += 1
|
131
|
+
end
|
132
|
+
|
133
|
+
return output.join
|
134
|
+
end
|
135
|
+
|
136
|
+
# Main encode function
|
137
|
+
def encode(input)
|
138
|
+
|
139
|
+
input = input.downcase.unpack("U*")
|
140
|
+
output = []
|
141
|
+
|
142
|
+
# Initialize the state:
|
143
|
+
n = INITIAL_N
|
144
|
+
delta = 0
|
145
|
+
bias = INITIAL_BIAS
|
146
|
+
|
147
|
+
# Handle the basic code points:
|
148
|
+
output = input.select do |char|
|
149
|
+
char if char < 0x80
|
150
|
+
end
|
151
|
+
|
152
|
+
h = b = output.length
|
153
|
+
|
154
|
+
# h is the number of code points that have been handled, b is the
|
155
|
+
# number of basic code points
|
156
|
+
|
157
|
+
output << DELIMITER if b > 0
|
158
|
+
|
159
|
+
# Main encoding loop:
|
160
|
+
while h < input.length do
|
161
|
+
# All non-basic code points < n have been
|
162
|
+
# handled already. Find the next larger one:
|
163
|
+
|
164
|
+
m = MAXINT
|
165
|
+
|
166
|
+
input.each do |char|
|
167
|
+
m = char if char >= n && char < m
|
168
|
+
end
|
169
|
+
|
170
|
+
# Increase delta enough to advance the decoder's
|
171
|
+
# <n,i> state to <m,0>, but guard against overflow:
|
172
|
+
|
173
|
+
raise(RangeError, "punycode_overflow (1)") if m - n > ((MAXINT - delta) / (h + 1)).floor
|
174
|
+
|
175
|
+
delta += (m - n) * (h + 1)
|
176
|
+
n = m
|
177
|
+
|
178
|
+
input.each_with_index do |char, j|
|
179
|
+
if char < n
|
180
|
+
delta += 1
|
181
|
+
raise(StandardError,"punycode_overflow(2)") if delta > MAXINT
|
182
|
+
end
|
183
|
+
|
184
|
+
if (char == n)
|
185
|
+
# Represent delta as a generalized variable-length integer:
|
186
|
+
q = delta
|
187
|
+
k = BASE
|
188
|
+
while true do
|
189
|
+
t = k <= bias ? TMIN : k >= bias + TMAX ? TMAX : k - bias
|
190
|
+
break if q < t
|
191
|
+
output << encode_digit(t + (q - t) % (BASE - t))
|
192
|
+
q = ( (q - t) / (BASE - t) ).floor
|
193
|
+
k += BASE
|
194
|
+
end
|
195
|
+
output << encode_digit(q)
|
196
|
+
bias = adapt(delta, h + 1, h == b)
|
197
|
+
delta = 0
|
198
|
+
h += 1
|
199
|
+
end
|
200
|
+
end
|
201
|
+
|
202
|
+
delta += 1
|
203
|
+
n += 1
|
204
|
+
end
|
205
|
+
return output.collect {|c| c.to_utf8_character}.join
|
206
|
+
end
|
207
|
+
|
208
|
+
end
|
209
|
+
|
210
|
+
module_function
|
211
|
+
|
212
|
+
# Converts a UTF-8 unicode string to a punycode ACE string.
|
213
|
+
# == Example
|
214
|
+
# SimpleIDN.to_ascii("møllerriis.com")
|
215
|
+
# => "xn--mllerriis-l8a.com"
|
216
|
+
def to_ascii(domain)
|
217
|
+
domain_array = domain.split(".") rescue []
|
218
|
+
return domain if domain_array.length == 0
|
219
|
+
out = []
|
220
|
+
i = 0
|
221
|
+
while i < domain_array.length
|
222
|
+
s = domain_array[i]
|
223
|
+
out << (s =~ /[^A-Z0-9\-*_]/i ? "xn--" + Punycode.encode(s) : s)
|
224
|
+
i += 1
|
225
|
+
end
|
226
|
+
return out.join(".")
|
227
|
+
end
|
228
|
+
|
229
|
+
# Converts a punycode ACE string to a UTF-8 unicode string.
|
230
|
+
# == Example
|
231
|
+
# SimpleIDN.to_unicode("xn--mllerriis-l8a.com")
|
232
|
+
# => "møllerriis.com"
|
233
|
+
def to_unicode(domain)
|
234
|
+
domain_array = domain.split(".") rescue []
|
235
|
+
return domain if domain_array.length == 0
|
236
|
+
out = []
|
237
|
+
i = 0
|
238
|
+
while i < domain_array.length
|
239
|
+
s = domain_array[i]
|
240
|
+
out << (s =~ /^xn\-\-/i ? Punycode.decode(s.gsub('xn--','')) : s)
|
241
|
+
i += 1
|
242
|
+
end
|
243
|
+
return out.join(".")
|
244
|
+
end
|
245
|
+
end
|
246
|
+
|
247
|
+
#------------------------------------------------------------------------------
|
248
|
+
# The MIT License
|
249
|
+
#
|
250
|
+
# Copyright (c) 2011-2013 Morten Møller Riis
|
251
|
+
#
|
252
|
+
# Permission is hereby granted, free of charge, to any person obtaining a copy
|
253
|
+
# of this software and associated documentation files (the "Software"), to deal
|
254
|
+
# in the Software without restriction, including without limitation the rights
|
255
|
+
# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
256
|
+
# copies of the Software, and to permit persons to whom the Software is
|
257
|
+
# furnished to do so, subject to the following conditions:
|
258
|
+
#
|
259
|
+
# The above copyright notice and this permission notice shall be included in
|
260
|
+
# all copies or substantial portions of the Software.
|
261
|
+
#
|
262
|
+
# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
263
|
+
# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
264
|
+
# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
265
|
+
# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
266
|
+
# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
267
|
+
# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
268
|
+
# THE SOFTWARE.
|
@@ -20,7 +20,9 @@ module MarkdownIt
|
|
20
20
|
# Useful for some operations with tokens
|
21
21
|
#------------------------------------------------------------------------------
|
22
22
|
def arrayReplaceAt(src, pos, newElements)
|
23
|
-
|
23
|
+
src[pos] = newElements
|
24
|
+
src.flatten!(1)
|
25
|
+
return src
|
24
26
|
end
|
25
27
|
|
26
28
|
#------------------------------------------------------------------------------
|
@@ -73,13 +75,6 @@ module MarkdownIt
|
|
73
75
|
return match
|
74
76
|
end
|
75
77
|
|
76
|
-
# not used
|
77
|
-
#------------------------------------------------------------------------------
|
78
|
-
# def replaceEntities(str)
|
79
|
-
# return str if str.index('&').nil?
|
80
|
-
# return str.gsub(ENTITY_RE, replaceEntityPattern)
|
81
|
-
# end
|
82
|
-
|
83
78
|
#------------------------------------------------------------------------------
|
84
79
|
def unescapeMd(str)
|
85
80
|
return str if !str.include?('\\')
|
@@ -143,11 +138,7 @@ module MarkdownIt
|
|
143
138
|
return false
|
144
139
|
end
|
145
140
|
|
146
|
-
|
147
|
-
# https://github.com/markdown-it/uc.micro
|
148
|
-
# UNICODE_PUNCT_RE = /[!-#%-\*,-\/:;\?@\[-\]_\{\}\xA1\xA7\xAB\xB6\xB7\xBB\xBF\u037E\u0387\u055A-\u055F\u0589\u058A\u05BE\u05C0\u05C3\u05C6\u05F3\u05F4\u0609\u060A\u060C\u060D\u061B\u061E\u061F\u066A-\u066D\u06D4\u0700-\u070D\u07F7-\u07F9\u0830-\u083E\u085E\u0964\u0965\u0970\u0AF0\u0DF4\u0E4F\u0E5A\u0E5B\u0F04-\u0F12\u0F14\u0F3A-\u0F3D\u0F85\u0FD0-\u0FD4\u0FD9\u0FDA\u104A-\u104F\u10FB\u1360-\u1368\u1400\u166D\u166E\u169B\u169C\u16EB-\u16ED\u1735\u1736\u17D4-\u17D6\u17D8-\u17DA\u1800-\u180A\u1944\u1945\u1A1E\u1A1F\u1AA0-\u1AA6\u1AA8-\u1AAD\u1B5A-\u1B60\u1BFC-\u1BFF\u1C3B-\u1C3F\u1C7E\u1C7F\u1CC0-\u1CC7\u1CD3\u2010-\u2027\u2030-\u2043\u2045-\u2051\u2053-\u205E\u207D\u207E\u208D\u208E\u2308-\u230B\u2329\u232A\u2768-\u2775\u27C5\u27C6\u27E6-\u27EF\u2983-\u2998\u29D8-\u29DB\u29FC\u29FD\u2CF9-\u2CFC\u2CFE\u2CFF\u2D70\u2E00-\u2E2E\u2E30-\u2E42\u3001-\u3003\u3008-\u3011\u3014-\u301F\u3030\u303D\u30A0\u30FB\uA4FE\uA4FF\uA60D-\uA60F\uA673\uA67E\uA6F2-\uA6F7\uA874-\uA877\uA8CE\uA8CF\uA8F8-\uA8FA\uA92E\uA92F\uA95F\uA9C1-\uA9CD\uA9DE\uA9DF\uAA5C-\uAA5F\uAADE\uAADF\uAAF0\uAAF1\uABEB\uFD3E\uFD3F\uFE10-\uFE19\uFE30-\uFE52\uFE54-\uFE61\uFE63\uFE68\uFE6A\uFE6B\uFF01-\uFF03\uFF05-\uFF0A\uFF0C-\uFF0F\uFF1A\uFF1B\uFF1F\uFF20\uFF3B-\uFF3D\uFF3F\uFF5B\uFF5D\uFF5F-\uFF65]|\uD800[\uDD00-\uDD02\uDF9F\uDFD0]|\uD801\uDD6F|\uD802[\uDC57\uDD1F\uDD3F\uDE50-\uDE58\uDE7F\uDEF0-\uDEF6\uDF39-\uDF3F\uDF99-\uDF9C]|\uD804[\uDC47-\uDC4D\uDCBB\uDCBC\uDCBE-\uDCC1\uDD40-\uDD43\uDD74\uDD75\uDDC5-\uDDC8\uDDCD\uDE38-\uDE3D]|\uD805[\uDCC6\uDDC1-\uDDC9\uDE41-\uDE43]|\uD809[\uDC70-\uDC74]|\uD81A[\uDE6E\uDE6F\uDEF5\uDF37-\uDF3B\uDF44]|\uD82F\uDC9F/
|
149
|
-
# was unable to get abouve to work TODO
|
150
|
-
UNICODE_PUNCT_RE = /[!-#%-\*,-\/:;\?@\[-\]_\{\}]/
|
141
|
+
UNICODE_PUNCT_RE = UCMicro::Categories::P::REGEX
|
151
142
|
|
152
143
|
# Currently without astral characters support.
|
153
144
|
#------------------------------------------------------------------------------
|
@@ -7,18 +7,21 @@ CONFIG = {
|
|
7
7
|
commonmark: MarkdownIt::Presets::Commonmark.options
|
8
8
|
}
|
9
9
|
|
10
|
+
#------------------------------------------------------------------------------
|
11
|
+
# This validator does not pretend to functionality of full weight sanitizers.
|
12
|
+
# It's a tradeoff between default security, simplicity and usability.
|
13
|
+
# If you need different setup - override validator method as you wish. Or
|
14
|
+
# replace it with dummy function and use external sanitizer.
|
10
15
|
|
11
|
-
|
16
|
+
BAD_PROTO_RE = /^(vbscript|javascript|file|data):/
|
17
|
+
GOOD_DATA_RE = /^data:image\/(gif|png|jpeg|webp);/
|
12
18
|
|
13
19
|
VALIDATE_LINK = lambda do |url|
|
14
20
|
# url should be normalized at this point, and existing entities are decoded
|
15
21
|
#
|
16
22
|
str = url.strip.downcase
|
17
23
|
|
18
|
-
|
19
|
-
return false
|
20
|
-
end
|
21
|
-
return true
|
24
|
+
return !!(BAD_PROTO_RE =~ str) ? (!!(GOOD_DATA_RE =~ str) ? true : false) : true
|
22
25
|
end
|
23
26
|
|
24
27
|
RECODE_HOSTNAME_FOR = [ 'http:', 'https:', 'mailto:' ]
|
@@ -26,40 +29,44 @@ RECODE_HOSTNAME_FOR = [ 'http:', 'https:', 'mailto:' ]
|
|
26
29
|
# mdurl comes from https://github.com/markdown-it/mdurl
|
27
30
|
NORMALIZE_LINK = lambda do |url|
|
28
31
|
parsed = MDUrl::Url.urlParse(url, true)
|
32
|
+
if parsed.hostname
|
33
|
+
# Encode hostnames in urls like:
|
34
|
+
# `http://host/`, `https://host/`, `mailto:user@host`, `//host/`
|
35
|
+
#
|
36
|
+
# We don't encode unknown schemas, because it's likely that we encode
|
37
|
+
# something we shouldn't (e.g. `skype:name` treated as `skype:host`)
|
38
|
+
if !parsed.protocol || RECODE_HOSTNAME_FOR.include?(parsed.protocol)
|
39
|
+
begin
|
40
|
+
trailing_dot = parsed.hostname[-1] == '.'
|
41
|
+
parsed.hostname = SimpleIDN.to_ascii(parsed.hostname)
|
42
|
+
parsed.hostname << '.' if trailing_dot
|
43
|
+
rescue
|
44
|
+
# then use what we already have
|
45
|
+
end
|
46
|
+
end
|
47
|
+
end
|
29
48
|
|
30
|
-
|
31
|
-
# # Encode hostnames in urls like:
|
32
|
-
# # `http://host/`, `https://host/`, `mailto:user@host`, `//host/`
|
33
|
-
# #
|
34
|
-
# # We don't encode unknown schemas, because it's likely that we encode
|
35
|
-
# # something we shouldn't (e.g. `skype:name` treated as `skype:host`)
|
36
|
-
# if !parsed[:protocol] || RECODE_HOSTNAME_FOR.include?(parsed[:protocol])
|
37
|
-
# # TODO is punycode really needed?
|
38
|
-
# # try {
|
39
|
-
# # parsed.hostname = punycode.toASCII(parsed.hostname);
|
40
|
-
# # } catch(er) {}
|
41
|
-
# end
|
42
|
-
# end
|
43
|
-
|
44
|
-
return MDUrl::Encode.encode(MDUrl::Format.format(parsed));
|
49
|
+
return MDUrl::Encode.encode(MDUrl::Format.format(parsed))
|
45
50
|
end
|
46
51
|
|
47
52
|
NORMALIZE_LINK_TEXT = lambda do |url|
|
48
53
|
parsed = MDUrl::Url.urlParse(url, true)
|
49
|
-
|
50
|
-
|
51
|
-
|
52
|
-
|
53
|
-
|
54
|
-
|
55
|
-
|
56
|
-
|
57
|
-
|
58
|
-
|
59
|
-
|
60
|
-
|
61
|
-
|
62
|
-
|
54
|
+
if parsed.hostname
|
55
|
+
# Encode hostnames in urls like:
|
56
|
+
# `http://host/`, `https://host/`, `mailto:user@host`, `//host/`
|
57
|
+
#
|
58
|
+
# We don't encode unknown schemas, because it's likely that we encode
|
59
|
+
# something we shouldn't (e.g. `skype:name` treated as `skype:host`)
|
60
|
+
if !parsed.protocol || RECODE_HOSTNAME_FOR.include?(parsed.protocol)
|
61
|
+
begin
|
62
|
+
trailing_dot = parsed.hostname[-1] == '.'
|
63
|
+
parsed.hostname = SimpleIDN.to_unicode(parsed.hostname)
|
64
|
+
parsed.hostname << '.' if trailing_dot
|
65
|
+
rescue
|
66
|
+
# then use what we already have
|
67
|
+
end
|
68
|
+
end
|
69
|
+
end
|
63
70
|
|
64
71
|
return MDUrl::Decode.decode(MDUrl::Format.format(parsed))
|
65
72
|
end
|
@@ -147,9 +154,9 @@ module MarkdownIt
|
|
147
154
|
# - __quotes__ - `“”‘’`, string. Double + single quotes replacement pairs, when
|
148
155
|
# typographer enabled and smartquotes on. Set doubles to '«»' for Russian,
|
149
156
|
# '„“' for German.
|
150
|
-
# - __highlight__ - `
|
157
|
+
# - __highlight__ - `nil`. Highlighter function for fenced code blocks.
|
151
158
|
# Highlighter `function (str, lang)` should return escaped HTML. It can also
|
152
|
-
# return
|
159
|
+
# return nil if the source was not changed and should be escaped externaly.
|
153
160
|
#
|
154
161
|
# ##### Example
|
155
162
|
#
|
@@ -273,20 +280,6 @@ module MarkdownIt
|
|
273
280
|
|
274
281
|
# Expose utils & helpers for easy acces from plugins
|
275
282
|
|
276
|
-
# TODO I don't know if these (utils and helpers) are really needed
|
277
|
-
# MarkdownIt#utils -> utils
|
278
|
-
#
|
279
|
-
# Assorted utility functions, useful to write plugins. See details
|
280
|
-
# [here](https://github.com/markdown-it/markdown-it/blob/master/lib/common/utils.js).
|
281
|
-
# this.utils = utils;
|
282
|
-
|
283
|
-
# MarkdownIt#helpers -> helpers
|
284
|
-
#
|
285
|
-
# Link components parser functions, useful to write plugins. See details
|
286
|
-
# [here](https://github.com/markdown-it/markdown-it/blob/master/lib/helpers).
|
287
|
-
# this.helpers = helpers;
|
288
|
-
|
289
|
-
|
290
283
|
@options = {}
|
291
284
|
configure(presetName)
|
292
285
|
set(options) if options
|
@@ -366,7 +359,7 @@ module MarkdownIt
|
|
366
359
|
# .disable('smartquotes');
|
367
360
|
# ```
|
368
361
|
#------------------------------------------------------------------------------
|
369
|
-
def enable(list, ignoreInvalid)
|
362
|
+
def enable(list, ignoreInvalid = false)
|
370
363
|
result = []
|
371
364
|
|
372
365
|
list = [ list ] if !list.is_a? Array
|
@@ -374,10 +367,10 @@ module MarkdownIt
|
|
374
367
|
result << @core.ruler.enable(list, true)
|
375
368
|
result << @block.ruler.enable(list, true)
|
376
369
|
result << @inline.ruler.enable(list, true)
|
377
|
-
|
378
|
-
|
379
|
-
|
380
|
-
if missed.
|
370
|
+
result.flatten!
|
371
|
+
|
372
|
+
missed = list.select {|name| !result.include?(name) }
|
373
|
+
if !(missed.empty? || ignoreInvalid)
|
381
374
|
raise StandardError, "MarkdownIt. Failed to enable unknown rule(s): #{missed}"
|
382
375
|
end
|
383
376
|
|
@@ -391,7 +384,8 @@ module MarkdownIt
|
|
391
384
|
# - ignoreInvalid (Boolean): set `true` to ignore errors when rule not found.
|
392
385
|
#
|
393
386
|
# The same as [[MarkdownIt.enable]], but turn specified rules off.
|
394
|
-
|
387
|
+
#------------------------------------------------------------------------------
|
388
|
+
def disable(list, ignoreInvalid = false)
|
395
389
|
result = []
|
396
390
|
|
397
391
|
list = [ list ] if !list.is_a? Array
|
@@ -399,10 +393,10 @@ module MarkdownIt
|
|
399
393
|
result << @core.ruler.disable(list, true)
|
400
394
|
result << @block.ruler.disable(list, true)
|
401
395
|
result << @inline.ruler.disable(list, true)
|
396
|
+
result.flatten!
|
402
397
|
|
403
|
-
missed = list.select {|name| result.include?(name) }
|
404
|
-
|
405
|
-
if missed.length && !ignoreInvalid
|
398
|
+
missed = list.select {|name| !result.include?(name) }
|
399
|
+
if !(missed.empty? || ignoreInvalid)
|
406
400
|
raise StandardError, "MarkdownIt. Failed to disable unknown rule(s): #{missed}"
|
407
401
|
end
|
408
402
|
|
@@ -426,10 +420,8 @@ module MarkdownIt
|
|
426
420
|
# });
|
427
421
|
# ```
|
428
422
|
def use(plugin, *args)
|
429
|
-
|
430
|
-
|
431
|
-
# plugin.call(plugin, args)
|
432
|
-
# return self
|
423
|
+
plugin.call(plugin, *args)
|
424
|
+
return self
|
433
425
|
end
|
434
426
|
|
435
427
|
|