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,51 @@
1
+ # Process html entity - {, ¯, ", ...
2
+ #------------------------------------------------------------------------------
3
+ module MarkdownIt
4
+ module RulesInline
5
+ class Entity
6
+ extend Common::Utils
7
+
8
+ DIGITAL_RE = /^&#((?:x[a-f0-9]{1,8}|[0-9]{1,8}));/i
9
+ NAMED_RE = /^&([a-z][a-z0-9]{1,31});/i
10
+
11
+
12
+ #------------------------------------------------------------------------------
13
+ def self.entity(state, silent)
14
+ pos = state.pos
15
+ max = state.posMax
16
+
17
+ return false if state.src.charCodeAt(pos) != 0x26 # &
18
+
19
+ if pos + 1 < max
20
+ ch = state.src.charCodeAt(pos + 1)
21
+
22
+ if ch == 0x23 # '#'
23
+ match = state.src.slice_to_end(pos).match(DIGITAL_RE)
24
+ if match
25
+ if !silent
26
+ code = match[1][0].downcase == 'x' ? match[1].slice_to_end(1).to_i(16) : match[1].to_i
27
+ state.pending += isValidEntityCode(code) ? fromCodePoint(code) : fromCodePoint(0xFFFD)
28
+ end
29
+ state.pos += match[0].length
30
+ return true
31
+ end
32
+ else
33
+ match = state.src.slice_to_end(pos).match(NAMED_RE)
34
+ if match
35
+ if HTMLEntities::MAPPINGS[match[1]]
36
+ state.pending += HTMLEntities::MAPPINGS[match[1]].chr(Encoding::UTF_8) if !silent
37
+ state.pos += match[0].length
38
+ return true
39
+ end
40
+ end
41
+ end
42
+ end
43
+
44
+ state.pending += '&' if !silent
45
+ state.pos += 1
46
+ return true
47
+ end
48
+
49
+ end
50
+ end
51
+ end
@@ -0,0 +1,55 @@
1
+ # Proceess escaped chars and hardbreaks
2
+ #------------------------------------------------------------------------------
3
+ module MarkdownIt
4
+ module RulesInline
5
+ class Escape
6
+
7
+ ESCAPED = []
8
+
9
+ 0.upto(255) { |i| ESCAPED.push(0) }
10
+
11
+ '\\!"#$%&\'()*+,./:;<=>?@[]^_`{|}~-'.split('').each { |ch| ESCAPED[ch.ord] = 1 }
12
+
13
+
14
+ #------------------------------------------------------------------------------
15
+ def self.escape(state, silent)
16
+ pos = state.pos
17
+ max = state.posMax
18
+
19
+ return false if state.src.charCodeAt(pos) != 0x5C # \
20
+
21
+ pos += 1
22
+
23
+ if pos < max
24
+ ch = state.src.charCodeAt(pos)
25
+
26
+ if ch < 256 && ESCAPED[ch] != 0
27
+ state.pending += state.src[pos] if !silent
28
+ state.pos += 2
29
+ return true
30
+ end
31
+
32
+ if ch == 0x0A
33
+ if !silent
34
+ state.push('hardbreak', 'br', 0)
35
+ end
36
+
37
+ pos += 1
38
+ # skip leading whitespaces from next line
39
+ while (pos < max && state.src.charCodeAt(pos) == 0x20)
40
+ pos += 1
41
+ end
42
+
43
+ state.pos = pos
44
+ return true
45
+ end
46
+ end
47
+
48
+ state.pending += '\\' if !silent
49
+ state.pos += 1
50
+ return true
51
+ end
52
+
53
+ end
54
+ end
55
+ end
@@ -0,0 +1,49 @@
1
+ # Process html tags
2
+ #------------------------------------------------------------------------------
3
+ module MarkdownIt
4
+
5
+ module RulesInline
6
+ class HtmlInline
7
+ include MarkdownIt::Common::HtmlRe
8
+
9
+ #------------------------------------------------------------------------------
10
+ def self.isLetter(ch)
11
+ lc = ch | 0x20 # to lower case
12
+ return (lc >= 0x61) && (lc <= 0x7a) # >= a && <= z
13
+ end
14
+
15
+ #------------------------------------------------------------------------------
16
+ def self.html_inline(state, silent)
17
+ pos = state.pos
18
+
19
+ return false if !state.md.options[:html]
20
+
21
+ # Check start
22
+ max = state.posMax
23
+ if (state.src.charCodeAt(pos) != 0x3C || pos + 2 >= max) # <
24
+ return false
25
+ end
26
+
27
+ # Quick fail on second char
28
+ ch = state.src.charCodeAt(pos + 1)
29
+ if (ch != 0x21 && # !
30
+ ch != 0x3F && # ?
31
+ ch != 0x2F && # /
32
+ !isLetter(ch))
33
+ return false
34
+ end
35
+
36
+ match = state.src.slice_to_end(pos).match(HTML_TAG_RE)
37
+ return false if !match
38
+
39
+ if !silent
40
+ token = state.push('html_inline', '', 0)
41
+ token.content = state.src.slice(pos...(pos + match[0].length))
42
+ end
43
+ state.pos += match[0].length
44
+ return true
45
+ end
46
+
47
+ end
48
+ end
49
+ end
@@ -0,0 +1,158 @@
1
+ # Process ![image](<src> "title")
2
+ #------------------------------------------------------------------------------
3
+ module MarkdownIt
4
+ module RulesInline
5
+ class Image
6
+ extend Helpers::ParseLinkDestination
7
+ extend Helpers::ParseLinkLabel
8
+ extend Helpers::ParseLinkTitle
9
+ extend Common::Utils
10
+
11
+ #------------------------------------------------------------------------------
12
+ def self.image(state, silent)
13
+ href = ''
14
+ oldPos = state.pos
15
+ max = state.posMax
16
+
17
+ return false if (state.src.charCodeAt(state.pos) != 0x21) # !
18
+ return false if (state.src.charCodeAt(state.pos + 1) != 0x5B) # [
19
+
20
+ labelStart = state.pos + 2
21
+ labelEnd = parseLinkLabel(state, state.pos + 1, false)
22
+
23
+ # parser failed to find ']', so it's not a valid link
24
+ return false if (labelEnd < 0)
25
+
26
+ pos = labelEnd + 1
27
+ if (pos < max && state.src.charCodeAt(pos) == 0x28) # (
28
+ #
29
+ # Inline link
30
+ #
31
+
32
+ # [link]( <href> "title" )
33
+ # ^^ skipping these spaces
34
+ pos += 1
35
+ while pos < max
36
+ code = state.src.charCodeAt(pos)
37
+ break if (code != 0x20 && code != 0x0A)
38
+ pos += 1
39
+ end
40
+ return false if (pos >= max)
41
+
42
+ # [link]( <href> "title" )
43
+ # ^^^^^^ parsing link destination
44
+ start = pos
45
+ res = parseLinkDestination(state.src, pos, state.posMax)
46
+ if (res[:ok])
47
+ href = state.md.normalizeLink.call(res[:str])
48
+ if (state.md.validateLink.call(href))
49
+ pos = res[:pos]
50
+ else
51
+ href = ''
52
+ end
53
+ end
54
+
55
+ # [link]( <href> "title" )
56
+ # ^^ skipping these spaces
57
+ start = pos
58
+ while pos < max
59
+ code = state.src.charCodeAt(pos)
60
+ break if (code != 0x20 && code != 0x0A)
61
+ pos += 1
62
+ end
63
+
64
+ # [link]( <href> "title" )
65
+ # ^^^^^^^ parsing link title
66
+ res = parseLinkTitle(state.src, pos, state.posMax)
67
+ if (pos < max && start != pos && res[:ok])
68
+ title = res[:str]
69
+ pos = res[:pos]
70
+
71
+ # [link]( <href> "title" )
72
+ # ^^ skipping these spaces
73
+ while pos < max
74
+ code = state.src.charCodeAt(pos);
75
+ break if (code != 0x20 && code != 0x0A)
76
+ pos += 1
77
+ end
78
+ else
79
+ title = ''
80
+ end
81
+
82
+ if (pos >= max || state.src.charCodeAt(pos) != 0x29) # )
83
+ state.pos = oldPos
84
+ return false
85
+ end
86
+ pos += 1
87
+ else
88
+ #
89
+ # Link reference
90
+ #
91
+ return false if state.env[:references].nil?
92
+
93
+ # [foo] [bar]
94
+ # ^^ optional whitespace (can include newlines)
95
+ while pos < max
96
+ code = state.src.charCodeAt(pos)
97
+ break if (code != 0x20 && code != 0x0A)
98
+ pos += 1
99
+ end
100
+
101
+ if (pos < max && state.src.charCodeAt(pos) == 0x5B) # [
102
+ start = pos + 1
103
+ pos = parseLinkLabel(state, pos)
104
+ if (pos >= 0)
105
+ label = state.src.slice(start...pos)
106
+ pos += 1
107
+ else
108
+ pos = labelEnd + 1
109
+ end
110
+ else
111
+ pos = labelEnd + 1
112
+ end
113
+
114
+ # covers label === '' and label === undefined
115
+ # (collapsed reference link and shortcut reference link respectively)
116
+ label = state.src.slice(labelStart...labelEnd) if label.nil? || label.empty?
117
+
118
+ ref = state.env[:references][normalizeReference(label)]
119
+ if (!ref)
120
+ state.pos = oldPos
121
+ return false
122
+ end
123
+ href = ref[:href]
124
+ title = ref[:title]
125
+ end
126
+
127
+ #
128
+ # We found the end of the link, and know for a fact it's a valid link;
129
+ # so all that's left to do is to call tokenizer.
130
+ #
131
+ if (!silent)
132
+ state.pos = labelStart
133
+ state.posMax = labelEnd
134
+
135
+ newState = RulesInline::StateInline.new(
136
+ state.src.slice(labelStart...labelEnd),
137
+ state.md,
138
+ state.env,
139
+ tokens = []
140
+ )
141
+ newState.md.inline.tokenize(newState)
142
+
143
+ token = state.push('image', 'img', 0)
144
+ token.attrs = attrs = [ [ 'src', href ], [ 'alt', '' ] ]
145
+ token.children = tokens
146
+ unless (title.nil? || title.empty?)
147
+ attrs.push([ 'title', title ])
148
+ end
149
+ end
150
+
151
+ state.pos = pos
152
+ state.posMax = max
153
+ return true
154
+ end
155
+
156
+ end
157
+ end
158
+ end
@@ -0,0 +1,153 @@
1
+ # Process [link](<to> "stuff")
2
+ #------------------------------------------------------------------------------
3
+ module MarkdownIt
4
+ module RulesInline
5
+ class Link
6
+ extend Helpers::ParseLinkDestination
7
+ extend Helpers::ParseLinkLabel
8
+ extend Helpers::ParseLinkTitle
9
+ extend Common::Utils
10
+
11
+ #------------------------------------------------------------------------------
12
+ def self.link(state, silent)
13
+ href = ''
14
+ oldPos = state.pos
15
+ max = state.posMax
16
+ start = state.pos
17
+
18
+ return false if (state.src.charCodeAt(state.pos) != 0x5B) # [
19
+
20
+ labelStart = state.pos + 1
21
+ labelEnd = parseLinkLabel(state, state.pos, true)
22
+
23
+ # parser failed to find ']', so it's not a valid link
24
+ return false if (labelEnd < 0)
25
+
26
+ pos = labelEnd + 1
27
+ if (pos < max && state.src.charCodeAt(pos) == 0x28) # (
28
+ #
29
+ # Inline link
30
+ #
31
+
32
+ # [link]( <href> "title" )
33
+ # ^^ skipping these spaces
34
+ pos += 1
35
+ while pos < max
36
+ code = state.src.charCodeAt(pos)
37
+ break if (code != 0x20 && code != 0x0A)
38
+ pos += 1
39
+ end
40
+ return false if (pos >= max)
41
+
42
+ # [link]( <href> "title" )
43
+ # ^^^^^^ parsing link destination
44
+ start = pos
45
+ res = parseLinkDestination(state.src, pos, state.posMax)
46
+ if (res[:ok])
47
+ href = state.md.normalizeLink.call(res[:str])
48
+ if (state.md.validateLink.call(href))
49
+ pos = res[:pos]
50
+ else
51
+ href = ''
52
+ end
53
+ end
54
+
55
+ # [link]( <href> "title" )
56
+ # ^^ skipping these spaces
57
+ start = pos
58
+ while pos < max
59
+ code = state.src.charCodeAt(pos)
60
+ break if (code != 0x20 && code != 0x0A)
61
+ pos += 1
62
+ end
63
+
64
+ # [link]( <href> "title" )
65
+ # ^^^^^^^ parsing link title
66
+ res = parseLinkTitle(state.src, pos, state.posMax)
67
+ if (pos < max && start != pos && res[:ok])
68
+ title = res[:str]
69
+ pos = res[:pos]
70
+
71
+ # [link]( <href> "title" )
72
+ # ^^ skipping these spaces
73
+ while pos < max
74
+ code = state.src.charCodeAt(pos)
75
+ break if (code != 0x20 && code != 0x0A)
76
+ pos += 1
77
+ end
78
+ else
79
+ title = ''
80
+ end
81
+
82
+ if (pos >= max || state.src.charCodeAt(pos) != 0x29) # )
83
+ state.pos = oldPos
84
+ return false
85
+ end
86
+ pos += 1
87
+ else
88
+ #
89
+ # Link reference
90
+ #
91
+ return false if state.env[:references].nil?
92
+
93
+ # [foo] [bar]
94
+ # ^^ optional whitespace (can include newlines)
95
+ while pos < max
96
+ code = state.src.charCodeAt(pos);
97
+ break if (code != 0x20 && code != 0x0A)
98
+ pos += 1
99
+ end
100
+
101
+ if (pos < max && state.src.charCodeAt(pos) == 0x5B) # [
102
+ start = pos + 1
103
+ pos = parseLinkLabel(state, pos)
104
+ if (pos >= 0)
105
+ label = state.src.slice(start...pos)
106
+ pos += 1
107
+ else
108
+ pos = labelEnd + 1
109
+ end
110
+ else
111
+ pos = labelEnd + 1
112
+ end
113
+
114
+ # covers label === '' and label === undefined
115
+ # (collapsed reference link and shortcut reference link respectively)
116
+ label = state.src.slice(labelStart...labelEnd) if label.nil? || label.empty?
117
+
118
+ ref = state.env[:references][normalizeReference(label)]
119
+ if (!ref)
120
+ state.pos = oldPos
121
+ return false
122
+ end
123
+ href = ref[:href]
124
+ title = ref[:title]
125
+ end
126
+
127
+ #
128
+ # We found the end of the link, and know for a fact it's a valid link;
129
+ # so all that's left to do is to call tokenizer.
130
+ #
131
+ if (!silent)
132
+ state.pos = labelStart
133
+ state.posMax = labelEnd
134
+
135
+ token = state.push('link_open', 'a', 1)
136
+ token.attrs = attrs = [ [ 'href', href ] ]
137
+ unless title.nil? || title.empty?
138
+ attrs.push([ 'title', title ])
139
+ end
140
+
141
+ state.md.inline.tokenize(state)
142
+
143
+ token = state.push('link_close', 'a', -1)
144
+ end
145
+
146
+ state.pos = pos
147
+ state.posMax = max
148
+ return true
149
+ end
150
+
151
+ end
152
+ end
153
+ end