@peaceroad/markdown-it-strong-ja 0.7.1 → 0.8.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.
- package/README.md +314 -195
- package/index.js +18 -48
- package/package.json +23 -5
- package/src/token-compat.js +108 -46
- package/src/token-core.js +467 -92
- package/src/token-link-utils.js +104 -400
- package/src/token-postprocess/fastpaths.js +349 -0
- package/src/token-postprocess/guards.js +436 -0
- package/src/token-postprocess/orchestrator.js +733 -0
- package/src/token-postprocess.js +1 -340
- package/src/token-utils.js +192 -148
package/src/token-link-utils.js
CHANGED
|
@@ -1,23 +1,33 @@
|
|
|
1
1
|
import Token from 'markdown-it/lib/token.mjs'
|
|
2
|
-
import {
|
|
3
|
-
import { isSpace, isWhiteSpace } from 'markdown-it/lib/common/utils.mjs'
|
|
2
|
+
import { isWhiteSpace } from 'markdown-it/lib/common/utils.mjs'
|
|
4
3
|
|
|
5
4
|
const CHAR_OPEN_BRACKET = 0x5B // [
|
|
6
5
|
const CHAR_CLOSE_BRACKET = 0x5D // ]
|
|
7
|
-
const CHAR_OPEN_PAREN = 0x28 // (
|
|
8
|
-
const CHAR_CLOSE_PAREN = 0x29 // )
|
|
9
6
|
|
|
10
7
|
const isWhitespaceToken = (token) => {
|
|
11
8
|
if (!token || token.type !== 'text') return false
|
|
12
9
|
const content = token.content
|
|
13
|
-
if (
|
|
10
|
+
if (token.__strongJaWhitespaceSource === content &&
|
|
11
|
+
typeof token.__strongJaIsWhitespace === 'boolean') {
|
|
12
|
+
return token.__strongJaIsWhitespace
|
|
13
|
+
}
|
|
14
|
+
if (!content) {
|
|
15
|
+
token.__strongJaWhitespaceSource = content
|
|
16
|
+
token.__strongJaIsWhitespace = true
|
|
17
|
+
return true
|
|
18
|
+
}
|
|
19
|
+
let isWhitespace = true
|
|
14
20
|
for (let i = 0; i < content.length; i++) {
|
|
15
|
-
if (!isWhiteSpace(content.charCodeAt(i)))
|
|
21
|
+
if (!isWhiteSpace(content.charCodeAt(i))) {
|
|
22
|
+
isWhitespace = false
|
|
23
|
+
break
|
|
24
|
+
}
|
|
16
25
|
}
|
|
17
|
-
|
|
26
|
+
token.__strongJaWhitespaceSource = content
|
|
27
|
+
token.__strongJaIsWhitespace = isWhitespace
|
|
28
|
+
return isWhitespace
|
|
18
29
|
}
|
|
19
30
|
|
|
20
|
-
// Collapsed reference helpers
|
|
21
31
|
const buildReferenceLabelRange = (tokens, startIdx, endIdx) => {
|
|
22
32
|
if (startIdx > endIdx) return ''
|
|
23
33
|
let label = ''
|
|
@@ -28,23 +38,15 @@ const buildReferenceLabelRange = (tokens, startIdx, endIdx) => {
|
|
|
28
38
|
label += token.content
|
|
29
39
|
} else if (token.type === 'softbreak' || token.type === 'hardbreak') {
|
|
30
40
|
label += ' '
|
|
31
|
-
} else if (token.type && token.type.endsWith('_open')
|
|
32
|
-
label += token.markup
|
|
33
|
-
} else if (token.type && token.type.endsWith('_close') && token.markup) {
|
|
41
|
+
} else if (token.type && token.markup && (token.type.endsWith('_open') || token.type.endsWith('_close'))) {
|
|
34
42
|
label += token.markup
|
|
35
43
|
}
|
|
36
44
|
}
|
|
37
45
|
return label
|
|
38
46
|
}
|
|
39
47
|
|
|
40
|
-
const
|
|
41
|
-
|
|
42
|
-
return label.replace(/^[*_]+/, '').replace(/[*_]+$/, '')
|
|
43
|
-
}
|
|
44
|
-
|
|
45
|
-
const normalizeReferenceCandidate = (state, text, { useClean = false } = {}) => {
|
|
46
|
-
const source = useClean ? cleanLabelText(text) : text
|
|
47
|
-
return normalizeRefKey(state, source)
|
|
48
|
+
const normalizeReferenceCandidate = (state, text) => {
|
|
49
|
+
return getNormalizeRef(state)(text)
|
|
48
50
|
}
|
|
49
51
|
|
|
50
52
|
const getNormalizeRef = (state) => {
|
|
@@ -56,10 +58,6 @@ const getNormalizeRef = (state) => {
|
|
|
56
58
|
return normalize
|
|
57
59
|
}
|
|
58
60
|
|
|
59
|
-
const normalizeRefKey = (state, label) => {
|
|
60
|
-
return getNormalizeRef(state)(label)
|
|
61
|
-
}
|
|
62
|
-
|
|
63
61
|
const adjustTokenLevels = (tokens, startIdx, endIdx, delta) => {
|
|
64
62
|
for (let i = startIdx; i < endIdx; i++) {
|
|
65
63
|
if (tokens[i]) tokens[i].level += delta
|
|
@@ -102,12 +100,23 @@ const cloneTextToken = (source, content) => {
|
|
|
102
100
|
Object.assign(newToken, source)
|
|
103
101
|
newToken.content = content
|
|
104
102
|
if (source.meta) newToken.meta = { ...source.meta }
|
|
105
|
-
if (source.map) newToken.map = source.map
|
|
106
103
|
return newToken
|
|
107
104
|
}
|
|
108
105
|
|
|
109
|
-
|
|
110
|
-
|
|
106
|
+
const applyBracketSegmentFlags = (token, seg) => {
|
|
107
|
+
if (seg === '[' || seg === ']') {
|
|
108
|
+
token.__strongJaHasBracket = true
|
|
109
|
+
token.__strongJaBracketAtomic = true
|
|
110
|
+
} else if (seg === '[]') {
|
|
111
|
+
token.__strongJaHasBracket = true
|
|
112
|
+
token.__strongJaBracketAtomic = false
|
|
113
|
+
} else {
|
|
114
|
+
token.__strongJaHasBracket = false
|
|
115
|
+
token.__strongJaBracketAtomic = false
|
|
116
|
+
}
|
|
117
|
+
}
|
|
118
|
+
|
|
119
|
+
const splitBracketToken = (tokens, index) => {
|
|
111
120
|
const token = tokens[index]
|
|
112
121
|
if (!token || token.type !== 'text') return false
|
|
113
122
|
if (token.__strongJaBracketAtomic) return false
|
|
@@ -126,82 +135,49 @@ const splitBracketToken = (tokens, index, options) => {
|
|
|
126
135
|
}
|
|
127
136
|
token.__strongJaHasBracket = true
|
|
128
137
|
}
|
|
129
|
-
const splitEmptyPair = options && options.splitEmptyPair
|
|
130
138
|
const segments = []
|
|
131
|
-
|
|
139
|
+
const contentLen = content.length
|
|
132
140
|
let pos = 0
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
141
|
+
let segmentStart = 0
|
|
142
|
+
while (pos < contentLen) {
|
|
143
|
+
const code = content.charCodeAt(pos)
|
|
144
|
+
if (code === CHAR_OPEN_BRACKET &&
|
|
136
145
|
content.charCodeAt(pos + 1) === CHAR_CLOSE_BRACKET) {
|
|
137
|
-
if (
|
|
138
|
-
segments.push(
|
|
139
|
-
buffer = ''
|
|
146
|
+
if (segmentStart < pos) {
|
|
147
|
+
segments.push(content.slice(segmentStart, pos))
|
|
140
148
|
}
|
|
141
149
|
segments.push('[]')
|
|
142
150
|
pos += 2
|
|
151
|
+
segmentStart = pos
|
|
143
152
|
continue
|
|
144
153
|
}
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
segments.push(buffer)
|
|
149
|
-
buffer = ''
|
|
154
|
+
if (code === CHAR_OPEN_BRACKET || code === CHAR_CLOSE_BRACKET) {
|
|
155
|
+
if (segmentStart < pos) {
|
|
156
|
+
segments.push(content.slice(segmentStart, pos))
|
|
150
157
|
}
|
|
151
|
-
segments.push(
|
|
158
|
+
segments.push(code === CHAR_OPEN_BRACKET ? '[' : ']')
|
|
152
159
|
pos++
|
|
160
|
+
segmentStart = pos
|
|
153
161
|
continue
|
|
154
162
|
}
|
|
155
|
-
buffer += ch
|
|
156
163
|
pos++
|
|
157
164
|
}
|
|
158
|
-
if (
|
|
165
|
+
if (segmentStart < contentLen) segments.push(content.slice(segmentStart))
|
|
159
166
|
if (segments.length <= 1) {
|
|
160
|
-
|
|
161
|
-
token.__strongJaHasBracket = false
|
|
162
|
-
token.__strongJaBracketAtomic = false
|
|
163
|
-
} else {
|
|
164
|
-
const seg = segments[0]
|
|
165
|
-
if (seg === '[' || seg === ']') {
|
|
166
|
-
token.__strongJaHasBracket = true
|
|
167
|
-
token.__strongJaBracketAtomic = true
|
|
168
|
-
} else if (seg === '[]') {
|
|
169
|
-
token.__strongJaHasBracket = true
|
|
170
|
-
token.__strongJaBracketAtomic = false
|
|
171
|
-
} else {
|
|
172
|
-
token.__strongJaHasBracket = false
|
|
173
|
-
token.__strongJaBracketAtomic = false
|
|
174
|
-
}
|
|
175
|
-
}
|
|
167
|
+
applyBracketSegmentFlags(token, segments[0])
|
|
176
168
|
return false
|
|
177
169
|
}
|
|
170
|
+
|
|
178
171
|
token.content = segments[0]
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
} else if (token.content === '[]') {
|
|
183
|
-
token.__strongJaHasBracket = true
|
|
184
|
-
token.__strongJaBracketAtomic = false
|
|
185
|
-
} else {
|
|
186
|
-
token.__strongJaHasBracket = false
|
|
187
|
-
token.__strongJaBracketAtomic = false
|
|
188
|
-
}
|
|
189
|
-
let insertIdx = index + 1
|
|
172
|
+
applyBracketSegmentFlags(token, token.content)
|
|
173
|
+
|
|
174
|
+
const replacements = [token]
|
|
190
175
|
for (let s = 1; s < segments.length; s++) {
|
|
191
176
|
const newToken = cloneTextToken(token, segments[s])
|
|
192
|
-
|
|
193
|
-
|
|
194
|
-
newToken.__strongJaBracketAtomic = true
|
|
195
|
-
} else if (segments[s] === '[]') {
|
|
196
|
-
newToken.__strongJaHasBracket = true
|
|
197
|
-
newToken.__strongJaBracketAtomic = false
|
|
198
|
-
} else {
|
|
199
|
-
newToken.__strongJaHasBracket = false
|
|
200
|
-
newToken.__strongJaBracketAtomic = false
|
|
201
|
-
}
|
|
202
|
-
tokens.splice(insertIdx, 0, newToken)
|
|
203
|
-
insertIdx++
|
|
177
|
+
applyBracketSegmentFlags(newToken, segments[s])
|
|
178
|
+
replacements.push(newToken)
|
|
204
179
|
}
|
|
180
|
+
tokens.splice(index, 1, ...replacements)
|
|
205
181
|
return true
|
|
206
182
|
}
|
|
207
183
|
|
|
@@ -209,40 +185,26 @@ const isBracketToken = (token, bracket) => {
|
|
|
209
185
|
return token && token.type === 'text' && token.content === bracket
|
|
210
186
|
}
|
|
211
187
|
|
|
212
|
-
const
|
|
213
|
-
|
|
214
|
-
|
|
215
|
-
|
|
216
|
-
|
|
217
|
-
|
|
218
|
-
|
|
219
|
-
|
|
220
|
-
|
|
221
|
-
|
|
222
|
-
|
|
223
|
-
}
|
|
224
|
-
|
|
225
|
-
const consumeCharactersFromTokens = (tokens, startIdx, count) => {
|
|
226
|
-
let remaining = count
|
|
227
|
-
let idx = startIdx
|
|
228
|
-
while (idx < tokens.length && remaining > 0) {
|
|
229
|
-
const token = tokens[idx]
|
|
230
|
-
if (!token || token.type !== 'text') {
|
|
231
|
-
return false
|
|
232
|
-
}
|
|
233
|
-
const len = token.content.length
|
|
234
|
-
if (remaining >= len) {
|
|
235
|
-
remaining -= len
|
|
236
|
-
tokens.splice(idx, 1)
|
|
188
|
+
const buildLinkCloseMap = (tokens, startIdx, endIdx) => {
|
|
189
|
+
const closeMap = new Map()
|
|
190
|
+
const stack = []
|
|
191
|
+
const max = tokens ? tokens.length - 1 : -1
|
|
192
|
+
const from = startIdx > 0 ? startIdx : 0
|
|
193
|
+
const to = endIdx < max ? endIdx : max
|
|
194
|
+
for (let i = from; i <= to; i++) {
|
|
195
|
+
const token = tokens[i]
|
|
196
|
+
if (!token) continue
|
|
197
|
+
if (token.type === 'link_open') {
|
|
198
|
+
stack.push(i)
|
|
237
199
|
continue
|
|
238
200
|
}
|
|
239
|
-
token.
|
|
240
|
-
|
|
201
|
+
if (token.type !== 'link_close' || stack.length === 0) continue
|
|
202
|
+
closeMap.set(stack.pop(), i)
|
|
241
203
|
}
|
|
242
|
-
return
|
|
204
|
+
return closeMap
|
|
243
205
|
}
|
|
244
206
|
|
|
245
|
-
const wrapLabelTokensWithLink = (tokens, labelStartIdx, labelEndIdx, linkOpenToken, linkCloseToken
|
|
207
|
+
const wrapLabelTokensWithLink = (tokens, labelStartIdx, labelEndIdx, linkOpenToken, linkCloseToken) => {
|
|
246
208
|
const wrapperPairs = []
|
|
247
209
|
let startIdx = labelStartIdx
|
|
248
210
|
let endIdx = labelEndIdx
|
|
@@ -250,7 +212,7 @@ const wrapLabelTokensWithLink = (tokens, labelStartIdx, labelEndIdx, linkOpenTok
|
|
|
250
212
|
const prevToken = tokens[startIdx - 1]
|
|
251
213
|
const nextToken = tokens[endIdx + 1]
|
|
252
214
|
if (!prevToken || !nextToken) break
|
|
253
|
-
if (
|
|
215
|
+
if (!prevToken.type || !prevToken.type.endsWith('_close')) break
|
|
254
216
|
const expectedOpen = prevToken.type.replace('_close', '_open')
|
|
255
217
|
if (nextToken.type !== expectedOpen) break
|
|
256
218
|
wrapperPairs.push({
|
|
@@ -266,17 +228,7 @@ const wrapLabelTokensWithLink = (tokens, labelStartIdx, labelEndIdx, linkOpenTok
|
|
|
266
228
|
endIdx -= 1
|
|
267
229
|
}
|
|
268
230
|
|
|
269
|
-
if (startIdx > endIdx)
|
|
270
|
-
if (labelSource !== undefined && labelSource !== null) {
|
|
271
|
-
const placeholder = new Token('text', '', 0)
|
|
272
|
-
placeholder.content = labelSource
|
|
273
|
-
placeholder.level = linkOpenToken.level + 1
|
|
274
|
-
tokens.splice(startIdx, 0, placeholder)
|
|
275
|
-
endIdx = startIdx
|
|
276
|
-
} else {
|
|
277
|
-
return startIdx
|
|
278
|
-
}
|
|
279
|
-
}
|
|
231
|
+
if (startIdx > endIdx) return startIdx
|
|
280
232
|
|
|
281
233
|
let labelLength = endIdx - startIdx + 1
|
|
282
234
|
const firstLabelToken = tokens[startIdx]
|
|
@@ -320,282 +272,23 @@ const wrapLabelTokensWithLink = (tokens, labelStartIdx, labelEndIdx, linkOpenTok
|
|
|
320
272
|
return startIdx + labelLength + 2
|
|
321
273
|
}
|
|
322
274
|
|
|
323
|
-
const parseInlineLinkTail = (content, md) => {
|
|
324
|
-
if (!content || content.charCodeAt(0) !== CHAR_OPEN_PAREN) return null
|
|
325
|
-
const max = content.length
|
|
326
|
-
let pos = 1
|
|
327
|
-
while (pos < max) {
|
|
328
|
-
const code = content.charCodeAt(pos)
|
|
329
|
-
if (!isSpace(code) && code !== 0x0A) break
|
|
330
|
-
pos++
|
|
331
|
-
}
|
|
332
|
-
if (pos >= max) return null
|
|
333
|
-
|
|
334
|
-
let href = ''
|
|
335
|
-
let destPos = pos
|
|
336
|
-
if (pos < max && content.charCodeAt(pos) === CHAR_CLOSE_PAREN) {
|
|
337
|
-
href = ''
|
|
338
|
-
} else {
|
|
339
|
-
const dest = parseLinkDestination(content, pos, max)
|
|
340
|
-
if (!dest.ok) return null
|
|
341
|
-
href = md.normalizeLink(dest.str)
|
|
342
|
-
if (!md.validateLink(href)) {
|
|
343
|
-
return null
|
|
344
|
-
}
|
|
345
|
-
pos = dest.pos
|
|
346
|
-
destPos = dest.pos
|
|
347
|
-
}
|
|
348
|
-
|
|
349
|
-
while (pos < max) {
|
|
350
|
-
const code = content.charCodeAt(pos)
|
|
351
|
-
if (!isSpace(code) && code !== 0x0A) break
|
|
352
|
-
pos++
|
|
353
|
-
}
|
|
354
|
-
|
|
355
|
-
let title = ''
|
|
356
|
-
const titleRes = parseLinkTitle(content, pos, max)
|
|
357
|
-
if (pos < max && pos !== destPos && titleRes.ok) {
|
|
358
|
-
title = titleRes.str
|
|
359
|
-
pos = titleRes.pos
|
|
360
|
-
while (pos < max) {
|
|
361
|
-
const code = content.charCodeAt(pos)
|
|
362
|
-
if (!isSpace(code) && code !== 0x0A) break
|
|
363
|
-
pos++
|
|
364
|
-
}
|
|
365
|
-
}
|
|
366
|
-
|
|
367
|
-
if (pos >= max || content.charCodeAt(pos) !== CHAR_CLOSE_PAREN) {
|
|
368
|
-
return null
|
|
369
|
-
}
|
|
370
|
-
pos++
|
|
371
|
-
return { href, title, consumed: pos }
|
|
372
|
-
}
|
|
373
|
-
|
|
374
|
-
const INLINE_LINK_BRACKET_SPLIT_OPTIONS = { splitEmptyPair: true }
|
|
375
|
-
|
|
376
|
-
const removeGhostLabelText = (tokens, linkCloseIndex, labelText) => {
|
|
377
|
-
if (!labelText) return
|
|
378
|
-
if (linkCloseIndex === null || linkCloseIndex === undefined) return
|
|
379
|
-
if (linkCloseIndex < 0 || linkCloseIndex >= tokens.length) return
|
|
380
|
-
const closeToken = tokens[linkCloseIndex]
|
|
381
|
-
if (!closeToken || closeToken.type !== 'link_close') return
|
|
382
|
-
let idx = linkCloseIndex + 1
|
|
383
|
-
while (idx < tokens.length) {
|
|
384
|
-
const token = tokens[idx]
|
|
385
|
-
if (!token) {
|
|
386
|
-
idx++
|
|
387
|
-
continue
|
|
388
|
-
}
|
|
389
|
-
if (token.type === 'text') {
|
|
390
|
-
if (token.content.startsWith(labelText)) {
|
|
391
|
-
if (token.content.length === labelText.length) {
|
|
392
|
-
tokens.splice(idx, 1)
|
|
393
|
-
} else {
|
|
394
|
-
token.content = token.content.slice(labelText.length)
|
|
395
|
-
}
|
|
396
|
-
}
|
|
397
|
-
break
|
|
398
|
-
}
|
|
399
|
-
if (!/_close$/.test(token.type)) {
|
|
400
|
-
break
|
|
401
|
-
}
|
|
402
|
-
idx++
|
|
403
|
-
}
|
|
404
|
-
}
|
|
405
|
-
|
|
406
|
-
const restoreLabelWhitespace = (tokens, labelSources) => {
|
|
407
|
-
if (!tokens || !labelSources || labelSources.length === 0) return
|
|
408
|
-
let labelIdx = 0
|
|
409
|
-
for (let i = 0; i < tokens.length && labelIdx < labelSources.length; i++) {
|
|
410
|
-
if (tokens[i].type !== 'link_open') continue
|
|
411
|
-
const closeIdx = findLinkCloseIndex(tokens, i)
|
|
412
|
-
if (closeIdx === -1) continue
|
|
413
|
-
const labelSource = labelSources[labelIdx] || ''
|
|
414
|
-
if (!labelSource) {
|
|
415
|
-
labelIdx++
|
|
416
|
-
continue
|
|
417
|
-
}
|
|
418
|
-
let cursor = 0
|
|
419
|
-
for (let pos = i + 1; pos < closeIdx; pos++) {
|
|
420
|
-
const t = tokens[pos]
|
|
421
|
-
const markup = t.markup || ''
|
|
422
|
-
const text = t.content || ''
|
|
423
|
-
const startPos = cursor
|
|
424
|
-
if (t.type === 'text') {
|
|
425
|
-
cursor += text.length
|
|
426
|
-
} else if (t.type === 'code_inline') {
|
|
427
|
-
cursor += markup.length + text.length + markup.length
|
|
428
|
-
} else if (markup) {
|
|
429
|
-
cursor += markup.length
|
|
430
|
-
}
|
|
431
|
-
if ((t.type === 'strong_open' || t.type === 'em_open') && startPos > 0) {
|
|
432
|
-
const prevToken = tokens[pos - 1]
|
|
433
|
-
if (prevToken && prevToken.type === 'text' && prevToken.content && !prevToken.content.endsWith(' ')) {
|
|
434
|
-
const hasSpaceBefore = startPos - 1 >= 0 && startPos - 1 < labelSource.length && labelSource[startPos - 1] === ' '
|
|
435
|
-
const hasSpaceAt = startPos >= 0 && startPos < labelSource.length && labelSource[startPos] === ' '
|
|
436
|
-
if (hasSpaceBefore || hasSpaceAt) {
|
|
437
|
-
prevToken.content += ' '
|
|
438
|
-
}
|
|
439
|
-
}
|
|
440
|
-
}
|
|
441
|
-
}
|
|
442
|
-
labelIdx++
|
|
443
|
-
}
|
|
444
|
-
}
|
|
445
|
-
|
|
446
|
-
const convertInlineLinks = (tokens, state) => {
|
|
447
|
-
if (!tokens || tokens.length === 0) return
|
|
448
|
-
let labelSources = tokens.__strongJaInlineLabelSources
|
|
449
|
-
if ((!labelSources || labelSources.length === 0) && state && state.env && Array.isArray(state.env.__strongJaInlineLabelSourceList) && state.env.__strongJaInlineLabelSourceList.length > 0) {
|
|
450
|
-
labelSources = state.env.__strongJaInlineLabelSourceList.shift()
|
|
451
|
-
}
|
|
452
|
-
let labelSourceIndex = tokens.__strongJaInlineLabelIndex || 0
|
|
453
|
-
let i = 0
|
|
454
|
-
while (i < tokens.length) {
|
|
455
|
-
if (splitBracketToken(tokens, i, INLINE_LINK_BRACKET_SPLIT_OPTIONS)) {
|
|
456
|
-
continue
|
|
457
|
-
}
|
|
458
|
-
if (!isBracketToken(tokens[i], '[')) {
|
|
459
|
-
i++
|
|
460
|
-
continue
|
|
461
|
-
}
|
|
462
|
-
let closeIdx = i + 1
|
|
463
|
-
let invalid = false
|
|
464
|
-
while (closeIdx < tokens.length && !isBracketToken(tokens[closeIdx], ']')) {
|
|
465
|
-
if (splitBracketToken(tokens, closeIdx, INLINE_LINK_BRACKET_SPLIT_OPTIONS)) {
|
|
466
|
-
continue
|
|
467
|
-
}
|
|
468
|
-
if (tokens[closeIdx].type === 'link_open') {
|
|
469
|
-
invalid = true
|
|
470
|
-
break
|
|
471
|
-
}
|
|
472
|
-
closeIdx++
|
|
473
|
-
}
|
|
474
|
-
if (invalid || closeIdx >= tokens.length) {
|
|
475
|
-
i++
|
|
476
|
-
continue
|
|
477
|
-
}
|
|
478
|
-
const currentLabelSource = labelSources && labelSourceIndex < labelSources.length
|
|
479
|
-
? labelSources[labelSourceIndex]
|
|
480
|
-
: undefined
|
|
481
|
-
|
|
482
|
-
const labelLength = closeIdx - i - 1
|
|
483
|
-
const needsPlaceholder = labelLength <= 0
|
|
484
|
-
if (needsPlaceholder && !currentLabelSource) {
|
|
485
|
-
i++
|
|
486
|
-
continue
|
|
487
|
-
}
|
|
488
|
-
|
|
489
|
-
let tailIdx = closeIdx + 1
|
|
490
|
-
let tailContent = ''
|
|
491
|
-
let parsedTail = null
|
|
492
|
-
let tailHasCloseParen = false
|
|
493
|
-
while (tailIdx < tokens.length) {
|
|
494
|
-
if (splitBracketToken(tokens, tailIdx, INLINE_LINK_BRACKET_SPLIT_OPTIONS)) {
|
|
495
|
-
continue
|
|
496
|
-
}
|
|
497
|
-
const tailToken = tokens[tailIdx]
|
|
498
|
-
if (tailToken.type !== 'text' || !tailToken.content) {
|
|
499
|
-
break
|
|
500
|
-
}
|
|
501
|
-
tailContent += tailToken.content
|
|
502
|
-
if (!tailHasCloseParen) {
|
|
503
|
-
if (tailToken.content.indexOf(')') === -1) {
|
|
504
|
-
tailIdx++
|
|
505
|
-
continue
|
|
506
|
-
}
|
|
507
|
-
tailHasCloseParen = true
|
|
508
|
-
}
|
|
509
|
-
parsedTail = parseInlineLinkTail(tailContent, state.md)
|
|
510
|
-
if (parsedTail) break
|
|
511
|
-
tailIdx++
|
|
512
|
-
}
|
|
513
|
-
|
|
514
|
-
if (!parsedTail) {
|
|
515
|
-
i++
|
|
516
|
-
continue
|
|
517
|
-
}
|
|
518
|
-
|
|
519
|
-
if (!consumeCharactersFromTokens(tokens, closeIdx + 1, parsedTail.consumed)) {
|
|
520
|
-
i++
|
|
521
|
-
continue
|
|
522
|
-
}
|
|
523
|
-
|
|
524
|
-
tokens.splice(closeIdx, 1)
|
|
525
|
-
tokens.splice(i, 1)
|
|
526
|
-
|
|
527
|
-
const linkOpenToken = new Token('link_open', 'a', 1)
|
|
528
|
-
linkOpenToken.attrs = [['href', parsedTail.href]]
|
|
529
|
-
if (parsedTail.title) linkOpenToken.attrPush(['title', parsedTail.title])
|
|
530
|
-
linkOpenToken.markup = '[]()'
|
|
531
|
-
linkOpenToken.info = 'auto'
|
|
532
|
-
const linkCloseToken = new Token('link_close', 'a', -1)
|
|
533
|
-
linkCloseToken.markup = '[]()'
|
|
534
|
-
linkCloseToken.info = 'auto'
|
|
535
|
-
|
|
536
|
-
const nextIndex = wrapLabelTokensWithLink(tokens, i, i + labelLength - 1, linkOpenToken, linkCloseToken, currentLabelSource)
|
|
537
|
-
if (nextIndex === i) {
|
|
538
|
-
i++
|
|
539
|
-
continue
|
|
540
|
-
}
|
|
541
|
-
if (currentLabelSource) {
|
|
542
|
-
const linkCloseIdx = findLinkCloseIndex(tokens, i)
|
|
543
|
-
if (linkCloseIdx !== -1) {
|
|
544
|
-
let cursor = 0
|
|
545
|
-
for (let pos = i + 1; pos < linkCloseIdx; pos++) {
|
|
546
|
-
const t = tokens[pos]
|
|
547
|
-
const markup = t.markup || ''
|
|
548
|
-
const text = t.content || ''
|
|
549
|
-
const startPos = cursor
|
|
550
|
-
if (t.type === 'text') {
|
|
551
|
-
cursor += text.length
|
|
552
|
-
} else if (t.type === 'code_inline') {
|
|
553
|
-
cursor += markup.length + text.length + markup.length
|
|
554
|
-
} else if (markup) {
|
|
555
|
-
cursor += markup.length
|
|
556
|
-
}
|
|
557
|
-
if ((t.type === 'strong_open' || t.type === 'em_open') && startPos > 0) {
|
|
558
|
-
const prevToken = tokens[pos - 1]
|
|
559
|
-
if (prevToken && prevToken.type === 'text' && prevToken.content && !prevToken.content.endsWith(' ')) {
|
|
560
|
-
const labelHasSpaceBefore = startPos - 1 >= 0 && startPos - 1 < currentLabelSource.length && currentLabelSource[startPos - 1] === ' '
|
|
561
|
-
const labelHasSpaceAt = startPos >= 0 && startPos < currentLabelSource.length && currentLabelSource[startPos] === ' '
|
|
562
|
-
if (labelHasSpaceBefore || labelHasSpaceAt) {
|
|
563
|
-
prevToken.content += ' '
|
|
564
|
-
}
|
|
565
|
-
}
|
|
566
|
-
}
|
|
567
|
-
}
|
|
568
|
-
}
|
|
569
|
-
}
|
|
570
|
-
if (needsPlaceholder && currentLabelSource) {
|
|
571
|
-
removeGhostLabelText(tokens, nextIndex - 1, currentLabelSource)
|
|
572
|
-
}
|
|
573
|
-
|
|
574
|
-
if (labelSources && labelSources.length > 0) {
|
|
575
|
-
if (labelSourceIndex < labelSources.length) {
|
|
576
|
-
labelSourceIndex++
|
|
577
|
-
}
|
|
578
|
-
}
|
|
579
|
-
i = nextIndex
|
|
580
|
-
}
|
|
581
|
-
if (labelSources) {
|
|
582
|
-
tokens.__strongJaInlineLabelIndex = labelSourceIndex
|
|
583
|
-
}
|
|
584
|
-
}
|
|
585
|
-
|
|
586
275
|
const convertCollapsedReferenceLinks = (tokens, state) => {
|
|
587
276
|
const references = state.env && state.env.references
|
|
588
277
|
if (!references) return
|
|
589
|
-
|
|
590
|
-
if (referenceCount
|
|
591
|
-
|
|
592
|
-
|
|
278
|
+
let referenceCount = state.__strongJaReferenceCount
|
|
279
|
+
if (referenceCount === undefined) {
|
|
280
|
+
referenceCount = Object.keys(references).length
|
|
281
|
+
state.__strongJaReferenceCount = referenceCount
|
|
282
|
+
}
|
|
283
|
+
if (referenceCount === 0) {
|
|
593
284
|
return
|
|
594
285
|
}
|
|
595
286
|
|
|
596
287
|
let i = 0
|
|
288
|
+
let linkCloseMap = null
|
|
597
289
|
while (i < tokens.length) {
|
|
598
290
|
if (splitBracketToken(tokens, i)) {
|
|
291
|
+
linkCloseMap = null
|
|
599
292
|
continue
|
|
600
293
|
}
|
|
601
294
|
if (!isBracketToken(tokens[i], '[')) {
|
|
@@ -604,10 +297,12 @@ const convertCollapsedReferenceLinks = (tokens, state) => {
|
|
|
604
297
|
}
|
|
605
298
|
let closeIdx = i + 1
|
|
606
299
|
while (closeIdx < tokens.length && !isBracketToken(tokens[closeIdx], ']')) {
|
|
607
|
-
|
|
300
|
+
const closeToken = tokens[closeIdx]
|
|
301
|
+
if (closeToken && closeToken.type === 'text' && splitBracketToken(tokens, closeIdx)) {
|
|
302
|
+
linkCloseMap = null
|
|
608
303
|
continue
|
|
609
304
|
}
|
|
610
|
-
if (
|
|
305
|
+
if (closeToken && closeToken.type === 'link_open') {
|
|
611
306
|
closeIdx = -1
|
|
612
307
|
break
|
|
613
308
|
}
|
|
@@ -627,13 +322,18 @@ const convertCollapsedReferenceLinks = (tokens, state) => {
|
|
|
627
322
|
const labelEnd = closeIdx - 1
|
|
628
323
|
const labelLength = closeIdx - i - 1
|
|
629
324
|
const labelText = buildReferenceLabelRange(tokens, labelStart, labelEnd)
|
|
630
|
-
|
|
325
|
+
if (labelText.indexOf('*') === -1 && labelText.indexOf('_') === -1) {
|
|
326
|
+
i++
|
|
327
|
+
continue
|
|
328
|
+
}
|
|
631
329
|
const whitespaceStart = closeIdx + 1
|
|
632
330
|
let refRemoveStart = whitespaceStart
|
|
633
331
|
while (refRemoveStart < tokens.length && isWhitespaceToken(tokens[refRemoveStart])) {
|
|
634
332
|
refRemoveStart++
|
|
635
333
|
}
|
|
636
|
-
|
|
334
|
+
const refStartToken = tokens[refRemoveStart]
|
|
335
|
+
if (refStartToken && refStartToken.type === 'text' && splitBracketToken(tokens, refRemoveStart)) {
|
|
336
|
+
linkCloseMap = null
|
|
637
337
|
continue
|
|
638
338
|
}
|
|
639
339
|
const whitespaceCount = refRemoveStart - whitespaceStart
|
|
@@ -643,7 +343,7 @@ const convertCollapsedReferenceLinks = (tokens, state) => {
|
|
|
643
343
|
let existingLinkClose = null
|
|
644
344
|
const nextToken = tokens[refRemoveStart]
|
|
645
345
|
if (isBracketToken(nextToken, '[]')) {
|
|
646
|
-
refKey = normalizeReferenceCandidate(state,
|
|
346
|
+
refKey = normalizeReferenceCandidate(state, labelText)
|
|
647
347
|
refRemoveCount = 1
|
|
648
348
|
} else if (isBracketToken(nextToken, '[')) {
|
|
649
349
|
let refCloseIdx = refRemoveStart + 1
|
|
@@ -657,14 +357,17 @@ const convertCollapsedReferenceLinks = (tokens, state) => {
|
|
|
657
357
|
const refStart = refRemoveStart + 1
|
|
658
358
|
const refEnd = refCloseIdx - 1
|
|
659
359
|
if (refStart > refEnd) {
|
|
660
|
-
refKey = normalizeReferenceCandidate(state,
|
|
360
|
+
refKey = normalizeReferenceCandidate(state, labelText)
|
|
661
361
|
} else {
|
|
662
362
|
const refLabelText = buildReferenceLabelRange(tokens, refStart, refEnd)
|
|
663
363
|
refKey = normalizeReferenceCandidate(state, refLabelText)
|
|
664
364
|
}
|
|
665
365
|
refRemoveCount = refCloseIdx - refRemoveStart + 1
|
|
666
366
|
} else if (nextToken && nextToken.type === 'link_open') {
|
|
667
|
-
|
|
367
|
+
if (linkCloseMap === null) {
|
|
368
|
+
linkCloseMap = buildLinkCloseMap(tokens, refRemoveStart, tokens.length - 1)
|
|
369
|
+
}
|
|
370
|
+
const linkCloseIdx = linkCloseMap.get(refRemoveStart) ?? -1
|
|
668
371
|
if (linkCloseIdx === -1) {
|
|
669
372
|
i++
|
|
670
373
|
continue
|
|
@@ -679,6 +382,7 @@ const convertCollapsedReferenceLinks = (tokens, state) => {
|
|
|
679
382
|
let linkOpenToken = null
|
|
680
383
|
let linkCloseToken = null
|
|
681
384
|
if (existingLinkOpen && existingLinkClose) {
|
|
385
|
+
linkCloseMap = null
|
|
682
386
|
if (whitespaceCount > 0) {
|
|
683
387
|
tokens.splice(whitespaceStart, whitespaceCount)
|
|
684
388
|
refRemoveStart -= whitespaceCount
|
|
@@ -698,6 +402,7 @@ const convertCollapsedReferenceLinks = (tokens, state) => {
|
|
|
698
402
|
i++
|
|
699
403
|
continue
|
|
700
404
|
}
|
|
405
|
+
linkCloseMap = null
|
|
701
406
|
if (whitespaceCount > 0) {
|
|
702
407
|
tokens.splice(whitespaceStart, whitespaceCount)
|
|
703
408
|
refRemoveStart -= whitespaceCount
|
|
@@ -722,12 +427,12 @@ const convertCollapsedReferenceLinks = (tokens, state) => {
|
|
|
722
427
|
}
|
|
723
428
|
}
|
|
724
429
|
|
|
725
|
-
// Link cleanup helpers
|
|
726
430
|
const mergeBrokenMarksAroundLinks = (tokens) => {
|
|
727
431
|
let i = 0
|
|
728
432
|
while (i < tokens.length) {
|
|
729
433
|
const closeToken = tokens[i]
|
|
730
|
-
if (!closeToken ||
|
|
434
|
+
if (!closeToken || !closeToken.type ||
|
|
435
|
+
(closeToken.type !== 'em_close' && closeToken.type !== 'strong_close')) {
|
|
731
436
|
i++
|
|
732
437
|
continue
|
|
733
438
|
}
|
|
@@ -766,8 +471,7 @@ const mergeBrokenMarksAroundLinks = (tokens) => {
|
|
|
766
471
|
|
|
767
472
|
export {
|
|
768
473
|
normalizeReferenceCandidate,
|
|
769
|
-
|
|
770
|
-
convertInlineLinks,
|
|
474
|
+
buildLinkCloseMap,
|
|
771
475
|
convertCollapsedReferenceLinks,
|
|
772
476
|
mergeBrokenMarksAroundLinks,
|
|
773
477
|
getMapFromTokenRange
|