@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
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import Token from 'markdown-it/lib/token.mjs'
|
|
2
2
|
import { buildLinkCloseMap, convertCollapsedReferenceLinks, mergeBrokenMarksAroundLinks } from '../token-link-utils.js'
|
|
3
|
-
import {
|
|
3
|
+
import { runBrokenRefRepairs } from './broken-ref.js'
|
|
4
4
|
import {
|
|
5
5
|
rebuildInlineLevels,
|
|
6
6
|
rebuildInlineLevelsFrom,
|
|
@@ -11,68 +11,35 @@ import {
|
|
|
11
11
|
import {
|
|
12
12
|
getRuntimeOpt,
|
|
13
13
|
hasRuntimeOverride,
|
|
14
|
-
getReferenceCount
|
|
14
|
+
getReferenceCount,
|
|
15
|
+
isAsciiWordCode,
|
|
16
|
+
isSoftSpaceCode,
|
|
17
|
+
cloneMap
|
|
15
18
|
} from '../token-utils.js'
|
|
16
19
|
import {
|
|
17
20
|
hasMarkerChars,
|
|
18
21
|
hasJapaneseContextInRange,
|
|
19
22
|
hasEmphasisSignalInRange,
|
|
20
23
|
buildAsteriskWrapperPrefixStats,
|
|
21
|
-
scanInlinePostprocessSignals
|
|
24
|
+
scanInlinePostprocessSignals,
|
|
25
|
+
INLINE_REPAIR_EM_OUTER_STRONG_SEQUENCE,
|
|
26
|
+
INLINE_REPAIR_TAIL_AFTER_LINK,
|
|
27
|
+
INLINE_REPAIR_LEADING_ASTERISK_EM,
|
|
28
|
+
INLINE_REPAIR_TRAILING_STRONG,
|
|
29
|
+
INLINE_REPAIR_BALANCE_SANITIZE
|
|
22
30
|
} from './guards.js'
|
|
23
31
|
import {
|
|
24
32
|
tryFixTailPatternTokenOnly,
|
|
25
33
|
tryFixTailDanglingStrongCloseTokenOnly
|
|
26
34
|
} from './fastpaths.js'
|
|
35
|
+
import { sanitizeEmStrongBalance } from './emphasis-balance.js'
|
|
27
36
|
|
|
28
|
-
const
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
const makeTokenLiteralText = (token) => {
|
|
35
|
-
if (!token) return
|
|
36
|
-
const literal = token.markup || fallbackMarkupByType(token.type)
|
|
37
|
-
token.type = 'text'
|
|
38
|
-
token.tag = ''
|
|
39
|
-
token.nesting = 0
|
|
40
|
-
token.content = literal
|
|
41
|
-
token.markup = ''
|
|
42
|
-
token.info = ''
|
|
43
|
-
}
|
|
44
|
-
|
|
45
|
-
const sanitizeEmStrongBalance = (tokens, onChangeStart = null) => {
|
|
46
|
-
if (!tokens || tokens.length === 0) return false
|
|
47
|
-
const stack = []
|
|
48
|
-
let changed = false
|
|
49
|
-
for (let i = 0; i < tokens.length; i++) {
|
|
50
|
-
const token = tokens[i]
|
|
51
|
-
if (!token || !token.type) continue
|
|
52
|
-
if (token.type === 'strong_open' || token.type === 'em_open') {
|
|
53
|
-
stack.push({ type: token.type, idx: i })
|
|
54
|
-
continue
|
|
55
|
-
}
|
|
56
|
-
if (token.type !== 'strong_close' && token.type !== 'em_close') continue
|
|
57
|
-
const expected = token.type === 'strong_close' ? 'strong_open' : 'em_open'
|
|
58
|
-
if (stack.length > 0 && stack[stack.length - 1].type === expected) {
|
|
59
|
-
stack.pop()
|
|
60
|
-
continue
|
|
61
|
-
}
|
|
62
|
-
if (onChangeStart) onChangeStart(i)
|
|
63
|
-
makeTokenLiteralText(token)
|
|
64
|
-
changed = true
|
|
65
|
-
}
|
|
66
|
-
for (let i = stack.length - 1; i >= 0; i--) {
|
|
67
|
-
const entry = stack[i]
|
|
68
|
-
const token = tokens[entry.idx]
|
|
69
|
-
if (!token) continue
|
|
70
|
-
if (onChangeStart) onChangeStart(entry.idx)
|
|
71
|
-
makeTokenLiteralText(token)
|
|
72
|
-
changed = true
|
|
73
|
-
}
|
|
74
|
-
return changed
|
|
75
|
-
}
|
|
37
|
+
const INLINE_REPAIR_ALL_EMPHASIS_FIXERS =
|
|
38
|
+
INLINE_REPAIR_EM_OUTER_STRONG_SEQUENCE |
|
|
39
|
+
INLINE_REPAIR_TAIL_AFTER_LINK |
|
|
40
|
+
INLINE_REPAIR_LEADING_ASTERISK_EM |
|
|
41
|
+
INLINE_REPAIR_TRAILING_STRONG |
|
|
42
|
+
INLINE_REPAIR_BALANCE_SANITIZE
|
|
76
43
|
|
|
77
44
|
const getPostprocessMetrics = (state) => {
|
|
78
45
|
if (!state || !state.env) return null
|
|
@@ -81,14 +48,17 @@ const getPostprocessMetrics = (state) => {
|
|
|
81
48
|
return metrics
|
|
82
49
|
}
|
|
83
50
|
|
|
84
|
-
const buildInlinePostprocessFacts = (children, inlineContent) => {
|
|
85
|
-
const preScan = scanInlinePostprocessSignals(children)
|
|
51
|
+
const buildInlinePostprocessFacts = (children, inlineContent, collectJapaneseContext) => {
|
|
52
|
+
const preScan = scanInlinePostprocessSignals(children, collectJapaneseContext)
|
|
86
53
|
return {
|
|
87
54
|
hasBracketText: inlineContent.indexOf('[') !== -1 || inlineContent.indexOf(']') !== -1,
|
|
88
55
|
hasEmphasis: preScan.hasEmphasis,
|
|
56
|
+
hasAsteriskWrapperImbalance: preScan.hasAsteriskWrapperImbalance,
|
|
89
57
|
hasLinkOpen: preScan.hasLinkOpen,
|
|
90
58
|
hasLinkClose: preScan.hasLinkClose,
|
|
91
59
|
hasCodeInline: preScan.hasCodeInline,
|
|
60
|
+
hasJapaneseContext: preScan.hasJapaneseContext,
|
|
61
|
+
repairMask: preScan.repairMask,
|
|
92
62
|
linkCloseMap: undefined,
|
|
93
63
|
wrapperPrefixStats: undefined,
|
|
94
64
|
rebuildLevelStart: undefined
|
|
@@ -159,14 +129,14 @@ const BROKEN_REF_REPAIR_HOOKS = {
|
|
|
159
129
|
markLevelRebuildFrom: markInlineLevelRebuildFrom
|
|
160
130
|
}
|
|
161
131
|
|
|
162
|
-
const bumpPostprocessMetric = (metrics, bucket, key) => {
|
|
163
|
-
if (!metrics || !bucket || !key) return
|
|
132
|
+
const bumpPostprocessMetric = (metrics, bucket, key, delta = 1) => {
|
|
133
|
+
if (!metrics || !bucket || !key || delta <= 0) return
|
|
164
134
|
let table = metrics[bucket]
|
|
165
135
|
if (!table || typeof table !== 'object') {
|
|
166
136
|
table = Object.create(null)
|
|
167
137
|
metrics[bucket] = table
|
|
168
138
|
}
|
|
169
|
-
table[key] = (table[key] || 0) +
|
|
139
|
+
table[key] = (table[key] || 0) + delta
|
|
170
140
|
}
|
|
171
141
|
|
|
172
142
|
const scanTailRepairCandidateAfterLinkClose = (tokens, linkCloseIdx) => {
|
|
@@ -232,11 +202,6 @@ const fixTailAfterLinkStrongClose = (tokens, isJapaneseMode, metrics = null, onC
|
|
|
232
202
|
return false
|
|
233
203
|
}
|
|
234
204
|
|
|
235
|
-
const cloneMap = (map) => {
|
|
236
|
-
if (!map || !Array.isArray(map)) return null
|
|
237
|
-
return [map[0], map[1]]
|
|
238
|
-
}
|
|
239
|
-
|
|
240
205
|
const cloneTextToken = (source, content) => {
|
|
241
206
|
const token = new Token('text', '', 0)
|
|
242
207
|
Object.assign(token, source)
|
|
@@ -245,19 +210,9 @@ const cloneTextToken = (source, content) => {
|
|
|
245
210
|
return token
|
|
246
211
|
}
|
|
247
212
|
|
|
248
|
-
const isSoftSpaceCode = (code) => {
|
|
249
|
-
return code === 0x20 || code === 0x09 || code === 0x3000
|
|
250
|
-
}
|
|
251
|
-
|
|
252
213
|
const CHAR_ASTERISK = 0x2A // *
|
|
253
214
|
const CHAR_BACKSLASH = 0x5C // \
|
|
254
215
|
|
|
255
|
-
const isAsciiWordCode = (code) => {
|
|
256
|
-
return (code >= 0x30 && code <= 0x39) ||
|
|
257
|
-
(code >= 0x41 && code <= 0x5A) ||
|
|
258
|
-
(code >= 0x61 && code <= 0x7A)
|
|
259
|
-
}
|
|
260
|
-
|
|
261
216
|
const textEndsAsciiWord = (text) => {
|
|
262
217
|
if (!text || text.length === 0) return false
|
|
263
218
|
return isAsciiWordCode(text.charCodeAt(text.length - 1))
|
|
@@ -459,46 +414,78 @@ const shouldRunInlineBrokenRefRepair = (facts, inlineContent, state) => {
|
|
|
459
414
|
return getReferenceCount(state) > 0
|
|
460
415
|
}
|
|
461
416
|
|
|
462
|
-
const applyBrokenRefRepairFacts = (facts, repairs) => {
|
|
463
|
-
if (!facts || !repairs) return
|
|
464
|
-
facts.hasBracketText = repairs.hasBracketText
|
|
465
|
-
facts.hasEmphasis = repairs.hasEmphasis
|
|
466
|
-
facts.hasLinkClose = repairs.hasLinkClose
|
|
467
|
-
}
|
|
468
|
-
|
|
469
|
-
const createBrokenRefScanState = () => {
|
|
470
|
-
return { depth: 0, brokenEnd: false, tailOpen: -1 }
|
|
471
|
-
}
|
|
472
|
-
|
|
473
417
|
const runInlineBrokenRefRepairStage = (children, facts, inlineContent, state) => {
|
|
474
418
|
if (!shouldRunInlineBrokenRefRepair(facts, inlineContent, state)) return false
|
|
475
|
-
const scanState =
|
|
476
|
-
const maxRepairPass = computeMaxBrokenRefRepairPass(children, scanState)
|
|
477
|
-
if (maxRepairPass <= 0) return false
|
|
419
|
+
const scanState = { depth: 0, brokenEnd: false, tailOpen: -1 }
|
|
478
420
|
const repairs = runBrokenRefRepairs(
|
|
479
421
|
children,
|
|
480
|
-
maxRepairPass,
|
|
481
422
|
scanState,
|
|
482
423
|
getPostprocessMetrics(state),
|
|
483
424
|
facts,
|
|
484
425
|
BROKEN_REF_REPAIR_HOOKS
|
|
485
426
|
)
|
|
486
|
-
|
|
427
|
+
facts.hasBracketText = repairs.hasBracketText
|
|
428
|
+
facts.hasEmphasis = repairs.hasEmphasis
|
|
429
|
+
facts.hasLinkClose = repairs.hasLinkClose
|
|
487
430
|
return repairs.changed
|
|
488
431
|
}
|
|
489
432
|
|
|
490
|
-
const runInlineEmphasisRepairStage = (
|
|
433
|
+
const runInlineEmphasisRepairStage = (
|
|
434
|
+
children,
|
|
435
|
+
facts,
|
|
436
|
+
state,
|
|
437
|
+
isJapaneseMode,
|
|
438
|
+
forceBalanceSanitize = false
|
|
439
|
+
) => {
|
|
491
440
|
if (!facts.hasEmphasis) return false
|
|
492
441
|
let changed = false
|
|
493
442
|
const markChangedFrom = createInlineChangeMarker(facts)
|
|
494
|
-
|
|
443
|
+
const metrics = getPostprocessMetrics(state)
|
|
444
|
+
const repairMask = forceBalanceSanitize
|
|
445
|
+
? INLINE_REPAIR_ALL_EMPHASIS_FIXERS
|
|
446
|
+
: (facts.repairMask || 0)
|
|
447
|
+
if ((repairMask & INLINE_REPAIR_EM_OUTER_STRONG_SEQUENCE) &&
|
|
448
|
+
fixEmOuterStrongSequence(children, markChangedFrom)) {
|
|
449
|
+
changed = true
|
|
450
|
+
bumpPostprocessMetric(metrics, 'emphasisFixers', 'em-outer-strong-sequence')
|
|
451
|
+
}
|
|
495
452
|
if (facts.hasLinkClose) {
|
|
496
|
-
|
|
497
|
-
|
|
498
|
-
|
|
453
|
+
if ((repairMask & INLINE_REPAIR_TAIL_AFTER_LINK) &&
|
|
454
|
+
fixTailAfterLinkStrongClose(children, isJapaneseMode, metrics, markChangedFrom)) {
|
|
455
|
+
changed = true
|
|
456
|
+
}
|
|
457
|
+
if ((repairMask & INLINE_REPAIR_LEADING_ASTERISK_EM) &&
|
|
458
|
+
fixLeadingAsteriskEm(children, markChangedFrom)) {
|
|
459
|
+
changed = true
|
|
460
|
+
bumpPostprocessMetric(metrics, 'emphasisFixers', 'leading-asterisk-em')
|
|
461
|
+
}
|
|
462
|
+
}
|
|
463
|
+
if ((repairMask & INLINE_REPAIR_TRAILING_STRONG) &&
|
|
464
|
+
fixTrailingStrong(children, markChangedFrom)) {
|
|
465
|
+
changed = true
|
|
466
|
+
bumpPostprocessMetric(metrics, 'emphasisFixers', 'trailing-strong')
|
|
467
|
+
}
|
|
468
|
+
const shouldAttemptSanitize = forceBalanceSanitize ||
|
|
469
|
+
changed ||
|
|
470
|
+
facts.hasAsteriskWrapperImbalance ||
|
|
471
|
+
(repairMask & INLINE_REPAIR_BALANCE_SANITIZE)
|
|
472
|
+
if (!shouldAttemptSanitize) {
|
|
473
|
+
bumpPostprocessMetric(metrics, 'emphasisSanitize', 'skipped-balanced')
|
|
474
|
+
return changed
|
|
475
|
+
}
|
|
476
|
+
bumpPostprocessMetric(metrics, 'emphasisSanitize', 'attempted')
|
|
477
|
+
if (forceBalanceSanitize || changed) {
|
|
478
|
+
bumpPostprocessMetric(metrics, 'emphasisSanitize', 'attempted-after-change')
|
|
479
|
+
} else {
|
|
480
|
+
bumpPostprocessMetric(metrics, 'emphasisSanitize', 'attempted-pre-scan-risk')
|
|
481
|
+
}
|
|
482
|
+
if (sanitizeEmStrongBalance(children, markChangedFrom)) {
|
|
483
|
+
changed = true
|
|
484
|
+
bumpPostprocessMetric(metrics, 'emphasisFixers', 'sanitize-em-strong-balance')
|
|
485
|
+
bumpPostprocessMetric(metrics, 'emphasisSanitize', 'repaired')
|
|
486
|
+
} else {
|
|
487
|
+
bumpPostprocessMetric(metrics, 'emphasisSanitize', 'no-change')
|
|
499
488
|
}
|
|
500
|
-
if (fixTrailingStrong(children, markChangedFrom)) changed = true
|
|
501
|
-
if (sanitizeEmStrongBalance(children, markChangedFrom)) changed = true
|
|
502
489
|
return changed
|
|
503
490
|
}
|
|
504
491
|
|
|
@@ -507,33 +494,17 @@ const shouldRunInlineCollapsedRefRepair = (facts, state) => {
|
|
|
507
494
|
return getReferenceCount(state) > 0
|
|
508
495
|
}
|
|
509
496
|
|
|
510
|
-
const applyCollapsedRefRepairFacts = (facts) => {
|
|
511
|
-
if (!facts) return
|
|
512
|
-
facts.hasLinkOpen = true
|
|
513
|
-
facts.hasLinkClose = true
|
|
514
|
-
}
|
|
515
|
-
|
|
516
|
-
const rewriteInlineCollapsedReferences = (children, facts, state, markChangedFrom) => {
|
|
517
|
-
const changed = convertCollapsedReferenceLinks(
|
|
518
|
-
children,
|
|
519
|
-
state,
|
|
520
|
-
facts,
|
|
521
|
-
markChangedFrom
|
|
522
|
-
)
|
|
523
|
-
if (!changed) return false
|
|
524
|
-
applyCollapsedRefRepairFacts(facts)
|
|
525
|
-
return true
|
|
526
|
-
}
|
|
527
|
-
|
|
528
497
|
const runInlineCollapsedRefStage = (children, facts, state) => {
|
|
529
498
|
if (!shouldRunInlineCollapsedRefRepair(facts, state)) return false
|
|
530
499
|
const markChangedFrom = createInlineChangeMarker(facts)
|
|
531
|
-
if (!
|
|
500
|
+
if (!convertCollapsedReferenceLinks(children, state, facts, markChangedFrom)) return false
|
|
501
|
+
facts.hasLinkOpen = true
|
|
502
|
+
facts.hasLinkClose = true
|
|
532
503
|
finalizeInlineLinkRepairStage(children, facts, markChangedFrom)
|
|
533
504
|
return true
|
|
534
505
|
}
|
|
535
506
|
|
|
536
|
-
const shouldSkipInlinePostprocessToken = (
|
|
507
|
+
const shouldSkipInlinePostprocessToken = (facts, isJapaneseMode) => {
|
|
537
508
|
if (!facts.hasEmphasis &&
|
|
538
509
|
!facts.hasBracketText &&
|
|
539
510
|
!facts.hasLinkOpen &&
|
|
@@ -541,8 +512,7 @@ const shouldSkipInlinePostprocessToken = (children, facts, isJapaneseMode) => {
|
|
|
541
512
|
!facts.hasCodeInline) {
|
|
542
513
|
return true
|
|
543
514
|
}
|
|
544
|
-
if (isJapaneseMode &&
|
|
545
|
-
!hasJapaneseContextInRange(children, 0, children.length - 1)) {
|
|
515
|
+
if (isJapaneseMode && !facts.hasJapaneseContext) {
|
|
546
516
|
return true
|
|
547
517
|
}
|
|
548
518
|
return false
|
|
@@ -569,7 +539,7 @@ const runInlineCoreRepairStages = (
|
|
|
569
539
|
return false
|
|
570
540
|
}
|
|
571
541
|
if (runInlineBrokenRefRepairStage(children, facts, inlineContent, state)) changed = true
|
|
572
|
-
if (runInlineEmphasisRepairStage(children, facts, state, isJapaneseMode)) changed = true
|
|
542
|
+
if (runInlineEmphasisRepairStage(children, facts, state, isJapaneseMode, changed)) changed = true
|
|
573
543
|
return changed
|
|
574
544
|
}
|
|
575
545
|
|
|
@@ -583,8 +553,8 @@ const processInlinePostprocessToken = (
|
|
|
583
553
|
) => {
|
|
584
554
|
if (!token || token.type !== 'inline' || !token.children || token.children.length === 0) return
|
|
585
555
|
const children = token.children
|
|
586
|
-
const facts = buildInlinePostprocessFacts(children, inlineContent)
|
|
587
|
-
if (shouldSkipInlinePostprocessToken(
|
|
556
|
+
const facts = buildInlinePostprocessFacts(children, inlineContent, isJapaneseMode)
|
|
557
|
+
if (shouldSkipInlinePostprocessToken(facts, isJapaneseMode)) return
|
|
588
558
|
const changed = runInlineCoreRepairStages(
|
|
589
559
|
children,
|
|
590
560
|
facts,
|