motion-markdown-it 0.4.0.3.0

Sign up to get free protection for your applications and to get access to all the features.
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