motion-markdown-it 0.4.0.3.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 (64) hide show
  1. checksums.yaml +7 -0
  2. data/README.md +243 -0
  3. data/lib/motion-markdown-it.rb +71 -0
  4. data/lib/motion-markdown-it/common/entities.rb +1084 -0
  5. data/lib/motion-markdown-it/common/html_blocks.rb +60 -0
  6. data/lib/motion-markdown-it/common/html_re.rb +28 -0
  7. data/lib/motion-markdown-it/common/string.rb +14 -0
  8. data/lib/motion-markdown-it/common/url_schemas.rb +173 -0
  9. data/lib/motion-markdown-it/common/utils.rb +216 -0
  10. data/lib/motion-markdown-it/helpers/parse_link_destination.rb +75 -0
  11. data/lib/motion-markdown-it/helpers/parse_link_label.rb +51 -0
  12. data/lib/motion-markdown-it/helpers/parse_link_title.rb +48 -0
  13. data/lib/motion-markdown-it/index.rb +507 -0
  14. data/lib/motion-markdown-it/parser_block.rb +113 -0
  15. data/lib/motion-markdown-it/parser_core.rb +46 -0
  16. data/lib/motion-markdown-it/parser_inline.rb +121 -0
  17. data/lib/motion-markdown-it/presets/commonmark.rb +76 -0
  18. data/lib/motion-markdown-it/presets/default.rb +42 -0
  19. data/lib/motion-markdown-it/presets/zero.rb +59 -0
  20. data/lib/motion-markdown-it/renderer.rb +286 -0
  21. data/lib/motion-markdown-it/ruler.rb +327 -0
  22. data/lib/motion-markdown-it/rules_block/blockquote.rb +138 -0
  23. data/lib/motion-markdown-it/rules_block/code.rb +35 -0
  24. data/lib/motion-markdown-it/rules_block/fence.rb +94 -0
  25. data/lib/motion-markdown-it/rules_block/heading.rb +56 -0
  26. data/lib/motion-markdown-it/rules_block/hr.rb +45 -0
  27. data/lib/motion-markdown-it/rules_block/html_block.rb +73 -0
  28. data/lib/motion-markdown-it/rules_block/lheading.rb +54 -0
  29. data/lib/motion-markdown-it/rules_block/list.rb +242 -0
  30. data/lib/motion-markdown-it/rules_block/paragraph.rb +51 -0
  31. data/lib/motion-markdown-it/rules_block/reference.rb +161 -0
  32. data/lib/motion-markdown-it/rules_block/state_block.rb +184 -0
  33. data/lib/motion-markdown-it/rules_block/table.rb +161 -0
  34. data/lib/motion-markdown-it/rules_core/block.rb +20 -0
  35. data/lib/motion-markdown-it/rules_core/inline.rb +20 -0
  36. data/lib/motion-markdown-it/rules_core/linkify.rb +138 -0
  37. data/lib/motion-markdown-it/rules_core/normalize.rb +44 -0
  38. data/lib/motion-markdown-it/rules_core/replacements.rb +90 -0
  39. data/lib/motion-markdown-it/rules_core/smartquotes.rb +158 -0
  40. data/lib/motion-markdown-it/rules_core/state_core.rb +20 -0
  41. data/lib/motion-markdown-it/rules_inline/autolink.rb +74 -0
  42. data/lib/motion-markdown-it/rules_inline/backticks.rb +51 -0
  43. data/lib/motion-markdown-it/rules_inline/emphasis.rb +172 -0
  44. data/lib/motion-markdown-it/rules_inline/entity.rb +51 -0
  45. data/lib/motion-markdown-it/rules_inline/escape.rb +55 -0
  46. data/lib/motion-markdown-it/rules_inline/html_inline.rb +49 -0
  47. data/lib/motion-markdown-it/rules_inline/image.rb +158 -0
  48. data/lib/motion-markdown-it/rules_inline/link.rb +153 -0
  49. data/lib/motion-markdown-it/rules_inline/newline.rb +47 -0
  50. data/lib/motion-markdown-it/rules_inline/state_inline.rb +57 -0
  51. data/lib/motion-markdown-it/rules_inline/strikethrough.rb +130 -0
  52. data/lib/motion-markdown-it/rules_inline/text.rb +94 -0
  53. data/lib/motion-markdown-it/token.rb +134 -0
  54. data/lib/motion-markdown-it/version.rb +5 -0
  55. data/spec/motion-markdown-it/bench_mark_spec.rb +44 -0
  56. data/spec/motion-markdown-it/commonmark_spec.rb +16 -0
  57. data/spec/motion-markdown-it/markdown_it_spec.rb +18 -0
  58. data/spec/motion-markdown-it/misc_spec.rb +277 -0
  59. data/spec/motion-markdown-it/ruler_spec.rb +153 -0
  60. data/spec/motion-markdown-it/testgen_helper.rb +68 -0
  61. data/spec/motion-markdown-it/token_spec.rb +17 -0
  62. data/spec/motion-markdown-it/utils_spec.rb +82 -0
  63. data/spec/spec_helper.rb +6 -0
  64. metadata +158 -0
