motion-markdown-it 8.4.1.2 → 10.0.0

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 650922a627efaf3a0b14a2b615a77fa2368f3fa9521aebd02fa8102a9d472c03
4
- data.tar.gz: e615b7de9baa7f930d2e69f3e8d6562d4796373e112602cc19b9472d5e4ed628
3
+ metadata.gz: a7f2ac0d111cfc878b1017c5e3c32d1e9a6b9468176051937bac57f0378e5ac8
4
+ data.tar.gz: 13b8f19a17c53fca0f8ae6c8e373f219bb90b9e6152e7d3a9a0b1ad54c3f7c63
5
5
  SHA512:
6
- metadata.gz: 13890868afe5b3eb188a35fbcd0042c9334e5047a7e05fe46262ca45cd8bd919442e129856b74dfd8844edf66884899f3c36bf350664cd2e9b057d2d43690985
7
- data.tar.gz: 73b64c8811203fb281a8ab9d802ca59ae330b2134d6d2cf0142c8fd20ca526efc97667ef8f080485f4d1e6f4f37813ee45b925df5e661a90f377e561fce636b2
6
+ metadata.gz: d632e566f5280d655dac450d8e5c9532dc17829ec8c40aee01c1b35df2909f55e467940e2598bf557aa8c4ee85285a0d6bb1801a28ed1ddd3c1a1767a306c9eb
7
+ data.tar.gz: f669a717a5d9f56c2f9d9d7669bd329610b0120a2dceeca3334eb72411184b371448d71a03ad04e4ff9d4f7c7d499750f98b091bd1415ba709011193b0fd385b
data/README.md CHANGED
@@ -1,11 +1,13 @@
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
- [![Build Status](https://travis-ci.org/digitalmoksha/motion-markdown-it.svg?branch=master)](https://travis-ci.org/digitalmoksha/motion-markdown-it)
4
+ [![Build Status](https://github.com/digitalmoksha/motion-markdown-it/actions/workflows/ci.yml/badge.svg)](https://github.com/digitalmoksha/motion-markdown-it/actions/workflows/ci.yml)
5
5
 
6
6
  Ruby/RubyMotion version of Markdown-it (CommonMark compliant and extendable)
7
7
 
8
- 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 8.4.1
8
+ This gem is a port of the [markdown-it Javascript package](https://github.com/markdown-it/markdown-it) by Vitaly Puzrin and Alex Kocharin.
9
+
10
+ _Currently synced with markdown-it 10.0.0_
9
11
 
10
12
  ---
11
13
 
@@ -52,12 +54,15 @@ redcarpet 3.4.0 0.0065
52
54
 
53
55
  ## Table of content
54
56
 
55
- - [Install](#install)
56
- - [Usage examples](#usage-examples)
57
- - [Plugins](#plugins)
58
- - [Upgrading](#upgrading)
59
- - [References / Thanks](#references--thanks)
60
- - [License](#license)
57
+ - [markdown-it](#markdown-it)
58
+ - [Install](#install)
59
+ - [Usage examples](#usage-examples)
60
+ - [Simple](#simple)
61
+ - [Init with presets and options](#init-with-presets-and-options)
62
+ - [Plugins](#plugins)
63
+ - [Upgrading](#upgrading)
64
+ - [References / Thanks](#references--thanks)
65
+ - [License](#license)
61
66
 
62
67
  <!--
63
68
  - [API](#api)
@@ -3,6 +3,8 @@ module MarkdownIt
3
3
 
4
4
  # TODO this list needs to be brought up to same level as the WC3 document
5
5
  # http://www.w3.org/TR/xml-entity-names/byalpha.html
6
+ # Consider pulling in https://github.com/fb55/entities/blob/master/maps/entities.json,
7
+ # is kept up to date
6
8
  #------------------------------------------------------------------------------
7
9
  class HTMLEntities
8
10
 
@@ -626,6 +628,7 @@ module MarkdownIt
626
628
  'nearr' => 0x2197, # ↗ NORTH EAST ARROW
627
629
  'nequiv' => 0x2262, # ≢ NOT IDENTICAL TO
628
630
  'nexist' => 0x2204, # ∄ THERE DOES NOT EXIST
631
+ 'ngE' => '≧̸', # ≧̸ from https://github.com/fb55/entities/blob/master/maps/entities.json
629
632
  'nge' => 0x2271, # ≱ dup NEITHER GREATER-THAN NOR EQUAL TO
630
633
  'nges' => 0x2271, # ≱ dup skip NEITHER GREATER-THAN NOR EQUAL TO
631
634
  'Ngr' => 0x039d, # Ν dup skip GREEK CAPITAL LETTER NU
@@ -48,14 +48,17 @@ module MarkdownIt
48
48
 
49
49
  #------------------------------------------------------------------------------
50
50
  def fromCodePoint(c)
51
- c.chr(Encoding::UTF_8)
51
+ # Some html entities are mapped directly as characters rather than code points.
52
+ # So if we're passed an Integer, convert to character, otherwise just return
53
+ # the character. For example `&ngE;`
54
+ c.is_a?(Integer) ? c.chr(Encoding::UTF_8) : c
52
55
  end
53
56
 
54
57
  #------------------------------------------------------------------------------
55
58
  def fromCharCode(c)
56
59
  c.chr
57
60
  end
58
-
61
+
59
62
  #------------------------------------------------------------------------------
60
63
  def charCodeAt(str, ch)
61
64
  str[ch].ord unless str[ch].nil?
@@ -216,11 +219,44 @@ module MarkdownIt
216
219
  # Hepler to unify [reference labels].
217
220
  #------------------------------------------------------------------------------
218
221
  def normalizeReference(str)
219
- # use .toUpperCase() instead of .toLowerCase()
220
- # here to avoid a conflict with Object.prototype
221
- # members (most notably, `__proto__`)
222
- return str.strip.gsub(/\s+/, ' ').upcase
222
+ # Trim and collapse whitespace
223
+ #
224
+ str = str.strip.gsub(/\s+/, ' ')
225
+
226
+ # .toLowerCase().toUpperCase() should get rid of all differences
227
+ # between letter variants.
228
+ #
229
+ # Simple .toLowerCase() doesn't normalize 125 code points correctly,
230
+ # and .toUpperCase doesn't normalize 6 of them (list of exceptions:
231
+ # İ, ϴ, ẞ, Ω, K, Å - those are already uppercased, but have differently
232
+ # uppercased versions).
233
+ #
234
+ # Here's an example showing how it happens. Lets take greek letter omega:
235
+ # uppercase U+0398 (Θ), U+03f4 (ϴ) and lowercase U+03b8 (θ), U+03d1 (ϑ)
236
+ #
237
+ # Unicode entries:
238
+ # 0398;GREEK CAPITAL LETTER THETA;Lu;0;L;;;;;N;;;;03B8;
239
+ # 03B8;GREEK SMALL LETTER THETA;Ll;0;L;;;;;N;;;0398;;0398
240
+ # 03D1;GREEK THETA SYMBOL;Ll;0;L;<compat> 03B8;;;;N;GREEK SMALL LETTER SCRIPT THETA;;0398;;0398
241
+ # 03F4;GREEK CAPITAL THETA SYMBOL;Lu;0;L;<compat> 0398;;;;N;;;;03B8;
242
+ #
243
+ # Case-insensitive comparison should treat all of them as equivalent.
244
+ #
245
+ # But .toLowerCase() doesn't change ϑ (it's already lowercase),
246
+ # and .toUpperCase() doesn't change ϴ (already uppercase).
247
+ #
248
+ # Applying first lower then upper case normalizes any character:
249
+ # '\u0398\u03f4\u03b8\u03d1'.toLowerCase().toUpperCase() === '\u0398\u0398\u0398\u0398'
250
+ #
251
+ # Note: this is equivalent to unicode case folding; unicode normalization
252
+ # is a different step that is not required here.
253
+ #
254
+ # Final result should be uppercased, because it's later stored in an object
255
+ # (this avoid a conflict with Object.prototype members,
256
+ # most notably, `__proto__`)
257
+ #
258
+ return str.downcase.upcase
223
259
  end
224
260
  end
225
261
  end
226
- end
262
+ end
@@ -15,7 +15,7 @@ module MarkdownIt
15
15
  pos += 1
16
16
  while (pos < max)
17
17
  code = charCodeAt(str, pos)
18
- return result if (code == 0x0A || isSpace(code)) # \n
18
+ return result if (code == 0x0A) # \n
19
19
  if (code == 0x3E) # >
20
20
  result[:pos] = pos + 1
21
21
  result[:str] = unescapeAll(str.slice((start + 1)...pos))
@@ -73,4 +73,4 @@ module MarkdownIt
73
73
  end
74
74
  end
75
75
  end
76
- end
76
+ end
@@ -8,9 +8,9 @@ module MarkdownIt
8
8
  class ParserCore
9
9
 
10
10
  attr_accessor :ruler
11
-
11
+
12
12
  RULES = [
13
- [ 'normalize', lambda { |state| RulesCore::Normalize.inline(state) } ],
13
+ [ 'normalize', lambda { |state| RulesCore::Normalize.normalize(state) } ],
14
14
  [ 'block', lambda { |state| RulesCore::Block.block(state) } ],
15
15
  [ 'inline', lambda { |state| RulesCore::Inline.inline(state) } ],
16
16
  [ 'linkify', lambda { |state| RulesCore::Linkify.linkify(state) } ],
@@ -43,4 +43,4 @@ module MarkdownIt
43
43
  end
44
44
  end
45
45
  end
46
- end
46
+ end
@@ -16,7 +16,7 @@
16
16
  #------------------------------------------------------------------------------
17
17
 
18
18
  module MarkdownIt
19
- class Ruler
19
+ class Ruler
20
20
 
21
21
  def initialize
22
22
  # // List of added rules. Each element is:
@@ -94,7 +94,7 @@ module MarkdownIt
94
94
  # *
95
95
  # * ##### Example
96
96
  # *
97
- # * Replace existing typorgapher replacement rule with new one:
97
+ # * Replace existing typographer replacement rule with new one:
98
98
  # *
99
99
  # * ```javascript
100
100
  # * var md = require('markdown-it')();
@@ -108,7 +108,7 @@ module MarkdownIt
108
108
  index = __find__(name)
109
109
 
110
110
  raise(StandardError, "Parser rule not found: #{name}") if index == -1
111
-
111
+
112
112
  @__rules__[index][:fn] = fn
113
113
  @__rules__[index][:alt] = opt[:alt] || ['']
114
114
  @__cache__ = nil
@@ -32,7 +32,9 @@ module MarkdownIt
32
32
  markup = state.src.slice(mem...pos)
33
33
  params = state.src.slice(pos...max)
34
34
 
35
- return false if params.include?(fromCharCode(marker))
35
+ if (marker == 0x60) # `
36
+ return false if params.include?(fromCharCode(marker))
37
+ end
36
38
 
37
39
  # Since start is found, we can report success here in validation mode
38
40
  return true if silent
@@ -109,6 +109,18 @@ module MarkdownIt
109
109
  # if it's indented more than 3 spaces, it should be a code block
110
110
  return false if (state.sCount[startLine] - state.blkIndent >= 4)
111
111
 
112
+ # Special case:
113
+ # - item 1
114
+ # - item 2
115
+ # - item 3
116
+ # - item 4
117
+ # - this one is a paragraph continuation
118
+ if (state.listIndent >= 0 &&
119
+ state.sCount[startLine] - state.listIndent >= 4 &&
120
+ state.sCount[startLine] < state.blkIndent)
121
+ return false
122
+ end
123
+
112
124
  # limit conditions when list can interrupt
113
125
  # a paragraph (validation mode only)
114
126
  if silent && state.parentType == 'paragraph'
@@ -220,11 +232,19 @@ module MarkdownIt
220
232
  token.markup = markerCharCode.chr
221
233
  token.map = itemLines = [ startLine, 0 ]
222
234
 
223
- oldIndent = state.blkIndent
235
+ # change current state, then restore it after parser subcall
224
236
  oldTight = state.tight
225
237
  oldTShift = state.tShift[startLine]
226
- oldLIndent = state.sCount[startLine]
238
+ oldSCount = state.sCount[startLine]
239
+
240
+ # - example list
241
+ # ^ listIndent position will be here
242
+ # ^ blkIndent position will be here
243
+ #
244
+ oldListIndent = state.listIndent
245
+ state.listIndent = state.blkIndent
227
246
  state.blkIndent = indent
247
+
228
248
  state.tight = true
229
249
  state.tShift[startLine] = contentStart - state.bMarks[startLine]
230
250
  state.sCount[startLine] = offset
@@ -250,9 +270,10 @@ module MarkdownIt
250
270
  # but we should filter last element, because it means list finish
251
271
  prevEmptyEnd = (state.line - startLine) > 1 && state.isEmpty(state.line - 1)
252
272
 
253
- state.blkIndent = oldIndent
273
+ state.blkIndent = state.listIndent
274
+ state.listIndent = oldListIndent
254
275
  state.tShift[startLine] = oldTShift
255
- state.sCount[startLine] = oldLIndent
276
+ state.sCount[startLine] = oldSCount
256
277
  state.tight = oldTight
257
278
 
258
279
  token = state.push('list_item_close', 'li', -1)
@@ -269,6 +290,9 @@ module MarkdownIt
269
290
  #
270
291
  break if (state.sCount[nextLine] < state.blkIndent)
271
292
 
293
+ # if it's indented more than 3 spaces, it should be a code block
294
+ break if (state.sCount[startLine] - state.blkIndent >= 4)
295
+
272
296
  # fail if terminating block found
273
297
  terminate = false
274
298
  (0...terminatorRules.length).each do |i|
@@ -6,7 +6,7 @@ module MarkdownIt
6
6
  include MarkdownIt::Common::Utils
7
7
 
8
8
  attr_accessor :src, :md, :env, :tokens, :bMarks, :eMarks, :tShift, :sCount, :bsCount
9
- attr_accessor :blkIndent, :line, :lineMax, :tight, :parentType, :ddIndent
9
+ attr_accessor :blkIndent, :line, :lineMax, :tight, :parentType, :ddIndent, :listIndent
10
10
  attr_accessor :level, :result
11
11
 
12
12
  #------------------------------------------------------------------------------
@@ -39,12 +39,14 @@ module MarkdownIt
39
39
  @bsCount = []
40
40
 
41
41
  # block parser variables
42
- @blkIndent = 0 # required block content indent (for example, if we are in list)
42
+ @blkIndent = 0 # equired block content indent (for example, if we are
43
+ # inside a list, it would be positioned after list marker)
43
44
  @line = 0 # line index in src
44
45
  @lineMax = 0 # lines count
45
46
  @tight = false # loose/tight mode for lists
46
47
  @parentType = 'root' # if `list`, block parser stops on two newlines
47
48
  @ddIndent = -1 # indent of the current dd block (-1 if there isn't any)
49
+ @listIndent = -1 # indent of the current list block (-1 if there isn't any)
48
50
 
49
51
  # can be 'blockquote', 'list', 'root', 'paragraph' or 'reference'
50
52
  # used in lists to determine if they interrupt a paragraph
@@ -113,9 +115,9 @@ module MarkdownIt
113
115
  token = Token.new(type, tag, nesting)
114
116
  token.block = true
115
117
 
116
- @level -= 1 if nesting < 0
118
+ @level -= 1 if nesting < 0 # closing tag
117
119
  token.level = @level
118
- @level += 1 if nesting > 0
120
+ @level += 1 if nesting > 0 # opening tag
119
121
 
120
122
  @tokens.push(token)
121
123
  return token
@@ -236,4 +238,4 @@ module MarkdownIt
236
238
 
237
239
  end
238
240
  end
239
- end
241
+ end
@@ -4,11 +4,12 @@ module MarkdownIt
4
4
  module RulesCore
5
5
  class Normalize
6
6
 
7
- NEWLINES_RE = /\r[\n\u0085]?|[\u2424\u2028\u0085]/
8
- NULL_RE = /\u0000/
7
+ # https://spec.commonmark.org/0.29/#line-ending
8
+ NEWLINES_RE = /\r\n?|\n/
9
+ NULL_RE = /\0/
9
10
 
10
11
  #------------------------------------------------------------------------------
11
- def self.inline(state)
12
+ def self.normalize(state)
12
13
  # Normalize newlines
13
14
  str = state.src.gsub(NEWLINES_RE, "\n")
14
15
 
@@ -19,4 +20,4 @@ module MarkdownIt
19
20
  end
20
21
  end
21
22
  end
22
- end
23
+ end
@@ -1,4 +1,4 @@
1
- # Simple typographyc replacements
1
+ # Simple typographic replacements
2
2
  #
3
3
  # (c) (C) → ©
4
4
  # (tm) (TM) → ™
@@ -35,7 +35,9 @@ module MarkdownIt
35
35
  if (!silent)
36
36
  token = state.push('code_inline', 'code', 0)
37
37
  token.markup = marker
38
- token.content = state.src.slice(pos...matchStart).gsub(/[ \n]+/, ' ').strip
38
+ token.content = state.src.slice(pos...matchStart)
39
+ .gsub(/\n/, ' ')
40
+ .gsub(/^ (.+) $/, '\1')
39
41
  end
40
42
  state.pos = matchEnd
41
43
  return true
@@ -5,44 +5,107 @@ module MarkdownIt
5
5
  class BalancePairs
6
6
 
7
7
  #------------------------------------------------------------------------------
8
- def self.link_pairs(state)
9
- delimiters = state.delimiters
10
- max = state.delimiters.length
11
-
12
- 0.upto(max - 1) do |i|
13
- lastDelim = delimiters[i]
14
-
15
- next if !lastDelim[:close]
16
-
17
- j = i - lastDelim[:jump] - 1
18
-
19
- while j >= 0
20
- currDelim = delimiters[j]
21
-
22
- if currDelim[:open] &&
23
- currDelim[:marker] == lastDelim[:marker] &&
24
- currDelim[:end] < 0 &&
25
- currDelim[:level] == lastDelim[:level]
26
-
27
- # typeofs are for backward compatibility with plugins
28
- # not needed: typeof currDelim.length !== 'undefined' &&
29
- # typeof lastDelim.length !== 'undefined' &&
30
- odd_match = (currDelim[:close] || lastDelim[:open]) &&
31
- (currDelim[:length] + lastDelim[:length]) % 3 == 0
32
-
33
- if !odd_match
34
- lastDelim[:jump] = i - j
35
- lastDelim[:open] = false
36
- currDelim[:end] = i
37
- currDelim[:jump] = 0
8
+ def self.processDelimiters(state, delimiters)
9
+ openersBottom = {}
10
+ max = delimiters.length
11
+
12
+ 0.upto(max - 1) do |closerIdx|
13
+ closer = delimiters[closerIdx]
14
+
15
+ # Length is only used for emphasis-specific "rule of 3",
16
+ # if it's not defined (in strikethrough or 3rd party plugins),
17
+ # we can default it to 0 to disable those checks.
18
+ #
19
+ closer[:length] = closer[:length] || 0
20
+
21
+ next if (!closer[:close])
22
+
23
+ # Previously calculated lower bounds (previous fails)
24
+ # for each marker and each delimiter length modulo 3.
25
+ unless openersBottom[closer[:marker]]
26
+ openersBottom[closer[:marker]] = [ -1, -1, -1 ]
27
+ end
28
+
29
+ minOpenerIdx = openersBottom[closer[:marker]][closer[:length] % 3]
30
+ newMinOpenerIdx = -1
31
+
32
+ openerIdx = closerIdx - closer[:jump] - 1
33
+
34
+ while openerIdx > minOpenerIdx
35
+ opener = delimiters[openerIdx]
36
+
37
+ (openerIdx -= opener[:jump] + 1) && next if (opener[:marker] != closer[:marker])
38
+
39
+ newMinOpenerIdx = openerIdx if (newMinOpenerIdx == -1)
40
+
41
+ if (opener[:open] &&
42
+ opener[:end] < 0 &&
43
+ opener[:level] == closer[:level])
44
+
45
+ isOddMatch = false
46
+
47
+ # from spec:
48
+ #
49
+ # If one of the delimiters can both open and close emphasis, then the
50
+ # sum of the lengths of the delimiter runs containing the opening and
51
+ # closing delimiters must not be a multiple of 3 unless both lengths
52
+ # are multiples of 3.
53
+ #
54
+ if (opener[:close] || closer[:open])
55
+ if ((opener[:length] + closer[:length]) % 3 == 0)
56
+ if (opener[:length] % 3 != 0 || closer[:length] % 3 != 0)
57
+ isOddMatch = true
58
+ end
59
+ end
60
+ end
61
+
62
+ if (!isOddMatch)
63
+ # If previous delimiter cannot be an opener, we can safely skip
64
+ # the entire sequence in future checks. This is required to make
65
+ # sure algorithm has linear complexity (see *_*_*_*_*_... case).
66
+ #
67
+ lastJump = openerIdx > 0 && !delimiters[openerIdx - 1][:open] ?
68
+ delimiters[openerIdx - 1][:jump] + 1 : 0
69
+
70
+ closer[:jump] = closerIdx - openerIdx + lastJump
71
+ closer[:open] = false
72
+ opener[:end] = closerIdx
73
+ opener[:jump] = lastJump
74
+ opener[:close] = false
75
+ newMinOpenerIdx = -1
38
76
  break
39
77
  end
40
78
  end
79
+
80
+ openerIdx -= opener[:jump] + 1
81
+ end
82
+
83
+ if (newMinOpenerIdx != -1)
84
+ # If match for this delimiter run failed, we want to set lower bound for
85
+ # future lookups. This is required to make sure algorithm has linear
86
+ # complexity.
87
+ #
88
+ # See details here:
89
+ # https://github.com/commonmark/cmark/issues/178#issuecomment-270417442
90
+ #
91
+ openersBottom[closer[:marker]][(closer[:length] || 0) % 3] = newMinOpenerIdx
92
+ end
93
+ end
94
+ end
95
+
96
+ #------------------------------------------------------------------------------
97
+ def self.link_pairs(state)
98
+ tokens_meta = state.tokens_meta
99
+ max = state.tokens_meta.length
41
100
 
42
- j -= currDelim[:jump] + 1
101
+ processDelimiters(state, state.delimiters)
102
+
103
+ 0.upto(max - 1) do |curr|
104
+ if (tokens_meta[curr] && tokens_meta[curr][:delimiters])
105
+ processDelimiters(state, tokens_meta[curr][:delimiters])
43
106
  end
44
107
  end
45
108
  end
46
109
  end
47
110
  end
48
- end
111
+ end
@@ -43,10 +43,6 @@ module MarkdownIt
43
43
  #
44
44
  token: state.tokens.length - 1,
45
45
 
46
- # Token level.
47
- #
48
- level: state.level,
49
-
50
46
  # If this delimiter is matched as a valid opener, `end` will be
51
47
  # equal to its position, otherwise it's `-1`.
52
48
  #
@@ -65,12 +61,8 @@ module MarkdownIt
65
61
  return true
66
62
  end
67
63
 
68
-
69
- # Walk through delimiter list and replace text tokens with tags
70
- #
71
- def self.postProcess(state)
72
- delimiters = state.delimiters
73
- max = state.delimiters.length
64
+ def self.private_postProcess(state, delimiters)
65
+ max = delimiters.length
74
66
 
75
67
  i = max - 1
76
68
  while i >= 0
@@ -119,6 +111,21 @@ module MarkdownIt
119
111
  i -= 1
120
112
  end
121
113
  end
114
+
115
+ # Walk through delimiter list and replace text tokens with tags
116
+ #
117
+ def self.postProcess(state)
118
+ tokens_meta = state.tokens_meta
119
+ max = state.tokens_meta.length
120
+
121
+ private_postProcess(state, state.delimiters)
122
+
123
+ 0.upto(max - 1) do |curr|
124
+ if (tokens_meta[curr] && tokens_meta[curr][:delimiters])
125
+ private_postProcess(state, tokens_meta[curr][:delimiters])
126
+ end
127
+ end
128
+ end
122
129
  end
123
130
  end
124
131
  end
@@ -5,7 +5,7 @@ module MarkdownIt
5
5
  class Entity
6
6
  extend Common::Utils
7
7
 
8
- DIGITAL_RE = /^&#((?:x[a-f0-9]{1,8}|[0-9]{1,8}));/i
8
+ DIGITAL_RE = /^&#((?:x[a-f0-9]{1,6}|[0-9]{1,7}));/i
9
9
  NAMED_RE = /^&([a-z][a-z0-9]{1,31});/i
10
10
 
11
11
 
@@ -5,7 +5,7 @@ module MarkdownIt
5
5
  class StateInline
6
6
  include MarkdownIt::Common::Utils
7
7
 
8
- attr_accessor :src, :env, :md, :tokens, :pos, :posMax, :level
8
+ attr_accessor :src, :env, :md, :tokens, :pos, :posMax, :level, :tokens_meta
9
9
  attr_accessor :pending, :pendingLevel, :cache, :delimiters
10
10
 
11
11
  #------------------------------------------------------------------------------
@@ -14,6 +14,7 @@ module MarkdownIt
14
14
  @env = env
15
15
  @md = md
16
16
  @tokens = outTokens
17
+ @tokens_meta = Array.new(outTokens.length)
17
18
 
18
19
  @pos = 0
19
20
  @posMax = @src.length
@@ -21,9 +22,15 @@ module MarkdownIt
21
22
  @pending = ''
22
23
  @pendingLevel = 0
23
24
 
24
- @cache = {} # Stores { start: end } pairs. Useful for backtrack
25
- # optimization of pairs parse (emphasis, strikes).
26
- @delimiters = []
25
+ # Stores { start: end } pairs. Useful for backtrack
26
+ # optimization of pairs parse (emphasis, strikes).
27
+ @cache = {}
28
+
29
+ # List of emphasis-like delimiters for current tag
30
+ @delimiters = []
31
+
32
+ # Stack of delimiter lists for upper level tags
33
+ @_prev_delimiters = [];
27
34
  end
28
35
 
29
36
 
@@ -44,13 +51,29 @@ module MarkdownIt
44
51
  def push(type, tag, nesting)
45
52
  pushPending unless @pending.empty?
46
53
 
47
- token = Token.new(type, tag, nesting);
48
- @level -= 1 if nesting < 0
54
+ token = Token.new(type, tag, nesting)
55
+ token_meta = nil
56
+
57
+ if nesting < 0
58
+ # closing tag
59
+ @level -= 1
60
+ @delimiters = @_prev_delimiters.pop
61
+ end
62
+
49
63
  token.level = @level
50
- @level += 1 if nesting > 0
64
+
65
+ if nesting > 0
66
+ # opening tag
67
+ @level += 1
68
+ @_prev_delimiters.push(@delimiters)
69
+ @delimiters = []
70
+ token_meta = { delimiters: @delimiters }
71
+ end
51
72
 
52
73
  @pendingLevel = @level
53
74
  @tokens.push(token)
75
+ @tokens_meta.push(token_meta)
76
+
54
77
  return token
55
78
  end
56
79
 
@@ -113,4 +136,4 @@ module MarkdownIt
113
136
  end
114
137
  end
115
138
  end
116
- end
139
+ end
@@ -34,10 +34,9 @@ module MarkdownIt
34
34
 
35
35
  state.delimiters.push({
36
36
  marker: marker,
37
- length: scanned[:length],
37
+ length: 0, # disable "rule of 3" length checks meant for emphasis
38
38
  jump: i,
39
39
  token: state.tokens.length - 1,
40
- level: state.level,
41
40
  end: -1,
42
41
  open: scanned[:can_open],
43
42
  close: scanned[:can_close]
@@ -50,12 +49,9 @@ module MarkdownIt
50
49
  return true
51
50
  end
52
51
 
53
- # Walk through delimiter list and replace text tokens with tags
54
- #------------------------------------------------------------------------------
55
- def self.postProcess(state)
52
+ def self.private_postProcess(state, delimiters)
56
53
  loneMarkers = []
57
- delimiters = state.delimiters
58
- max = state.delimiters.length
54
+ max = delimiters.length
59
55
 
60
56
  0.upto(max - 1) do |i|
61
57
  startDelim = delimiters[i]
@@ -109,6 +105,21 @@ module MarkdownIt
109
105
  end
110
106
  end
111
107
  end
108
+
109
+ # Walk through delimiter list and replace text tokens with tags
110
+ #
111
+ def self.postProcess(state)
112
+ tokens_meta = state.tokens_meta
113
+ max = state.tokens_meta.length
114
+
115
+ private_postProcess(state, state.delimiters)
116
+
117
+ 0.upto(max - 1) do |curr|
118
+ if (tokens_meta[curr] && tokens_meta[curr][:delimiters])
119
+ private_postProcess(state, tokens_meta[curr][:delimiters])
120
+ end
121
+ end
122
+ end
112
123
  end
113
124
  end
114
125
  end
@@ -1,4 +1,10 @@
1
+ # Clean up tokens after emphasis and strikethrough postprocessing:
1
2
  # Merge adjacent text nodes into one, and re-calculate all token levels
3
+ #
4
+ # This is necessary because initially emphasis delimiter markers (*, _, ~)
5
+ # are treated as their own separate text tokens. Then emphasis rule either
6
+ # leaves them as text (needed to merge with adjacent text) or turns them
7
+ # into opening/closing tags (which messes up levels inside).
2
8
  #------------------------------------------------------------------------------
3
9
  module MarkdownIt
4
10
  module RulesInline
@@ -12,9 +18,11 @@ module MarkdownIt
12
18
 
13
19
  last = curr = 0
14
20
  while curr < max
15
- # re-calculate levels
16
- level += tokens[curr].nesting
21
+ # re-calculate levels after emphasis/strikethrough turns some text nodes
22
+ # into opening/closing tags
23
+ level -= 1 if tokens[curr].nesting < 0 # closing tag
17
24
  tokens[curr].level = level
25
+ level += 1 if tokens[curr].nesting > 0 # opening tag
18
26
 
19
27
  if tokens[curr].type == 'text' &&
20
28
  curr + 1 < max &&
@@ -1,5 +1,3 @@
1
1
  module MotionMarkdownIt
2
-
3
- VERSION = '8.4.1.2'
4
-
2
+ VERSION = '10.0.0'
5
3
  end
data/spec/spec_helper.rb CHANGED
@@ -1,5 +1,6 @@
1
1
  # make sure to have `--require spec_helper` in `.rspec` to have the
2
2
  # spec_helper.rb included automatically in spec files
3
- require 'pry-byebug'
4
3
  require 'motion-markdown-it/testgen_helper'
5
4
  require 'motion-markdown-it'
5
+
6
+ require 'pry'
metadata CHANGED
@@ -1,16 +1,16 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: motion-markdown-it
3
3
  version: !ruby/object:Gem::Version
4
- version: 8.4.1.2
4
+ version: 10.0.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Brett Walker
8
8
  - Vitaly Puzrin
9
9
  - Alex Kocharin
10
- autorequire:
10
+ autorequire:
11
11
  bindir: bin
12
12
  cert_chain: []
13
- date: 2019-06-08 00:00:00.000000000 Z
13
+ date: 2023-01-16 00:00:00.000000000 Z
14
14
  dependencies:
15
15
  - !ruby/object:Gem::Dependency
16
16
  name: mdurl-rb
@@ -46,28 +46,28 @@ dependencies:
46
46
  requirements:
47
47
  - - "~>"
48
48
  - !ruby/object:Gem::Version
49
- version: '2.0'
49
+ version: '4.0'
50
50
  type: :runtime
51
51
  prerelease: false
52
52
  version_requirements: !ruby/object:Gem::Requirement
53
53
  requirements:
54
54
  - - "~>"
55
55
  - !ruby/object:Gem::Version
56
- version: '2.0'
56
+ version: '4.0'
57
57
  - !ruby/object:Gem::Dependency
58
- name: bacon-expect
58
+ name: motion-expect
59
59
  requirement: !ruby/object:Gem::Requirement
60
60
  requirements:
61
61
  - - "~>"
62
62
  - !ruby/object:Gem::Version
63
- version: '1.0'
63
+ version: '2.0'
64
64
  type: :development
65
65
  prerelease: false
66
66
  version_requirements: !ruby/object:Gem::Requirement
67
67
  requirements:
68
68
  - - "~>"
69
69
  - !ruby/object:Gem::Version
70
- version: '1.0'
70
+ version: '2.0'
71
71
  description: Ruby/RubyMotion version of markdown-it
72
72
  email: github@digitalmoksha.com
73
73
  executables: []
@@ -141,7 +141,7 @@ homepage: https://github.com/digitalmoksha/motion-markdown-it
141
141
  licenses:
142
142
  - MIT
143
143
  metadata: {}
144
- post_install_message:
144
+ post_install_message:
145
145
  rdoc_options: []
146
146
  require_paths:
147
147
  - lib
@@ -156,9 +156,8 @@ required_rubygems_version: !ruby/object:Gem::Requirement
156
156
  - !ruby/object:Gem::Version
157
157
  version: '0'
158
158
  requirements: []
159
- rubyforge_project:
160
- rubygems_version: 2.7.6
161
- signing_key:
159
+ rubygems_version: 3.3.23
160
+ signing_key:
162
161
  specification_version: 4
163
162
  summary: Ruby version markdown-it
164
163
  test_files: