@depup/markdown-it 14.1.1-depup.1
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.
- package/LICENSE +22 -0
- package/README.md +31 -0
- package/bin/markdown-it.mjs +107 -0
- package/changes.json +10 -0
- package/dist/index.cjs.js +5547 -0
- package/dist/markdown-it.js +6969 -0
- package/dist/markdown-it.min.js +2 -0
- package/index.mjs +1 -0
- package/lib/common/html_blocks.mjs +67 -0
- package/lib/common/html_re.mjs +25 -0
- package/lib/common/utils.mjs +304 -0
- package/lib/helpers/index.mjs +11 -0
- package/lib/helpers/parse_link_destination.mjs +77 -0
- package/lib/helpers/parse_link_label.mjs +49 -0
- package/lib/helpers/parse_link_title.mjs +66 -0
- package/lib/index.mjs +565 -0
- package/lib/parser_block.mjs +134 -0
- package/lib/parser_core.mjs +62 -0
- package/lib/parser_inline.mjs +197 -0
- package/lib/presets/commonmark.mjs +88 -0
- package/lib/presets/default.mjs +47 -0
- package/lib/presets/zero.mjs +70 -0
- package/lib/renderer.mjs +322 -0
- package/lib/ruler.mjs +340 -0
- package/lib/rules_block/blockquote.mjs +209 -0
- package/lib/rules_block/code.mjs +30 -0
- package/lib/rules_block/fence.mjs +94 -0
- package/lib/rules_block/heading.mjs +51 -0
- package/lib/rules_block/hr.mjs +40 -0
- package/lib/rules_block/html_block.mjs +69 -0
- package/lib/rules_block/lheading.mjs +82 -0
- package/lib/rules_block/list.mjs +331 -0
- package/lib/rules_block/paragraph.mjs +46 -0
- package/lib/rules_block/reference.mjs +212 -0
- package/lib/rules_block/state_block.mjs +220 -0
- package/lib/rules_block/table.mjs +228 -0
- package/lib/rules_core/block.mjs +13 -0
- package/lib/rules_core/inline.mjs +11 -0
- package/lib/rules_core/linkify.mjs +134 -0
- package/lib/rules_core/normalize.mjs +17 -0
- package/lib/rules_core/replacements.mjs +101 -0
- package/lib/rules_core/smartquotes.mjs +193 -0
- package/lib/rules_core/state_core.mjs +17 -0
- package/lib/rules_core/text_join.mjs +43 -0
- package/lib/rules_inline/autolink.mjs +72 -0
- package/lib/rules_inline/backticks.mjs +60 -0
- package/lib/rules_inline/balance_pairs.mjs +124 -0
- package/lib/rules_inline/emphasis.mjs +123 -0
- package/lib/rules_inline/entity.mjs +51 -0
- package/lib/rules_inline/escape.mjs +69 -0
- package/lib/rules_inline/fragments_join.mjs +38 -0
- package/lib/rules_inline/html_inline.mjs +50 -0
- package/lib/rules_inline/image.mjs +138 -0
- package/lib/rules_inline/link.mjs +139 -0
- package/lib/rules_inline/linkify.mjs +63 -0
- package/lib/rules_inline/newline.mjs +42 -0
- package/lib/rules_inline/state_inline.mjs +123 -0
- package/lib/rules_inline/strikethrough.mjs +127 -0
- package/lib/rules_inline/text.mjs +86 -0
- package/lib/token.mjs +191 -0
- package/package.json +109 -0
|
@@ -0,0 +1,209 @@
|
|
|
1
|
+
// Block quotes
|
|
2
|
+
|
|
3
|
+
import { isSpace } from '../common/utils.mjs'
|
|
4
|
+
|
|
5
|
+
export default function blockquote (state, startLine, endLine, silent) {
|
|
6
|
+
let pos = state.bMarks[startLine] + state.tShift[startLine]
|
|
7
|
+
let max = state.eMarks[startLine]
|
|
8
|
+
|
|
9
|
+
const oldLineMax = state.lineMax
|
|
10
|
+
|
|
11
|
+
// if it's indented more than 3 spaces, it should be a code block
|
|
12
|
+
if (state.sCount[startLine] - state.blkIndent >= 4) { return false }
|
|
13
|
+
|
|
14
|
+
// check the block quote marker
|
|
15
|
+
if (state.src.charCodeAt(pos) !== 0x3E/* > */) { return false }
|
|
16
|
+
|
|
17
|
+
// we know that it's going to be a valid blockquote,
|
|
18
|
+
// so no point trying to find the end of it in silent mode
|
|
19
|
+
if (silent) { return true }
|
|
20
|
+
|
|
21
|
+
const oldBMarks = []
|
|
22
|
+
const oldBSCount = []
|
|
23
|
+
const oldSCount = []
|
|
24
|
+
const oldTShift = []
|
|
25
|
+
|
|
26
|
+
const terminatorRules = state.md.block.ruler.getRules('blockquote')
|
|
27
|
+
|
|
28
|
+
const oldParentType = state.parentType
|
|
29
|
+
state.parentType = 'blockquote'
|
|
30
|
+
let lastLineEmpty = false
|
|
31
|
+
let nextLine
|
|
32
|
+
|
|
33
|
+
// Search the end of the block
|
|
34
|
+
//
|
|
35
|
+
// Block ends with either:
|
|
36
|
+
// 1. an empty line outside:
|
|
37
|
+
// ```
|
|
38
|
+
// > test
|
|
39
|
+
//
|
|
40
|
+
// ```
|
|
41
|
+
// 2. an empty line inside:
|
|
42
|
+
// ```
|
|
43
|
+
// >
|
|
44
|
+
// test
|
|
45
|
+
// ```
|
|
46
|
+
// 3. another tag:
|
|
47
|
+
// ```
|
|
48
|
+
// > test
|
|
49
|
+
// - - -
|
|
50
|
+
// ```
|
|
51
|
+
for (nextLine = startLine; nextLine < endLine; nextLine++) {
|
|
52
|
+
// check if it's outdented, i.e. it's inside list item and indented
|
|
53
|
+
// less than said list item:
|
|
54
|
+
//
|
|
55
|
+
// ```
|
|
56
|
+
// 1. anything
|
|
57
|
+
// > current blockquote
|
|
58
|
+
// 2. checking this line
|
|
59
|
+
// ```
|
|
60
|
+
const isOutdented = state.sCount[nextLine] < state.blkIndent
|
|
61
|
+
|
|
62
|
+
pos = state.bMarks[nextLine] + state.tShift[nextLine]
|
|
63
|
+
max = state.eMarks[nextLine]
|
|
64
|
+
|
|
65
|
+
if (pos >= max) {
|
|
66
|
+
// Case 1: line is not inside the blockquote, and this line is empty.
|
|
67
|
+
break
|
|
68
|
+
}
|
|
69
|
+
|
|
70
|
+
if (state.src.charCodeAt(pos++) === 0x3E/* > */ && !isOutdented) {
|
|
71
|
+
// This line is inside the blockquote.
|
|
72
|
+
|
|
73
|
+
// set offset past spaces and ">"
|
|
74
|
+
let initial = state.sCount[nextLine] + 1
|
|
75
|
+
let spaceAfterMarker
|
|
76
|
+
let adjustTab
|
|
77
|
+
|
|
78
|
+
// skip one optional space after '>'
|
|
79
|
+
if (state.src.charCodeAt(pos) === 0x20 /* space */) {
|
|
80
|
+
// ' > test '
|
|
81
|
+
// ^ -- position start of line here:
|
|
82
|
+
pos++
|
|
83
|
+
initial++
|
|
84
|
+
adjustTab = false
|
|
85
|
+
spaceAfterMarker = true
|
|
86
|
+
} else if (state.src.charCodeAt(pos) === 0x09 /* tab */) {
|
|
87
|
+
spaceAfterMarker = true
|
|
88
|
+
|
|
89
|
+
if ((state.bsCount[nextLine] + initial) % 4 === 3) {
|
|
90
|
+
// ' >\t test '
|
|
91
|
+
// ^ -- position start of line here (tab has width===1)
|
|
92
|
+
pos++
|
|
93
|
+
initial++
|
|
94
|
+
adjustTab = false
|
|
95
|
+
} else {
|
|
96
|
+
// ' >\t test '
|
|
97
|
+
// ^ -- position start of line here + shift bsCount slightly
|
|
98
|
+
// to make extra space appear
|
|
99
|
+
adjustTab = true
|
|
100
|
+
}
|
|
101
|
+
} else {
|
|
102
|
+
spaceAfterMarker = false
|
|
103
|
+
}
|
|
104
|
+
|
|
105
|
+
let offset = initial
|
|
106
|
+
oldBMarks.push(state.bMarks[nextLine])
|
|
107
|
+
state.bMarks[nextLine] = pos
|
|
108
|
+
|
|
109
|
+
while (pos < max) {
|
|
110
|
+
const ch = state.src.charCodeAt(pos)
|
|
111
|
+
|
|
112
|
+
if (isSpace(ch)) {
|
|
113
|
+
if (ch === 0x09) {
|
|
114
|
+
offset += 4 - (offset + state.bsCount[nextLine] + (adjustTab ? 1 : 0)) % 4
|
|
115
|
+
} else {
|
|
116
|
+
offset++
|
|
117
|
+
}
|
|
118
|
+
} else {
|
|
119
|
+
break
|
|
120
|
+
}
|
|
121
|
+
|
|
122
|
+
pos++
|
|
123
|
+
}
|
|
124
|
+
|
|
125
|
+
lastLineEmpty = pos >= max
|
|
126
|
+
|
|
127
|
+
oldBSCount.push(state.bsCount[nextLine])
|
|
128
|
+
state.bsCount[nextLine] = state.sCount[nextLine] + 1 + (spaceAfterMarker ? 1 : 0)
|
|
129
|
+
|
|
130
|
+
oldSCount.push(state.sCount[nextLine])
|
|
131
|
+
state.sCount[nextLine] = offset - initial
|
|
132
|
+
|
|
133
|
+
oldTShift.push(state.tShift[nextLine])
|
|
134
|
+
state.tShift[nextLine] = pos - state.bMarks[nextLine]
|
|
135
|
+
continue
|
|
136
|
+
}
|
|
137
|
+
|
|
138
|
+
// Case 2: line is not inside the blockquote, and the last line was empty.
|
|
139
|
+
if (lastLineEmpty) { break }
|
|
140
|
+
|
|
141
|
+
// Case 3: another tag found.
|
|
142
|
+
let terminate = false
|
|
143
|
+
for (let i = 0, l = terminatorRules.length; i < l; i++) {
|
|
144
|
+
if (terminatorRules[i](state, nextLine, endLine, true)) {
|
|
145
|
+
terminate = true
|
|
146
|
+
break
|
|
147
|
+
}
|
|
148
|
+
}
|
|
149
|
+
|
|
150
|
+
if (terminate) {
|
|
151
|
+
// Quirk to enforce "hard termination mode" for paragraphs;
|
|
152
|
+
// normally if you call `tokenize(state, startLine, nextLine)`,
|
|
153
|
+
// paragraphs will look below nextLine for paragraph continuation,
|
|
154
|
+
// but if blockquote is terminated by another tag, they shouldn't
|
|
155
|
+
state.lineMax = nextLine
|
|
156
|
+
|
|
157
|
+
if (state.blkIndent !== 0) {
|
|
158
|
+
// state.blkIndent was non-zero, we now set it to zero,
|
|
159
|
+
// so we need to re-calculate all offsets to appear as
|
|
160
|
+
// if indent wasn't changed
|
|
161
|
+
oldBMarks.push(state.bMarks[nextLine])
|
|
162
|
+
oldBSCount.push(state.bsCount[nextLine])
|
|
163
|
+
oldTShift.push(state.tShift[nextLine])
|
|
164
|
+
oldSCount.push(state.sCount[nextLine])
|
|
165
|
+
state.sCount[nextLine] -= state.blkIndent
|
|
166
|
+
}
|
|
167
|
+
|
|
168
|
+
break
|
|
169
|
+
}
|
|
170
|
+
|
|
171
|
+
oldBMarks.push(state.bMarks[nextLine])
|
|
172
|
+
oldBSCount.push(state.bsCount[nextLine])
|
|
173
|
+
oldTShift.push(state.tShift[nextLine])
|
|
174
|
+
oldSCount.push(state.sCount[nextLine])
|
|
175
|
+
|
|
176
|
+
// A negative indentation means that this is a paragraph continuation
|
|
177
|
+
//
|
|
178
|
+
state.sCount[nextLine] = -1
|
|
179
|
+
}
|
|
180
|
+
|
|
181
|
+
const oldIndent = state.blkIndent
|
|
182
|
+
state.blkIndent = 0
|
|
183
|
+
|
|
184
|
+
const token_o = state.push('blockquote_open', 'blockquote', 1)
|
|
185
|
+
token_o.markup = '>'
|
|
186
|
+
const lines = [startLine, 0]
|
|
187
|
+
token_o.map = lines
|
|
188
|
+
|
|
189
|
+
state.md.block.tokenize(state, startLine, nextLine)
|
|
190
|
+
|
|
191
|
+
const token_c = state.push('blockquote_close', 'blockquote', -1)
|
|
192
|
+
token_c.markup = '>'
|
|
193
|
+
|
|
194
|
+
state.lineMax = oldLineMax
|
|
195
|
+
state.parentType = oldParentType
|
|
196
|
+
lines[1] = state.line
|
|
197
|
+
|
|
198
|
+
// Restore original tShift; this might not be necessary since the parser
|
|
199
|
+
// has already been here, but just to make sure we can do that.
|
|
200
|
+
for (let i = 0; i < oldTShift.length; i++) {
|
|
201
|
+
state.bMarks[i + startLine] = oldBMarks[i]
|
|
202
|
+
state.tShift[i + startLine] = oldTShift[i]
|
|
203
|
+
state.sCount[i + startLine] = oldSCount[i]
|
|
204
|
+
state.bsCount[i + startLine] = oldBSCount[i]
|
|
205
|
+
}
|
|
206
|
+
state.blkIndent = oldIndent
|
|
207
|
+
|
|
208
|
+
return true
|
|
209
|
+
}
|
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
// Code block (4 spaces padded)
|
|
2
|
+
|
|
3
|
+
export default function code (state, startLine, endLine/*, silent */) {
|
|
4
|
+
if (state.sCount[startLine] - state.blkIndent < 4) { return false }
|
|
5
|
+
|
|
6
|
+
let nextLine = startLine + 1
|
|
7
|
+
let last = nextLine
|
|
8
|
+
|
|
9
|
+
while (nextLine < endLine) {
|
|
10
|
+
if (state.isEmpty(nextLine)) {
|
|
11
|
+
nextLine++
|
|
12
|
+
continue
|
|
13
|
+
}
|
|
14
|
+
|
|
15
|
+
if (state.sCount[nextLine] - state.blkIndent >= 4) {
|
|
16
|
+
nextLine++
|
|
17
|
+
last = nextLine
|
|
18
|
+
continue
|
|
19
|
+
}
|
|
20
|
+
break
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
state.line = last
|
|
24
|
+
|
|
25
|
+
const token = state.push('code_block', 'code', 0)
|
|
26
|
+
token.content = state.getLines(startLine, last, 4 + state.blkIndent, false) + '\n'
|
|
27
|
+
token.map = [startLine, state.line]
|
|
28
|
+
|
|
29
|
+
return true
|
|
30
|
+
}
|
|
@@ -0,0 +1,94 @@
|
|
|
1
|
+
// fences (``` lang, ~~~ lang)
|
|
2
|
+
|
|
3
|
+
export default function fence (state, startLine, endLine, silent) {
|
|
4
|
+
let pos = state.bMarks[startLine] + state.tShift[startLine]
|
|
5
|
+
let max = state.eMarks[startLine]
|
|
6
|
+
|
|
7
|
+
// if it's indented more than 3 spaces, it should be a code block
|
|
8
|
+
if (state.sCount[startLine] - state.blkIndent >= 4) { return false }
|
|
9
|
+
|
|
10
|
+
if (pos + 3 > max) { return false }
|
|
11
|
+
|
|
12
|
+
const marker = state.src.charCodeAt(pos)
|
|
13
|
+
|
|
14
|
+
if (marker !== 0x7E/* ~ */ && marker !== 0x60 /* ` */) {
|
|
15
|
+
return false
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
// scan marker length
|
|
19
|
+
let mem = pos
|
|
20
|
+
pos = state.skipChars(pos, marker)
|
|
21
|
+
|
|
22
|
+
let len = pos - mem
|
|
23
|
+
|
|
24
|
+
if (len < 3) { return false }
|
|
25
|
+
|
|
26
|
+
const markup = state.src.slice(mem, pos)
|
|
27
|
+
const params = state.src.slice(pos, max)
|
|
28
|
+
|
|
29
|
+
if (marker === 0x60 /* ` */) {
|
|
30
|
+
if (params.indexOf(String.fromCharCode(marker)) >= 0) {
|
|
31
|
+
return false
|
|
32
|
+
}
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
// Since start is found, we can report success here in validation mode
|
|
36
|
+
if (silent) { return true }
|
|
37
|
+
|
|
38
|
+
// search end of block
|
|
39
|
+
let nextLine = startLine
|
|
40
|
+
let haveEndMarker = false
|
|
41
|
+
|
|
42
|
+
for (;;) {
|
|
43
|
+
nextLine++
|
|
44
|
+
if (nextLine >= endLine) {
|
|
45
|
+
// unclosed block should be autoclosed by end of document.
|
|
46
|
+
// also block seems to be autoclosed by end of parent
|
|
47
|
+
break
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
pos = mem = state.bMarks[nextLine] + state.tShift[nextLine]
|
|
51
|
+
max = state.eMarks[nextLine]
|
|
52
|
+
|
|
53
|
+
if (pos < max && state.sCount[nextLine] < state.blkIndent) {
|
|
54
|
+
// non-empty line with negative indent should stop the list:
|
|
55
|
+
// - ```
|
|
56
|
+
// test
|
|
57
|
+
break
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
if (state.src.charCodeAt(pos) !== marker) { continue }
|
|
61
|
+
|
|
62
|
+
if (state.sCount[nextLine] - state.blkIndent >= 4) {
|
|
63
|
+
// closing fence should be indented less than 4 spaces
|
|
64
|
+
continue
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
pos = state.skipChars(pos, marker)
|
|
68
|
+
|
|
69
|
+
// closing code fence must be at least as long as the opening one
|
|
70
|
+
if (pos - mem < len) { continue }
|
|
71
|
+
|
|
72
|
+
// make sure tail has spaces only
|
|
73
|
+
pos = state.skipSpaces(pos)
|
|
74
|
+
|
|
75
|
+
if (pos < max) { continue }
|
|
76
|
+
|
|
77
|
+
haveEndMarker = true
|
|
78
|
+
// found!
|
|
79
|
+
break
|
|
80
|
+
}
|
|
81
|
+
|
|
82
|
+
// If a fence has heading spaces, they should be removed from its inner block
|
|
83
|
+
len = state.sCount[startLine]
|
|
84
|
+
|
|
85
|
+
state.line = nextLine + (haveEndMarker ? 1 : 0)
|
|
86
|
+
|
|
87
|
+
const token = state.push('fence', 'code', 0)
|
|
88
|
+
token.info = params
|
|
89
|
+
token.content = state.getLines(startLine + 1, nextLine, len, true)
|
|
90
|
+
token.markup = markup
|
|
91
|
+
token.map = [startLine, state.line]
|
|
92
|
+
|
|
93
|
+
return true
|
|
94
|
+
}
|
|
@@ -0,0 +1,51 @@
|
|
|
1
|
+
// heading (#, ##, ...)
|
|
2
|
+
|
|
3
|
+
import { isSpace } from '../common/utils.mjs'
|
|
4
|
+
|
|
5
|
+
export default function heading (state, startLine, endLine, silent) {
|
|
6
|
+
let pos = state.bMarks[startLine] + state.tShift[startLine]
|
|
7
|
+
let max = state.eMarks[startLine]
|
|
8
|
+
|
|
9
|
+
// if it's indented more than 3 spaces, it should be a code block
|
|
10
|
+
if (state.sCount[startLine] - state.blkIndent >= 4) { return false }
|
|
11
|
+
|
|
12
|
+
let ch = state.src.charCodeAt(pos)
|
|
13
|
+
|
|
14
|
+
if (ch !== 0x23/* # */ || pos >= max) { return false }
|
|
15
|
+
|
|
16
|
+
// count heading level
|
|
17
|
+
let level = 1
|
|
18
|
+
ch = state.src.charCodeAt(++pos)
|
|
19
|
+
while (ch === 0x23/* # */ && pos < max && level <= 6) {
|
|
20
|
+
level++
|
|
21
|
+
ch = state.src.charCodeAt(++pos)
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
if (level > 6 || (pos < max && !isSpace(ch))) { return false }
|
|
25
|
+
|
|
26
|
+
if (silent) { return true }
|
|
27
|
+
|
|
28
|
+
// Let's cut tails like ' ### ' from the end of string
|
|
29
|
+
|
|
30
|
+
max = state.skipSpacesBack(max, pos)
|
|
31
|
+
const tmp = state.skipCharsBack(max, 0x23, pos) // #
|
|
32
|
+
if (tmp > pos && isSpace(state.src.charCodeAt(tmp - 1))) {
|
|
33
|
+
max = tmp
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
state.line = startLine + 1
|
|
37
|
+
|
|
38
|
+
const token_o = state.push('heading_open', 'h' + String(level), 1)
|
|
39
|
+
token_o.markup = '########'.slice(0, level)
|
|
40
|
+
token_o.map = [startLine, state.line]
|
|
41
|
+
|
|
42
|
+
const token_i = state.push('inline', '', 0)
|
|
43
|
+
token_i.content = state.src.slice(pos, max).trim()
|
|
44
|
+
token_i.map = [startLine, state.line]
|
|
45
|
+
token_i.children = []
|
|
46
|
+
|
|
47
|
+
const token_c = state.push('heading_close', 'h' + String(level), -1)
|
|
48
|
+
token_c.markup = '########'.slice(0, level)
|
|
49
|
+
|
|
50
|
+
return true
|
|
51
|
+
}
|
|
@@ -0,0 +1,40 @@
|
|
|
1
|
+
// Horizontal rule
|
|
2
|
+
|
|
3
|
+
import { isSpace } from '../common/utils.mjs'
|
|
4
|
+
|
|
5
|
+
export default function hr (state, startLine, endLine, silent) {
|
|
6
|
+
const max = state.eMarks[startLine]
|
|
7
|
+
// if it's indented more than 3 spaces, it should be a code block
|
|
8
|
+
if (state.sCount[startLine] - state.blkIndent >= 4) { return false }
|
|
9
|
+
|
|
10
|
+
let pos = state.bMarks[startLine] + state.tShift[startLine]
|
|
11
|
+
const marker = state.src.charCodeAt(pos++)
|
|
12
|
+
|
|
13
|
+
// Check hr marker
|
|
14
|
+
if (marker !== 0x2A/* * */ &&
|
|
15
|
+
marker !== 0x2D/* - */ &&
|
|
16
|
+
marker !== 0x5F/* _ */) {
|
|
17
|
+
return false
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
// markers can be mixed with spaces, but there should be at least 3 of them
|
|
21
|
+
|
|
22
|
+
let cnt = 1
|
|
23
|
+
while (pos < max) {
|
|
24
|
+
const ch = state.src.charCodeAt(pos++)
|
|
25
|
+
if (ch !== marker && !isSpace(ch)) { return false }
|
|
26
|
+
if (ch === marker) { cnt++ }
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
if (cnt < 3) { return false }
|
|
30
|
+
|
|
31
|
+
if (silent) { return true }
|
|
32
|
+
|
|
33
|
+
state.line = startLine + 1
|
|
34
|
+
|
|
35
|
+
const token = state.push('hr', 'hr', 0)
|
|
36
|
+
token.map = [startLine, state.line]
|
|
37
|
+
token.markup = Array(cnt + 1).join(String.fromCharCode(marker))
|
|
38
|
+
|
|
39
|
+
return true
|
|
40
|
+
}
|
|
@@ -0,0 +1,69 @@
|
|
|
1
|
+
// HTML block
|
|
2
|
+
|
|
3
|
+
import block_names from '../common/html_blocks.mjs'
|
|
4
|
+
import { HTML_OPEN_CLOSE_TAG_RE } from '../common/html_re.mjs'
|
|
5
|
+
|
|
6
|
+
// An array of opening and corresponding closing sequences for html tags,
|
|
7
|
+
// last argument defines whether it can terminate a paragraph or not
|
|
8
|
+
//
|
|
9
|
+
const HTML_SEQUENCES = [
|
|
10
|
+
[/^<(script|pre|style|textarea)(?=(\s|>|$))/i, /<\/(script|pre|style|textarea)>/i, true],
|
|
11
|
+
[/^<!--/, /-->/, true],
|
|
12
|
+
[/^<\?/, /\?>/, true],
|
|
13
|
+
[/^<![A-Z]/, />/, true],
|
|
14
|
+
[/^<!\[CDATA\[/, /\]\]>/, true],
|
|
15
|
+
[new RegExp('^</?(' + block_names.join('|') + ')(?=(\\s|/?>|$))', 'i'), /^$/, true],
|
|
16
|
+
[new RegExp(HTML_OPEN_CLOSE_TAG_RE.source + '\\s*$'), /^$/, false]
|
|
17
|
+
]
|
|
18
|
+
|
|
19
|
+
export default function html_block (state, startLine, endLine, silent) {
|
|
20
|
+
let pos = state.bMarks[startLine] + state.tShift[startLine]
|
|
21
|
+
let max = state.eMarks[startLine]
|
|
22
|
+
|
|
23
|
+
// if it's indented more than 3 spaces, it should be a code block
|
|
24
|
+
if (state.sCount[startLine] - state.blkIndent >= 4) { return false }
|
|
25
|
+
|
|
26
|
+
if (!state.md.options.html) { return false }
|
|
27
|
+
|
|
28
|
+
if (state.src.charCodeAt(pos) !== 0x3C/* < */) { return false }
|
|
29
|
+
|
|
30
|
+
let lineText = state.src.slice(pos, max)
|
|
31
|
+
|
|
32
|
+
let i = 0
|
|
33
|
+
for (; i < HTML_SEQUENCES.length; i++) {
|
|
34
|
+
if (HTML_SEQUENCES[i][0].test(lineText)) { break }
|
|
35
|
+
}
|
|
36
|
+
if (i === HTML_SEQUENCES.length) { return false }
|
|
37
|
+
|
|
38
|
+
if (silent) {
|
|
39
|
+
// true if this sequence can be a terminator, false otherwise
|
|
40
|
+
return HTML_SEQUENCES[i][2]
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
let nextLine = startLine + 1
|
|
44
|
+
|
|
45
|
+
// If we are here - we detected HTML block.
|
|
46
|
+
// Let's roll down till block end.
|
|
47
|
+
if (!HTML_SEQUENCES[i][1].test(lineText)) {
|
|
48
|
+
for (; nextLine < endLine; nextLine++) {
|
|
49
|
+
if (state.sCount[nextLine] < state.blkIndent) { break }
|
|
50
|
+
|
|
51
|
+
pos = state.bMarks[nextLine] + state.tShift[nextLine]
|
|
52
|
+
max = state.eMarks[nextLine]
|
|
53
|
+
lineText = state.src.slice(pos, max)
|
|
54
|
+
|
|
55
|
+
if (HTML_SEQUENCES[i][1].test(lineText)) {
|
|
56
|
+
if (lineText.length !== 0) { nextLine++ }
|
|
57
|
+
break
|
|
58
|
+
}
|
|
59
|
+
}
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
state.line = nextLine
|
|
63
|
+
|
|
64
|
+
const token = state.push('html_block', '', 0)
|
|
65
|
+
token.map = [startLine, nextLine]
|
|
66
|
+
token.content = state.getLines(startLine, nextLine, state.blkIndent, true)
|
|
67
|
+
|
|
68
|
+
return true
|
|
69
|
+
}
|
|
@@ -0,0 +1,82 @@
|
|
|
1
|
+
// lheading (---, ===)
|
|
2
|
+
|
|
3
|
+
export default function lheading (state, startLine, endLine/*, silent */) {
|
|
4
|
+
const terminatorRules = state.md.block.ruler.getRules('paragraph')
|
|
5
|
+
|
|
6
|
+
// if it's indented more than 3 spaces, it should be a code block
|
|
7
|
+
if (state.sCount[startLine] - state.blkIndent >= 4) { return false }
|
|
8
|
+
|
|
9
|
+
const oldParentType = state.parentType
|
|
10
|
+
state.parentType = 'paragraph' // use paragraph to match terminatorRules
|
|
11
|
+
|
|
12
|
+
// jump line-by-line until empty one or EOF
|
|
13
|
+
let level = 0
|
|
14
|
+
let marker
|
|
15
|
+
let nextLine = startLine + 1
|
|
16
|
+
|
|
17
|
+
for (; nextLine < endLine && !state.isEmpty(nextLine); nextLine++) {
|
|
18
|
+
// this would be a code block normally, but after paragraph
|
|
19
|
+
// it's considered a lazy continuation regardless of what's there
|
|
20
|
+
if (state.sCount[nextLine] - state.blkIndent > 3) { continue }
|
|
21
|
+
|
|
22
|
+
//
|
|
23
|
+
// Check for underline in setext header
|
|
24
|
+
//
|
|
25
|
+
if (state.sCount[nextLine] >= state.blkIndent) {
|
|
26
|
+
let pos = state.bMarks[nextLine] + state.tShift[nextLine]
|
|
27
|
+
const max = state.eMarks[nextLine]
|
|
28
|
+
|
|
29
|
+
if (pos < max) {
|
|
30
|
+
marker = state.src.charCodeAt(pos)
|
|
31
|
+
|
|
32
|
+
if (marker === 0x2D/* - */ || marker === 0x3D/* = */) {
|
|
33
|
+
pos = state.skipChars(pos, marker)
|
|
34
|
+
pos = state.skipSpaces(pos)
|
|
35
|
+
|
|
36
|
+
if (pos >= max) {
|
|
37
|
+
level = (marker === 0x3D/* = */ ? 1 : 2)
|
|
38
|
+
break
|
|
39
|
+
}
|
|
40
|
+
}
|
|
41
|
+
}
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
// quirk for blockquotes, this line should already be checked by that rule
|
|
45
|
+
if (state.sCount[nextLine] < 0) { continue }
|
|
46
|
+
|
|
47
|
+
// Some tags can terminate paragraph without empty line.
|
|
48
|
+
let terminate = false
|
|
49
|
+
for (let i = 0, l = terminatorRules.length; i < l; i++) {
|
|
50
|
+
if (terminatorRules[i](state, nextLine, endLine, true)) {
|
|
51
|
+
terminate = true
|
|
52
|
+
break
|
|
53
|
+
}
|
|
54
|
+
}
|
|
55
|
+
if (terminate) { break }
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
if (!level) {
|
|
59
|
+
// Didn't find valid underline
|
|
60
|
+
return false
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
const content = state.getLines(startLine, nextLine, state.blkIndent, false).trim()
|
|
64
|
+
|
|
65
|
+
state.line = nextLine + 1
|
|
66
|
+
|
|
67
|
+
const token_o = state.push('heading_open', 'h' + String(level), 1)
|
|
68
|
+
token_o.markup = String.fromCharCode(marker)
|
|
69
|
+
token_o.map = [startLine, state.line]
|
|
70
|
+
|
|
71
|
+
const token_i = state.push('inline', '', 0)
|
|
72
|
+
token_i.content = content
|
|
73
|
+
token_i.map = [startLine, state.line - 1]
|
|
74
|
+
token_i.children = []
|
|
75
|
+
|
|
76
|
+
const token_c = state.push('heading_close', 'h' + String(level), -1)
|
|
77
|
+
token_c.markup = String.fromCharCode(marker)
|
|
78
|
+
|
|
79
|
+
state.parentType = oldParentType
|
|
80
|
+
|
|
81
|
+
return true
|
|
82
|
+
}
|