@peaceroad/markdown-it-strong-ja 0.7.2 → 0.8.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/README.md +326 -195
- package/index.js +27 -40
- package/package.json +26 -6
- package/src/token-compat.js +71 -22
- package/src/token-core.js +521 -132
- package/src/token-link-utils.js +434 -539
- package/src/token-postprocess/broken-ref.js +475 -0
- package/src/token-postprocess/fastpaths.js +349 -0
- package/src/token-postprocess/guards.js +499 -0
- package/src/token-postprocess/orchestrator.js +672 -0
- package/src/token-postprocess.js +1 -334
- package/src/token-utils.js +215 -142
package/src/token-postprocess.js
CHANGED
|
@@ -1,334 +1 @@
|
|
|
1
|
-
|
|
2
|
-
import { convertCollapsedReferenceLinks, mergeBrokenMarksAroundLinks, getMapFromTokenRange } from './token-link-utils.js'
|
|
3
|
-
import {
|
|
4
|
-
rebuildInlineLevels,
|
|
5
|
-
findLinkClose,
|
|
6
|
-
fixEmOuterStrongSequence,
|
|
7
|
-
fixLeadingAsteriskEm,
|
|
8
|
-
fixTrailingStrong
|
|
9
|
-
} from './token-core.js'
|
|
10
|
-
import { getRuntimeOpt } from './token-utils.js'
|
|
11
|
-
|
|
12
|
-
const scanBrokenRefState = (text, out) => {
|
|
13
|
-
if (!text || text.indexOf('][') === -1) {
|
|
14
|
-
out.depth = 0
|
|
15
|
-
out.brokenEnd = false
|
|
16
|
-
return out
|
|
17
|
-
}
|
|
18
|
-
let depth = 0
|
|
19
|
-
let lastOpen = -1
|
|
20
|
-
let lastClose = -1
|
|
21
|
-
for (let i = 0; i < text.length; i++) {
|
|
22
|
-
const ch = text.charCodeAt(i)
|
|
23
|
-
if (ch === 0x5B) {
|
|
24
|
-
depth++
|
|
25
|
-
lastOpen = i
|
|
26
|
-
} else if (ch === 0x5D) {
|
|
27
|
-
if (depth > 0) depth--
|
|
28
|
-
lastClose = i
|
|
29
|
-
}
|
|
30
|
-
}
|
|
31
|
-
out.depth = depth
|
|
32
|
-
out.brokenEnd = depth > 0 && lastOpen > lastClose
|
|
33
|
-
return out
|
|
34
|
-
}
|
|
35
|
-
|
|
36
|
-
const updateBracketDepth = (text, depth) => {
|
|
37
|
-
if (!text || depth <= 0) return depth
|
|
38
|
-
for (let i = 0; i < text.length; i++) {
|
|
39
|
-
const ch = text.charCodeAt(i)
|
|
40
|
-
if (ch === 0x5B) {
|
|
41
|
-
depth++
|
|
42
|
-
} else if (ch === 0x5D) {
|
|
43
|
-
if (depth > 0) {
|
|
44
|
-
depth--
|
|
45
|
-
if (depth === 0) return 0
|
|
46
|
-
}
|
|
47
|
-
}
|
|
48
|
-
}
|
|
49
|
-
return depth
|
|
50
|
-
}
|
|
51
|
-
|
|
52
|
-
const getAttr = (token, name) => {
|
|
53
|
-
if (!token || !token.attrs) return ''
|
|
54
|
-
for (let i = 0; i < token.attrs.length; i++) {
|
|
55
|
-
if (token.attrs[i][0] === name) return token.attrs[i][1]
|
|
56
|
-
}
|
|
57
|
-
return ''
|
|
58
|
-
}
|
|
59
|
-
|
|
60
|
-
const buildLabelText = (tokens, startIdx, endIdx) => {
|
|
61
|
-
let label = ''
|
|
62
|
-
for (let i = startIdx; i <= endIdx; i++) {
|
|
63
|
-
const t = tokens[i]
|
|
64
|
-
if (!t) continue
|
|
65
|
-
if (t.type === 'text') {
|
|
66
|
-
label += t.content
|
|
67
|
-
} else if (t.type === 'code_inline') {
|
|
68
|
-
const fence = t.markup || '`'
|
|
69
|
-
label += fence + t.content + fence
|
|
70
|
-
} else if (t.markup) {
|
|
71
|
-
label += t.markup
|
|
72
|
-
}
|
|
73
|
-
}
|
|
74
|
-
return label
|
|
75
|
-
}
|
|
76
|
-
|
|
77
|
-
const buildRawFromTokens = (tokens, startIdx, endIdx) => {
|
|
78
|
-
let raw = ''
|
|
79
|
-
for (let i = startIdx; i <= endIdx; i++) {
|
|
80
|
-
const t = tokens[i]
|
|
81
|
-
if (!t) continue
|
|
82
|
-
if (t.type === 'link_open') {
|
|
83
|
-
const closeIdx = findLinkClose(tokens, i)
|
|
84
|
-
if (closeIdx === -1 || closeIdx > endIdx) break
|
|
85
|
-
const label = buildLabelText(tokens, i + 1, closeIdx - 1)
|
|
86
|
-
const href = getAttr(t, 'href')
|
|
87
|
-
raw += `[${label}](${href || ''})`
|
|
88
|
-
i = closeIdx
|
|
89
|
-
continue
|
|
90
|
-
}
|
|
91
|
-
if (t.type === 'text') {
|
|
92
|
-
raw += t.content
|
|
93
|
-
continue
|
|
94
|
-
}
|
|
95
|
-
if (t.type === 'code_inline') {
|
|
96
|
-
const fence = t.markup || '`'
|
|
97
|
-
raw += fence + t.content + fence
|
|
98
|
-
continue
|
|
99
|
-
}
|
|
100
|
-
if (t.markup) {
|
|
101
|
-
raw += t.markup
|
|
102
|
-
}
|
|
103
|
-
}
|
|
104
|
-
return raw
|
|
105
|
-
}
|
|
106
|
-
|
|
107
|
-
const parseInlineWithFixes = (md, raw, env) => {
|
|
108
|
-
const parsed = md.parseInline(raw, env)
|
|
109
|
-
const inline = parsed && parsed.length > 0 ? parsed[0] : null
|
|
110
|
-
if (!inline || !inline.children) return null
|
|
111
|
-
const children = inline.children
|
|
112
|
-
let changed = false
|
|
113
|
-
if (fixEmOuterStrongSequence(children)) changed = true
|
|
114
|
-
if (fixLeadingAsteriskEm(children)) changed = true
|
|
115
|
-
if (fixTrailingStrong(children)) changed = true
|
|
116
|
-
if (changed) rebuildInlineLevels(children)
|
|
117
|
-
return children
|
|
118
|
-
}
|
|
119
|
-
|
|
120
|
-
const hasUnsafeAttrs = (token) => {
|
|
121
|
-
if (!token) return false
|
|
122
|
-
if (token.meta && Object.keys(token.meta).length > 0) return true
|
|
123
|
-
if (!token.attrs || token.attrs.length === 0) return false
|
|
124
|
-
if (token.type !== 'link_open') return true
|
|
125
|
-
for (let i = 0; i < token.attrs.length; i++) {
|
|
126
|
-
const name = token.attrs[i][0]
|
|
127
|
-
if (name !== 'href' && name !== 'title') return true
|
|
128
|
-
}
|
|
129
|
-
return false
|
|
130
|
-
}
|
|
131
|
-
|
|
132
|
-
const REPARSE_ALLOWED_TYPES = new Set([
|
|
133
|
-
'text',
|
|
134
|
-
'strong_open',
|
|
135
|
-
'strong_close',
|
|
136
|
-
'em_open',
|
|
137
|
-
'em_close',
|
|
138
|
-
'code_inline',
|
|
139
|
-
'link_open',
|
|
140
|
-
'link_close',
|
|
141
|
-
'softbreak',
|
|
142
|
-
'hardbreak'
|
|
143
|
-
])
|
|
144
|
-
|
|
145
|
-
const shouldReparseSegment = (tokens, startIdx, endIdx) => {
|
|
146
|
-
for (let i = startIdx; i <= endIdx && i < tokens.length; i++) {
|
|
147
|
-
const t = tokens[i]
|
|
148
|
-
if (!t) continue
|
|
149
|
-
if (hasUnsafeAttrs(t)) return false
|
|
150
|
-
if (t.type && !REPARSE_ALLOWED_TYPES.has(t.type)) return false
|
|
151
|
-
}
|
|
152
|
-
return true
|
|
153
|
-
}
|
|
154
|
-
|
|
155
|
-
const fixTailAfterLinkStrongClose = (tokens, md, env) => {
|
|
156
|
-
let strongDepth = 0
|
|
157
|
-
for (let i = 0; i < tokens.length; i++) {
|
|
158
|
-
const t = tokens[i]
|
|
159
|
-
if (!t) continue
|
|
160
|
-
if (t.type === 'strong_open') strongDepth++
|
|
161
|
-
if (t.type === 'strong_close') {
|
|
162
|
-
if (strongDepth > 0) strongDepth--
|
|
163
|
-
}
|
|
164
|
-
if (t.type !== 'link_close') continue
|
|
165
|
-
if (strongDepth !== 0) continue
|
|
166
|
-
let startIdx = -1
|
|
167
|
-
let foundStrongClose = -1
|
|
168
|
-
let foundStrongOpen = -1
|
|
169
|
-
for (let j = i + 1; j < tokens.length; j++) {
|
|
170
|
-
const node = tokens[j]
|
|
171
|
-
if (!node) continue
|
|
172
|
-
if (node.type === 'strong_open') {
|
|
173
|
-
foundStrongOpen = j
|
|
174
|
-
break
|
|
175
|
-
}
|
|
176
|
-
if (node.type === 'strong_close') {
|
|
177
|
-
foundStrongClose = j
|
|
178
|
-
break
|
|
179
|
-
}
|
|
180
|
-
if (node.type === 'text' && node.content && startIdx === -1) {
|
|
181
|
-
startIdx = j
|
|
182
|
-
}
|
|
183
|
-
}
|
|
184
|
-
if (foundStrongClose === -1 || foundStrongOpen !== -1) continue
|
|
185
|
-
if (startIdx === -1) startIdx = foundStrongClose
|
|
186
|
-
const raw = buildRawFromTokens(tokens, startIdx, tokens.length - 1)
|
|
187
|
-
const children = parseInlineWithFixes(md, raw, env)
|
|
188
|
-
if (children && children.length > 0) {
|
|
189
|
-
tokens.splice(startIdx, tokens.length - startIdx, ...children)
|
|
190
|
-
return true
|
|
191
|
-
}
|
|
192
|
-
}
|
|
193
|
-
return false
|
|
194
|
-
}
|
|
195
|
-
|
|
196
|
-
const registerTokenPostprocess = (md, baseOpt, getNoLinkMdInstance) => {
|
|
197
|
-
if (md.__strongJaTokenPostprocessRegistered) return
|
|
198
|
-
md.__strongJaTokenPostprocessRegistered = true
|
|
199
|
-
md.core.ruler.after('inline', 'strong_ja_token_postprocess', (state) => {
|
|
200
|
-
if (!state || !state.tokens) return
|
|
201
|
-
const opt = getRuntimeOpt(state, baseOpt)
|
|
202
|
-
if (opt.postprocess === false) return
|
|
203
|
-
if (state.__strongJaReferenceCount === undefined) {
|
|
204
|
-
const references = state.env && state.env.references
|
|
205
|
-
state.__strongJaReferenceCount = references ? Object.keys(references).length : 0
|
|
206
|
-
}
|
|
207
|
-
for (let i = 0; i < state.tokens.length; i++) {
|
|
208
|
-
const token = state.tokens[i]
|
|
209
|
-
if (!token || token.type !== 'inline' || !token.children || token.children.length === 0) continue
|
|
210
|
-
const children = token.children
|
|
211
|
-
let changed = false
|
|
212
|
-
let hasBracketText = false
|
|
213
|
-
let hasEmphasis = false
|
|
214
|
-
let hasLinkClose = false
|
|
215
|
-
let reparseCount = 0
|
|
216
|
-
let maxReparse = 0
|
|
217
|
-
const scanState = { depth: 0, brokenEnd: false }
|
|
218
|
-
for (let j = 0; j < children.length; j++) {
|
|
219
|
-
const child = children[j]
|
|
220
|
-
if (!child) continue
|
|
221
|
-
if (!hasEmphasis &&
|
|
222
|
-
(child.type === 'strong_open' || child.type === 'strong_close' || child.type === 'em_open' || child.type === 'em_close')) {
|
|
223
|
-
hasEmphasis = true
|
|
224
|
-
}
|
|
225
|
-
if (!hasLinkClose && child.type === 'link_close') {
|
|
226
|
-
hasLinkClose = true
|
|
227
|
-
}
|
|
228
|
-
if (child.type !== 'text' || !child.content) continue
|
|
229
|
-
if (!hasBracketText && (child.content.indexOf('[') !== -1 || child.content.indexOf(']') !== -1)) {
|
|
230
|
-
hasBracketText = true
|
|
231
|
-
}
|
|
232
|
-
if (scanBrokenRefState(child.content, scanState).brokenEnd) {
|
|
233
|
-
maxReparse++
|
|
234
|
-
}
|
|
235
|
-
}
|
|
236
|
-
if (maxReparse !== 0) {
|
|
237
|
-
let allowReparse = true
|
|
238
|
-
while (true) {
|
|
239
|
-
let didReparse = false
|
|
240
|
-
let brokenRefStart = -1
|
|
241
|
-
let brokenRefDepth = 0
|
|
242
|
-
hasBracketText = false
|
|
243
|
-
hasEmphasis = false
|
|
244
|
-
hasLinkClose = false
|
|
245
|
-
for (let j = 0; j < children.length; j++) {
|
|
246
|
-
const child = children[j]
|
|
247
|
-
if (!child) continue
|
|
248
|
-
if (child.type === 'text' && child.content) {
|
|
249
|
-
if (!hasBracketText && (child.content.indexOf('[') !== -1 || child.content.indexOf(']') !== -1)) {
|
|
250
|
-
hasBracketText = true
|
|
251
|
-
}
|
|
252
|
-
if (brokenRefStart === -1) {
|
|
253
|
-
const scan = scanBrokenRefState(child.content, scanState)
|
|
254
|
-
if (scan.brokenEnd) {
|
|
255
|
-
brokenRefStart = j
|
|
256
|
-
brokenRefDepth = scan.depth
|
|
257
|
-
continue
|
|
258
|
-
}
|
|
259
|
-
} else {
|
|
260
|
-
brokenRefDepth = updateBracketDepth(child.content, brokenRefDepth)
|
|
261
|
-
if (brokenRefDepth <= 0) {
|
|
262
|
-
brokenRefStart = -1
|
|
263
|
-
brokenRefDepth = 0
|
|
264
|
-
}
|
|
265
|
-
}
|
|
266
|
-
}
|
|
267
|
-
if (!hasEmphasis &&
|
|
268
|
-
(child.type === 'strong_open' || child.type === 'strong_close' || child.type === 'em_open' || child.type === 'em_close')) {
|
|
269
|
-
hasEmphasis = true
|
|
270
|
-
}
|
|
271
|
-
if (!hasLinkClose && child.type === 'link_close') {
|
|
272
|
-
hasLinkClose = true
|
|
273
|
-
}
|
|
274
|
-
if (allowReparse && brokenRefStart !== -1 && child.type === 'link_open') {
|
|
275
|
-
if (brokenRefDepth <= 0) {
|
|
276
|
-
brokenRefStart = -1
|
|
277
|
-
brokenRefDepth = 0
|
|
278
|
-
continue
|
|
279
|
-
}
|
|
280
|
-
const closeIdx = findLinkClose(children, j)
|
|
281
|
-
if (closeIdx !== -1) {
|
|
282
|
-
if (shouldReparseSegment(children, brokenRefStart, closeIdx)) {
|
|
283
|
-
const originalMap = getMapFromTokenRange(children, brokenRefStart, closeIdx)
|
|
284
|
-
const raw = buildRawFromTokens(children, brokenRefStart, closeIdx)
|
|
285
|
-
const noLink = getNoLinkMdInstance(md, opt)
|
|
286
|
-
const parsed = parseInlineWithFixes(noLink, raw, state.env)
|
|
287
|
-
if (parsed && parsed.length > 0) {
|
|
288
|
-
if (originalMap) {
|
|
289
|
-
for (let k = 0; k < parsed.length; k++) {
|
|
290
|
-
const childToken = parsed[k]
|
|
291
|
-
if (childToken && !childToken.map) childToken.map = [originalMap[0], originalMap[1]]
|
|
292
|
-
}
|
|
293
|
-
}
|
|
294
|
-
children.splice(brokenRefStart, closeIdx - brokenRefStart + 1, ...parsed)
|
|
295
|
-
} else {
|
|
296
|
-
const text = new Token('text', '', 0)
|
|
297
|
-
text.content = raw
|
|
298
|
-
if (originalMap) text.map = [originalMap[0], originalMap[1]]
|
|
299
|
-
children.splice(brokenRefStart, closeIdx - brokenRefStart + 1, text)
|
|
300
|
-
}
|
|
301
|
-
brokenRefStart = -1
|
|
302
|
-
changed = true
|
|
303
|
-
didReparse = true
|
|
304
|
-
break
|
|
305
|
-
}
|
|
306
|
-
brokenRefStart = -1
|
|
307
|
-
}
|
|
308
|
-
}
|
|
309
|
-
}
|
|
310
|
-
if (!didReparse) break
|
|
311
|
-
reparseCount++
|
|
312
|
-
if (reparseCount >= maxReparse) {
|
|
313
|
-
allowReparse = false
|
|
314
|
-
}
|
|
315
|
-
if (!allowReparse) {
|
|
316
|
-
continue
|
|
317
|
-
}
|
|
318
|
-
}
|
|
319
|
-
}
|
|
320
|
-
if (hasEmphasis) {
|
|
321
|
-
if (fixEmOuterStrongSequence(children)) changed = true
|
|
322
|
-
if (hasLinkClose && fixTailAfterLinkStrongClose(children, md, state.env)) changed = true
|
|
323
|
-
if (hasLinkClose && fixLeadingAsteriskEm(children)) changed = true
|
|
324
|
-
if (fixTrailingStrong(children)) changed = true
|
|
325
|
-
}
|
|
326
|
-
if (changed) rebuildInlineLevels(children)
|
|
327
|
-
if (!hasBracketText) continue
|
|
328
|
-
convertCollapsedReferenceLinks(children, state)
|
|
329
|
-
mergeBrokenMarksAroundLinks(children)
|
|
330
|
-
}
|
|
331
|
-
})
|
|
332
|
-
}
|
|
333
|
-
|
|
334
|
-
export { registerTokenPostprocess }
|
|
1
|
+
export { registerTokenPostprocess } from './token-postprocess/orchestrator.js'
|