@depup/markdown-it 14.3.0-depup.39 → 15.0.0-depup.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 (72) hide show
  1. package/README.md +5 -9
  2. package/bin/markdown-it.mjs +2 -2
  3. package/changes.json +3 -19
  4. package/dist/browser/markdown-it.esm.min.mjs +2972 -0
  5. package/dist/browser/markdown-it.esm.min.mjs.map +1 -0
  6. package/dist/browser/markdown-it.umd.min.js +14 -0
  7. package/dist/browser/markdown-it.umd.min.js.map +1 -0
  8. package/dist/markdown-it.cjs.js +4412 -0
  9. package/dist/markdown-it.cjs.js.map +1 -0
  10. package/dist/markdown-it.d.cts +19 -0
  11. package/dist/markdown-it.d.mts +979 -0
  12. package/dist/{index.cjs.js → markdown-it.mjs} +1437 -1466
  13. package/dist/markdown-it.mjs.map +1 -0
  14. package/package.json +48 -46
  15. package/dist/index.cjs.js.map +0 -1
  16. package/dist/markdown-it.js +0 -3975
  17. package/dist/markdown-it.js.map +0 -1
  18. package/dist/markdown-it.min.js +0 -3
  19. package/dist/markdown-it.min.js.map +0 -1
  20. package/index.mjs +0 -1
  21. package/lib/common/html_blocks.mjs +0 -67
  22. package/lib/common/html_re.mjs +0 -25
  23. package/lib/common/utils.mjs +0 -324
  24. package/lib/helpers/index.mjs +0 -11
  25. package/lib/helpers/parse_link_destination.mjs +0 -77
  26. package/lib/helpers/parse_link_label.mjs +0 -49
  27. package/lib/helpers/parse_link_title.mjs +0 -66
  28. package/lib/index.mjs +0 -565
  29. package/lib/parser_block.mjs +0 -134
  30. package/lib/parser_core.mjs +0 -62
  31. package/lib/parser_inline.mjs +0 -197
  32. package/lib/presets/commonmark.mjs +0 -88
  33. package/lib/presets/default.mjs +0 -47
  34. package/lib/presets/zero.mjs +0 -70
  35. package/lib/renderer.mjs +0 -322
  36. package/lib/ruler.mjs +0 -340
  37. package/lib/rules_block/blockquote.mjs +0 -209
  38. package/lib/rules_block/code.mjs +0 -30
  39. package/lib/rules_block/fence.mjs +0 -94
  40. package/lib/rules_block/heading.mjs +0 -51
  41. package/lib/rules_block/hr.mjs +0 -40
  42. package/lib/rules_block/html_block.mjs +0 -80
  43. package/lib/rules_block/lheading.mjs +0 -85
  44. package/lib/rules_block/list.mjs +0 -331
  45. package/lib/rules_block/paragraph.mjs +0 -48
  46. package/lib/rules_block/reference.mjs +0 -212
  47. package/lib/rules_block/state_block.mjs +0 -220
  48. package/lib/rules_block/table.mjs +0 -228
  49. package/lib/rules_core/block.mjs +0 -13
  50. package/lib/rules_core/inline.mjs +0 -11
  51. package/lib/rules_core/linkify.mjs +0 -134
  52. package/lib/rules_core/normalize.mjs +0 -17
  53. package/lib/rules_core/replacements.mjs +0 -101
  54. package/lib/rules_core/smartquotes.mjs +0 -209
  55. package/lib/rules_core/state_core.mjs +0 -17
  56. package/lib/rules_core/text_join.mjs +0 -43
  57. package/lib/rules_inline/autolink.mjs +0 -72
  58. package/lib/rules_inline/backticks.mjs +0 -60
  59. package/lib/rules_inline/balance_pairs.mjs +0 -124
  60. package/lib/rules_inline/emphasis.mjs +0 -123
  61. package/lib/rules_inline/entity.mjs +0 -51
  62. package/lib/rules_inline/escape.mjs +0 -83
  63. package/lib/rules_inline/fragments_join.mjs +0 -38
  64. package/lib/rules_inline/html_inline.mjs +0 -50
  65. package/lib/rules_inline/image.mjs +0 -138
  66. package/lib/rules_inline/link.mjs +0 -139
  67. package/lib/rules_inline/linkify.mjs +0 -63
  68. package/lib/rules_inline/newline.mjs +0 -42
  69. package/lib/rules_inline/state_inline.mjs +0 -154
  70. package/lib/rules_inline/strikethrough.mjs +0 -127
  71. package/lib/rules_inline/text.mjs +0 -86
  72. package/lib/token.mjs +0 -191
