@peaceroad/markdown-it-strong-ja 0.8.0 → 0.9.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 +15 -3
- package/index.js +31 -22
- package/package.json +8 -6
- package/src/token-compat.js +13 -18
- package/src/token-core.js +189 -76
- package/src/token-link-utils.js +386 -193
- package/src/token-postprocess/broken-ref.js +482 -0
- package/src/token-postprocess/guards.js +217 -198
- package/src/token-postprocess/orchestrator.js +295 -385
- package/src/token-utils.js +73 -27
package/README.md
CHANGED
|
@@ -98,6 +98,14 @@ Terms used below:
|
|
|
98
98
|
- Run: a contiguous group of the same marker (`*`, `**`, `***`, ...).
|
|
99
99
|
- Line: text split by `\n`.
|
|
100
100
|
|
|
101
|
+
### TL;DR
|
|
102
|
+
|
|
103
|
+
- Baseline: start from plain `markdown-it` delimiter pairing.
|
|
104
|
+
- Local helper path: only `*` runs with local Japanese context enter strong-ja boundary logic.
|
|
105
|
+
- Mixed-text guard: `japanese-boundary-guard` additionally suppresses mixed JA/EN over-conversion.
|
|
106
|
+
- Postprocess: token-only repairs run only for malformed link/reference-adjacent spans.
|
|
107
|
+
|
|
108
|
+
|
|
101
109
|
### Step 1: Build the baseline with plain `markdown-it`
|
|
102
110
|
|
|
103
111
|
`markdown-it` runs first. If it can already parse a pattern (including cross-line `**...**`), that baseline structure is kept.
|
|
@@ -368,6 +376,7 @@ Supporting visuals:
|
|
|
368
376
|
- Default: `true`
|
|
369
377
|
- Set `false` to disable link/reference postprocess repairs.
|
|
370
378
|
- In `mode: 'compatible'`, repairs are skipped even when this is `true`.
|
|
379
|
+
- Repairs stay local to malformed link/reference-adjacent spans; valid inputs such as `[w](u) *string* [w](u)` are left unchanged.
|
|
371
380
|
|
|
372
381
|
### `coreRulesBeforePostprocess`
|
|
373
382
|
|
|
@@ -387,7 +396,10 @@ Supporting visuals:
|
|
|
387
396
|
|
|
388
397
|
## Notes
|
|
389
398
|
|
|
390
|
-
- Use `state.env.__strongJaTokenOpt` to override options per render.
|
|
391
|
-
-
|
|
392
|
-
-
|
|
399
|
+
- Use `state.env.__strongJaTokenOpt` to override runtime-effective options per render.
|
|
400
|
+
- Repeated `.use(...)` on the same `MarkdownIt` instance is treated as first-install-wins no-op. Create a new `MarkdownIt` instance for a different plugin option set.
|
|
401
|
+
- Runtime-effective override keys are merged with plugin options, but setup-time behavior (such as rule registration/order) cannot be switched at render time and cannot be retrofitted after the first `.use(...)` on the same `MarkdownIt` instance.
|
|
402
|
+
- `mode` and `postprocess` are runtime-effective via initial install or per-render override. `mditAttrs`, `patchCorePush`, and `coreRulesBeforePostprocess` are setup-time effective after the first `.use(...)` on a `MarkdownIt` instance.
|
|
403
|
+
- This is an ESM plugin (`type: module`) and is tested against `markdown-it` 14.x in Node.js, browser bundlers, and VS Code extension pipelines that use `markdown-it` ESM.
|
|
404
|
+
- The implementation relies on `markdown-it` internal ESM modules / core rule internals (`lib/token.mjs`, `lib/common/utils.mjs`, `ruler.__rules__`) plus a `scanDelims` prototype patch, so internal `markdown-it` changes may require plugin updates.
|
|
393
405
|
- `scanDelims` patch is applied once per `MarkdownIt` prototype in the same process.
|
package/index.js
CHANGED
|
@@ -1,32 +1,41 @@
|
|
|
1
|
-
import { hasCjkBreaksRule,
|
|
1
|
+
import { hasCjkBreaksRule, ensureCoreRuleOrder, deriveOptionInfo } from './src/token-utils.js'
|
|
2
2
|
import { patchScanDelims } from './src/token-core.js'
|
|
3
3
|
import { registerTokenCompat } from './src/token-compat.js'
|
|
4
4
|
import { registerTokenPostprocess } from './src/token-postprocess.js'
|
|
5
5
|
|
|
6
|
+
const DEFAULT_OPTION = {
|
|
7
|
+
mditAttrs: true, // assume markdown-it-attrs integration by default
|
|
8
|
+
mode: 'japanese', // 'japanese'(->japanese-boundary-guard) | 'japanese-boundary' | 'japanese-boundary-guard' | 'aggressive' | 'compatible'
|
|
9
|
+
coreRulesBeforePostprocess: [], // e.g. ['cjk_breaks'] to keep rules ahead of postprocess
|
|
10
|
+
postprocess: true, // enable link/ref reconstruction pass
|
|
11
|
+
patchCorePush: true // keep restore-softbreaks after late cjk_breaks
|
|
12
|
+
}
|
|
13
|
+
|
|
14
|
+
const buildNormalizedOption = (md, option) => {
|
|
15
|
+
const opt = { ...DEFAULT_OPTION }
|
|
16
|
+
if (option) Object.assign(opt, option)
|
|
17
|
+
opt.hasCjkBreaks = hasCjkBreaksRule(md)
|
|
18
|
+
deriveOptionInfo(opt)
|
|
19
|
+
return opt
|
|
20
|
+
}
|
|
21
|
+
|
|
6
22
|
const mditStrongJa = (md, option) => {
|
|
7
|
-
if (option && typeof option.engine === 'string' && option.engine !== 'token') {
|
|
8
|
-
throw new Error('mditStrongJa: legacy engine was removed; use token (default)')
|
|
9
|
-
}
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
patchCorePush: true // keep restore-softbreaks after late cjk_breaks
|
|
16
|
-
}
|
|
17
|
-
if (option) Object.assign(opt, option)
|
|
18
|
-
opt.hasCjkBreaks = hasCjkBreaksRule(md)
|
|
19
|
-
deriveModeInfo(opt)
|
|
20
|
-
|
|
21
|
-
md.__strongJaTokenOpt = opt
|
|
23
|
+
if (option && typeof option.engine === 'string' && option.engine !== 'token') {
|
|
24
|
+
throw new Error('mditStrongJa: legacy engine was removed; use token (default)')
|
|
25
|
+
}
|
|
26
|
+
if (md.__strongJaTokenInstalled) {
|
|
27
|
+
return md
|
|
28
|
+
}
|
|
29
|
+
const nextOpt = buildNormalizedOption(md, option)
|
|
30
|
+
md.__strongJaTokenOpt = nextOpt
|
|
22
31
|
patchScanDelims(md)
|
|
23
|
-
registerTokenCompat(md,
|
|
32
|
+
registerTokenCompat(md, nextOpt)
|
|
24
33
|
|
|
25
|
-
registerTokenPostprocess(md,
|
|
26
|
-
|
|
27
|
-
|
|
34
|
+
registerTokenPostprocess(md, nextOpt)
|
|
35
|
+
ensureCoreRuleOrder(md, nextOpt.__strongJaNormalizedCoreRulesBeforePostprocess, 'strong_ja_token_postprocess')
|
|
36
|
+
md.__strongJaTokenInstalled = true
|
|
28
37
|
|
|
29
38
|
return md
|
|
30
39
|
}
|
|
31
|
-
|
|
32
|
-
export default mditStrongJa
|
|
40
|
+
|
|
41
|
+
export default mditStrongJa
|
package/package.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@peaceroad/markdown-it-strong-ja",
|
|
3
|
-
"description": "
|
|
4
|
-
"version": "0.
|
|
3
|
+
"description": "Extends asterisk emphasis handling for Japanese text while keeping markdown-it behavior as close as practical.",
|
|
4
|
+
"version": "0.9.0",
|
|
5
5
|
"main": "index.js",
|
|
6
6
|
"type": "module",
|
|
7
7
|
"files": [
|
|
@@ -18,6 +18,7 @@
|
|
|
18
18
|
"test:postprocess-fastpath": "node test/post-processing-fastpath.test.js",
|
|
19
19
|
"test:postprocess-fastpath-roster": "node test/post-processing-fastpath-roster.test.js",
|
|
20
20
|
"test:postprocess-flow": "node test/post-processing-flow.test.js",
|
|
21
|
+
"test:postprocess-link-helper": "node test/post-processing-link-helper.test.js",
|
|
21
22
|
"test:postprocess-gate": "node test/postprocess-gate.js",
|
|
22
23
|
"test:tokenonly-progress": "node test/post-processing-progress.test.js",
|
|
23
24
|
"test:readme": "node test/test-readme.js",
|
|
@@ -35,13 +36,14 @@
|
|
|
35
36
|
"markdown-it": "^14.1.0"
|
|
36
37
|
},
|
|
37
38
|
"devDependencies": {
|
|
38
|
-
"@peaceroad/markdown-it-cjk-breaks-mod": "^0.1.
|
|
39
|
-
"@peaceroad/markdown-it-hr-sandwiched-semantic-container": "^0.
|
|
40
|
-
"@peaceroad/markdown-it-renderer-image": "^0.
|
|
41
|
-
"@peaceroad/markdown-it-renderer-inline-text": "^0.
|
|
39
|
+
"@peaceroad/markdown-it-cjk-breaks-mod": "^0.1.10",
|
|
40
|
+
"@peaceroad/markdown-it-hr-sandwiched-semantic-container": "^0.11.0",
|
|
41
|
+
"@peaceroad/markdown-it-renderer-image": "^0.12.0",
|
|
42
|
+
"@peaceroad/markdown-it-renderer-inline-text": "^0.8.0",
|
|
42
43
|
"markdown-it-attrs": "^4.3.1",
|
|
43
44
|
"markdown-it-sub": "^2.0.0",
|
|
44
45
|
"markdown-it-sup": "^2.0.0",
|
|
45
46
|
"p7d-markdown-it-p-captions": "^0.21.0"
|
|
46
47
|
}
|
|
47
48
|
}
|
|
49
|
+
|
package/src/token-compat.js
CHANGED
|
@@ -4,9 +4,8 @@ import {
|
|
|
4
4
|
isJapaneseChar,
|
|
5
5
|
hasCjkBreaksRule,
|
|
6
6
|
isCjkBreaksRuleName,
|
|
7
|
-
deriveModeInfo,
|
|
8
|
-
MODE_FLAG_COMPATIBLE,
|
|
9
7
|
getRuntimeOpt,
|
|
8
|
+
hasRuntimeOverride,
|
|
10
9
|
moveRuleAfter
|
|
11
10
|
} from './token-utils.js'
|
|
12
11
|
|
|
@@ -27,16 +26,16 @@ const trimTrailingSpaceTab = (text) => {
|
|
|
27
26
|
return end === text.length ? text : text.slice(0, end)
|
|
28
27
|
}
|
|
29
28
|
|
|
29
|
+
const getStateSource = (state) => {
|
|
30
|
+
return state && typeof state.src === 'string' ? state.src : ''
|
|
31
|
+
}
|
|
32
|
+
|
|
30
33
|
const registerTokenCompat = (md, baseOpt) => {
|
|
31
|
-
const baseModeFlags = typeof baseOpt.__strongJaModeFlags === 'number'
|
|
32
|
-
? baseOpt.__strongJaModeFlags
|
|
33
|
-
: deriveModeInfo(baseOpt).__strongJaModeFlags
|
|
34
|
-
const baseCompatible = (baseModeFlags & MODE_FLAG_COMPATIBLE) !== 0
|
|
35
34
|
const isCompatibleMode = (state) => {
|
|
36
35
|
const override = state && state.env && state.env.__strongJaTokenOpt
|
|
37
|
-
if (!override) return
|
|
36
|
+
if (!hasRuntimeOverride(override)) return baseOpt.__strongJaIsCompatibleMode === true
|
|
38
37
|
const opt = getRuntimeOpt(state, baseOpt)
|
|
39
|
-
return
|
|
38
|
+
return opt.__strongJaIsCompatibleMode === true
|
|
40
39
|
}
|
|
41
40
|
|
|
42
41
|
let hasTextJoinRule = false
|
|
@@ -88,6 +87,8 @@ const registerTokenCompat = (md, baseOpt) => {
|
|
|
88
87
|
const normalizeSoftbreakSpacing = (state) => {
|
|
89
88
|
if (isCompatibleMode(state)) return
|
|
90
89
|
if (!state) return
|
|
90
|
+
const src = getStateSource(state)
|
|
91
|
+
if (!src || src.indexOf('\n') === -1) return
|
|
91
92
|
if (baseOpt.hasCjkBreaks !== true && state.md) {
|
|
92
93
|
baseOpt.hasCjkBreaks = hasCjkBreaksRule(state.md)
|
|
93
94
|
}
|
|
@@ -170,11 +171,8 @@ const registerTokenCompat = (md, baseOpt) => {
|
|
|
170
171
|
const restoreSoftbreaksAfterCjk = (state) => {
|
|
171
172
|
if (isCompatibleMode(state)) return
|
|
172
173
|
if (!state) return
|
|
173
|
-
const
|
|
174
|
-
if (
|
|
175
|
-
const opt = getRuntimeOpt(state, baseOpt)
|
|
176
|
-
if (opt.mditAttrs !== false) return
|
|
177
|
-
}
|
|
174
|
+
const src = getStateSource(state)
|
|
175
|
+
if (!src || src.indexOf('\n') === -1 || src.indexOf('{') === -1) return
|
|
178
176
|
if (!state.md || state.md.__strongJaRestoreSoftbreaksForAttrs !== true) return
|
|
179
177
|
if (baseOpt.hasCjkBreaks !== true && state.md) {
|
|
180
178
|
baseOpt.hasCjkBreaks = hasCjkBreaksRule(state.md)
|
|
@@ -245,11 +243,8 @@ const registerTokenCompat = (md, baseOpt) => {
|
|
|
245
243
|
md.core.ruler.before('linkify', 'strong_ja_token_pre_attrs', (state) => {
|
|
246
244
|
if (isCompatibleMode(state)) return
|
|
247
245
|
if (!state || !state.tokens) return
|
|
248
|
-
const
|
|
249
|
-
if (
|
|
250
|
-
const opt = getRuntimeOpt(state, baseOpt)
|
|
251
|
-
if (opt.mditAttrs === false) return
|
|
252
|
-
}
|
|
246
|
+
const src = getStateSource(state)
|
|
247
|
+
if (!src || src.indexOf('{') === -1 || src.indexOf('}') === -1) return
|
|
253
248
|
for (let i = 0; i < state.tokens.length; i++) {
|
|
254
249
|
const token = state.tokens[i]
|
|
255
250
|
if (!token || token.type !== 'inline' || !token.children || token.children.length === 0) continue
|