@@ -0,0 +1,60 @@
1
+ # List of valid html blocks names, accorting to commonmark spec
2
+ # http://jgm.github.io/CommonMark/spec.html#html-blocks
3
+ #------------------------------------------------------------------------------
4
+ module MarkdownIt
5
+ HTML_BLOCKS = {}
6
+
7
+ [
8
+ 'article',
9
+ 'aside',
10
+ 'button',
11
+ 'blockquote',
12
+ 'body',
13
+ 'canvas',
14
+ 'caption',
15
+ 'col',
16
+ 'colgroup',
17
+ 'dd',
18
+ 'div',
19
+ 'dl',
20
+ 'dt',
21
+ 'embed',
22
+ 'fieldset',
23
+ 'figcaption',
24
+ 'figure',
25
+ 'footer',
26
+ 'form',
27
+ 'h1',
28
+ 'h2',
29
+ 'h3',
30
+ 'h4',
31
+ 'h5',
32
+ 'h6',
33
+ 'header',
34
+ 'hgroup',
35
+ 'hr',
36
+ 'iframe',
37
+ 'li',
38
+ 'map',
39
+ 'object',
40
+ 'ol',
41
+ 'output',
42
+ 'p',
43
+ 'pre',
44
+ 'progress',
45
+ 'script',
46
+ 'section',
47
+ 'style',
48
+ 'table',
49
+ 'tbody',
50
+ 'td',
51
+ 'textarea',
52
+ 'tfoot',
53
+ 'th',
54
+ 'tr',
55
+ 'thead',
56
+ 'ul',
57
+ 'video'
58
+ ].each { |name| HTML_BLOCKS[name] = true }
59
+
60
+ end
@@ -0,0 +1,28 @@
1
+ # Regexps to match html elements
2
+ #------------------------------------------------------------------------------
3
+ module MarkdownIt
4
+ module Common
5
+ module HtmlRe
6
+ ATTR_NAME = '[a-zA-Z_:][a-zA-Z0-9:._-]*'
7
+
8
+ UNQUOTED = '[^"\'=<>`\\x00-\\x20]+'
9
+ SINGLE_QUOTED = "'[^']*'"
10
+ DOUBLE_QUOTED = '"[^"]*"';
11
+
12
+ ATTR_VALUE = '(?:' + UNQUOTED + '|' + SINGLE_QUOTED + '|' + DOUBLE_QUOTED + ')'
13
+
14
+ ATTRIBUTE = '(?:\\s+' + ATTR_NAME + '(?:\\s*=\\s*' + ATTR_VALUE + ')?)'
15
+
16
+ OPEN_TAG = '<[A-Za-z][A-Za-z0-9\\-]*' + ATTRIBUTE + '*\\s*\\/?>'
17
+
18
+ CLOSE_TAG = '<\\/[A-Za-z][A-Za-z0-9\\-]*\\s*>'
19
+ COMMENT = '<!---->|<!--(?:-?[^>-])(?:-?[^-])*-->'
20
+ PROCESSING = '<[?].*?[?]>'
21
+ DECLARATION = '<![A-Z]+\\s+[^>]*>'
22
+ CDATA = '<!\\[CDATA\\[[\\s\\S]*?\\]\\]>'
23
+
24
+ HTML_TAG_RE = Regexp.new('^(?:' + OPEN_TAG + '|' + CLOSE_TAG + '|' + COMMENT +
25
+ '|' + PROCESSING + '|' + DECLARATION + '|' + CDATA + ')')
26
+ end
27
+ end
28
+ end
@@ -0,0 +1,14 @@
1
+ class String
2
+
3
+ # grab the remainder of the string starting at 'start'
4
+ #------------------------------------------------------------------------------
5
+ def slice_to_end(start)
6
+ self.slice(start...self.length)
7
+ end
8
+
9
+ # port of Javascript function charCodeAt
10
+ #------------------------------------------------------------------------------
11
+ def charCodeAt(ch)
12
+ self[ch].ord unless self[ch].nil?
13
+ end
14
+ end
@@ -0,0 +1,173 @@
1
+ # List of valid url schemas, accorting to commonmark spec
2
+ # http://jgm.github.io/CommonMark/spec.html#autolinks
3
+ #------------------------------------------------------------------------------
4
+ module MarkdownIt
5
+
6
+ URL_SCHEMAS = [
7
+ 'coap',
8
+ 'doi',
9
+ 'javascript',
10
+ 'aaa',
11
+ 'aaas',
12
+ 'about',
13
+ 'acap',
14
+ 'cap',
15
+ 'cid',
16
+ 'crid',
17
+ 'data',
18
+ 'dav',
19
+ 'dict',
20
+ 'dns',
21
+ 'file',
22
+ 'ftp',
23
+ 'geo',
24
+ 'go',
25
+ 'gopher',
26
+ 'h323',
27
+ 'http',
28
+ 'https',
29
+ 'iax',
30
+ 'icap',
31
+ 'im',
32
+ 'imap',
33
+ 'info',
34
+ 'ipp',
35
+ 'iris',
36
+ 'iris.beep',
37
+ 'iris.xpc',
38
+ 'iris.xpcs',
39
+ 'iris.lwz',
40
+ 'ldap',
41
+ 'mailto',
42
+ 'mid',
43
+ 'msrp',
44
+ 'msrps',
45
+ 'mtqp',
46
+ 'mupdate',
47
+ 'news',
48
+ 'nfs',
49
+ 'ni',
50
+ 'nih',
51
+ 'nntp',
52
+ 'opaquelocktoken',
53
+ 'pop',
54
+ 'pres',
55
+ 'rtsp',
56
+ 'service',
57
+ 'session',
58
+ 'shttp',
59
+ 'sieve',
60
+ 'sip',
61
+ 'sips',
62
+ 'sms',
63
+ 'snmp',
64
+ 'soap.beep',
65
+ 'soap.beeps',
66
+ 'tag',
67
+ 'tel',
68
+ 'telnet',
69
+ 'tftp',
70
+ 'thismessage',
71
+ 'tn3270',
72
+ 'tip',
73
+ 'tv',
74
+ 'urn',
75
+ 'vemmi',
76
+ 'ws',
77
+ 'wss',
78
+ 'xcon',
79
+ 'xcon-userid',
80
+ 'xmlrpc.beep',
81
+ 'xmlrpc.beeps',
82
+ 'xmpp',
83
+ 'z39.50r',
84
+ 'z39.50s',
85
+ 'adiumxtra',
86
+ 'afp',
87
+ 'afs',
88
+ 'aim',
89
+ 'apt',
90
+ 'attachment',
91
+ 'aw',
92
+ 'beshare',
93
+ 'bitcoin',
94
+ 'bolo',
95
+ 'callto',
96
+ 'chrome',
97
+ 'chrome-extension',
98
+ 'com-eventbrite-attendee',
99
+ 'content',
100
+ 'cvs',
101
+ 'dlna-playsingle',
102
+ 'dlna-playcontainer',
103
+ 'dtn',
104
+ 'dvb',
105
+ 'ed2k',
106
+ 'facetime',
107
+ 'feed',
108
+ 'finger',
109
+ 'fish',
110
+ 'gg',
111
+ 'git',
112
+ 'gizmoproject',
113
+ 'gtalk',
114
+ 'hcp',
115
+ 'icon',
116
+ 'ipn',
117
+ 'irc',
118
+ 'irc6',
119
+ 'ircs',
120
+ 'itms',
121
+ 'jar',
122
+ 'jms',
123
+ 'keyparc',
124
+ 'lastfm',
125
+ 'ldaps',
126
+ 'magnet',
127
+ 'maps',
128
+ 'market',
129
+ 'message',
130
+ 'mms',
131
+ 'ms-help',
132
+ 'msnim',
133
+ 'mumble',
134
+ 'mvn',
135
+ 'notes',
136
+ 'oid',
137
+ 'palm',
138
+ 'paparazzi',
139
+ 'platform',
140
+ 'proxy',
141
+ 'psyc',
142
+ 'query',
143
+ 'res',
144
+ 'resource',
145
+ 'rmi',
146
+ 'rsync',
147
+ 'rtmp',
148
+ 'secondlife',
149
+ 'sftp',
150
+ 'sgn',
151
+ 'skype',
152
+ 'smb',
153
+ 'soldat',
154
+ 'spotify',
155
+ 'ssh',
156
+ 'steam',
157
+ 'svn',
158
+ 'teamspeak',
159
+ 'things',
160
+ 'udp',
161
+ 'unreal',
162
+ 'ut2004',
163
+ 'ventrilo',
164
+ 'view-source',
165
+ 'webcal',
166
+ 'wtai',
167
+ 'wyciwyg',
168
+ 'xfire',
169
+ 'xri',
170
+ 'ymsgr'
171
+ ]
172
+
173
+ end
@@ -0,0 +1,216 @@
1
+ module MarkdownIt
2
+ module Common
3
+ module Utils
4
+
5
+ # Merge multiple hashes
6
+ #------------------------------------------------------------------------------
7
+ def assign(obj, *args)
8
+ raise(ArgumentError, "#{obj} must be a Hash") if !obj.is_a?(Hash)
9
+
10
+ args.each do |source|
11
+ next if source.nil?
12
+ raise(ArgumentError, "#{source} must be a Hash") if !source.is_a?(Hash)
13
+ obj.merge!(source)
14
+ end
15
+
16
+ return obj
17
+ end
18
+
19
+ # Remove element from array and put another array at those position.
20
+ # Useful for some operations with tokens
21
+ #------------------------------------------------------------------------------
22
+ def arrayReplaceAt(src, pos, newElements)
23
+ return [].concat([src.slice(0...pos), newElements, src.slice_to_end(pos + 1)])
24
+ end
25
+
26
+ #------------------------------------------------------------------------------
27
+ def isValidEntityCode(c)
28
+ # broken sequence
29
+ return false if (c >= 0xD800 && c <= 0xDFFF)
30
+
31
+ # never used
32
+ return false if (c >= 0xFDD0 && c <= 0xFDEF)
33
+ return false if ((c & 0xFFFF) === 0xFFFF || (c & 0xFFFF) === 0xFFFE)
34
+
35
+ # control codes
36
+ return false if (c >= 0x00 && c <= 0x08)
37
+ return false if (c === 0x0B)
38
+ return false if (c >= 0x0E && c <= 0x1F)
39
+ return false if (c >= 0x7F && c <= 0x9F)
40
+
41
+ # out of range
42
+ return false if (c > 0x10FFFF)
43
+
44
+ return true
45
+ end
46
+
47
+ #------------------------------------------------------------------------------
48
+ def fromCodePoint(c)
49
+ c.chr(Encoding::UTF_8)
50
+ end
51
+
52
+
53
+ UNESCAPE_MD_RE = /\\([\!\"\#\$\%\&\'\(\)\*\+\,\-.\/:;<=>?@\[\\\]^_`{|}~])/
54
+
55
+ ENTITY_RE = /&([a-z#][a-z0-9]{1,31});/i
56
+ UNESCAPE_ALL_RE = Regexp.new(UNESCAPE_MD_RE.source + '|' + ENTITY_RE.source, 'i')
57
+
58
+ DIGITAL_ENTITY_TEST_RE = /^#((?:x[a-f0-9]{1,8}|[0-9]{1,8}))/i
59
+
60
+ #------------------------------------------------------------------------------
61
+ def replaceEntityPattern(match, name)
62
+ code = 0
63
+
64
+ return HTMLEntities::MAPPINGS[name].chr(Encoding::UTF_8) if HTMLEntities::MAPPINGS[name]
65
+
66
+ if (name.charCodeAt(0) == 0x23 && DIGITAL_ENTITY_TEST_RE =~ name) # '#'
67
+ code = name[1].downcase == 'x' ? name.slice_to_end(2).to_i(16) : name.slice_to_end(1).to_i
68
+ if (isValidEntityCode(code))
69
+ return fromCodePoint(code)
70
+ end
71
+ end
72
+
73
+ return match
74
+ end
75
+
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
+ #------------------------------------------------------------------------------
84
+ def unescapeMd(str)
85
+ return str if !str.include?('\\')
86
+ return str.gsub(UNESCAPE_MD_RE, '\1')
87
+ end
88
+
89
+ #------------------------------------------------------------------------------
90
+ def unescapeAll(str)
91
+ return str if (str.index('\\').nil? && str.index('&').nil?)
92
+
93
+ return str.gsub(UNESCAPE_ALL_RE) do |match|
94
+ next $1 if ($1)
95
+ next replaceEntityPattern(match, $2)
96
+ end
97
+ end
98
+
99
+
100
+ HTML_ESCAPE_TEST_RE = /[&<>"]/
101
+ HTML_ESCAPE_REPLACE_RE = /[&<>"]/
102
+ HTML_REPLACEMENTS = {
103
+ '&' => '&amp;',
104
+ '<' => '&lt;',
105
+ '>' => '&gt;',
106
+ '"' => '&quot;'
107
+ }
108
+
109
+ #------------------------------------------------------------------------------
110
+ def escapeHtml(str)
111
+ if HTML_ESCAPE_TEST_RE =~ str
112
+ return str.gsub(HTML_ESCAPE_REPLACE_RE, HTML_REPLACEMENTS)
113
+ end
114
+ return str
115
+ end
116
+
117
+ REGEXP_ESCAPE_RE = /[.?*+^$\[\]\\(){}|-]/
118
+
119
+ #------------------------------------------------------------------------------
120
+ def escapeRE(str)
121
+ str.gsub(REGEXP_ESCAPE_RE) {|s| '\\' + s}
122
+ end
123
+
124
+
125
+ # Zs (unicode class) || [\t\f\v\r\n]
126
+ #------------------------------------------------------------------------------
127
+ def isWhiteSpace(code)
128
+ return true if (code >= 0x2000 && code <= 0x200A)
129
+ case code
130
+ when 0x09, # \t
131
+ 0x0A, # \n
132
+ 0x0B, # \v
133
+ 0x0C, # \f
134
+ 0x0D, # \r
135
+ 0x20,
136
+ 0xA0,
137
+ 0x1680,
138
+ 0x202F,
139
+ 0x205F,
140
+ 0x3000
141
+ return true
142
+ end
143
+ return false
144
+ end
145
+
146
+ # from file uc.micro/categories/P/regex in github project
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 = /[!-#%-\*,-\/:;\?@\[-\]_\{\}]/
151
+
152
+ # Currently without astral characters support.
153
+ #------------------------------------------------------------------------------
154
+ def isPunctChar(char)
155
+ return UNICODE_PUNCT_RE =~ char
156
+ end
157
+
158
+
159
+ # Markdown ASCII punctuation characters.
160
+ #
161
+ # !, ", #, $, %, &, ', (, ), *, +, ,, -, ., /, :, ;, <, =, >, ?, @, [, \, ], ^, _, `, {, |, }, or ~
162
+ # http://spec.commonmark.org/0.15/#ascii-punctuation-character
163
+ #
164
+ # Don't confuse with unicode punctuation !!! It lacks some chars in ascii range.
165
+ #------------------------------------------------------------------------------
166
+ def isMdAsciiPunct(ch)
167
+ case ch
168
+ when 0x21, # !
169
+ 0x22, # "
170
+ 0x23, # #
171
+ 0x24, # $
172
+ 0x25, # %
173
+ 0x26, # &
174
+ 0x27, # '
175
+ 0x28, # (
176
+ 0x29, # )
177
+ 0x2A, # *
178
+ 0x2B, # +
179
+ 0x2C, # ,
180
+ 0x2D, # -
181
+ 0x2E, # .
182
+ 0x2F, # /
183
+ 0x3A, # :
184
+ 0x3B, # ;
185
+ 0x3C, # <
186
+ 0x3D, # =
187
+ 0x3E, # >
188
+ 0x3F, # ?
189
+ 0x40, # @
190
+ 0x5B, # [
191
+ 0x5C, # \
192
+ 0x5D, # ]
193
+ 0x5E, # ^
194
+ 0x5F, # _
195
+ 0x60, # `
196
+ 0x7B, # {
197
+ 0x7C, # |
198
+ 0x7D, # }
199
+ 0x7E # ~
200
+ return true
201
+ else
202
+ return false
203
+ end
204
+ end
205
+
206
+ # Hepler to unify [reference labels].
207
+ #------------------------------------------------------------------------------
208
+ def normalizeReference(str)
209
+ # use .toUpperCase() instead of .toLowerCase()
210
+ # here to avoid a conflict with Object.prototype
211
+ # members (most notably, `__proto__`)
212
+ return str.strip.gsub(/\s+/, ' ').upcase
213
+ end
214
+ end
215
+ end
216
+ end