@@ -1,101 +0,0 @@
1
- // Simple typographic replacements
2
- //
3
- // (c) (C) → ©
4
- // (tm) (TM) → ™
5
- // (r) (R) → ®
6
- // +- → ±
7
- // ... → … (also ?.... → ?.., !.... → !..)
8
- // ???????? → ???, !!!!! → !!!, `,,` → `,`
9
- // -- → –, --- → —
10
- //
11
-
12
- // TODO:
13
- // - fractionals 1/2, 1/4, 3/4 -> ½, ¼, ¾
14
- // - multiplications 2 x 4 -> 2 × 4
15
-
16
- const RARE_RE = /\+-|\.\.|\?\?\?\?|!!!!|,,|--/
17
-
18
- // Workaround for phantomjs - need regex without /g flag,
19
- // or root check will fail every second time
20
- const SCOPED_ABBR_TEST_RE = /\((c|tm|r)\)/i
21
-
22
- const SCOPED_ABBR_RE = /\((c|tm|r)\)/ig
23
- const SCOPED_ABBR = {
24
- c: '©',
25
- r: '®',
26
- tm: '™'
27
- }
28
-
29
- function replaceFn (match, name) {
30
- return SCOPED_ABBR[name.toLowerCase()]
31
- }
32
-
33
- function replace_scoped (inlineTokens) {
34
- let inside_autolink = 0
35
-
36
- for (let i = inlineTokens.length - 1; i >= 0; i--) {
37
- const token = inlineTokens[i]
38
-
39
- if (token.type === 'text' && !inside_autolink) {
40
- token.content = token.content.replace(SCOPED_ABBR_RE, replaceFn)
41
- }
42
-
43
- if (token.type === 'link_open' && token.info === 'auto') {
44
- inside_autolink--
45
- }
46
-
47
- if (token.type === 'link_close' && token.info === 'auto') {
48
- inside_autolink++
49
- }
50
- }
51
- }
52
-
53
- function replace_rare (inlineTokens) {
54
- let inside_autolink = 0
55
-
56
- for (let i = inlineTokens.length - 1; i >= 0; i--) {
57
- const token = inlineTokens[i]
58
-
59
- if (token.type === 'text' && !inside_autolink) {
60
- if (RARE_RE.test(token.content)) {
61
- token.content = token.content
62
- .replace(/\+-/g, '±')
63
- // .., ..., ....... -> …
64
- // but ?..... & !..... -> ?.. & !..
65
- .replace(/\.{2,}/g, '…').replace(/([?!])…/g, '$1..')
66
- .replace(/([?!]){4,}/g, '$1$1$1').replace(/,{2,}/g, ',')
67
- // em-dash
68
- .replace(/(^|[^-])---(?=[^-]|$)/mg, '$1\u2014')
69
- // en-dash
70
- .replace(/(^|\s)--(?=\s|$)/mg, '$1\u2013')
71
- .replace(/(^|[^-\s])--(?=[^-\s]|$)/mg, '$1\u2013')
72
- }
73
- }
74
-
75
- if (token.type === 'link_open' && token.info === 'auto') {
76
- inside_autolink--
77
- }
78
-
79
- if (token.type === 'link_close' && token.info === 'auto') {
80
- inside_autolink++
81
- }
82
- }
83
- }
84
-
85
- export default function replace (state) {
86
- let blkIdx
87
-
88
- if (!state.md.options.typographer) { return }
89
-
90
- for (blkIdx = state.tokens.length - 1; blkIdx >= 0; blkIdx--) {
91
- if (state.tokens[blkIdx].type !== 'inline') { continue }
92
-
93
- if (SCOPED_ABBR_TEST_RE.test(state.tokens[blkIdx].content)) {
94
- replace_scoped(state.tokens[blkIdx].children)
95
- }
96
-
97
- if (RARE_RE.test(state.tokens[blkIdx].content)) {
98
- replace_rare(state.tokens[blkIdx].children)
99
- }
100
- }
101
- }
@@ -1,209 +0,0 @@
1
- // Convert straight quotation marks to typographic ones
2
- //
3
-
4
- import { isWhiteSpace, isPunctCharCode, isMdAsciiPunct } from '../common/utils.mjs'
5
-
6
- const QUOTE_TEST_RE = /['"]/
7
- const QUOTE_RE = /['"]/g
8
- const APOSTROPHE = '\u2019' /* ’ */
9
-
10
- function addReplacement (replacements, tokenIdx, pos, ch) {
11
- if (!replacements[tokenIdx]) {
12
- replacements[tokenIdx] = []
13
- }
14
-
15
- replacements[tokenIdx].push({ pos, ch })
16
- }
17
-
18
- function applyReplacements (str, replacements) {
19
- let result = ''
20
- let lastPos = 0
21
-
22
- replacements.sort((a, b) => a.pos - b.pos)
23
-
24
- for (let i = 0; i < replacements.length; i++) {
25
- const replacement = replacements[i]
26
-
27
- result += str.slice(lastPos, replacement.pos) + replacement.ch
28
- lastPos = replacement.pos + 1
29
- }
30
-
31
- return result + str.slice(lastPos)
32
- }
33
-
34
- function process_inlines (tokens, state) {
35
- let j
36
-
37
- const stack = []
38
- // token index -> list of replacements in the original token content
39
- const replacements = {}
40
-
41
- for (let i = 0; i < tokens.length; i++) {
42
- const token = tokens[i]
43
-
44
- const thisLevel = tokens[i].level
45
-
46
- for (j = stack.length - 1; j >= 0; j--) {
47
- if (stack[j].level <= thisLevel) { break }
48
- }
49
- stack.length = j + 1
50
-
51
- if (token.type !== 'text') { continue }
52
-
53
- const text = token.content
54
- let pos = 0
55
- const max = text.length
56
-
57
- /* eslint no-labels:0,block-scoped-var:0 */
58
- OUTER:
59
- while (pos < max) {
60
- QUOTE_RE.lastIndex = pos
61
- const t = QUOTE_RE.exec(text)
62
- if (!t) { break }
63
-
64
- let canOpen = true
65
- let canClose = true
66
- pos = t.index + 1
67
- const isSingle = (t[0] === "'")
68
-
69
- // Find previous character,
70
- // default to space if it's the beginning of the line
71
- //
72
- let lastChar = 0x20
73
-
74
- if (t.index - 1 >= 0) {
75
- lastChar = text.charCodeAt(t.index - 1)
76
- } else {
77
- for (j = i - 1; j >= 0; j--) {
78
- if (tokens[j].type === 'softbreak' || tokens[j].type === 'hardbreak') break // lastChar defaults to 0x20
79
- if (!tokens[j].content) continue // should skip all tokens except 'text', 'html_inline' or 'code_inline'
80
-
81
- lastChar = tokens[j].content.charCodeAt(tokens[j].content.length - 1)
82
- break
83
- }
84
- }
85
-
86
- // Find next character,
87
- // default to space if it's the end of the line
88
- //
89
- let nextChar = 0x20
90
-
91
- if (pos < max) {
92
- nextChar = text.charCodeAt(pos)
93
- } else {
94
- for (j = i + 1; j < tokens.length; j++) {
95
- if (tokens[j].type === 'softbreak' || tokens[j].type === 'hardbreak') break // nextChar defaults to 0x20
96
- if (!tokens[j].content) continue // should skip all tokens except 'text', 'html_inline' or 'code_inline'
97
-
98
- nextChar = tokens[j].content.charCodeAt(0)
99
- break
100
- }
101
- }
102
-
103
- const isLastPunctChar = isMdAsciiPunct(lastChar) || isPunctCharCode(lastChar)
104
- const isNextPunctChar = isMdAsciiPunct(nextChar) || isPunctCharCode(nextChar)
105
-
106
- const isLastWhiteSpace = isWhiteSpace(lastChar)
107
- const isNextWhiteSpace = isWhiteSpace(nextChar)
108
-
109
- if (isNextWhiteSpace) {
110
- canOpen = false
111
- } else if (isNextPunctChar) {
112
- if (!(isLastWhiteSpace || isLastPunctChar)) {
113
- canOpen = false
114
- }
115
- }
116
-
117
- if (isLastWhiteSpace) {
118
- canClose = false
119
- } else if (isLastPunctChar) {
120
- if (!(isNextWhiteSpace || isNextPunctChar)) {
121
- canClose = false
122
- }
123
- }
124
-
125
- if (nextChar === 0x22 /* " */ && t[0] === '"') {
126
- if (lastChar >= 0x30 /* 0 */ && lastChar <= 0x39 /* 9 */) {
127
- // special case: 1"" - count first quote as an inch
128
- canClose = canOpen = false
129
- }
130
- }
131
-
132
- if (canOpen && canClose) {
133
- // Replace quotes in the middle of punctuation sequence, but not
134
- // in the middle of the words, i.e.:
135
- //
136
- // 1. foo " bar " baz - not replaced
137
- // 2. foo-"-bar-"-baz - replaced
138
- // 3. foo"bar"baz - not replaced
139
- //
140
- canOpen = isLastPunctChar
141
- canClose = isNextPunctChar
142
- }
143
-
144
- if (!canOpen && !canClose) {
145
- // middle of word
146
- if (isSingle) {
147
- addReplacement(replacements, i, t.index, APOSTROPHE)
148
- }
149
- continue
150
- }
151
-
152
- if (canClose) {
153
- // this could be a closing quote, rewind the stack to get a match
154
- for (j = stack.length - 1; j >= 0; j--) {
155
- let item = stack[j]
156
- if (stack[j].level < thisLevel) { break }
157
- if (item.single === isSingle && stack[j].level === thisLevel) {
158
- item = stack[j]
159
-
160
- let openQuote
161
- let closeQuote
162
- if (isSingle) {
163
- openQuote = state.md.options.quotes[2]
164
- closeQuote = state.md.options.quotes[3]
165
- } else {
166
- openQuote = state.md.options.quotes[0]
167
- closeQuote = state.md.options.quotes[1]
168
- }
169
-
170
- addReplacement(replacements, i, t.index, closeQuote)
171
- addReplacement(replacements, item.token, item.pos, openQuote)
172
-
173
- stack.length = j
174
- continue OUTER
175
- }
176
- }
177
- }
178
-
179
- if (canOpen) {
180
- stack.push({
181
- token: i,
182
- pos: t.index,
183
- single: isSingle,
184
- level: thisLevel
185
- })
186
- } else if (canClose && isSingle) {
187
- addReplacement(replacements, i, t.index, APOSTROPHE)
188
- }
189
- }
190
- }
191
-
192
- Object.keys(replacements).forEach(function (tokenIdx) {
193
- tokens[tokenIdx].content = applyReplacements(tokens[tokenIdx].content, replacements[tokenIdx])
194
- })
195
- }
196
-
197
- export default function smartquotes (state) {
198
- /* eslint max-depth:0 */
199
- if (!state.md.options.typographer) { return }
200
-
201
- for (let blkIdx = state.tokens.length - 1; blkIdx >= 0; blkIdx--) {
202
- if (state.tokens[blkIdx].type !== 'inline' ||
203
- !QUOTE_TEST_RE.test(state.tokens[blkIdx].content)) {
204
- continue
205
- }
206
-
207
- process_inlines(state.tokens[blkIdx].children, state)
208
- }
209
- }
@@ -1,17 +0,0 @@
1
- // Core state object
2
- //
3
-
4
- import Token from '../token.mjs'
5
-
6
- function StateCore (src, md, env) {
7
- this.src = src
8
- this.env = env
9
- this.tokens = []
10
- this.inlineMode = false
11
- this.md = md // link to parser instance
12
- }
13
-
14
- // re-export Token class to use in core rules
15
- StateCore.prototype.Token = Token
16
-
17
- export default StateCore
@@ -1,43 +0,0 @@
1
- // Join raw text tokens with the rest of the text
2
- //
3
- // This is set as a separate rule to provide an opportunity for plugins
4
- // to run text replacements after text join, but before escape join.
5
- //
6
- // For example, `\:)` shouldn't be replaced with an emoji.
7
- //
8
-
9
- export default function text_join (state) {
10
- let curr, last
11
- const blockTokens = state.tokens
12
- const l = blockTokens.length
13
-
14
- for (let j = 0; j < l; j++) {
15
- if (blockTokens[j].type !== 'inline') continue
16
-
17
- const tokens = blockTokens[j].children
18
- const max = tokens.length
19
-
20
- for (curr = 0; curr < max; curr++) {
21
- if (tokens[curr].type === 'text_special') {
22
- tokens[curr].type = 'text'
23
- }
24
- }
25
-
26
- for (curr = last = 0; curr < max; curr++) {
27
- if (tokens[curr].type === 'text' &&
28
- curr + 1 < max &&
29
- tokens[curr + 1].type === 'text') {
30
- // collapse two adjacent text nodes
31
- tokens[curr + 1].content = tokens[curr].content + tokens[curr + 1].content
32
- } else {
33
- if (curr !== last) { tokens[last] = tokens[curr] }
34
-
35
- last++
36
- }
37
- }
38
-
39
- if (curr !== last) {
40
- tokens.length = last
41
- }
42
- }
43
- }
@@ -1,72 +0,0 @@
1
- // Process autolinks '<protocol:...>'
2
-
3
- /* eslint max-len:0 */
4
- const EMAIL_RE = /^([a-zA-Z0-9.!#$%&'*+/=?^_`{|}~-]+@[a-zA-Z0-9](?:[a-zA-Z0-9-]{0,61}[a-zA-Z0-9])?(?:\.[a-zA-Z0-9](?:[a-zA-Z0-9-]{0,61}[a-zA-Z0-9])?)*)$/
5
- /* eslint-disable-next-line no-control-regex */
6
- const AUTOLINK_RE = /^([a-zA-Z][a-zA-Z0-9+.-]{1,31}):([^<>\x00-\x20]*)$/
7
-
8
- export default function autolink (state, silent) {
9
- let pos = state.pos
10
-
11
- if (state.src.charCodeAt(pos) !== 0x3C/* < */) { return false }
12
-
13
- const start = state.pos
14
- const max = state.posMax
15
-
16
- for (;;) {
17
- if (++pos >= max) return false
18
-
19
- const ch = state.src.charCodeAt(pos)
20
-
21
- if (ch === 0x3C /* < */) return false
22
- if (ch === 0x3E /* > */) break
23
- }
24
-
25
- const url = state.src.slice(start + 1, pos)
26
-
27
- if (AUTOLINK_RE.test(url)) {
28
- const fullUrl = state.md.normalizeLink(url)
29
- if (!state.md.validateLink(fullUrl)) { return false }
30
-
31
- if (!silent) {
32
- const token_o = state.push('link_open', 'a', 1)
33
- token_o.attrs = [['href', fullUrl]]
34
- token_o.markup = 'autolink'
35
- token_o.info = 'auto'
36
-
37
- const token_t = state.push('text', '', 0)
38
- token_t.content = state.md.normalizeLinkText(url)
39
-
40
- const token_c = state.push('link_close', 'a', -1)
41
- token_c.markup = 'autolink'
42
- token_c.info = 'auto'
43
- }
44
-
45
- state.pos += url.length + 2
46
- return true
47
- }
48
-
49
- if (EMAIL_RE.test(url)) {
50
- const fullUrl = state.md.normalizeLink('mailto:' + url)
51
- if (!state.md.validateLink(fullUrl)) { return false }
52
-
53
- if (!silent) {
54
- const token_o = state.push('link_open', 'a', 1)
55
- token_o.attrs = [['href', fullUrl]]
56
- token_o.markup = 'autolink'
57
- token_o.info = 'auto'
58
-
59
- const token_t = state.push('text', '', 0)
60
- token_t.content = state.md.normalizeLinkText(url)
61
-
62
- const token_c = state.push('link_close', 'a', -1)
63
- token_c.markup = 'autolink'
64
- token_c.info = 'auto'
65
- }
66
-
67
- state.pos += url.length + 2
68
- return true
69
- }
70
-
71
- return false
72
- }
@@ -1,60 +0,0 @@
1
- // Parse backticks
2
-
3
- export default function backtick (state, silent) {
4
- let pos = state.pos
5
- const ch = state.src.charCodeAt(pos)
6
-
7
- if (ch !== 0x60/* ` */) { return false }
8
-
9
- const start = pos
10
- pos++
11
- const max = state.posMax
12
-
13
- // scan marker length
14
- while (pos < max && state.src.charCodeAt(pos) === 0x60/* ` */) { pos++ }
15
-
16
- const marker = state.src.slice(start, pos)
17
- const openerLength = marker.length
18
-
19
- if (state.backticksScanned && (state.backticks[openerLength] || 0) <= start) {
20
- if (!silent) state.pending += marker
21
- state.pos += openerLength
22
- return true
23
- }
24
-
25
- let matchEnd = pos
26
- let matchStart
27
-
28
- // Nothing found in the cache, scan until the end of the line (or until marker is found)
29
- while ((matchStart = state.src.indexOf('`', matchEnd)) !== -1) {
30
- matchEnd = matchStart + 1
31
-
32
- // scan marker length
33
- while (matchEnd < max && state.src.charCodeAt(matchEnd) === 0x60/* ` */) { matchEnd++ }
34
-
35
- const closerLength = matchEnd - matchStart
36
-
37
- if (closerLength === openerLength) {
38
- // Found matching closer length.
39
- if (!silent) {
40
- const token = state.push('code_inline', 'code', 0)
41
- token.markup = marker
42
- token.content = state.src.slice(pos, matchStart)
43
- .replace(/\n/g, ' ')
44
- .replace(/^ (.+) $/, '$1')
45
- }
46
- state.pos = matchEnd
47
- return true
48
- }
49
-
50
- // Some different length found, put it in cache as upper limit of where closer can be found
51
- state.backticks[closerLength] = matchStart
52
- }
53
-
54
- // Scanned through the end, didn't find anything
55
- state.backticksScanned = true
56
-
57
- if (!silent) state.pending += marker
58
- state.pos += openerLength
59
- return true
60
- }
@@ -1,124 +0,0 @@
1
- // For each opening emphasis-like marker find a matching closing one
2
- //
3
-
4
- function processDelimiters (delimiters) {
5
- const openersBottom = {}
6
- const max = delimiters.length
7
-
8
- if (!max) return
9
-
10
- // headerIdx is the first delimiter of the current (where closer is) delimiter run
11
- let headerIdx = 0
12
- let lastTokenIdx = -2 // needs any value lower than -1
13
- const jumps = []
14
-
15
- for (let closerIdx = 0; closerIdx < max; closerIdx++) {
16
- const closer = delimiters[closerIdx]
17
-
18
- jumps.push(0)
19
-
20
- // markers belong to same delimiter run if:
21
- // - they have adjacent tokens
22
- // - AND markers are the same
23
- //
24
- if (delimiters[headerIdx].marker !== closer.marker || lastTokenIdx !== closer.token - 1) {
25
- headerIdx = closerIdx
26
- }
27
-
28
- lastTokenIdx = closer.token
29
-
30
- // Length is only used for emphasis-specific "rule of 3",
31
- // if it's not defined (in strikethrough or 3rd party plugins),
32
- // we can default it to 0 to disable those checks.
33
- //
34
- closer.length = closer.length || 0
35
-
36
- if (!closer.close) continue
37
-
38
- // Previously calculated lower bounds (previous fails)
39
- // for each marker, each delimiter length modulo 3,
40
- // and for whether this closer can be an opener;
41
- // https://github.com/commonmark/cmark/commit/34250e12ccebdc6372b8b49c44fab57c72443460
42
- /* eslint-disable-next-line no-prototype-builtins */
43
- if (!openersBottom.hasOwnProperty(closer.marker)) {
44
- openersBottom[closer.marker] = [-1, -1, -1, -1, -1, -1]
45
- }
46
-
47
- const minOpenerIdx = openersBottom[closer.marker][(closer.open ? 3 : 0) + (closer.length % 3)]
48
-
49
- let openerIdx = headerIdx - jumps[headerIdx] - 1
50
-
51
- let newMinOpenerIdx = openerIdx
52
-
53
- for (; openerIdx > minOpenerIdx; openerIdx -= jumps[openerIdx] + 1) {
54
- const opener = delimiters[openerIdx]
55
-
56
- if (opener.marker !== closer.marker) continue
57
-
58
- if (opener.open && opener.end < 0) {
59
- let isOddMatch = false
60
-
61
- // from spec:
62
- //
63
- // If one of the delimiters can both open and close emphasis, then the
64
- // sum of the lengths of the delimiter runs containing the opening and
65
- // closing delimiters must not be a multiple of 3 unless both lengths
66
- // are multiples of 3.
67
- //
68
- if (opener.close || closer.open) {
69
- if ((opener.length + closer.length) % 3 === 0) {
70
- if (opener.length % 3 !== 0 || closer.length % 3 !== 0) {
71
- isOddMatch = true
72
- }
73
- }
74
- }
75
-
76
- if (!isOddMatch) {
77
- // If previous delimiter cannot be an opener, we can safely skip
78
- // the entire sequence in future checks. This is required to make
79
- // sure algorithm has linear complexity (see *_*_*_*_*_... case).
80
- //
81
- const lastJump = openerIdx > 0 && !delimiters[openerIdx - 1].open
82
- ? jumps[openerIdx - 1] + 1
83
- : 0
84
-
85
- jumps[closerIdx] = closerIdx - openerIdx + lastJump
86
- jumps[openerIdx] = lastJump
87
-
88
- closer.open = false
89
- opener.end = closerIdx
90
- opener.close = false
91
- newMinOpenerIdx = -1
92
- // treat next token as start of run,
93
- // it optimizes skips in **<...>**a**<...>** pathological case
94
- lastTokenIdx = -2
95
- break
96
- }
97
- }
98
- }
99
-
100
- if (newMinOpenerIdx !== -1) {
101
- // If match for this delimiter run failed, we want to set lower bound for
102
- // future lookups. This is required to make sure algorithm has linear
103
- // complexity.
104
- //
105
- // See details here:
106
- // https://github.com/commonmark/cmark/issues/178#issuecomment-270417442
107
- //
108
- openersBottom[closer.marker][(closer.open ? 3 : 0) + ((closer.length || 0) % 3)] = newMinOpenerIdx
109
- }
110
- }
111
- }
112
-
113
- export default function link_pairs (state) {
114
- const tokens_meta = state.tokens_meta
115
- const max = state.tokens_meta.length
116
-
117
- processDelimiters(state.delimiters)
118
-
119
- for (let curr = 0; curr < max; curr++) {
120
- if (tokens_meta[curr] && tokens_meta[curr].delimiters) {
121
- processDelimiters(tokens_meta[curr].delimiters)
122
- }
123
- }
124
- }