@peaceroad/markdown-it-strong-ja 0.9.0 → 0.9.2
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 +77 -0
- package/package.json +9 -9
- package/src/token-compat.js +9 -12
- package/src/token-core.js +85 -73
- package/src/token-link-utils.js +1 -6
- package/src/token-postprocess/broken-ref.js +113 -24
- package/src/token-postprocess/emphasis-balance.js +50 -0
- package/src/token-postprocess/fastpaths.js +1 -5
- package/src/token-postprocess/guards.js +75 -15
- package/src/token-postprocess/orchestrator.js +89 -119
- package/src/token-utils.js +222 -130
|
@@ -115,14 +115,14 @@ const expandSegmentEndForWrapperBalance = (tokens, startIdx, endIdx) => {
|
|
|
115
115
|
return balance.total > 0 ? -1 : expandedEnd
|
|
116
116
|
}
|
|
117
117
|
|
|
118
|
-
const bumpBrokenRefMetric = (metrics, bucket, key) => {
|
|
119
|
-
if (!metrics || !bucket || !key) return
|
|
118
|
+
const bumpBrokenRefMetric = (metrics, bucket, key, delta = 1) => {
|
|
119
|
+
if (!metrics || !bucket || !key || delta <= 0) return
|
|
120
120
|
let table = metrics[bucket]
|
|
121
121
|
if (!table || typeof table !== 'object') {
|
|
122
122
|
table = Object.create(null)
|
|
123
123
|
metrics[bucket] = table
|
|
124
124
|
}
|
|
125
|
-
table[key] = (table[key] || 0) +
|
|
125
|
+
table[key] = (table[key] || 0) + delta
|
|
126
126
|
}
|
|
127
127
|
|
|
128
128
|
const ensureBrokenRefLinkCloseMap = (tokens, facts = null, hooks = null, fallbackCache = null) => {
|
|
@@ -190,6 +190,7 @@ const resolveBrokenRefCandidateGuardFlow = (
|
|
|
190
190
|
children,
|
|
191
191
|
brokenRefCandidate,
|
|
192
192
|
segmentEnd,
|
|
193
|
+
metrics = null,
|
|
193
194
|
facts = null,
|
|
194
195
|
hooks = null,
|
|
195
196
|
fallbackCache = null
|
|
@@ -203,6 +204,10 @@ const resolveBrokenRefCandidateGuardFlow = (
|
|
|
203
204
|
if (!wrapperSignals.hasTextMarker) {
|
|
204
205
|
return BROKEN_REF_FLOW_SKIP_NO_TEXT_MARKER
|
|
205
206
|
}
|
|
207
|
+
if (!hasBrokenRefActiveFastPathTokenSignal(wrapperSignals)) {
|
|
208
|
+
bumpBrokenRefMetric(metrics, 'brokenRefCandidateFlow', 'no-active-signature')
|
|
209
|
+
return BROKEN_REF_FLOW_SKIP_NO_ACTIVE_SIGNATURE
|
|
210
|
+
}
|
|
206
211
|
const wrapperPrefixStats = ensureBrokenRefWrapperPrefixStats(children, facts, hooks, fallbackCache)
|
|
207
212
|
if (!shouldAttemptBrokenRefRewrite(
|
|
208
213
|
children,
|
|
@@ -214,6 +219,7 @@ const resolveBrokenRefCandidateGuardFlow = (
|
|
|
214
219
|
)) {
|
|
215
220
|
return BROKEN_REF_FLOW_SKIP_GUARD
|
|
216
221
|
}
|
|
222
|
+
bumpBrokenRefMetric(metrics, 'brokenRefCandidateFlow', 'guard-passed')
|
|
217
223
|
return null
|
|
218
224
|
}
|
|
219
225
|
|
|
@@ -232,12 +238,16 @@ const resolveBrokenRefFastPathFlow = (
|
|
|
232
238
|
metrics,
|
|
233
239
|
bumpBrokenRefMetric
|
|
234
240
|
)
|
|
241
|
+
bumpBrokenRefMetric(metrics, 'brokenRefCandidateFlow', 'fastpath-dispatch')
|
|
235
242
|
if (fastPathResult === BROKEN_REF_FAST_PATH_RESULT_NO_ACTIVE_SIGNATURE) {
|
|
243
|
+
bumpBrokenRefMetric(metrics, 'brokenRefCandidateFlow', 'no-active-signature')
|
|
236
244
|
return BROKEN_REF_FLOW_SKIP_NO_ACTIVE_SIGNATURE
|
|
237
245
|
}
|
|
238
246
|
if (fastPathResult === BROKEN_REF_FAST_PATH_RESULT_NO_MATCH) {
|
|
247
|
+
bumpBrokenRefMetric(metrics, 'brokenRefCandidateFlow', 'no-fastpath-match')
|
|
239
248
|
return BROKEN_REF_FLOW_SKIP_NO_FASTPATH_MATCH
|
|
240
249
|
}
|
|
250
|
+
bumpBrokenRefMetric(metrics, 'brokenRefCandidateFlow', 'repaired')
|
|
241
251
|
return BROKEN_REF_FLOW_REPAIRED
|
|
242
252
|
}
|
|
243
253
|
|
|
@@ -256,6 +266,7 @@ const runBrokenRefCandidateRewrite = (
|
|
|
256
266
|
children,
|
|
257
267
|
brokenRefCandidate,
|
|
258
268
|
segmentEnd,
|
|
269
|
+
metrics,
|
|
259
270
|
facts,
|
|
260
271
|
hooks,
|
|
261
272
|
fallbackCache
|
|
@@ -308,7 +319,7 @@ const createBrokenRefPassSignals = (seedSignals = null) => {
|
|
|
308
319
|
const observeBrokenRefTextToken = (passSignals, candidateState, text, tokenIdx, scanState) => {
|
|
309
320
|
const hasOpenBracket = text.indexOf('[') !== -1
|
|
310
321
|
const hasCloseBracket = text.indexOf(']') !== -1
|
|
311
|
-
if (!passSignals.hasBracketText && (hasOpenBracket || hasCloseBracket)) {
|
|
322
|
+
if (passSignals && !passSignals.hasBracketText && (hasOpenBracket || hasCloseBracket)) {
|
|
312
323
|
passSignals.hasBracketText = true
|
|
313
324
|
}
|
|
314
325
|
if (candidateState.start === -1) {
|
|
@@ -383,6 +394,7 @@ const tryRepairBrokenRefCandidateAtLinkOpen = (
|
|
|
383
394
|
const closeIdx = linkCloseMap.get(childIdx) ?? -1
|
|
384
395
|
if (closeIdx === -1) return null
|
|
385
396
|
bumpBrokenRefMetric(metrics, 'brokenRefFlow', 'candidate')
|
|
397
|
+
bumpBrokenRefMetric(metrics, 'brokenRefCandidateFlow', 'candidate')
|
|
386
398
|
const flowResult = runBrokenRefCandidateRewrite(
|
|
387
399
|
children,
|
|
388
400
|
brokenRefCandidate,
|
|
@@ -437,46 +449,123 @@ const runBrokenRefRepairPass = (children, scanState, metrics = null, facts = nul
|
|
|
437
449
|
return buildBrokenRefRepairPassResult(false, passSignals)
|
|
438
450
|
}
|
|
439
451
|
|
|
440
|
-
const
|
|
452
|
+
const hasPotentialBrokenRefRepairPass = (children, scanState) => {
|
|
441
453
|
resetBrokenRefScanState(scanState)
|
|
442
|
-
let maxRepairPass = 0
|
|
443
454
|
for (let j = 0; j < children.length; j++) {
|
|
444
455
|
const child = children[j]
|
|
445
456
|
if (!child || child.type !== 'text' || !child.content) continue
|
|
446
457
|
if (child.content.indexOf('[') === -1) continue
|
|
447
458
|
if (scanBrokenRefState(child.content, scanState).brokenEnd) {
|
|
448
|
-
|
|
459
|
+
return true
|
|
449
460
|
}
|
|
450
461
|
}
|
|
451
|
-
return
|
|
462
|
+
return false
|
|
463
|
+
}
|
|
464
|
+
|
|
465
|
+
const hasBrokenRefActiveFastPathTokenSignal = (wrapperSignals) => {
|
|
466
|
+
if (!wrapperSignals) return false
|
|
467
|
+
// Current broken-ref fast paths are all strong-token driven.
|
|
468
|
+
return wrapperSignals.strongOpenInRange > 0 || wrapperSignals.strongCloseInRange > 0
|
|
452
469
|
}
|
|
453
470
|
|
|
454
|
-
const
|
|
471
|
+
const countGuardedBrokenRefRepairPasses = (children, scanState, facts = null, hooks = null) => {
|
|
472
|
+
resetBrokenRefScanState(scanState)
|
|
473
|
+
const brokenRefCandidate = resetBrokenRefCandidateState({ start: -1, depth: 0, startTextOffset: 0 })
|
|
474
|
+
const fallbackCache = {
|
|
475
|
+
linkCloseMap: undefined,
|
|
476
|
+
wrapperPrefixStats: undefined
|
|
477
|
+
}
|
|
455
478
|
let repairPassCount = 0
|
|
479
|
+
for (let j = 0; j < children.length; j++) {
|
|
480
|
+
const child = children[j]
|
|
481
|
+
if (!child) continue
|
|
482
|
+
if (child.type === 'text' && child.content) {
|
|
483
|
+
observeBrokenRefTextToken(null, brokenRefCandidate, child.content, j, scanState)
|
|
484
|
+
}
|
|
485
|
+
if (child.type !== 'link_open' || brokenRefCandidate.start === -1) continue
|
|
486
|
+
if (brokenRefCandidate.depth <= 0) {
|
|
487
|
+
resetBrokenRefCandidateState(brokenRefCandidate)
|
|
488
|
+
continue
|
|
489
|
+
}
|
|
490
|
+
const linkCloseMap = ensureBrokenRefLinkCloseMap(children, facts, hooks, fallbackCache)
|
|
491
|
+
const closeIdx = linkCloseMap.get(j) ?? -1
|
|
492
|
+
if (closeIdx === -1) continue
|
|
493
|
+
const segmentEnd = resolveBrokenRefSegmentEnd(children, brokenRefCandidate, closeIdx)
|
|
494
|
+
const wrapperSignals = buildBrokenRefWrapperRangeSignals(
|
|
495
|
+
children,
|
|
496
|
+
brokenRefCandidate.start,
|
|
497
|
+
segmentEnd,
|
|
498
|
+
brokenRefCandidate.startTextOffset
|
|
499
|
+
)
|
|
500
|
+
if (!wrapperSignals.hasTextMarker || !hasBrokenRefActiveFastPathTokenSignal(wrapperSignals)) {
|
|
501
|
+
resetBrokenRefCandidateState(brokenRefCandidate)
|
|
502
|
+
continue
|
|
503
|
+
}
|
|
504
|
+
const wrapperPrefixStats = ensureBrokenRefWrapperPrefixStats(children, facts, hooks, fallbackCache)
|
|
505
|
+
if (shouldAttemptBrokenRefRewrite(
|
|
506
|
+
children,
|
|
507
|
+
brokenRefCandidate.start,
|
|
508
|
+
segmentEnd,
|
|
509
|
+
brokenRefCandidate.startTextOffset,
|
|
510
|
+
wrapperPrefixStats,
|
|
511
|
+
wrapperSignals
|
|
512
|
+
)) {
|
|
513
|
+
repairPassCount++
|
|
514
|
+
}
|
|
515
|
+
resetBrokenRefCandidateState(brokenRefCandidate)
|
|
516
|
+
}
|
|
517
|
+
return repairPassCount
|
|
518
|
+
}
|
|
519
|
+
|
|
520
|
+
const buildBrokenRefRepairsResult = (changed, passSignals) => {
|
|
521
|
+
return {
|
|
522
|
+
changed,
|
|
523
|
+
hasBracketText: passSignals.hasBracketText,
|
|
524
|
+
hasEmphasis: passSignals.hasEmphasis,
|
|
525
|
+
hasLinkClose: passSignals.hasLinkClose
|
|
526
|
+
}
|
|
527
|
+
}
|
|
528
|
+
|
|
529
|
+
const runBrokenRefRepairs = (children, scanState, metrics = null, facts = null, hooks = null) => {
|
|
530
|
+
const seedSignals = createBrokenRefPassSignals(createBrokenRefSignalSeed(facts))
|
|
531
|
+
if (!hasPotentialBrokenRefRepairPass(children, scanState)) {
|
|
532
|
+
return buildBrokenRefRepairsResult(false, seedSignals)
|
|
533
|
+
}
|
|
534
|
+
|
|
456
535
|
let changed = false
|
|
457
|
-
|
|
458
|
-
|
|
536
|
+
bumpBrokenRefMetric(metrics, 'brokenRefPasses', 'budgeted')
|
|
537
|
+
bumpBrokenRefMetric(metrics, 'brokenRefPasses', 'executed')
|
|
538
|
+
|
|
539
|
+
let pass = runBrokenRefRepairPass(children, scanState, metrics, facts, hooks)
|
|
540
|
+
if (!pass.didRepair) {
|
|
541
|
+
bumpBrokenRefMetric(metrics, 'brokenRefPasses', 'stopped-no-repair')
|
|
542
|
+
return buildBrokenRefRepairsResult(changed, pass)
|
|
543
|
+
}
|
|
544
|
+
|
|
545
|
+
changed = true
|
|
546
|
+
bumpBrokenRefMetric(metrics, 'brokenRefPasses', 'repaired')
|
|
547
|
+
|
|
548
|
+
const remainingBudget = countGuardedBrokenRefRepairPasses(children, scanState, facts, hooks)
|
|
549
|
+
if (remainingBudget > 0) {
|
|
550
|
+
bumpBrokenRefMetric(metrics, 'brokenRefPasses', 'budgeted', remainingBudget)
|
|
551
|
+
}
|
|
552
|
+
|
|
553
|
+
let repairPassCount = 0
|
|
554
|
+
while (repairPassCount < remainingBudget) {
|
|
555
|
+
bumpBrokenRefMetric(metrics, 'brokenRefPasses', 'executed')
|
|
556
|
+
pass = runBrokenRefRepairPass(children, scanState, metrics, facts, hooks)
|
|
459
557
|
if (!pass.didRepair) {
|
|
460
|
-
|
|
461
|
-
|
|
462
|
-
hasBracketText: pass.hasBracketText,
|
|
463
|
-
hasEmphasis: pass.hasEmphasis,
|
|
464
|
-
hasLinkClose: pass.hasLinkClose
|
|
465
|
-
}
|
|
558
|
+
bumpBrokenRefMetric(metrics, 'brokenRefPasses', 'stopped-no-repair')
|
|
559
|
+
return buildBrokenRefRepairsResult(changed, pass)
|
|
466
560
|
}
|
|
467
561
|
changed = true
|
|
468
562
|
repairPassCount++
|
|
563
|
+
bumpBrokenRefMetric(metrics, 'brokenRefPasses', 'repaired')
|
|
469
564
|
}
|
|
470
565
|
const finalSignals = collectBrokenRefPassSignals(children, createBrokenRefSignalSeed(facts))
|
|
471
|
-
return
|
|
472
|
-
changed,
|
|
473
|
-
hasBracketText: finalSignals.hasBracketText,
|
|
474
|
-
hasEmphasis: finalSignals.hasEmphasis,
|
|
475
|
-
hasLinkClose: finalSignals.hasLinkClose
|
|
476
|
-
}
|
|
566
|
+
return buildBrokenRefRepairsResult(changed, finalSignals)
|
|
477
567
|
}
|
|
478
568
|
|
|
479
569
|
export {
|
|
480
|
-
computeMaxBrokenRefRepairPass,
|
|
481
570
|
runBrokenRefRepairs
|
|
482
571
|
}
|
|
@@ -0,0 +1,50 @@
|
|
|
1
|
+
const fallbackMarkupByType = (type) => {
|
|
2
|
+
if (type === 'strong_open' || type === 'strong_close') return '**'
|
|
3
|
+
if (type === 'em_open' || type === 'em_close') return '*'
|
|
4
|
+
return ''
|
|
5
|
+
}
|
|
6
|
+
|
|
7
|
+
const makeTokenLiteralText = (token) => {
|
|
8
|
+
if (!token) return
|
|
9
|
+
const literal = token.markup || fallbackMarkupByType(token.type)
|
|
10
|
+
token.type = 'text'
|
|
11
|
+
token.tag = ''
|
|
12
|
+
token.nesting = 0
|
|
13
|
+
token.content = literal
|
|
14
|
+
token.markup = ''
|
|
15
|
+
token.info = ''
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
const sanitizeEmStrongBalance = (tokens, onChangeStart = null) => {
|
|
19
|
+
if (!tokens || tokens.length === 0) return false
|
|
20
|
+
const stack = []
|
|
21
|
+
let changed = false
|
|
22
|
+
for (let i = 0; i < tokens.length; i++) {
|
|
23
|
+
const token = tokens[i]
|
|
24
|
+
if (!token || !token.type) continue
|
|
25
|
+
if (token.type === 'strong_open' || token.type === 'em_open') {
|
|
26
|
+
stack.push({ type: token.type, idx: i })
|
|
27
|
+
continue
|
|
28
|
+
}
|
|
29
|
+
if (token.type !== 'strong_close' && token.type !== 'em_close') continue
|
|
30
|
+
const expected = token.type === 'strong_close' ? 'strong_open' : 'em_open'
|
|
31
|
+
if (stack.length > 0 && stack[stack.length - 1].type === expected) {
|
|
32
|
+
stack.pop()
|
|
33
|
+
continue
|
|
34
|
+
}
|
|
35
|
+
if (onChangeStart) onChangeStart(i)
|
|
36
|
+
makeTokenLiteralText(token)
|
|
37
|
+
changed = true
|
|
38
|
+
}
|
|
39
|
+
for (let i = stack.length - 1; i >= 0; i--) {
|
|
40
|
+
const entry = stack[i]
|
|
41
|
+
const token = tokens[entry.idx]
|
|
42
|
+
if (!token) continue
|
|
43
|
+
if (onChangeStart) onChangeStart(entry.idx)
|
|
44
|
+
makeTokenLiteralText(token)
|
|
45
|
+
changed = true
|
|
46
|
+
}
|
|
47
|
+
return changed
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
export { sanitizeEmStrongBalance }
|
|
@@ -1,9 +1,5 @@
|
|
|
1
1
|
import Token from 'markdown-it/lib/token.mjs'
|
|
2
|
-
|
|
3
|
-
const cloneMap = (map) => {
|
|
4
|
-
if (!map || !Array.isArray(map)) return null
|
|
5
|
-
return [map[0], map[1]]
|
|
6
|
-
}
|
|
2
|
+
import { cloneMap } from '../token-utils.js'
|
|
7
3
|
|
|
8
4
|
const cloneTextLike = (source, content) => {
|
|
9
5
|
const token = new Token('text', '', 0)
|
|
@@ -1,6 +1,11 @@
|
|
|
1
|
-
import { isJapaneseChar } from '../token-utils.js'
|
|
1
|
+
import { codePointAtSafe, codePointBeforeSafe, codePointSize, isJapaneseChar } from '../token-utils.js'
|
|
2
2
|
|
|
3
3
|
const CHAR_ASTERISK = 0x2A // *
|
|
4
|
+
const INLINE_REPAIR_EM_OUTER_STRONG_SEQUENCE = 1 << 0
|
|
5
|
+
const INLINE_REPAIR_TAIL_AFTER_LINK = 1 << 1
|
|
6
|
+
const INLINE_REPAIR_LEADING_ASTERISK_EM = 1 << 2
|
|
7
|
+
const INLINE_REPAIR_TRAILING_STRONG = 1 << 3
|
|
8
|
+
const INLINE_REPAIR_BALANCE_SANITIZE = 1 << 4
|
|
4
9
|
|
|
5
10
|
const hasMarkerChars = (text) => {
|
|
6
11
|
return !!text && text.indexOf('*') !== -1
|
|
@@ -41,11 +46,13 @@ const tokenHasJapaneseChars = (token) => {
|
|
|
41
46
|
return token.__strongJaHasJapaneseChar
|
|
42
47
|
}
|
|
43
48
|
let hasJapanese = false
|
|
44
|
-
for (let i = 0; i < content.length;
|
|
45
|
-
|
|
49
|
+
for (let i = 0; i < content.length;) {
|
|
50
|
+
const code = codePointAtSafe(content, i)
|
|
51
|
+
if (isJapaneseChar(code)) {
|
|
46
52
|
hasJapanese = true
|
|
47
53
|
break
|
|
48
54
|
}
|
|
55
|
+
i += codePointSize(code)
|
|
49
56
|
}
|
|
50
57
|
token.__strongJaJapaneseSource = content
|
|
51
58
|
token.__strongJaHasJapaneseChar = hasJapanese
|
|
@@ -98,9 +105,9 @@ const countDelimiterLikeStrongRuns = (content, from = 0, limit = 0) => {
|
|
|
98
105
|
continue
|
|
99
106
|
}
|
|
100
107
|
const pos = at
|
|
101
|
-
const prevCode = pos
|
|
108
|
+
const prevCode = codePointBeforeSafe(content, pos, 0)
|
|
102
109
|
const nextPos = pos + 2
|
|
103
|
-
const nextCode =
|
|
110
|
+
const nextCode = codePointAtSafe(content, nextPos, 0)
|
|
104
111
|
const prevSameMarker = prevCode === CHAR_ASTERISK
|
|
105
112
|
const nextSameMarker = nextCode === CHAR_ASTERISK
|
|
106
113
|
if (prevSameMarker || nextSameMarker) {
|
|
@@ -389,13 +396,9 @@ const hasBrokenRefImmediateRewriteSignal = (wrapperSignals) => {
|
|
|
389
396
|
return wrapperSignals.hasImbalance && hasBrokenRefExplicitAsteriskSignal(wrapperSignals)
|
|
390
397
|
}
|
|
391
398
|
|
|
392
|
-
const shouldRejectBalancedBrokenRefRewrite = (wrapperSignals) => {
|
|
393
|
-
return !wrapperSignals.hasImbalance && hasBrokenRefExplicitAsteriskSignal(wrapperSignals)
|
|
394
|
-
}
|
|
395
|
-
|
|
396
399
|
const shouldAttemptBrokenRefRewriteFromSignals = (wrapperSignals) => {
|
|
397
400
|
if (hasBrokenRefImmediateRewriteSignal(wrapperSignals)) return true
|
|
398
|
-
if (
|
|
401
|
+
if (!wrapperSignals.hasImbalance && hasBrokenRefExplicitAsteriskSignal(wrapperSignals)) return false
|
|
399
402
|
return hasBrokenRefStrongRunEvidence(wrapperSignals)
|
|
400
403
|
}
|
|
401
404
|
|
|
@@ -413,16 +416,47 @@ const shouldAttemptBrokenRefRewrite = (
|
|
|
413
416
|
return shouldAttemptBrokenRefRewriteFromSignals(signals)
|
|
414
417
|
}
|
|
415
418
|
|
|
416
|
-
const scanInlinePostprocessSignals = (children) => {
|
|
419
|
+
const scanInlinePostprocessSignals = (children, collectJapaneseContext = false) => {
|
|
417
420
|
let hasEmphasis = false
|
|
418
421
|
let hasLinkOpen = false
|
|
419
422
|
let hasLinkClose = false
|
|
420
423
|
let hasCodeInline = false
|
|
424
|
+
let hasJapaneseContext = false
|
|
425
|
+
let hasTextStrongMarker = false
|
|
426
|
+
let strongOpenCount = 0
|
|
427
|
+
let strongCloseCount = 0
|
|
428
|
+
let emOpenCount = 0
|
|
429
|
+
let emCloseCount = 0
|
|
430
|
+
let hasAsteriskWrapperImbalance = false
|
|
431
|
+
const emphasisStack = []
|
|
421
432
|
for (let j = 0; j < children.length; j++) {
|
|
422
433
|
const child = children[j]
|
|
423
434
|
if (!child) continue
|
|
424
|
-
if (!
|
|
435
|
+
if (collectJapaneseContext && !hasJapaneseContext && tokenHasJapaneseChars(child)) {
|
|
436
|
+
hasJapaneseContext = true
|
|
437
|
+
}
|
|
438
|
+
if (!hasTextStrongMarker && child.type === 'text' && child.content && child.content.indexOf('**') !== -1) {
|
|
439
|
+
hasTextStrongMarker = true
|
|
440
|
+
}
|
|
441
|
+
const isAsteriskEmphasis = isAsteriskEmphasisToken(child)
|
|
442
|
+
if (isAsteriskEmphasis) {
|
|
425
443
|
hasEmphasis = true
|
|
444
|
+
if (child.type === 'strong_open') strongOpenCount++
|
|
445
|
+
else if (child.type === 'strong_close') strongCloseCount++
|
|
446
|
+
else if (child.type === 'em_open') emOpenCount++
|
|
447
|
+
else if (child.type === 'em_close') emCloseCount++
|
|
448
|
+
if (!hasAsteriskWrapperImbalance) {
|
|
449
|
+
if (child.type === 'strong_open' || child.type === 'em_open') {
|
|
450
|
+
emphasisStack.push(child.type)
|
|
451
|
+
} else {
|
|
452
|
+
const expected = child.type === 'strong_close' ? 'strong_open' : 'em_open'
|
|
453
|
+
if (emphasisStack.length > 0 && emphasisStack[emphasisStack.length - 1] === expected) {
|
|
454
|
+
emphasisStack.pop()
|
|
455
|
+
} else {
|
|
456
|
+
hasAsteriskWrapperImbalance = true
|
|
457
|
+
}
|
|
458
|
+
}
|
|
459
|
+
}
|
|
426
460
|
}
|
|
427
461
|
if (!hasLinkOpen && child.type === 'link_open') {
|
|
428
462
|
hasLinkOpen = true
|
|
@@ -433,13 +467,34 @@ const scanInlinePostprocessSignals = (children) => {
|
|
|
433
467
|
if (!hasCodeInline && child.type === 'code_inline') {
|
|
434
468
|
hasCodeInline = true
|
|
435
469
|
}
|
|
436
|
-
|
|
470
|
+
}
|
|
471
|
+
if (!hasAsteriskWrapperImbalance && emphasisStack.length > 0) {
|
|
472
|
+
hasAsteriskWrapperImbalance = true
|
|
473
|
+
}
|
|
474
|
+
let repairMask = 0
|
|
475
|
+
if (emOpenCount >= 2 && emCloseCount >= 2 && strongOpenCount > 0) {
|
|
476
|
+
repairMask |= INLINE_REPAIR_EM_OUTER_STRONG_SEQUENCE
|
|
477
|
+
}
|
|
478
|
+
if (hasLinkClose && strongCloseCount > 0) {
|
|
479
|
+
repairMask |= INLINE_REPAIR_TAIL_AFTER_LINK
|
|
480
|
+
}
|
|
481
|
+
if (hasLinkClose && emCloseCount > 0) {
|
|
482
|
+
repairMask |= INLINE_REPAIR_LEADING_ASTERISK_EM
|
|
483
|
+
}
|
|
484
|
+
if (emOpenCount > 0 && emCloseCount > 0 && hasTextStrongMarker) {
|
|
485
|
+
repairMask |= INLINE_REPAIR_TRAILING_STRONG
|
|
486
|
+
}
|
|
487
|
+
if (hasAsteriskWrapperImbalance) {
|
|
488
|
+
repairMask |= INLINE_REPAIR_BALANCE_SANITIZE
|
|
437
489
|
}
|
|
438
490
|
return {
|
|
439
491
|
hasEmphasis,
|
|
440
492
|
hasLinkOpen,
|
|
441
493
|
hasLinkClose,
|
|
442
|
-
hasCodeInline
|
|
494
|
+
hasCodeInline,
|
|
495
|
+
hasJapaneseContext,
|
|
496
|
+
repairMask,
|
|
497
|
+
hasAsteriskWrapperImbalance
|
|
443
498
|
}
|
|
444
499
|
}
|
|
445
500
|
|
|
@@ -451,5 +506,10 @@ export {
|
|
|
451
506
|
buildAsteriskWrapperPrefixStats,
|
|
452
507
|
buildBrokenRefWrapperRangeSignals,
|
|
453
508
|
shouldAttemptBrokenRefRewrite,
|
|
454
|
-
scanInlinePostprocessSignals
|
|
509
|
+
scanInlinePostprocessSignals,
|
|
510
|
+
INLINE_REPAIR_EM_OUTER_STRONG_SEQUENCE,
|
|
511
|
+
INLINE_REPAIR_TAIL_AFTER_LINK,
|
|
512
|
+
INLINE_REPAIR_LEADING_ASTERISK_EM,
|
|
513
|
+
INLINE_REPAIR_TRAILING_STRONG,
|
|
514
|
+
INLINE_REPAIR_BALANCE_SANITIZE
|
|
455
515
|
}
|