@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 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
- - Overrides are merged with plugin options, but setup-time behavior (such as rule registration/order) cannot be switched at render time.
392
- - This is an ESM plugin (`type: module`) and works in Node.js, browser bundlers, and VS Code extension pipelines that use `markdown-it` ESM.
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, normalizeCoreRulesBeforePostprocess, ensureCoreRuleOrder, deriveModeInfo } from './src/token-utils.js'
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
- const opt = {
11
- mditAttrs: true, // assume markdown-it-attrs integration by default
12
- mode: 'japanese', // 'japanese'(->japanese-boundary-guard) | 'japanese-boundary' | 'japanese-boundary-guard' | 'aggressive' | 'compatible'
13
- coreRulesBeforePostprocess: [], // e.g. ['cjk_breaks'] to keep rules ahead of postprocess
14
- postprocess: true, // enable link/ref reconstruction pass
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, opt)
32
+ registerTokenCompat(md, nextOpt)
24
33
 
25
- registerTokenPostprocess(md, opt)
26
- const coreRulesBeforePostprocess = normalizeCoreRulesBeforePostprocess(opt.coreRulesBeforePostprocess)
27
- ensureCoreRuleOrder(md, coreRulesBeforePostprocess, 'strong_ja_token_postprocess')
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": "This is a plugin for markdown-it. It is an alternative to the standard `**` (strong) and `*` (em) processing. It also processes strings that cannot be converted by the standard.",
4
- "version": "0.8.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.7",
39
- "@peaceroad/markdown-it-hr-sandwiched-semantic-container": "^0.8.5",
40
- "@peaceroad/markdown-it-renderer-image": "^0.10.0",
41
- "@peaceroad/markdown-it-renderer-inline-text": "^0.6.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
+
@@ -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 baseCompatible
36
+ if (!hasRuntimeOverride(override)) return baseOpt.__strongJaIsCompatibleMode === true
38
37
  const opt = getRuntimeOpt(state, baseOpt)
39
- return (opt.__strongJaModeFlags & MODE_FLAG_COMPATIBLE) !== 0
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 overrideOpt = state.env && state.env.__strongJaTokenOpt
174
- if (overrideOpt) {
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 overrideOpt = state.env && state.env.__strongJaTokenOpt
249
- if (overrideOpt) {
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