@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.
@@ -0,0 +1,672 @@
1
+ import Token from 'markdown-it/lib/token.mjs'
2
+ import { buildLinkCloseMap, convertCollapsedReferenceLinks, mergeBrokenMarksAroundLinks } from '../token-link-utils.js'
3
+ import { computeMaxBrokenRefRepairPass, runBrokenRefRepairs } from './broken-ref.js'
4
+ import {
5
+ rebuildInlineLevels,
6
+ rebuildInlineLevelsFrom,
7
+ fixEmOuterStrongSequence,
8
+ fixLeadingAsteriskEm,
9
+ fixTrailingStrong
10
+ } from '../token-core.js'
11
+ import {
12
+ getRuntimeOpt,
13
+ getReferenceCount
14
+ } from '../token-utils.js'
15
+ import {
16
+ hasMarkerChars,
17
+ hasJapaneseContextInRange,
18
+ hasEmphasisSignalInRange,
19
+ buildAsteriskWrapperPrefixStats,
20
+ scanInlinePostprocessSignals
21
+ } from './guards.js'
22
+ import {
23
+ tryFixTailPatternTokenOnly,
24
+ tryFixTailDanglingStrongCloseTokenOnly
25
+ } from './fastpaths.js'
26
+
27
+ const fallbackMarkupByType = (type) => {
28
+ if (type === 'strong_open' || type === 'strong_close') return '**'
29
+ if (type === 'em_open' || type === 'em_close') return '*'
30
+ return ''
31
+ }
32
+
33
+ const makeTokenLiteralText = (token) => {
34
+ if (!token) return
35
+ const literal = token.markup || fallbackMarkupByType(token.type)
36
+ token.type = 'text'
37
+ token.tag = ''
38
+ token.nesting = 0
39
+ token.content = literal
40
+ token.markup = ''
41
+ token.info = ''
42
+ }
43
+
44
+ const sanitizeEmStrongBalance = (tokens, onChangeStart = null) => {
45
+ if (!tokens || tokens.length === 0) return false
46
+ const stack = []
47
+ let changed = false
48
+ for (let i = 0; i < tokens.length; i++) {
49
+ const token = tokens[i]
50
+ if (!token || !token.type) continue
51
+ if (token.type === 'strong_open' || token.type === 'em_open') {
52
+ stack.push({ type: token.type, idx: i })
53
+ continue
54
+ }
55
+ if (token.type !== 'strong_close' && token.type !== 'em_close') continue
56
+ const expected = token.type === 'strong_close' ? 'strong_open' : 'em_open'
57
+ if (stack.length > 0 && stack[stack.length - 1].type === expected) {
58
+ stack.pop()
59
+ continue
60
+ }
61
+ if (onChangeStart) onChangeStart(i)
62
+ makeTokenLiteralText(token)
63
+ changed = true
64
+ }
65
+ for (let i = stack.length - 1; i >= 0; i--) {
66
+ const entry = stack[i]
67
+ const token = tokens[entry.idx]
68
+ if (!token) continue
69
+ if (onChangeStart) onChangeStart(entry.idx)
70
+ makeTokenLiteralText(token)
71
+ changed = true
72
+ }
73
+ return changed
74
+ }
75
+
76
+ const getPostprocessMetrics = (state) => {
77
+ if (!state || !state.env) return null
78
+ const metrics = state.env.__strongJaPostprocessMetrics
79
+ if (!metrics || typeof metrics !== 'object') return null
80
+ return metrics
81
+ }
82
+
83
+ const buildInlinePostprocessFacts = (children, inlineContent) => {
84
+ const preScan = scanInlinePostprocessSignals(children)
85
+ return {
86
+ hasBracketText: inlineContent.indexOf('[') !== -1 || inlineContent.indexOf(']') !== -1,
87
+ hasEmphasis: preScan.hasEmphasis,
88
+ hasLinkOpen: preScan.hasLinkOpen,
89
+ hasLinkClose: preScan.hasLinkClose,
90
+ hasCodeInline: undefined,
91
+ referenceCount: undefined,
92
+ metrics: undefined,
93
+ linkCloseMap: undefined,
94
+ wrapperPrefixStats: undefined,
95
+ rebuildLevelStart: undefined
96
+ }
97
+ }
98
+
99
+ const ensureInlineHasCodeInline = (facts, tokens) => {
100
+ if (facts.hasCodeInline !== undefined) return facts.hasCodeInline
101
+ let hasCodeInline = false
102
+ if (tokens && tokens.length > 0) {
103
+ for (let idx = 0; idx < tokens.length; idx++) {
104
+ if (tokens[idx] && tokens[idx].type === 'code_inline') {
105
+ hasCodeInline = true
106
+ break
107
+ }
108
+ }
109
+ }
110
+ facts.hasCodeInline = hasCodeInline
111
+ return hasCodeInline
112
+ }
113
+
114
+ const ensureInlineReferenceCount = (facts, state) => {
115
+ if (!facts || !facts.hasBracketText) return 0
116
+ if (facts.referenceCount === undefined) {
117
+ facts.referenceCount = getReferenceCount(state)
118
+ }
119
+ return facts.referenceCount
120
+ }
121
+
122
+ const ensureInlineMetrics = (facts, state) => {
123
+ if (!facts) return null
124
+ if (facts.metrics === undefined) {
125
+ facts.metrics = getPostprocessMetrics(state)
126
+ }
127
+ return facts.metrics
128
+ }
129
+
130
+ const ensureInlineLinkCloseMap = (facts, tokens) => {
131
+ if (!tokens || tokens.length === 0) return new Map()
132
+ if (!facts) return buildLinkCloseMap(tokens, 0, tokens.length - 1)
133
+ if (facts.linkCloseMap === undefined) {
134
+ facts.linkCloseMap = buildLinkCloseMap(tokens, 0, tokens.length - 1)
135
+ }
136
+ return facts.linkCloseMap
137
+ }
138
+
139
+ const ensureInlineWrapperPrefixStats = (facts, tokens) => {
140
+ if (!tokens || tokens.length === 0) return null
141
+ if (!facts) return buildAsteriskWrapperPrefixStats(tokens)
142
+ if (facts.wrapperPrefixStats === undefined) {
143
+ facts.wrapperPrefixStats = buildAsteriskWrapperPrefixStats(tokens)
144
+ }
145
+ return facts.wrapperPrefixStats
146
+ }
147
+
148
+ const invalidateInlineDerivedCaches = (facts) => {
149
+ if (!facts) return
150
+ facts.linkCloseMap = undefined
151
+ facts.wrapperPrefixStats = undefined
152
+ }
153
+
154
+ const markInlineLevelRebuildFrom = (facts, startIdx) => {
155
+ if (!facts) return
156
+ const from = startIdx > 0 ? startIdx : 0
157
+ if (facts.rebuildLevelStart === undefined || from < facts.rebuildLevelStart) {
158
+ facts.rebuildLevelStart = from
159
+ }
160
+ }
161
+
162
+ const rebuildInlineLevelsForFacts = (tokens, facts) => {
163
+ if (!facts || facts.rebuildLevelStart === undefined) {
164
+ rebuildInlineLevels(tokens)
165
+ } else {
166
+ rebuildInlineLevelsFrom(tokens, facts.rebuildLevelStart)
167
+ }
168
+ if (facts) {
169
+ facts.rebuildLevelStart = undefined
170
+ }
171
+ }
172
+
173
+ const createInlineChangeMarker = (facts) => {
174
+ return (startIdx) => {
175
+ markInlineLevelRebuildFrom(facts, startIdx)
176
+ }
177
+ }
178
+
179
+ const finalizeInlineLinkRepairStage = (children, facts, markChangedFrom) => {
180
+ invalidateInlineDerivedCaches(facts)
181
+ if (!mergeBrokenMarksAroundLinks(children, markChangedFrom)) return false
182
+ invalidateInlineDerivedCaches(facts)
183
+ rebuildInlineLevelsForFacts(children, facts)
184
+ return true
185
+ }
186
+
187
+ const BROKEN_REF_REPAIR_HOOKS = {
188
+ ensureLinkCloseMap: ensureInlineLinkCloseMap,
189
+ ensureWrapperPrefixStats: ensureInlineWrapperPrefixStats,
190
+ invalidateDerivedCaches: invalidateInlineDerivedCaches,
191
+ markLevelRebuildFrom: markInlineLevelRebuildFrom
192
+ }
193
+
194
+ const bumpPostprocessMetric = (metrics, bucket, key) => {
195
+ if (!metrics || !bucket || !key) return
196
+ let table = metrics[bucket]
197
+ if (!table || typeof table !== 'object') {
198
+ table = Object.create(null)
199
+ metrics[bucket] = table
200
+ }
201
+ table[key] = (table[key] || 0) + 1
202
+ }
203
+
204
+ const scanTailRepairCandidateAfterLinkClose = (tokens, linkCloseIdx) => {
205
+ if (!tokens || linkCloseIdx < 0 || linkCloseIdx >= tokens.length) return null
206
+ let startIdx = -1
207
+ let foundStrongClose = -1
208
+ let foundStrongOpen = -1
209
+ for (let j = linkCloseIdx + 1; j < tokens.length; j++) {
210
+ const node = tokens[j]
211
+ if (!node) continue
212
+ if (node.type === 'strong_open') {
213
+ foundStrongOpen = j
214
+ break
215
+ }
216
+ if (node.type === 'strong_close') {
217
+ foundStrongClose = j
218
+ break
219
+ }
220
+ if (node.type === 'text' && node.content && startIdx === -1) {
221
+ startIdx = j
222
+ }
223
+ }
224
+ if (foundStrongClose === -1 || foundStrongOpen !== -1) return null
225
+ if (startIdx === -1) startIdx = foundStrongClose
226
+ return { startIdx, strongCloseIdx: foundStrongClose }
227
+ }
228
+
229
+ const tryRepairTailCandidate = (tokens, candidate, isJapaneseMode, metrics = null, onChangeStart = null) => {
230
+ if (!tokens || !candidate) return false
231
+ const startIdx = candidate.startIdx
232
+ const strongCloseIdx = candidate.strongCloseIdx
233
+ const endIdx = tokens.length - 1
234
+ if (isJapaneseMode && !hasJapaneseContextInRange(tokens, startIdx, endIdx)) return false
235
+ if (!hasEmphasisSignalInRange(tokens, startIdx, endIdx)) return false
236
+ if (tryFixTailPatternTokenOnly(tokens, startIdx, endIdx)) {
237
+ if (onChangeStart) onChangeStart(startIdx)
238
+ bumpPostprocessMetric(metrics, 'tailFastPaths', 'tail-pattern')
239
+ return true
240
+ }
241
+ if (tryFixTailDanglingStrongCloseTokenOnly(tokens, startIdx, strongCloseIdx)) {
242
+ if (onChangeStart) onChangeStart(startIdx)
243
+ bumpPostprocessMetric(metrics, 'tailFastPaths', 'tail-dangling-strong-close')
244
+ return true
245
+ }
246
+ return false
247
+ }
248
+
249
+ const fixTailAfterLinkStrongClose = (tokens, isJapaneseMode, metrics = null, onChangeStart = null) => {
250
+ let strongDepth = 0
251
+ for (let i = 0; i < tokens.length; i++) {
252
+ const t = tokens[i]
253
+ if (!t) continue
254
+ if (t.type === 'strong_open') strongDepth++
255
+ if (t.type === 'strong_close') {
256
+ if (strongDepth > 0) strongDepth--
257
+ }
258
+ if (t.type !== 'link_close') continue
259
+ if (strongDepth !== 0) continue
260
+ const candidate = scanTailRepairCandidateAfterLinkClose(tokens, i)
261
+ if (!candidate) continue
262
+ if (tryRepairTailCandidate(tokens, candidate, isJapaneseMode, metrics, onChangeStart)) return true
263
+ }
264
+ return false
265
+ }
266
+
267
+ const cloneMap = (map) => {
268
+ if (!map || !Array.isArray(map)) return null
269
+ return [map[0], map[1]]
270
+ }
271
+
272
+ const cloneTextToken = (source, content) => {
273
+ const token = new Token('text', '', 0)
274
+ Object.assign(token, source)
275
+ token.content = content
276
+ if (source.meta) token.meta = { ...source.meta }
277
+ return token
278
+ }
279
+
280
+ const isSoftSpaceCode = (code) => {
281
+ return code === 0x20 || code === 0x09 || code === 0x3000
282
+ }
283
+
284
+ const isAsciiWordCode = (code) => {
285
+ return (code >= 0x30 && code <= 0x39) ||
286
+ (code >= 0x41 && code <= 0x5A) ||
287
+ (code >= 0x61 && code <= 0x7A)
288
+ }
289
+
290
+ const textEndsAsciiWord = (text) => {
291
+ if (!text || text.length === 0) return false
292
+ return isAsciiWordCode(text.charCodeAt(text.length - 1))
293
+ }
294
+
295
+ const textStartsAsciiWord = (text) => {
296
+ if (!text || text.length === 0) return false
297
+ return isAsciiWordCode(text.charCodeAt(0))
298
+ }
299
+
300
+ const isEscapedMarkerAt = (content, index) => {
301
+ let slashCount = 0
302
+ for (let i = index - 1; i >= 0 && content.charCodeAt(i) === 0x5C; i--) {
303
+ slashCount++
304
+ }
305
+ return (slashCount % 2) === 1
306
+ }
307
+
308
+ const findLastStandaloneStrongMarker = (content) => {
309
+ if (!content || content.length < 2) return -1
310
+ let pos = content.lastIndexOf('**')
311
+ while (pos !== -1) {
312
+ const prev = pos > 0 ? content.charCodeAt(pos - 1) : 0
313
+ const next = pos + 2 < content.length ? content.charCodeAt(pos + 2) : 0
314
+ if (prev !== 0x2A &&
315
+ next !== 0x2A &&
316
+ !isEscapedMarkerAt(content, pos)) {
317
+ return pos
318
+ }
319
+ pos = content.lastIndexOf('**', pos - 1)
320
+ }
321
+ return -1
322
+ }
323
+
324
+ const hasLeadingStandaloneStrongMarker = (content) => {
325
+ if (!content || content.length < 2) return false
326
+ if (content.charCodeAt(0) !== 0x2A || content.charCodeAt(1) !== 0x2A) return false
327
+ if (content.length > 2 && content.charCodeAt(2) === 0x2A) return false
328
+ return true
329
+ }
330
+
331
+ const tryPromoteStrongAroundInlineLink = (tokens, strictAsciiStrongGuard = false, facts = null) => {
332
+ if (!tokens || tokens.length < 3) return false
333
+ let changed = false
334
+ for (let i = 1; i < tokens.length - 1; i++) {
335
+ const linkOpen = tokens[i]
336
+ if (!linkOpen || linkOpen.type !== 'link_open') continue
337
+ const linkCloseMap = ensureInlineLinkCloseMap(facts, tokens)
338
+ const closeIdx = linkCloseMap.get(i) ?? -1
339
+ if (closeIdx === -1 || closeIdx + 1 >= tokens.length) continue
340
+
341
+ const left = tokens[i - 1]
342
+ const right = tokens[closeIdx + 1]
343
+ if (!left || left.type !== 'text' || !left.content) {
344
+ i = closeIdx
345
+ continue
346
+ }
347
+ if (!right || right.type !== 'text' || !right.content) {
348
+ i = closeIdx
349
+ continue
350
+ }
351
+ if (!hasLeadingStandaloneStrongMarker(right.content)) {
352
+ i = closeIdx
353
+ continue
354
+ }
355
+ const markerPos = findLastStandaloneStrongMarker(left.content)
356
+ if (markerPos === -1) {
357
+ i = closeIdx
358
+ continue
359
+ }
360
+
361
+ const prefix = left.content.slice(0, markerPos)
362
+ const leftInner = left.content.slice(markerPos + 2)
363
+ if (leftInner && isSoftSpaceCode(leftInner.charCodeAt(0))) {
364
+ i = closeIdx
365
+ continue
366
+ }
367
+ const rightTail = right.content.slice(2)
368
+ if (strictAsciiStrongGuard &&
369
+ (textEndsAsciiWord(prefix) || textStartsAsciiWord(rightTail))) {
370
+ i = closeIdx
371
+ continue
372
+ }
373
+
374
+ const replacement = []
375
+ if (prefix) replacement.push(cloneTextToken(left, prefix))
376
+
377
+ const strongOpen = new Token('strong_open', 'strong', 1)
378
+ strongOpen.markup = '**'
379
+ strongOpen.map = cloneMap(left.map) || cloneMap(linkOpen.map) || cloneMap(right.map) || null
380
+ replacement.push(strongOpen)
381
+
382
+ if (leftInner) replacement.push(cloneTextToken(left, leftInner))
383
+ for (let j = i; j <= closeIdx; j++) replacement.push(tokens[j])
384
+
385
+ const strongClose = new Token('strong_close', 'strong', -1)
386
+ strongClose.markup = '**'
387
+ strongClose.map = cloneMap(right.map) || cloneMap(linkOpen.map) || cloneMap(left.map) || null
388
+ replacement.push(strongClose)
389
+
390
+ if (rightTail) replacement.push(cloneTextToken(right, rightTail))
391
+
392
+ tokens.splice(i - 1, closeIdx - i + 3, ...replacement)
393
+ changed = true
394
+ invalidateInlineDerivedCaches(facts)
395
+ markInlineLevelRebuildFrom(facts, i - 1)
396
+ i = i - 1 + replacement.length - 1
397
+ }
398
+ return changed
399
+ }
400
+
401
+ const tryPromoteStrongAroundInlineCode = (
402
+ tokens,
403
+ strictAsciiCodeGuard = false,
404
+ strictAsciiStrongGuard = false,
405
+ facts = null
406
+ ) => {
407
+ if (!tokens || tokens.length < 3) return false
408
+ let changed = false
409
+ for (let i = 0; i <= tokens.length - 3; i++) {
410
+ const left = tokens[i]
411
+ const code = tokens[i + 1]
412
+ const right = tokens[i + 2]
413
+ if (!left || !code || !right) continue
414
+ if (left.type !== 'text' || !left.content) continue
415
+ if (code.type !== 'code_inline') continue
416
+ if (right.type !== 'text' || !right.content) continue
417
+ if (!hasLeadingStandaloneStrongMarker(right.content)) continue
418
+ const markerPos = findLastStandaloneStrongMarker(left.content)
419
+ if (markerPos === -1) continue
420
+
421
+ const prefix = left.content.slice(0, markerPos)
422
+ const leftInner = left.content.slice(markerPos + 2)
423
+ const rightTail = right.content.slice(2)
424
+ if (strictAsciiStrongGuard &&
425
+ (textEndsAsciiWord(prefix) || textStartsAsciiWord(rightTail))) {
426
+ continue
427
+ }
428
+ if (strictAsciiCodeGuard &&
429
+ leftInner &&
430
+ isSoftSpaceCode(leftInner.charCodeAt(0)) &&
431
+ code.content &&
432
+ isAsciiWordCode(code.content.charCodeAt(0))) {
433
+ continue
434
+ }
435
+
436
+ const replacement = []
437
+ if (prefix) replacement.push(cloneTextToken(left, prefix))
438
+
439
+ const strongOpen = new Token('strong_open', 'strong', 1)
440
+ strongOpen.markup = '**'
441
+ strongOpen.map = cloneMap(left.map) || cloneMap(code.map) || cloneMap(right.map) || null
442
+ replacement.push(strongOpen)
443
+
444
+ if (leftInner) replacement.push(cloneTextToken(left, leftInner))
445
+ replacement.push(code)
446
+
447
+ const strongClose = new Token('strong_close', 'strong', -1)
448
+ strongClose.markup = '**'
449
+ strongClose.map = cloneMap(right.map) || cloneMap(code.map) || cloneMap(left.map) || null
450
+ replacement.push(strongClose)
451
+
452
+ if (rightTail) replacement.push(cloneTextToken(right, rightTail))
453
+
454
+ tokens.splice(i, 3, ...replacement)
455
+ changed = true
456
+ invalidateInlineDerivedCaches(facts)
457
+ markInlineLevelRebuildFrom(facts, i)
458
+ i += replacement.length - 1
459
+ }
460
+ return changed
461
+ }
462
+
463
+ const tryActivateInlineEmphasis = (
464
+ children,
465
+ facts,
466
+ strictAsciiCodeGuard,
467
+ strictAsciiStrongGuard
468
+ ) => {
469
+ if (!facts || facts.hasEmphasis) return false
470
+ if (facts.hasLinkOpen &&
471
+ facts.hasLinkClose &&
472
+ tryPromoteStrongAroundInlineLink(children, strictAsciiStrongGuard, facts)) {
473
+ facts.hasEmphasis = true
474
+ return true
475
+ }
476
+ if (facts.hasBracketText || facts.hasLinkOpen || facts.hasLinkClose) return false
477
+ if (!ensureInlineHasCodeInline(facts, children)) return false
478
+ if (tryPromoteStrongAroundInlineCode(children, strictAsciiCodeGuard, strictAsciiStrongGuard, facts)) {
479
+ facts.hasEmphasis = true
480
+ return true
481
+ }
482
+ return false
483
+ }
484
+
485
+ const shouldRunInlineBrokenRefRepair = (facts, inlineContent, state) => {
486
+ if (!facts || !facts.hasLinkOpen || !facts.hasLinkClose || !facts.hasBracketText) return false
487
+ if (inlineContent.indexOf('***') !== -1) return false
488
+ return ensureInlineReferenceCount(facts, state) > 0
489
+ }
490
+
491
+ const applyBrokenRefRepairFacts = (facts, repairs) => {
492
+ if (!facts || !repairs) return
493
+ facts.hasBracketText = repairs.hasBracketText
494
+ facts.hasEmphasis = repairs.hasEmphasis
495
+ facts.hasLinkClose = repairs.hasLinkClose
496
+ }
497
+
498
+ const createBrokenRefScanState = () => {
499
+ return { depth: 0, brokenEnd: false, tailOpen: -1 }
500
+ }
501
+
502
+ const runInlineBrokenRefRepairStage = (children, facts, inlineContent, state) => {
503
+ if (!shouldRunInlineBrokenRefRepair(facts, inlineContent, state)) return false
504
+ const scanState = createBrokenRefScanState()
505
+ const maxRepairPass = computeMaxBrokenRefRepairPass(children, scanState)
506
+ if (maxRepairPass <= 0) return false
507
+ const repairs = runBrokenRefRepairs(
508
+ children,
509
+ maxRepairPass,
510
+ scanState,
511
+ ensureInlineMetrics(facts, state),
512
+ facts,
513
+ BROKEN_REF_REPAIR_HOOKS
514
+ )
515
+ applyBrokenRefRepairFacts(facts, repairs)
516
+ return repairs.changed
517
+ }
518
+
519
+ const runInlineEmphasisRepairStage = (children, facts, state, isJapaneseMode) => {
520
+ if (!facts.hasEmphasis) return false
521
+ let changed = false
522
+ const markChangedFrom = createInlineChangeMarker(facts)
523
+ if (fixEmOuterStrongSequence(children, markChangedFrom)) changed = true
524
+ if (facts.hasLinkClose) {
525
+ const metrics = ensureInlineMetrics(facts, state)
526
+ if (fixTailAfterLinkStrongClose(children, isJapaneseMode, metrics, markChangedFrom)) changed = true
527
+ if (fixLeadingAsteriskEm(children, markChangedFrom)) changed = true
528
+ }
529
+ if (fixTrailingStrong(children, markChangedFrom)) changed = true
530
+ if (sanitizeEmStrongBalance(children, markChangedFrom)) changed = true
531
+ return changed
532
+ }
533
+
534
+ const shouldRunInlineCollapsedRefRepair = (facts, state) => {
535
+ if (!facts || !facts.hasBracketText) return false
536
+ return ensureInlineReferenceCount(facts, state) > 0
537
+ }
538
+
539
+ const applyCollapsedRefRepairFacts = (facts) => {
540
+ if (!facts) return
541
+ facts.hasLinkOpen = true
542
+ facts.hasLinkClose = true
543
+ }
544
+
545
+ const rewriteInlineCollapsedReferences = (children, facts, state, markChangedFrom) => {
546
+ const changed = convertCollapsedReferenceLinks(
547
+ children,
548
+ state,
549
+ facts,
550
+ markChangedFrom
551
+ )
552
+ if (!changed) return false
553
+ applyCollapsedRefRepairFacts(facts)
554
+ return true
555
+ }
556
+
557
+ const runInlineCollapsedRefStage = (children, facts, state) => {
558
+ if (!shouldRunInlineCollapsedRefRepair(facts, state)) return false
559
+ const markChangedFrom = createInlineChangeMarker(facts)
560
+ if (!rewriteInlineCollapsedReferences(children, facts, state, markChangedFrom)) return false
561
+ finalizeInlineLinkRepairStage(children, facts, markChangedFrom)
562
+ return true
563
+ }
564
+
565
+ const shouldSkipInlinePostprocessToken = (children, facts, isJapaneseMode) => {
566
+ if (!facts.hasEmphasis &&
567
+ !facts.hasBracketText &&
568
+ !facts.hasLinkOpen &&
569
+ !facts.hasLinkClose &&
570
+ !ensureInlineHasCodeInline(facts, children)) {
571
+ return true
572
+ }
573
+ if (isJapaneseMode &&
574
+ !hasJapaneseContextInRange(children, 0, children.length - 1)) {
575
+ return true
576
+ }
577
+ return false
578
+ }
579
+
580
+ const runInlineCoreRepairStages = (
581
+ children,
582
+ facts,
583
+ inlineContent,
584
+ state,
585
+ isJapaneseMode,
586
+ strictAsciiCodeGuard,
587
+ strictAsciiStrongGuard
588
+ ) => {
589
+ let changed = false
590
+ if (!facts.hasEmphasis && tryActivateInlineEmphasis(
591
+ children,
592
+ facts,
593
+ strictAsciiCodeGuard,
594
+ strictAsciiStrongGuard
595
+ )) {
596
+ changed = true
597
+ } else if (!facts.hasEmphasis && !facts.hasBracketText) {
598
+ return false
599
+ }
600
+ if (runInlineBrokenRefRepairStage(children, facts, inlineContent, state)) changed = true
601
+ if (runInlineEmphasisRepairStage(children, facts, state, isJapaneseMode)) changed = true
602
+ return changed
603
+ }
604
+
605
+ const processInlinePostprocessToken = (
606
+ token,
607
+ inlineContent,
608
+ state,
609
+ isJapaneseMode,
610
+ strictAsciiCodeGuard,
611
+ strictAsciiStrongGuard
612
+ ) => {
613
+ if (!token || token.type !== 'inline' || !token.children || token.children.length === 0) return
614
+ const children = token.children
615
+ const facts = buildInlinePostprocessFacts(children, inlineContent)
616
+ if (shouldSkipInlinePostprocessToken(children, facts, isJapaneseMode)) return
617
+ const changed = runInlineCoreRepairStages(
618
+ children,
619
+ facts,
620
+ inlineContent,
621
+ state,
622
+ isJapaneseMode,
623
+ strictAsciiCodeGuard,
624
+ strictAsciiStrongGuard
625
+ )
626
+ if (changed) rebuildInlineLevelsForFacts(children, facts)
627
+ runInlineCollapsedRefStage(children, facts, state)
628
+ }
629
+
630
+ const processInlinePostprocessStateTokens = (
631
+ state,
632
+ isJapaneseMode,
633
+ strictAsciiCodeGuard,
634
+ strictAsciiStrongGuard
635
+ ) => {
636
+ for (let i = 0; i < state.tokens.length; i++) {
637
+ const token = state.tokens[i]
638
+ if (!token || token.type !== 'inline' || !token.children || token.children.length === 0) continue
639
+ const inlineContent = typeof token.content === 'string' ? token.content : ''
640
+ if (!hasMarkerChars(inlineContent)) continue
641
+ processInlinePostprocessToken(
642
+ token,
643
+ inlineContent,
644
+ state,
645
+ isJapaneseMode,
646
+ strictAsciiCodeGuard,
647
+ strictAsciiStrongGuard
648
+ )
649
+ }
650
+ }
651
+
652
+ const registerTokenPostprocess = (md, baseOpt) => {
653
+ if (md.__strongJaTokenPostprocessRegistered) return
654
+ md.__strongJaTokenPostprocessRegistered = true
655
+ md.core.ruler.after('inline', 'strong_ja_token_postprocess', (state) => {
656
+ if (!state || !state.tokens) return
657
+ const overrideOpt = state.env && state.env.__strongJaTokenOpt
658
+ const opt = overrideOpt ? getRuntimeOpt(state, baseOpt) : baseOpt
659
+ if (!opt.__strongJaPostprocessActive) return
660
+ const isJapaneseMode = opt.__strongJaIsJapaneseMode
661
+ const strictAsciiCodeGuard = opt.__strongJaStrictAsciiCodeGuard
662
+ const strictAsciiStrongGuard = opt.__strongJaStrictAsciiStrongGuard
663
+ processInlinePostprocessStateTokens(
664
+ state,
665
+ isJapaneseMode,
666
+ strictAsciiCodeGuard,
667
+ strictAsciiStrongGuard
668
+ )
669
+ })
670
+ }
671
+
672
+ export { registerTokenPostprocess }